lua-cli 3.0.1 → 3.0.2-alpha.1

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.
@@ -47,8 +47,8 @@ export async function chatCommand() {
47
47
  name: 'environment',
48
48
  message: 'Select environment:',
49
49
  choices: [
50
- { name: 'šŸ”§ Sandbox (with skill overrides)', value: 'sandbox' },
51
- { name: 'šŸš€ Production', value: 'production' }
50
+ { name: 'šŸ”§ Sandbox (Agent will execute skills etc from your local machine)', value: 'sandbox' },
51
+ { name: 'šŸš€ Production (Agent will execute latest version of skills etc)', value: 'production' }
52
52
  ]
53
53
  }
54
54
  ]);
@@ -45,7 +45,7 @@ export async function chatClearCommand() {
45
45
  }
46
46
  ]);
47
47
  if (!confirmAnswer || !confirmAnswer.confirm) {
48
- console.log("\nāŒ Operation cancelled. History not cleared.\n");
48
+ // console.log("\nāŒ Operation cancelled. History not cleared.\n");
49
49
  return;
50
50
  }
51
51
  // Step 4: Clear history via API
@@ -233,7 +233,7 @@ async function toggleFeature(context, feature) {
233
233
  }
234
234
  ]);
235
235
  if (!confirmAnswer || !confirmAnswer.confirm) {
236
- console.log("\nāŒ Operation cancelled.\n");
236
+ // console.log("\nāŒ Operation cancelled.\n");
237
237
  return;
238
238
  }
239
239
  writeProgress(`šŸ”„ ${newStatus ? 'Activating' : 'Deactivating'} feature...`);
@@ -5,7 +5,7 @@
5
5
  import inquirer from 'inquirer';
6
6
  import { loadApiKey, checkApiKey } from "../services/auth.js";
7
7
  import { withErrorHandling, writeProgress, writeSuccess, writeInfo, writeError, } from "../utils/cli.js";
8
- import { promptAgentChoice, promptOrganizationSelection, promptAgentSelection, promptMetadataCollection, promptFeatureConfiguration, promptBusinessConfiguration, } from "../utils/init-prompts.js";
8
+ import { promptAgentChoice, promptOrganizationSelection, promptAgentSelection, promptMetadataCollection, promptBusinessConfiguration, } from "../utils/init-prompts.js";
9
9
  import { fetchAgentTypes, selectBaseAgentType, createNewAgent, fetchExistingAgentDetails, } from "../utils/init-agent.js";
10
10
  import { initializeProject, installDependencies, clearLinesIfNeeded, } from "../utils/init-helpers.js";
11
11
  import { readSkillYaml, updateYamlAgent } from "../utils/files.js";
@@ -84,9 +84,13 @@ export async function initCommand() {
84
84
  writeInfo(` Current Agent ID: ${existingAgentId}\n`);
85
85
  const { wantSwitch } = await inquirer.prompt([
86
86
  {
87
- type: 'confirm',
87
+ type: 'list',
88
88
  name: 'wantSwitch',
89
89
  message: 'Do you want to switch this project to a different agent?',
90
+ choices: [
91
+ { name: 'No - Keep current agent', value: false },
92
+ { name: 'Yes - Switch to a different agent', value: true }
93
+ ],
90
94
  default: false
91
95
  }
92
96
  ]);
@@ -232,12 +236,12 @@ async function createNewAgentFlow(apiKey, userData) {
232
236
  const metadata = selectedAgentType.requiredSubAgentMetadata?.length
233
237
  ? await promptMetadataCollection(selectedAgentType.requiredSubAgentMetadata)
234
238
  : {};
235
- // Configure features
239
+ // Enable all features by default (skip configuration prompt)
236
240
  const availableFeatures = Object.keys(selectedAgentType.features);
237
- const features = availableFeatures.length > 0
238
- ? await promptFeatureConfiguration(selectedAgentType)
239
- : {};
240
- linesToClear += availableFeatures.length;
241
+ const features = availableFeatures.reduce((acc, feature) => {
242
+ acc[feature] = true;
243
+ return acc;
244
+ }, {});
241
245
  // Collect business configuration
242
246
  // If using existing org, don't ask for business name (use org name)
243
247
  const businessConfig = await promptBusinessConfiguration(usingExistingOrg);
@@ -8,11 +8,11 @@ export declare const AGENT_READY_WAIT_TIME = 30000;
8
8
  /**
9
9
  * Business type options for agent creation
10
10
  */
11
- export declare const BUSINESS_TYPES: readonly ["Retail & Consumer Goods (e.g. clothing store, bookstore)", "Food & Beverage (e.g. restaurant, bakery)", "Hospitality (e.g. hotel, resort)", "Personal services (e.g. hair salon, spa)", "Education (e.g. language school, online courses)", "Health (e.g. gym, yoga studio, clinic)"];
11
+ export declare const BUSINESS_TYPES: readonly ["Retail & Consumer Goods (e.g. clothing store, bookstore)", "Food & Beverage (e.g. restaurant, bakery)", "Hospitality (e.g. hotel, resort)", "Personal services (e.g. hair salon, spa)", "Education (e.g. language school, online courses)", "Health (e.g. gym, yoga studio, clinic)", "Other (describe your business)"];
12
12
  /**
13
13
  * Brand personality options for agent creation
14
14
  */
15
- export declare const BRAND_PERSONALITIES: readonly ["Energetic & fun", "Refined & elegant", "Chatty", "Casual", "Funny", "Friendly"];
15
+ export declare const BRAND_PERSONALITIES: readonly ["Energetic & fun", "Refined & elegant", "Chatty", "Casual", "Funny", "Friendly", "Other (describe your brand personality)"];
16
16
  /**
17
17
  * Default business name
18
18
  */
@@ -14,7 +14,8 @@ export const BUSINESS_TYPES = [
14
14
  "Hospitality (e.g. hotel, resort)",
15
15
  "Personal services (e.g. hair salon, spa)",
16
16
  "Education (e.g. language school, online courses)",
17
- "Health (e.g. gym, yoga studio, clinic)"
17
+ "Health (e.g. gym, yoga studio, clinic)",
18
+ "Other (describe your business)"
18
19
  ];
19
20
  /**
20
21
  * Brand personality options for agent creation
@@ -25,7 +26,8 @@ export const BRAND_PERSONALITIES = [
25
26
  "Chatty",
26
27
  "Casual",
27
28
  "Funny",
28
- "Friendly"
29
+ "Friendly",
30
+ "Other (describe your brand personality)"
29
31
  ];
30
32
  /**
31
33
  * Default business name
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import inquirer from "inquirer";
6
6
  import { saveApiKey, checkApiKey, requestEmailOTP, verifyOTPAndGetToken, generateApiKey } from "../services/auth.js";
7
- import { clearPromptLines, writeProgress, writeSuccess } from "./cli.js";
7
+ import { clearPromptLines, writeProgress, writeSuccess, writeInfo } from "./cli.js";
8
8
  /**
9
9
  * Configuration for OTP verification
10
10
  */
@@ -57,12 +57,13 @@ export async function handleEmailAuth() {
57
57
  ]);
58
58
  clearPromptLines(2);
59
59
  // Step 2: Send OTP
60
- writeProgress("šŸ“§ Sending OTP to your email...");
61
- const otpSent = await requestEmailOTP(email);
62
- if (!otpSent) {
63
- throw new Error("Failed to send OTP. Please try again.");
64
- }
65
- writeProgress("āœ… OTP sent successfully!");
60
+ // writeProgress("šŸ“§ Sending OTP to your email...");
61
+ requestEmailOTP(email).catch((error) => {
62
+ });
63
+ // if (!otpSent) {
64
+ // throw new Error("Failed to send OTP. Please try again.");
65
+ // }
66
+ // writeProgress("āœ… OTP sent successfully!");
66
67
  // Step 3: Verify OTP with retry logic
67
68
  const signInToken = await verifyOTPWithRetry(email);
68
69
  // Step 4: Generate API key
@@ -74,6 +75,14 @@ export async function handleEmailAuth() {
74
75
  // Step 5: Save API key
75
76
  await saveApiKey(apiKey);
76
77
  writeSuccess("āœ… API key generated and saved securely.");
78
+ // Guide user to next steps
79
+ writeInfo("\nšŸŽ‰ You're all set! Here's what to do next:\n");
80
+ writeInfo(" 1ļøāƒ£ Create a new project directory:");
81
+ writeInfo(" mkdir my-agent && cd my-agent\n");
82
+ writeInfo(" 2ļøāƒ£ Initialize your agent:");
83
+ writeInfo(" lua init\n");
84
+ writeInfo(" 3ļøāƒ£ Follow the prompts to create or select an agent\n");
85
+ writeInfo("šŸ’” Tip: Run 'lua --help' to see all available commands\n");
77
86
  }
78
87
  /**
79
88
  * Verifies OTP with retry logic.
@@ -92,7 +101,7 @@ async function verifyOTPWithRetry(email) {
92
101
  {
93
102
  type: "input",
94
103
  name: "pin",
95
- message: "Enter the OTP code:",
104
+ message: "Enter the OTP sent to your email:",
96
105
  validate: (input) => {
97
106
  return input.length === OTP_CONFIG.OTP_LENGTH || `OTP must be ${OTP_CONFIG.OTP_LENGTH} digits`;
98
107
  }
@@ -13,22 +13,22 @@ export declare function withErrorHandling<T>(commandFn: () => Promise<T>, comman
13
13
  */
14
14
  export declare function clearPromptLines(count?: number): void;
15
15
  /**
16
- * Writes a progress message that will be replaced by the next message
17
- * Uses carriage return to overwrite the current line
16
+ * Writes a progress message that overwrites the current line
17
+ * Uses carriage return to replace previous progress messages
18
18
  */
19
19
  export declare function writeProgress(message: string): void;
20
20
  /**
21
21
  * Writes a final success message that will remain visible
22
- * Uses console.log to ensure it stays in the output
22
+ * Clears the progress line first, then writes the message with newline
23
23
  */
24
24
  export declare function writeSuccess(message: string): void;
25
25
  /**
26
26
  * Writes an error message
27
- * Uses console.error for proper error output
27
+ * Clears the progress line first, then writes the error with newline
28
28
  */
29
29
  export declare function writeError(message: string): void;
30
30
  /**
31
31
  * Writes an info message
32
- * Uses console.log for informational output
32
+ * Clears the progress line first, then writes the message with newline
33
33
  */
34
34
  export declare function writeInfo(message: string): void;
package/dist/utils/cli.js CHANGED
@@ -12,7 +12,7 @@ export async function withErrorHandling(commandFn, commandName) {
12
12
  }
13
13
  catch (error) {
14
14
  if (error.name === 'ExitPromptError') {
15
- console.log("\nāŒ Operation cancelled.");
15
+ // console.log("\nāŒ Operation cancelled.");
16
16
  process.exit(0);
17
17
  }
18
18
  if (AuthenticationError.isAuthenticationError(error)) {
@@ -35,30 +35,34 @@ export function clearPromptLines(count = 1) {
35
35
  }
36
36
  }
37
37
  /**
38
- * Writes a progress message that will be replaced by the next message
39
- * Uses carriage return to overwrite the current line
38
+ * Writes a progress message that overwrites the current line
39
+ * Uses carriage return to replace previous progress messages
40
40
  */
41
41
  export function writeProgress(message) {
42
- process.stdout.write(`${message}\r`);
42
+ // Clear current line and write message (no newline - will be overwritten)
43
+ process.stdout.write('\r\x1b[K' + message);
43
44
  }
44
45
  /**
45
46
  * Writes a final success message that will remain visible
46
- * Uses console.log to ensure it stays in the output
47
+ * Clears the progress line first, then writes the message with newline
47
48
  */
48
49
  export function writeSuccess(message) {
49
- console.log(message);
50
+ // Clear any progress message, write message, and ensure newline
51
+ process.stdout.write('\r\x1b[K' + message + '\n');
50
52
  }
51
53
  /**
52
54
  * Writes an error message
53
- * Uses console.error for proper error output
55
+ * Clears the progress line first, then writes the error with newline
54
56
  */
55
57
  export function writeError(message) {
56
- console.error(message);
58
+ // Clear any progress message, write error, and ensure newline
59
+ process.stderr.write('\r\x1b[K' + message + '\n');
57
60
  }
58
61
  /**
59
62
  * Writes an info message
60
- * Uses console.log for informational output
63
+ * Clears the progress line first, then writes the message with newline
61
64
  */
62
65
  export function writeInfo(message) {
63
- console.log(message);
66
+ // Clear any progress message, write message, and ensure newline
67
+ process.stdout.write('\r\x1b[K' + message + '\n');
64
68
  }
@@ -14,10 +14,10 @@ export async function promptAgentChoice() {
14
14
  {
15
15
  type: "list",
16
16
  name: "agentChoice",
17
- message: "What would you like to do?",
17
+ message: "How would you like to create your AI Agent?",
18
18
  choices: [
19
- { name: "Select existing agent", value: "existing" },
20
- { name: "Create new agent", value: "create" }
19
+ { name: "Extend one of your existing agents", value: "existing" },
20
+ { name: "Create a new agent", value: "create" }
21
21
  ]
22
22
  }
23
23
  ]);
@@ -147,6 +147,19 @@ export async function promptBusinessConfiguration(skipBusinessName = false) {
147
147
  choices: BUSINESS_TYPES
148
148
  }
149
149
  ]);
150
+ // If "Other" selected, prompt for custom description
151
+ let customBusinessDescription = '';
152
+ if (businessType.startsWith('Other')) {
153
+ const { description } = await inquirer.prompt([
154
+ {
155
+ type: "input",
156
+ name: "description",
157
+ message: "Describe your business:",
158
+ validate: (input) => input.trim().length > 0 || "Business description is required"
159
+ }
160
+ ]);
161
+ customBusinessDescription = description;
162
+ }
150
163
  const { brandPersonality } = await inquirer.prompt([
151
164
  {
152
165
  type: "list",
@@ -155,6 +168,19 @@ export async function promptBusinessConfiguration(skipBusinessName = false) {
155
168
  choices: BRAND_PERSONALITIES
156
169
  }
157
170
  ]);
171
+ // If "Other" selected, prompt for custom personality description
172
+ let customPersonalityDescription = '';
173
+ if (brandPersonality.startsWith('Other')) {
174
+ const { description } = await inquirer.prompt([
175
+ {
176
+ type: "input",
177
+ name: "description",
178
+ message: "Describe your brand personality:",
179
+ validate: (input) => input.trim().length > 0 || "Brand personality description is required"
180
+ }
181
+ ]);
182
+ customPersonalityDescription = description;
183
+ }
158
184
  const { brandTraits } = await inquirer.prompt([
159
185
  {
160
186
  type: "input",
@@ -166,8 +192,8 @@ export async function promptBusinessConfiguration(skipBusinessName = false) {
166
192
  return {
167
193
  businessName,
168
194
  agentName,
169
- businessType,
170
- brandPersonality,
195
+ businessType: customBusinessDescription || businessType, // Use custom description if provided
196
+ brandPersonality: customPersonalityDescription || brandPersonality, // Use custom personality if provided
171
197
  brandTraits
172
198
  };
173
199
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  /**
6
6
  * Wraps inquirer.prompt to gracefully handle Ctrl+C interruptions
7
+ * Also ensures clean terminal state before showing prompts
7
8
  */
8
9
  export declare function safePrompt<T = any>(questions: any): Promise<T | null>;
9
10
  /**
@@ -5,16 +5,20 @@
5
5
  import inquirer from 'inquirer';
6
6
  /**
7
7
  * Wraps inquirer.prompt to gracefully handle Ctrl+C interruptions
8
+ * Also ensures clean terminal state before showing prompts
8
9
  */
9
10
  export async function safePrompt(questions) {
10
11
  try {
12
+ // Ensure any previous output is fully flushed before showing prompt
13
+ // Small delay to let terminal render previous messages
14
+ await new Promise(resolve => setTimeout(resolve, 10));
11
15
  const answers = await inquirer.prompt(questions);
12
16
  return answers;
13
17
  }
14
18
  catch (error) {
15
19
  // Handle Ctrl+C gracefully
16
20
  if (error.name === 'ExitPromptError' || error.message?.includes('SIGINT')) {
17
- console.log('\n\nšŸ‘‹ Operation cancelled. Goodbye!\n');
21
+ // console.log('\n\nšŸ‘‹ Operation cancelled. Goodbye!\n');
18
22
  process.exit(0);
19
23
  }
20
24
  throw error;
@@ -25,7 +29,7 @@ export async function safePrompt(questions) {
25
29
  */
26
30
  export function setupGlobalInterruptHandler() {
27
31
  process.on('SIGINT', () => {
28
- console.log('\n\nšŸ‘‹ Operation cancelled. Goodbye!\n');
32
+ // console.log('\n\nšŸ‘‹ Operation cancelled. Goodbye!\n');
29
33
  process.exit(0);
30
34
  });
31
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lua-cli",
3
- "version": "3.0.1",
3
+ "version": "3.0.2-alpha.1",
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",
@@ -20,7 +20,7 @@
20
20
  "inquirer": "^12.9.6",
21
21
  "stripe": "^17.5.0",
22
22
  "js-yaml": "^4.1.0",
23
- "lua-cli": "^3.0.0",
23
+ "lua-cli": "^3.0.2-alpha.1",
24
24
  "openai": "^5.23.0",
25
25
  "uuid": "^13.0.0",
26
26
  "zod": "^3.24.1"
@@ -1,4 +1,4 @@
1
- import { LuaTool } from "lua-cli/skill";
1
+ import { LuaTool } from "lua-cli";
2
2
  import { z } from "zod";
3
3
  import { AI, JobInstance, Jobs } from "../../../dist/api-exports";
4
4
  import ApiService from "../services/ApiService";
@@ -1,4 +1,4 @@
1
- import { LuaTool } from "lua-cli/skill";
1
+ import { LuaTool } from "lua-cli";
2
2
  import { z } from "zod";
3
3
  import ApiService from "../services/ApiService";
4
4
 
@@ -1,4 +1,4 @@
1
- import { LuaTool } from "lua-cli/skill";
1
+ import { LuaTool } from "lua-cli";
2
2
  import { z } from "zod";
3
3
 
4
4
  export default class GetWeatherTool implements LuaTool {
@@ -10,7 +10,14 @@ export class GetUserDataTool implements LuaTool {
10
10
  constructor() {}
11
11
 
12
12
  async execute(input: z.infer<typeof this.inputSchema>) {
13
- return User.get();
13
+ const user = await User.get();
14
+ return {
15
+ success: true,
16
+ message: "User data retrieved",
17
+ data: user.data,
18
+ name: user.name,
19
+ age: user.age
20
+ };
14
21
  }
15
22
  }
16
23
 
@@ -28,8 +35,14 @@ export class UpdateUserDataTool implements LuaTool {
28
35
 
29
36
  async execute(input: z.infer<typeof this.inputSchema>) {
30
37
  const user = await User.get(); //get instance of user
31
- await user.send([{ type: "text", text: "Hello, how are you?" }]);
32
- return await user.update(input.data);
38
+ user.name = input.data.name;
39
+ user.age = input.data.age;
40
+ await user.save();
41
+ // await user.send([{ type: "text", text: "Hello, how are you?" }]);
42
+ return {
43
+ success: true,
44
+ message: "User data updated"
45
+ };
33
46
  }
34
47
  }
35
48
 
@@ -1,47 +0,0 @@
1
- agent:
2
- agentId: baseAgent_agent_1760922427216_fk9w0ezhh
3
- orgId: 026cc41b-e013-4474-9b65-5a15f8881f92
4
- persona: |
5
- Meet Vivienne, the vibrant and dynamic assistant at V3 Test, a lively retail and consumer goods store that specializes in bringing a splash of color and excitement to everyday life. Vivienne embodies the brand's energetic and fun personality, always ready to engage with customers in a way that makes shopping an enjoyable and memorable experience. Her role is to be the friendly face and knowledgeable guide for anyone who steps into the store, whether they're looking for the latest fashion trends or a unique gift for a loved one.
6
-
7
- V3 Test is all about creating a joyful and spirited shopping environment, and Vivienne is the perfect personification of this ethos. She is lively, approachable, and always ready with a smile, making every interaction feel like a conversation with a good friend. Her voice is warm and enthusiastic, with a hint of playfulness that puts customers at ease and encourages them to explore the store's offerings.
8
-
9
- Vivienne's target customers are diverse, ranging from young adults in their twenties who are fashion-forward and tech-savvy, to busy parents looking for quality products that add a touch of fun to their family life. She understands the fast-paced lifestyle of her customers and is adept at tailoring her approach to meet their individual needs, whether they're in a hurry or have time to browse.
10
-
11
- Her sales approach is consultative and friendly, focusing on understanding the customer's needs and preferences before suggesting products that align with their style and personality. Vivienne is confident in her recommendations, always ready to upsell when appropriate, but never pushy. She believes in building relationships with customers, ensuring they leave the store not only with products they love but also with a positive impression of the brand.
12
-
13
- In terms of communication style, Vivienne strikes a perfect balance between being informal and efficient. She is warm and engaging, making customers feel valued and appreciated, while also being mindful of their time. Her interactions are peppered with humor and light-hearted banter, creating a shopping experience that is both enjoyable and efficient. Whether it's through in-person interactions or digital communication, Vivienne ensures that every customer feels like a part of the V3 Test family.
14
- welcomeMessage: Hi, I am your AI assistant. How can I help you today?
15
- skills:
16
- - name: general-skill
17
- version: 0.0.6
18
- skillId: 1faf9b3a-e352-4e63-a6c4-a3deca815361
19
- - name: user-data-skill
20
- version: 0.0.15
21
- skillId: e0c382c1-f469-4880-962a-a756ea3c1411
22
- - name: product-skill
23
- version: 0.0.15
24
- skillId: d4cdc7bc-6d42-4232-902d-2b9cf68bd74a
25
- - name: basket-skill
26
- version: 0.0.14
27
- skillId: 5b06c5ff-7cf3-49c4-8641-142270c81db4
28
- - name: order-skill
29
- version: 0.0.14
30
- skillId: d4045304-7c30-4750-9edd-340eb1357a39
31
- - name: custom-data-skill
32
- version: 0.0.13
33
- skillId: 83fe411c-90a1-4bd3-9271-ac8e03d6a3be
34
- - name: payment-skill
35
- version: 0.0.13
36
- skillId: f2248c02-c6c6-4c3a-89bf-ff09ec11529a
37
- jobs:
38
- - name: test-job
39
- version: 1.0.13
40
- jobId: d66b73a0-f944-4718-b6a2-f07bfeabd625
41
- schedule:
42
- type: once
43
- executeAt: '2025-10-20T01:08:04.639Z'
44
- webhooks:
45
- - name: test-webhook
46
- version: 1.0.12
47
- webhookId: c967fd58-1d4d-49b6-8fa6-ec36b4d23e7f