lua-cli 3.1.0-alpha.4 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/api/cdn.api.service.d.ts +18 -0
  2. package/dist/api/cdn.api.service.js +43 -0
  3. package/dist/api/custom.data.api.service.d.ts +4 -3
  4. package/dist/api/custom.data.api.service.js +4 -3
  5. package/dist/api/developer.api.service.d.ts +54 -1
  6. package/dist/api/developer.api.service.js +89 -0
  7. package/dist/api/job.api.service.d.ts +10 -0
  8. package/dist/api/job.api.service.js +14 -0
  9. package/dist/api/lazy-instances.d.ts +8 -0
  10. package/dist/api/lazy-instances.js +16 -0
  11. package/dist/api/postprocessor.api.service.d.ts +3 -6
  12. package/dist/api/postprocessor.api.service.js +2 -3
  13. package/dist/api-exports.d.ts +74 -6
  14. package/dist/api-exports.js +87 -7
  15. package/dist/cli/command-definitions.js +34 -7
  16. package/dist/commands/admin.js +1 -1
  17. package/dist/commands/channels.js +1 -1
  18. package/dist/commands/compile.js +23 -4
  19. package/dist/commands/evals.d.ts +8 -0
  20. package/dist/commands/evals.js +41 -0
  21. package/dist/commands/index.d.ts +2 -0
  22. package/dist/commands/index.js +2 -0
  23. package/dist/commands/init.d.ts +10 -1
  24. package/dist/commands/init.js +13 -3
  25. package/dist/commands/mcp.d.ts +18 -0
  26. package/dist/commands/mcp.js +393 -0
  27. package/dist/commands/push.js +172 -14
  28. package/dist/common/data.entry.instance.d.ts +1 -1
  29. package/dist/common/data.entry.instance.js +4 -4
  30. package/dist/common/job.instance.d.ts +24 -0
  31. package/dist/common/job.instance.js +38 -0
  32. package/dist/config/constants.d.ts +1 -0
  33. package/dist/config/constants.js +1 -0
  34. package/dist/index.js +1 -0
  35. package/dist/interfaces/cdn.d.ts +24 -0
  36. package/dist/interfaces/cdn.js +5 -0
  37. package/dist/interfaces/compile.d.ts +1 -0
  38. package/dist/interfaces/custom.data.d.ts +3 -3
  39. package/dist/interfaces/index.d.ts +1 -0
  40. package/dist/interfaces/mcp.d.ts +64 -0
  41. package/dist/interfaces/mcp.js +5 -0
  42. package/dist/types/api-contracts.d.ts +36 -14
  43. package/dist/types/compile.types.d.ts +5 -0
  44. package/dist/types/index.d.ts +2 -2
  45. package/dist/types/index.js +3 -1
  46. package/dist/types/skill.d.ts +120 -13
  47. package/dist/types/skill.js +95 -5
  48. package/dist/utils/bundling.d.ts +4 -11
  49. package/dist/utils/bundling.js +19 -27
  50. package/dist/utils/compile.d.ts +17 -8
  51. package/dist/utils/compile.js +71 -37
  52. package/dist/utils/deployment.js +13 -6
  53. package/dist/utils/dev-api.js +1 -2
  54. package/dist/utils/dev-server.js +1 -1
  55. package/dist/utils/files.d.ts +8 -1
  56. package/dist/utils/files.js +13 -2
  57. package/dist/utils/init-helpers.d.ts +3 -1
  58. package/dist/utils/init-helpers.js +7 -2
  59. package/dist/utils/mcp-server-management.d.ts +23 -0
  60. package/dist/utils/mcp-server-management.js +212 -0
  61. package/dist/utils/sandbox.d.ts +4 -2
  62. package/dist/utils/sandbox.js +22 -3
  63. package/dist/web/app.css +1505 -14
  64. package/dist/web/app.js +79 -64
  65. package/package.json +2 -6
  66. package/template/QUICKSTART.md +57 -761
  67. package/template/README.md +80 -906
  68. package/template/examples/README.md +106 -0
  69. package/template/{src → examples}/jobs/AbandonedBasketProcessorJob.ts +67 -11
  70. package/template/{src → examples}/postprocessors/modifyResponse.ts +3 -3
  71. package/template/{src → examples}/skills/tools/GameScoreTrackerTool.ts +11 -15
  72. package/template/{src → examples}/skills/tools/OrderTool.ts +25 -0
  73. package/template/examples/skills/tools/PremiumFeatureTool.ts +98 -0
  74. package/template/{src → examples}/skills/tools/UserDataTool.ts +34 -0
  75. package/template/examples/webhooks/FileUploadWebhook.ts +86 -0
  76. package/template/package-lock.json +7895 -0
  77. package/template/package.json +1 -1
  78. package/template/src/index.ts +40 -22
  79. /package/template/{src → examples}/jobs/DailyCleanupJob.ts +0 -0
  80. /package/template/{src → examples}/jobs/DataMigrationJob.ts +0 -0
  81. /package/template/{src → examples}/jobs/HealthCheckJob.ts +0 -0
  82. /package/template/{src → examples}/preprocessors/messageMatching.ts +0 -0
  83. /package/template/{src → examples}/services/ApiService.ts +0 -0
  84. /package/template/{src → examples}/services/GetWeather.ts +0 -0
  85. /package/template/{src → examples}/skills/basket.skill.ts +0 -0
  86. /package/template/{src → examples}/skills/product.skill.ts +0 -0
  87. /package/template/{src → examples}/skills/tools/BasketTool.ts +0 -0
  88. /package/template/{src → examples}/skills/tools/CreateInlineJob.ts +0 -0
  89. /package/template/{src → examples}/skills/tools/CreatePostTool.ts +0 -0
  90. /package/template/{src → examples}/skills/tools/CustomDataTool.ts +0 -0
  91. /package/template/{src → examples}/skills/tools/GetWeatherTool.ts +0 -0
  92. /package/template/{src → examples}/skills/tools/PaymentTool.ts +0 -0
  93. /package/template/{src → examples}/skills/tools/ProductsTool.ts +0 -0
  94. /package/template/{src → examples}/skills/tools/SmartBasketTool.ts +0 -0
  95. /package/template/{src → examples}/skills/user.skill.ts +0 -0
  96. /package/template/{src → examples}/webhooks/PaymentWebhook.ts +0 -0
  97. /package/template/{src → examples}/webhooks/UserEventWebhook.ts +0 -0
@@ -459,7 +459,7 @@ export class PreProcessor {
459
459
  * name: 'response-formatter',
460
460
  * description: 'Formats responses with branding',
461
461
  * execute: async (user, message, response, channel) => {
462
- * return response + '\n\n---\nPowered by Acme Corp';
462
+ * return { modifiedResponse: response + '\n\n---\nPowered by Acme Corp' };
463
463
  * }
464
464
  * });
465
465
  * ```
@@ -468,7 +468,6 @@ export class PostProcessor {
468
468
  constructor(config) {
469
469
  this.name = config.name || 'unnamed-postprocessor';
470
470
  this.description = config.description;
471
- this.asyncMode = config.async ?? false; // Default to synchronous
472
471
  this.executeFunction = config.execute;
473
472
  }
474
473
  getName() {
@@ -477,13 +476,99 @@ export class PostProcessor {
477
476
  getDescription() {
478
477
  return this.description;
479
478
  }
480
- getAsync() {
481
- return this.asyncMode;
482
- }
483
479
  async execute(user, message, response, channel) {
484
480
  return this.executeFunction(user, message, response, channel);
485
481
  }
486
482
  }
483
+ /**
484
+ * LuaMCPServer class.
485
+ * Defines an MCP (Model Context Protocol) server connection.
486
+ *
487
+ * MCP servers provide tools that can be used by your agent at runtime.
488
+ * You can connect to local servers (via stdio) or remote servers (via SSE/HTTP).
489
+ *
490
+ * @example
491
+ * ```typescript
492
+ * import { LuaMCPServer } from 'lua-cli';
493
+ *
494
+ * // Local MCP server via npx
495
+ * const wikipediaServer = new LuaMCPServer({
496
+ * name: 'wikipedia',
497
+ * transport: 'stdio',
498
+ * command: 'npx',
499
+ * args: ['-y', 'wikipedia-mcp'],
500
+ * description: 'Wikipedia search and retrieval'
501
+ * });
502
+ *
503
+ * // Remote MCP server via SSE
504
+ * const weatherServer = new LuaMCPServer({
505
+ * name: 'weather',
506
+ * transport: 'sse',
507
+ * url: 'https://api.example.com/mcp',
508
+ * headers: {
509
+ * 'Authorization': 'Bearer ${env.WEATHER_API_KEY}'
510
+ * },
511
+ * description: 'Weather information service'
512
+ * });
513
+ * ```
514
+ */
515
+ export class LuaMCPServer {
516
+ constructor(config) {
517
+ if (!config.name) {
518
+ throw new Error('MCP server name is required');
519
+ }
520
+ if (config.transport === 'stdio' && !config.command) {
521
+ throw new Error('Command is required for stdio transport');
522
+ }
523
+ if (config.transport === 'sse' && !config.url) {
524
+ throw new Error('URL is required for sse transport');
525
+ }
526
+ this.config = config;
527
+ }
528
+ getName() {
529
+ return this.config.name;
530
+ }
531
+ getTransport() {
532
+ return this.config.transport;
533
+ }
534
+ getTimeout() {
535
+ return this.config.timeout;
536
+ }
537
+ getConfig() {
538
+ return this.config;
539
+ }
540
+ /**
541
+ * Returns the server configuration in a format suitable for serialization.
542
+ * Environment variable references (${env.VAR_NAME}) are preserved for runtime resolution.
543
+ */
544
+ toJSON() {
545
+ const base = {
546
+ name: this.config.name,
547
+ transport: this.config.transport,
548
+ };
549
+ if (this.config.timeout) {
550
+ base.timeout = this.config.timeout;
551
+ }
552
+ if (this.config.transport === 'stdio') {
553
+ const stdioConfig = this.config;
554
+ base.command = stdioConfig.command;
555
+ if (stdioConfig.args) {
556
+ base.args = stdioConfig.args;
557
+ }
558
+ if (stdioConfig.env) {
559
+ base.env = stdioConfig.env;
560
+ }
561
+ }
562
+ else {
563
+ const sseConfig = this.config;
564
+ base.url = sseConfig.url;
565
+ if (sseConfig.headers) {
566
+ base.headers = sseConfig.headers;
567
+ }
568
+ }
569
+ return base;
570
+ }
571
+ }
487
572
  /**
488
573
  * LuaAgent class.
489
574
  * Unified agent configuration that consolidates skills, webhooks, jobs, and processors.
@@ -524,6 +609,7 @@ export class LuaAgent {
524
609
  * @param config.jobs - Optional array of jobs
525
610
  * @param config.preProcessors - Optional array of preprocessors
526
611
  * @param config.postProcessors - Optional array of postprocessors
612
+ * @param config.mcpServers - Optional array of MCP servers
527
613
  */
528
614
  constructor(config) {
529
615
  this.name = config.name;
@@ -533,6 +619,7 @@ export class LuaAgent {
533
619
  this.jobs = config.jobs || [];
534
620
  this.preProcessors = config.preProcessors || [];
535
621
  this.postProcessors = config.postProcessors || [];
622
+ this.mcpServers = config.mcpServers || [];
536
623
  }
537
624
  getName() {
538
625
  return this.name;
@@ -555,4 +642,7 @@ export class LuaAgent {
555
642
  getPostProcessors() {
556
643
  return this.postProcessors;
557
644
  }
645
+ getMCPServers() {
646
+ return this.mcpServers;
647
+ }
558
648
  }
@@ -65,15 +65,8 @@ export declare function bundlePreProcessor(preprocessor: any, indexFile: any, di
65
65
  */
66
66
  export declare function bundlePostProcessor(postprocessor: any, indexFile: any, distDir: string, project?: any, debugMode?: boolean): Promise<any>;
67
67
  /**
68
- * Extracts execute code and input schema from a tool.
69
- * This function:
70
- * 1. Reads the bundled tool code
71
- * 2. Detects and bundles any Jobs.create() calls within execute
72
- * 3. Extracts the execute function
73
- * 4. Converts Zod schema to JSON Schema format
74
- *
75
- * @param tool - The tool to extract metadata from (mutated with executeCode and inputSchema)
76
- * @param project - The ts-morph Project instance for AST analysis
77
- * @param distDir - Distribution directory for bundling nested jobs
68
+ * Extracts tool code from a bundled tool.
69
+ * Reads the bundled code, wraps it for VM execution (execute and condition),
70
+ * and converts the Zod schema to JSON Schema format.
78
71
  */
79
- export declare function extractExecuteCode(tool: ToolInfo, project: Project, distDir?: string): Promise<void>;
72
+ export declare function extractToolCode(tool: ToolInfo, project: Project): Promise<void>;
@@ -8,7 +8,7 @@ import { build } from "esbuild";
8
8
  import { Project, Node } from "ts-morph";
9
9
  import { writeProgress } from "./cli.js";
10
10
  import { COMPILE_DIRS, COMPILE_FILES, ESBUILD_TOOL_CONFIG, ESBUILD_INDEX_CONFIG, DEFAULT_INPUT_SCHEMA, EXTERNAL_PACKAGES, } from '../config/compile.constants.js';
11
- import { wrapToolForVM, createExecuteFunction, evaluateZodSchemaToJsonSchema } from './compile.js';
11
+ import { wrapExecuteForVM, wrapConditionForVM, evaluateZodSchemaToJsonSchema } from './compile.js';
12
12
  /**
13
13
  * Helper function to remove lua-cli and api-exports imports from source code.
14
14
  * Used when bundling via stdin or temp files where the plugin can't process them.
@@ -347,8 +347,6 @@ export async function bundleTool(tool, distDir, modifiedSource, debugMode) {
347
347
  plugins: [sandboxGlobalsPlugin],
348
348
  });
349
349
  }
350
- // Wrap the bundled code for VM execution environment
351
- await wrapToolForVM(outputPath, tool);
352
350
  // Clean up temp file if created (unless in debug mode)
353
351
  if (tempFile && fs.existsSync(tempFile) && !debugMode) {
354
352
  try {
@@ -819,7 +817,6 @@ export async function bundlePostProcessor(postprocessor, indexFile, distDir, pro
819
817
  name: postprocessor.name,
820
818
  version: postprocessor.version,
821
819
  description: postprocessor.description,
822
- async: postprocessor.async === true ? true : false, // Explicitly set boolean
823
820
  executeFunction,
824
821
  code: compressedCode
825
822
  };
@@ -845,18 +842,11 @@ async function bundleAndCompressProcessorCode(executeFunction, processorName, ty
845
842
  })`, distDir, sourceFilePath, debugMode);
846
843
  }
847
844
  /**
848
- * Extracts execute code and input schema from a tool.
849
- * This function:
850
- * 1. Reads the bundled tool code
851
- * 2. Detects and bundles any Jobs.create() calls within execute
852
- * 3. Extracts the execute function
853
- * 4. Converts Zod schema to JSON Schema format
854
- *
855
- * @param tool - The tool to extract metadata from (mutated with executeCode and inputSchema)
856
- * @param project - The ts-morph Project instance for AST analysis
857
- * @param distDir - Distribution directory for bundling nested jobs
845
+ * Extracts tool code from a bundled tool.
846
+ * Reads the bundled code, wraps it for VM execution (execute and condition),
847
+ * and converts the Zod schema to JSON Schema format.
858
848
  */
859
- export async function extractExecuteCode(tool, project, distDir) {
849
+ export async function extractToolCode(tool, project) {
860
850
  try {
861
851
  const toolSourceFile = project.getSourceFile(tool.filePath);
862
852
  if (!toolSourceFile) {
@@ -890,28 +880,30 @@ export async function extractExecuteCode(tool, project, distDir) {
890
880
  return;
891
881
  }
892
882
  }
893
- // Extract execute code from bundled file
894
- tool.executeCode = extractExecuteCodeFromBundledFile(tool);
895
- // NOTE: Dynamic job bundling moved to source-level processing
896
- // Attempting to extract from minified bundled code is too fragile
883
+ // Read bundled code and wrap for VM execution
884
+ const rawBundledCode = readBundledToolCode(tool);
885
+ if (rawBundledCode) {
886
+ tool.executeCode = wrapExecuteForVM(rawBundledCode, tool.className);
887
+ // Check if tool has condition and wrap it
888
+ const hasCondition = classDecl.getMethod('condition') || classDecl.getProperty('condition');
889
+ if (hasCondition) {
890
+ tool.conditionCode = wrapConditionForVM(rawBundledCode, tool.className);
891
+ }
892
+ }
897
893
  // Extract and convert input schema
898
894
  tool.inputSchema = await extractInputSchema(classDecl, tool);
899
895
  }
900
896
  catch (error) {
901
- console.warn(`Warning: Could not extract execute code for ${tool.className}:`, error);
897
+ console.warn(`Warning: Could not extract tool metadata for ${tool.className}:`, error);
902
898
  }
903
899
  }
904
900
  /**
905
- * Extracts execute code from the bundled tool file.
906
- *
907
- * @param tool - The tool whose bundled code to read
908
- * @returns The execute function code or undefined if not found
901
+ * Reads the raw bundled tool code from the dist directory.
909
902
  */
910
- function extractExecuteCodeFromBundledFile(tool) {
903
+ function readBundledToolCode(tool) {
911
904
  const bundledPath = path.join(process.cwd(), COMPILE_DIRS.DIST, COMPILE_DIRS.TOOLS, `${tool.className}.js`);
912
905
  if (fs.existsSync(bundledPath)) {
913
- const bundledCode = fs.readFileSync(bundledPath, 'utf8');
914
- return createExecuteFunction(bundledCode, tool);
906
+ return fs.readFileSync(bundledPath, 'utf8');
915
907
  }
916
908
  return undefined;
917
909
  }
@@ -12,24 +12,25 @@ export declare function compressCode(code: string): string;
12
12
  */
13
13
  export declare function findIndexFile(): string;
14
14
  /**
15
- * Resolves import path from module specifier with support for multiple extensions and index files
16
- * @param moduleSpecifier - The import path (e.g., './tools/MyTool' or '../utils')
15
+ * Resolves import path from module specifier with support for multiple extensions and index files.
16
+ * Handles modern TypeScript projects that use .js extensions in imports (Node16/NodeNext resolution).
17
+ * @param moduleSpecifier - The import path (e.g., './tools/MyTool.js' or '../utils')
17
18
  * @param currentFilePath - The file doing the importing
18
19
  * @returns Resolved absolute file path
19
20
  */
20
21
  export declare function resolveImportPath(moduleSpecifier: string, currentFilePath: string): string;
21
- /**
22
- * Creates execute function wrapper from bundled code
23
- */
24
- export declare function createExecuteFunction(bundledCode: string, tool: ToolInfo): string;
25
22
  /**
26
23
  * Evaluates Zod schema code and converts it to JSON Schema
27
24
  */
28
25
  export declare function evaluateZodSchemaToJsonSchema(zodSchemaCode: string): Promise<any>;
29
26
  /**
30
- * Wraps bundled tool code for VM execution
27
+ * Wraps raw bundled tool code for execute function
28
+ */
29
+ export declare function wrapExecuteForVM(bundledCode: string, className: string): string;
30
+ /**
31
+ * Wraps raw bundled tool code for condition evaluation
31
32
  */
32
- export declare function wrapToolForVM(outputPath: string, tool: ToolInfo): Promise<void>;
33
+ export declare function wrapConditionForVM(bundledCode: string, className: string): string;
33
34
  /**
34
35
  * Extracts tool information from a new expression in the AST
35
36
  */
@@ -69,6 +70,7 @@ export declare function extractLuaAgentMetadata(indexFile: any): {
69
70
  jobs: any[];
70
71
  preProcessors: any[];
71
72
  postProcessors: any[];
73
+ mcpServers: any[];
72
74
  } | null;
73
75
  /**
74
76
  * Gets the file paths where skills are defined in a LuaAgent.
@@ -93,10 +95,17 @@ export declare function resolveLuaAgentReferences(agentMetadata: {
93
95
  jobs: any[];
94
96
  preProcessors: any[];
95
97
  postProcessors: any[];
98
+ mcpServers: any[];
96
99
  }, indexFile: any, project: Project): {
97
100
  skills: any[];
98
101
  webhooks: any[];
99
102
  jobs: any[];
100
103
  preProcessors: any[];
101
104
  postProcessors: any[];
105
+ mcpServers: any[];
102
106
  };
107
+ /**
108
+ * Extracts MCP server metadata from a source file.
109
+ * Looks for LuaMCPServer constructor calls.
110
+ */
111
+ export declare function extractMCPServersMetadata(sourceFile: any): any[];
@@ -29,17 +29,24 @@ export function findIndexFile() {
29
29
  throw new Error("index.ts not found in current directory or src/ directory");
30
30
  }
31
31
  /**
32
- * Resolves import path from module specifier with support for multiple extensions and index files
33
- * @param moduleSpecifier - The import path (e.g., './tools/MyTool' or '../utils')
32
+ * Resolves import path from module specifier with support for multiple extensions and index files.
33
+ * Handles modern TypeScript projects that use .js extensions in imports (Node16/NodeNext resolution).
34
+ * @param moduleSpecifier - The import path (e.g., './tools/MyTool.js' or '../utils')
34
35
  * @param currentFilePath - The file doing the importing
35
36
  * @returns Resolved absolute file path
36
37
  */
37
38
  export function resolveImportPath(moduleSpecifier, currentFilePath) {
38
39
  const extensions = ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];
39
- if (moduleSpecifier.startsWith('./') || moduleSpecifier.startsWith('../')) {
40
+ // Handle modern TS projects using .js extensions in imports (Node16/NodeNext module resolution)
41
+ // Strip the extension so we can properly resolve to the .ts source file
42
+ let normalizedSpecifier = moduleSpecifier;
43
+ if (moduleSpecifier.endsWith('.js')) {
44
+ normalizedSpecifier = moduleSpecifier.slice(0, -3);
45
+ }
46
+ if (normalizedSpecifier.startsWith('./') || normalizedSpecifier.startsWith('../')) {
40
47
  // Relative import - resolve relative to current file
41
48
  const currentDir = path.dirname(currentFilePath);
42
- const basePath = path.resolve(currentDir, moduleSpecifier);
49
+ const basePath = path.resolve(currentDir, normalizedSpecifier);
43
50
  // Try each extension in order
44
51
  for (const ext of extensions) {
45
52
  const fullPath = ext.startsWith('/') ? path.join(basePath, ext) : basePath + ext;
@@ -52,7 +59,7 @@ export function resolveImportPath(moduleSpecifier, currentFilePath) {
52
59
  }
53
60
  else {
54
61
  // Absolute import - check in src/ directory
55
- const srcBase = path.resolve(process.cwd(), 'src', moduleSpecifier);
62
+ const srcBase = path.resolve(process.cwd(), 'src', normalizedSpecifier);
56
63
  for (const ext of extensions) {
57
64
  const fullPath = ext.startsWith('/') ? path.join(srcBase, ext) : srcBase + ext;
58
65
  if (fs.existsSync(fullPath)) {
@@ -60,17 +67,9 @@ export function resolveImportPath(moduleSpecifier, currentFilePath) {
60
67
  }
61
68
  }
62
69
  // Fallback: return .ts in src/ (original behavior)
63
- return path.resolve(process.cwd(), 'src', moduleSpecifier + '.ts');
70
+ return path.resolve(process.cwd(), 'src', normalizedSpecifier + '.ts');
64
71
  }
65
72
  }
66
- /**
67
- * Creates execute function wrapper from bundled code
68
- */
69
- export function createExecuteFunction(bundledCode, tool) {
70
- // The bundled code is already wrapped for VM execution by wrapToolForVM
71
- // Just return it directly since it's already an async function
72
- return bundledCode;
73
- }
74
73
  /**
75
74
  * Evaluates Zod schema code and converts it to JSON Schema
76
75
  */
@@ -109,25 +108,28 @@ export async function evaluateZodSchemaToJsonSchema(zodSchemaCode) {
109
108
  }
110
109
  }
111
110
  /**
112
- * Wraps bundled tool code for VM execution
111
+ * Wraps raw bundled tool code for execute function
113
112
  */
114
- export async function wrapToolForVM(outputPath, tool) {
115
- const bundledCode = fs.readFileSync(outputPath, 'utf8');
116
- // Create a wrapper that's compatible with the existing sandbox.ts VM system
117
- // The sandbox expects: const executeFunction = ${toolCode}; module.exports = async (input) => { return await executeFunction(input); };
118
- const wrappedCode = `async (input) => {
119
-
120
- // Execute the bundled tool code
113
+ export function wrapExecuteForVM(bundledCode, className) {
114
+ return `async (input) => {
121
115
  ${bundledCode}
122
116
 
123
- // Get the tool class from exports
124
- const ToolClass = module.exports.default || module.exports.${tool.className} || module.exports;
125
-
126
- // Create and execute the tool
117
+ const ToolClass = module.exports.default || module.exports.${className} || module.exports;
127
118
  const toolInstance = new ToolClass();
128
119
  return await toolInstance.execute(input);
129
120
  }`;
130
- fs.writeFileSync(outputPath, wrappedCode);
121
+ }
122
+ /**
123
+ * Wraps raw bundled tool code for condition evaluation
124
+ */
125
+ export function wrapConditionForVM(bundledCode, className) {
126
+ return `async () => {
127
+ ${bundledCode}
128
+
129
+ const ToolClass = module.exports.default || module.exports.${className} || module.exports;
130
+ const toolInstance = new ToolClass();
131
+ return await toolInstance.condition() === true;
132
+ }`;
131
133
  }
132
134
  /**
133
135
  * Extracts tool information from a new expression in the AST
@@ -463,7 +465,6 @@ export function extractPostProcessorsMetadata(indexFile) {
463
465
  const configObj = args[0];
464
466
  let name = '';
465
467
  let description = '';
466
- let asyncMode = false;
467
468
  configObj.getProperties().forEach((prop) => {
468
469
  if (Node.isPropertyAssignment(prop)) {
469
470
  const propName = prop.getName();
@@ -474,18 +475,12 @@ export function extractPostProcessorsMetadata(indexFile) {
474
475
  else if (propName === 'description' && value) {
475
476
  description = value.getText().replace(/['"]/g, '');
476
477
  }
477
- else if (propName === 'async' && value) {
478
- // Properly extract boolean value by checking node kind
479
- const nodeKind = value.getKind();
480
- asyncMode = nodeKind === 110; // TrueKeyword = 110, FalseKeyword = 95
481
- }
482
478
  }
483
479
  });
484
480
  if (name) {
485
481
  postprocessors.push({
486
482
  name,
487
- description,
488
- async: asyncMode
483
+ description
489
484
  });
490
485
  }
491
486
  }
@@ -518,6 +513,7 @@ export function extractLuaAgentMetadata(indexFile) {
518
513
  const jobs = [];
519
514
  const preProcessors = [];
520
515
  const postProcessors = [];
516
+ const mcpServers = [];
521
517
  // Extract properties from LuaAgent config
522
518
  configObj.getProperties().forEach((prop) => {
523
519
  if (Node.isPropertyAssignment(prop)) {
@@ -608,6 +604,22 @@ export function extractLuaAgentMetadata(indexFile) {
608
604
  }
609
605
  });
610
606
  }
607
+ else if (propName === 'mcpServers' && value && Node.isArrayLiteralExpression(value)) {
608
+ // Extract MCP server references from the array
609
+ value.getElements().forEach((element) => {
610
+ if (Node.isIdentifier(element)) {
611
+ mcpServers.push({ ref: element.getText() });
612
+ }
613
+ else if (Node.isNewExpression(element)) {
614
+ // Extract inline MCP server metadata
615
+ const mcpArgs = element.getArguments();
616
+ if (mcpArgs.length > 0 && Node.isObjectLiteralExpression(mcpArgs[0])) {
617
+ const mcpConfig = extractConfigFromObjectLiteral(mcpArgs[0]);
618
+ mcpServers.push(mcpConfig);
619
+ }
620
+ }
621
+ });
622
+ }
611
623
  }
612
624
  });
613
625
  if (name && persona) {
@@ -618,7 +630,8 @@ export function extractLuaAgentMetadata(indexFile) {
618
630
  webhooks,
619
631
  jobs,
620
632
  preProcessors,
621
- postProcessors
633
+ postProcessors,
634
+ mcpServers
622
635
  };
623
636
  }
624
637
  }
@@ -788,9 +801,30 @@ export function resolveLuaAgentReferences(agentMetadata, indexFile, project) {
788
801
  webhooks: resolveArrayReferences(agentMetadata.webhooks, extractWebhooksMetadata),
789
802
  jobs: resolveArrayReferences(agentMetadata.jobs, extractJobsMetadata),
790
803
  preProcessors: resolveArrayReferences(agentMetadata.preProcessors, extractPreProcessorsMetadata),
791
- postProcessors: resolveArrayReferences(agentMetadata.postProcessors, extractPostProcessorsMetadata)
804
+ postProcessors: resolveArrayReferences(agentMetadata.postProcessors, extractPostProcessorsMetadata),
805
+ mcpServers: resolveArrayReferences(agentMetadata.mcpServers, extractMCPServersMetadata)
792
806
  };
793
807
  }
808
+ /**
809
+ * Extracts MCP server metadata from a source file.
810
+ * Looks for LuaMCPServer constructor calls.
811
+ */
812
+ export function extractMCPServersMetadata(sourceFile) {
813
+ const mcpServers = [];
814
+ sourceFile.forEachDescendant((node) => {
815
+ if (Node.isNewExpression(node)) {
816
+ const expression = node.getExpression();
817
+ if (expression.getText() === 'LuaMCPServer') {
818
+ const args = node.getArguments();
819
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
820
+ const config = extractConfigFromObjectLiteral(args[0]);
821
+ mcpServers.push(config);
822
+ }
823
+ }
824
+ }
825
+ });
826
+ return mcpServers;
827
+ }
794
828
  /**
795
829
  * Finds a variable declaration in a source file by name.
796
830
  */
@@ -154,12 +154,19 @@ function buildSkillsArray(skillsMetadata, skillToTools, tools) {
154
154
  name: skillMeta.name,
155
155
  description: skillMeta.description,
156
156
  context: skillMeta.context,
157
- tools: skillTools.map(tool => ({
158
- name: tool.name,
159
- description: tool.description || '',
160
- inputSchema: tool.inputSchema || DEFAULT_INPUT_SCHEMA,
161
- execute: compressCode(tool.executeCode || '')
162
- }))
157
+ tools: skillTools.map(tool => {
158
+ const toolData = {
159
+ name: tool.name,
160
+ description: tool.description || '',
161
+ inputSchema: tool.inputSchema || DEFAULT_INPUT_SCHEMA,
162
+ execute: compressCode(tool.executeCode || '')
163
+ };
164
+ // Include condition if tool has one
165
+ if (tool.conditionCode) {
166
+ toolData.condition = compressCode(tool.conditionCode);
167
+ }
168
+ return toolData;
169
+ })
163
170
  };
164
171
  });
165
172
  }
@@ -349,8 +349,7 @@ export async function pushSinglePostProcessorToSandbox(apiKey, agentId, postproc
349
349
  version: sandboxVersion,
350
350
  description: postprocessorData.description,
351
351
  code: postprocessorData.code,
352
- executeFunction: postprocessorData.executeFunction,
353
- async: Boolean(postprocessorData.async ?? false)
352
+ executeFunction: postprocessorData.executeFunction
354
353
  };
355
354
  if (sandboxPostProcessorId) {
356
355
  // Try to update existing sandbox version
@@ -792,7 +792,7 @@ async function handleCustomDataEndpoint(req, res, apiKey, agentId) {
792
792
  req.on('end', () => resolve(data));
793
793
  });
794
794
  const updateData = JSON.parse(body);
795
- result = await customDataApi.update(collectionName, entryId, updateData);
795
+ result = await customDataApi.update(collectionName, entryId, updateData.data, updateData.searchText);
796
796
  res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
797
797
  res.end(JSON.stringify({ success: true, data: result }));
798
798
  }
@@ -1,4 +1,11 @@
1
- export declare function copyTemplateFiles(templateDir: string, targetDir: string): void;
1
+ /**
2
+ * Copies template files to target directory.
3
+ *
4
+ * @param templateDir - Source template directory
5
+ * @param targetDir - Target directory to copy to
6
+ * @param includeExamples - Whether to include the examples/ directory (default: false)
7
+ */
8
+ export declare function copyTemplateFiles(templateDir: string, targetDir: string, includeExamples?: boolean): void;
2
9
  export declare function createSkillYaml(agentId: string, orgId: string, skillName?: string, skillId?: string, persona?: string): void;
3
10
  export declare function readSkillYaml(): any;
4
11
  export declare function readSkillConfig(): any;
@@ -2,18 +2,29 @@ import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import pkg from 'js-yaml';
4
4
  const { load, dump } = pkg;
5
- export function copyTemplateFiles(templateDir, targetDir) {
5
+ /**
6
+ * Copies template files to target directory.
7
+ *
8
+ * @param templateDir - Source template directory
9
+ * @param targetDir - Target directory to copy to
10
+ * @param includeExamples - Whether to include the examples/ directory (default: false)
11
+ */
12
+ export function copyTemplateFiles(templateDir, targetDir, includeExamples = false) {
6
13
  const files = fs.readdirSync(templateDir);
7
14
  for (const file of files) {
8
15
  // Skip node_modules and package-lock.json to avoid circular dependencies
9
16
  if (file === 'node_modules' || file === 'package-lock.json') {
10
17
  continue;
11
18
  }
19
+ // Skip examples/ by default (user can include with --with-examples flag)
20
+ if (file === 'examples' && !includeExamples) {
21
+ continue;
22
+ }
12
23
  const srcPath = path.join(templateDir, file);
13
24
  const destPath = path.join(targetDir, file);
14
25
  if (fs.statSync(srcPath).isDirectory()) {
15
26
  fs.mkdirSync(destPath, { recursive: true });
16
- copyTemplateFiles(srcPath, destPath);
27
+ copyTemplateFiles(srcPath, destPath, includeExamples);
17
28
  }
18
29
  else if (file === 'package.json') {
19
30
  // Special handling for package.json to update lua-cli version
@@ -14,9 +14,11 @@ export declare function getTemplateDir(): string;
14
14
  * @param agentId - Agent ID for configuration
15
15
  * @param orgId - Organization ID for configuration
16
16
  * @param persona - Optional persona configuration
17
+ * @param agentName - Optional agent name
18
+ * @param withExamples - Whether to include example skills, tools, jobs, etc. (default: false)
17
19
  * @returns Current working directory
18
20
  */
19
- export declare function initializeProject(agentId: string, orgId: string, persona?: string, agentName?: string): string;
21
+ export declare function initializeProject(agentId: string, orgId: string, persona?: string, agentName?: string, withExamples?: boolean): string;
20
22
  /**
21
23
  * Installs npm dependencies for the project.
22
24
  *
@@ -24,17 +24,22 @@ export function getTemplateDir() {
24
24
  * @param agentId - Agent ID for configuration
25
25
  * @param orgId - Organization ID for configuration
26
26
  * @param persona - Optional persona configuration
27
+ * @param agentName - Optional agent name
28
+ * @param withExamples - Whether to include example skills, tools, jobs, etc. (default: false)
27
29
  * @returns Current working directory
28
30
  */
29
- export function initializeProject(agentId, orgId, persona, agentName) {
31
+ export function initializeProject(agentId, orgId, persona, agentName, withExamples = false) {
30
32
  const templateDir = getTemplateDir();
31
33
  const currentDir = process.cwd();
32
- copyTemplateFiles(templateDir, currentDir);
34
+ copyTemplateFiles(templateDir, currentDir, withExamples);
33
35
  createSkillYaml(agentId, orgId, undefined, undefined, persona);
34
36
  // Update LuaAgent in index.ts with agent configuration
35
37
  updateLuaAgentInIndexFile(currentDir, agentName, persona);
36
38
  writeProgress("✅ Created lua.skill.yaml");
37
39
  writeProgress("✅ Copied template files");
40
+ if (withExamples) {
41
+ writeProgress("✅ Included example skills, tools, jobs, and webhooks");
42
+ }
38
43
  writeProgress("✅ Updated LuaAgent configuration");
39
44
  return currentDir;
40
45
  }