lua-cli 2.5.8 → 3.0.0-alpha.4

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 (115) hide show
  1. package/dist/api/job.api.service.d.ts +219 -0
  2. package/dist/api/job.api.service.js +216 -0
  3. package/dist/api/lazy-instances.d.ts +24 -0
  4. package/dist/api/lazy-instances.js +48 -0
  5. package/dist/api/postprocessor.api.service.d.ts +158 -0
  6. package/dist/api/postprocessor.api.service.js +111 -0
  7. package/dist/api/preprocessor.api.service.d.ts +158 -0
  8. package/dist/api/preprocessor.api.service.js +111 -0
  9. package/dist/api/user.data.api.service.d.ts +13 -0
  10. package/dist/api/user.data.api.service.js +20 -0
  11. package/dist/api/webhook.api.service.d.ts +151 -0
  12. package/dist/api/webhook.api.service.js +134 -0
  13. package/dist/api-exports.d.ts +176 -41
  14. package/dist/api-exports.js +195 -21
  15. package/dist/cli/command-definitions.js +75 -5
  16. package/dist/commands/chat.js +32 -5
  17. package/dist/commands/compile.js +140 -7
  18. package/dist/commands/dev.js +23 -2
  19. package/dist/commands/index.d.ts +4 -0
  20. package/dist/commands/index.js +4 -0
  21. package/dist/commands/init.js +53 -7
  22. package/dist/commands/jobs.d.ts +20 -0
  23. package/dist/commands/jobs.js +533 -0
  24. package/dist/commands/logs.js +2 -5
  25. package/dist/commands/postprocessors.d.ts +8 -0
  26. package/dist/commands/postprocessors.js +431 -0
  27. package/dist/commands/preprocessors.d.ts +8 -0
  28. package/dist/commands/preprocessors.js +431 -0
  29. package/dist/commands/push.js +686 -5
  30. package/dist/commands/test.d.ts +9 -18
  31. package/dist/commands/test.js +574 -82
  32. package/dist/commands/webhooks.d.ts +18 -0
  33. package/dist/commands/webhooks.js +424 -0
  34. package/dist/common/job.instance.d.ts +80 -0
  35. package/dist/common/job.instance.js +116 -0
  36. package/dist/common/user.instance.d.ts +1 -0
  37. package/dist/common/user.instance.js +9 -0
  38. package/dist/config/constants.d.ts +4 -3
  39. package/dist/config/constants.js +10 -8
  40. package/dist/interfaces/agent.d.ts +2 -1
  41. package/dist/interfaces/chat.d.ts +52 -1
  42. package/dist/interfaces/index.d.ts +10 -0
  43. package/dist/interfaces/index.js +7 -0
  44. package/dist/interfaces/jobs.d.ts +193 -0
  45. package/dist/interfaces/jobs.js +5 -0
  46. package/dist/interfaces/postprocessors.d.ts +35 -0
  47. package/dist/interfaces/postprocessors.js +4 -0
  48. package/dist/interfaces/preprocessors.d.ts +35 -0
  49. package/dist/interfaces/preprocessors.js +4 -0
  50. package/dist/interfaces/webhooks.d.ts +104 -0
  51. package/dist/interfaces/webhooks.js +5 -0
  52. package/dist/types/api-contracts.d.ts +5 -0
  53. package/dist/types/compile.types.d.ts +49 -0
  54. package/dist/types/index.d.ts +1 -1
  55. package/dist/types/index.js +1 -1
  56. package/dist/types/skill.d.ts +521 -0
  57. package/dist/types/skill.js +471 -0
  58. package/dist/utils/agent-management.d.ts +25 -0
  59. package/dist/utils/agent-management.js +67 -0
  60. package/dist/utils/bundling.d.ts +44 -5
  61. package/dist/utils/bundling.js +723 -23
  62. package/dist/utils/compile.d.ts +63 -0
  63. package/dist/utils/compile.js +712 -36
  64. package/dist/utils/deployment.d.ts +2 -1
  65. package/dist/utils/deployment.js +16 -2
  66. package/dist/utils/dev-api.d.ts +42 -2
  67. package/dist/utils/dev-api.js +177 -4
  68. package/dist/utils/dev-server.d.ts +1 -1
  69. package/dist/utils/dev-server.js +4 -4
  70. package/dist/utils/dynamic-job-bundler.d.ts +17 -0
  71. package/dist/utils/dynamic-job-bundler.js +143 -0
  72. package/dist/utils/init-agent.d.ts +3 -1
  73. package/dist/utils/init-agent.js +6 -4
  74. package/dist/utils/init-prompts.d.ts +2 -1
  75. package/dist/utils/init-prompts.js +14 -9
  76. package/dist/utils/job-management.d.ts +24 -0
  77. package/dist/utils/job-management.js +264 -0
  78. package/dist/utils/postprocessor-management.d.ts +9 -0
  79. package/dist/utils/postprocessor-management.js +118 -0
  80. package/dist/utils/pre-bundle-jobs.d.ts +26 -0
  81. package/dist/utils/pre-bundle-jobs.js +176 -0
  82. package/dist/utils/preprocessor-management.d.ts +9 -0
  83. package/dist/utils/preprocessor-management.js +118 -0
  84. package/dist/utils/sandbox-storage.d.ts +48 -0
  85. package/dist/utils/sandbox-storage.js +114 -0
  86. package/dist/utils/sandbox.d.ts +61 -1
  87. package/dist/utils/sandbox.js +299 -72
  88. package/dist/utils/tool-detection.d.ts +3 -2
  89. package/dist/utils/tool-detection.js +18 -4
  90. package/dist/utils/webhook-management.d.ts +24 -0
  91. package/dist/utils/webhook-management.js +256 -0
  92. package/package.json +1 -1
  93. package/template/README.md +30 -2
  94. package/template/lua.skill.yaml +47 -0
  95. package/template/package-lock.json +10505 -0
  96. package/template/package.json +2 -1
  97. package/template/src/index.ts +103 -2
  98. package/template/src/jobs/AbandonedBasketProcessorJob.ts +139 -0
  99. package/template/src/jobs/DailyCleanupJob.ts +100 -0
  100. package/template/src/jobs/DataMigrationJob.ts +133 -0
  101. package/template/src/jobs/HealthCheckJob.ts +87 -0
  102. package/template/src/tools/CreateInlineJob.ts +42 -0
  103. package/template/src/tools/GameScoreTrackerTool.ts +356 -0
  104. package/template/src/tools/SmartBasketTool.ts +188 -0
  105. package/template/src/webhooks/PaymentWebhook.ts +113 -0
  106. package/template/src/webhooks/UserEventWebhook.ts +77 -0
  107. package/API_REFERENCE.md +0 -1408
  108. package/CHANGELOG.md +0 -236
  109. package/CLI_REFERENCE.md +0 -908
  110. package/GETTING_STARTED.md +0 -1040
  111. package/INSTANCE_TYPES.md +0 -1158
  112. package/README.md +0 -865
  113. package/TEMPLATE_GUIDE.md +0 -1398
  114. package/USER_DATA_INSTANCE.md +0 -621
  115. package/template/TOOL_EXAMPLES.md +0 -655
@@ -2,102 +2,594 @@
2
2
  * Test Command
3
3
  * Orchestrates the testing of individual tools in a local sandbox environment
4
4
  */
5
+ import fs from "fs";
6
+ import path from "path";
5
7
  import { compileCommand } from "./compile.js";
6
8
  import { withErrorHandling, clearPromptLines, writeProgress, writeSuccess } from "../utils/cli.js";
7
9
  import { loadApiKey } from "../services/auth.js";
8
- import { executeTool, loadEnvironmentVariables } from "../utils/sandbox.js";
10
+ import { executeTool, executeWebhook, executeJob, executePreProcessor, executePostProcessor, loadEnvironmentVariables } from "../utils/sandbox.js";
9
11
  import { readSkillConfig } from "../utils/files.js";
12
+ import { safePrompt } from "../utils/prompt-handler.js";
10
13
  import { decompressCode, readDeployJson, extractToolsFromDeployData, hasEnvFile, hasConfigEnvVars, } from "../utils/test-helpers.js";
11
14
  import { promptToolSelection, generatePromptsForObject } from "../utils/test-prompts.js";
12
15
  /**
13
- * Main test command - tests a tool in a local sandbox environment.
16
+ * Main test command - tests tools, webhooks, jobs, preprocessors, or postprocessors.
14
17
  *
15
- * This command performs the following steps:
16
- * 1. Compiles the skill to ensure latest code
17
- * 2. Loads deploy.json with tool definitions
18
- * 3. Extracts all available tools
19
- * 4. Prompts user to select a tool
20
- * 5. Collects input values based on tool's input schema
21
- * 6. Executes the tool in a sandboxed environment
22
- * 7. Displays the results
23
- *
24
- * Features:
25
- * - Interactive tool selection from compiled tools
26
- * - Dynamic input prompts based on tool schemas
27
- * - Support for nested object inputs
28
- * - Environment variable injection
29
- * - Secure sandbox execution
30
- * - Detailed error reporting
18
+ * This command can test:
19
+ * - Skills/Tools: Interactive tool execution with input prompts
20
+ * - Webhooks: Test webhook with query params, headers, and body
21
+ * - Jobs: Trigger job execution manually
22
+ * - PreProcessors: Test message preprocessing
23
+ * - PostProcessors: Test response postprocessing
31
24
  *
25
+ * @param type - Optional type argument ('skill', 'webhook', 'job', 'preprocessor', 'postprocessor')
32
26
  * @returns Promise that resolves when test completes
33
27
  */
34
- export async function testCommand() {
28
+ export async function testCommand(type) {
35
29
  return withErrorHandling(async () => {
36
- writeProgress("🧪 Testing Lua skill...");
37
- // Step 1: Compile the code
38
- writeProgress("📦 Compiling code first...");
39
- await compileCommand();
40
- // Step 2: Load deploy data and extract tools
41
- const deployData = readDeployJson();
42
- const allTools = extractToolsFromDeployData(deployData);
43
- // Step 3: Load authentication and configuration
44
- const apiKey = await loadApiKey();
45
- if (!apiKey) {
46
- throw new Error("No API key found. Please run 'lua auth configure' first.");
47
- }
48
- const config = readSkillConfig();
49
- const agentId = config?.agent?.agentId;
50
- if (!agentId) {
51
- throw new Error("No agent ID found in lua.skill.yaml. Please run 'lua init' first.");
52
- }
53
- // Step 4: Load environment variables
54
- const envVars = loadEnvironmentVariables();
55
- if (hasEnvFile()) {
56
- writeProgress(`📄 Loaded environment variables from .env file`);
57
- }
58
- if (hasConfigEnvVars(config)) {
59
- writeProgress(`📄 Loaded environment variables from lua.skill.yaml`);
60
- }
61
- // Step 5: Let user select a tool
62
- const selectedTool = await promptToolSelection(allTools);
63
- clearPromptLines(2);
64
- writeProgress(`✅ Selected tool: ${selectedTool.name}`);
65
- // Step 6: Collect input values based on schema
66
- let inputValues = {};
67
- const inputSchema = selectedTool.inputSchema;
68
- if (inputSchema.properties) {
69
- writeProgress("\n📝 Enter input values:");
70
- inputValues = await generatePromptsForObject(inputSchema, '', inputSchema.required || []);
71
- }
72
- // Step 7: Execute the tool
73
- writeProgress("\n🚀 Executing tool...");
74
- writeProgress(`Input: ${JSON.stringify(inputValues, null, 2)}`);
75
- const toolCode = decompressCode(selectedTool.execute);
76
- // Set environment variables for sandbox
77
- const originalEnv = { ...process.env };
78
- for (const [key, value] of Object.entries(envVars)) {
79
- process.env[key] = value;
80
- }
81
- try {
82
- const result = await executeTool({
83
- toolCode,
84
- inputs: inputValues,
85
- apiKey,
86
- agentId
87
- });
88
- writeSuccess("✅ Tool execution successful!");
89
- console.log(`Output: ${JSON.stringify(result, null, 2)}`);
90
- }
91
- catch (executionError) {
92
- console.error("\n❌ Tool execution failed:");
93
- console.error(executionError.message);
94
- if (executionError.stack) {
95
- console.error(executionError.stack);
30
+ let selectedType;
31
+ // Step 1: Check if type was provided as argument
32
+ if (type) {
33
+ // Validate the provided type
34
+ if (type !== 'skill' && type !== 'webhook' && type !== 'job' && type !== 'preprocessor' && type !== 'postprocessor') {
35
+ console.error(`❌ Invalid type: "${type}". Must be "skill", "webhook", "job", "preprocessor", or "postprocessor".`);
36
+ console.log('\nUsage:');
37
+ console.log(' lua test - Interactive selection');
38
+ console.log(' lua test skill - Test a skill/tool directly');
39
+ console.log(' lua test webhook - Test a webhook directly');
40
+ console.log(' lua test job - Test a job directly');
41
+ console.log(' lua test preprocessor - Test a preprocessor directly');
42
+ console.log(' lua test postprocessor - Test a postprocessor directly');
43
+ process.exit(1);
44
+ }
45
+ selectedType = type;
46
+ }
47
+ else {
48
+ // Step 2: Prompt for type selection
49
+ const typeAnswer = await safePrompt([
50
+ {
51
+ type: 'list',
52
+ name: 'type',
53
+ message: 'What would you like to test?',
54
+ choices: [
55
+ { name: '🛠️ Skill/Tool', value: 'skill' },
56
+ { name: '🪝 Webhook', value: 'webhook' },
57
+ { name: '⏰ Job', value: 'job' },
58
+ { name: '📥 PreProcessor', value: 'preprocessor' },
59
+ { name: '📤 PostProcessor', value: 'postprocessor' }
60
+ ]
61
+ }
62
+ ]);
63
+ if (!typeAnswer) {
64
+ console.log("Test cancelled.");
65
+ return;
96
66
  }
67
+ selectedType = typeAnswer.type;
68
+ }
69
+ // Step 3: Route to appropriate function
70
+ if (selectedType === 'skill') {
71
+ await testSkill();
72
+ }
73
+ else if (selectedType === 'webhook') {
74
+ await testWebhook();
75
+ }
76
+ else if (selectedType === 'job') {
77
+ await testJob();
97
78
  }
98
- finally {
99
- // Restore original environment variables
100
- process.env = originalEnv;
79
+ else if (selectedType === 'preprocessor') {
80
+ await testPreProcessor();
81
+ }
82
+ else if (selectedType === 'postprocessor') {
83
+ await testPostProcessor();
101
84
  }
102
85
  }, "testing");
103
86
  }
87
+ /**
88
+ * Test a skill/tool interactively.
89
+ */
90
+ async function testSkill() {
91
+ writeProgress("🧪 Testing Lua skill...");
92
+ // Step 1: Compile the code
93
+ writeProgress("📦 Compiling code first...");
94
+ await compileCommand();
95
+ // Step 2: Load deploy data and extract tools
96
+ const deployData = readDeployJson();
97
+ const allTools = extractToolsFromDeployData(deployData);
98
+ // Step 3: Load authentication and configuration
99
+ const apiKey = await loadApiKey();
100
+ if (!apiKey) {
101
+ throw new Error("No API key found. Please run 'lua auth configure' first.");
102
+ }
103
+ const config = readSkillConfig();
104
+ const agentId = config?.agent?.agentId;
105
+ if (!agentId) {
106
+ throw new Error("No agent ID found in lua.skill.yaml. Please run 'lua init' first.");
107
+ }
108
+ // Step 4: Load environment variables
109
+ const envVars = loadEnvironmentVariables();
110
+ if (hasEnvFile()) {
111
+ writeProgress(`📄 Loaded environment variables from .env file`);
112
+ }
113
+ if (hasConfigEnvVars(config)) {
114
+ writeProgress(`📄 Loaded environment variables from lua.skill.yaml`);
115
+ }
116
+ // Step 5: Let user select a tool
117
+ const selectedTool = await promptToolSelection(allTools);
118
+ clearPromptLines(2);
119
+ writeProgress(`✅ Selected tool: ${selectedTool.name}`);
120
+ // Step 6: Collect input values based on schema
121
+ let inputValues = {};
122
+ const inputSchema = selectedTool.inputSchema;
123
+ if (inputSchema.properties) {
124
+ writeProgress("\n📝 Enter input values:");
125
+ inputValues = await generatePromptsForObject(inputSchema, '', inputSchema.required || []);
126
+ }
127
+ // Step 7: Execute the tool
128
+ writeProgress("\n🚀 Executing tool...");
129
+ writeProgress(`Input: ${JSON.stringify(inputValues, null, 2)}`);
130
+ const toolCode = decompressCode(selectedTool.execute);
131
+ // Set environment variables for sandbox
132
+ const originalEnv = { ...process.env };
133
+ for (const [key, value] of Object.entries(envVars)) {
134
+ process.env[key] = value;
135
+ }
136
+ try {
137
+ const result = await executeTool({
138
+ toolCode,
139
+ inputs: inputValues,
140
+ apiKey,
141
+ agentId
142
+ });
143
+ writeSuccess("✅ Tool execution successful!");
144
+ console.log(`Output: ${JSON.stringify(result, null, 2)}`);
145
+ }
146
+ catch (executionError) {
147
+ console.error("\n❌ Tool execution failed:");
148
+ console.error(executionError.message);
149
+ if (executionError.stack) {
150
+ console.error(executionError.stack);
151
+ }
152
+ }
153
+ finally {
154
+ // Restore original environment variables
155
+ process.env = originalEnv;
156
+ }
157
+ }
158
+ /**
159
+ * Test a webhook interactively.
160
+ */
161
+ async function testWebhook() {
162
+ writeProgress("🪝 Testing webhook...");
163
+ // Step 1: Compile the code
164
+ writeProgress("📦 Compiling code first...");
165
+ await compileCommand();
166
+ // Step 2: Load configuration
167
+ const config = readSkillConfig();
168
+ const webhooks = config.webhooks || [];
169
+ if (webhooks.length === 0) {
170
+ console.error("❌ No webhooks found in configuration.");
171
+ console.log("💡 Create a webhook using LuaWebhook in your code.");
172
+ return;
173
+ }
174
+ // Step 3: Load bundled webhook data
175
+ const bundledWebhooksPath = path.join(process.cwd(), 'dist', 'webhooks.json');
176
+ if (!fs.existsSync(bundledWebhooksPath)) {
177
+ console.error("❌ Bundled webhook data not found. Please run compilation first.");
178
+ return;
179
+ }
180
+ const bundledWebhooks = JSON.parse(fs.readFileSync(bundledWebhooksPath, 'utf8'));
181
+ // Step 4: Select webhook to test
182
+ const webhookAnswer = await safePrompt([
183
+ {
184
+ type: 'list',
185
+ name: 'selectedWebhook',
186
+ message: 'Select a webhook to test:',
187
+ choices: webhooks.map((webhook) => ({
188
+ name: `${webhook.name} (v${webhook.version})`,
189
+ value: webhook
190
+ }))
191
+ }
192
+ ]);
193
+ if (!webhookAnswer) {
194
+ console.log("Test cancelled.");
195
+ return;
196
+ }
197
+ const selectedWebhook = webhookAnswer.selectedWebhook;
198
+ // Find bundled webhook data
199
+ const bundledWebhook = bundledWebhooks.find((w) => w.name === selectedWebhook.name);
200
+ if (!bundledWebhook || !bundledWebhook.code) {
201
+ console.error("❌ Bundled webhook code not found.");
202
+ return;
203
+ }
204
+ // Step 5: Load authentication
205
+ const apiKey = await loadApiKey();
206
+ if (!apiKey) {
207
+ throw new Error("No API key found. Please run 'lua auth configure' first.");
208
+ }
209
+ const agentId = config?.agent?.agentId;
210
+ if (!agentId) {
211
+ throw new Error("No agent ID found in lua.skill.yaml.");
212
+ }
213
+ // Step 6: Collect query parameters based on schema
214
+ let query = {};
215
+ if (bundledWebhook.querySchema && bundledWebhook.querySchema.properties) {
216
+ writeProgress("\n📝 Enter query parameters:");
217
+ query = await generatePromptsForObject(bundledWebhook.querySchema, '', bundledWebhook.querySchema.required || []);
218
+ }
219
+ // Step 7: Collect headers based on schema
220
+ let headers = {};
221
+ if (bundledWebhook.headerSchema && bundledWebhook.headerSchema.properties) {
222
+ writeProgress("\n📝 Enter headers:");
223
+ headers = await generatePromptsForObject(bundledWebhook.headerSchema, '', bundledWebhook.headerSchema.required || []);
224
+ }
225
+ // Step 8: Collect body based on schema
226
+ let body = {};
227
+ if (bundledWebhook.bodySchema && bundledWebhook.bodySchema.properties) {
228
+ writeProgress("\n📝 Enter request body:");
229
+ body = await generatePromptsForObject(bundledWebhook.bodySchema, '', bundledWebhook.bodySchema.required || []);
230
+ }
231
+ // Step 9: Execute webhook through sandbox
232
+ writeProgress("\n🚀 Executing webhook...");
233
+ writeProgress(`Query: ${JSON.stringify(query, null, 2)}`);
234
+ writeProgress(`Headers: ${JSON.stringify(headers, null, 2)}`);
235
+ writeProgress(`Body: ${JSON.stringify(body, null, 2)}`);
236
+ const webhookCode = decompressCode(bundledWebhook.code);
237
+ // Load environment variables
238
+ const envVars = loadEnvironmentVariables();
239
+ const originalEnv = { ...process.env };
240
+ for (const [key, value] of Object.entries(envVars)) {
241
+ process.env[key] = value;
242
+ }
243
+ try {
244
+ const result = await executeWebhook({
245
+ webhookCode,
246
+ query,
247
+ headers,
248
+ body,
249
+ apiKey,
250
+ agentId
251
+ });
252
+ writeSuccess("\n✅ Webhook execution successful!");
253
+ console.log(`Output: ${JSON.stringify(result, null, 2)}`);
254
+ }
255
+ catch (executionError) {
256
+ console.error("\n❌ Webhook execution failed:");
257
+ console.error(executionError.message);
258
+ if (executionError.stack) {
259
+ console.error(executionError.stack);
260
+ }
261
+ }
262
+ finally {
263
+ // Restore original environment variables
264
+ process.env = originalEnv;
265
+ }
266
+ }
267
+ /**
268
+ * Test a job by manually triggering it.
269
+ */
270
+ async function testJob() {
271
+ writeProgress("⏰ Testing job...");
272
+ // Step 1: Compile the code
273
+ writeProgress("📦 Compiling code first...");
274
+ await compileCommand();
275
+ // Step 2: Load configuration
276
+ const apiKey = await loadApiKey();
277
+ if (!apiKey) {
278
+ throw new Error("No API key found. Please run 'lua auth configure' first.");
279
+ }
280
+ const config = readSkillConfig();
281
+ const agentId = config?.agent?.agentId;
282
+ if (!agentId) {
283
+ throw new Error("No agent ID found in lua.skill.yaml.");
284
+ }
285
+ const jobs = config.jobs || [];
286
+ if (jobs.length === 0) {
287
+ console.error("❌ No jobs found in configuration.");
288
+ console.log("💡 Create a job using LuaJob in your code.");
289
+ return;
290
+ }
291
+ // Step 3: Load bundled job data
292
+ const bundledJobsPath = path.join(process.cwd(), 'dist', 'jobs.json');
293
+ if (!fs.existsSync(bundledJobsPath)) {
294
+ console.error("❌ Bundled job data not found. Please run compilation first.");
295
+ return;
296
+ }
297
+ const bundledJobs = JSON.parse(fs.readFileSync(bundledJobsPath, 'utf8'));
298
+ // Step 4: Select job to test
299
+ const jobAnswer = await safePrompt([
300
+ {
301
+ type: 'list',
302
+ name: 'selectedJob',
303
+ message: 'Select a job to test:',
304
+ choices: jobs.map((job) => ({
305
+ name: `${job.name} (v${job.version}) - ${formatSchedule(job.schedule)}`,
306
+ value: job
307
+ }))
308
+ }
309
+ ]);
310
+ if (!jobAnswer) {
311
+ console.log("Test cancelled.");
312
+ return;
313
+ }
314
+ const selectedJob = jobAnswer.selectedJob;
315
+ // Find bundled job data
316
+ const bundledJob = bundledJobs.find((j) => j.name === selectedJob.name);
317
+ if (!bundledJob || !bundledJob.code) {
318
+ console.error("❌ Bundled job code not found.");
319
+ return;
320
+ }
321
+ // Step 5: Execute job through sandbox
322
+ writeProgress(`\n🚀 Executing job: ${selectedJob.name}...`);
323
+ writeProgress(`📅 Schedule: ${formatSchedule(selectedJob.schedule)}`);
324
+ const jobCode = decompressCode(bundledJob.code);
325
+ // Load environment variables
326
+ const envVars = loadEnvironmentVariables();
327
+ const originalEnv = { ...process.env };
328
+ for (const [key, value] of Object.entries(envVars)) {
329
+ process.env[key] = value;
330
+ }
331
+ try {
332
+ const result = await executeJob({
333
+ jobCode,
334
+ apiKey,
335
+ agentId,
336
+ jobData: {
337
+ id: selectedJob.jobId,
338
+ jobId: selectedJob.jobId,
339
+ name: selectedJob.name,
340
+ schedule: selectedJob.schedule,
341
+ metadata: bundledJob.metadata || selectedJob.metadata || {}
342
+ }
343
+ });
344
+ writeSuccess("\n✅ Job execution successful!");
345
+ console.log(`Output: ${JSON.stringify(result, null, 2)}`);
346
+ }
347
+ catch (executionError) {
348
+ console.error("\n❌ Job execution failed:");
349
+ console.error(executionError.message);
350
+ if (executionError.stack) {
351
+ console.error(executionError.stack);
352
+ }
353
+ }
354
+ finally {
355
+ // Restore original environment variables
356
+ process.env = originalEnv;
357
+ }
358
+ }
359
+ /**
360
+ * Test a preprocessor interactively.
361
+ */
362
+ async function testPreProcessor() {
363
+ writeProgress("📥 Testing preprocessor...");
364
+ // Step 1: Compile the code
365
+ writeProgress("📦 Compiling code first...");
366
+ await compileCommand();
367
+ // Step 2: Load bundled preprocessor data
368
+ const preprocessorsPath = path.join(process.cwd(), 'dist', 'preprocessors.json');
369
+ if (!fs.existsSync(preprocessorsPath)) {
370
+ console.error("❌ No preprocessors found. Create a PreProcessor in your code.");
371
+ return;
372
+ }
373
+ const preprocessors = JSON.parse(fs.readFileSync(preprocessorsPath, 'utf8'));
374
+ if (preprocessors.length === 0) {
375
+ console.error("❌ No preprocessors found.");
376
+ return;
377
+ }
378
+ // Step 3: Select preprocessor to test
379
+ const preprocessorAnswer = await safePrompt([
380
+ {
381
+ type: 'list',
382
+ name: 'selected',
383
+ message: 'Select a preprocessor to test:',
384
+ choices: preprocessors.map((p) => ({
385
+ name: `${p.name} (v${p.version})`,
386
+ value: p
387
+ }))
388
+ }
389
+ ]);
390
+ if (!preprocessorAnswer)
391
+ return;
392
+ const selected = preprocessorAnswer.selected;
393
+ if (!selected.code) {
394
+ console.error("❌ Preprocessor code not found.");
395
+ return;
396
+ }
397
+ // Step 4: Collect test inputs
398
+ const messageAnswer = await safePrompt([
399
+ {
400
+ type: 'input',
401
+ name: 'message',
402
+ message: 'Enter test message:',
403
+ default: 'Hello, I need help with my order'
404
+ }
405
+ ]);
406
+ if (!messageAnswer)
407
+ return;
408
+ const channelAnswer = await safePrompt([
409
+ {
410
+ type: 'input',
411
+ name: 'channel',
412
+ message: 'Enter channel:',
413
+ default: 'web'
414
+ }
415
+ ]);
416
+ if (!channelAnswer)
417
+ return;
418
+ // Step 5: Execute preprocessor
419
+ writeProgress("\n🚀 Executing preprocessor...");
420
+ writeProgress(`Input message: ${messageAnswer.message}`);
421
+ writeProgress(`Channel: ${channelAnswer.channel}`);
422
+ const apiKey = await loadApiKey();
423
+ if (!apiKey)
424
+ throw new Error("No API key found.");
425
+ const config = readSkillConfig();
426
+ const agentId = config?.agent?.agentId;
427
+ if (!agentId)
428
+ throw new Error("No agent ID found.");
429
+ const preprocessorCode = decompressCode(selected.code);
430
+ // Load environment variables
431
+ const envVars = loadEnvironmentVariables();
432
+ const originalEnv = { ...process.env };
433
+ for (const [key, value] of Object.entries(envVars)) {
434
+ process.env[key] = value;
435
+ }
436
+ try {
437
+ // Convert string message to ChatMessage array
438
+ const messages = [{ type: 'text', text: messageAnswer.message }];
439
+ const result = await executePreProcessor({
440
+ processorCode: preprocessorCode,
441
+ messages: messages, // Pass array instead of string
442
+ channel: channelAnswer.channel,
443
+ apiKey,
444
+ agentId
445
+ });
446
+ writeSuccess("\n✅ PreProcessor execution successful!");
447
+ console.log(`\nProcessed messages (${result.length}):`);
448
+ result.forEach((msg, idx) => {
449
+ if (msg.type === 'text') {
450
+ console.log(` ${idx + 1}. [TEXT] ${msg.text}`);
451
+ }
452
+ else if (msg.type === 'image') {
453
+ console.log(` ${idx + 1}. [IMAGE] ${msg.mimeType}`);
454
+ }
455
+ else if (msg.type === 'file') {
456
+ console.log(` ${idx + 1}. [FILE] ${msg.mimeType}`);
457
+ }
458
+ else {
459
+ console.log(` ${idx + 1}. [${msg.type}]`, msg);
460
+ }
461
+ });
462
+ }
463
+ catch (error) {
464
+ console.error("\n❌ PreProcessor execution failed:");
465
+ console.error(error.message);
466
+ }
467
+ finally {
468
+ process.env = originalEnv;
469
+ }
470
+ }
471
+ /**
472
+ * Test a postprocessor interactively.
473
+ */
474
+ async function testPostProcessor() {
475
+ writeProgress("📤 Testing postprocessor...");
476
+ // Step 1: Compile the code
477
+ writeProgress("📦 Compiling code first...");
478
+ await compileCommand();
479
+ // Step 2: Load bundled postprocessor data
480
+ const postprocessorsPath = path.join(process.cwd(), 'dist', 'postprocessors.json');
481
+ if (!fs.existsSync(postprocessorsPath)) {
482
+ console.error("❌ No postprocessors found. Create a PostProcessor in your code.");
483
+ return;
484
+ }
485
+ const postprocessors = JSON.parse(fs.readFileSync(postprocessorsPath, 'utf8'));
486
+ if (postprocessors.length === 0) {
487
+ console.error("❌ No postprocessors found.");
488
+ return;
489
+ }
490
+ // Step 3: Select postprocessor to test
491
+ const postprocessorAnswer = await safePrompt([
492
+ {
493
+ type: 'list',
494
+ name: 'selected',
495
+ message: 'Select a postprocessor to test:',
496
+ choices: postprocessors.map((p) => ({
497
+ name: `${p.name} (v${p.version})`,
498
+ value: p
499
+ }))
500
+ }
501
+ ]);
502
+ if (!postprocessorAnswer)
503
+ return;
504
+ const selected = postprocessorAnswer.selected;
505
+ if (!selected.code) {
506
+ console.error("❌ Postprocessor code not found.");
507
+ return;
508
+ }
509
+ // Step 4: Collect test inputs
510
+ const messageAnswer = await safePrompt([
511
+ {
512
+ type: 'input',
513
+ name: 'message',
514
+ message: 'Enter original user message:',
515
+ default: 'What products do you have?'
516
+ }
517
+ ]);
518
+ if (!messageAnswer)
519
+ return;
520
+ const responseAnswer = await safePrompt([
521
+ {
522
+ type: 'input',
523
+ name: 'response',
524
+ message: 'Enter agent response to process:',
525
+ default: 'We have laptops, phones, and tablets available.'
526
+ }
527
+ ]);
528
+ if (!responseAnswer)
529
+ return;
530
+ const channelAnswer = await safePrompt([
531
+ {
532
+ type: 'input',
533
+ name: 'channel',
534
+ message: 'Enter channel:',
535
+ default: 'web'
536
+ }
537
+ ]);
538
+ if (!channelAnswer)
539
+ return;
540
+ // Step 5: Execute postprocessor
541
+ writeProgress("\n🚀 Executing postprocessor...");
542
+ writeProgress(`Original message: ${messageAnswer.message}`);
543
+ writeProgress(`Agent response: ${responseAnswer.response}`);
544
+ writeProgress(`Channel: ${channelAnswer.channel}`);
545
+ const apiKey = await loadApiKey();
546
+ if (!apiKey)
547
+ throw new Error("No API key found.");
548
+ const config = readSkillConfig();
549
+ const agentId = config?.agent?.agentId;
550
+ if (!agentId)
551
+ throw new Error("No agent ID found.");
552
+ const postprocessorCode = decompressCode(selected.code);
553
+ // Load environment variables
554
+ const envVars = loadEnvironmentVariables();
555
+ const originalEnv = { ...process.env };
556
+ for (const [key, value] of Object.entries(envVars)) {
557
+ process.env[key] = value;
558
+ }
559
+ try {
560
+ const result = await executePostProcessor({
561
+ processorCode: postprocessorCode,
562
+ message: messageAnswer.message,
563
+ response: responseAnswer.response,
564
+ channel: channelAnswer.channel,
565
+ apiKey,
566
+ agentId
567
+ });
568
+ writeSuccess("\n✅ PostProcessor execution successful!");
569
+ console.log(`Processed response: ${result}`);
570
+ }
571
+ catch (error) {
572
+ console.error("\n❌ PostProcessor execution failed:");
573
+ console.error(error.message);
574
+ }
575
+ finally {
576
+ process.env = originalEnv;
577
+ }
578
+ }
579
+ /**
580
+ * Format schedule for display
581
+ */
582
+ function formatSchedule(schedule) {
583
+ if (!schedule)
584
+ return 'Not configured';
585
+ switch (schedule.type) {
586
+ case 'cron':
587
+ return `Cron: ${schedule.expression}${schedule.timezone ? ` (${schedule.timezone})` : ''}`;
588
+ case 'once':
589
+ return `Once at: ${new Date(schedule.executeAt).toLocaleString()}`;
590
+ case 'interval':
591
+ return `Every ${schedule.seconds} seconds`;
592
+ default:
593
+ return 'Unknown schedule type';
594
+ }
595
+ }