lua-cli 2.3.0 → 2.3.2

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.
@@ -7,13 +7,15 @@
7
7
  *
8
8
  * This command performs the following steps:
9
9
  * 1. Validates configuration has required fields
10
- * 2. Authenticates the user
11
- * 3. Fetches available versions from server
12
- * 4. Prompts user to select a version
13
- * 5. Shows warning and requests confirmation
14
- * 6. Publishes selected version to production
10
+ * 2. Prompts user to select a skill (if multiple skills exist)
11
+ * 3. Authenticates the user
12
+ * 4. Fetches available versions from server for selected skill
13
+ * 5. Prompts user to select a version
14
+ * 6. Shows warning and requests confirmation
15
+ * 7. Publishes selected version to production
15
16
  *
16
17
  * Features:
18
+ * - Supports multi-skill projects
17
19
  * - Lists all available versions with metadata
18
20
  * - Shows which version is currently deployed
19
21
  * - Sorts versions by date (newest first)
@@ -4,21 +4,23 @@
4
4
  */
5
5
  import { loadApiKey, checkApiKey } from '../services/auth.js';
6
6
  import { readSkillConfig } from '../utils/files.js';
7
- import { withErrorHandling, writeProgress, writeSuccess } from '../utils/cli.js';
8
- import { sortVersionsByDate, promptVersionSelection, confirmDeployment, validateDeployConfig, validateVersionsAvailable, } from '../utils/deploy-helpers.js';
7
+ import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
8
+ import { sortVersionsByDate, promptVersionSelection, confirmDeployment, validateDeployConfig, validateVersionsAvailable, promptSkillSelection, getAvailableSkills, } from '../utils/deploy-helpers.js';
9
9
  import { fetchVersions, publishVersion } from '../utils/deploy-api.js';
10
10
  /**
11
11
  * Main deploy command - deploys a skill version to production.
12
12
  *
13
13
  * This command performs the following steps:
14
14
  * 1. Validates configuration has required fields
15
- * 2. Authenticates the user
16
- * 3. Fetches available versions from server
17
- * 4. Prompts user to select a version
18
- * 5. Shows warning and requests confirmation
19
- * 6. Publishes selected version to production
15
+ * 2. Prompts user to select a skill (if multiple skills exist)
16
+ * 3. Authenticates the user
17
+ * 4. Fetches available versions from server for selected skill
18
+ * 5. Prompts user to select a version
19
+ * 6. Shows warning and requests confirmation
20
+ * 7. Publishes selected version to production
20
21
  *
21
22
  * Features:
23
+ * - Supports multi-skill projects
22
24
  * - Lists all available versions with metadata
23
25
  * - Shows which version is currently deployed
24
26
  * - Sorts versions by date (newest first)
@@ -39,7 +41,24 @@ export async function deployCommand() {
39
41
  // Step 1: Validate configuration
40
42
  const config = readSkillConfig();
41
43
  validateDeployConfig(config);
42
- // Step 2: Authenticate
44
+ // Step 2: Get available skills and prompt for selection
45
+ const availableSkills = getAvailableSkills(config);
46
+ if (availableSkills.length === 0) {
47
+ console.error("āŒ No skills found in configuration. Please compile your skill first using 'lua compile'.");
48
+ process.exit(1);
49
+ }
50
+ let selectedSkill;
51
+ if (availableSkills.length === 1) {
52
+ // Only one skill, use it automatically
53
+ selectedSkill = availableSkills[0];
54
+ writeInfo(`šŸ“¦ Deploying skill: ${selectedSkill.name}`);
55
+ }
56
+ else {
57
+ // Multiple skills, prompt for selection
58
+ selectedSkill = await promptSkillSelection(availableSkills);
59
+ writeInfo(`šŸ“¦ Selected skill: ${selectedSkill.name}`);
60
+ }
61
+ // Step 3: Authenticate
43
62
  const apiKey = await loadApiKey();
44
63
  if (!apiKey) {
45
64
  console.error("āŒ No API key found. Please run 'lua auth configure' to set up your API key.");
@@ -47,22 +66,22 @@ export async function deployCommand() {
47
66
  }
48
67
  const userData = await checkApiKey(apiKey);
49
68
  writeProgress("āœ… Authenticated");
50
- // Step 3: Fetch available versions
69
+ // Step 4: Fetch available versions for the selected skill
51
70
  writeProgress("šŸ”„ Fetching available versions...");
52
- const versionsResponse = await fetchVersions(apiKey, config.agent.agentId, config.skill.skillId);
71
+ const versionsResponse = await fetchVersions(apiKey, config.agent.agentId, selectedSkill.skillId);
53
72
  validateVersionsAvailable(versionsResponse.versions);
54
- // Step 4: Sort and display versions
73
+ // Step 5: Sort and display versions
55
74
  const sortedVersions = sortVersionsByDate(versionsResponse.versions);
56
75
  const selectedVersion = await promptVersionSelection(sortedVersions);
57
- // Step 5: Confirm deployment
76
+ // Step 6: Confirm deployment
58
77
  const confirmed = await confirmDeployment();
59
78
  if (!confirmed) {
60
79
  console.log("āŒ Deployment cancelled.");
61
80
  process.exit(0);
62
81
  }
63
- // Step 6: Publish the selected version
82
+ // Step 7: Publish the selected version
64
83
  writeProgress("šŸ”„ Publishing version...");
65
- const publishResponse = await publishVersion(apiKey, config.agent.agentId, config.skill.skillId, selectedVersion);
66
- writeSuccess(`āœ… Version ${publishResponse.activeVersionId} deployed successfully`);
84
+ const publishResponse = await publishVersion(apiKey, config.agent.agentId, selectedSkill.skillId, selectedVersion);
85
+ writeSuccess(`āœ… Version ${publishResponse.activeVersionId} of "${selectedSkill.name}" deployed successfully`);
67
86
  }, "deployment");
68
87
  }
@@ -3,7 +3,7 @@
3
3
  * Orchestrates the initialization of a new Lua skill project
4
4
  */
5
5
  import { loadApiKey, checkApiKey } from "../services/auth.js";
6
- import { withErrorHandling, writeSuccess } from "../utils/cli.js";
6
+ import { withErrorHandling, writeProgress, writeSuccess, } from "../utils/cli.js";
7
7
  import { promptAgentChoice, promptOrganizationSelection, promptAgentSelection, promptMetadataCollection, promptFeatureConfiguration, promptBusinessConfiguration, } from "../utils/init-prompts.js";
8
8
  import { fetchAgentTypes, selectBaseAgentType, createNewAgent, } from "../utils/init-agent.js";
9
9
  import { initializeProject, installDependencies, clearLinesIfNeeded, } from "../utils/init-helpers.js";
@@ -38,6 +38,8 @@ export async function initCommand() {
38
38
  console.error("āŒ No API key found. Run `lua auth configure` first.");
39
39
  process.exit(1);
40
40
  }
41
+ const userData = await checkApiKey(apiKey);
42
+ writeProgress("āœ… Authenticated");
41
43
  // Step 2: Choose between existing or new agent
42
44
  const agentChoice = await promptAgentChoice();
43
45
  let selectedAgent;
@@ -46,7 +48,7 @@ export async function initCommand() {
46
48
  let welcomeMessage;
47
49
  if (agentChoice === "existing") {
48
50
  // Step 3a: Select existing agent
49
- const result = await selectExistingAgent(apiKey);
51
+ const result = await selectExistingAgent(userData);
50
52
  selectedAgent = result.agent;
51
53
  selectedOrg = result.org;
52
54
  }
@@ -68,12 +70,10 @@ export async function initCommand() {
68
70
  /**
69
71
  * Handles the flow for selecting an existing agent.
70
72
  *
71
- * @param apiKey - User's API key
73
+ * @param userData - User's data
72
74
  * @returns Selected agent and organization
73
75
  */
74
- async function selectExistingAgent(apiKey) {
75
- // Get user data from API
76
- const userData = await checkApiKey(apiKey);
76
+ async function selectExistingAgent(userData) {
77
77
  // Extract organizations
78
78
  const orgs = userData.admin.orgs;
79
79
  if (!orgs || orgs.length === 0) {
@@ -7,11 +7,13 @@
7
7
  *
8
8
  * This command performs the following steps:
9
9
  * 1. Validates configuration has required fields
10
- * 2. Prompts for user confirmation
11
- * 3. Authenticates the user
12
- * 4. Compiles the skill
13
- * 5. Validates deploy.json matches configuration
14
- * 6. Pushes version to server
10
+ * 2. Prompts user to select a skill (if multiple skills exist)
11
+ * 3. Prompts to confirm or update version
12
+ * 4. Authenticates the user
13
+ * 5. Compiles the skill (always, to ensure deploy.json is current)
14
+ * 6. Validates deploy.json matches configuration for selected skill
15
+ * 7. Extracts the specific skill's deploy data
16
+ * 8. Pushes version to server
15
17
  *
16
18
  * Use this command to:
17
19
  * - Upload a new version of your skill
@@ -5,19 +5,21 @@
5
5
  import { compileCommand } from './compile.js';
6
6
  import { checkApiKey, loadApiKey } from '../services/auth.js';
7
7
  import { readSkillConfig } from '../utils/files.js';
8
- import { withErrorHandling, writeProgress, writeSuccess } from '../utils/cli.js';
9
- import { readDeployJson, confirmVersionPush, validatePushConfig, validateDeployData, } from '../utils/push-helpers.js';
8
+ import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
9
+ import { readDeployJson, validatePushConfig, validateDeployData, promptSkillSelection, promptVersionConfirmOrUpdate, getAvailableSkills, updateSkillVersionInYaml, getSkillDeployData, } from '../utils/push-helpers.js';
10
10
  import { pushVersion } from '../utils/push-api.js';
11
11
  /**
12
12
  * Main push command - pushes a skill version to the server.
13
13
  *
14
14
  * This command performs the following steps:
15
15
  * 1. Validates configuration has required fields
16
- * 2. Prompts for user confirmation
17
- * 3. Authenticates the user
18
- * 4. Compiles the skill
19
- * 5. Validates deploy.json matches configuration
20
- * 6. Pushes version to server
16
+ * 2. Prompts user to select a skill (if multiple skills exist)
17
+ * 3. Prompts to confirm or update version
18
+ * 4. Authenticates the user
19
+ * 5. Compiles the skill (always, to ensure deploy.json is current)
20
+ * 6. Validates deploy.json matches configuration for selected skill
21
+ * 7. Extracts the specific skill's deploy data
22
+ * 8. Pushes version to server
21
23
  *
22
24
  * Use this command to:
23
25
  * - Upload a new version of your skill
@@ -33,14 +35,33 @@ export async function pushCommand() {
33
35
  // Step 1: Validate configuration
34
36
  const config = readSkillConfig();
35
37
  validatePushConfig(config);
36
- const version = config.skill.version;
37
- // Step 2: Confirm with user
38
- const confirmed = await confirmVersionPush(version);
39
- if (!confirmed) {
40
- console.log("āŒ Push cancelled.");
41
- process.exit(0);
38
+ // Step 2: Get available skills and prompt for selection
39
+ const availableSkills = getAvailableSkills(config);
40
+ if (availableSkills.length === 0) {
41
+ console.error("āŒ No skills found in configuration. Please compile your skill first using 'lua compile'.");
42
+ process.exit(1);
43
+ }
44
+ let selectedSkill;
45
+ if (availableSkills.length === 1) {
46
+ // Only one skill, use it automatically
47
+ selectedSkill = availableSkills[0];
48
+ writeInfo(`šŸ“¦ Pushing skill: ${selectedSkill.name}`);
49
+ }
50
+ else {
51
+ // Multiple skills, prompt for selection
52
+ selectedSkill = await promptSkillSelection(availableSkills);
53
+ writeInfo(`šŸ“¦ Selected skill: ${selectedSkill.name}`);
54
+ }
55
+ // Step 3: Confirm or update version
56
+ const confirmedVersion = await promptVersionConfirmOrUpdate(selectedSkill.version);
57
+ let versionUpdated = false;
58
+ if (confirmedVersion !== selectedSkill.version) {
59
+ writeInfo(`šŸ“ Updating version from ${selectedSkill.version} to ${confirmedVersion}`);
60
+ updateSkillVersionInYaml(selectedSkill.name, confirmedVersion);
61
+ selectedSkill.version = confirmedVersion;
62
+ versionUpdated = true;
42
63
  }
43
- // Step 3: Authenticate
64
+ // Step 4: Authenticate
44
65
  const apiKey = await loadApiKey();
45
66
  if (!apiKey) {
46
67
  console.error("āŒ No API key found. Please run 'lua auth configure' to set up your API key.");
@@ -48,19 +69,21 @@ export async function pushCommand() {
48
69
  }
49
70
  const userData = await checkApiKey(apiKey);
50
71
  writeProgress("āœ… Authenticated");
51
- // Step 4: Compile the skill
72
+ // Step 5: Compile the skill (always compile to ensure up-to-date, or if version was updated)
52
73
  writeProgress("šŸ”„ Compiling skill...");
53
74
  await compileCommand();
54
- // Step 5: Validate deploy data
75
+ // Step 6: Validate deploy data for the selected skill
55
76
  const deployData = readDeployJson();
56
- validateDeployData(deployData, version);
57
- // Step 6: Push version to server
77
+ validateDeployData(deployData, selectedSkill);
78
+ // Step 7: Extract the specific skill's deploy data
79
+ const skillDeployData = getSkillDeployData(deployData, selectedSkill.name);
80
+ // Step 8: Push version to server
58
81
  const agentId = config.agent.agentId;
59
- const skillId = config.skill.skillId;
82
+ const skillId = selectedSkill.skillId;
60
83
  writeProgress("šŸ”„ Pushing version to server...");
61
- const result = await pushVersion(apiKey, agentId, skillId, deployData);
84
+ const result = await pushVersion(apiKey, agentId, skillId, skillDeployData);
62
85
  if (result.success && result.data) {
63
- writeSuccess(`āœ… Version ${result.data.version} pushed successfully`);
86
+ writeSuccess(`āœ… Version ${result.data.version} of "${selectedSkill.name}" pushed successfully`);
64
87
  }
65
88
  else if (result.error) {
66
89
  console.error(`āŒ ${result.error.message}`);
@@ -1,3 +1,4 @@
1
+ import { AuthenticationError } from "../errors/auth.error.js";
1
2
  /**
2
3
  * Generic HTTP client with common error handling
3
4
  * Provides a base class for all API service classes with standardized HTTP methods
@@ -28,6 +29,9 @@ export class HttpClient {
28
29
  });
29
30
  // Check if response is ok (status 200-299)
30
31
  if (!response.ok) {
32
+ if (response.status === 401) {
33
+ throw new AuthenticationError("Invalid API key");
34
+ }
31
35
  return {
32
36
  success: false,
33
37
  error: {
@@ -55,6 +59,9 @@ export class HttpClient {
55
59
  };
56
60
  }
57
61
  catch (error) {
62
+ if (AuthenticationError.isAuthenticationError(error)) {
63
+ throw error;
64
+ }
58
65
  // Handle network errors, timeouts, etc.
59
66
  return {
60
67
  success: false,
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Authentication Error
3
+ * Thrown when API requests fail with 401 Unauthorized status
4
+ */
5
+ export declare class AuthenticationError extends Error {
6
+ readonly statusCode: number;
7
+ readonly isAuthenticationError: boolean;
8
+ constructor(message?: string);
9
+ /**
10
+ * Checks if an error is an AuthenticationError
11
+ * @param error - The error to check
12
+ * @returns True if the error is an AuthenticationError
13
+ */
14
+ static isAuthenticationError(error: unknown): error is AuthenticationError;
15
+ }
@@ -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.js CHANGED
@@ -25,7 +25,7 @@ const program = new Command();
25
25
  program
26
26
  .name("lua")
27
27
  .description("Lua AI Skill Management CLI")
28
- .version("2.3.0");
28
+ .version("2.3.1");
29
29
  // Set up all command groups
30
30
  setupAuthCommands(program);
31
31
  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
  }
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.