lua-cli 2.3.0 → 2.4.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.
Files changed (56) hide show
  1. package/dist/api/products.api.service.js +1 -0
  2. package/dist/cli/command-definitions.d.ts +0 -8
  3. package/dist/cli/command-definitions.js +51 -18
  4. package/dist/commands/chat.d.ts +17 -0
  5. package/dist/commands/chat.js +236 -0
  6. package/dist/commands/chatClear.d.ts +15 -0
  7. package/dist/commands/chatClear.js +75 -0
  8. package/dist/commands/deploy.d.ts +7 -5
  9. package/dist/commands/deploy.js +34 -15
  10. package/dist/commands/env.d.ts +19 -0
  11. package/dist/commands/env.js +434 -0
  12. package/dist/commands/index.d.ts +6 -0
  13. package/dist/commands/index.js +6 -0
  14. package/dist/commands/init.js +6 -6
  15. package/dist/commands/persona.d.ts +15 -0
  16. package/dist/commands/persona.js +503 -0
  17. package/dist/commands/production.d.ts +15 -0
  18. package/dist/commands/production.js +532 -0
  19. package/dist/commands/push.d.ts +7 -5
  20. package/dist/commands/push.js +100 -21
  21. package/dist/commands/resources.d.ts +17 -0
  22. package/dist/commands/resources.js +361 -0
  23. package/dist/common/data.entry.instance.js +6 -2
  24. package/dist/common/http.client.js +7 -0
  25. package/dist/config/compile.constants.d.ts +4 -3
  26. package/dist/config/compile.constants.js +3 -7
  27. package/dist/config/constants.d.ts +6 -0
  28. package/dist/config/constants.js +11 -0
  29. package/dist/errors/auth.error.d.ts +15 -0
  30. package/dist/errors/auth.error.js +27 -0
  31. package/dist/errors/index.d.ts +4 -0
  32. package/dist/errors/index.js +4 -0
  33. package/dist/index.d.ts +0 -9
  34. package/dist/index.js +30 -11
  35. package/dist/interfaces/agent.d.ts +33 -49
  36. package/dist/services/auth.d.ts +1 -2
  37. package/dist/services/auth.js +3 -4
  38. package/dist/utils/bundling.js +61 -0
  39. package/dist/utils/cli.js +6 -0
  40. package/dist/utils/deploy-helpers.d.ts +22 -0
  41. package/dist/utils/deploy-helpers.js +61 -2
  42. package/dist/utils/deployment.js +33 -1
  43. package/dist/utils/dev-server.js +255 -0
  44. package/dist/utils/init-agent.js +3 -3
  45. package/dist/utils/prompt-handler.d.ts +12 -0
  46. package/dist/utils/prompt-handler.js +31 -0
  47. package/dist/utils/push-helpers.d.ts +47 -3
  48. package/dist/utils/push-helpers.js +167 -10
  49. package/dist/utils/sandbox.js +18 -5
  50. package/dist/web/app.css +1302 -465
  51. package/dist/web/app.js +53 -46
  52. package/package.json +1 -1
  53. package/template/package.json +1 -1
  54. package/template/src/tools/BasketTool.ts +4 -1
  55. package/template/src/tools/ProductsTool.ts +7 -7
  56. package/dist/web/tools-page.css +0 -381
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Authentication Error
3
+ * Thrown when API requests fail with 401 Unauthorized status
4
+ */
5
+ export class AuthenticationError extends Error {
6
+ constructor(message = "Invalid API key") {
7
+ super(message);
8
+ this.statusCode = 401;
9
+ this.isAuthenticationError = true;
10
+ this.name = "AuthenticationError";
11
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, AuthenticationError);
14
+ }
15
+ }
16
+ /**
17
+ * Checks if an error is an AuthenticationError
18
+ * @param error - The error to check
19
+ * @returns True if the error is an AuthenticationError
20
+ */
21
+ static isAuthenticationError(error) {
22
+ return (error instanceof AuthenticationError ||
23
+ (error instanceof Error &&
24
+ "isAuthenticationError" in error &&
25
+ error.isAuthenticationError === true));
26
+ }
27
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Error types and utilities
3
+ */
4
+ export { AuthenticationError } from "./auth.error.js";
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Error types and utilities
3
+ */
4
+ export { AuthenticationError } from "./auth.error.js";
package/dist/index.d.ts CHANGED
@@ -6,15 +6,6 @@
6
6
  * Provides tools for authentication, project initialization, compilation,
7
7
  * testing, deployment, and development.
8
8
  *
9
- * Usage:
10
- * lua auth configure # Set up authentication
11
- * lua init # Initialize new project
12
- * lua compile # Compile skill
13
- * lua test # Test tools
14
- * lua push # Push to server
15
- * lua deploy # Deploy to production
16
- * lua dev # Start development mode
17
- *
18
9
  * For more information: https://docs.heylua.ai
19
10
  */
20
11
  export {};
package/dist/index.js CHANGED
@@ -6,15 +6,6 @@
6
6
  * Provides tools for authentication, project initialization, compilation,
7
7
  * testing, deployment, and development.
8
8
  *
9
- * Usage:
10
- * lua auth configure # Set up authentication
11
- * lua init # Initialize new project
12
- * lua compile # Compile skill
13
- * lua test # Test tools
14
- * lua push # Push to server
15
- * lua deploy # Deploy to production
16
- * lua dev # Start development mode
17
- *
18
9
  * For more information: https://docs.heylua.ai
19
10
  */
20
11
  import { Command } from "commander";
@@ -24,8 +15,36 @@ const program = new Command();
24
15
  // Configure program metadata
25
16
  program
26
17
  .name("lua")
27
- .description("Lua AI Skill Management CLI")
28
- .version("2.3.0");
18
+ .description("Lua AI - Build and deploy AI agents with superpowers")
19
+ .version("2.4.0")
20
+ .addHelpText('before', `
21
+ ------------------------------------------------------------------
22
+ Lua AI CLI v2.4.0 - Build and deploy AI agents with superpowers
23
+ ------------------------------------------------------------------
24
+ `)
25
+ .addHelpText('after', `
26
+ Categories:
27
+ 🔐 Authentication Manage API keys and authentication
28
+ 🚀 Project Setup Initialize and configure projects
29
+ 📦 Development Build and test your skills locally
30
+ ☁️ Deployment Push and deploy to production
31
+ 💬 Testing Chat and test your agent
32
+ ⚙️ Configuration Manage environment and persona
33
+
34
+ Examples:
35
+ $ lua auth configure 🔑 Set up your API key
36
+ $ lua init 🚀 Initialize a new project
37
+ $ lua compile 📦 Compile your skills
38
+ $ lua test 🧪 Test tools interactively
39
+ $ lua push ☁️ Push to server
40
+ $ lua deploy 🚀 Deploy to production
41
+ $ lua chat 💬 Start interactive chat
42
+ $ lua env ⚙️ Manage environment variables
43
+ $ lua persona 🤖 Manage agent persona
44
+
45
+ 🌙 Documentation: https://docs.heylua.ai
46
+ 🌙 Support: https://heylua.ai/support
47
+ `);
29
48
  // Set up all command groups
30
49
  setupAuthCommands(program);
31
50
  setupSkillCommands(program);
@@ -46,62 +46,46 @@ export interface CreateAgentRequest {
46
46
  * Response from agent creation API.
47
47
  */
48
48
  export interface CreateAgentResponse {
49
- success: boolean;
50
- data?: {
51
- agentId: string;
52
- name: string;
53
- baseAgentId: string;
54
- persona: string;
55
- createdAt: string;
56
- welcomeMessage: string;
57
- featuresOverride: Record<string, any>;
49
+ agentId: string;
50
+ name: string;
51
+ baseAgentId: string;
52
+ persona: string;
53
+ createdAt: string;
54
+ welcomeMessage: string;
55
+ featuresOverride: Record<string, any>;
56
+ _id: string;
57
+ updatedAt: string;
58
+ __v: number;
59
+ org: {
60
+ registeredName: string;
61
+ type: string;
62
+ agents: string[];
63
+ paymentMethods: any[];
58
64
  _id: string;
59
- updatedAt: string;
65
+ id: string;
66
+ createdAt: number;
60
67
  __v: number;
61
- org: {
62
- registeredName: string;
63
- type: string;
64
- agents: string[];
65
- paymentMethods: any[];
66
- _id: string;
67
- id: string;
68
- createdAt: number;
69
- __v: number;
70
- };
71
- };
72
- error?: {
73
- message: string;
74
- error: string;
75
- statusCode: number;
76
68
  };
77
69
  }
78
70
  /**
79
71
  * Response from get agent details API.
80
72
  */
81
73
  export interface AgentDetailsResponse {
82
- success: boolean;
83
- data?: {
84
- _id: string;
85
- agentId: string;
86
- name: string;
87
- baseAgentId: string;
88
- persona: string;
89
- createdAt: string;
90
- welcomeMessage: string;
91
- featuresOverride: Record<string, any>;
92
- updatedAt: string;
93
- __v: number;
94
- personaConfig: {
95
- agentName: string;
96
- businessType: string;
97
- brandPersonality: string;
98
- brandTraits: string;
99
- };
100
- skills: any[];
101
- };
102
- error?: {
103
- message: string;
104
- error: string;
105
- statusCode: number;
74
+ _id: string;
75
+ agentId: string;
76
+ name: string;
77
+ baseAgentId: string;
78
+ persona: string;
79
+ createdAt: string;
80
+ welcomeMessage: string;
81
+ featuresOverride: Record<string, any>;
82
+ updatedAt: string;
83
+ __v: number;
84
+ personaConfig: {
85
+ agentName: string;
86
+ businessType: string;
87
+ brandPersonality: string;
88
+ brandTraits: string;
106
89
  };
90
+ skills: any[];
107
91
  }
@@ -27,11 +27,10 @@ export declare function loadApiKey(): Promise<string | null>;
27
27
  export declare function deleteApiKey(): Promise<boolean>;
28
28
  /**
29
29
  * Validates an API key with the server and retrieves user data.
30
- * This function will exit the process if the API key is invalid.
31
30
  *
32
31
  * @param apiKey - The API key to validate
33
32
  * @returns Promise resolving to user data including admin info and organizations
34
- * @throws Exits process with code 1 if API key is invalid
33
+ * @throws AuthenticationError if the API key is invalid
35
34
  */
36
35
  export declare function checkApiKey(apiKey: string): Promise<UserData>;
37
36
  /**
@@ -6,6 +6,7 @@ import keytar from "keytar";
6
6
  import AuthApi from "../api/auth.api.service.js";
7
7
  import { BASE_URLS } from "../config/constants.js";
8
8
  import { KEYTAR_SERVICE, KEYTAR_ACCOUNT } from "../config/auth.constants.js";
9
+ import { AuthenticationError } from "../errors/auth.error.js";
9
10
  // ============================================================================
10
11
  // KEYTAR OPERATIONS (Secure Local Storage)
11
12
  // ============================================================================
@@ -42,18 +43,16 @@ export async function deleteApiKey() {
42
43
  // ============================================================================
43
44
  /**
44
45
  * Validates an API key with the server and retrieves user data.
45
- * This function will exit the process if the API key is invalid.
46
46
  *
47
47
  * @param apiKey - The API key to validate
48
48
  * @returns Promise resolving to user data including admin info and organizations
49
- * @throws Exits process with code 1 if API key is invalid
49
+ * @throws AuthenticationError if the API key is invalid
50
50
  */
51
51
  export async function checkApiKey(apiKey) {
52
52
  const authApi = new AuthApi(BASE_URLS.API);
53
53
  const result = await authApi.checkApiKey(apiKey);
54
54
  if (!result.success) {
55
- console.error(`❌ Invalid API key`);
56
- process.exit(1);
55
+ throw new AuthenticationError("Invalid API key");
57
56
  }
58
57
  return result.data;
59
58
  }
@@ -8,6 +8,66 @@ import { build } from "esbuild";
8
8
  import { writeProgress } from "./cli.js";
9
9
  import { COMPILE_DIRS, COMPILE_FILES, ESBUILD_TOOL_CONFIG, ESBUILD_INDEX_CONFIG, DEFAULT_INPUT_SCHEMA, } from '../config/compile.constants.js';
10
10
  import { wrapToolForVM, createExecuteFunction, evaluateZodSchemaToJsonSchema, } from './compile.js';
11
+ /**
12
+ * esbuild plugin to inject sandbox globals instead of requiring lua-cli
13
+ * This removes require("lua-cli") statements and injects the global API objects
14
+ * that are available in the sandbox (Product, User, Data, Baskets, Order)
15
+ */
16
+ const sandboxGlobalsPlugin = {
17
+ name: 'sandbox-globals',
18
+ setup(build) {
19
+ // Only process user files, not node_modules
20
+ build.onLoad({ filter: /\.([jt]sx?)$/, namespace: 'file' }, async (args) => {
21
+ // Skip node_modules
22
+ if (args.path.includes('node_modules')) {
23
+ return null;
24
+ }
25
+ const contents = await fs.promises.readFile(args.path, 'utf8');
26
+ // Only transform files that import from lua-cli
27
+ if (!contents.includes('lua-cli')) {
28
+ return null;
29
+ }
30
+ // Replace lua-cli imports with global references
31
+ let transformedContents = contents;
32
+ // Replace named imports from lua-cli
33
+ // Match: import { Products, User, Data, etc. } from "lua-cli"
34
+ transformedContents = transformedContents.replace(/import\s+{([^}]+)}\s+from\s+["']lua-cli["'];?/g, (match, imports) => {
35
+ // Just remove the import, globals will be available in sandbox
36
+ return '// lua-cli imports removed - using sandbox globals';
37
+ });
38
+ // Replace lua-cli/skill imports - keep env and LuaTool as they might be needed
39
+ transformedContents = transformedContents.replace(/import\s+{([^}]+)}\s+from\s+["']lua-cli\/skill["'];?/g, (match, imports) => {
40
+ // Check if env is imported, if so we need to keep a reference
41
+ if (imports.includes('env')) {
42
+ return '// lua-cli/skill imports removed - env available in sandbox';
43
+ }
44
+ return '// lua-cli/skill imports removed - using sandbox globals';
45
+ });
46
+ // Map import names to sandbox global names
47
+ // Products -> Product, Orders -> Order, etc.
48
+ const globalMappings = {
49
+ 'Products': 'Products',
50
+ 'User': 'User',
51
+ 'Data': 'Data',
52
+ 'Baskets': 'Baskets',
53
+ 'Orders': 'Orders'
54
+ };
55
+ // Replace usage of imported names with globals
56
+ for (const [importName, globalName] of Object.entries(globalMappings)) {
57
+ // Replace standalone usage (e.g., Products.method() -> Product.method())
58
+ const regex = new RegExp(`\\b${importName}\\.`, 'g');
59
+ transformedContents = transformedContents.replace(regex, `${globalName}.`);
60
+ }
61
+ // Note: env function and LuaTool interface are already available in sandbox
62
+ // env is a function in the sandbox context (see sandbox.ts line 333)
63
+ return {
64
+ contents: transformedContents,
65
+ loader: args.path.endsWith('.ts') ? 'ts' :
66
+ args.path.endsWith('.tsx') ? 'tsx' : 'js'
67
+ };
68
+ });
69
+ },
70
+ };
11
71
  /**
12
72
  * Bundles a tool's TypeScript code into a standalone JavaScript file.
13
73
  * Uses esbuild to:
@@ -26,6 +86,7 @@ export async function bundleTool(tool, distDir) {
26
86
  ...ESBUILD_TOOL_CONFIG,
27
87
  entryPoints: [tool.filePath],
28
88
  outfile: outputPath,
89
+ plugins: [sandboxGlobalsPlugin],
29
90
  });
30
91
  // Wrap the bundled code for VM execution environment
31
92
  await wrapToolForVM(outputPath, tool);
package/dist/utils/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Centralized CLI utilities for consistent error handling and output management
3
3
  */
4
+ import { AuthenticationError } from "../errors/auth.error.js";
4
5
  /**
5
6
  * Wraps a command function with standardized error handling
6
7
  * Handles SIGINT (Ctrl+C) gracefully and provides consistent error messages
@@ -14,6 +15,11 @@ export async function withErrorHandling(commandFn, commandName) {
14
15
  console.log("\n❌ Operation cancelled.");
15
16
  process.exit(0);
16
17
  }
18
+ if (AuthenticationError.isAuthenticationError(error)) {
19
+ console.error(`❌ Authentication failed: ${error.message}`);
20
+ console.error("💡 Run 'lua auth configure' to update your API key.");
21
+ process.exit(1);
22
+ }
17
23
  console.error(`❌ Error during ${commandName}:`, error.message);
18
24
  process.exit(1);
19
25
  }
@@ -3,6 +3,14 @@
3
3
  * Helper functions for deployment operations
4
4
  */
5
5
  import { VersionInfo } from '../interfaces/deploy.js';
6
+ /**
7
+ * Selected skill for deployment.
8
+ */
9
+ export interface SelectedSkillForDeploy {
10
+ name: string;
11
+ version: string;
12
+ skillId: string;
13
+ }
6
14
  /**
7
15
  * Formats a version for display in the selection list.
8
16
  *
@@ -30,6 +38,13 @@ export declare function promptVersionSelection(versions: VersionInfo[]): Promise
30
38
  * @returns True if confirmed, false otherwise
31
39
  */
32
40
  export declare function confirmDeployment(): Promise<boolean>;
41
+ /**
42
+ * Prompts user to select a skill from available skills.
43
+ *
44
+ * @param skills - Array of available skills
45
+ * @returns Selected skill
46
+ */
47
+ export declare function promptSkillSelection(skills: SelectedSkillForDeploy[]): Promise<SelectedSkillForDeploy>;
33
48
  /**
34
49
  * Validates that configuration has required fields for deployment.
35
50
  *
@@ -37,6 +52,13 @@ export declare function confirmDeployment(): Promise<boolean>;
37
52
  * @throws Error if configuration is invalid
38
53
  */
39
54
  export declare function validateDeployConfig(config: any): void;
55
+ /**
56
+ * Gets available skills from configuration.
57
+ *
58
+ * @param config - Skill configuration
59
+ * @returns Array of available skills
60
+ */
61
+ export declare function getAvailableSkills(config: any): SelectedSkillForDeploy[];
40
62
  /**
41
63
  * Validates that versions are available for deployment.
42
64
  *
@@ -62,6 +62,28 @@ export async function confirmDeployment() {
62
62
  clearPromptLines(2);
63
63
  return confirmed;
64
64
  }
65
+ /**
66
+ * Prompts user to select a skill from available skills.
67
+ *
68
+ * @param skills - Array of available skills
69
+ * @returns Selected skill
70
+ */
71
+ export async function promptSkillSelection(skills) {
72
+ const skillChoices = skills.map((skill) => ({
73
+ name: `${skill.name} (v${skill.version})`,
74
+ value: skill
75
+ }));
76
+ const { selectedSkill } = await inquirer.prompt([
77
+ {
78
+ type: "list",
79
+ name: "selectedSkill",
80
+ message: "Select a skill to deploy:",
81
+ choices: skillChoices
82
+ }
83
+ ]);
84
+ clearPromptLines(2);
85
+ return selectedSkill;
86
+ }
65
87
  /**
66
88
  * Validates that configuration has required fields for deployment.
67
89
  *
@@ -69,9 +91,46 @@ export async function confirmDeployment() {
69
91
  * @throws Error if configuration is invalid
70
92
  */
71
93
  export function validateDeployConfig(config) {
72
- if (!config || !config.agent?.agentId || !config.skill?.skillId) {
73
- throw new Error("No lua.skill.yaml found or missing agentId/skillId. Please run this command from a skill directory.");
94
+ if (!config) {
95
+ throw new Error("No lua.skill.yaml found. Please run this command from a skill directory.");
96
+ }
97
+ if (!config.agent?.agentId) {
98
+ throw new Error("Missing agentId in skill configuration");
99
+ }
100
+ // Check for new multi-skill format
101
+ if (config.skills && Array.isArray(config.skills) && config.skills.length > 0) {
102
+ return; // Valid multi-skill config
103
+ }
104
+ // Check for legacy single-skill format
105
+ if (config.skill?.skillId) {
106
+ return; // Valid legacy config
107
+ }
108
+ throw new Error("No skills found in configuration. Please compile your skill first.");
109
+ }
110
+ /**
111
+ * Gets available skills from configuration.
112
+ *
113
+ * @param config - Skill configuration
114
+ * @returns Array of available skills
115
+ */
116
+ export function getAvailableSkills(config) {
117
+ // Check for new multi-skill format
118
+ if (config.skills && Array.isArray(config.skills) && config.skills.length > 0) {
119
+ return config.skills.map((skill) => ({
120
+ name: skill.name,
121
+ version: skill.version,
122
+ skillId: skill.skillId
123
+ }));
124
+ }
125
+ // Fallback to legacy single-skill format
126
+ if (config.skill) {
127
+ return [{
128
+ name: config.skill.name || 'unnamed-skill',
129
+ version: config.skill.version,
130
+ skillId: config.skill.skillId
131
+ }];
74
132
  }
133
+ return [];
75
134
  }
76
135
  /**
77
136
  * Validates that versions are available for deployment.
@@ -62,9 +62,11 @@ export async function createLegacyDeploymentData(tools, luaDir, indexFile) {
62
62
  const skillsArray = buildSkillsArray(skillsMetadata, skillToTools, tools);
63
63
  // Ensure all skills exist in YAML config and have valid IDs
64
64
  const updatedSkillsArray = await ensureSkillsExistInYaml(skillsArray, config);
65
+ // Override versions from YAML config if they exist
66
+ const finalSkillsArray = overrideVersionsFromConfig(updatedSkillsArray, config);
65
67
  // Write deployment data
66
68
  const deployData = {
67
- skills: updatedSkillsArray
69
+ skills: finalSkillsArray
68
70
  };
69
71
  fs.writeFileSync(path.join(luaDir, COMPILE_FILES.DEPLOY_JSON), JSON.stringify(deployData, null, JSON_FORMAT.INDENT));
70
72
  // Write individual tool files (uncompressed for debugging)
@@ -144,6 +146,36 @@ function buildSkillsArray(skillsMetadata, skillToTools, tools) {
144
146
  };
145
147
  });
146
148
  }
149
+ /**
150
+ * Overrides skill versions from YAML config.
151
+ * This ensures that any version updates in the YAML take precedence over code versions.
152
+ *
153
+ * @param skillsArray - Array of skills from code
154
+ * @param config - Skill configuration from YAML
155
+ * @returns Skills array with versions overridden from config
156
+ */
157
+ function overrideVersionsFromConfig(skillsArray, config) {
158
+ // Get version map from YAML config
159
+ const configVersionMap = new Map();
160
+ if (config.skills && Array.isArray(config.skills)) {
161
+ config.skills.forEach((skill) => {
162
+ if (skill.name && skill.version) {
163
+ configVersionMap.set(skill.name, skill.version);
164
+ }
165
+ });
166
+ }
167
+ // Override versions in skills array
168
+ return skillsArray.map(skill => {
169
+ const configVersion = configVersionMap.get(skill.name);
170
+ if (configVersion) {
171
+ return {
172
+ ...skill,
173
+ version: configVersion
174
+ };
175
+ }
176
+ return skill;
177
+ });
178
+ }
147
179
  /**
148
180
  * Writes individual tool files to the .lua directory for debugging.
149
181
  * These are uncompressed versions of the tool code.