lua-cli 2.3.2 → 2.4.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.
- package/dist/api/products.api.service.js +1 -0
- package/dist/cli/command-definitions.d.ts +0 -8
- package/dist/cli/command-definitions.js +51 -18
- package/dist/commands/chat.d.ts +17 -0
- package/dist/commands/chat.js +236 -0
- package/dist/commands/chatClear.d.ts +15 -0
- package/dist/commands/chatClear.js +75 -0
- package/dist/commands/env.d.ts +19 -0
- package/dist/commands/env.js +434 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.js +6 -0
- package/dist/commands/persona.d.ts +15 -0
- package/dist/commands/persona.js +503 -0
- package/dist/commands/production.d.ts +15 -0
- package/dist/commands/production.js +532 -0
- package/dist/commands/push.js +56 -0
- package/dist/commands/resources.d.ts +17 -0
- package/dist/commands/resources.js +361 -0
- package/dist/common/data.entry.instance.js +6 -2
- package/dist/config/compile.constants.d.ts +4 -3
- package/dist/config/compile.constants.js +3 -7
- package/dist/config/constants.d.ts +6 -0
- package/dist/config/constants.js +11 -0
- package/dist/index.d.ts +0 -9
- package/dist/index.js +30 -11
- package/dist/utils/bundling.js +61 -0
- package/dist/utils/prompt-handler.d.ts +12 -0
- package/dist/utils/prompt-handler.js +31 -0
- package/dist/utils/push-helpers.js +36 -31
- package/dist/utils/sandbox.js +2 -2
- package/dist/web/app.js +1 -1
- package/package.json +1 -1
- package/template/package-lock.json +1 -1
- package/template/src/tools/BasketTool.ts +4 -1
- package/template/src/tools/ProductsTool.ts +7 -7
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production Command
|
|
3
|
+
* Overview and management of production environment
|
|
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
|
+
/**
|
|
12
|
+
* Main production command - overview of production environment
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - View current persona and versions
|
|
16
|
+
* - View deployed skills and versions
|
|
17
|
+
* - Manage environment variables
|
|
18
|
+
*
|
|
19
|
+
* @returns Promise that resolves when command completes
|
|
20
|
+
*/
|
|
21
|
+
export async function productionCommand() {
|
|
22
|
+
return withErrorHandling(async () => {
|
|
23
|
+
// Step 1: Load configuration
|
|
24
|
+
const config = readSkillConfig();
|
|
25
|
+
validateConfig(config);
|
|
26
|
+
validateAgentConfig(config);
|
|
27
|
+
const agentId = config.agent.agentId;
|
|
28
|
+
// Step 2: Authenticate
|
|
29
|
+
const apiKey = await loadApiKey();
|
|
30
|
+
if (!apiKey) {
|
|
31
|
+
console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
await checkApiKey(apiKey);
|
|
35
|
+
writeProgress("✅ Authenticated");
|
|
36
|
+
const context = {
|
|
37
|
+
agentId,
|
|
38
|
+
apiKey,
|
|
39
|
+
};
|
|
40
|
+
// Step 3: Start management loop
|
|
41
|
+
await manageProduction(context, config);
|
|
42
|
+
}, "production");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Main production management loop
|
|
46
|
+
*/
|
|
47
|
+
async function manageProduction(context, config) {
|
|
48
|
+
let continueManaging = true;
|
|
49
|
+
while (continueManaging) {
|
|
50
|
+
console.log("\n" + "=".repeat(60));
|
|
51
|
+
console.log("🌙 Production Environment");
|
|
52
|
+
console.log("=".repeat(60) + "\n");
|
|
53
|
+
const actionAnswer = await safePrompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'list',
|
|
56
|
+
name: 'action',
|
|
57
|
+
message: 'What would you like to view?',
|
|
58
|
+
choices: [
|
|
59
|
+
{ name: '🤖 Persona - View current persona and versions', value: 'persona' },
|
|
60
|
+
{ name: '⚙️ Skills - View deployed skills and versions', value: 'skills' },
|
|
61
|
+
{ name: '🔐 Environment Variables - Manage production env', value: 'env' },
|
|
62
|
+
{ name: '❌ Exit', value: 'exit' }
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
if (!actionAnswer)
|
|
67
|
+
return;
|
|
68
|
+
const { action } = actionAnswer;
|
|
69
|
+
switch (action) {
|
|
70
|
+
case 'persona':
|
|
71
|
+
await viewProductionPersona(context);
|
|
72
|
+
break;
|
|
73
|
+
case 'skills':
|
|
74
|
+
await viewProductionSkills(context, config);
|
|
75
|
+
break;
|
|
76
|
+
case 'env':
|
|
77
|
+
await manageProductionEnv(context);
|
|
78
|
+
break;
|
|
79
|
+
case 'exit':
|
|
80
|
+
continueManaging = false;
|
|
81
|
+
console.log("\n👋 Goodbye!\n");
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* View production persona and versions
|
|
88
|
+
*/
|
|
89
|
+
async function viewProductionPersona(context) {
|
|
90
|
+
writeProgress("🔄 Loading persona information...");
|
|
91
|
+
try {
|
|
92
|
+
const response = await fetch(`${BASE_URLS.API}/developer/agents/${context.agentId}/persona/versions`, {
|
|
93
|
+
method: 'GET',
|
|
94
|
+
headers: {
|
|
95
|
+
'Authorization': `Bearer ${context.apiKey}`,
|
|
96
|
+
'Content-Type': 'application/json'
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
const errorText = await response.text();
|
|
101
|
+
console.error(`\n❌ API Error: ${response.status} - ${errorText}\n`);
|
|
102
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
103
|
+
}
|
|
104
|
+
const data = await response.json();
|
|
105
|
+
let versions = [];
|
|
106
|
+
if (Array.isArray(data)) {
|
|
107
|
+
versions = data;
|
|
108
|
+
}
|
|
109
|
+
else if (data.data && Array.isArray(data.data)) {
|
|
110
|
+
versions = data.data;
|
|
111
|
+
}
|
|
112
|
+
else if (data.versions && Array.isArray(data.versions)) {
|
|
113
|
+
versions = data.versions;
|
|
114
|
+
}
|
|
115
|
+
if (versions.length === 0) {
|
|
116
|
+
console.log("\nℹ️ No persona versions found.");
|
|
117
|
+
console.log("💡 Create a persona version first using: lua persona\n");
|
|
118
|
+
await safePrompt([
|
|
119
|
+
{
|
|
120
|
+
type: 'input',
|
|
121
|
+
name: 'continue',
|
|
122
|
+
message: 'Press Enter to continue...'
|
|
123
|
+
}
|
|
124
|
+
]);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// Find current deployed version
|
|
128
|
+
const currentVersion = versions.find(v => v.isCurrent);
|
|
129
|
+
console.log("\n" + "=".repeat(60));
|
|
130
|
+
console.log("🤖 Current Production Persona");
|
|
131
|
+
console.log("=".repeat(60) + "\n");
|
|
132
|
+
if (currentVersion) {
|
|
133
|
+
const date = new Date(currentVersion.createdDate);
|
|
134
|
+
console.log(`Version: ${currentVersion.version} ⭐`);
|
|
135
|
+
console.log(`Deployed: ${date.toLocaleString()}`);
|
|
136
|
+
if (currentVersion.createdBy) {
|
|
137
|
+
console.log(`Created by: ${currentVersion.createdBy}`);
|
|
138
|
+
}
|
|
139
|
+
console.log("\n" + "-".repeat(60) + "\n");
|
|
140
|
+
console.log(currentVersion.persona);
|
|
141
|
+
console.log("\n" + "=".repeat(60) + "\n");
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
console.log("⚠️ No persona currently deployed.");
|
|
145
|
+
console.log("💡 Deploy a version using: lua persona → Production → Deploy\n");
|
|
146
|
+
console.log("Available versions:\n");
|
|
147
|
+
versions.forEach((v, i) => {
|
|
148
|
+
const date = new Date(v.createdDate);
|
|
149
|
+
console.log(` ${i + 1}. Version ${v.version} - ${date.toLocaleDateString()}`);
|
|
150
|
+
});
|
|
151
|
+
console.log();
|
|
152
|
+
}
|
|
153
|
+
// Show available versions
|
|
154
|
+
console.log(`Total versions available: ${versions.length}\n`);
|
|
155
|
+
await safePrompt([
|
|
156
|
+
{
|
|
157
|
+
type: 'input',
|
|
158
|
+
name: 'continue',
|
|
159
|
+
message: 'Press Enter to continue...'
|
|
160
|
+
}
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
console.error('❌ Error loading persona information:', error);
|
|
165
|
+
if (error instanceof Error) {
|
|
166
|
+
console.error(` ${error.message}\n`);
|
|
167
|
+
}
|
|
168
|
+
await safePrompt([
|
|
169
|
+
{
|
|
170
|
+
type: 'input',
|
|
171
|
+
name: 'continue',
|
|
172
|
+
message: 'Press Enter to continue...'
|
|
173
|
+
}
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* View production skills and their versions
|
|
179
|
+
*/
|
|
180
|
+
async function viewProductionSkills(context, config) {
|
|
181
|
+
writeProgress("🔄 Loading skill information...");
|
|
182
|
+
try {
|
|
183
|
+
const skills = config.skills || [];
|
|
184
|
+
if (skills.length === 0) {
|
|
185
|
+
console.log("\nℹ️ No skills found in configuration.\n");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
console.log("\n" + "=".repeat(60));
|
|
189
|
+
console.log("⚙️ Production Skills");
|
|
190
|
+
console.log("=".repeat(60) + "\n");
|
|
191
|
+
// Fetch version info for each skill
|
|
192
|
+
for (const skill of skills) {
|
|
193
|
+
try {
|
|
194
|
+
const response = await fetch(`${BASE_URLS.API}/developer/skills/${context.agentId}/${skill.skillId}/versions`, {
|
|
195
|
+
method: 'GET',
|
|
196
|
+
headers: {
|
|
197
|
+
'Authorization': `Bearer ${context.apiKey}`,
|
|
198
|
+
'Content-Type': 'application/json'
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
if (response.ok) {
|
|
202
|
+
const data = await response.json();
|
|
203
|
+
const versions = data.data?.versions || data.versions || [];
|
|
204
|
+
const activeVersionId = data.data?.activeVersionId || data.activeVersionId;
|
|
205
|
+
// Find active version
|
|
206
|
+
const activeVersion = versions.find((v) => v.skillId === activeVersionId);
|
|
207
|
+
console.log(`📦 ${skill.name}`);
|
|
208
|
+
console.log(` Skill ID: ${skill.skillId}`);
|
|
209
|
+
if (activeVersion) {
|
|
210
|
+
console.log(` Deployed Version: ${activeVersion.version} ⭐`);
|
|
211
|
+
const date = new Date(activeVersion.createdAt);
|
|
212
|
+
console.log(` Deployed: ${date.toLocaleString()}`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log(` Deployed Version: Not deployed`);
|
|
216
|
+
}
|
|
217
|
+
console.log(` Total Versions: ${versions.length}`);
|
|
218
|
+
console.log();
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
console.log(`📦 ${skill.name}`);
|
|
222
|
+
console.log(` Skill ID: ${skill.skillId}`);
|
|
223
|
+
console.log(` Status: Unable to fetch version info`);
|
|
224
|
+
console.log();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
console.log(`📦 ${skill.name}`);
|
|
229
|
+
console.log(` Skill ID: ${skill.skillId}`);
|
|
230
|
+
console.log(` Status: Error loading versions`);
|
|
231
|
+
console.log();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
console.log("=".repeat(60) + "\n");
|
|
235
|
+
await safePrompt([
|
|
236
|
+
{
|
|
237
|
+
type: 'input',
|
|
238
|
+
name: 'continue',
|
|
239
|
+
message: 'Press Enter to continue...'
|
|
240
|
+
}
|
|
241
|
+
]);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
console.error('❌ Error loading skill information:', error);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Manage production environment variables
|
|
249
|
+
*/
|
|
250
|
+
async function manageProductionEnv(context) {
|
|
251
|
+
let continueManaging = true;
|
|
252
|
+
while (continueManaging) {
|
|
253
|
+
// Load current variables
|
|
254
|
+
const variables = await loadProductionEnvVariables(context);
|
|
255
|
+
console.log("\n" + "=".repeat(60));
|
|
256
|
+
console.log("🔐 Production Environment Variables");
|
|
257
|
+
console.log("=".repeat(60) + "\n");
|
|
258
|
+
if (variables.length === 0) {
|
|
259
|
+
console.log("ℹ️ No environment variables configured.\n");
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
variables.forEach((v, index) => {
|
|
263
|
+
// Mask values partially for security
|
|
264
|
+
const maskedValue = v.value.length > 4
|
|
265
|
+
? v.value.substring(0, 4) + '*'.repeat(Math.min(v.value.length - 4, 20))
|
|
266
|
+
: '*'.repeat(v.value.length);
|
|
267
|
+
console.log(`${index + 1}. ${v.key} = ${maskedValue}`);
|
|
268
|
+
});
|
|
269
|
+
console.log();
|
|
270
|
+
}
|
|
271
|
+
const actionAnswer = await safePrompt([
|
|
272
|
+
{
|
|
273
|
+
type: 'list',
|
|
274
|
+
name: 'action',
|
|
275
|
+
message: 'What would you like to do?',
|
|
276
|
+
choices: [
|
|
277
|
+
{ name: '➕ Add new variable', value: 'add' },
|
|
278
|
+
{ name: '✏️ Update existing variable', value: 'update' },
|
|
279
|
+
{ name: '🗑️ Delete variable', value: 'delete' },
|
|
280
|
+
{ name: '👁️ View variable value', value: 'view' },
|
|
281
|
+
{ name: '🔄 Refresh list', value: 'refresh' },
|
|
282
|
+
{ name: '⬅️ Back to main menu', value: 'back' }
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
]);
|
|
286
|
+
if (!actionAnswer)
|
|
287
|
+
return;
|
|
288
|
+
const { action } = actionAnswer;
|
|
289
|
+
switch (action) {
|
|
290
|
+
case 'add':
|
|
291
|
+
await addProductionVariable(context, variables);
|
|
292
|
+
break;
|
|
293
|
+
case 'update':
|
|
294
|
+
await updateProductionVariable(context, variables);
|
|
295
|
+
break;
|
|
296
|
+
case 'delete':
|
|
297
|
+
await deleteProductionVariable(context, variables);
|
|
298
|
+
break;
|
|
299
|
+
case 'view':
|
|
300
|
+
await viewProductionVariable(variables);
|
|
301
|
+
break;
|
|
302
|
+
case 'refresh':
|
|
303
|
+
// Just loop again
|
|
304
|
+
break;
|
|
305
|
+
case 'back':
|
|
306
|
+
continueManaging = false;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Load production environment variables
|
|
313
|
+
*/
|
|
314
|
+
async function loadProductionEnvVariables(context) {
|
|
315
|
+
try {
|
|
316
|
+
const response = await fetch(`${BASE_URLS.API}/developer/agents/${context.agentId}/env`, {
|
|
317
|
+
method: 'GET',
|
|
318
|
+
headers: {
|
|
319
|
+
'accept': 'application/json',
|
|
320
|
+
'Authorization': `Bearer ${context.apiKey}`
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
if (!response.ok) {
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
const data = await response.json();
|
|
327
|
+
if (data.data && typeof data.data === 'object') {
|
|
328
|
+
return Object.entries(data.data).map(([key, value]) => ({
|
|
329
|
+
key,
|
|
330
|
+
value: String(value)
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
333
|
+
return [];
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
console.error('⚠️ Error loading environment variables');
|
|
337
|
+
return [];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Save production environment variables
|
|
342
|
+
*/
|
|
343
|
+
async function saveProductionEnvVariables(context, variables) {
|
|
344
|
+
try {
|
|
345
|
+
const envData = {};
|
|
346
|
+
variables.forEach(v => {
|
|
347
|
+
if (v.key.trim()) {
|
|
348
|
+
envData[v.key.trim()] = v.value;
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
const response = await fetch(`${BASE_URLS.API}/developer/agents/${context.agentId}/env`, {
|
|
352
|
+
method: 'POST',
|
|
353
|
+
headers: {
|
|
354
|
+
'accept': 'application/json',
|
|
355
|
+
'Authorization': `Bearer ${context.apiKey}`,
|
|
356
|
+
'Content-Type': 'application/json'
|
|
357
|
+
},
|
|
358
|
+
body: JSON.stringify(envData)
|
|
359
|
+
});
|
|
360
|
+
if (!response.ok) {
|
|
361
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
362
|
+
}
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
console.error('❌ Error saving environment variables:', error);
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Add a new production environment variable
|
|
372
|
+
*/
|
|
373
|
+
async function addProductionVariable(context, currentVariables) {
|
|
374
|
+
const answers = await safePrompt([
|
|
375
|
+
{
|
|
376
|
+
type: 'input',
|
|
377
|
+
name: 'key',
|
|
378
|
+
message: 'Variable name:',
|
|
379
|
+
validate: (input) => {
|
|
380
|
+
if (!input.trim())
|
|
381
|
+
return 'Variable name is required';
|
|
382
|
+
if (!/^[A-Z_][A-Z0-9_]*$/i.test(input.trim())) {
|
|
383
|
+
return 'Variable name must start with a letter or underscore and contain only letters, numbers, and underscores';
|
|
384
|
+
}
|
|
385
|
+
if (currentVariables.some(v => v.key === input.trim())) {
|
|
386
|
+
return 'Variable already exists. Use update to modify it.';
|
|
387
|
+
}
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
type: 'input',
|
|
393
|
+
name: 'value',
|
|
394
|
+
message: 'Variable value:',
|
|
395
|
+
}
|
|
396
|
+
]);
|
|
397
|
+
if (!answers)
|
|
398
|
+
return;
|
|
399
|
+
const newVariable = {
|
|
400
|
+
key: answers.key.trim(),
|
|
401
|
+
value: answers.value
|
|
402
|
+
};
|
|
403
|
+
const updatedVariables = [...currentVariables, newVariable];
|
|
404
|
+
writeProgress("🔄 Saving...");
|
|
405
|
+
const success = await saveProductionEnvVariables(context, updatedVariables);
|
|
406
|
+
if (success) {
|
|
407
|
+
writeSuccess(`✅ Variable "${newVariable.key}" added successfully`);
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
console.error("❌ Failed to save variable");
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Update an existing production environment variable
|
|
415
|
+
*/
|
|
416
|
+
async function updateProductionVariable(context, currentVariables) {
|
|
417
|
+
if (currentVariables.length === 0) {
|
|
418
|
+
console.log("\nℹ️ No variables to update.\n");
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const selectAnswer = await safePrompt([
|
|
422
|
+
{
|
|
423
|
+
type: 'list',
|
|
424
|
+
name: 'selectedKey',
|
|
425
|
+
message: 'Select variable to update:',
|
|
426
|
+
choices: currentVariables.map(v => ({
|
|
427
|
+
name: v.key,
|
|
428
|
+
value: v.key
|
|
429
|
+
}))
|
|
430
|
+
}
|
|
431
|
+
]);
|
|
432
|
+
if (!selectAnswer)
|
|
433
|
+
return;
|
|
434
|
+
const currentVariable = currentVariables.find(v => v.key === selectAnswer.selectedKey);
|
|
435
|
+
const valueAnswer = await safePrompt([
|
|
436
|
+
{
|
|
437
|
+
type: 'input',
|
|
438
|
+
name: 'newValue',
|
|
439
|
+
message: `New value for ${selectAnswer.selectedKey}:`,
|
|
440
|
+
default: currentVariable.value
|
|
441
|
+
}
|
|
442
|
+
]);
|
|
443
|
+
if (!valueAnswer)
|
|
444
|
+
return;
|
|
445
|
+
const updatedVariables = currentVariables.map(v => v.key === selectAnswer.selectedKey ? { ...v, value: valueAnswer.newValue } : v);
|
|
446
|
+
writeProgress("🔄 Saving...");
|
|
447
|
+
const success = await saveProductionEnvVariables(context, updatedVariables);
|
|
448
|
+
if (success) {
|
|
449
|
+
writeSuccess(`✅ Variable "${selectAnswer.selectedKey}" updated successfully`);
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
console.error("❌ Failed to update variable");
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Delete a production environment variable
|
|
457
|
+
*/
|
|
458
|
+
async function deleteProductionVariable(context, currentVariables) {
|
|
459
|
+
if (currentVariables.length === 0) {
|
|
460
|
+
console.log("\nℹ️ No variables to delete.\n");
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const selectAnswer = await safePrompt([
|
|
464
|
+
{
|
|
465
|
+
type: 'list',
|
|
466
|
+
name: 'selectedKey',
|
|
467
|
+
message: 'Select variable to delete:',
|
|
468
|
+
choices: currentVariables.map(v => ({
|
|
469
|
+
name: v.key,
|
|
470
|
+
value: v.key
|
|
471
|
+
}))
|
|
472
|
+
}
|
|
473
|
+
]);
|
|
474
|
+
if (!selectAnswer)
|
|
475
|
+
return;
|
|
476
|
+
const confirmAnswer = await safePrompt([
|
|
477
|
+
{
|
|
478
|
+
type: 'confirm',
|
|
479
|
+
name: 'confirm',
|
|
480
|
+
message: `Are you sure you want to delete "${selectAnswer.selectedKey}" from production?`,
|
|
481
|
+
default: false
|
|
482
|
+
}
|
|
483
|
+
]);
|
|
484
|
+
if (!confirmAnswer || !confirmAnswer.confirm) {
|
|
485
|
+
console.log("\nℹ️ Deletion cancelled.\n");
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const updatedVariables = currentVariables.filter(v => v.key !== selectAnswer.selectedKey);
|
|
489
|
+
writeProgress("🔄 Saving...");
|
|
490
|
+
const success = await saveProductionEnvVariables(context, updatedVariables);
|
|
491
|
+
if (success) {
|
|
492
|
+
writeSuccess(`✅ Variable "${selectAnswer.selectedKey}" deleted successfully`);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
console.error("❌ Failed to delete variable");
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* View a variable's full value (unmasked)
|
|
500
|
+
*/
|
|
501
|
+
async function viewProductionVariable(currentVariables) {
|
|
502
|
+
if (currentVariables.length === 0) {
|
|
503
|
+
console.log("\nℹ️ No variables to view.\n");
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const selectAnswer = await safePrompt([
|
|
507
|
+
{
|
|
508
|
+
type: 'list',
|
|
509
|
+
name: 'selectedKey',
|
|
510
|
+
message: 'Select variable to view:',
|
|
511
|
+
choices: currentVariables.map(v => ({
|
|
512
|
+
name: v.key,
|
|
513
|
+
value: v.key
|
|
514
|
+
}))
|
|
515
|
+
}
|
|
516
|
+
]);
|
|
517
|
+
if (!selectAnswer)
|
|
518
|
+
return;
|
|
519
|
+
const variable = currentVariables.find(v => v.key === selectAnswer.selectedKey);
|
|
520
|
+
console.log("\n" + "=".repeat(60));
|
|
521
|
+
console.log(`Variable: ${variable.key}`);
|
|
522
|
+
console.log("=".repeat(60));
|
|
523
|
+
console.log(variable.value);
|
|
524
|
+
console.log("=".repeat(60) + "\n");
|
|
525
|
+
await safePrompt([
|
|
526
|
+
{
|
|
527
|
+
type: 'input',
|
|
528
|
+
name: 'continue',
|
|
529
|
+
message: 'Press Enter to continue...'
|
|
530
|
+
}
|
|
531
|
+
]);
|
|
532
|
+
}
|
package/dist/commands/push.js
CHANGED
|
@@ -6,8 +6,10 @@ import { compileCommand } from './compile.js';
|
|
|
6
6
|
import { checkApiKey, loadApiKey } from '../services/auth.js';
|
|
7
7
|
import { readSkillConfig } from '../utils/files.js';
|
|
8
8
|
import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
|
|
9
|
+
import { safePrompt } from '../utils/prompt-handler.js';
|
|
9
10
|
import { readDeployJson, validatePushConfig, validateDeployData, promptSkillSelection, promptVersionConfirmOrUpdate, getAvailableSkills, updateSkillVersionInYaml, getSkillDeployData, } from '../utils/push-helpers.js';
|
|
10
11
|
import { pushVersion } from '../utils/push-api.js';
|
|
12
|
+
import { fetchVersions, publishVersion, } from '../utils/deploy-api.js';
|
|
11
13
|
/**
|
|
12
14
|
* Main push command - pushes a skill version to the server.
|
|
13
15
|
*
|
|
@@ -84,6 +86,18 @@ export async function pushCommand() {
|
|
|
84
86
|
const result = await pushVersion(apiKey, agentId, skillId, skillDeployData);
|
|
85
87
|
if (result.success && result.data) {
|
|
86
88
|
writeSuccess(`✅ Version ${result.data.version} of "${selectedSkill.name}" pushed successfully`);
|
|
89
|
+
// Ask if user wants to deploy now
|
|
90
|
+
const deployAnswer = await safePrompt([
|
|
91
|
+
{
|
|
92
|
+
type: 'confirm',
|
|
93
|
+
name: 'deployNow',
|
|
94
|
+
message: 'Would you like to deploy this version to production now?',
|
|
95
|
+
default: false
|
|
96
|
+
}
|
|
97
|
+
]);
|
|
98
|
+
if (deployAnswer && deployAnswer.deployNow) {
|
|
99
|
+
await deployVersionAfterPush(apiKey, config.agent.agentId, selectedSkill, result.data.version);
|
|
100
|
+
}
|
|
87
101
|
}
|
|
88
102
|
else if (result.error) {
|
|
89
103
|
console.error(`❌ ${result.error.message}`);
|
|
@@ -95,3 +109,45 @@ export async function pushCommand() {
|
|
|
95
109
|
}
|
|
96
110
|
}, "push");
|
|
97
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Deploy a version immediately after pushing
|
|
114
|
+
*/
|
|
115
|
+
async function deployVersionAfterPush(apiKey, agentId, selectedSkill, pushedVersion) {
|
|
116
|
+
try {
|
|
117
|
+
writeProgress("\n🔄 Fetching available versions...");
|
|
118
|
+
// Fetch versions to verify the pushed version exists
|
|
119
|
+
const versionsResponse = await fetchVersions(apiKey, agentId, selectedSkill.skillId);
|
|
120
|
+
if (!versionsResponse.versions || versionsResponse.versions.length === 0) {
|
|
121
|
+
console.error("❌ No versions available. The push may have failed.");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Show warning
|
|
125
|
+
console.log("\n⚠️ WARNING: You are about to deploy to PRODUCTION!");
|
|
126
|
+
console.log("⚠️ This will affect ALL users immediately.\n");
|
|
127
|
+
const confirmAnswer = await safePrompt([
|
|
128
|
+
{
|
|
129
|
+
type: 'confirm',
|
|
130
|
+
name: 'confirm',
|
|
131
|
+
message: 'Are you absolutely sure you want to deploy?',
|
|
132
|
+
default: false
|
|
133
|
+
}
|
|
134
|
+
]);
|
|
135
|
+
if (!confirmAnswer || !confirmAnswer.confirm) {
|
|
136
|
+
console.log("\n❌ Deployment cancelled. Version pushed but not deployed.\n");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Find the pushed version in the list
|
|
140
|
+
const versionToDeploy = versionsResponse.versions.find((v) => v.version === pushedVersion);
|
|
141
|
+
if (!versionToDeploy) {
|
|
142
|
+
console.error(`\n❌ Version ${pushedVersion} not found in available versions.\n`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
writeProgress("🔄 Publishing version...");
|
|
146
|
+
const publishResponse = await publishVersion(apiKey, agentId, selectedSkill.skillId, pushedVersion);
|
|
147
|
+
writeSuccess(`\n✅ Version ${pushedVersion} of "${selectedSkill.name}" deployed successfully to production\n`);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.error('\n❌ Error deploying version:', error);
|
|
151
|
+
console.log('💡 You can deploy later using: lua deploy\n');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resources Command
|
|
3
|
+
* Manages agent resources (knowledge base documents)
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Main resources command - manages agent resources
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - List all resources
|
|
10
|
+
* - Create new resources
|
|
11
|
+
* - Update existing resources
|
|
12
|
+
* - Delete resources
|
|
13
|
+
* - View resource content
|
|
14
|
+
*
|
|
15
|
+
* @returns Promise that resolves when command completes
|
|
16
|
+
*/
|
|
17
|
+
export declare function resourcesCommand(): Promise<void>;
|