lua-cli 3.0.0-alpha.5 → 3.0.0-alpha.7

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.
@@ -18,10 +18,7 @@
18
18
  * Note: This does NOT deploy to production. Use `lua deploy` for that.
19
19
  *
20
20
  * @param type - Optional type argument ('skill', 'persona', 'webhook', 'job', 'preprocessor', 'postprocessor', or 'all')
21
- * @param options - Command options (force, autoDeploy)
21
+ * @param cmdObj - Commander command object with options
22
22
  * @returns Promise that resolves when push completes
23
23
  */
24
- export declare function pushCommand(type?: string, options?: {
25
- force?: boolean;
26
- autoDeploy?: boolean;
27
- }): Promise<void>;
24
+ export declare function pushCommand(type?: string, cmdObj?: any): Promise<void>;
@@ -32,15 +32,20 @@ import PostProcessorApi from '../api/postprocessor.api.service.js';
32
32
  * Note: This does NOT deploy to production. Use `lua deploy` for that.
33
33
  *
34
34
  * @param type - Optional type argument ('skill', 'persona', 'webhook', 'job', 'preprocessor', 'postprocessor', or 'all')
35
- * @param options - Command options (force, autoDeploy)
35
+ * @param cmdObj - Commander command object with options
36
36
  * @returns Promise that resolves when push completes
37
37
  */
38
- export async function pushCommand(type, options) {
38
+ export async function pushCommand(type, cmdObj) {
39
39
  return withErrorHandling(async () => {
40
+ // Extract options from Commander command object
41
+ const options = {
42
+ force: cmdObj?.force || false,
43
+ autoDeploy: cmdObj?.autoDeploy || false
44
+ };
40
45
  let selectedType;
41
46
  // Handle 'all' type with force flag
42
47
  if (type === 'all') {
43
- if (!options?.force) {
48
+ if (!options.force) {
44
49
  console.error('āŒ The "all" type requires the --force flag');
45
50
  console.log('\nUsage:');
46
51
  console.log(' lua push all --force Push all components without prompts');
@@ -1058,6 +1063,9 @@ async function deployVersionAfterPush(apiKey, agentId, selectedSkill, pushedVers
1058
1063
  */
1059
1064
  async function pushAllCommand(options) {
1060
1065
  writeProgress("šŸš€ Push All - Pushing all components to server...\n");
1066
+ if (options.autoDeploy) {
1067
+ writeInfo("šŸš€ Auto-deploy to production is ENABLED\n");
1068
+ }
1061
1069
  // Step 1: Compile first
1062
1070
  writeProgress("šŸ“¦ Compiling project...");
1063
1071
  await compileCommand();
@@ -1080,7 +1088,24 @@ async function pushAllCommand(options) {
1080
1088
  process.exit(1);
1081
1089
  }
1082
1090
  const deployData = JSON.parse(fs.readFileSync(deployJsonPath, 'utf8'));
1083
- // Track results
1091
+ // Step 3b: Read bundled webhooks and jobs from dist/
1092
+ const webhooksJsonPath = path.join(process.cwd(), 'dist', 'webhooks.json');
1093
+ const jobsJsonPath = path.join(process.cwd(), 'dist', 'jobs.json');
1094
+ const preprocessorsJsonPath = path.join(process.cwd(), 'dist', 'preprocessors.json');
1095
+ const postprocessorsJsonPath = path.join(process.cwd(), 'dist', 'postprocessors.json');
1096
+ const bundledWebhooks = fs.existsSync(webhooksJsonPath)
1097
+ ? JSON.parse(fs.readFileSync(webhooksJsonPath, 'utf8'))
1098
+ : [];
1099
+ const bundledJobs = fs.existsSync(jobsJsonPath)
1100
+ ? JSON.parse(fs.readFileSync(jobsJsonPath, 'utf8'))
1101
+ : [];
1102
+ const bundledPreprocessors = fs.existsSync(preprocessorsJsonPath)
1103
+ ? JSON.parse(fs.readFileSync(preprocessorsJsonPath, 'utf8'))
1104
+ : [];
1105
+ const bundledPostprocessors = fs.existsSync(postprocessorsJsonPath)
1106
+ ? JSON.parse(fs.readFileSync(postprocessorsJsonPath, 'utf8'))
1107
+ : [];
1108
+ // Track results for both push and deploy
1084
1109
  const results = {
1085
1110
  skills: [],
1086
1111
  webhooks: [],
@@ -1088,6 +1113,12 @@ async function pushAllCommand(options) {
1088
1113
  preprocessors: [],
1089
1114
  postprocessors: []
1090
1115
  };
1116
+ // Track what needs to be deployed
1117
+ const toDeploySkills = [];
1118
+ const toDeployWebhooks = [];
1119
+ const toDeployJobs = [];
1120
+ const toDeployPreprocessors = [];
1121
+ const toDeployPostprocessors = [];
1091
1122
  // Step 4: Push all skills
1092
1123
  if (config.skills && config.skills.length > 0) {
1093
1124
  writeProgress(`\nšŸ“¦ Pushing ${config.skills.length} skill(s)...`);
@@ -1112,24 +1143,22 @@ async function pushAllCommand(options) {
1112
1143
  // Auto-bump patch version
1113
1144
  const newVersion = bumpPatchVersion(currentVersion);
1114
1145
  writeInfo(` šŸ“ ${skillConfig.name}: ${currentVersion} → ${newVersion}`);
1115
- // Push version
1146
+ // Push version - use the full skillData with tools
1116
1147
  const pushResult = await pushVersion(apiKey, agentId, skillId, {
1117
- version: newVersion,
1118
- description: skillConfig.description || '',
1119
- context: skillConfig.context || '',
1120
- code: skillData.code,
1121
- executeFunction: skillData.executeFunction,
1122
- inputSchema: skillData.inputSchema,
1123
- outputSchema: skillData.outputSchema,
1148
+ ...skillData, // Include all fields from deploy.json (tools, name, etc.)
1149
+ version: newVersion, // Override with new version
1124
1150
  });
1151
+ if (!pushResult.success) {
1152
+ console.error(` āŒ Failed to push ${skillConfig.name}:`, pushResult.error?.message);
1153
+ continue;
1154
+ }
1125
1155
  // Update YAML with new version
1126
1156
  updateSkillVersionInYaml(skillConfig.name, newVersion);
1127
1157
  results.skills.push({ name: skillConfig.name, version: newVersion, skillId });
1128
1158
  writeSuccess(` āœ… ${skillConfig.name} v${newVersion} pushed`);
1129
- // Auto-deploy if requested
1159
+ // Queue for deployment if requested
1130
1160
  if (options.autoDeploy) {
1131
- await publishVersion(apiKey, agentId, skillId, newVersion);
1132
- writeSuccess(` šŸš€ ${skillConfig.name} v${newVersion} deployed to production`);
1161
+ toDeploySkills.push({ skillId, version: newVersion, name: skillConfig.name });
1133
1162
  }
1134
1163
  }
1135
1164
  catch (error) {
@@ -1142,9 +1171,9 @@ async function pushAllCommand(options) {
1142
1171
  writeProgress(`\nšŸŖ Pushing ${config.webhooks.length} webhook(s)...`);
1143
1172
  for (const webhookConfig of config.webhooks) {
1144
1173
  try {
1145
- const webhookData = deployData.webhooks?.find((w) => w.name === webhookConfig.name);
1174
+ const webhookData = bundledWebhooks.find((w) => w.name === webhookConfig.name);
1146
1175
  if (!webhookData) {
1147
- console.warn(`āš ļø Webhook "${webhookConfig.name}" not found in deploy.json, skipping`);
1176
+ console.warn(`āš ļø Webhook "${webhookConfig.name}" not found in compiled data, skipping`);
1148
1177
  continue;
1149
1178
  }
1150
1179
  // Validate webhookId and version exist
@@ -1188,18 +1217,9 @@ async function pushAllCommand(options) {
1188
1217
  updateWebhookVersionInYaml(webhookConfig.name, newVersion);
1189
1218
  results.webhooks.push({ name: webhookConfig.name, version: newVersion });
1190
1219
  writeSuccess(` āœ… ${webhookConfig.name} v${newVersion} pushed`);
1191
- // Auto-deploy if requested
1220
+ // Queue for deployment if requested
1192
1221
  if (options.autoDeploy) {
1193
- const deployResponse = await fetch(`${BASE_URLS.API}/developer/webhooks/${agentId}/${webhookConfig.webhookId}/${newVersion}/publish`, {
1194
- method: 'PUT',
1195
- headers: {
1196
- 'Authorization': `Bearer ${apiKey}`,
1197
- 'Content-Type': 'application/json'
1198
- }
1199
- });
1200
- if (deployResponse.ok) {
1201
- writeSuccess(` šŸš€ ${webhookConfig.name} v${newVersion} deployed to production`);
1202
- }
1222
+ toDeployWebhooks.push({ webhookId: webhookConfig.webhookId, version: newVersion, name: webhookConfig.name });
1203
1223
  }
1204
1224
  }
1205
1225
  catch (error) {
@@ -1212,9 +1232,9 @@ async function pushAllCommand(options) {
1212
1232
  writeProgress(`\nā° Pushing ${config.jobs.length} job(s)...`);
1213
1233
  for (const jobConfig of config.jobs) {
1214
1234
  try {
1215
- const jobData = deployData.jobs?.find((j) => j.name === jobConfig.name);
1235
+ const jobData = bundledJobs.find((j) => j.name === jobConfig.name);
1216
1236
  if (!jobData) {
1217
- console.warn(`āš ļø Job "${jobConfig.name}" not found in deploy.json, skipping`);
1237
+ console.warn(`āš ļø Job "${jobConfig.name}" not found in compiled data, skipping`);
1218
1238
  continue;
1219
1239
  }
1220
1240
  // Validate jobId and version exist
@@ -1259,18 +1279,9 @@ async function pushAllCommand(options) {
1259
1279
  updateJobVersionInYaml(jobConfig.name, newVersion);
1260
1280
  results.jobs.push({ name: jobConfig.name, version: newVersion });
1261
1281
  writeSuccess(` āœ… ${jobConfig.name} v${newVersion} pushed`);
1262
- // Auto-deploy if requested
1282
+ // Queue for deployment if requested
1263
1283
  if (options.autoDeploy) {
1264
- const deployResponse = await fetch(`${BASE_URLS.API}/developer/jobs/${agentId}/${jobConfig.jobId}/${newVersion}/publish`, {
1265
- method: 'PUT',
1266
- headers: {
1267
- 'Authorization': `Bearer ${apiKey}`,
1268
- 'Content-Type': 'application/json'
1269
- }
1270
- });
1271
- if (deployResponse.ok) {
1272
- writeSuccess(` šŸš€ ${jobConfig.name} v${newVersion} deployed to production`);
1273
- }
1284
+ toDeployJobs.push({ jobId: jobConfig.jobId, version: newVersion, name: jobConfig.name });
1274
1285
  }
1275
1286
  }
1276
1287
  catch (error) {
@@ -1284,9 +1295,9 @@ async function pushAllCommand(options) {
1284
1295
  const preprocessorService = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
1285
1296
  for (const processorConfig of config.preprocessors) {
1286
1297
  try {
1287
- const processorData = deployData.preprocessors?.find((p) => p.name === processorConfig.name);
1298
+ const processorData = bundledPreprocessors.find((p) => p.name === processorConfig.name);
1288
1299
  if (!processorData) {
1289
- console.warn(`āš ļø Preprocessor "${processorConfig.name}" not found in deploy.json, skipping`);
1300
+ console.warn(`āš ļø Preprocessor "${processorConfig.name}" not found in compiled data, skipping`);
1290
1301
  continue;
1291
1302
  }
1292
1303
  // Validate preprocessorId and version exist
@@ -1323,12 +1334,9 @@ async function pushAllCommand(options) {
1323
1334
  updateProcessorVersionInYaml('preprocessors', processorConfig.name, newVersion);
1324
1335
  results.preprocessors.push({ name: processorConfig.name, version: newVersion });
1325
1336
  writeSuccess(` āœ… ${processorConfig.name} v${newVersion} pushed`);
1326
- // Auto-deploy if requested
1337
+ // Queue for deployment if requested
1327
1338
  if (options.autoDeploy) {
1328
- const deployResult = await preprocessorService.publishPreProcessorVersion(preprocessorId, newVersion);
1329
- if (deployResult.success) {
1330
- writeSuccess(` šŸš€ ${processorConfig.name} v${newVersion} deployed to production`);
1331
- }
1339
+ toDeployPreprocessors.push({ preprocessorId, version: newVersion, name: processorConfig.name });
1332
1340
  }
1333
1341
  }
1334
1342
  catch (error) {
@@ -1342,9 +1350,9 @@ async function pushAllCommand(options) {
1342
1350
  const postprocessorService = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
1343
1351
  for (const processorConfig of config.postprocessors) {
1344
1352
  try {
1345
- const processorData = deployData.postprocessors?.find((p) => p.name === processorConfig.name);
1353
+ const processorData = bundledPostprocessors.find((p) => p.name === processorConfig.name);
1346
1354
  if (!processorData) {
1347
- console.warn(`āš ļø Postprocessor "${processorConfig.name}" not found in deploy.json, skipping`);
1355
+ console.warn(`āš ļø Postprocessor "${processorConfig.name}" not found in compiled data, skipping`);
1348
1356
  continue;
1349
1357
  }
1350
1358
  // Validate postprocessorId and version exist
@@ -1381,12 +1389,9 @@ async function pushAllCommand(options) {
1381
1389
  updateProcessorVersionInYaml('postprocessors', processorConfig.name, newVersion);
1382
1390
  results.postprocessors.push({ name: processorConfig.name, version: newVersion });
1383
1391
  writeSuccess(` āœ… ${processorConfig.name} v${newVersion} pushed`);
1384
- // Auto-deploy if requested
1392
+ // Queue for deployment if requested
1385
1393
  if (options.autoDeploy) {
1386
- const deployResult = await postprocessorService.publishPostProcessorVersion(postprocessorId, newVersion);
1387
- if (deployResult.success) {
1388
- writeSuccess(` šŸš€ ${processorConfig.name} v${newVersion} deployed to production`);
1389
- }
1394
+ toDeployPostprocessors.push({ postprocessorId, version: newVersion, name: processorConfig.name });
1390
1395
  }
1391
1396
  }
1392
1397
  catch (error) {
@@ -1394,7 +1399,104 @@ async function pushAllCommand(options) {
1394
1399
  }
1395
1400
  }
1396
1401
  }
1397
- // Step 9: Print summary
1402
+ // Step 9: Deploy all components if autoDeploy is enabled
1403
+ if (options.autoDeploy && (toDeploySkills.length > 0 || toDeployWebhooks.length > 0 || toDeployJobs.length > 0 || toDeployPreprocessors.length > 0 || toDeployPostprocessors.length > 0)) {
1404
+ writeProgress('\nšŸš€ Deploying all pushed versions to production...');
1405
+ writeInfo('ā±ļø Waiting for server to process versions (5 seconds)...\n');
1406
+ // Wait for server to process all pushed versions
1407
+ await new Promise(resolve => setTimeout(resolve, 5000));
1408
+ // Deploy all skills
1409
+ if (toDeploySkills.length > 0) {
1410
+ writeProgress(`šŸ“¦ Deploying ${toDeploySkills.length} skill(s)...`);
1411
+ for (const skill of toDeploySkills) {
1412
+ const deployed = await retryDeploy(() => publishVersion(apiKey, agentId, skill.skillId, skill.version), skill.name, skill.version, 2 // Only 2 retries since we already waited
1413
+ );
1414
+ if (deployed) {
1415
+ writeSuccess(` šŸš€ ${skill.name} v${skill.version} deployed`);
1416
+ }
1417
+ else {
1418
+ console.warn(` āš ļø ${skill.name} deployment failed`);
1419
+ }
1420
+ }
1421
+ }
1422
+ // Deploy all webhooks
1423
+ if (toDeployWebhooks.length > 0) {
1424
+ writeProgress(`šŸŖ Deploying ${toDeployWebhooks.length} webhook(s)...`);
1425
+ for (const webhook of toDeployWebhooks) {
1426
+ const deployed = await retryDeploy(async () => {
1427
+ const response = await fetch(`${BASE_URLS.API}/developer/webhooks/${agentId}/${webhook.webhookId}/${webhook.version}/publish`, {
1428
+ method: 'PUT',
1429
+ headers: {
1430
+ 'Authorization': `Bearer ${apiKey}`,
1431
+ 'Content-Type': 'application/json'
1432
+ }
1433
+ });
1434
+ if (!response.ok) {
1435
+ throw new Error(`HTTP ${response.status}`);
1436
+ }
1437
+ }, webhook.name, webhook.version, 2);
1438
+ if (deployed) {
1439
+ writeSuccess(` šŸš€ ${webhook.name} v${webhook.version} deployed`);
1440
+ }
1441
+ else {
1442
+ console.warn(` āš ļø ${webhook.name} deployment failed`);
1443
+ }
1444
+ }
1445
+ }
1446
+ // Deploy all jobs
1447
+ if (toDeployJobs.length > 0) {
1448
+ writeProgress(`ā° Deploying ${toDeployJobs.length} job(s)...`);
1449
+ for (const job of toDeployJobs) {
1450
+ const deployed = await retryDeploy(async () => {
1451
+ const response = await fetch(`${BASE_URLS.API}/developer/jobs/${agentId}/${job.jobId}/${job.version}/publish`, {
1452
+ method: 'PUT',
1453
+ headers: {
1454
+ 'Authorization': `Bearer ${apiKey}`,
1455
+ 'Content-Type': 'application/json'
1456
+ }
1457
+ });
1458
+ if (!response.ok) {
1459
+ throw new Error(`HTTP ${response.status}`);
1460
+ }
1461
+ }, job.name, job.version, 2);
1462
+ if (deployed) {
1463
+ writeSuccess(` šŸš€ ${job.name} v${job.version} deployed`);
1464
+ }
1465
+ else {
1466
+ console.warn(` āš ļø ${job.name} deployment failed`);
1467
+ }
1468
+ }
1469
+ }
1470
+ // Deploy all preprocessors
1471
+ if (toDeployPreprocessors.length > 0) {
1472
+ writeProgress(`šŸ“„ Deploying ${toDeployPreprocessors.length} preprocessor(s)...`);
1473
+ const preprocessorService = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
1474
+ for (const processor of toDeployPreprocessors) {
1475
+ const deployed = await retryDeploy(() => preprocessorService.publishPreProcessorVersion(processor.preprocessorId, processor.version), processor.name, processor.version, 2);
1476
+ if (deployed) {
1477
+ writeSuccess(` šŸš€ ${processor.name} v${processor.version} deployed`);
1478
+ }
1479
+ else {
1480
+ console.warn(` āš ļø ${processor.name} deployment failed`);
1481
+ }
1482
+ }
1483
+ }
1484
+ // Deploy all postprocessors
1485
+ if (toDeployPostprocessors.length > 0) {
1486
+ writeProgress(`šŸ“¤ Deploying ${toDeployPostprocessors.length} postprocessor(s)...`);
1487
+ const postprocessorService = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
1488
+ for (const processor of toDeployPostprocessors) {
1489
+ const deployed = await retryDeploy(() => postprocessorService.publishPostProcessorVersion(processor.postprocessorId, processor.version), processor.name, processor.version, 2);
1490
+ if (deployed) {
1491
+ writeSuccess(` šŸš€ ${processor.name} v${processor.version} deployed`);
1492
+ }
1493
+ else {
1494
+ console.warn(` āš ļø ${processor.name} deployment failed`);
1495
+ }
1496
+ }
1497
+ }
1498
+ }
1499
+ // Step 10: Print summary
1398
1500
  writeSuccess('\nāœ… Push All Complete!\n');
1399
1501
  if (results.skills.length > 0) {
1400
1502
  console.log(`šŸ› ļø Skills (${results.skills.length}):`);
@@ -1435,3 +1537,25 @@ function bumpPatchVersion(version) {
1435
1537
  const newPatch = parseInt(patch, 10) + 1;
1436
1538
  return `${major}.${minor}.${newPatch}`;
1437
1539
  }
1540
+ /**
1541
+ * Retry deployment with exponential backoff
1542
+ * The server needs time to process pushed versions before they can be deployed
1543
+ */
1544
+ async function retryDeploy(deployFn, componentName, version, maxRetries = 3) {
1545
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1546
+ try {
1547
+ const delay = attempt * 2000; // 2s, 4s, 6s (longer delays)
1548
+ await new Promise(resolve => setTimeout(resolve, delay));
1549
+ await deployFn();
1550
+ return true;
1551
+ }
1552
+ catch (error) {
1553
+ if (attempt === maxRetries) {
1554
+ console.error(` [Retry ${attempt}/${maxRetries}] Deploy failed: ${error.message}`);
1555
+ return false;
1556
+ }
1557
+ // Continue to next retry silently
1558
+ }
1559
+ }
1560
+ return false;
1561
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lua-cli",
3
- "version": "3.0.0-alpha.5",
3
+ "version": "3.0.0-alpha.7",
4
4
  "description": "Command-line interface for Lua AI platform - develop, test, and deploy LuaSkills with custom tools",
5
5
  "readmeFilename": "README.md",
6
6
  "main": "dist/api-exports.js",
@@ -1,47 +1,69 @@
1
1
  agent:
2
2
  agentId: baseAgent_agent_1760922427216_fk9w0ezhh
3
3
  orgId: 026cc41b-e013-4474-9b65-5a15f8881f92
4
- persona: |
5
- Meet Vivienne, the vibrant and dynamic assistant at V3 Test, a lively retail and consumer goods store that specializes in bringing a splash of color and excitement to everyday life. Vivienne embodies the brand's energetic and fun personality, always ready to engage with customers in a way that makes shopping an enjoyable and memorable experience. Her role is to be the friendly face and knowledgeable guide for anyone who steps into the store, whether they're looking for the latest fashion trends or a unique gift for a loved one.
4
+ persona: >
5
+ Meet Vivienne, the vibrant and dynamic assistant at V3 Test, a lively retail and consumer goods store that
6
+ specializes in bringing a splash of color and excitement to everyday life. Vivienne embodies the brand's energetic
7
+ and fun personality, always ready to engage with customers in a way that makes shopping an enjoyable and memorable
8
+ experience. Her role is to be the friendly face and knowledgeable guide for anyone who steps into the store, whether
9
+ they're looking for the latest fashion trends or a unique gift for a loved one.
6
10
 
7
- V3 Test is all about creating a joyful and spirited shopping environment, and Vivienne is the perfect personification of this ethos. She is lively, approachable, and always ready with a smile, making every interaction feel like a conversation with a good friend. Her voice is warm and enthusiastic, with a hint of playfulness that puts customers at ease and encourages them to explore the store's offerings.
8
11
 
9
- Vivienne's target customers are diverse, ranging from young adults in their twenties who are fashion-forward and tech-savvy, to busy parents looking for quality products that add a touch of fun to their family life. She understands the fast-paced lifestyle of her customers and is adept at tailoring her approach to meet their individual needs, whether they're in a hurry or have time to browse.
12
+ V3 Test is all about creating a joyful and spirited shopping environment, and Vivienne is the perfect
13
+ personification of this ethos. She is lively, approachable, and always ready with a smile, making every interaction
14
+ feel like a conversation with a good friend. Her voice is warm and enthusiastic, with a hint of playfulness that
15
+ puts customers at ease and encourages them to explore the store's offerings.
10
16
 
11
- Her sales approach is consultative and friendly, focusing on understanding the customer's needs and preferences before suggesting products that align with their style and personality. Vivienne is confident in her recommendations, always ready to upsell when appropriate, but never pushy. She believes in building relationships with customers, ensuring they leave the store not only with products they love but also with a positive impression of the brand.
12
17
 
13
- In terms of communication style, Vivienne strikes a perfect balance between being informal and efficient. She is warm and engaging, making customers feel valued and appreciated, while also being mindful of their time. Her interactions are peppered with humor and light-hearted banter, creating a shopping experience that is both enjoyable and efficient. Whether it's through in-person interactions or digital communication, Vivienne ensures that every customer feels like a part of the V3 Test family.
18
+ Vivienne's target customers are diverse, ranging from young adults in their twenties who are fashion-forward and
19
+ tech-savvy, to busy parents looking for quality products that add a touch of fun to their family life. She
20
+ understands the fast-paced lifestyle of her customers and is adept at tailoring her approach to meet their
21
+ individual needs, whether they're in a hurry or have time to browse.
22
+
23
+
24
+ Her sales approach is consultative and friendly, focusing on understanding the customer's needs and preferences
25
+ before suggesting products that align with their style and personality. Vivienne is confident in her
26
+ recommendations, always ready to upsell when appropriate, but never pushy. She believes in building relationships
27
+ with customers, ensuring they leave the store not only with products they love but also with a positive impression
28
+ of the brand.
29
+
30
+
31
+ In terms of communication style, Vivienne strikes a perfect balance between being informal and efficient. She is
32
+ warm and engaging, making customers feel valued and appreciated, while also being mindful of their time. Her
33
+ interactions are peppered with humor and light-hearted banter, creating a shopping experience that is both enjoyable
34
+ and efficient. Whether it's through in-person interactions or digital communication, Vivienne ensures that every
35
+ customer feels like a part of the V3 Test family.
14
36
  welcomeMessage: Hi, I am your AI assistant. How can I help you today?
15
37
  skills:
16
38
  - name: general-skill
17
- version: 0.0.4
39
+ version: 0.0.6
18
40
  skillId: 1faf9b3a-e352-4e63-a6c4-a3deca815361
19
41
  - name: user-data-skill
20
- version: 0.0.2
42
+ version: 0.0.15
21
43
  skillId: e0c382c1-f469-4880-962a-a756ea3c1411
22
44
  - name: product-skill
23
- version: 0.0.2
45
+ version: 0.0.15
24
46
  skillId: d4cdc7bc-6d42-4232-902d-2b9cf68bd74a
25
47
  - name: basket-skill
26
- version: 0.0.2
48
+ version: 0.0.14
27
49
  skillId: 5b06c5ff-7cf3-49c4-8641-142270c81db4
28
50
  - name: order-skill
29
- version: 0.0.2
51
+ version: 0.0.14
30
52
  skillId: d4045304-7c30-4750-9edd-340eb1357a39
31
53
  - name: custom-data-skill
32
- version: 0.0.2
54
+ version: 0.0.13
33
55
  skillId: 83fe411c-90a1-4bd3-9271-ac8e03d6a3be
34
56
  - name: payment-skill
35
- version: 0.0.2
57
+ version: 0.0.13
36
58
  skillId: f2248c02-c6c6-4c3a-89bf-ff09ec11529a
37
59
  jobs:
38
60
  - name: test-job
39
- version: 1.0.2
61
+ version: 1.0.13
40
62
  jobId: d66b73a0-f944-4718-b6a2-f07bfeabd625
41
63
  schedule:
42
64
  type: once
43
65
  executeAt: '2025-10-20T01:08:04.639Z'
44
66
  webhooks:
45
67
  - name: test-webhook
46
- version: 1.0.1
68
+ version: 1.0.12
47
69
  webhookId: c967fd58-1d4d-49b6-8fa6-ec36b4d23e7f
@@ -20,7 +20,7 @@
20
20
  "inquirer": "^12.9.6",
21
21
  "stripe": "^17.5.0",
22
22
  "js-yaml": "^4.1.0",
23
- "lua-cli": "^3.0.0-alpha.5",
23
+ "lua-cli": "file:..",
24
24
  "openai": "^5.23.0",
25
25
  "uuid": "^13.0.0",
26
26
  "zod": "^3.24.1"