lua-cli 1.3.2-alpha.0 → 1.3.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.
@@ -184,10 +184,10 @@ export declare class ToolApi {
184
184
  static patchTool(url: string, data: any, apiKey: string): Promise<ApiResponse<any>>;
185
185
  }
186
186
  export declare class UserDataApi {
187
- static getUserData(apiKey: string, agentId: string): Promise<ApiResponse<UserData>>;
188
- static createUserData(apiKey: string, agentId: string, data: any): Promise<ApiResponse<UserData>>;
189
- static updateUserData(apiKey: string, agentId: string, data: any): Promise<ApiResponse<UserData>>;
190
- static deleteUserData(apiKey: string, agentId: string): Promise<ApiResponse<UserData>>;
187
+ static getUserData(apiKey: string, agentId: string): Promise<any>;
188
+ static createUserData(apiKey: string, agentId: string, data: any): Promise<any>;
189
+ static updateUserData(apiKey: string, agentId: string, data: any): Promise<ApiResponse<any>>;
190
+ static deleteUserData(apiKey: string, agentId: string): Promise<ApiResponse<any>>;
191
191
  }
192
192
  /**
193
193
  * Main API service that exports all API classes
@@ -200,24 +200,28 @@ export class ToolApi {
200
200
  // User Data API calls
201
201
  export class UserDataApi {
202
202
  static async getUserData(apiKey, agentId) {
203
- return httpClient.get(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, {
203
+ const response = await httpClient.get(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, {
204
204
  Authorization: `Bearer ${apiKey}`,
205
205
  });
206
+ return response;
206
207
  }
207
208
  static async createUserData(apiKey, agentId, data) {
208
- return httpClient.post(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, data, {
209
+ const response = await httpClient.put(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, data, {
209
210
  Authorization: `Bearer ${apiKey}`,
210
211
  });
212
+ return response.data.data;
211
213
  }
212
214
  static async updateUserData(apiKey, agentId, data) {
213
- return httpClient.put(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, data, {
215
+ const response = await httpClient.put(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, data, {
214
216
  Authorization: `Bearer ${apiKey}`,
215
217
  });
218
+ return response.data.data;
216
219
  }
217
220
  static async deleteUserData(apiKey, agentId) {
218
- return httpClient.delete(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, {
221
+ const response = await httpClient.delete(`${BASE_URLS.LOCAL}/developer/user/data/agent/${agentId}`, {
219
222
  Authorization: `Bearer ${apiKey}`,
220
223
  });
224
+ return response;
221
225
  }
222
226
  }
223
227
  /**
package/dist/skill.d.ts CHANGED
@@ -1,6 +1,20 @@
1
1
  import { ZodType } from "zod";
2
2
  import { LuaTool } from "./types/index.js";
3
3
  export { LuaTool };
4
+ /**
5
+ * Safe environment variable access function
6
+ * Gets injected at runtime with skill-specific environment variables
7
+ *
8
+ * @param key - The environment variable key to retrieve
9
+ * @returns The environment variable value or undefined if not found
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const baseUrl = env('BASE_URL');
14
+ * const apiKey = env('API_KEY');
15
+ * ```
16
+ */
17
+ export declare const env: (key: string) => string | undefined;
4
18
  export interface LuaSkillConfig {
5
19
  description: string;
6
20
  context: string;
@@ -25,6 +39,7 @@ export declare class LuaSkill {
25
39
  * ```
26
40
  */
27
41
  constructor(config: LuaSkillConfig);
28
- addTool<TInput extends ZodType, TOutput extends ZodType>(tool: LuaTool<TInput, TOutput>): void;
42
+ addTool<TInput extends ZodType>(tool: LuaTool<TInput>): void;
43
+ addTools(tools: LuaTool<any>[]): void;
29
44
  run(input: Record<string, any>): Promise<any>;
30
45
  }
package/dist/skill.js CHANGED
@@ -1,4 +1,46 @@
1
1
  import { assertValidToolName } from "./types/index.js";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import yaml from "js-yaml";
5
+ /**
6
+ * Safe environment variable access function
7
+ * Gets injected at runtime with skill-specific environment variables
8
+ *
9
+ * @param key - The environment variable key to retrieve
10
+ * @returns The environment variable value or undefined if not found
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const baseUrl = env('BASE_URL');
15
+ * const apiKey = env('API_KEY');
16
+ * ```
17
+ */
18
+ export const env = (key) => {
19
+ // Try to load environment variables from lua.skill.yaml
20
+ try {
21
+ // Look for lua.skill.yaml in current directory and parent directories
22
+ let currentDir = process.cwd();
23
+ let yamlPath = null;
24
+ while (currentDir !== path.dirname(currentDir)) {
25
+ const potentialPath = path.join(currentDir, 'lua.skill.yaml');
26
+ if (fs.existsSync(potentialPath)) {
27
+ yamlPath = potentialPath;
28
+ break;
29
+ }
30
+ currentDir = path.dirname(currentDir);
31
+ }
32
+ if (yamlPath) {
33
+ const yamlContent = fs.readFileSync(yamlPath, 'utf8');
34
+ const config = yaml.load(yamlContent);
35
+ return config?.skill?.env?.[key];
36
+ }
37
+ }
38
+ catch (error) {
39
+ // If we can't load the YAML, fall back to undefined
40
+ console.warn(`Warning: Could not load environment variables from lua.skill.yaml: ${error}`);
41
+ }
42
+ return undefined;
43
+ };
2
44
  export class LuaSkill {
3
45
  /**
4
46
  * Creates a new LuaSkill instance
@@ -25,6 +67,13 @@ export class LuaSkill {
25
67
  assertValidToolName(tool.name);
26
68
  this.tools.push(tool);
27
69
  }
70
+ addTools(tools) {
71
+ // Validate all tool names before adding them
72
+ for (const tool of tools) {
73
+ assertValidToolName(tool.name);
74
+ }
75
+ this.tools.push(...tools);
76
+ }
28
77
  async run(input) {
29
78
  const tool = this.tools.find(tool => tool.name === input.tool);
30
79
  if (!tool) {
@@ -62,11 +62,10 @@ export declare function validateToolName(name: string): boolean;
62
62
  * Throws an error if the tool name is invalid
63
63
  */
64
64
  export declare function assertValidToolName(name: string): void;
65
- export interface LuaTool<TInput extends ZodType = ZodType, TOutput extends ZodType = ZodType> {
65
+ export interface LuaTool<TInput extends ZodType = ZodType> {
66
66
  name: string;
67
67
  description: string;
68
68
  inputSchema: TInput;
69
- outputSchema: TOutput;
70
69
  execute: (input: any) => Promise<any>;
71
70
  }
72
71
  export interface LuaSkillConfig {
@@ -78,6 +77,7 @@ export declare class LuaSkill {
78
77
  private readonly description;
79
78
  private readonly context;
80
79
  constructor(config: LuaSkillConfig);
81
- addTool<TInput extends ZodType, TOutput extends ZodType>(tool: LuaTool<TInput, TOutput>): void;
80
+ addTool<TInput extends ZodType>(tool: LuaTool<TInput>): void;
81
+ addTools(tools: LuaTool<any>[]): void;
82
82
  run(input: Record<string, any>): Promise<any>;
83
83
  }
@@ -3,6 +3,7 @@
3
3
  * Provides methods to interact with user data stored in the Lua system
4
4
  */
5
5
  export declare class UserDataAPI {
6
+ userData: any;
6
7
  constructor();
7
8
  /**
8
9
  * Get user data for the current agent
@@ -3,13 +3,15 @@
3
3
  * Provides methods to interact with user data stored in the Lua system
4
4
  */
5
5
  export class UserDataAPI {
6
- constructor() { }
6
+ constructor() {
7
+ this.userData = {};
8
+ }
7
9
  /**
8
10
  * Get user data for the current agent
9
11
  * @returns Promise<UserDataResponse>
10
12
  */
11
13
  async get() {
12
- return { success: true };
14
+ return { success: true, data: this.userData };
13
15
  }
14
16
  /**
15
17
  * Create or update user data for the current agent
@@ -17,7 +19,8 @@ export class UserDataAPI {
17
19
  * @returns Promise<UserDataResponse>
18
20
  */
19
21
  async create(data) {
20
- return { success: true };
22
+ this.userData = data;
23
+ return { success: true, data: this.userData };
21
24
  }
22
25
  /**
23
26
  * Update existing user data for the current agent
@@ -26,13 +29,15 @@ export class UserDataAPI {
26
29
  */
27
30
  async update(data) {
28
31
  // Update is the same as create for this API
29
- return { success: true };
32
+ this.userData = { ...this.userData, ...data };
33
+ return { success: true, data: this.userData };
30
34
  }
31
35
  /**
32
36
  * Clear all user data for the current agent
33
37
  * @returns Promise<{success: boolean}>
34
38
  */
35
39
  async clear() {
40
+ this.userData = {};
36
41
  return { success: true };
37
42
  }
38
43
  }
@@ -27,10 +27,30 @@ export function copyTemplateFiles(templateDir, targetDir) {
27
27
  function updatePackageJson(srcPath, destPath) {
28
28
  // Read the template package.json
29
29
  const templatePackageJson = JSON.parse(fs.readFileSync(srcPath, 'utf8'));
30
- // Get the current CLI version from the main package.json
31
- const mainPackageJsonPath = path.join(process.cwd(), 'package.json');
32
- const mainPackageJson = JSON.parse(fs.readFileSync(mainPackageJsonPath, 'utf8'));
33
- const currentCliVersion = mainPackageJson.version;
30
+ // Get the current CLI version from the CLI's own package.json
31
+ // We need to find the CLI's package.json, not the current working directory's
32
+ let currentCliVersion = '1.3.2-alpha.2'; // Default fallback version
33
+ try {
34
+ // Try to find the CLI's package.json by looking for it in common locations
35
+ const possiblePaths = [
36
+ path.join(__dirname, '..', '..', 'package.json'), // From dist/utils/
37
+ path.join(process.cwd(), 'package.json'), // Current directory (fallback)
38
+ path.join(process.env.HOME || '', '.npm-global', 'lib', 'node_modules', 'lua-cli', 'package.json'), // Global install
39
+ ];
40
+ for (const packagePath of possiblePaths) {
41
+ if (fs.existsSync(packagePath)) {
42
+ const mainPackageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
43
+ if (mainPackageJson.name === 'lua-cli') {
44
+ currentCliVersion = mainPackageJson.version;
45
+ break;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ catch (error) {
51
+ // If we can't read any package.json, use the fallback version
52
+ console.log(`Using fallback CLI version: ${currentCliVersion}`);
53
+ }
34
54
  // Update the lua-cli dependency version
35
55
  if (templatePackageJson.dependencies && templatePackageJson.dependencies['lua-cli']) {
36
56
  templatePackageJson.dependencies['lua-cli'] = `^${currentCliVersion}`;
@@ -50,7 +70,13 @@ ${personaSection}${welcomeMessageSection}
50
70
  skill:
51
71
  name: "${skillName}"
52
72
  version: "0.0.1"
53
- ${skillIdSection}`;
73
+ ${skillIdSection} env:
74
+ # Example environment variables - customize these for your skill
75
+ PINECONE_API_KEY: "pcsk_5iFtQD_xxxxx"
76
+ OPENAI_API_KEY: "sk-proj--xxxx"
77
+ STRIPE_SECRET_KEY: "sk_test_xxxx"
78
+ # Add your own environment variables below
79
+ # CUSTOM_VAR: "custom-value"`;
54
80
  fs.writeFileSync("lua.skill.yaml", yamlContent);
55
81
  }
56
82
  export function readSkillYaml() {
@@ -0,0 +1,27 @@
1
+ export interface SandboxOptions {
2
+ apiKey: string;
3
+ agentId: string;
4
+ customConsole?: any;
5
+ broadcastLog?: (logData: any) => void;
6
+ }
7
+ export interface ExecuteToolOptions extends SandboxOptions {
8
+ toolCode: string;
9
+ inputs: any;
10
+ }
11
+ /**
12
+ * Creates a VM sandbox context with all necessary globals and utilities
13
+ */
14
+ export declare function createSandbox(options: SandboxOptions): any;
15
+ /**
16
+ * Executes a tool in a VM sandbox
17
+ */
18
+ export declare function executeTool(options: ExecuteToolOptions): Promise<any>;
19
+ /**
20
+ * Creates a custom console that broadcasts logs via WebSocket
21
+ */
22
+ export declare function createBroadcastConsole(broadcastLog: (logData: any) => void): {
23
+ log: (...args: any[]) => void;
24
+ error: (...args: any[]) => void;
25
+ warn: (...args: any[]) => void;
26
+ info: (...args: any[]) => void;
27
+ };
@@ -0,0 +1,271 @@
1
+ import { createRequire } from "module";
2
+ import vm from "vm";
3
+ import path from "path";
4
+ import { UserDataApi } from "../services/api.js";
5
+ import { readSkillConfig } from "./files.js";
6
+ /**
7
+ * Creates a VM sandbox context with all necessary globals and utilities
8
+ */
9
+ export function createSandbox(options) {
10
+ const { apiKey, agentId, customConsole, broadcastLog } = options;
11
+ // Extract environment variables from YAML config and merge with process.env
12
+ const config = readSkillConfig();
13
+ const envVars = {};
14
+ // Copy process.env, filtering out undefined values
15
+ for (const [key, value] of Object.entries(process.env)) {
16
+ if (value !== undefined) {
17
+ envVars[key] = value;
18
+ }
19
+ }
20
+ // Override with config values
21
+ if (config?.skill?.env) {
22
+ for (const [key, value] of Object.entries(config.skill.env)) {
23
+ envVars[key] = value;
24
+ }
25
+ }
26
+ // Create a CommonJS context for execution
27
+ const require = createRequire(process.cwd() + '/package.json');
28
+ const updateUserData = async (data) => {
29
+ return await UserDataApi.updateUserData(apiKey, agentId, data);
30
+ };
31
+ const getUserData = async () => {
32
+ return await UserDataApi.getUserData(apiKey, agentId);
33
+ };
34
+ const linkUserData = async (data) => {
35
+ return await UserDataApi.createUserData(apiKey, agentId, data);
36
+ };
37
+ // Create console object (use custom console if provided, otherwise default)
38
+ const consoleObj = customConsole || console;
39
+ // Create comprehensive polyfills for browser/Node.js APIs
40
+ const polyfills = {
41
+ // AbortController polyfill
42
+ AbortController: globalThis.AbortController || class AbortController {
43
+ constructor() {
44
+ this.signal = {
45
+ aborted: false,
46
+ addEventListener: () => { },
47
+ removeEventListener: () => { },
48
+ dispatchEvent: () => { }
49
+ };
50
+ }
51
+ abort() {
52
+ this.signal.aborted = true;
53
+ }
54
+ },
55
+ // FormData polyfill
56
+ FormData: globalThis.FormData || class FormData {
57
+ constructor() {
58
+ this._data = [];
59
+ }
60
+ append(name, value) {
61
+ this._data.push({ name, value });
62
+ }
63
+ get(name) {
64
+ const item = this._data.find(d => d.name === name);
65
+ return item ? item.value : null;
66
+ }
67
+ getAll(name) {
68
+ return this._data.filter(d => d.name === name).map(d => d.value);
69
+ }
70
+ has(name) {
71
+ return this._data.some(d => d.name === name);
72
+ }
73
+ delete(name) {
74
+ this._data = this._data.filter(d => d.name !== name);
75
+ }
76
+ set(name, value) {
77
+ this.delete(name);
78
+ this.append(name, value);
79
+ }
80
+ entries() {
81
+ return this._data.map(d => [d.name, d.value]);
82
+ }
83
+ keys() {
84
+ return this._data.map(d => d.name);
85
+ }
86
+ values() {
87
+ return this._data.map(d => d.value);
88
+ }
89
+ },
90
+ // TextEncoder/TextDecoder polyfills
91
+ TextEncoder: globalThis.TextEncoder || class TextEncoder {
92
+ encode(input) {
93
+ return Buffer.from(input, 'utf8');
94
+ }
95
+ },
96
+ TextDecoder: globalThis.TextDecoder || class TextDecoder {
97
+ decode(input) {
98
+ return Buffer.from(input).toString('utf8');
99
+ }
100
+ },
101
+ // Crypto polyfill (basic)
102
+ crypto: globalThis.crypto || {
103
+ randomUUID: () => {
104
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
105
+ const r = Math.random() * 16 | 0;
106
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
107
+ return v.toString(16);
108
+ });
109
+ },
110
+ getRandomValues: (array) => {
111
+ for (let i = 0; i < array.length; i++) {
112
+ array[i] = Math.floor(Math.random() * 256);
113
+ }
114
+ return array;
115
+ }
116
+ }
117
+ };
118
+ // Create a sandbox context
119
+ const sandbox = {
120
+ require,
121
+ console: consoleObj,
122
+ Buffer,
123
+ setTimeout,
124
+ setInterval,
125
+ clearTimeout,
126
+ clearInterval,
127
+ process: {
128
+ ...process,
129
+ env: envVars
130
+ },
131
+ global: globalThis,
132
+ __dirname: process.cwd(),
133
+ __filename: path.join(process.cwd(), 'index.ts'),
134
+ module: { exports: {} },
135
+ exports: {},
136
+ // Web APIs with polyfills
137
+ fetch: globalThis.fetch,
138
+ URLSearchParams: globalThis.URLSearchParams,
139
+ URL: globalThis.URL,
140
+ Headers: globalThis.Headers,
141
+ Request: globalThis.Request,
142
+ Response: globalThis.Response,
143
+ FormData: polyfills.FormData,
144
+ AbortController: polyfills.AbortController,
145
+ TextEncoder: polyfills.TextEncoder,
146
+ TextDecoder: polyfills.TextDecoder,
147
+ crypto: polyfills.crypto,
148
+ // Additional globals
149
+ Object,
150
+ Array,
151
+ String,
152
+ Number,
153
+ Boolean,
154
+ Date,
155
+ Math,
156
+ JSON,
157
+ Error,
158
+ TypeError,
159
+ ReferenceError,
160
+ SyntaxError,
161
+ globalThis,
162
+ undefined: undefined,
163
+ null: null,
164
+ Infinity: Infinity,
165
+ NaN: NaN,
166
+ user: {
167
+ data: {
168
+ update: updateUserData,
169
+ get: getUserData,
170
+ create: linkUserData
171
+ }
172
+ },
173
+ // Environment variables function
174
+ env: (key) => envVars[key]
175
+ };
176
+ return sandbox;
177
+ }
178
+ /**
179
+ * Executes a tool in a VM sandbox
180
+ */
181
+ export async function executeTool(options) {
182
+ const { toolCode, inputs } = options;
183
+ // Create sandbox
184
+ const sandbox = createSandbox(options);
185
+ // Create the CommonJS wrapper code
186
+ const commonJsWrapper = `
187
+ const executeFunction = ${toolCode};
188
+
189
+ // Export the function for testing
190
+ module.exports = async (input) => {
191
+ return await executeFunction(input);
192
+ };
193
+ `;
194
+ // Execute the code in the sandbox
195
+ const context = vm.createContext(sandbox);
196
+ // Add polyfills to global scope for libraries that expect them
197
+ vm.runInContext(`
198
+ if (typeof global !== 'undefined') {
199
+ global.AbortController = AbortController;
200
+ global.FormData = FormData;
201
+ global.TextEncoder = TextEncoder;
202
+ global.TextDecoder = TextDecoder;
203
+ global.crypto = crypto;
204
+ global.fetch = fetch;
205
+ global.Headers = Headers;
206
+ global.Request = Request;
207
+ global.Response = Response;
208
+ global.URL = URL;
209
+ global.URLSearchParams = URLSearchParams;
210
+ }
211
+ `, context);
212
+ vm.runInContext(commonJsWrapper, context);
213
+ // Get the exported function and execute it
214
+ const executeFunction = context.module.exports;
215
+ return await executeFunction(inputs);
216
+ }
217
+ /**
218
+ * Creates a custom console that broadcasts logs via WebSocket
219
+ */
220
+ export function createBroadcastConsole(broadcastLog) {
221
+ return {
222
+ log: (...args) => {
223
+ const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
224
+ broadcastLog({
225
+ type: 'log',
226
+ subType: 'info',
227
+ message: message,
228
+ timestamp: new Date().toISOString(),
229
+ id: Date.now().toString()
230
+ });
231
+ // Also log to server console
232
+ console.log(...args);
233
+ },
234
+ error: (...args) => {
235
+ const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
236
+ broadcastLog({
237
+ type: 'log',
238
+ subType: 'error',
239
+ message: message,
240
+ timestamp: new Date().toISOString(),
241
+ id: Date.now().toString()
242
+ });
243
+ // Also log to server console
244
+ console.error(...args);
245
+ },
246
+ warn: (...args) => {
247
+ const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
248
+ broadcastLog({
249
+ type: 'log',
250
+ subType: 'warn',
251
+ message: message,
252
+ timestamp: new Date().toISOString(),
253
+ id: Date.now().toString()
254
+ });
255
+ // Also log to server console
256
+ console.warn(...args);
257
+ },
258
+ info: (...args) => {
259
+ const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
260
+ broadcastLog({
261
+ type: 'log',
262
+ subType: 'info',
263
+ message: message,
264
+ timestamp: new Date().toISOString(),
265
+ id: Date.now().toString()
266
+ });
267
+ // Also log to server console
268
+ console.info(...args);
269
+ }
270
+ };
271
+ }