lua-cli 3.0.0-alpha.1 → 3.0.0-alpha.11
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/chat.api.service.d.ts +8 -0
- package/dist/api/chat.api.service.js +55 -0
- 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 +27 -7
- package/dist/api-exports.js +48 -30
- package/dist/cli/command-definitions.js +13 -6
- package/dist/commands/chat.js +71 -39
- package/dist/commands/compile.js +16 -2
- package/dist/commands/dev.js +23 -2
- package/dist/commands/push.d.ts +3 -2
- package/dist/commands/push.js +536 -6
- 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/services/auth.d.ts +8 -2
- package/dist/services/auth.js +35 -3
- 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 -8
- package/package.json +1 -1
- package/template/env.example +5 -0
- 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-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
|
+
}>>;
|
|
@@ -69,3 +69,117 @@ export async function getAllSandboxSkillIds(deployData) {
|
|
|
69
69
|
}
|
|
70
70
|
return skillOverrides;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Retrieves sandbox preprocessor ID from secure storage.
|
|
74
|
+
*
|
|
75
|
+
* @param preprocessorName - Preprocessor name
|
|
76
|
+
* @returns The sandbox preprocessor ID or null if not found
|
|
77
|
+
*/
|
|
78
|
+
export async function getSandboxPreProcessorId(preprocessorName) {
|
|
79
|
+
try {
|
|
80
|
+
const account = `${SANDBOX_STORAGE.ACCOUNT}_preprocessor_${preprocessorName}`;
|
|
81
|
+
return await keytar.getPassword(SANDBOX_STORAGE.SERVICE, account);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Stores sandbox preprocessor ID in secure storage.
|
|
89
|
+
*
|
|
90
|
+
* @param sandboxId - The sandbox preprocessor ID to store
|
|
91
|
+
* @param preprocessorName - Preprocessor name
|
|
92
|
+
*/
|
|
93
|
+
export async function setSandboxPreProcessorId(sandboxId, preprocessorName) {
|
|
94
|
+
try {
|
|
95
|
+
const account = `${SANDBOX_STORAGE.ACCOUNT}_preprocessor_${preprocessorName}`;
|
|
96
|
+
await keytar.setPassword(SANDBOX_STORAGE.SERVICE, account, sandboxId);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
// Ignore storage errors
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Retrieves sandbox postprocessor ID from secure storage.
|
|
104
|
+
*
|
|
105
|
+
* @param postprocessorName - Postprocessor name
|
|
106
|
+
* @returns The sandbox postprocessor ID or null if not found
|
|
107
|
+
*/
|
|
108
|
+
export async function getSandboxPostProcessorId(postprocessorName) {
|
|
109
|
+
try {
|
|
110
|
+
const account = `${SANDBOX_STORAGE.ACCOUNT}_postprocessor_${postprocessorName}`;
|
|
111
|
+
return await keytar.getPassword(SANDBOX_STORAGE.SERVICE, account);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Stores sandbox postprocessor ID in secure storage.
|
|
119
|
+
*
|
|
120
|
+
* @param sandboxId - The sandbox postprocessor ID to store
|
|
121
|
+
* @param postprocessorName - Postprocessor name
|
|
122
|
+
*/
|
|
123
|
+
export async function setSandboxPostProcessorId(sandboxId, postprocessorName) {
|
|
124
|
+
try {
|
|
125
|
+
const account = `${SANDBOX_STORAGE.ACCOUNT}_postprocessor_${postprocessorName}`;
|
|
126
|
+
await keytar.setPassword(SANDBOX_STORAGE.SERVICE, account, sandboxId);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
// Ignore storage errors
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Gets all sandbox preprocessor overrides for the current config.
|
|
134
|
+
*
|
|
135
|
+
* @param config - Configuration with preprocessors
|
|
136
|
+
* @returns Array of preprocessor overrides
|
|
137
|
+
*/
|
|
138
|
+
export async function getAllSandboxPreProcessorIds(config) {
|
|
139
|
+
const overrides = [];
|
|
140
|
+
try {
|
|
141
|
+
const preprocessors = config.preprocessors || [];
|
|
142
|
+
for (const preprocessor of preprocessors) {
|
|
143
|
+
if (preprocessor.preprocessorId && preprocessor.name) {
|
|
144
|
+
const sandboxId = await getSandboxPreProcessorId(preprocessor.name);
|
|
145
|
+
if (sandboxId) {
|
|
146
|
+
overrides.push({
|
|
147
|
+
preprocessorId: preprocessor.preprocessorId,
|
|
148
|
+
sandboxId: sandboxId
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
console.error('Error getting sandbox preprocessor IDs:', error);
|
|
156
|
+
}
|
|
157
|
+
return overrides;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Gets all sandbox postprocessor overrides for the current config.
|
|
161
|
+
*
|
|
162
|
+
* @param config - Configuration with postprocessors
|
|
163
|
+
* @returns Array of postprocessor overrides
|
|
164
|
+
*/
|
|
165
|
+
export async function getAllSandboxPostProcessorIds(config) {
|
|
166
|
+
const overrides = [];
|
|
167
|
+
try {
|
|
168
|
+
const postprocessors = config.postprocessors || [];
|
|
169
|
+
for (const postprocessor of postprocessors) {
|
|
170
|
+
if (postprocessor.postprocessorId && postprocessor.name) {
|
|
171
|
+
const sandboxId = await getSandboxPostProcessorId(postprocessor.name);
|
|
172
|
+
if (sandboxId) {
|
|
173
|
+
overrides.push({
|
|
174
|
+
postprocessorId: postprocessor.postprocessorId,
|
|
175
|
+
sandboxId: sandboxId
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
console.error('Error getting sandbox postprocessor IDs:', error);
|
|
183
|
+
}
|
|
184
|
+
return overrides;
|
|
185
|
+
}
|
package/dist/utils/sandbox.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface ExecuteJobOptions extends SandboxOptions {
|
|
|
20
20
|
}
|
|
21
21
|
export interface ExecutePreProcessorOptions extends SandboxOptions {
|
|
22
22
|
processorCode: string;
|
|
23
|
-
|
|
23
|
+
messages: any[];
|
|
24
24
|
channel: string;
|
|
25
25
|
}
|
|
26
26
|
export interface ExecutePostProcessorOptions extends SandboxOptions {
|
|
@@ -75,7 +75,7 @@ export declare function executeJob(options: ExecuteJobOptions): Promise<any>;
|
|
|
75
75
|
* @param options - PreProcessor execution options
|
|
76
76
|
* @returns Processed message string
|
|
77
77
|
*/
|
|
78
|
-
export declare function executePreProcessor(options: ExecutePreProcessorOptions): Promise<
|
|
78
|
+
export declare function executePreProcessor(options: ExecutePreProcessorOptions): Promise<any[]>;
|
|
79
79
|
/**
|
|
80
80
|
* Executes a postprocessor in a sandboxed environment.
|
|
81
81
|
*
|
package/dist/utils/sandbox.js
CHANGED
|
@@ -13,6 +13,7 @@ import WebhookApi from "../api/webhook.api.service.js";
|
|
|
13
13
|
import JobApi from "../api/job.api.service.js";
|
|
14
14
|
import { BasketStatus } from "../interfaces/baskets.js";
|
|
15
15
|
import { OrderStatus } from "../interfaces/orders.js";
|
|
16
|
+
import { compressCode } from "./compile.js";
|
|
16
17
|
/**
|
|
17
18
|
* Loads environment variables from multiple sources in priority order:
|
|
18
19
|
* 1. process.env (lowest priority)
|
|
@@ -221,6 +222,7 @@ export function createSandbox(options) {
|
|
|
221
222
|
Products: productService,
|
|
222
223
|
Data: dataService,
|
|
223
224
|
Baskets: basketsService,
|
|
225
|
+
compressCode: compressCode,
|
|
224
226
|
Orders: orderService,
|
|
225
227
|
// Jobs API
|
|
226
228
|
Jobs: {
|
|
@@ -229,14 +231,27 @@ export function createSandbox(options) {
|
|
|
229
231
|
const executeString = typeof config.execute === 'function'
|
|
230
232
|
? config.execute.toString()
|
|
231
233
|
: config.execute;
|
|
232
|
-
// Create job
|
|
234
|
+
// Create job with version and activation
|
|
233
235
|
return await jobService.createJobInstance({
|
|
234
|
-
name: config.name,
|
|
236
|
+
name: config.name + '_' + Date.now(),
|
|
235
237
|
description: config.description,
|
|
236
238
|
context: config.description || '',
|
|
237
239
|
schedule: config.schedule,
|
|
238
240
|
timeout: config.timeout,
|
|
239
|
-
retry: config.retry
|
|
241
|
+
retry: config.retry,
|
|
242
|
+
metadata: config.metadata,
|
|
243
|
+
dynamic: true,
|
|
244
|
+
version: {
|
|
245
|
+
version: '1.0.0',
|
|
246
|
+
description: config.description,
|
|
247
|
+
context: config.description || '',
|
|
248
|
+
code: '',
|
|
249
|
+
executeFunction: executeString,
|
|
250
|
+
timeout: config.timeout,
|
|
251
|
+
retry: config.retry,
|
|
252
|
+
metadata: config.metadata
|
|
253
|
+
},
|
|
254
|
+
activate: config.activate ?? true
|
|
240
255
|
});
|
|
241
256
|
},
|
|
242
257
|
get: async (jobId) => jobService.getJob(jobId)
|
|
@@ -330,9 +345,9 @@ export async function executeWebhook(options) {
|
|
|
330
345
|
const executeFunction = ${webhookCode};
|
|
331
346
|
|
|
332
347
|
// Export the function for testing
|
|
333
|
-
module.exports = async (
|
|
348
|
+
module.exports = async (query, headers, body) => {
|
|
334
349
|
try{
|
|
335
|
-
return await executeFunction(
|
|
350
|
+
return await executeFunction(query, headers, body);
|
|
336
351
|
}catch(e){
|
|
337
352
|
console.error(e);
|
|
338
353
|
return { status: 'error', error: e.message };
|
|
@@ -438,7 +453,7 @@ try{
|
|
|
438
453
|
* @returns Processed message string
|
|
439
454
|
*/
|
|
440
455
|
export async function executePreProcessor(options) {
|
|
441
|
-
const { processorCode,
|
|
456
|
+
const { processorCode, messages, channel, apiKey, agentId } = options;
|
|
442
457
|
// Create sandbox
|
|
443
458
|
const sandbox = createSandbox(options);
|
|
444
459
|
// Get user instance first (outside VM)
|
|
@@ -453,7 +468,7 @@ const executeFunction = ${processorCode};
|
|
|
453
468
|
module.exports = async (input) => {
|
|
454
469
|
try{
|
|
455
470
|
// userInstance is passed as parameter
|
|
456
|
-
return await executeFunction(input.user, input.
|
|
471
|
+
return await executeFunction(input.user, input.messages, input.channel);
|
|
457
472
|
}catch(e){
|
|
458
473
|
console.error(e);
|
|
459
474
|
return { status: 'error', error: e.message };
|
|
@@ -481,7 +496,7 @@ try{
|
|
|
481
496
|
vm.runInContext(commonJsWrapper, context);
|
|
482
497
|
// Get the exported function and execute with user instance
|
|
483
498
|
const executeFunction = context.module.exports;
|
|
484
|
-
return await executeFunction({ user: userInstance,
|
|
499
|
+
return await executeFunction({ user: userInstance, messages, channel });
|
|
485
500
|
}
|
|
486
501
|
/**
|
|
487
502
|
* Executes a postprocessor in a sandboxed environment.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lua-cli",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.11",
|
|
4
4
|
"description": "Command-line interface for Lua AI platform - develop, test, and deploy LuaSkills with custom tools",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"main": "dist/api-exports.js",
|