lua-cli 3.0.2-alpha.1 ā 3.0.2-alpha.3
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/cli/command-definitions.js +1 -0
- package/dist/commands/compile.d.ts +4 -1
- package/dist/commands/compile.js +116 -10
- package/dist/utils/bundling.d.ts +9 -5
- package/dist/utils/bundling.js +215 -188
- package/dist/utils/compile.d.ts +4 -1
- package/dist/utils/compile.js +24 -3
- package/dist/utils/deployment.js +10 -2
- package/dist/utils/pre-bundle-jobs.d.ts +1 -0
- package/dist/utils/pre-bundle-jobs.js +14 -2
- package/package.json +5 -1
- package/template/lua.skill.yaml +1 -0
- package/template/package.json +1 -1
- package/dist/utils/dynamic-job-bundler.d.ts +0 -17
- package/dist/utils/dynamic-job-bundler.js +0 -143
|
@@ -51,6 +51,7 @@ export function setupSkillCommands(program) {
|
|
|
51
51
|
program
|
|
52
52
|
.command("compile")
|
|
53
53
|
.description("š¦ Compile skill to deployable format")
|
|
54
|
+
.option("--debug", "Enable debug mode with verbose logging and temp file preservation")
|
|
54
55
|
.action(compileCommand);
|
|
55
56
|
program
|
|
56
57
|
.command("test [type]")
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
* - Skills deleted from code are removed from YAML
|
|
28
28
|
* - Skills not in YAML are deleted from server (or deactivated if they have versions)
|
|
29
29
|
*
|
|
30
|
+
* @param options - Command options including debug flag
|
|
30
31
|
* @returns Promise that resolves when compilation is complete
|
|
31
32
|
*/
|
|
32
|
-
export declare function compileCommand(
|
|
33
|
+
export declare function compileCommand(options?: {
|
|
34
|
+
debug?: boolean;
|
|
35
|
+
}): Promise<void>;
|
package/dist/commands/compile.js
CHANGED
|
@@ -43,17 +43,43 @@ import { syncAgentPersonaWithYaml } from '../utils/agent-management.js';
|
|
|
43
43
|
* - Skills deleted from code are removed from YAML
|
|
44
44
|
* - Skills not in YAML are deleted from server (or deactivated if they have versions)
|
|
45
45
|
*
|
|
46
|
+
* @param options - Command options including debug flag
|
|
46
47
|
* @returns Promise that resolves when compilation is complete
|
|
47
48
|
*/
|
|
48
|
-
export async function compileCommand() {
|
|
49
|
+
export async function compileCommand(options) {
|
|
49
50
|
return withErrorHandling(async () => {
|
|
51
|
+
const debugMode = options?.debug || process.env.LUA_DEBUG === 'true';
|
|
52
|
+
if (debugMode) {
|
|
53
|
+
console.log('š Debug mode enabled');
|
|
54
|
+
console.log(' - Verbose logging: ON');
|
|
55
|
+
console.log(' - Temp file preservation: ON');
|
|
56
|
+
console.log(' - Full error stacks: ON\n');
|
|
57
|
+
}
|
|
50
58
|
writeProgress("šØ Compiling Lua skill...");
|
|
59
|
+
// Track compilation issues
|
|
60
|
+
const compilationWarnings = [];
|
|
61
|
+
const failedBundles = [];
|
|
62
|
+
const startTime = Date.now();
|
|
51
63
|
// Step 1: Prepare output directories
|
|
64
|
+
if (debugMode)
|
|
65
|
+
console.log('š Preparing output directories...');
|
|
52
66
|
const { distDir, luaDir } = prepareOutputDirectories();
|
|
67
|
+
if (debugMode)
|
|
68
|
+
console.log(` ā Created: ${distDir}`);
|
|
69
|
+
if (debugMode)
|
|
70
|
+
console.log(` ā Created: ${luaDir}\n`);
|
|
53
71
|
// Step 2: Analyze TypeScript project and detect tools
|
|
72
|
+
if (debugMode)
|
|
73
|
+
console.log('š Finding index file...');
|
|
54
74
|
const indexPath = findIndexFile();
|
|
75
|
+
if (debugMode)
|
|
76
|
+
console.log(` ā Found: ${indexPath}\n`);
|
|
77
|
+
if (debugMode)
|
|
78
|
+
console.log('š Creating TypeScript project...');
|
|
55
79
|
const project = createTypeScriptProject();
|
|
56
80
|
const indexFile = project.addSourceFileAtPath(indexPath);
|
|
81
|
+
if (debugMode)
|
|
82
|
+
console.log(` ā Loaded source file\n`);
|
|
57
83
|
// Step 2a: Check for LuaAgent (unified agent configuration)
|
|
58
84
|
writeProgress("š Checking for LuaAgent configuration...");
|
|
59
85
|
const { extractLuaAgentMetadata, resolveLuaAgentReferences, getSkillFilePaths } = await import('../utils/compile.js');
|
|
@@ -69,7 +95,7 @@ export async function compileCommand() {
|
|
|
69
95
|
resolvedAgentData = resolveLuaAgentReferences(agentMetadata, indexFile, project);
|
|
70
96
|
// Get file paths where skills are defined so we can scan them for tools
|
|
71
97
|
skillFilePaths = getSkillFilePaths(agentMetadata, indexFile);
|
|
72
|
-
writeProgress(`š¦ Agent contains: ${resolvedAgentData
|
|
98
|
+
writeProgress(`š¦ Agent contains: ${resolvedAgentData?.skills?.length || 0} skill(s), ${resolvedAgentData?.webhooks?.length || 0} webhook(s), ${resolvedAgentData?.jobs?.length || 0} job(s), ${resolvedAgentData?.preProcessors?.length || 0} preprocessor(s), ${resolvedAgentData?.postProcessors?.length || 0} postprocessor(s)`);
|
|
73
99
|
}
|
|
74
100
|
else {
|
|
75
101
|
writeProgress(`ā¹ļø No LuaAgent found, using legacy detection for individual components`);
|
|
@@ -80,21 +106,41 @@ export async function compileCommand() {
|
|
|
80
106
|
// Step 3: Bundle each tool and extract metadata
|
|
81
107
|
const { preBundleJobsInSource, replaceJobPlaceholders } = await import('../utils/pre-bundle-jobs.js');
|
|
82
108
|
for (const tool of tools) {
|
|
109
|
+
if (debugMode)
|
|
110
|
+
console.log(`\nš§ Processing tool: ${tool.className}`);
|
|
111
|
+
if (debugMode)
|
|
112
|
+
console.log(` File: ${tool.filePath}`);
|
|
83
113
|
// Step 3a: Pre-bundle any Jobs.create() in the tool source
|
|
114
|
+
const toolStartTime = Date.now();
|
|
84
115
|
const { modifiedSource, jobBundles } = await preBundleJobsInSource(tool.filePath, project, distDir);
|
|
116
|
+
if (debugMode && jobBundles.size > 0) {
|
|
117
|
+
console.log(` ā Found ${jobBundles.size} nested job(s) to pre-bundle`);
|
|
118
|
+
}
|
|
85
119
|
// Step 3b: Bundle the tool (with placeholders for job execute functions)
|
|
86
|
-
await bundleTool(tool, distDir, modifiedSource);
|
|
120
|
+
await bundleTool(tool, distDir, modifiedSource, debugMode);
|
|
87
121
|
// Step 3c: Replace placeholders in the bundled tool file
|
|
88
122
|
if (jobBundles.size > 0) {
|
|
89
123
|
const toolBundlePath = path.join(distDir, 'tools', `${tool.className}.js`);
|
|
90
124
|
if (fs.existsSync(toolBundlePath)) {
|
|
91
125
|
let bundledToolCode = fs.readFileSync(toolBundlePath, 'utf8');
|
|
126
|
+
const beforeSize = bundledToolCode.length;
|
|
92
127
|
bundledToolCode = replaceJobPlaceholders(bundledToolCode, jobBundles);
|
|
128
|
+
const afterSize = bundledToolCode.length;
|
|
129
|
+
if (debugMode)
|
|
130
|
+
console.log(` ā Replaced placeholders (+${afterSize - beforeSize} bytes)`);
|
|
93
131
|
fs.writeFileSync(toolBundlePath, bundledToolCode);
|
|
94
132
|
}
|
|
95
133
|
}
|
|
96
134
|
// Step 3d: Extract execute code
|
|
97
135
|
await extractExecuteCode(tool, project, distDir);
|
|
136
|
+
if (debugMode) {
|
|
137
|
+
const toolTime = Date.now() - toolStartTime;
|
|
138
|
+
const bundledPath = path.join(distDir, 'tools', `${tool.className}.js`);
|
|
139
|
+
if (fs.existsSync(bundledPath)) {
|
|
140
|
+
const size = fs.statSync(bundledPath).size;
|
|
141
|
+
console.log(` ā Bundled: ${(size / 1024).toFixed(2)}KB in ${toolTime}ms`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
98
144
|
}
|
|
99
145
|
// Step 4: Bundle the main index file
|
|
100
146
|
await bundleMainIndex(indexPath, distDir);
|
|
@@ -119,8 +165,15 @@ export async function compileCommand() {
|
|
|
119
165
|
writeProgress(`š¦ Found ${webhooksMetadata.length} webhook(s)...`);
|
|
120
166
|
// Bundle each webhook (extract execute function and schemas)
|
|
121
167
|
for (const webhook of webhooksMetadata) {
|
|
122
|
-
|
|
168
|
+
if (debugMode)
|
|
169
|
+
console.log(`\nš Processing webhook: ${webhook.name}`);
|
|
170
|
+
const webhookStartTime = Date.now();
|
|
171
|
+
const bundled = await bundleWebhook(webhook, indexFile, distDir, project, debugMode);
|
|
123
172
|
bundledWebhooks.push(bundled);
|
|
173
|
+
if (debugMode) {
|
|
174
|
+
const webhookTime = Date.now() - webhookStartTime;
|
|
175
|
+
console.log(` ā Completed in ${webhookTime}ms`);
|
|
176
|
+
}
|
|
124
177
|
}
|
|
125
178
|
// Ensure webhooks exist in YAML with valid IDs
|
|
126
179
|
const configForWebhooks = readSkillConfig(); // Re-read for webhooks
|
|
@@ -141,8 +194,15 @@ export async function compileCommand() {
|
|
|
141
194
|
writeProgress(`š¦ Found ${jobsMetadata.length} job(s)...`);
|
|
142
195
|
// Bundle each job (extract execute function)
|
|
143
196
|
for (const job of jobsMetadata) {
|
|
144
|
-
|
|
197
|
+
if (debugMode)
|
|
198
|
+
console.log(`\nāļø Processing job: ${job.name}`);
|
|
199
|
+
const jobStartTime = Date.now();
|
|
200
|
+
const bundled = await bundleJob(job, indexFile, distDir, project, debugMode);
|
|
145
201
|
bundledJobs.push(bundled);
|
|
202
|
+
if (debugMode) {
|
|
203
|
+
const jobTime = Date.now() - jobStartTime;
|
|
204
|
+
console.log(` ā Completed in ${jobTime}ms`);
|
|
205
|
+
}
|
|
146
206
|
}
|
|
147
207
|
// Ensure jobs exist in YAML with valid IDs
|
|
148
208
|
const configForJobs = readSkillConfig(); // Re-read for jobs
|
|
@@ -162,7 +222,9 @@ export async function compileCommand() {
|
|
|
162
222
|
if (preprocessorsMetadata.length > 0) {
|
|
163
223
|
writeProgress(`š¦ Found ${preprocessorsMetadata.length} preprocessor(s)...`);
|
|
164
224
|
for (const preprocessor of preprocessorsMetadata) {
|
|
165
|
-
|
|
225
|
+
if (debugMode)
|
|
226
|
+
console.log(`\nā” Processing preprocessor: ${preprocessor.name}`);
|
|
227
|
+
const bundled = await bundlePreProcessor(preprocessor, indexFile, distDir, project, debugMode);
|
|
166
228
|
bundledPreProcessors.push(bundled);
|
|
167
229
|
}
|
|
168
230
|
// Ensure preprocessors exist in YAML with valid IDs
|
|
@@ -182,7 +244,9 @@ export async function compileCommand() {
|
|
|
182
244
|
if (postprocessorsMetadata.length > 0) {
|
|
183
245
|
writeProgress(`š¦ Found ${postprocessorsMetadata.length} postprocessor(s)...`);
|
|
184
246
|
for (const postprocessor of postprocessorsMetadata) {
|
|
185
|
-
|
|
247
|
+
if (debugMode)
|
|
248
|
+
console.log(`\nā” Processing postprocessor: ${postprocessor.name}`);
|
|
249
|
+
const bundled = await bundlePostProcessor(postprocessor, indexFile, distDir, project, debugMode);
|
|
186
250
|
bundledPostProcessors.push(bundled);
|
|
187
251
|
}
|
|
188
252
|
// Ensure postprocessors exist in YAML with valid IDs
|
|
@@ -194,6 +258,7 @@ export async function compileCommand() {
|
|
|
194
258
|
await syncServerPostProcessorsWithYaml(postprocessorConfig);
|
|
195
259
|
fs.writeFileSync(path.join(distDir, 'postprocessors.json'), JSON.stringify(bundledPostProcessors, null, 2));
|
|
196
260
|
}
|
|
261
|
+
// Build compilation summary
|
|
197
262
|
const summaryParts = [`${tools.length} tools bundled`];
|
|
198
263
|
if (webhooksMetadata.length > 0)
|
|
199
264
|
summaryParts.push(`${webhooksMetadata.length} webhook(s) registered`);
|
|
@@ -203,6 +268,36 @@ export async function compileCommand() {
|
|
|
203
268
|
summaryParts.push(`${preprocessorsMetadata.length} preprocessor(s) registered`);
|
|
204
269
|
if (postprocessorsMetadata.length > 0)
|
|
205
270
|
summaryParts.push(`${postprocessorsMetadata.length} postprocessor(s) registered`);
|
|
271
|
+
// Check for empty bundles (potential failures)
|
|
272
|
+
const emptyBundles = [];
|
|
273
|
+
for (const tool of tools) {
|
|
274
|
+
const bundledPath = path.join(distDir, 'tools', `${tool.className}.js`);
|
|
275
|
+
if (fs.existsSync(bundledPath)) {
|
|
276
|
+
const size = fs.statSync(bundledPath).size;
|
|
277
|
+
if (size < 100) { // Less than 100 bytes is suspiciously small
|
|
278
|
+
emptyBundles.push(`${tool.className} (${size} bytes)`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
emptyBundles.push(`${tool.className} (file missing)`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (emptyBundles.length > 0) {
|
|
286
|
+
console.warn(`\nā ļø Warning: ${emptyBundles.length} tool(s) may have bundling issues:`);
|
|
287
|
+
emptyBundles.forEach(name => console.warn(` - ${name}`));
|
|
288
|
+
console.warn(` Run with NODE_ENV=development for detailed error logs.\n`);
|
|
289
|
+
}
|
|
290
|
+
const totalTime = Date.now() - startTime;
|
|
291
|
+
if (debugMode) {
|
|
292
|
+
console.log(`\nā±ļø Total compilation time: ${(totalTime / 1000).toFixed(2)}s`);
|
|
293
|
+
console.log(`š Output directories:`);
|
|
294
|
+
console.log(` - ${distDir}`);
|
|
295
|
+
console.log(` - ${luaDir}`);
|
|
296
|
+
const tempDir = path.join(distDir, '.temp');
|
|
297
|
+
if (fs.existsSync(tempDir)) {
|
|
298
|
+
console.log(` - ${tempDir} (preserved for debugging)`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
206
301
|
writeSuccess(`ā
Skill compiled successfully - ${summaryParts.join(', ')}`);
|
|
207
302
|
}, "compilation");
|
|
208
303
|
}
|
|
@@ -230,11 +325,22 @@ function prepareOutputDirectories() {
|
|
|
230
325
|
}
|
|
231
326
|
/**
|
|
232
327
|
* Creates and configures a TypeScript project for AST analysis.
|
|
328
|
+
* Validates that tsconfig.json exists before creating project.
|
|
233
329
|
*
|
|
234
330
|
* @returns Configured ts-morph Project instance
|
|
331
|
+
* @throws Error if tsconfig.json is missing or invalid
|
|
235
332
|
*/
|
|
236
333
|
function createTypeScriptProject() {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
334
|
+
const tsconfigPath = path.join(process.cwd(), COMPILE_FILES.TSCONFIG_JSON);
|
|
335
|
+
if (!fs.existsSync(tsconfigPath)) {
|
|
336
|
+
throw new Error(`tsconfig.json not found at ${tsconfigPath}\n` +
|
|
337
|
+
`Please ensure you're in a Lua CLI project directory.`);
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
return new Project({ tsConfigFilePath: tsconfigPath });
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
throw new Error(`Failed to parse tsconfig.json: ${error.message}\n` +
|
|
344
|
+
`Please check that your tsconfig.json is valid.`);
|
|
345
|
+
}
|
|
240
346
|
}
|
package/dist/utils/bundling.d.ts
CHANGED
|
@@ -22,8 +22,10 @@ export declare const sandboxGlobalsPlugin: Plugin;
|
|
|
22
22
|
*
|
|
23
23
|
* @param tool - The tool to bundle
|
|
24
24
|
* @param distDir - The distribution directory for output
|
|
25
|
+
* @param modifiedSource - Optional modified source (for pre-bundled jobs)
|
|
26
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
25
27
|
*/
|
|
26
|
-
export declare function bundleTool(tool: ToolInfo, distDir: string, modifiedSource?: string): Promise<void>;
|
|
28
|
+
export declare function bundleTool(tool: ToolInfo, distDir: string, modifiedSource?: string, debugMode?: boolean): Promise<void>;
|
|
27
29
|
/**
|
|
28
30
|
* Bundles the main index.ts file into a standalone JavaScript file.
|
|
29
31
|
* This creates the entry point for the skill.
|
|
@@ -39,9 +41,10 @@ export declare function bundleMainIndex(indexPath: string, distDir: string): Pro
|
|
|
39
41
|
* @param indexFile - The TypeScript source file containing the webhook
|
|
40
42
|
* @param distDir - Distribution directory for output
|
|
41
43
|
* @param project - Optional ts-morph Project for resolving imports
|
|
44
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
42
45
|
* @returns Webhook with bundled code and schemas
|
|
43
46
|
*/
|
|
44
|
-
export declare function bundleWebhook(webhook: any, indexFile: any, distDir: string, project?: any): Promise<any>;
|
|
47
|
+
export declare function bundleWebhook(webhook: any, indexFile: any, distDir: string, project?: any, debugMode?: boolean): Promise<any>;
|
|
45
48
|
/**
|
|
46
49
|
* Extracts and bundles job execute function.
|
|
47
50
|
*
|
|
@@ -49,17 +52,18 @@ export declare function bundleWebhook(webhook: any, indexFile: any, distDir: str
|
|
|
49
52
|
* @param indexFile - The TypeScript source file containing the job
|
|
50
53
|
* @param distDir - Distribution directory for output
|
|
51
54
|
* @param project - Optional ts-morph Project for resolving imports
|
|
55
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
52
56
|
* @returns Job with bundled code
|
|
53
57
|
*/
|
|
54
|
-
export declare function bundleJob(job: any, indexFile: any, distDir: string, project?: any): Promise<any>;
|
|
58
|
+
export declare function bundleJob(job: any, indexFile: any, distDir: string, project?: any, debugMode?: boolean): Promise<any>;
|
|
55
59
|
/**
|
|
56
60
|
* Bundles and compresses preprocessor execute function code.
|
|
57
61
|
*/
|
|
58
|
-
export declare function bundlePreProcessor(preprocessor: any, indexFile: any, distDir: string, project?: any): Promise<any>;
|
|
62
|
+
export declare function bundlePreProcessor(preprocessor: any, indexFile: any, distDir: string, project?: any, debugMode?: boolean): Promise<any>;
|
|
59
63
|
/**
|
|
60
64
|
* Bundles and compresses postprocessor execute function code.
|
|
61
65
|
*/
|
|
62
|
-
export declare function bundlePostProcessor(postprocessor: any, indexFile: any, distDir: string, project?: any): Promise<any>;
|
|
66
|
+
export declare function bundlePostProcessor(postprocessor: any, indexFile: any, distDir: string, project?: any, debugMode?: boolean): Promise<any>;
|
|
63
67
|
/**
|
|
64
68
|
* Extracts execute code and input schema from a tool.
|
|
65
69
|
* This function:
|
package/dist/utils/bundling.js
CHANGED
|
@@ -7,7 +7,7 @@ import path from "path";
|
|
|
7
7
|
import { build } from "esbuild";
|
|
8
8
|
import { Project, Node } from "ts-morph";
|
|
9
9
|
import { writeProgress } from "./cli.js";
|
|
10
|
-
import { COMPILE_DIRS, COMPILE_FILES, ESBUILD_TOOL_CONFIG, ESBUILD_INDEX_CONFIG, DEFAULT_INPUT_SCHEMA, } from '../config/compile.constants.js';
|
|
10
|
+
import { COMPILE_DIRS, COMPILE_FILES, ESBUILD_TOOL_CONFIG, ESBUILD_INDEX_CONFIG, DEFAULT_INPUT_SCHEMA, EXTERNAL_PACKAGES, } from '../config/compile.constants.js';
|
|
11
11
|
import { wrapToolForVM, createExecuteFunction, evaluateZodSchemaToJsonSchema } from './compile.js';
|
|
12
12
|
/**
|
|
13
13
|
* Helper function to remove lua-cli and api-exports imports from source code.
|
|
@@ -30,6 +30,156 @@ function stripLuaCliImports(sourceCode) {
|
|
|
30
30
|
: '// lua-cli/skill imports removed - using sandbox globals';
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Extracts and filters relevant imports from source code.
|
|
35
|
+
* Removes lua-cli internal classes and API imports that are available in the sandbox.
|
|
36
|
+
*
|
|
37
|
+
* @param sourceFilePath - Path to the source file
|
|
38
|
+
* @returns Array of relevant import statements
|
|
39
|
+
*/
|
|
40
|
+
function extractRelevantImports(sourceFilePath) {
|
|
41
|
+
const sourceContent = fs.readFileSync(sourceFilePath, 'utf8');
|
|
42
|
+
// Extract all import statements from the source
|
|
43
|
+
const importPattern = /^import\s+.+\s+from\s+['"][^'"]+['"];?$/gm;
|
|
44
|
+
const imports = sourceContent.match(importPattern) || [];
|
|
45
|
+
// Filter to only imports that might be used (exclude lua-cli internal classes and APIs)
|
|
46
|
+
return imports.filter(imp => !imp.includes('LuaTool') &&
|
|
47
|
+
!imp.includes('LuaWebhook') &&
|
|
48
|
+
!imp.includes('LuaJob') &&
|
|
49
|
+
!imp.includes('PreProcessor') &&
|
|
50
|
+
!imp.includes('PostProcessor') &&
|
|
51
|
+
!imp.includes('LuaAgent') &&
|
|
52
|
+
!imp.includes('lua-cli') && // Exclude all lua-cli imports (they're available in sandbox)
|
|
53
|
+
!imp.includes('api-exports') && // Exclude api-exports
|
|
54
|
+
!imp.includes('../../../dist/api-exports') // Exclude direct api-exports imports
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Generic function to bundle and compress execute function code with dependencies.
|
|
59
|
+
*
|
|
60
|
+
* @param executeFunction - Raw execute function code
|
|
61
|
+
* @param componentName - Name of the component (webhook/job/processor)
|
|
62
|
+
* @param componentType - Type identifier for temp files
|
|
63
|
+
* @param vmWrapperGenerator - Function that generates the VM wrapper code
|
|
64
|
+
* @param distDir - Distribution directory
|
|
65
|
+
* @param sourceFilePath - Path to source file containing the component
|
|
66
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
67
|
+
* @returns Compressed base64-encoded bundled code
|
|
68
|
+
*/
|
|
69
|
+
async function bundleAndCompressExecuteFunction(executeFunction, componentName, componentType, vmWrapperGenerator, distDir, sourceFilePath, debugMode) {
|
|
70
|
+
const { compressCode } = await import('./compile.js');
|
|
71
|
+
// Create temporary file with the execute function wrapped as a module
|
|
72
|
+
const tempDir = path.join(distDir, '.temp');
|
|
73
|
+
if (!fs.existsSync(tempDir)) {
|
|
74
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
const tempFile = path.join(tempDir, `${componentName}-${componentType}.ts`);
|
|
77
|
+
const tempOutput = path.join(tempDir, `${componentName}-${componentType}.js`);
|
|
78
|
+
try {
|
|
79
|
+
// Extract relevant imports from source file
|
|
80
|
+
const relevantImports = extractRelevantImports(sourceFilePath);
|
|
81
|
+
if (debugMode) {
|
|
82
|
+
console.log(` ā Found ${relevantImports.length} import(s) to bundle`);
|
|
83
|
+
if (relevantImports.length > 0 && debugMode) {
|
|
84
|
+
relevantImports.forEach(imp => console.log(` - ${imp}`));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Write execute function as a module export with all relevant imports
|
|
88
|
+
const moduleCode = `
|
|
89
|
+
// ${componentType} execute function for ${componentName}
|
|
90
|
+
${relevantImports.join('\n')}
|
|
91
|
+
|
|
92
|
+
// The execute function with all dependencies available
|
|
93
|
+
const executeFunc = ${executeFunction};
|
|
94
|
+
|
|
95
|
+
export default executeFunc;
|
|
96
|
+
`;
|
|
97
|
+
fs.writeFileSync(tempFile, moduleCode);
|
|
98
|
+
if (debugMode) {
|
|
99
|
+
console.log(` ā Created temp file: ${path.basename(tempFile)}`);
|
|
100
|
+
}
|
|
101
|
+
// Bundle with esbuild using the source file's directory for import resolution
|
|
102
|
+
await build({
|
|
103
|
+
entryPoints: [tempFile],
|
|
104
|
+
bundle: true,
|
|
105
|
+
platform: 'node',
|
|
106
|
+
target: 'node16',
|
|
107
|
+
format: 'cjs',
|
|
108
|
+
minify: true,
|
|
109
|
+
outfile: tempOutput,
|
|
110
|
+
external: [...EXTERNAL_PACKAGES], // Use same external packages as tools
|
|
111
|
+
plugins: [sandboxGlobalsPlugin],
|
|
112
|
+
absWorkingDir: path.dirname(sourceFilePath), // Use source file's directory for resolution
|
|
113
|
+
});
|
|
114
|
+
// Read bundled code and validate it exists and has content
|
|
115
|
+
if (!fs.existsSync(tempOutput)) {
|
|
116
|
+
throw new Error(`esbuild failed to create output file for ${componentName}`);
|
|
117
|
+
}
|
|
118
|
+
const bundledCode = fs.readFileSync(tempOutput, 'utf8');
|
|
119
|
+
if (bundledCode.length === 0) {
|
|
120
|
+
throw new Error(`esbuild created empty bundle for ${componentName}`);
|
|
121
|
+
}
|
|
122
|
+
// Wrap for VM execution using provided generator
|
|
123
|
+
const wrappedCode = vmWrapperGenerator(bundledCode);
|
|
124
|
+
// Compress the wrapped code
|
|
125
|
+
const compressed = compressCode(wrappedCode);
|
|
126
|
+
if (debugMode) {
|
|
127
|
+
console.log(` ā Bundle size: ${(bundledCode.length / 1024).toFixed(2)}KB (uncompressed)`);
|
|
128
|
+
console.log(` ā Compressed: ${(compressed.length / 1024).toFixed(2)}KB (base64 gzip)`);
|
|
129
|
+
}
|
|
130
|
+
// Clean up temp files (unless in debug mode)
|
|
131
|
+
if (!debugMode) {
|
|
132
|
+
try {
|
|
133
|
+
fs.unlinkSync(tempFile);
|
|
134
|
+
fs.unlinkSync(tempOutput);
|
|
135
|
+
}
|
|
136
|
+
catch (cleanupError) {
|
|
137
|
+
// Ignore cleanup errors
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
console.log(` ā¹ļø Preserved temp files for debugging:`);
|
|
142
|
+
console.log(` - ${tempFile}`);
|
|
143
|
+
console.log(` - ${tempOutput}`);
|
|
144
|
+
}
|
|
145
|
+
return compressed;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
// Provide helpful error messages based on error type
|
|
149
|
+
let errorMessage = `Warning: Could not bundle ${componentType} ${componentName}`;
|
|
150
|
+
if (error.message && error.message.includes('Could not resolve')) {
|
|
151
|
+
errorMessage += `\n Dependency resolution failed: ${error.message}`;
|
|
152
|
+
errorMessage += `\n Hint: Ensure all imported packages are in package.json and run 'npm install'`;
|
|
153
|
+
}
|
|
154
|
+
else if (error.message && error.message.includes('Transform failed')) {
|
|
155
|
+
errorMessage += `\n TypeScript compilation failed: ${error.message}`;
|
|
156
|
+
errorMessage += `\n Hint: Check syntax in ${path.basename(sourceFilePath)}`;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
errorMessage += `: ${error.message || error}`;
|
|
160
|
+
}
|
|
161
|
+
console.warn(errorMessage);
|
|
162
|
+
if (debugMode && error.stack) {
|
|
163
|
+
console.error(' Full stack trace:', error.stack);
|
|
164
|
+
}
|
|
165
|
+
// Clean up on error (unless in debug mode)
|
|
166
|
+
if (!debugMode) {
|
|
167
|
+
try {
|
|
168
|
+
if (fs.existsSync(tempFile))
|
|
169
|
+
fs.unlinkSync(tempFile);
|
|
170
|
+
if (fs.existsSync(tempOutput))
|
|
171
|
+
fs.unlinkSync(tempOutput);
|
|
172
|
+
}
|
|
173
|
+
catch (cleanupError) {
|
|
174
|
+
// Ignore cleanup errors
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
console.log(` ā¹ļø Temp files preserved for debugging (check dist/.temp/)`);
|
|
179
|
+
}
|
|
180
|
+
return '';
|
|
181
|
+
}
|
|
182
|
+
}
|
|
33
183
|
/**
|
|
34
184
|
* esbuild plugin to inject sandbox globals instead of requiring lua-cli
|
|
35
185
|
* This removes require("lua-cli") statements and injects the global API objects
|
|
@@ -109,9 +259,14 @@ export const sandboxGlobalsPlugin = {
|
|
|
109
259
|
*
|
|
110
260
|
* @param tool - The tool to bundle
|
|
111
261
|
* @param distDir - The distribution directory for output
|
|
262
|
+
* @param modifiedSource - Optional modified source (for pre-bundled jobs)
|
|
263
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
112
264
|
*/
|
|
113
|
-
export async function bundleTool(tool, distDir, modifiedSource) {
|
|
114
|
-
|
|
265
|
+
export async function bundleTool(tool, distDir, modifiedSource, debugMode) {
|
|
266
|
+
if (!debugMode)
|
|
267
|
+
writeProgress(`š¦ Bundling ${tool.className}...`);
|
|
268
|
+
if (debugMode)
|
|
269
|
+
console.log(` ā Bundling ${tool.className}...`);
|
|
115
270
|
try {
|
|
116
271
|
const outputPath = path.join(distDir, COMPILE_DIRS.TOOLS, `${tool.className}.js`);
|
|
117
272
|
let entryPoint = tool.filePath;
|
|
@@ -175,8 +330,8 @@ export async function bundleTool(tool, distDir, modifiedSource) {
|
|
|
175
330
|
}
|
|
176
331
|
// Wrap the bundled code for VM execution environment
|
|
177
332
|
await wrapToolForVM(outputPath, tool);
|
|
178
|
-
// Clean up temp file if created
|
|
179
|
-
if (tempFile && fs.existsSync(tempFile)) {
|
|
333
|
+
// Clean up temp file if created (unless in debug mode)
|
|
334
|
+
if (tempFile && fs.existsSync(tempFile) && !debugMode) {
|
|
180
335
|
try {
|
|
181
336
|
fs.unlinkSync(tempFile);
|
|
182
337
|
}
|
|
@@ -184,9 +339,16 @@ export async function bundleTool(tool, distDir, modifiedSource) {
|
|
|
184
339
|
// Ignore cleanup errors
|
|
185
340
|
}
|
|
186
341
|
}
|
|
342
|
+
else if (tempFile && debugMode) {
|
|
343
|
+
if (debugMode)
|
|
344
|
+
console.log(` ā¹ļø Preserved temp file: ${tempFile}`);
|
|
345
|
+
}
|
|
187
346
|
}
|
|
188
347
|
catch (error) {
|
|
189
348
|
console.warn(`Warning: Failed to bundle ${tool.className}:`, error);
|
|
349
|
+
if (debugMode && error instanceof Error) {
|
|
350
|
+
console.error(' Stack trace:', error.stack);
|
|
351
|
+
}
|
|
190
352
|
}
|
|
191
353
|
}
|
|
192
354
|
/**
|
|
@@ -216,16 +378,19 @@ export async function bundleMainIndex(indexPath, distDir) {
|
|
|
216
378
|
* @param indexFile - The TypeScript source file containing the webhook
|
|
217
379
|
* @param distDir - Distribution directory for output
|
|
218
380
|
* @param project - Optional ts-morph Project for resolving imports
|
|
381
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
219
382
|
* @returns Webhook with bundled code and schemas
|
|
220
383
|
*/
|
|
221
|
-
export async function bundleWebhook(webhook, indexFile, distDir, project) {
|
|
222
|
-
|
|
384
|
+
export async function bundleWebhook(webhook, indexFile, distDir, project, debugMode) {
|
|
385
|
+
if (!debugMode)
|
|
386
|
+
writeProgress(`š¦ Bundling webhook ${webhook.name}...`);
|
|
223
387
|
try {
|
|
224
388
|
// Find the LuaWebhook constructor in the AST
|
|
225
389
|
let executeFunction = '';
|
|
226
390
|
let querySchema = undefined;
|
|
227
391
|
let headerSchema = undefined;
|
|
228
392
|
let bodySchema = undefined;
|
|
393
|
+
let sourceFilePath = indexFile.getFilePath();
|
|
229
394
|
// Helper function to search for webhook in a file
|
|
230
395
|
const searchFileForWebhook = (file) => {
|
|
231
396
|
file.forEachDescendant((node) => {
|
|
@@ -271,6 +436,8 @@ export async function bundleWebhook(webhook, indexFile, distDir, project) {
|
|
|
271
436
|
querySchema = foundQuerySchema;
|
|
272
437
|
headerSchema = foundHeaderSchema;
|
|
273
438
|
bodySchema = foundBodySchema;
|
|
439
|
+
// Update source file path to the file where webhook was found
|
|
440
|
+
sourceFilePath = file.getFilePath();
|
|
274
441
|
}
|
|
275
442
|
}
|
|
276
443
|
}
|
|
@@ -315,7 +482,7 @@ export async function bundleWebhook(webhook, indexFile, distDir, project) {
|
|
|
315
482
|
// Bundle and compress the execute function (like tools)
|
|
316
483
|
let compressedCode = '';
|
|
317
484
|
if (executeFunction) {
|
|
318
|
-
compressedCode = await bundleAndCompressWebhookCode(executeFunction, webhook.name, distDir);
|
|
485
|
+
compressedCode = await bundleAndCompressWebhookCode(executeFunction, webhook.name, distDir, sourceFilePath, debugMode);
|
|
319
486
|
}
|
|
320
487
|
return {
|
|
321
488
|
...webhook,
|
|
@@ -332,44 +499,17 @@ export async function bundleWebhook(webhook, indexFile, distDir, project) {
|
|
|
332
499
|
/**
|
|
333
500
|
* Bundles and compresses webhook execute function code.
|
|
334
501
|
* Creates a temporary file, bundles with esbuild, compresses with gzip.
|
|
502
|
+
* Includes all imports from the source file to ensure dependencies are bundled.
|
|
335
503
|
*
|
|
336
504
|
* @param executeFunction - Raw execute function code
|
|
337
505
|
* @param webhookName - Name of the webhook
|
|
338
506
|
* @param distDir - Distribution directory
|
|
507
|
+
* @param sourceFilePath - Path to the source file containing the webhook
|
|
508
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
339
509
|
* @returns Compressed base64-encoded bundled code
|
|
340
510
|
*/
|
|
341
|
-
async function bundleAndCompressWebhookCode(executeFunction, webhookName, distDir) {
|
|
342
|
-
|
|
343
|
-
// Create temporary file with the execute function wrapped as a module
|
|
344
|
-
const tempDir = path.join(distDir, '.temp');
|
|
345
|
-
if (!fs.existsSync(tempDir)) {
|
|
346
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
347
|
-
}
|
|
348
|
-
const tempFile = path.join(tempDir, `${webhookName}-webhook.ts`);
|
|
349
|
-
const tempOutput = path.join(tempDir, `${webhookName}-webhook.js`);
|
|
350
|
-
try {
|
|
351
|
-
// Write execute function as a module export
|
|
352
|
-
const moduleCode = stripLuaCliImports(`
|
|
353
|
-
// Webhook execute function for ${webhookName}
|
|
354
|
-
export default ${executeFunction};
|
|
355
|
-
`);
|
|
356
|
-
fs.writeFileSync(tempFile, moduleCode);
|
|
357
|
-
// Bundle with esbuild
|
|
358
|
-
await build({
|
|
359
|
-
entryPoints: [tempFile],
|
|
360
|
-
bundle: true,
|
|
361
|
-
platform: 'node',
|
|
362
|
-
target: 'node16',
|
|
363
|
-
format: 'cjs',
|
|
364
|
-
minify: true,
|
|
365
|
-
outfile: tempOutput,
|
|
366
|
-
external: [], // Bundle everything
|
|
367
|
-
plugins: [sandboxGlobalsPlugin],
|
|
368
|
-
});
|
|
369
|
-
// Read bundled code
|
|
370
|
-
let bundledCode = fs.readFileSync(tempOutput, 'utf8');
|
|
371
|
-
// Wrap for webhook VM execution (similar to tools)
|
|
372
|
-
const wrappedCode = `(async (query, headers, body) => {
|
|
511
|
+
async function bundleAndCompressWebhookCode(executeFunction, webhookName, distDir, sourceFilePath, debugMode) {
|
|
512
|
+
return bundleAndCompressExecuteFunction(executeFunction, webhookName, 'webhook', (bundledCode) => `(async (query, headers, body) => {
|
|
373
513
|
|
|
374
514
|
// Execute the bundled webhook code
|
|
375
515
|
${bundledCode}
|
|
@@ -379,33 +519,7 @@ export default ${executeFunction};
|
|
|
379
519
|
|
|
380
520
|
// Execute with three separate parameters (not an object)
|
|
381
521
|
return await executeFunction(query, headers, body);
|
|
382
|
-
})
|
|
383
|
-
// Compress the wrapped code
|
|
384
|
-
const compressed = compressCode(wrappedCode);
|
|
385
|
-
// Clean up temp files
|
|
386
|
-
try {
|
|
387
|
-
fs.unlinkSync(tempFile);
|
|
388
|
-
fs.unlinkSync(tempOutput);
|
|
389
|
-
}
|
|
390
|
-
catch (cleanupError) {
|
|
391
|
-
// Ignore cleanup errors
|
|
392
|
-
}
|
|
393
|
-
return compressed;
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
396
|
-
console.warn(`Warning: Could not bundle webhook ${webhookName} code:`, error);
|
|
397
|
-
// Clean up on error
|
|
398
|
-
try {
|
|
399
|
-
if (fs.existsSync(tempFile))
|
|
400
|
-
fs.unlinkSync(tempFile);
|
|
401
|
-
if (fs.existsSync(tempOutput))
|
|
402
|
-
fs.unlinkSync(tempOutput);
|
|
403
|
-
}
|
|
404
|
-
catch (cleanupError) {
|
|
405
|
-
// Ignore cleanup errors
|
|
406
|
-
}
|
|
407
|
-
return '';
|
|
408
|
-
}
|
|
522
|
+
})`, distDir, sourceFilePath, debugMode);
|
|
409
523
|
}
|
|
410
524
|
/**
|
|
411
525
|
* Extracts and bundles job execute function.
|
|
@@ -414,13 +528,16 @@ export default ${executeFunction};
|
|
|
414
528
|
* @param indexFile - The TypeScript source file containing the job
|
|
415
529
|
* @param distDir - Distribution directory for output
|
|
416
530
|
* @param project - Optional ts-morph Project for resolving imports
|
|
531
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
417
532
|
* @returns Job with bundled code
|
|
418
533
|
*/
|
|
419
|
-
export async function bundleJob(job, indexFile, distDir, project) {
|
|
420
|
-
|
|
534
|
+
export async function bundleJob(job, indexFile, distDir, project, debugMode) {
|
|
535
|
+
if (!debugMode)
|
|
536
|
+
writeProgress(`š¦ Bundling job ${job.name}...`);
|
|
421
537
|
try {
|
|
422
538
|
// Find the LuaJob constructor in the AST
|
|
423
539
|
let executeFunction = '';
|
|
540
|
+
let sourceFilePath = indexFile.getFilePath();
|
|
424
541
|
// Helper function to search for job in a file
|
|
425
542
|
const searchFileForJob = (file) => {
|
|
426
543
|
file.forEachDescendant((node) => {
|
|
@@ -451,6 +568,8 @@ export async function bundleJob(job, indexFile, distDir, project) {
|
|
|
451
568
|
// Only set executeFunction if this is the matching job
|
|
452
569
|
if (isMatchingJob && foundExecute) {
|
|
453
570
|
executeFunction = foundExecute;
|
|
571
|
+
// Update source file path to the file where job was found
|
|
572
|
+
sourceFilePath = file.getFilePath();
|
|
454
573
|
}
|
|
455
574
|
}
|
|
456
575
|
}
|
|
@@ -484,7 +603,7 @@ export async function bundleJob(job, indexFile, distDir, project) {
|
|
|
484
603
|
// Bundle and compress the execute function (like tools)
|
|
485
604
|
let compressedCode = '';
|
|
486
605
|
if (executeFunction) {
|
|
487
|
-
compressedCode = await bundleAndCompressJobCode(executeFunction, job.name, distDir);
|
|
606
|
+
compressedCode = await bundleAndCompressJobCode(executeFunction, job.name, distDir, sourceFilePath, debugMode);
|
|
488
607
|
}
|
|
489
608
|
return {
|
|
490
609
|
...job,
|
|
@@ -500,44 +619,17 @@ export async function bundleJob(job, indexFile, distDir, project) {
|
|
|
500
619
|
/**
|
|
501
620
|
* Bundles and compresses job execute function code.
|
|
502
621
|
* Creates a temporary file, bundles with esbuild, compresses with gzip.
|
|
622
|
+
* Includes all imports from the source file to ensure dependencies are bundled.
|
|
503
623
|
*
|
|
504
624
|
* @param executeFunction - Raw execute function code
|
|
505
625
|
* @param jobName - Name of the job
|
|
506
626
|
* @param distDir - Distribution directory
|
|
627
|
+
* @param sourceFilePath - Path to the source file containing the job
|
|
628
|
+
* @param debugMode - Enable verbose logging and preserve temp files
|
|
507
629
|
* @returns Compressed base64-encoded bundled code
|
|
508
630
|
*/
|
|
509
|
-
async function bundleAndCompressJobCode(executeFunction, jobName, distDir) {
|
|
510
|
-
|
|
511
|
-
// Create temporary file with the execute function wrapped as a module
|
|
512
|
-
const tempDir = path.join(distDir, '.temp');
|
|
513
|
-
if (!fs.existsSync(tempDir)) {
|
|
514
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
515
|
-
}
|
|
516
|
-
const tempFile = path.join(tempDir, `${jobName}-job.ts`);
|
|
517
|
-
const tempOutput = path.join(tempDir, `${jobName}-job.js`);
|
|
518
|
-
try {
|
|
519
|
-
// Write execute function as a module export
|
|
520
|
-
const moduleCode = stripLuaCliImports(`
|
|
521
|
-
// Job execute function for ${jobName}
|
|
522
|
-
export default ${executeFunction};
|
|
523
|
-
`);
|
|
524
|
-
fs.writeFileSync(tempFile, moduleCode);
|
|
525
|
-
// Bundle with esbuild
|
|
526
|
-
await build({
|
|
527
|
-
entryPoints: [tempFile],
|
|
528
|
-
bundle: true,
|
|
529
|
-
platform: 'node',
|
|
530
|
-
target: 'node16',
|
|
531
|
-
format: 'cjs',
|
|
532
|
-
minify: true,
|
|
533
|
-
outfile: tempOutput,
|
|
534
|
-
external: [], // Bundle everything
|
|
535
|
-
plugins: [sandboxGlobalsPlugin],
|
|
536
|
-
});
|
|
537
|
-
// Read bundled code
|
|
538
|
-
let bundledCode = fs.readFileSync(tempOutput, 'utf8');
|
|
539
|
-
// Wrap for job VM execution (similar to tools, but accepts job parameter)
|
|
540
|
-
const wrappedCode = `(async (job) => {
|
|
631
|
+
async function bundleAndCompressJobCode(executeFunction, jobName, distDir, sourceFilePath, debugMode) {
|
|
632
|
+
return bundleAndCompressExecuteFunction(executeFunction, jobName, 'job', (bundledCode) => `(async (job) => {
|
|
541
633
|
// Execute the bundled job code
|
|
542
634
|
${bundledCode}
|
|
543
635
|
|
|
@@ -546,41 +638,17 @@ export default ${executeFunction};
|
|
|
546
638
|
|
|
547
639
|
// Execute job with job instance parameter
|
|
548
640
|
return await executeFunction(job);
|
|
549
|
-
})
|
|
550
|
-
// Compress the wrapped code
|
|
551
|
-
const compressed = compressCode(wrappedCode);
|
|
552
|
-
// Clean up temp files
|
|
553
|
-
try {
|
|
554
|
-
fs.unlinkSync(tempFile);
|
|
555
|
-
fs.unlinkSync(tempOutput);
|
|
556
|
-
}
|
|
557
|
-
catch (cleanupError) {
|
|
558
|
-
// Ignore cleanup errors
|
|
559
|
-
}
|
|
560
|
-
return compressed;
|
|
561
|
-
}
|
|
562
|
-
catch (error) {
|
|
563
|
-
console.warn(`Warning: Could not bundle job ${jobName} code:`, error);
|
|
564
|
-
// Clean up on error
|
|
565
|
-
try {
|
|
566
|
-
if (fs.existsSync(tempFile))
|
|
567
|
-
fs.unlinkSync(tempFile);
|
|
568
|
-
if (fs.existsSync(tempOutput))
|
|
569
|
-
fs.unlinkSync(tempOutput);
|
|
570
|
-
}
|
|
571
|
-
catch (cleanupError) {
|
|
572
|
-
// Ignore cleanup errors
|
|
573
|
-
}
|
|
574
|
-
return '';
|
|
575
|
-
}
|
|
641
|
+
})`, distDir, sourceFilePath, debugMode);
|
|
576
642
|
}
|
|
577
643
|
/**
|
|
578
644
|
* Bundles and compresses preprocessor execute function code.
|
|
579
645
|
*/
|
|
580
|
-
export async function bundlePreProcessor(preprocessor, indexFile, distDir, project) {
|
|
581
|
-
|
|
646
|
+
export async function bundlePreProcessor(preprocessor, indexFile, distDir, project, debugMode) {
|
|
647
|
+
if (!debugMode)
|
|
648
|
+
writeProgress(`š¦ Bundling preprocessor ${preprocessor.name}...`);
|
|
582
649
|
try {
|
|
583
650
|
let executeFunction = '';
|
|
651
|
+
let sourceFilePath = indexFile.getFilePath();
|
|
584
652
|
const searchFileForPreProcessor = (file) => {
|
|
585
653
|
file.forEachDescendant((node) => {
|
|
586
654
|
if (Node.isNewExpression(node)) {
|
|
@@ -608,6 +676,8 @@ export async function bundlePreProcessor(preprocessor, indexFile, distDir, proje
|
|
|
608
676
|
});
|
|
609
677
|
if (isMatching && foundExecute) {
|
|
610
678
|
executeFunction = foundExecute;
|
|
679
|
+
// Update source file path to the file where preprocessor was found
|
|
680
|
+
sourceFilePath = file.getFilePath();
|
|
611
681
|
}
|
|
612
682
|
}
|
|
613
683
|
}
|
|
@@ -639,7 +709,7 @@ export async function bundlePreProcessor(preprocessor, indexFile, distDir, proje
|
|
|
639
709
|
}
|
|
640
710
|
let compressedCode = '';
|
|
641
711
|
if (executeFunction) {
|
|
642
|
-
compressedCode = await bundleAndCompressProcessorCode(executeFunction, preprocessor.name, 'pre', distDir);
|
|
712
|
+
compressedCode = await bundleAndCompressProcessorCode(executeFunction, preprocessor.name, 'pre', distDir, sourceFilePath, debugMode);
|
|
643
713
|
}
|
|
644
714
|
return {
|
|
645
715
|
name: preprocessor.name,
|
|
@@ -659,10 +729,12 @@ export async function bundlePreProcessor(preprocessor, indexFile, distDir, proje
|
|
|
659
729
|
/**
|
|
660
730
|
* Bundles and compresses postprocessor execute function code.
|
|
661
731
|
*/
|
|
662
|
-
export async function bundlePostProcessor(postprocessor, indexFile, distDir, project) {
|
|
663
|
-
|
|
732
|
+
export async function bundlePostProcessor(postprocessor, indexFile, distDir, project, debugMode) {
|
|
733
|
+
if (!debugMode)
|
|
734
|
+
writeProgress(`š¦ Bundling postprocessor ${postprocessor.name}...`);
|
|
664
735
|
try {
|
|
665
736
|
let executeFunction = '';
|
|
737
|
+
let sourceFilePath = indexFile.getFilePath();
|
|
666
738
|
const searchFileForPostProcessor = (file) => {
|
|
667
739
|
file.forEachDescendant((node) => {
|
|
668
740
|
if (Node.isNewExpression(node)) {
|
|
@@ -690,6 +762,8 @@ export async function bundlePostProcessor(postprocessor, indexFile, distDir, pro
|
|
|
690
762
|
});
|
|
691
763
|
if (isMatching && foundExecute) {
|
|
692
764
|
executeFunction = foundExecute;
|
|
765
|
+
// Update source file path to the file where postprocessor was found
|
|
766
|
+
sourceFilePath = file.getFilePath();
|
|
693
767
|
}
|
|
694
768
|
}
|
|
695
769
|
}
|
|
@@ -721,7 +795,7 @@ export async function bundlePostProcessor(postprocessor, indexFile, distDir, pro
|
|
|
721
795
|
}
|
|
722
796
|
let compressedCode = '';
|
|
723
797
|
if (executeFunction) {
|
|
724
|
-
compressedCode = await bundleAndCompressProcessorCode(executeFunction, postprocessor.name, 'post', distDir);
|
|
798
|
+
compressedCode = await bundleAndCompressProcessorCode(executeFunction, postprocessor.name, 'post', distDir, sourceFilePath, debugMode);
|
|
725
799
|
}
|
|
726
800
|
return {
|
|
727
801
|
name: postprocessor.name,
|
|
@@ -740,65 +814,18 @@ export async function bundlePostProcessor(postprocessor, indexFile, distDir, pro
|
|
|
740
814
|
}
|
|
741
815
|
/**
|
|
742
816
|
* Bundles and compresses processor execute function code.
|
|
817
|
+
* Includes all imports from the source file to ensure dependencies are bundled.
|
|
743
818
|
*/
|
|
744
|
-
async function bundleAndCompressProcessorCode(executeFunction, processorName, type, distDir) {
|
|
745
|
-
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
749
|
-
}
|
|
750
|
-
const tempFile = path.join(tempDir, `${processorName}-${type}processor.ts`);
|
|
751
|
-
const tempOutput = path.join(tempDir, `${processorName}-${type}processor.js`);
|
|
752
|
-
try {
|
|
753
|
-
// Processor execute functions receive: (user, message, [response], channel)
|
|
754
|
-
const paramList = type === 'pre' ? 'user, message, channel' : 'user, message, response, channel';
|
|
755
|
-
const moduleCode = stripLuaCliImports(`
|
|
756
|
-
// ${type === 'pre' ? 'Pre' : 'Post'}Processor execute function for ${processorName}
|
|
757
|
-
export default ${executeFunction};
|
|
758
|
-
`);
|
|
759
|
-
fs.writeFileSync(tempFile, moduleCode);
|
|
760
|
-
await build({
|
|
761
|
-
entryPoints: [tempFile],
|
|
762
|
-
bundle: true,
|
|
763
|
-
platform: 'node',
|
|
764
|
-
target: 'node16',
|
|
765
|
-
format: 'cjs',
|
|
766
|
-
minify: true,
|
|
767
|
-
outfile: tempOutput,
|
|
768
|
-
external: [],
|
|
769
|
-
plugins: [sandboxGlobalsPlugin],
|
|
770
|
-
});
|
|
771
|
-
let bundledCode = fs.readFileSync(tempOutput, 'utf8');
|
|
772
|
-
const wrappedCode = `(async (${paramList}) => {
|
|
819
|
+
async function bundleAndCompressProcessorCode(executeFunction, processorName, type, distDir, sourceFilePath, debugMode) {
|
|
820
|
+
// Processor execute functions receive: (user, message, [response], channel)
|
|
821
|
+
const paramList = type === 'pre' ? 'user, message, channel' : 'user, message, response, channel';
|
|
822
|
+
return bundleAndCompressExecuteFunction(executeFunction, processorName, `${type}processor`, (bundledCode) => `(async (${paramList}) => {
|
|
773
823
|
// Execute the bundled processor code
|
|
774
824
|
${bundledCode}
|
|
775
825
|
|
|
776
826
|
const executeFunction = module.exports.default || module.exports;
|
|
777
827
|
return await executeFunction(${paramList});
|
|
778
|
-
})
|
|
779
|
-
const compressed = compressCode(wrappedCode);
|
|
780
|
-
try {
|
|
781
|
-
fs.unlinkSync(tempFile);
|
|
782
|
-
fs.unlinkSync(tempOutput);
|
|
783
|
-
}
|
|
784
|
-
catch (cleanupError) {
|
|
785
|
-
// Ignore
|
|
786
|
-
}
|
|
787
|
-
return compressed;
|
|
788
|
-
}
|
|
789
|
-
catch (error) {
|
|
790
|
-
console.warn(`Warning: Could not bundle ${type}processor ${processorName} code:`, error);
|
|
791
|
-
try {
|
|
792
|
-
if (fs.existsSync(tempFile))
|
|
793
|
-
fs.unlinkSync(tempFile);
|
|
794
|
-
if (fs.existsSync(tempOutput))
|
|
795
|
-
fs.unlinkSync(tempOutput);
|
|
796
|
-
}
|
|
797
|
-
catch (cleanupError) {
|
|
798
|
-
// Ignore
|
|
799
|
-
}
|
|
800
|
-
return '';
|
|
801
|
-
}
|
|
828
|
+
})`, distDir, sourceFilePath, debugMode);
|
|
802
829
|
}
|
|
803
830
|
/**
|
|
804
831
|
* Extracts execute code and input schema from a tool.
|
package/dist/utils/compile.d.ts
CHANGED
|
@@ -12,7 +12,10 @@ export declare function compressCode(code: string): string;
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function findIndexFile(): string;
|
|
14
14
|
/**
|
|
15
|
-
* Resolves import path from module specifier
|
|
15
|
+
* Resolves import path from module specifier with support for multiple extensions and index files
|
|
16
|
+
* @param moduleSpecifier - The import path (e.g., './tools/MyTool' or '../utils')
|
|
17
|
+
* @param currentFilePath - The file doing the importing
|
|
18
|
+
* @returns Resolved absolute file path
|
|
16
19
|
*/
|
|
17
20
|
export declare function resolveImportPath(moduleSpecifier: string, currentFilePath: string): string;
|
|
18
21
|
/**
|
package/dist/utils/compile.js
CHANGED
|
@@ -29,16 +29,37 @@ export function findIndexFile() {
|
|
|
29
29
|
throw new Error("index.ts not found in current directory or src/ directory");
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
* Resolves import path from module specifier
|
|
32
|
+
* Resolves import path from module specifier with support for multiple extensions and index files
|
|
33
|
+
* @param moduleSpecifier - The import path (e.g., './tools/MyTool' or '../utils')
|
|
34
|
+
* @param currentFilePath - The file doing the importing
|
|
35
|
+
* @returns Resolved absolute file path
|
|
33
36
|
*/
|
|
34
37
|
export function resolveImportPath(moduleSpecifier, currentFilePath) {
|
|
38
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];
|
|
35
39
|
if (moduleSpecifier.startsWith('./') || moduleSpecifier.startsWith('../')) {
|
|
36
40
|
// Relative import - resolve relative to current file
|
|
37
41
|
const currentDir = path.dirname(currentFilePath);
|
|
38
|
-
|
|
42
|
+
const basePath = path.resolve(currentDir, moduleSpecifier);
|
|
43
|
+
// Try each extension in order
|
|
44
|
+
for (const ext of extensions) {
|
|
45
|
+
const fullPath = ext.startsWith('/') ? path.join(basePath, ext) : basePath + ext;
|
|
46
|
+
if (fs.existsSync(fullPath)) {
|
|
47
|
+
return fullPath;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Fallback: return .ts extension (original behavior)
|
|
51
|
+
return basePath + '.ts';
|
|
39
52
|
}
|
|
40
53
|
else {
|
|
41
|
-
// Absolute import -
|
|
54
|
+
// Absolute import - check in src/ directory
|
|
55
|
+
const srcBase = path.resolve(process.cwd(), 'src', moduleSpecifier);
|
|
56
|
+
for (const ext of extensions) {
|
|
57
|
+
const fullPath = ext.startsWith('/') ? path.join(srcBase, ext) : srcBase + ext;
|
|
58
|
+
if (fs.existsSync(fullPath)) {
|
|
59
|
+
return fullPath;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Fallback: return .ts in src/ (original behavior)
|
|
42
63
|
return path.resolve(process.cwd(), 'src', moduleSpecifier + '.ts');
|
|
43
64
|
}
|
|
44
65
|
}
|
package/dist/utils/deployment.js
CHANGED
|
@@ -56,6 +56,10 @@ function readPackageJson() {
|
|
|
56
56
|
*/
|
|
57
57
|
export async function createLegacyDeploymentData(tools, luaDir, indexFile, agentData) {
|
|
58
58
|
const config = readSkillConfig();
|
|
59
|
+
// Handle null config gracefully
|
|
60
|
+
if (!config) {
|
|
61
|
+
console.warn('ā ļø Warning: lua.skill.yaml not found. Creating deployment with default configuration.');
|
|
62
|
+
}
|
|
59
63
|
let skillsMetadata;
|
|
60
64
|
// Check if we have agent data (from LuaAgent approach)
|
|
61
65
|
if (agentData && agentData.skills && agentData.skills.length > 0) {
|
|
@@ -75,9 +79,9 @@ export async function createLegacyDeploymentData(tools, luaDir, indexFile, agent
|
|
|
75
79
|
// Build skills array with their associated tools
|
|
76
80
|
const skillsArray = buildSkillsArray(skillsMetadata, skillToTools, tools);
|
|
77
81
|
// Ensure all skills exist in YAML config and have valid IDs
|
|
78
|
-
const updatedSkillsArray = await ensureSkillsExistInYaml(skillsArray, config);
|
|
82
|
+
const updatedSkillsArray = config ? await ensureSkillsExistInYaml(skillsArray, config) : skillsArray;
|
|
79
83
|
// Override versions from YAML config if they exist
|
|
80
|
-
const finalSkillsArray = overrideVersionsFromConfig(updatedSkillsArray, config);
|
|
84
|
+
const finalSkillsArray = config ? overrideVersionsFromConfig(updatedSkillsArray, config) : updatedSkillsArray;
|
|
81
85
|
// Write deployment data
|
|
82
86
|
const deployData = {
|
|
83
87
|
skills: finalSkillsArray
|
|
@@ -169,6 +173,10 @@ function buildSkillsArray(skillsMetadata, skillToTools, tools) {
|
|
|
169
173
|
* @returns Skills array with versions overridden from config
|
|
170
174
|
*/
|
|
171
175
|
function overrideVersionsFromConfig(skillsArray, config) {
|
|
176
|
+
// Handle null config
|
|
177
|
+
if (!config) {
|
|
178
|
+
return skillsArray;
|
|
179
|
+
}
|
|
172
180
|
// Get version map from YAML config
|
|
173
181
|
const configVersionMap = new Map();
|
|
174
182
|
if (config.skills && Array.isArray(config.skills)) {
|
|
@@ -22,5 +22,6 @@ export declare function preBundleJobsInSource(sourceFilePath: string, project: P
|
|
|
22
22
|
/**
|
|
23
23
|
* Replaces placeholders in bundled code with actual job bundles
|
|
24
24
|
* The bundled job code is NOT compressed - it's JavaScript that will be part of the tool
|
|
25
|
+
* Validates that all placeholders are found and replaced
|
|
25
26
|
*/
|
|
26
27
|
export declare function replaceJobPlaceholders(bundledCode: string, jobBundles: Map<string, string>): string;
|
|
@@ -162,15 +162,27 @@ export default executeFunc;
|
|
|
162
162
|
/**
|
|
163
163
|
* Replaces placeholders in bundled code with actual job bundles
|
|
164
164
|
* The bundled job code is NOT compressed - it's JavaScript that will be part of the tool
|
|
165
|
+
* Validates that all placeholders are found and replaced
|
|
165
166
|
*/
|
|
166
167
|
export function replaceJobPlaceholders(bundledCode, jobBundles) {
|
|
167
168
|
let result = bundledCode;
|
|
169
|
+
const replacementsMade = new Map();
|
|
168
170
|
jobBundles.forEach((bundledJobCode, placeholder) => {
|
|
169
171
|
// The placeholder is used as an identifier (not a string), just replace it directly
|
|
170
172
|
// It appears as: execute: __BUNDLED_JOB_EXECUTE___1
|
|
171
|
-
|
|
173
|
+
// Use word boundary to prevent partial matches
|
|
174
|
+
const placeholderPattern = new RegExp(`\\b${placeholder}\\b`, 'g');
|
|
175
|
+
const beforeLength = result.length;
|
|
172
176
|
result = result.replace(placeholderPattern, bundledJobCode);
|
|
173
|
-
|
|
177
|
+
const wasReplaced = result.length !== beforeLength;
|
|
178
|
+
replacementsMade.set(placeholder, wasReplaced);
|
|
179
|
+
if (wasReplaced) {
|
|
180
|
+
// console.log(`[PreBundleJobs] ā
Replaced ${placeholder} with bundled code (${(bundledJobCode.length / 1024).toFixed(1)}KB)`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
console.warn(`ā ļø Warning: Placeholder ${placeholder} not found in bundled code. Nested job may not work correctly.`);
|
|
184
|
+
console.warn(` This can happen if esbuild mangled the identifier during minification.`);
|
|
185
|
+
}
|
|
174
186
|
});
|
|
175
187
|
return result;
|
|
176
188
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lua-cli",
|
|
3
|
-
"version": "3.0.2-alpha.
|
|
3
|
+
"version": "3.0.2-alpha.3",
|
|
4
4
|
"description": "Build, test, and deploy AI agents with custom tools, webhooks, and scheduled jobs. Features LuaAgent unified configuration, streaming chat, and batch deployment.",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"main": "dist/api-exports.js",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"@types/inquirer": "^9.0.9",
|
|
90
90
|
"@types/jest": "^29.5.8",
|
|
91
91
|
"@types/js-yaml": "^4.0.9",
|
|
92
|
+
"@types/lodash": "^4.17.20",
|
|
92
93
|
"@types/node": "^24.5.1",
|
|
93
94
|
"@types/node-fetch": "^2.6.13",
|
|
94
95
|
"@types/react": "^18.2.0",
|
|
@@ -96,7 +97,10 @@
|
|
|
96
97
|
"@types/ws": "^8.18.1",
|
|
97
98
|
"@typescript-eslint/parser": "^8.44.1",
|
|
98
99
|
"@typescript-eslint/typescript-estree": "^8.44.1",
|
|
100
|
+
"date-fns": "^4.1.0",
|
|
99
101
|
"jest": "^29.7.0",
|
|
102
|
+
"lodash": "^4.17.21",
|
|
103
|
+
"stripe": "^19.2.0",
|
|
100
104
|
"ts-jest": "^29.1.1",
|
|
101
105
|
"ts-node": "^10.9.2",
|
|
102
106
|
"typescript": "^5.9.2"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
skills: []
|
package/template/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
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;
|
|
@@ -1,143 +0,0 @@
|
|
|
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
|
-
}
|