lua-cli 1.3.2-alpha.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import pkg from 'js-yaml';
4
- const { load } = pkg;
4
+ const { load, dump } = pkg;
5
5
  export function copyTemplateFiles(templateDir, targetDir) {
6
6
  const files = fs.readdirSync(templateDir);
7
7
  for (const file of files) {
@@ -29,7 +29,7 @@ function updatePackageJson(srcPath, destPath) {
29
29
  const templatePackageJson = JSON.parse(fs.readFileSync(srcPath, 'utf8'));
30
30
  // Get the current CLI version from the CLI's own package.json
31
31
  // We need to find the CLI's package.json, not the current working directory's
32
- let currentCliVersion = '1.3.2-alpha.0'; // Default fallback version
32
+ let currentCliVersion = '1.3.2-alpha.2'; // Default fallback version
33
33
  try {
34
34
  // Try to find the CLI's package.json by looking for it in common locations
35
35
  const possiblePaths = [
@@ -59,7 +59,6 @@ function updatePackageJson(srcPath, destPath) {
59
59
  fs.writeFileSync(destPath, JSON.stringify(templatePackageJson, null, 2) + '\n');
60
60
  }
61
61
  export function createSkillYaml(agentId, orgId, skillName, skillId, persona, welcomeMessage) {
62
- const skillIdSection = skillId ? ` skillId: "${skillId}"\n` : '';
63
62
  // Handle multiline strings properly for YAML
64
63
  const personaSection = persona ? ` persona: |\n${persona.split('\n').map(line => ` ${line}`).join('\n')}\n` : '';
65
64
  const welcomeMessageSection = welcomeMessage ? ` welcomeMessage: "${welcomeMessage}"\n` : '';
@@ -67,18 +66,9 @@ export function createSkillYaml(agentId, orgId, skillName, skillId, persona, wel
67
66
  agentId: "${agentId}"
68
67
  orgId: "${orgId}"
69
68
  ${personaSection}${welcomeMessageSection}
70
- skill:
71
- name: "${skillName}"
72
- version: "0.0.1"
73
- ${skillIdSection} env:
74
- # Example environment variables - customize these for your skill
75
- API_URL: "https://api.example.com"
76
- API_KEY: "your-api-key-here"
77
- DEBUG_MODE: "false"
78
- MAX_RETRIES: "3"
79
- TIMEOUT_MS: "5000"
80
- # Add your own environment variables below
81
- # CUSTOM_VAR: "custom-value"`;
69
+ skills:
70
+ # Skills will be auto-generated during compilation
71
+ `;
82
72
  fs.writeFileSync("lua.skill.yaml", yamlContent);
83
73
  }
84
74
  export function readSkillYaml() {
@@ -110,18 +100,13 @@ export function updateSkillYamlPersona(persona, welcomeMessage) {
110
100
  if (welcomeMessage) {
111
101
  data.agent.welcomeMessage = welcomeMessage;
112
102
  }
113
- // Convert back to YAML with proper formatting
114
- const updatedYamlContent = `agent:
115
- agentId: "${data.agent.agentId}"
116
- orgId: "${data.agent.orgId}"
117
- persona: |
118
- ${persona.split('\n').map(line => ` ${line}`).join('\n')}
119
- welcomeMessage: "${data.agent.welcomeMessage || ''}"
120
-
121
- skill:
122
- name: "${data.skill.name}"
123
- version: "${data.skill.version}"
124
- skillId: "${data.skill.skillId || ''}"
125
- `;
103
+ // Use yaml.dump to properly handle both old and new formats
104
+ const updatedYamlContent = dump(data, {
105
+ indent: 2,
106
+ lineWidth: -1,
107
+ noRefs: true,
108
+ quotingType: '"',
109
+ forceQuotes: false
110
+ });
126
111
  fs.writeFileSync(yamlPath, updatedYamlContent);
127
112
  }
@@ -8,79 +8,17 @@ export interface ExecuteToolOptions extends SandboxOptions {
8
8
  toolCode: string;
9
9
  inputs: any;
10
10
  }
11
+ /**
12
+ * Loads environment variables from multiple sources in priority order:
13
+ * 1. process.env (lowest priority)
14
+ * 2. .env file (medium priority)
15
+ * 3. lua.skill.yaml env section (highest priority)
16
+ */
17
+ export declare function loadEnvironmentVariables(): Record<string, string>;
11
18
  /**
12
19
  * Creates a VM sandbox context with all necessary globals and utilities
13
20
  */
14
- export declare function createSandbox(options: SandboxOptions): {
15
- require: NodeJS.Require;
16
- console: any;
17
- Buffer: BufferConstructor;
18
- setTimeout: typeof setTimeout;
19
- setInterval: typeof setInterval;
20
- clearTimeout: typeof clearTimeout;
21
- clearInterval: typeof clearInterval;
22
- process: NodeJS.Process;
23
- global: typeof globalThis;
24
- __dirname: string;
25
- __filename: string;
26
- module: {
27
- exports: {};
28
- };
29
- exports: {};
30
- fetch: typeof fetch;
31
- URLSearchParams: {
32
- new (init?: string[][] | Record<string, string> | string | URLSearchParams): URLSearchParams;
33
- prototype: URLSearchParams;
34
- };
35
- URL: {
36
- new (url: string | URL, base?: string | URL): URL;
37
- prototype: URL;
38
- canParse(url: string | URL, base?: string | URL): boolean;
39
- createObjectURL(obj: Blob | MediaSource): string;
40
- parse(url: string | URL, base?: string | URL): URL | null;
41
- revokeObjectURL(url: string): void;
42
- };
43
- Headers: {
44
- new (init?: HeadersInit): Headers;
45
- prototype: Headers;
46
- };
47
- Request: {
48
- new (input: RequestInfo | URL, init?: RequestInit): Request;
49
- prototype: Request;
50
- };
51
- Response: {
52
- new (body?: BodyInit | null, init?: ResponseInit): Response;
53
- prototype: Response;
54
- error(): Response;
55
- json(data: any, init?: ResponseInit): Response;
56
- redirect(url: string | URL, status?: number): Response;
57
- };
58
- Object: ObjectConstructor;
59
- Array: ArrayConstructor;
60
- String: StringConstructor;
61
- Number: NumberConstructor;
62
- Boolean: BooleanConstructor;
63
- Date: DateConstructor;
64
- Math: Math;
65
- JSON: JSON;
66
- Error: ErrorConstructor;
67
- TypeError: TypeErrorConstructor;
68
- ReferenceError: ReferenceErrorConstructor;
69
- SyntaxError: SyntaxErrorConstructor;
70
- globalThis: typeof globalThis;
71
- undefined: undefined;
72
- null: null;
73
- Infinity: number;
74
- NaN: number;
75
- user: {
76
- data: {
77
- update: (data: any) => Promise<import("../services/api.js").ApiResponse<any>>;
78
- get: () => Promise<any>;
79
- create: (data: any) => Promise<any>;
80
- };
81
- };
82
- env: (key: string) => string;
83
- };
21
+ export declare function createSandbox(options: SandboxOptions): any;
84
22
  /**
85
23
  * Executes a tool in a VM sandbox
86
24
  */
@@ -1,21 +1,60 @@
1
1
  import { createRequire } from "module";
2
2
  import vm from "vm";
3
3
  import path from "path";
4
+ import fs from "fs";
4
5
  import { UserDataApi } from "../services/api.js";
5
6
  import { readSkillConfig } from "./files.js";
6
7
  /**
7
- * Creates a VM sandbox context with all necessary globals and utilities
8
+ * Loads environment variables from multiple sources in priority order:
9
+ * 1. process.env (lowest priority)
10
+ * 2. .env file (medium priority)
11
+ * 3. lua.skill.yaml env section (highest priority)
8
12
  */
9
- export function createSandbox(options) {
10
- const { apiKey, agentId, customConsole, broadcastLog } = options;
11
- // Extract environment variables from YAML config
12
- const config = readSkillConfig();
13
+ export function loadEnvironmentVariables() {
13
14
  const envVars = {};
15
+ // 1. Start with process.env
16
+ for (const [key, value] of Object.entries(process.env)) {
17
+ if (value !== undefined) {
18
+ envVars[key] = value;
19
+ }
20
+ }
21
+ // 2. Load from .env file if it exists
22
+ const envFilePath = path.join(process.cwd(), '.env');
23
+ if (fs.existsSync(envFilePath)) {
24
+ try {
25
+ const envFileContent = fs.readFileSync(envFilePath, 'utf8');
26
+ const envLines = envFileContent.split('\n');
27
+ for (const line of envLines) {
28
+ const trimmedLine = line.trim();
29
+ if (trimmedLine && !trimmedLine.startsWith('#')) {
30
+ const [key, ...valueParts] = trimmedLine.split('=');
31
+ if (key && valueParts.length > 0) {
32
+ const value = valueParts.join('=').replace(/^["']|["']$/g, ''); // Remove quotes
33
+ envVars[key.trim()] = value;
34
+ }
35
+ }
36
+ }
37
+ }
38
+ catch (error) {
39
+ console.warn('Warning: Could not read .env file:', error);
40
+ }
41
+ }
42
+ // 3. Override with YAML config values (highest priority)
43
+ const config = readSkillConfig();
14
44
  if (config?.skill?.env) {
15
45
  for (const [key, value] of Object.entries(config.skill.env)) {
16
46
  envVars[key] = value;
17
47
  }
18
48
  }
49
+ return envVars;
50
+ }
51
+ /**
52
+ * Creates a VM sandbox context with all necessary globals and utilities
53
+ */
54
+ export function createSandbox(options) {
55
+ const { apiKey, agentId, customConsole, broadcastLog } = options;
56
+ // Load environment variables from multiple sources (same logic as test command)
57
+ const envVars = loadEnvironmentVariables();
19
58
  // Create a CommonJS context for execution
20
59
  const require = createRequire(process.cwd() + '/package.json');
21
60
  const updateUserData = async (data) => {
@@ -29,6 +68,85 @@ export function createSandbox(options) {
29
68
  };
30
69
  // Create console object (use custom console if provided, otherwise default)
31
70
  const consoleObj = customConsole || console;
71
+ // Create comprehensive polyfills for browser/Node.js APIs
72
+ const polyfills = {
73
+ // AbortController polyfill
74
+ AbortController: globalThis.AbortController || class AbortController {
75
+ constructor() {
76
+ this.signal = {
77
+ aborted: false,
78
+ addEventListener: () => { },
79
+ removeEventListener: () => { },
80
+ dispatchEvent: () => { }
81
+ };
82
+ }
83
+ abort() {
84
+ this.signal.aborted = true;
85
+ }
86
+ },
87
+ // FormData polyfill
88
+ FormData: globalThis.FormData || class FormData {
89
+ constructor() {
90
+ this._data = [];
91
+ }
92
+ append(name, value) {
93
+ this._data.push({ name, value });
94
+ }
95
+ get(name) {
96
+ const item = this._data.find(d => d.name === name);
97
+ return item ? item.value : null;
98
+ }
99
+ getAll(name) {
100
+ return this._data.filter(d => d.name === name).map(d => d.value);
101
+ }
102
+ has(name) {
103
+ return this._data.some(d => d.name === name);
104
+ }
105
+ delete(name) {
106
+ this._data = this._data.filter(d => d.name !== name);
107
+ }
108
+ set(name, value) {
109
+ this.delete(name);
110
+ this.append(name, value);
111
+ }
112
+ entries() {
113
+ return this._data.map(d => [d.name, d.value]);
114
+ }
115
+ keys() {
116
+ return this._data.map(d => d.name);
117
+ }
118
+ values() {
119
+ return this._data.map(d => d.value);
120
+ }
121
+ },
122
+ // TextEncoder/TextDecoder polyfills
123
+ TextEncoder: globalThis.TextEncoder || class TextEncoder {
124
+ encode(input) {
125
+ return Buffer.from(input, 'utf8');
126
+ }
127
+ },
128
+ TextDecoder: globalThis.TextDecoder || class TextDecoder {
129
+ decode(input) {
130
+ return Buffer.from(input).toString('utf8');
131
+ }
132
+ },
133
+ // Crypto polyfill (basic)
134
+ crypto: globalThis.crypto || {
135
+ randomUUID: () => {
136
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
137
+ const r = Math.random() * 16 | 0;
138
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
139
+ return v.toString(16);
140
+ });
141
+ },
142
+ getRandomValues: (array) => {
143
+ for (let i = 0; i < array.length; i++) {
144
+ array[i] = Math.floor(Math.random() * 256);
145
+ }
146
+ return array;
147
+ }
148
+ }
149
+ };
32
150
  // Create a sandbox context
33
151
  const sandbox = {
34
152
  require,
@@ -38,19 +156,26 @@ export function createSandbox(options) {
38
156
  setInterval,
39
157
  clearTimeout,
40
158
  clearInterval,
41
- process,
159
+ process: {
160
+ env: envVars
161
+ },
42
162
  global: globalThis,
43
163
  __dirname: process.cwd(),
44
164
  __filename: path.join(process.cwd(), 'index.ts'),
45
165
  module: { exports: {} },
46
166
  exports: {},
47
- // Web APIs
167
+ // Web APIs with polyfills
48
168
  fetch: globalThis.fetch,
49
169
  URLSearchParams: globalThis.URLSearchParams,
50
170
  URL: globalThis.URL,
51
171
  Headers: globalThis.Headers,
52
172
  Request: globalThis.Request,
53
173
  Response: globalThis.Response,
174
+ FormData: polyfills.FormData,
175
+ AbortController: polyfills.AbortController,
176
+ TextEncoder: polyfills.TextEncoder,
177
+ TextDecoder: polyfills.TextDecoder,
178
+ crypto: polyfills.crypto,
54
179
  // Additional globals
55
180
  Object,
56
181
  Array,
@@ -94,11 +219,32 @@ const executeFunction = ${toolCode};
94
219
 
95
220
  // Export the function for testing
96
221
  module.exports = async (input) => {
222
+ try{
97
223
  return await executeFunction(input);
224
+ }catch(e){
225
+ console.error(e);
226
+ return { status: 'error', error: e.message };
227
+ }
98
228
  };
99
229
  `;
100
230
  // Execute the code in the sandbox
101
231
  const context = vm.createContext(sandbox);
232
+ // Add polyfills to global scope for libraries that expect them
233
+ vm.runInContext(`
234
+ if (typeof global !== 'undefined') {
235
+ global.AbortController = AbortController;
236
+ global.FormData = FormData;
237
+ global.TextEncoder = TextEncoder;
238
+ global.TextDecoder = TextDecoder;
239
+ global.crypto = crypto;
240
+ global.fetch = fetch;
241
+ global.Headers = Headers;
242
+ global.Request = Request;
243
+ global.Response = Response;
244
+ global.URL = URL;
245
+ global.URLSearchParams = URLSearchParams;
246
+ }
247
+ `, context);
102
248
  vm.runInContext(commonJsWrapper, context);
103
249
  // Get the exported function and execute it
104
250
  const executeFunction = context.module.exports;