lua-cli 3.0.0-alpha.1 → 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.
- package/dist/api/job.api.service.d.ts +16 -7
- package/dist/api/job.api.service.js +21 -5
- package/dist/api/postprocessor.api.service.d.ts +61 -1
- package/dist/api/postprocessor.api.service.js +35 -0
- package/dist/api/preprocessor.api.service.d.ts +61 -1
- package/dist/api/preprocessor.api.service.js +35 -0
- package/dist/api-exports.d.ts +26 -6
- package/dist/api-exports.js +42 -29
- package/dist/commands/chat.js +32 -5
- package/dist/commands/compile.js +16 -2
- package/dist/commands/dev.js +23 -2
- package/dist/commands/push.js +5 -3
- package/dist/commands/test.js +18 -2
- package/dist/common/job.instance.d.ts +3 -0
- package/dist/common/job.instance.js +8 -0
- package/dist/config/constants.d.ts +6 -5
- package/dist/config/constants.js +12 -10
- package/dist/interfaces/chat.d.ts +30 -1
- package/dist/interfaces/jobs.d.ts +21 -0
- package/dist/types/skill.d.ts +75 -56
- package/dist/types/skill.js +53 -59
- package/dist/utils/bundling.d.ts +13 -4
- package/dist/utils/bundling.js +83 -26
- package/dist/utils/compile.js +27 -6
- package/dist/utils/dev-api.d.ts +42 -2
- package/dist/utils/dev-api.js +177 -4
- package/dist/utils/dev-server.d.ts +1 -1
- package/dist/utils/dev-server.js +4 -4
- package/dist/utils/dynamic-job-bundler.d.ts +17 -0
- package/dist/utils/dynamic-job-bundler.js +143 -0
- package/dist/utils/pre-bundle-jobs.d.ts +26 -0
- package/dist/utils/pre-bundle-jobs.js +176 -0
- package/dist/utils/sandbox-storage.d.ts +48 -0
- package/dist/utils/sandbox-storage.js +114 -0
- package/dist/utils/sandbox.d.ts +2 -2
- package/dist/utils/sandbox.js +23 -7
- package/package.json +1 -1
- package/template/lua.skill.yaml +47 -0
- package/template/package-lock.json +10505 -0
- package/template/package.json +2 -1
- package/template/src/index.ts +65 -3
- package/template/src/tools/CreateInlineJob.ts +42 -0
- package/API_REFERENCE.md +0 -1408
- package/CHANGELOG.md +0 -236
- package/CLI_REFERENCE.md +0 -908
- package/GETTING_STARTED.md +0 -1040
- package/INSTANCE_TYPES.md +0 -1158
- package/README.md +0 -865
- package/TEMPLATE_GUIDE.md +0 -1398
- package/USER_DATA_INSTANCE.md +0 -621
- package/template/AGENT_CONFIGURATION.md +0 -251
- package/template/COMPLEX_JOB_EXAMPLES.md +0 -795
- package/template/DYNAMIC_JOB_CREATION.md +0 -371
- package/template/TOOL_EXAMPLES.md +0 -655
- package/template/WEBHOOKS_JOBS_QUICKSTART.md +0 -318
- package/template/WEBHOOK_JOB_EXAMPLES.md +0 -817
- package/template/src/index-agent-example.ts +0 -201
- package/template/src/postprocessors/ResponseFormatter.ts +0 -151
- package/template/src/preprocessors/MessageFilter.ts +0 -91
package/dist/utils/dev-api.js
CHANGED
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import ChatApi from '../api/chat.api.service.js';
|
|
6
6
|
import SkillApi from '../api/skills.api.service.js';
|
|
7
|
+
import PreProcessorApi from '../api/preprocessor.api.service.js';
|
|
8
|
+
import PostProcessorApi from '../api/postprocessor.api.service.js';
|
|
7
9
|
import { BASE_URLS } from '../config/constants.js';
|
|
8
10
|
import { writeProgress, writeSuccess } from './cli.js';
|
|
9
11
|
import { loadEnvironmentVariables } from './sandbox.js';
|
|
10
|
-
import { getSandboxSkillId, setSandboxSkillId, getAllSandboxSkillIds } from './sandbox-storage.js';
|
|
12
|
+
import { getSandboxSkillId, setSandboxSkillId, getAllSandboxSkillIds, getSandboxPreProcessorId, setSandboxPreProcessorId, getSandboxPostProcessorId, setSandboxPostProcessorId } from './sandbox-storage.js';
|
|
11
13
|
/**
|
|
12
|
-
* Sends a chat message to the API with skill
|
|
14
|
+
* Sends a chat message to the API with skill and processor overrides for sandbox testing.
|
|
13
15
|
*
|
|
14
16
|
* @param apiKey - User's API key
|
|
15
17
|
* @param agentId - Agent ID
|
|
@@ -18,9 +20,10 @@ import { getSandboxSkillId, setSandboxSkillId, getAllSandboxSkillIds } from './s
|
|
|
18
20
|
* @param message - Message to send
|
|
19
21
|
* @param persona - Optional persona override
|
|
20
22
|
* @param deployData - Deploy data containing all skills
|
|
23
|
+
* @param config - Optional config for processor overrides
|
|
21
24
|
* @returns The chat response text or null if failed
|
|
22
25
|
*/
|
|
23
|
-
export async function sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona, deployData) {
|
|
26
|
+
export async function sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona, deployData, config) {
|
|
24
27
|
try {
|
|
25
28
|
// Get all sandbox skill IDs for skill override
|
|
26
29
|
const allSkillOverrides = await getAllSandboxSkillIds(deployData);
|
|
@@ -31,6 +34,10 @@ export async function sendChatMessage(apiKey, agentId, skillId, sandboxId, messa
|
|
|
31
34
|
sandboxId: sandboxId
|
|
32
35
|
}
|
|
33
36
|
];
|
|
37
|
+
// Get sandbox processor overrides if config provided
|
|
38
|
+
const { getAllSandboxPreProcessorIds, getAllSandboxPostProcessorIds } = await import('./sandbox-storage.js');
|
|
39
|
+
const preprocessorOverride = config ? await getAllSandboxPreProcessorIds(config) : [];
|
|
40
|
+
const postprocessorOverride = config ? await getAllSandboxPostProcessorIds(config) : [];
|
|
34
41
|
const chatRequest = {
|
|
35
42
|
messages: [
|
|
36
43
|
{
|
|
@@ -39,7 +46,9 @@ export async function sendChatMessage(apiKey, agentId, skillId, sandboxId, messa
|
|
|
39
46
|
}
|
|
40
47
|
],
|
|
41
48
|
navigate: true,
|
|
42
|
-
skillOverride: skillOverride
|
|
49
|
+
skillOverride: skillOverride,
|
|
50
|
+
preprocessorOverride: preprocessorOverride,
|
|
51
|
+
postprocessorOverride: postprocessorOverride
|
|
43
52
|
};
|
|
44
53
|
// Add persona override if provided
|
|
45
54
|
if (persona) {
|
|
@@ -260,3 +269,167 @@ export async function pushSkillsToSandbox(apiKey, agentId, deployData, isInitial
|
|
|
260
269
|
}
|
|
261
270
|
return sandboxIds;
|
|
262
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Pushes a single preprocessor to the sandbox.
|
|
274
|
+
* Attempts to update existing sandbox version, creates new one if update fails.
|
|
275
|
+
*
|
|
276
|
+
* @param apiKey - User's API key
|
|
277
|
+
* @param agentId - Agent ID
|
|
278
|
+
* @param preprocessorId - PreProcessor ID
|
|
279
|
+
* @param preprocessorData - PreProcessor data to push
|
|
280
|
+
* @param isInitial - Whether this is the initial push (affects logging)
|
|
281
|
+
* @returns True if successful, false otherwise
|
|
282
|
+
*/
|
|
283
|
+
export async function pushSinglePreProcessorToSandbox(apiKey, agentId, preprocessorId, preprocessorData, isInitial = false) {
|
|
284
|
+
const preprocessorName = preprocessorData.name || 'Unknown PreProcessor';
|
|
285
|
+
const sandboxPreProcessorId = await getSandboxPreProcessorId(preprocessorName);
|
|
286
|
+
// Ensure version has -sandbox postfix
|
|
287
|
+
const baseVersion = preprocessorData.version || '1.0.0';
|
|
288
|
+
const sandboxVersion = baseVersion.endsWith('-sandbox') ? baseVersion : `${baseVersion}-sandbox`;
|
|
289
|
+
const payload = {
|
|
290
|
+
name: preprocessorName,
|
|
291
|
+
version: sandboxVersion,
|
|
292
|
+
description: preprocessorData.description,
|
|
293
|
+
context: preprocessorData.context,
|
|
294
|
+
code: preprocessorData.code,
|
|
295
|
+
executeFunction: preprocessorData.executeFunction,
|
|
296
|
+
async: Boolean(preprocessorData.async ?? false)
|
|
297
|
+
};
|
|
298
|
+
if (sandboxPreProcessorId) {
|
|
299
|
+
// Try to update existing sandbox version
|
|
300
|
+
if (!isInitial) {
|
|
301
|
+
writeProgress(`🔄 Updating existing preprocessor sandbox version...`);
|
|
302
|
+
}
|
|
303
|
+
const api = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
304
|
+
const updateResult = await api.updateDevPreProcessor(preprocessorId, sandboxPreProcessorId, payload);
|
|
305
|
+
if (updateResult.success && updateResult.data) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
if (!isInitial) {
|
|
310
|
+
writeProgress("⚠️ Failed to update preprocessor sandbox, creating new one...");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Create new sandbox version
|
|
315
|
+
if (!isInitial) {
|
|
316
|
+
writeProgress(`🔄 Creating new preprocessor sandbox version...`);
|
|
317
|
+
}
|
|
318
|
+
const api = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
319
|
+
const result = await api.pushDevPreProcessor(preprocessorId, payload);
|
|
320
|
+
if (result.success && result.data) {
|
|
321
|
+
// Store the new sandbox preprocessor ID
|
|
322
|
+
await setSandboxPreProcessorId(result.data.versionId, preprocessorName);
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
else if (result.error) {
|
|
326
|
+
console.error(`❌ PreProcessor sandbox push failed: ${result.error.message}`);
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Pushes a single postprocessor to the sandbox.
|
|
333
|
+
* Attempts to update existing sandbox version, creates new one if update fails.
|
|
334
|
+
*
|
|
335
|
+
* @param apiKey - User's API key
|
|
336
|
+
* @param agentId - Agent ID
|
|
337
|
+
* @param postprocessorId - PostProcessor ID
|
|
338
|
+
* @param postprocessorData - PostProcessor data to push
|
|
339
|
+
* @param isInitial - Whether this is the initial push (affects logging)
|
|
340
|
+
* @returns True if successful, false otherwise
|
|
341
|
+
*/
|
|
342
|
+
export async function pushSinglePostProcessorToSandbox(apiKey, agentId, postprocessorId, postprocessorData, isInitial = false) {
|
|
343
|
+
const postprocessorName = postprocessorData.name || 'Unknown PostProcessor';
|
|
344
|
+
const sandboxPostProcessorId = await getSandboxPostProcessorId(postprocessorName);
|
|
345
|
+
// Ensure version has -sandbox postfix
|
|
346
|
+
const baseVersion = postprocessorData.version || '1.0.0';
|
|
347
|
+
const sandboxVersion = baseVersion.endsWith('-sandbox') ? baseVersion : `${baseVersion}-sandbox`;
|
|
348
|
+
const payload = {
|
|
349
|
+
name: postprocessorName,
|
|
350
|
+
version: sandboxVersion,
|
|
351
|
+
description: postprocessorData.description,
|
|
352
|
+
context: postprocessorData.context,
|
|
353
|
+
code: postprocessorData.code,
|
|
354
|
+
executeFunction: postprocessorData.executeFunction,
|
|
355
|
+
async: Boolean(postprocessorData.async ?? false)
|
|
356
|
+
};
|
|
357
|
+
if (sandboxPostProcessorId) {
|
|
358
|
+
// Try to update existing sandbox version
|
|
359
|
+
if (!isInitial) {
|
|
360
|
+
writeProgress(`🔄 Updating existing postprocessor sandbox version...`);
|
|
361
|
+
}
|
|
362
|
+
const api = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
363
|
+
const updateResult = await api.updateDevPostProcessor(postprocessorId, sandboxPostProcessorId, payload);
|
|
364
|
+
if (updateResult.success && updateResult.data) {
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
if (!isInitial) {
|
|
369
|
+
writeProgress("⚠️ Failed to update postprocessor sandbox, creating new one...");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Create new sandbox version
|
|
374
|
+
if (!isInitial) {
|
|
375
|
+
writeProgress(`🔄 Creating new postprocessor sandbox version...`);
|
|
376
|
+
}
|
|
377
|
+
const api = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
378
|
+
const result = await api.pushDevPostProcessor(postprocessorId, payload);
|
|
379
|
+
if (result.success && result.data) {
|
|
380
|
+
// Store the new sandbox postprocessor ID
|
|
381
|
+
await setSandboxPostProcessorId(result.data.versionId, postprocessorName);
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
else if (result.error) {
|
|
385
|
+
console.error(`❌ PostProcessor sandbox push failed: ${result.error.message}`);
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Pushes preprocessors and postprocessors to sandbox.
|
|
392
|
+
*
|
|
393
|
+
* @param apiKey - User's API key
|
|
394
|
+
* @param agentId - Agent ID
|
|
395
|
+
* @param config - Configuration with preprocessors and postprocessors
|
|
396
|
+
* @param bundledPreProcessors - Bundled preprocessor data from compilation
|
|
397
|
+
* @param bundledPostProcessors - Bundled postprocessor data from compilation
|
|
398
|
+
* @param isInitial - Whether this is the initial push
|
|
399
|
+
* @returns Object with counts of pushed processors
|
|
400
|
+
*/
|
|
401
|
+
export async function pushProcessorsToSandbox(apiKey, agentId, config, bundledPreProcessors, bundledPostProcessors, isInitial = false) {
|
|
402
|
+
let preprocessorCount = 0;
|
|
403
|
+
let postprocessorCount = 0;
|
|
404
|
+
// Push preprocessors
|
|
405
|
+
const configPreProcessors = config.preprocessors || [];
|
|
406
|
+
for (const preprocessor of configPreProcessors) {
|
|
407
|
+
const bundled = bundledPreProcessors.find(p => p.name === preprocessor.name);
|
|
408
|
+
if (bundled && bundled.code && preprocessor.preprocessorId) {
|
|
409
|
+
try {
|
|
410
|
+
const success = await pushSinglePreProcessorToSandbox(apiKey, agentId, preprocessor.preprocessorId, bundled, isInitial);
|
|
411
|
+
if (success)
|
|
412
|
+
preprocessorCount++;
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
console.error(`❌ Failed to push preprocessor ${preprocessor.name}:`, error);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// Push postprocessors
|
|
420
|
+
const configPostProcessors = config.postprocessors || [];
|
|
421
|
+
for (const postprocessor of configPostProcessors) {
|
|
422
|
+
const bundled = bundledPostProcessors.find(p => p.name === postprocessor.name);
|
|
423
|
+
if (bundled && bundled.code && postprocessor.postprocessorId) {
|
|
424
|
+
try {
|
|
425
|
+
const success = await pushSinglePostProcessorToSandbox(apiKey, agentId, postprocessor.postprocessorId, bundled, isInitial);
|
|
426
|
+
if (success)
|
|
427
|
+
postprocessorCount++;
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
console.error(`❌ Failed to push postprocessor ${postprocessor.name}:`, error);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return { preprocessors: preprocessorCount, postprocessors: postprocessorCount };
|
|
435
|
+
}
|
|
@@ -21,4 +21,4 @@ export interface DevServer {
|
|
|
21
21
|
* @param port - Port to run server on
|
|
22
22
|
* @returns Server instance with WebSocket and broadcast function
|
|
23
23
|
*/
|
|
24
|
-
export declare function createChatServer(apiKey: string, agentId: string, skillId: string, sandboxId: string, port: number): DevServer;
|
|
24
|
+
export declare function createChatServer(apiKey: string, agentId: string, skillId: string, sandboxId: string, port: number, config?: any): DevServer;
|
package/dist/utils/dev-server.js
CHANGED
|
@@ -42,7 +42,7 @@ function readDeployJson() {
|
|
|
42
42
|
* @param port - Port to run server on
|
|
43
43
|
* @returns Server instance with WebSocket and broadcast function
|
|
44
44
|
*/
|
|
45
|
-
export function createChatServer(apiKey, agentId, skillId, sandboxId, port) {
|
|
45
|
+
export function createChatServer(apiKey, agentId, skillId, sandboxId, port, config) {
|
|
46
46
|
const deployData = readDeployJson();
|
|
47
47
|
const server = createServer((req, res) => {
|
|
48
48
|
// Enable CORS
|
|
@@ -56,7 +56,7 @@ export function createChatServer(apiKey, agentId, skillId, sandboxId, port) {
|
|
|
56
56
|
}
|
|
57
57
|
// Route handlers
|
|
58
58
|
if (req.method === 'POST' && req.url === '/chat') {
|
|
59
|
-
handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, deployData);
|
|
59
|
+
handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, deployData, config);
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
if (req.method === 'GET' && req.url === '/persona') {
|
|
@@ -173,7 +173,7 @@ export function createChatServer(apiKey, agentId, skillId, sandboxId, port) {
|
|
|
173
173
|
/**
|
|
174
174
|
* Handles POST /chat - Send chat messages
|
|
175
175
|
*/
|
|
176
|
-
function handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, deployData) {
|
|
176
|
+
function handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, deployData, config) {
|
|
177
177
|
let body = '';
|
|
178
178
|
req.on('data', (chunk) => {
|
|
179
179
|
body += chunk.toString();
|
|
@@ -181,7 +181,7 @@ function handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, deplo
|
|
|
181
181
|
req.on('end', async () => {
|
|
182
182
|
try {
|
|
183
183
|
const { message, persona } = JSON.parse(body);
|
|
184
|
-
const response = await sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona, deployData);
|
|
184
|
+
const response = await sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona, deployData, config);
|
|
185
185
|
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
186
186
|
res.end(JSON.stringify({
|
|
187
187
|
success: response !== null,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic Job Bundler
|
|
3
|
+
* Handles detection and bundling of Jobs.create() calls within execute functions
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Detects if code contains Jobs.create() calls
|
|
7
|
+
*/
|
|
8
|
+
export declare function containsJobsCreate(code: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Extracts Jobs.create() execute functions and bundles them with dependencies.
|
|
11
|
+
* Finds execute functions in the code and creates standalone bundles.
|
|
12
|
+
*/
|
|
13
|
+
export declare function bundleNestedJobs(code: string, parentName: string, distDir: string): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Cleans up temporary bundling directory
|
|
16
|
+
*/
|
|
17
|
+
export declare function cleanupTempDir(distDir: string): void;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic Job Bundler
|
|
3
|
+
* Handles detection and bundling of Jobs.create() calls within execute functions
|
|
4
|
+
*/
|
|
5
|
+
import { build } from 'esbuild';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { compressCode } from './compile.js';
|
|
9
|
+
import { sandboxGlobalsPlugin } from './bundling.js';
|
|
10
|
+
/**
|
|
11
|
+
* Detects if code contains Jobs.create() calls
|
|
12
|
+
*/
|
|
13
|
+
export function containsJobsCreate(code) {
|
|
14
|
+
const found = /Jobs\.create\s*\(/i.test(code);
|
|
15
|
+
if (found) {
|
|
16
|
+
console.log('[DynamicJobs] ✅ Detected Jobs.create() in code');
|
|
17
|
+
}
|
|
18
|
+
return found;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extracts Jobs.create() execute functions and bundles them with dependencies.
|
|
22
|
+
* Finds execute functions in the code and creates standalone bundles.
|
|
23
|
+
*/
|
|
24
|
+
export async function bundleNestedJobs(code, parentName, distDir) {
|
|
25
|
+
if (!containsJobsCreate(code)) {
|
|
26
|
+
return code;
|
|
27
|
+
}
|
|
28
|
+
console.log(`[DynamicJobs] ⚠️ Jobs.create() with external dependencies not yet fully supported`);
|
|
29
|
+
console.log(`[DynamicJobs] 💡 Recommendation: Use fetch() or lua-cli APIs in job execute functions`);
|
|
30
|
+
console.log(`[DynamicJobs] 📋 Full bundling support planned for v3.1.0`);
|
|
31
|
+
// Return original code as-is
|
|
32
|
+
// The job will have access to lua-cli globals but external packages won't be bundled
|
|
33
|
+
return code;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Helper to extract job execute function from code
|
|
37
|
+
*/
|
|
38
|
+
function extractJobExecuteFromCode(code) {
|
|
39
|
+
// This extracts the execute function body
|
|
40
|
+
// For now, return a placeholder that indicates the limitation
|
|
41
|
+
return `
|
|
42
|
+
// Note: This job execute function runs with limited context
|
|
43
|
+
// Use fetch() for external APIs or lua-cli globals (User, Data, Products)
|
|
44
|
+
console.log('Job execute running with user:', user);
|
|
45
|
+
return { executed: true };
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Bundles a job's execute function independently
|
|
50
|
+
*/
|
|
51
|
+
async function bundleJobExecuteFunction(executeFunction, jobName, distDir) {
|
|
52
|
+
const tempDir = path.join(distDir, '.temp');
|
|
53
|
+
if (!fs.existsSync(tempDir)) {
|
|
54
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
const tempFile = path.join(tempDir, `${jobName}.js`);
|
|
57
|
+
const tempOutput = path.join(tempDir, `${jobName}-bundled.js`);
|
|
58
|
+
try {
|
|
59
|
+
// Extract imports that the execute function might need
|
|
60
|
+
// Common ones: Stripe, axios, etc.
|
|
61
|
+
const moduleCode = `
|
|
62
|
+
// Job execute function for ${jobName}
|
|
63
|
+
// Import dependencies that might be used
|
|
64
|
+
import Stripe from 'stripe';
|
|
65
|
+
import { env, User, Data, Products, Baskets, Orders } from 'lua-cli';
|
|
66
|
+
|
|
67
|
+
// The execute function with all dependencies available
|
|
68
|
+
const executeFunc = ${executeFunction};
|
|
69
|
+
|
|
70
|
+
// Export as default for esbuild to bundle
|
|
71
|
+
export default executeFunc;
|
|
72
|
+
`;
|
|
73
|
+
fs.writeFileSync(tempFile, moduleCode);
|
|
74
|
+
// Bundle with esbuild - bundle ALL dependencies (including Stripe, axios, etc.)
|
|
75
|
+
await build({
|
|
76
|
+
entryPoints: [tempFile],
|
|
77
|
+
bundle: true,
|
|
78
|
+
platform: 'node',
|
|
79
|
+
target: 'node16',
|
|
80
|
+
format: 'cjs',
|
|
81
|
+
minify: true,
|
|
82
|
+
outfile: tempOutput,
|
|
83
|
+
external: [], // Bundle everything except lua-cli APIs (handled by plugin)
|
|
84
|
+
plugins: [sandboxGlobalsPlugin], // This handles lua-cli globals
|
|
85
|
+
// Important: Don't externalize packages like stripe, axios, etc.
|
|
86
|
+
// They need to be included in the bundle
|
|
87
|
+
});
|
|
88
|
+
// Read bundled code (includes all dependencies like Stripe, axios, etc.)
|
|
89
|
+
let bundledCode = fs.readFileSync(tempOutput, 'utf8');
|
|
90
|
+
// Log bundle size for debugging
|
|
91
|
+
console.log(`[DynamicJobs] Bundled size for ${jobName}: ${(bundledCode.length / 1024).toFixed(2)}KB`);
|
|
92
|
+
// Wrap for VM execution - the bundled code includes ALL dependencies
|
|
93
|
+
const wrappedCode = `(async (job) => {
|
|
94
|
+
|
|
95
|
+
${bundledCode}
|
|
96
|
+
|
|
97
|
+
// Get the execute function from exports
|
|
98
|
+
const executeFunction = module.exports || module.exports.default;
|
|
99
|
+
|
|
100
|
+
// Execute with job
|
|
101
|
+
return await executeFunction(job);
|
|
102
|
+
})`;
|
|
103
|
+
// Compress the wrapped code
|
|
104
|
+
const compressed = compressCode(wrappedCode);
|
|
105
|
+
// Clean up temp files
|
|
106
|
+
try {
|
|
107
|
+
fs.unlinkSync(tempFile);
|
|
108
|
+
fs.unlinkSync(tempOutput);
|
|
109
|
+
}
|
|
110
|
+
catch (cleanupError) {
|
|
111
|
+
// Ignore cleanup errors
|
|
112
|
+
}
|
|
113
|
+
return compressed;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
console.warn(`Warning: Could not bundle job execute function ${jobName}:`, error);
|
|
117
|
+
// Clean up on error
|
|
118
|
+
try {
|
|
119
|
+
if (fs.existsSync(tempFile))
|
|
120
|
+
fs.unlinkSync(tempFile);
|
|
121
|
+
if (fs.existsSync(tempOutput))
|
|
122
|
+
fs.unlinkSync(tempOutput);
|
|
123
|
+
}
|
|
124
|
+
catch (cleanupError) {
|
|
125
|
+
// Ignore cleanup errors
|
|
126
|
+
}
|
|
127
|
+
return '';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Cleans up temporary bundling directory
|
|
132
|
+
*/
|
|
133
|
+
export function cleanupTempDir(distDir) {
|
|
134
|
+
const tempDir = path.join(distDir, '.temp');
|
|
135
|
+
if (fs.existsSync(tempDir)) {
|
|
136
|
+
try {
|
|
137
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
// Ignore cleanup errors
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-Bundle Jobs - Extract and bundle Jobs.create() before tool bundling
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Detect Jobs.create() in source
|
|
6
|
+
* 2. Extract execute function
|
|
7
|
+
* 3. Bundle execute with ALL dependencies
|
|
8
|
+
* 4. Replace execute with placeholder
|
|
9
|
+
* 5. Bundle tool/webhook/job
|
|
10
|
+
* 6. Replace placeholder with bundled job code
|
|
11
|
+
* 7. Compress
|
|
12
|
+
*/
|
|
13
|
+
import { Project } from 'ts-morph';
|
|
14
|
+
/**
|
|
15
|
+
* Pre-processes source file to extract and bundle Jobs.create() execute functions
|
|
16
|
+
* Returns modified source code with placeholders
|
|
17
|
+
*/
|
|
18
|
+
export declare function preBundleJobsInSource(sourceFilePath: string, project: Project, distDir: string): Promise<{
|
|
19
|
+
modifiedSource: string;
|
|
20
|
+
jobBundles: Map<string, string>;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Replaces placeholders in bundled code with actual job bundles
|
|
24
|
+
* The bundled job code is NOT compressed - it's JavaScript that will be part of the tool
|
|
25
|
+
*/
|
|
26
|
+
export declare function replaceJobPlaceholders(bundledCode: string, jobBundles: Map<string, string>): string;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-Bundle Jobs - Extract and bundle Jobs.create() before tool bundling
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Detect Jobs.create() in source
|
|
6
|
+
* 2. Extract execute function
|
|
7
|
+
* 3. Bundle execute with ALL dependencies
|
|
8
|
+
* 4. Replace execute with placeholder
|
|
9
|
+
* 5. Bundle tool/webhook/job
|
|
10
|
+
* 6. Replace placeholder with bundled job code
|
|
11
|
+
* 7. Compress
|
|
12
|
+
*/
|
|
13
|
+
import { Node } from 'ts-morph';
|
|
14
|
+
import { build } from 'esbuild';
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { sandboxGlobalsPlugin } from './bundling.js';
|
|
18
|
+
const JOB_PLACEHOLDER = '__BUNDLED_JOB_EXECUTE__';
|
|
19
|
+
/**
|
|
20
|
+
* Pre-processes source file to extract and bundle Jobs.create() execute functions
|
|
21
|
+
* Returns modified source code with placeholders
|
|
22
|
+
*/
|
|
23
|
+
export async function preBundleJobsInSource(sourceFilePath, project, distDir) {
|
|
24
|
+
const sourceFile = project.getSourceFile(sourceFilePath);
|
|
25
|
+
if (!sourceFile) {
|
|
26
|
+
return { modifiedSource: fs.readFileSync(sourceFilePath, 'utf8'), jobBundles: new Map() };
|
|
27
|
+
}
|
|
28
|
+
const jobBundles = new Map();
|
|
29
|
+
const bundlingPromises = [];
|
|
30
|
+
let jobIndex = 0;
|
|
31
|
+
let modifiedSource = sourceFile.getFullText();
|
|
32
|
+
// Find all Jobs.create() calls
|
|
33
|
+
sourceFile.forEachDescendant((node) => {
|
|
34
|
+
if (Node.isCallExpression(node)) {
|
|
35
|
+
const expression = node.getExpression();
|
|
36
|
+
// Check if this is Jobs.create()
|
|
37
|
+
if (Node.isPropertyAccessExpression(expression)) {
|
|
38
|
+
const object = expression.getExpression();
|
|
39
|
+
const property = expression.getName();
|
|
40
|
+
if (object.getText() === 'Jobs' && property === 'create') {
|
|
41
|
+
jobIndex++;
|
|
42
|
+
const placeholder = `${JOB_PLACEHOLDER}_${jobIndex}`;
|
|
43
|
+
console.log(`[PreBundleJobs] Found Jobs.create() #${jobIndex}`);
|
|
44
|
+
// Get the config object argument
|
|
45
|
+
const args = node.getArguments();
|
|
46
|
+
if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
|
|
47
|
+
const configObj = args[0];
|
|
48
|
+
// Find the execute property
|
|
49
|
+
const executeProperty = configObj.getProperty('execute');
|
|
50
|
+
if (executeProperty && Node.isPropertyAssignment(executeProperty)) {
|
|
51
|
+
const executeInitializer = executeProperty.getInitializer();
|
|
52
|
+
if (executeInitializer) {
|
|
53
|
+
const executeCode = executeInitializer.getText();
|
|
54
|
+
console.log(`[PreBundleJobs] Extracting execute function for bundling...`);
|
|
55
|
+
// Bundle the execute function with dependencies (async)
|
|
56
|
+
const bundlePromise = bundleJobExecuteFunction(executeCode, `job_${jobIndex}`, distDir, sourceFilePath).then(bundledCode => {
|
|
57
|
+
if (bundledCode) {
|
|
58
|
+
jobBundles.set(placeholder, bundledCode);
|
|
59
|
+
console.log(`[PreBundleJobs] ✅ Bundled job #${jobIndex} with dependencies`);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
bundlingPromises.push(bundlePromise);
|
|
63
|
+
// Replace execute function with a function that references the bundled code
|
|
64
|
+
// Don't use string placeholder - use a reference
|
|
65
|
+
const originalText = executeProperty.getText();
|
|
66
|
+
const replacementText = `execute: ${placeholder}`;
|
|
67
|
+
modifiedSource = modifiedSource.replace(originalText, replacementText);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// Wait for all bundling to complete
|
|
76
|
+
if (bundlingPromises.length > 0) {
|
|
77
|
+
console.log(`[PreBundleJobs] Waiting for ${bundlingPromises.length} job(s) to bundle...`);
|
|
78
|
+
await Promise.all(bundlingPromises);
|
|
79
|
+
console.log(`[PreBundleJobs] ✅ All job bundles complete`);
|
|
80
|
+
}
|
|
81
|
+
return { modifiedSource, jobBundles };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Bundles a job execute function with all its dependencies
|
|
85
|
+
*/
|
|
86
|
+
async function bundleJobExecuteFunction(executeCode, jobName, distDir, sourceFilePath) {
|
|
87
|
+
const tempDir = path.join(distDir, '.temp');
|
|
88
|
+
if (!fs.existsSync(tempDir)) {
|
|
89
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
const tempOutput = path.join(tempDir, `${jobName}-bundled.js`);
|
|
92
|
+
try {
|
|
93
|
+
// Read the original source file to get its imports
|
|
94
|
+
const sourceContent = fs.readFileSync(sourceFilePath, 'utf8');
|
|
95
|
+
// Extract all import statements from the source
|
|
96
|
+
const importPattern = /^import\s+.+\s+from\s+['"][^'"]+['"];?$/gm;
|
|
97
|
+
const imports = sourceContent.match(importPattern) || [];
|
|
98
|
+
// Filter to only imports that might be used (exclude lua-cli internal classes and APIs)
|
|
99
|
+
const relevantImports = imports.filter(imp => !imp.includes('LuaTool') &&
|
|
100
|
+
!imp.includes('LuaWebhook') &&
|
|
101
|
+
!imp.includes('LuaJob') &&
|
|
102
|
+
!imp.includes('lua-cli') && // Exclude all lua-cli imports (they're available in sandbox)
|
|
103
|
+
!imp.includes('api-exports') && // Exclude api-exports
|
|
104
|
+
!imp.includes('../../../dist/api-exports') // Exclude direct api-exports imports
|
|
105
|
+
);
|
|
106
|
+
console.log(`[PreBundleJobs] Including ${relevantImports.length} import(s) in job bundle`);
|
|
107
|
+
// Create a TypeScript module with the execute function and all imports
|
|
108
|
+
const moduleCode = `
|
|
109
|
+
// Auto-generated job execute bundle
|
|
110
|
+
${relevantImports.join('\n')}
|
|
111
|
+
|
|
112
|
+
// The execute function with all dependencies available
|
|
113
|
+
const executeFunc = ${executeCode};
|
|
114
|
+
|
|
115
|
+
export default executeFunc;
|
|
116
|
+
`;
|
|
117
|
+
// Bundle with esbuild using stdin to preserve import resolution
|
|
118
|
+
await build({
|
|
119
|
+
stdin: {
|
|
120
|
+
contents: moduleCode,
|
|
121
|
+
resolveDir: path.dirname(sourceFilePath),
|
|
122
|
+
sourcefile: sourceFilePath,
|
|
123
|
+
loader: 'ts',
|
|
124
|
+
},
|
|
125
|
+
bundle: true,
|
|
126
|
+
platform: 'node',
|
|
127
|
+
target: 'node16',
|
|
128
|
+
format: 'cjs',
|
|
129
|
+
minify: true,
|
|
130
|
+
outfile: tempOutput,
|
|
131
|
+
external: [],
|
|
132
|
+
plugins: [sandboxGlobalsPlugin],
|
|
133
|
+
});
|
|
134
|
+
// Read bundled code
|
|
135
|
+
const bundledCode = fs.readFileSync(tempOutput, 'utf8');
|
|
136
|
+
console.log(`[PreBundleJobs] Bundle size: ${(bundledCode.length / 1024).toFixed(2)}KB`);
|
|
137
|
+
// DON'T compress - just wrap for VM execution
|
|
138
|
+
// Compression happens later when the entire tool is bundled
|
|
139
|
+
const wrappedCode = `(async (job) => {
|
|
140
|
+
${bundledCode}
|
|
141
|
+
const executeFunction = module.exports.default || module.exports;
|
|
142
|
+
return await executeFunction(job);
|
|
143
|
+
})`;
|
|
144
|
+
// Cleanup temp files
|
|
145
|
+
try {
|
|
146
|
+
fs.unlinkSync(tempOutput);
|
|
147
|
+
}
|
|
148
|
+
catch { }
|
|
149
|
+
// Return uncompressed bundled code
|
|
150
|
+
return wrappedCode;
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.warn(`[PreBundleJobs] Error bundling job ${jobName}:`, error);
|
|
154
|
+
try {
|
|
155
|
+
if (fs.existsSync(tempOutput))
|
|
156
|
+
fs.unlinkSync(tempOutput);
|
|
157
|
+
}
|
|
158
|
+
catch { }
|
|
159
|
+
return '';
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Replaces placeholders in bundled code with actual job bundles
|
|
164
|
+
* The bundled job code is NOT compressed - it's JavaScript that will be part of the tool
|
|
165
|
+
*/
|
|
166
|
+
export function replaceJobPlaceholders(bundledCode, jobBundles) {
|
|
167
|
+
let result = bundledCode;
|
|
168
|
+
jobBundles.forEach((bundledJobCode, placeholder) => {
|
|
169
|
+
// The placeholder is used as an identifier (not a string), just replace it directly
|
|
170
|
+
// It appears as: execute: __BUNDLED_JOB_EXECUTE___1
|
|
171
|
+
const placeholderPattern = new RegExp(placeholder, 'g');
|
|
172
|
+
result = result.replace(placeholderPattern, bundledJobCode);
|
|
173
|
+
console.log(`[PreBundleJobs] ✅ Replaced ${placeholder} with bundled code (${(bundledJobCode.length / 1024).toFixed(1)}KB)`);
|
|
174
|
+
});
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
@@ -25,3 +25,51 @@ export declare function setSandboxSkillId(sandboxId: string, skillName?: string)
|
|
|
25
25
|
* @returns Array of skill overrides with skillId and sandboxId pairs
|
|
26
26
|
*/
|
|
27
27
|
export declare function getAllSandboxSkillIds(deployData: any): Promise<SkillOverride[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Retrieves sandbox preprocessor ID from secure storage.
|
|
30
|
+
*
|
|
31
|
+
* @param preprocessorName - Preprocessor name
|
|
32
|
+
* @returns The sandbox preprocessor ID or null if not found
|
|
33
|
+
*/
|
|
34
|
+
export declare function getSandboxPreProcessorId(preprocessorName: string): Promise<string | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Stores sandbox preprocessor ID in secure storage.
|
|
37
|
+
*
|
|
38
|
+
* @param sandboxId - The sandbox preprocessor ID to store
|
|
39
|
+
* @param preprocessorName - Preprocessor name
|
|
40
|
+
*/
|
|
41
|
+
export declare function setSandboxPreProcessorId(sandboxId: string, preprocessorName: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Retrieves sandbox postprocessor ID from secure storage.
|
|
44
|
+
*
|
|
45
|
+
* @param postprocessorName - Postprocessor name
|
|
46
|
+
* @returns The sandbox postprocessor ID or null if not found
|
|
47
|
+
*/
|
|
48
|
+
export declare function getSandboxPostProcessorId(postprocessorName: string): Promise<string | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Stores sandbox postprocessor ID in secure storage.
|
|
51
|
+
*
|
|
52
|
+
* @param sandboxId - The sandbox postprocessor ID to store
|
|
53
|
+
* @param postprocessorName - Postprocessor name
|
|
54
|
+
*/
|
|
55
|
+
export declare function setSandboxPostProcessorId(sandboxId: string, postprocessorName: string): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Gets all sandbox preprocessor overrides for the current config.
|
|
58
|
+
*
|
|
59
|
+
* @param config - Configuration with preprocessors
|
|
60
|
+
* @returns Array of preprocessor overrides
|
|
61
|
+
*/
|
|
62
|
+
export declare function getAllSandboxPreProcessorIds(config: any): Promise<Array<{
|
|
63
|
+
preprocessorId: string;
|
|
64
|
+
sandboxId: string;
|
|
65
|
+
}>>;
|
|
66
|
+
/**
|
|
67
|
+
* Gets all sandbox postprocessor overrides for the current config.
|
|
68
|
+
*
|
|
69
|
+
* @param config - Configuration with postprocessors
|
|
70
|
+
* @returns Array of postprocessor overrides
|
|
71
|
+
*/
|
|
72
|
+
export declare function getAllSandboxPostProcessorIds(config: any): Promise<Array<{
|
|
73
|
+
postprocessorId: string;
|
|
74
|
+
sandboxId: string;
|
|
75
|
+
}>>;
|