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,503 @@
1
+ /**
2
+ * Persona Command
3
+ * Manages agent persona for sandbox and production environments
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import yaml from 'js-yaml';
8
+ import inquirer from 'inquirer';
9
+ import { loadApiKey, checkApiKey } from '../services/auth.js';
10
+ import { readSkillConfig } from '../utils/files.js';
11
+ import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
12
+ import { BASE_URLS } from '../config/constants.js';
13
+ import { safePrompt } from '../utils/prompt-handler.js';
14
+ import { validateConfig, validateAgentConfig, } from '../utils/dev-helpers.js';
15
+ /**
16
+ * Main persona command - manages agent persona
17
+ *
18
+ * Features:
19
+ * - Environment selection (sandbox or production)
20
+ * - Sandbox: view, edit, save persona + create versions
21
+ * - Production: list versions, view details, deploy versions
22
+ *
23
+ * @returns Promise that resolves when command completes
24
+ */
25
+ export async function personaCommand() {
26
+ return withErrorHandling(async () => {
27
+ // Step 1: Load configuration first (to get agentId)
28
+ const config = readSkillConfig();
29
+ validateConfig(config);
30
+ validateAgentConfig(config);
31
+ const agentId = config.agent.agentId;
32
+ // Step 2: Authenticate
33
+ const apiKey = await loadApiKey();
34
+ if (!apiKey) {
35
+ console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
36
+ process.exit(1);
37
+ }
38
+ await checkApiKey(apiKey);
39
+ 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
+ ]
50
+ }
51
+ ]);
52
+ if (!envAnswer)
53
+ return;
54
+ const context = {
55
+ environment: envAnswer.environment,
56
+ agentId,
57
+ apiKey,
58
+ };
59
+ // Step 4: Start management based on environment
60
+ if (envAnswer.environment === 'sandbox') {
61
+ await manageSandboxPersona(context);
62
+ }
63
+ else {
64
+ await manageProductionPersona(context);
65
+ }
66
+ }, "persona");
67
+ }
68
+ /**
69
+ * Manage sandbox persona - edit and save
70
+ */
71
+ async function manageSandboxPersona(context) {
72
+ let continueManaging = true;
73
+ while (continueManaging) {
74
+ // Load current persona
75
+ const currentPersona = loadSandboxPersona();
76
+ // Show menu
77
+ console.log("\n" + "=".repeat(60));
78
+ console.log("🌙 Sandbox Persona Management");
79
+ console.log("=".repeat(60) + "\n");
80
+ if (currentPersona && currentPersona.trim()) {
81
+ const preview = currentPersona.length > 100
82
+ ? currentPersona.substring(0, 100) + '...'
83
+ : currentPersona;
84
+ console.log("Current persona:");
85
+ console.log(preview);
86
+ console.log();
87
+ }
88
+ else {
89
+ console.log("ℹ️ No persona configured.\n");
90
+ }
91
+ const actionAnswer = await safePrompt([
92
+ {
93
+ type: 'list',
94
+ name: 'action',
95
+ message: 'What would you like to do?',
96
+ choices: [
97
+ { name: '👁️ View full persona', value: 'view' },
98
+ { name: '✏️ Edit persona', value: 'edit' },
99
+ { name: '📦 Create version (push to production)', value: 'create_version' },
100
+ { name: '📋 List versions', value: 'list_versions' },
101
+ { name: '❌ Exit', value: 'exit' }
102
+ ]
103
+ }
104
+ ]);
105
+ if (!actionAnswer)
106
+ return;
107
+ const { action } = actionAnswer;
108
+ switch (action) {
109
+ case 'view':
110
+ await viewPersona(currentPersona);
111
+ break;
112
+ case 'edit':
113
+ await editSandboxPersona(context, currentPersona);
114
+ break;
115
+ case 'create_version':
116
+ await createPersonaVersion(context, currentPersona);
117
+ break;
118
+ case 'list_versions':
119
+ await listPersonaVersions(context);
120
+ break;
121
+ case 'exit':
122
+ continueManaging = false;
123
+ console.log("\n👋 Goodbye!\n");
124
+ break;
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * Manage production persona - view and deploy versions
130
+ */
131
+ async function manageProductionPersona(context) {
132
+ let continueManaging = true;
133
+ while (continueManaging) {
134
+ console.log("\n" + "=".repeat(60));
135
+ console.log("🌙 Production Persona Management");
136
+ console.log("=".repeat(60) + "\n");
137
+ const actionAnswer = await safePrompt([
138
+ {
139
+ type: 'list',
140
+ name: 'action',
141
+ message: 'What would you like to do?',
142
+ choices: [
143
+ { name: '👁️ View persona versions', value: 'view' },
144
+ { name: '🚀 Deploy persona version', value: 'deploy' },
145
+ { name: '❌ Exit', value: 'exit' }
146
+ ]
147
+ }
148
+ ]);
149
+ if (!actionAnswer)
150
+ return;
151
+ const { action } = actionAnswer;
152
+ switch (action) {
153
+ case 'view':
154
+ await listPersonaVersions(context);
155
+ break;
156
+ case 'deploy':
157
+ await deployPersonaVersion(context);
158
+ break;
159
+ case 'exit':
160
+ continueManaging = false;
161
+ console.log("\n👋 Goodbye!\n");
162
+ break;
163
+ }
164
+ }
165
+ }
166
+ /**
167
+ * Load sandbox persona from lua.skill.yaml
168
+ */
169
+ function loadSandboxPersona() {
170
+ try {
171
+ const config = readSkillConfig();
172
+ return config.agent?.persona || '';
173
+ }
174
+ catch (error) {
175
+ return '';
176
+ }
177
+ }
178
+ /**
179
+ * Save sandbox persona to lua.skill.yaml
180
+ */
181
+ function saveSandboxPersona(persona) {
182
+ try {
183
+ const configPath = path.join(process.cwd(), 'lua.skill.yaml');
184
+ // Read current config
185
+ const fileContent = fs.readFileSync(configPath, 'utf8');
186
+ const config = yaml.load(fileContent);
187
+ // Ensure agent object exists
188
+ if (!config.agent) {
189
+ config.agent = {};
190
+ }
191
+ // Update persona
192
+ config.agent.persona = persona;
193
+ // Write back to file
194
+ const newContent = yaml.dump(config, {
195
+ lineWidth: -1,
196
+ noRefs: true
197
+ });
198
+ fs.writeFileSync(configPath, newContent, 'utf8');
199
+ return true;
200
+ }
201
+ catch (error) {
202
+ console.error('❌ Error saving persona to lua.skill.yaml:', error);
203
+ return false;
204
+ }
205
+ }
206
+ /**
207
+ * View full persona content
208
+ */
209
+ async function viewPersona(persona) {
210
+ console.log("\n" + "=".repeat(60));
211
+ console.log("Agent Persona");
212
+ console.log("=".repeat(60));
213
+ if (persona && persona.trim()) {
214
+ console.log(persona);
215
+ }
216
+ else {
217
+ console.log("No persona configured.");
218
+ }
219
+ console.log("=".repeat(60) + "\n");
220
+ await inquirer.prompt([
221
+ {
222
+ type: 'input',
223
+ name: 'continue',
224
+ message: 'Press Enter to continue...'
225
+ }
226
+ ]);
227
+ }
228
+ /**
229
+ * Edit sandbox persona
230
+ */
231
+ async function editSandboxPersona(context, currentPersona) {
232
+ // Provide helpful default if empty
233
+ const defaultPersona = currentPersona || `# Write your agent persona here
234
+ #
235
+ # Example:
236
+ # You are a helpful customer service assistant for [Your Company].
237
+ # You help users with product inquiries and order management.
238
+ # You are friendly, professional, and knowledgeable.`;
239
+ const personaAnswer = await safePrompt([
240
+ {
241
+ type: 'editor',
242
+ name: 'newPersona',
243
+ message: 'Edit persona (will open in your default editor):',
244
+ default: defaultPersona,
245
+ validate: (input) => {
246
+ if (!input.trim()) {
247
+ return 'Persona cannot be empty';
248
+ }
249
+ // Remove comment lines for validation
250
+ const withoutComments = input.split('\n')
251
+ .filter((line) => !line.trim().startsWith('#'))
252
+ .join('\n')
253
+ .trim();
254
+ if (!withoutComments) {
255
+ return 'Persona cannot be empty (only comments found)';
256
+ }
257
+ return true;
258
+ }
259
+ }
260
+ ]);
261
+ if (!personaAnswer)
262
+ return;
263
+ const { newPersona } = personaAnswer;
264
+ const trimmedPersona = newPersona.trim();
265
+ writeProgress("🔄 Saving persona to lua.skill.yaml...");
266
+ const success = saveSandboxPersona(trimmedPersona);
267
+ if (success) {
268
+ writeSuccess("✅ Persona saved to lua.skill.yaml successfully");
269
+ }
270
+ else {
271
+ console.error("❌ Failed to save persona to lua.skill.yaml");
272
+ }
273
+ }
274
+ /**
275
+ * Create a new persona version
276
+ */
277
+ async function createPersonaVersion(context, currentPersona) {
278
+ if (!currentPersona || !currentPersona.trim()) {
279
+ console.log("\n❌ No persona to create version from. Please edit and save a persona first.\n");
280
+ return;
281
+ }
282
+ console.log("\n⚠️ This will create a new persona version that can be deployed to production.");
283
+ const confirmAnswer = await safePrompt([
284
+ {
285
+ type: 'confirm',
286
+ name: 'confirm',
287
+ message: 'Create new persona version?',
288
+ default: true
289
+ }
290
+ ]);
291
+ if (!confirmAnswer || !confirmAnswer.confirm) {
292
+ console.log("\nℹ️ Version creation cancelled.\n");
293
+ return;
294
+ }
295
+ writeProgress("🔄 Creating persona version...");
296
+ try {
297
+ const response = await fetch(`${BASE_URLS.API}/developer/agents/${context.agentId}/persona/version`, {
298
+ method: 'POST',
299
+ headers: {
300
+ 'Authorization': `Bearer ${context.apiKey}`,
301
+ 'Content-Type': 'application/json'
302
+ },
303
+ body: JSON.stringify({ persona: currentPersona })
304
+ });
305
+ if (!response.ok) {
306
+ const errorText = await response.text();
307
+ throw new Error(`HTTP error! status: ${response.status}, ${errorText}`);
308
+ }
309
+ const data = await response.json();
310
+ const versionNum = data.version || data.data?.version || 'N/A';
311
+ writeSuccess(`✅ Persona version created successfully (version: ${versionNum})`);
312
+ writeInfo("💡 You can deploy this version from the production environment.");
313
+ }
314
+ catch (error) {
315
+ console.error('❌ Error creating persona version:', error);
316
+ }
317
+ }
318
+ /**
319
+ * List persona versions
320
+ */
321
+ async function listPersonaVersions(context) {
322
+ writeProgress("🔄 Loading persona versions...");
323
+ try {
324
+ const response = await fetch(`${BASE_URLS.API}/developer/agents/${context.agentId}/persona/versions`, {
325
+ method: 'GET',
326
+ headers: {
327
+ 'Authorization': `Bearer ${context.apiKey}`,
328
+ 'Content-Type': 'application/json'
329
+ }
330
+ });
331
+ if (!response.ok) {
332
+ const errorText = await response.text();
333
+ console.error(`\n❌ API Error: ${response.status} - ${errorText}\n`);
334
+ throw new Error(`HTTP error! status: ${response.status}`);
335
+ }
336
+ const data = await response.json();
337
+ // Handle different response formats
338
+ let versions = [];
339
+ if (Array.isArray(data)) {
340
+ versions = data;
341
+ }
342
+ else if (data.data && Array.isArray(data.data)) {
343
+ versions = data.data;
344
+ }
345
+ else if (data.versions && Array.isArray(data.versions)) {
346
+ versions = data.versions;
347
+ }
348
+ if (versions.length === 0) {
349
+ console.log("\nℹ️ No persona versions found.\n");
350
+ console.log("💡 Create a version first from sandbox mode.\n");
351
+ return;
352
+ }
353
+ // Sort versions by date (newest first)
354
+ const sortedVersions = versions.sort((a, b) => {
355
+ return b.createdDate - a.createdDate;
356
+ });
357
+ // Let user select a version to view
358
+ const versionAnswer = await safePrompt([
359
+ {
360
+ type: 'list',
361
+ name: 'selectedVersionIndex',
362
+ message: 'Select a persona version to view:',
363
+ choices: sortedVersions.map((version, index) => {
364
+ const date = new Date(version.createdDate);
365
+ const dateStr = date.toLocaleDateString();
366
+ const deployedMark = version.isCurrent ? ' ⭐ CURRENT' : '';
367
+ return {
368
+ name: `Version ${version.version} (${dateStr})${deployedMark}`,
369
+ value: index
370
+ };
371
+ })
372
+ }
373
+ ]);
374
+ if (!versionAnswer)
375
+ return;
376
+ // Show the selected version's full persona
377
+ await viewVersionDetails([sortedVersions[versionAnswer.selectedVersionIndex]]);
378
+ }
379
+ catch (error) {
380
+ console.error('❌ Error loading persona versions:', error);
381
+ }
382
+ }
383
+ /**
384
+ * View details of a specific version
385
+ */
386
+ async function viewVersionDetails(versions) {
387
+ const version = versions[0]; // Already pre-selected
388
+ const date = new Date(version.createdDate);
389
+ console.log("\n" + "=".repeat(60));
390
+ console.log(`Persona Version ${version.version}`);
391
+ console.log("=".repeat(60));
392
+ console.log(`Created: ${date.toLocaleString()}`);
393
+ console.log(`Status: ${version.isCurrent ? '⭐ CURRENT' : 'Available'}`);
394
+ if (version.createdBy) {
395
+ console.log(`Created by: ${version.createdBy}`);
396
+ }
397
+ console.log("=".repeat(60) + "\n");
398
+ console.log(version.persona);
399
+ console.log("\n" + "=".repeat(60) + "\n");
400
+ await inquirer.prompt([
401
+ {
402
+ type: 'input',
403
+ name: 'continue',
404
+ message: 'Press Enter to continue...'
405
+ }
406
+ ]);
407
+ }
408
+ /**
409
+ * Deploy a persona version to production
410
+ */
411
+ async function deployPersonaVersion(context) {
412
+ writeProgress("🔄 Loading persona versions...");
413
+ try {
414
+ const response = await fetch(`${BASE_URLS.API}/developer/agents/${context.agentId}/persona/versions`, {
415
+ method: 'GET',
416
+ headers: {
417
+ 'Authorization': `Bearer ${context.apiKey}`,
418
+ 'Content-Type': 'application/json'
419
+ }
420
+ });
421
+ if (!response.ok) {
422
+ const errorText = await response.text();
423
+ console.error(`\n❌ API Error: ${response.status} - ${errorText}\n`);
424
+ throw new Error(`HTTP error! status: ${response.status}`);
425
+ }
426
+ const data = await response.json();
427
+ // Handle different response formats
428
+ let versions = [];
429
+ if (Array.isArray(data)) {
430
+ versions = data;
431
+ }
432
+ else if (data.data && Array.isArray(data.data)) {
433
+ versions = data.data;
434
+ }
435
+ else if (data.versions && Array.isArray(data.versions)) {
436
+ versions = data.versions;
437
+ }
438
+ if (versions.length === 0) {
439
+ console.log("\nℹ️ No persona versions available to deploy.\n");
440
+ console.log("💡 Create a version first from sandbox mode.\n");
441
+ return;
442
+ }
443
+ // Sort versions by date (newest first)
444
+ const sortedVersions = versions.sort((a, b) => b.createdDate - a.createdDate);
445
+ console.log("\n" + "=".repeat(60));
446
+ console.log("🌙 Select Persona Version to Deploy");
447
+ console.log("=".repeat(60) + "\n");
448
+ const versionAnswer = await safePrompt([
449
+ {
450
+ type: 'list',
451
+ name: 'selectedVersion',
452
+ message: 'Select version to deploy:',
453
+ choices: sortedVersions.map((v) => {
454
+ const date = new Date(v.createdDate);
455
+ const dateStr = date.toLocaleDateString();
456
+ const timeStr = date.toLocaleTimeString();
457
+ const currentMark = v.isCurrent ? ' ⭐ CURRENTLY DEPLOYED' : '';
458
+ return {
459
+ name: `Version ${v.version} - ${dateStr} ${timeStr}${currentMark}`,
460
+ value: v.version
461
+ };
462
+ })
463
+ }
464
+ ]);
465
+ if (!versionAnswer)
466
+ return;
467
+ const { selectedVersion } = versionAnswer;
468
+ // Show confirmation
469
+ console.log("\n⚠️ WARNING: You are about to deploy to PRODUCTION!");
470
+ console.log("⚠️ This will affect ALL users immediately.\n");
471
+ const confirmAnswer = await safePrompt([
472
+ {
473
+ type: 'confirm',
474
+ name: 'confirm',
475
+ message: 'Are you absolutely sure you want to deploy this persona version?',
476
+ default: false
477
+ }
478
+ ]);
479
+ if (!confirmAnswer || !confirmAnswer.confirm) {
480
+ console.log("\n❌ Deployment cancelled.\n");
481
+ return;
482
+ }
483
+ writeProgress("🔄 Deploying persona version...");
484
+ const deployResponse = await fetch(`${BASE_URLS.API}/developer/agents/${context.agentId}/persona/version/${selectedVersion}`, {
485
+ method: 'POST',
486
+ headers: {
487
+ 'Authorization': `Bearer ${context.apiKey}`,
488
+ 'Content-Type': 'application/json'
489
+ },
490
+ body: JSON.stringify({})
491
+ });
492
+ if (!deployResponse.ok) {
493
+ const errorText = await deployResponse.text();
494
+ console.error(`\n❌ Deploy Error: ${deployResponse.status} - ${errorText}\n`);
495
+ throw new Error(`HTTP error! status: ${deployResponse.status}`);
496
+ }
497
+ writeSuccess(`✅ Persona version ${selectedVersion} deployed successfully to production`);
498
+ writeInfo("💡 The new persona is now active for all users.");
499
+ }
500
+ catch (error) {
501
+ console.error('❌ Error deploying persona version:', error);
502
+ }
503
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Production Command
3
+ * Overview and management of production environment
4
+ */
5
+ /**
6
+ * Main production command - overview of production environment
7
+ *
8
+ * Features:
9
+ * - View current persona and versions
10
+ * - View deployed skills and versions
11
+ * - Manage environment variables
12
+ *
13
+ * @returns Promise that resolves when command completes
14
+ */
15
+ export declare function productionCommand(): Promise<void>;