lua-cli 2.5.6 → 2.5.8

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 (40) hide show
  1. package/dist/api/agent.api.service.d.ts +45 -0
  2. package/dist/api/agent.api.service.js +54 -0
  3. package/dist/api/user.data.api.service.d.ts +15 -0
  4. package/dist/api/user.data.api.service.js +31 -0
  5. package/dist/cli/command-definitions.js +77 -5
  6. package/dist/commands/completion.d.ts +11 -0
  7. package/dist/commands/completion.js +209 -0
  8. package/dist/commands/env.d.ts +3 -2
  9. package/dist/commands/env.js +42 -17
  10. package/dist/commands/features.d.ts +16 -0
  11. package/dist/commands/features.js +352 -0
  12. package/dist/commands/index.d.ts +3 -0
  13. package/dist/commands/index.js +3 -0
  14. package/dist/commands/persona.d.ts +3 -2
  15. package/dist/commands/persona.js +43 -18
  16. package/dist/commands/push.d.ts +9 -13
  17. package/dist/commands/push.js +271 -82
  18. package/dist/commands/skills.d.ts +16 -0
  19. package/dist/commands/skills.js +438 -0
  20. package/dist/common/basket.instance.js +38 -19
  21. package/dist/common/data.entry.instance.d.ts +7 -0
  22. package/dist/common/data.entry.instance.js +35 -9
  23. package/dist/common/order.instance.d.ts +6 -0
  24. package/dist/common/order.instance.js +48 -15
  25. package/dist/common/product.instance.d.ts +6 -0
  26. package/dist/common/product.instance.js +34 -9
  27. package/dist/common/product.pagination.instance.js +6 -2
  28. package/dist/common/product.search.instance.js +4 -1
  29. package/dist/common/user.instance.d.ts +14 -0
  30. package/dist/common/user.instance.js +49 -9
  31. package/dist/index.js +14 -3
  32. package/dist/interfaces/agent.d.ts +31 -0
  33. package/dist/interfaces/message.d.ts +18 -0
  34. package/dist/interfaces/message.js +1 -0
  35. package/dist/types/api-contracts.d.ts +9 -0
  36. package/dist/types/api-contracts.js +0 -7
  37. package/dist/web/app.css +152 -736
  38. package/dist/web/app.js +45 -45
  39. package/package.json +2 -2
  40. package/template/package.json +1 -1
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Features Command
3
+ * Manages agent features (tickets, RAG, webSearch, etc.)
4
+ */
5
+ import { loadApiKey, checkApiKey } from '../services/auth.js';
6
+ import { readSkillConfig } from '../utils/files.js';
7
+ import { withErrorHandling, writeProgress, writeSuccess } from '../utils/cli.js';
8
+ import { BASE_URLS } from '../config/constants.js';
9
+ import { safePrompt } from '../utils/prompt-handler.js';
10
+ import { validateConfig, validateAgentConfig, } from '../utils/dev-helpers.js';
11
+ import AgentApi from '../api/agent.api.service.js';
12
+ /**
13
+ * Main features command - manages agent features
14
+ *
15
+ * Features:
16
+ * - List all available features
17
+ * - View feature details (active status and context)
18
+ * - Enable/disable features
19
+ * - Update feature context
20
+ *
21
+ * @returns Promise that resolves when command completes
22
+ */
23
+ export async function featuresCommand() {
24
+ return withErrorHandling(async () => {
25
+ // Step 1: Load configuration
26
+ const config = readSkillConfig();
27
+ validateConfig(config);
28
+ validateAgentConfig(config);
29
+ const agentId = config.agent.agentId;
30
+ // Step 2: Authenticate
31
+ const apiKey = await loadApiKey();
32
+ if (!apiKey) {
33
+ console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
34
+ process.exit(1);
35
+ }
36
+ await checkApiKey(apiKey);
37
+ writeProgress("✅ Authenticated");
38
+ // Step 3: Create API instance
39
+ const agentApi = new AgentApi(BASE_URLS.API, apiKey);
40
+ const context = {
41
+ agentId,
42
+ apiKey,
43
+ agentApi,
44
+ };
45
+ // Step 4: Start feature management
46
+ await manageFeatures(context);
47
+ }, "features");
48
+ }
49
+ /**
50
+ * Main management loop for features
51
+ */
52
+ async function manageFeatures(context) {
53
+ let continueManaging = true;
54
+ while (continueManaging) {
55
+ // Load current features
56
+ writeProgress("🔄 Loading features...");
57
+ let features;
58
+ try {
59
+ const response = await context.agentApi.getAgentFeatures(context.agentId);
60
+ if (!response.data) {
61
+ throw new Error("No data returned from API");
62
+ }
63
+ features = response.data.features;
64
+ }
65
+ catch (error) {
66
+ console.error("❌ Error loading features:", error);
67
+ await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to try again...' }]);
68
+ continue;
69
+ }
70
+ // Show current state
71
+ console.log("\n" + "=".repeat(60));
72
+ console.log("🎯 Agent Features");
73
+ console.log("=".repeat(60) + "\n");
74
+ if (features.length === 0) {
75
+ console.log("ℹ️ No features available for this agent.\n");
76
+ }
77
+ else {
78
+ console.log("Available features:\n");
79
+ features.forEach((feature, index) => {
80
+ const status = feature.active ? "✅" : "❌";
81
+ console.log(`${index + 1}. ${status} ${feature.title}`);
82
+ console.log(` Name: ${feature.name}`);
83
+ console.log(` Status: ${feature.active ? "Active" : "Inactive"}`);
84
+ console.log();
85
+ });
86
+ }
87
+ // Show menu
88
+ const actionAnswer = await safePrompt([
89
+ {
90
+ type: 'list',
91
+ name: 'action',
92
+ message: 'What would you like to do?',
93
+ choices: [
94
+ { name: '👁️ View feature details', value: 'view' },
95
+ { name: '✏️ Manage a feature', value: 'manage' },
96
+ { name: '🔄 Refresh list', value: 'refresh' },
97
+ { name: '❌ Exit', value: 'exit' }
98
+ ]
99
+ }
100
+ ]);
101
+ if (!actionAnswer)
102
+ return;
103
+ const { action } = actionAnswer;
104
+ switch (action) {
105
+ case 'view':
106
+ await viewFeatureDetails(context, features);
107
+ break;
108
+ case 'manage':
109
+ await manageFeature(context, features);
110
+ break;
111
+ case 'refresh':
112
+ // Just loop again to refresh
113
+ break;
114
+ case 'exit':
115
+ continueManaging = false;
116
+ console.log("\n👋 Goodbye!\n");
117
+ break;
118
+ }
119
+ }
120
+ }
121
+ /**
122
+ * View detailed information about a feature
123
+ */
124
+ async function viewFeatureDetails(context, features) {
125
+ if (features.length === 0) {
126
+ console.log("\nℹ️ No features available.\n");
127
+ return;
128
+ }
129
+ // Prompt to select a feature
130
+ const featureAnswer = await safePrompt([
131
+ {
132
+ type: 'list',
133
+ name: 'selectedFeature',
134
+ message: 'Select a feature to view:',
135
+ choices: features.map(feature => ({
136
+ name: `${feature.active ? '✅' : '❌'} ${feature.title}`,
137
+ value: feature
138
+ }))
139
+ }
140
+ ]);
141
+ if (!featureAnswer)
142
+ return;
143
+ const feature = featureAnswer.selectedFeature;
144
+ // Display feature details
145
+ console.log("\n" + "=".repeat(60));
146
+ console.log(`🎯 ${feature.title}`);
147
+ console.log("=".repeat(60));
148
+ console.log(`Name: ${feature.name}`);
149
+ console.log(`Status: ${feature.active ? '✅ Active' : '❌ Inactive'}`);
150
+ console.log("\nContext/Instructions:");
151
+ console.log("─".repeat(60));
152
+ console.log(feature.context);
153
+ console.log("=".repeat(60) + "\n");
154
+ await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
155
+ }
156
+ /**
157
+ * Manage a specific feature (activate/deactivate or update context)
158
+ */
159
+ async function manageFeature(context, features) {
160
+ if (features.length === 0) {
161
+ console.log("\nℹ️ No features available.\n");
162
+ return;
163
+ }
164
+ // Step 1: Select feature
165
+ const featureAnswer = await safePrompt([
166
+ {
167
+ type: 'list',
168
+ name: 'selectedFeature',
169
+ message: 'Select a feature to manage:',
170
+ choices: features.map(feature => ({
171
+ name: `${feature.active ? '✅' : '❌'} ${feature.title}`,
172
+ value: feature
173
+ }))
174
+ }
175
+ ]);
176
+ if (!featureAnswer)
177
+ return;
178
+ const feature = featureAnswer.selectedFeature;
179
+ // Step 2: Show current status
180
+ console.log("\n" + "─".repeat(60));
181
+ console.log(`Feature: ${feature.title}`);
182
+ console.log(`Current Status: ${feature.active ? '✅ Active' : '❌ Inactive'}`);
183
+ console.log("─".repeat(60) + "\n");
184
+ // Step 3: Select action
185
+ const actionAnswer = await safePrompt([
186
+ {
187
+ type: 'list',
188
+ name: 'action',
189
+ message: 'What would you like to do?',
190
+ choices: [
191
+ {
192
+ name: feature.active ? '❌ Deactivate feature' : '✅ Activate feature',
193
+ value: 'toggle'
194
+ },
195
+ { name: '✏️ Update context/instructions', value: 'context' },
196
+ { name: '🔄 Update both status and context', value: 'both' },
197
+ { name: '⬅️ Back', value: 'back' }
198
+ ]
199
+ }
200
+ ]);
201
+ if (!actionAnswer || actionAnswer.action === 'back')
202
+ return;
203
+ try {
204
+ switch (actionAnswer.action) {
205
+ case 'toggle':
206
+ await toggleFeature(context, feature);
207
+ break;
208
+ case 'context':
209
+ await updateFeatureContext(context, feature);
210
+ break;
211
+ case 'both':
212
+ await updateBoth(context, feature);
213
+ break;
214
+ }
215
+ }
216
+ catch (error) {
217
+ console.error("\n❌ Error updating feature:", error);
218
+ await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
219
+ }
220
+ }
221
+ /**
222
+ * Toggle feature active status
223
+ */
224
+ async function toggleFeature(context, feature) {
225
+ const newStatus = !feature.active;
226
+ const action = newStatus ? 'activate' : 'deactivate';
227
+ const confirmAnswer = await safePrompt([
228
+ {
229
+ type: 'confirm',
230
+ name: 'confirm',
231
+ message: `Are you sure you want to ${action} "${feature.title}"?`,
232
+ default: true
233
+ }
234
+ ]);
235
+ if (!confirmAnswer || !confirmAnswer.confirm) {
236
+ console.log("\n❌ Operation cancelled.\n");
237
+ return;
238
+ }
239
+ writeProgress(`🔄 ${newStatus ? 'Activating' : 'Deactivating'} feature...`);
240
+ const response = await context.agentApi.updateAgentFeature(context.agentId, {
241
+ featureName: feature.name,
242
+ active: newStatus
243
+ });
244
+ writeSuccess(`✅ Feature "${feature.title}" ${newStatus ? 'activated' : 'deactivated'} successfully`);
245
+ await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
246
+ }
247
+ /**
248
+ * Update feature context
249
+ */
250
+ async function updateFeatureContext(context, feature) {
251
+ console.log("\n📝 Current context:");
252
+ console.log("─".repeat(60));
253
+ console.log(feature.context);
254
+ console.log("─".repeat(60) + "\n");
255
+ const contextAnswer = await safePrompt([
256
+ {
257
+ type: 'editor',
258
+ name: 'newContext',
259
+ message: 'Edit feature context (will open in your default editor):',
260
+ default: feature.context,
261
+ validate: (input) => {
262
+ if (!input || !input.trim()) {
263
+ return 'Context cannot be empty';
264
+ }
265
+ return true;
266
+ }
267
+ }
268
+ ]);
269
+ if (!contextAnswer)
270
+ return;
271
+ const confirmAnswer = await safePrompt([
272
+ {
273
+ type: 'confirm',
274
+ name: 'confirm',
275
+ message: 'Save updated context?',
276
+ default: true
277
+ }
278
+ ]);
279
+ if (!confirmAnswer || !confirmAnswer.confirm) {
280
+ console.log("\n❌ Update cancelled.\n");
281
+ return;
282
+ }
283
+ writeProgress("🔄 Updating feature context...");
284
+ const response = await context.agentApi.updateAgentFeature(context.agentId, {
285
+ featureName: feature.name,
286
+ featureContext: contextAnswer.newContext.trim()
287
+ });
288
+ writeSuccess(`✅ Context for "${feature.title}" updated successfully`);
289
+ await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
290
+ }
291
+ /**
292
+ * Update both status and context
293
+ */
294
+ async function updateBoth(context, feature) {
295
+ // Step 1: Select new status
296
+ const statusAnswer = await safePrompt([
297
+ {
298
+ type: 'confirm',
299
+ name: 'active',
300
+ message: 'Should this feature be active?',
301
+ default: feature.active
302
+ }
303
+ ]);
304
+ if (!statusAnswer)
305
+ return;
306
+ // Step 2: Edit context
307
+ console.log("\n📝 Current context:");
308
+ console.log("─".repeat(60));
309
+ console.log(feature.context);
310
+ console.log("─".repeat(60) + "\n");
311
+ const contextAnswer = await safePrompt([
312
+ {
313
+ type: 'editor',
314
+ name: 'newContext',
315
+ message: 'Edit feature context (will open in your default editor):',
316
+ default: feature.context,
317
+ validate: (input) => {
318
+ if (!input || !input.trim()) {
319
+ return 'Context cannot be empty';
320
+ }
321
+ return true;
322
+ }
323
+ }
324
+ ]);
325
+ if (!contextAnswer)
326
+ return;
327
+ // Step 3: Confirm
328
+ console.log("\n📋 Summary of changes:");
329
+ console.log(`Status: ${feature.active ? '✅ Active' : '❌ Inactive'} → ${statusAnswer.active ? '✅ Active' : '❌ Inactive'}`);
330
+ console.log(`Context: ${contextAnswer.newContext === feature.context ? 'No change' : 'Updated'}`);
331
+ console.log();
332
+ const confirmAnswer = await safePrompt([
333
+ {
334
+ type: 'confirm',
335
+ name: 'confirm',
336
+ message: 'Save all changes?',
337
+ default: true
338
+ }
339
+ ]);
340
+ if (!confirmAnswer || !confirmAnswer.confirm) {
341
+ console.log("\n❌ Update cancelled.\n");
342
+ return;
343
+ }
344
+ writeProgress("🔄 Updating feature...");
345
+ const response = await context.agentApi.updateAgentFeature(context.agentId, {
346
+ featureName: feature.name,
347
+ active: statusAnswer.active,
348
+ featureContext: contextAnswer.newContext.trim()
349
+ });
350
+ writeSuccess(`✅ Feature "${feature.title}" updated successfully`);
351
+ await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
352
+ }
@@ -17,3 +17,6 @@ export { adminCommand } from "./admin.js";
17
17
  export { docsCommand } from "./docs.js";
18
18
  export { channelsCommand } from "./channels.js";
19
19
  export { logsCommand } from "./logs.js";
20
+ export { completionCommand } from "./completion.js";
21
+ export { skillsCommand } from "./skills.js";
22
+ export { featuresCommand } from "./features.js";
@@ -17,3 +17,6 @@ export { adminCommand } from "./admin.js";
17
17
  export { docsCommand } from "./docs.js";
18
18
  export { channelsCommand } from "./channels.js";
19
19
  export { logsCommand } from "./logs.js";
20
+ export { completionCommand } from "./completion.js";
21
+ export { skillsCommand } from "./skills.js";
22
+ export { featuresCommand } from "./features.js";
@@ -6,10 +6,11 @@
6
6
  * Main persona command - manages agent persona
7
7
  *
8
8
  * Features:
9
- * - Environment selection (sandbox or production)
9
+ * - Environment selection (sandbox/staging or production)
10
10
  * - Sandbox: view, edit, save persona + create versions
11
11
  * - Production: list versions, view details, deploy versions
12
12
  *
13
+ * @param env - Optional environment argument ('sandbox', 'staging', or 'production')
13
14
  * @returns Promise that resolves when command completes
14
15
  */
15
- export declare function personaCommand(): Promise<void>;
16
+ export declare function personaCommand(env?: string): Promise<void>;
@@ -16,13 +16,14 @@ import { validateConfig, validateAgentConfig, } from '../utils/dev-helpers.js';
16
16
  * Main persona command - manages agent persona
17
17
  *
18
18
  * Features:
19
- * - Environment selection (sandbox or production)
19
+ * - Environment selection (sandbox/staging or production)
20
20
  * - Sandbox: view, edit, save persona + create versions
21
21
  * - Production: list versions, view details, deploy versions
22
22
  *
23
+ * @param env - Optional environment argument ('sandbox', 'staging', or 'production')
23
24
  * @returns Promise that resolves when command completes
24
25
  */
25
- export async function personaCommand() {
26
+ export async function personaCommand(env) {
26
27
  return withErrorHandling(async () => {
27
28
  // Step 1: Load configuration first (to get agentId)
28
29
  const config = readSkillConfig();
@@ -37,27 +38,51 @@ export async function personaCommand() {
37
38
  }
38
39
  await checkApiKey(apiKey);
39
40
  writeProgress("✅ Authenticated");
40
- // Step 3: Select environment
41
- const envAnswer = await safePrompt([
42
- {
43
- type: 'list',
44
- name: 'environment',
45
- message: 'Select environment:',
46
- choices: [
47
- { name: '🔧 Sandbox (edit and test)', value: 'sandbox' },
48
- { name: '🚀 Production (view and deploy versions)', value: 'production' }
49
- ]
41
+ let selectedEnvironment;
42
+ // Step 3: Check if environment was provided as argument
43
+ if (env) {
44
+ // Normalize the environment (staging is an alias for sandbox)
45
+ const normalizedEnv = env.toLowerCase();
46
+ if (normalizedEnv === 'sandbox' || normalizedEnv === 'staging') {
47
+ selectedEnvironment = 'sandbox';
50
48
  }
51
- ]);
52
- if (!envAnswer)
53
- return;
49
+ else if (normalizedEnv === 'production') {
50
+ selectedEnvironment = 'production';
51
+ }
52
+ else {
53
+ console.error(`❌ Invalid environment: "${env}". Must be "sandbox", "staging", or "production".`);
54
+ console.log('\nUsage:');
55
+ console.log(' lua persona - Interactive selection');
56
+ console.log(' lua persona sandbox - Manage sandbox persona directly');
57
+ console.log(' lua persona staging - Manage staging persona (alias for sandbox)');
58
+ console.log(' lua persona production - Manage production persona directly');
59
+ process.exit(1);
60
+ }
61
+ }
62
+ else {
63
+ // Step 4: Prompt for environment selection
64
+ const envAnswer = await safePrompt([
65
+ {
66
+ type: 'list',
67
+ name: 'environment',
68
+ message: 'Select environment:',
69
+ choices: [
70
+ { name: '🔧 Sandbox (edit and test)', value: 'sandbox' },
71
+ { name: '🚀 Production (view and deploy versions)', value: 'production' }
72
+ ]
73
+ }
74
+ ]);
75
+ if (!envAnswer)
76
+ return;
77
+ selectedEnvironment = envAnswer.environment;
78
+ }
54
79
  const context = {
55
- environment: envAnswer.environment,
80
+ environment: selectedEnvironment,
56
81
  agentId,
57
82
  apiKey,
58
83
  };
59
- // Step 4: Start management based on environment
60
- if (envAnswer.environment === 'sandbox') {
84
+ // Step 5: Start management based on environment
85
+ if (selectedEnvironment === 'sandbox') {
61
86
  await manageSandboxPersona(context);
62
87
  }
63
88
  else {
@@ -3,25 +3,21 @@
3
3
  * Orchestrates pushing skill versions to the server
4
4
  */
5
5
  /**
6
- * Main push command - pushes a skill version to the server.
6
+ * Main push command - pushes a skill or persona version to the server.
7
7
  *
8
8
  * This command performs the following steps:
9
- * 1. Validates configuration has required fields
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
9
+ * 1. If type argument provided, uses it directly
10
+ * 2. Otherwise, prompts user to select 'skill' or 'persona'
11
+ * 3. Routes to appropriate push flow
17
12
  *
18
13
  * Use this command to:
19
- * - Upload a new version of your skill
20
- * - Make your skill available for testing in dev mode
21
- * - Prepare your skill for deployment
14
+ * - Upload a new version of your skill or persona
15
+ * - Make your skill/persona available for testing in dev mode
16
+ * - Prepare your skill/persona for deployment
22
17
  *
23
18
  * Note: This does NOT deploy to production. Use `lua deploy` for that.
24
19
  *
20
+ * @param type - Optional type argument ('skill' or 'persona')
25
21
  * @returns Promise that resolves when push completes
26
22
  */
27
- export declare function pushCommand(): Promise<void>;
23
+ export declare function pushCommand(type?: string): Promise<void>;