lua-cli 3.0.0-alpha.4 → 3.0.0-alpha.6

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.
@@ -70,16 +70,23 @@ Examples:
70
70
  program
71
71
  .command("push [type]")
72
72
  .description("☁️ Push skill, webhook, job, or persona version to server")
73
+ .option('--force', 'Skip all confirmation prompts (auto-confirm)')
74
+ .option('--auto-deploy', 'Automatically deploy to production after push')
73
75
  .addHelpText('after', `
74
76
  Arguments:
75
- type Optional: 'skill', 'webhook', 'job', or 'persona' (prompts if not provided)
77
+ type Optional: 'skill', 'webhook', 'job', 'preprocessor', 'postprocessor', 'persona', or 'all' (prompts if not provided)
78
+
79
+ Options:
80
+ --force Skip all confirmation prompts
81
+ --auto-deploy Automatically deploy to production after push
76
82
 
77
83
  Examples:
78
- $ lua push Interactive selection
79
- $ lua push skill Push a skill directly
80
- $ lua push webhook Push a webhook directly
81
- $ lua push job Push a job directly
82
- $ lua push persona Push a persona directly
84
+ $ lua push Interactive selection
85
+ $ lua push skill Push a skill directly
86
+ $ lua push webhook Push a webhook directly
87
+ $ lua push job Push a job directly
88
+ $ lua push all --force Push all components from YAML without prompts
89
+ $ lua push all --force --auto-deploy Push and deploy all to production
83
90
  `)
84
91
  .action(pushCommand);
85
92
  program
@@ -17,7 +17,8 @@
17
17
  *
18
18
  * Note: This does NOT deploy to production. Use `lua deploy` for that.
19
19
  *
20
- * @param type - Optional type argument ('skill' or 'persona')
20
+ * @param type - Optional type argument ('skill', 'persona', 'webhook', 'job', 'preprocessor', 'postprocessor', or 'all')
21
+ * @param cmdObj - Commander command object with options
21
22
  * @returns Promise that resolves when push completes
22
23
  */
23
- export declare function pushCommand(type?: string): Promise<void>;
24
+ export declare function pushCommand(type?: string, cmdObj?: any): Promise<void>;
@@ -31,17 +31,34 @@ import PostProcessorApi from '../api/postprocessor.api.service.js';
31
31
  *
32
32
  * Note: This does NOT deploy to production. Use `lua deploy` for that.
33
33
  *
34
- * @param type - Optional type argument ('skill' or 'persona')
34
+ * @param type - Optional type argument ('skill', 'persona', 'webhook', 'job', 'preprocessor', 'postprocessor', or 'all')
35
+ * @param cmdObj - Commander command object with options
35
36
  * @returns Promise that resolves when push completes
36
37
  */
37
- export async function pushCommand(type) {
38
+ export async function pushCommand(type, cmdObj) {
38
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
+ };
39
45
  let selectedType;
46
+ // Handle 'all' type with force flag
47
+ if (type === 'all') {
48
+ if (!options.force) {
49
+ console.error('❌ The "all" type requires the --force flag');
50
+ console.log('\nUsage:');
51
+ console.log(' lua push all --force Push all components without prompts');
52
+ console.log(' lua push all --force --auto-deploy Push and deploy all to production');
53
+ process.exit(1);
54
+ }
55
+ return await pushAllCommand(options);
56
+ }
40
57
  // Step 1: Check if type was provided as argument
41
58
  if (type) {
42
59
  // Validate the provided type
43
60
  if (type !== 'skill' && type !== 'persona' && type !== 'webhook' && type !== 'job' && type !== 'preprocessor' && type !== 'postprocessor') {
44
- console.error(`❌ Invalid type: "${type}". Must be "skill", "persona", "webhook", "job", "preprocessor", or "postprocessor".`);
61
+ console.error(`❌ Invalid type: "${type}". Must be "skill", "persona", "webhook", "job", "preprocessor", "postprocessor", or "all".`);
45
62
  console.log('\nUsage:');
46
63
  console.log(' lua push - Interactive selection');
47
64
  console.log(' lua push skill - Push a skill directly');
@@ -50,6 +67,7 @@ export async function pushCommand(type) {
50
67
  console.log(' lua push job - Push a job directly');
51
68
  console.log(' lua push preprocessor - Push a preprocessor directly');
52
69
  console.log(' lua push postprocessor - Push a postprocessor directly');
70
+ console.log(' lua push all --force - Push all components without prompts');
53
71
  process.exit(1);
54
72
  }
55
73
  selectedType = type;
@@ -1031,3 +1049,518 @@ async function deployVersionAfterPush(apiKey, agentId, selectedSkill, pushedVers
1031
1049
  console.log('💡 You can deploy later using: lua deploy\n');
1032
1050
  }
1033
1051
  }
1052
+ /**
1053
+ * Push all command - Pushes all components (skills, webhooks, jobs, processors) without prompts
1054
+ *
1055
+ * This command:
1056
+ * 1. Compiles the project
1057
+ * 2. Reads lua.skill.yaml to get all components
1058
+ * 3. Auto-bumps patch versions
1059
+ * 4. Pushes all components
1060
+ * 5. Optionally auto-deploys to production
1061
+ *
1062
+ * @param options - Command options (force is required, autoDeploy is optional)
1063
+ */
1064
+ async function pushAllCommand(options) {
1065
+ writeProgress("🚀 Push All - Pushing all components to server...\n");
1066
+ if (options.autoDeploy) {
1067
+ writeInfo("🚀 Auto-deploy to production is ENABLED\n");
1068
+ }
1069
+ // Step 1: Compile first
1070
+ writeProgress("📦 Compiling project...");
1071
+ await compileCommand();
1072
+ // Step 2: Load configuration and API key
1073
+ const config = readSkillConfig();
1074
+ if (!config?.agent?.agentId) {
1075
+ console.error('❌ No agent ID found in lua.skill.yaml. Run "lua init" first.');
1076
+ process.exit(1);
1077
+ }
1078
+ const apiKey = await loadApiKey();
1079
+ if (!apiKey) {
1080
+ console.error('❌ No API key found. Run "lua auth configure" first.');
1081
+ process.exit(1);
1082
+ }
1083
+ const agentId = config.agent.agentId; // Validated above, safe to assert
1084
+ // Step 3: Read deploy.json for component data
1085
+ const deployJsonPath = path.join(process.cwd(), '.lua', 'deploy.json');
1086
+ if (!fs.existsSync(deployJsonPath)) {
1087
+ console.error('❌ No deploy.json found. Compilation may have failed.');
1088
+ process.exit(1);
1089
+ }
1090
+ const deployData = JSON.parse(fs.readFileSync(deployJsonPath, 'utf8'));
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
1109
+ const results = {
1110
+ skills: [],
1111
+ webhooks: [],
1112
+ jobs: [],
1113
+ preprocessors: [],
1114
+ postprocessors: []
1115
+ };
1116
+ // Track what needs to be deployed
1117
+ const toDeploySkills = [];
1118
+ const toDeployWebhooks = [];
1119
+ const toDeployJobs = [];
1120
+ const toDeployPreprocessors = [];
1121
+ const toDeployPostprocessors = [];
1122
+ // Step 4: Push all skills
1123
+ if (config.skills && config.skills.length > 0) {
1124
+ writeProgress(`\n📦 Pushing ${config.skills.length} skill(s)...`);
1125
+ for (const skillConfig of config.skills) {
1126
+ try {
1127
+ const skillData = deployData.skills.find((s) => s.name === skillConfig.name);
1128
+ if (!skillData) {
1129
+ console.warn(`⚠️ Skill "${skillConfig.name}" not found in deploy.json, skipping`);
1130
+ continue;
1131
+ }
1132
+ // Validate skillId and version exist
1133
+ const skillId = skillConfig.skillId;
1134
+ const currentVersion = skillConfig.version;
1135
+ if (!skillId) {
1136
+ console.warn(`⚠️ Skill "${skillConfig.name}" has no skillId, skipping`);
1137
+ continue;
1138
+ }
1139
+ if (!currentVersion) {
1140
+ console.warn(`⚠️ Skill "${skillConfig.name}" has no version, skipping`);
1141
+ continue;
1142
+ }
1143
+ // Auto-bump patch version
1144
+ const newVersion = bumpPatchVersion(currentVersion);
1145
+ writeInfo(` 📝 ${skillConfig.name}: ${currentVersion} → ${newVersion}`);
1146
+ // Push version
1147
+ const pushResult = await pushVersion(apiKey, agentId, skillId, {
1148
+ version: newVersion,
1149
+ description: skillConfig.description || '',
1150
+ context: skillConfig.context || '',
1151
+ code: skillData.code,
1152
+ executeFunction: skillData.executeFunction,
1153
+ inputSchema: skillData.inputSchema,
1154
+ outputSchema: skillData.outputSchema,
1155
+ });
1156
+ if (!pushResult.success) {
1157
+ console.error(` ❌ Failed to push ${skillConfig.name}:`, pushResult.error?.message);
1158
+ continue;
1159
+ }
1160
+ // Update YAML with new version
1161
+ updateSkillVersionInYaml(skillConfig.name, newVersion);
1162
+ results.skills.push({ name: skillConfig.name, version: newVersion, skillId });
1163
+ writeSuccess(` ✅ ${skillConfig.name} v${newVersion} pushed`);
1164
+ // Queue for deployment if requested
1165
+ if (options.autoDeploy) {
1166
+ toDeploySkills.push({ skillId, version: newVersion, name: skillConfig.name });
1167
+ }
1168
+ }
1169
+ catch (error) {
1170
+ console.error(` ❌ Failed to push ${skillConfig.name}:`, error.message);
1171
+ }
1172
+ }
1173
+ }
1174
+ // Step 5: Push all webhooks
1175
+ if (config.webhooks && config.webhooks.length > 0) {
1176
+ writeProgress(`\n🪝 Pushing ${config.webhooks.length} webhook(s)...`);
1177
+ for (const webhookConfig of config.webhooks) {
1178
+ try {
1179
+ const webhookData = bundledWebhooks.find((w) => w.name === webhookConfig.name);
1180
+ if (!webhookData) {
1181
+ console.warn(`⚠️ Webhook "${webhookConfig.name}" not found in compiled data, skipping`);
1182
+ continue;
1183
+ }
1184
+ // Validate webhookId and version exist
1185
+ if (!webhookConfig.webhookId) {
1186
+ console.warn(`⚠️ Webhook "${webhookConfig.name}" has no webhookId, skipping`);
1187
+ continue;
1188
+ }
1189
+ if (!webhookConfig.version) {
1190
+ console.warn(`⚠️ Webhook "${webhookConfig.name}" has no version, skipping`);
1191
+ continue;
1192
+ }
1193
+ // Auto-bump patch version
1194
+ const newVersion = bumpPatchVersion(webhookConfig.version);
1195
+ writeInfo(` 📝 ${webhookConfig.name}: ${webhookConfig.version} → ${newVersion}`);
1196
+ // Prepare webhook data for push
1197
+ const pushData = {
1198
+ name: webhookConfig.name,
1199
+ version: newVersion,
1200
+ description: webhookData.description || webhookConfig.description || '',
1201
+ context: webhookData.context || webhookConfig.context || '',
1202
+ webhookId: webhookConfig.webhookId,
1203
+ querySchema: webhookData.querySchema,
1204
+ headerSchema: webhookData.headerSchema,
1205
+ bodySchema: webhookData.bodySchema,
1206
+ code: webhookData.code,
1207
+ executeFunction: webhookData.executeFunction
1208
+ };
1209
+ // Push version using fetch (like existing webhook push)
1210
+ const response = await fetch(`${BASE_URLS.API}/developer/webhooks/${agentId}/${webhookConfig.webhookId}/version`, {
1211
+ method: 'POST',
1212
+ headers: {
1213
+ 'Authorization': `Bearer ${apiKey}`,
1214
+ 'Content-Type': 'application/json'
1215
+ },
1216
+ body: JSON.stringify(pushData)
1217
+ });
1218
+ if (!response.ok) {
1219
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
1220
+ }
1221
+ // Update YAML
1222
+ updateWebhookVersionInYaml(webhookConfig.name, newVersion);
1223
+ results.webhooks.push({ name: webhookConfig.name, version: newVersion });
1224
+ writeSuccess(` ✅ ${webhookConfig.name} v${newVersion} pushed`);
1225
+ // Queue for deployment if requested
1226
+ if (options.autoDeploy) {
1227
+ toDeployWebhooks.push({ webhookId: webhookConfig.webhookId, version: newVersion, name: webhookConfig.name });
1228
+ }
1229
+ }
1230
+ catch (error) {
1231
+ console.error(` ❌ Failed to push ${webhookConfig.name}:`, error.message);
1232
+ }
1233
+ }
1234
+ }
1235
+ // Step 6: Push all jobs
1236
+ if (config.jobs && config.jobs.length > 0) {
1237
+ writeProgress(`\n⏰ Pushing ${config.jobs.length} job(s)...`);
1238
+ for (const jobConfig of config.jobs) {
1239
+ try {
1240
+ const jobData = bundledJobs.find((j) => j.name === jobConfig.name);
1241
+ if (!jobData) {
1242
+ console.warn(`⚠️ Job "${jobConfig.name}" not found in compiled data, skipping`);
1243
+ continue;
1244
+ }
1245
+ // Validate jobId and version exist
1246
+ if (!jobConfig.jobId) {
1247
+ console.warn(`⚠️ Job "${jobConfig.name}" has no jobId, skipping`);
1248
+ continue;
1249
+ }
1250
+ if (!jobConfig.version) {
1251
+ console.warn(`⚠️ Job "${jobConfig.name}" has no version, skipping`);
1252
+ continue;
1253
+ }
1254
+ // Auto-bump patch version
1255
+ const newVersion = bumpPatchVersion(jobConfig.version);
1256
+ writeInfo(` 📝 ${jobConfig.name}: ${jobConfig.version} → ${newVersion}`);
1257
+ // Prepare job data for push
1258
+ const pushData = {
1259
+ name: jobConfig.name,
1260
+ version: newVersion,
1261
+ description: jobData.description || jobConfig.description || '',
1262
+ context: jobData.context || jobConfig.context || '',
1263
+ jobId: jobConfig.jobId,
1264
+ schedule: jobData.schedule || jobConfig.schedule,
1265
+ timeout: jobData.timeout,
1266
+ retry: jobData.retry,
1267
+ code: jobData.code,
1268
+ executeFunction: jobData.executeFunction,
1269
+ metadata: jobData.metadata || jobConfig.metadata
1270
+ };
1271
+ // Push version using fetch
1272
+ const response = await fetch(`${BASE_URLS.API}/developer/jobs/${agentId}/${jobConfig.jobId}/version`, {
1273
+ method: 'POST',
1274
+ headers: {
1275
+ 'Authorization': `Bearer ${apiKey}`,
1276
+ 'Content-Type': 'application/json'
1277
+ },
1278
+ body: JSON.stringify(pushData)
1279
+ });
1280
+ if (!response.ok) {
1281
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
1282
+ }
1283
+ // Update YAML
1284
+ updateJobVersionInYaml(jobConfig.name, newVersion);
1285
+ results.jobs.push({ name: jobConfig.name, version: newVersion });
1286
+ writeSuccess(` ✅ ${jobConfig.name} v${newVersion} pushed`);
1287
+ // Queue for deployment if requested
1288
+ if (options.autoDeploy) {
1289
+ toDeployJobs.push({ jobId: jobConfig.jobId, version: newVersion, name: jobConfig.name });
1290
+ }
1291
+ }
1292
+ catch (error) {
1293
+ console.error(` ❌ Failed to push ${jobConfig.name}:`, error.message);
1294
+ }
1295
+ }
1296
+ }
1297
+ // Step 7: Push all preprocessors
1298
+ if (config.preprocessors && config.preprocessors.length > 0) {
1299
+ writeProgress(`\n📥 Pushing ${config.preprocessors.length} preprocessor(s)...`);
1300
+ const preprocessorService = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
1301
+ for (const processorConfig of config.preprocessors) {
1302
+ try {
1303
+ const processorData = bundledPreprocessors.find((p) => p.name === processorConfig.name);
1304
+ if (!processorData) {
1305
+ console.warn(`⚠️ Preprocessor "${processorConfig.name}" not found in compiled data, skipping`);
1306
+ continue;
1307
+ }
1308
+ // Validate preprocessorId and version exist
1309
+ const preprocessorId = processorConfig.preprocessorId;
1310
+ const currentVersion = processorConfig.version;
1311
+ if (!preprocessorId) {
1312
+ console.warn(`⚠️ Preprocessor "${processorConfig.name}" has no preprocessorId, skipping`);
1313
+ continue;
1314
+ }
1315
+ if (!currentVersion) {
1316
+ console.warn(`⚠️ Preprocessor "${processorConfig.name}" has no version, skipping`);
1317
+ continue;
1318
+ }
1319
+ // Auto-bump patch version
1320
+ const newVersion = bumpPatchVersion(currentVersion);
1321
+ writeInfo(` 📝 ${processorConfig.name}: ${currentVersion} → ${newVersion}`);
1322
+ // Prepare version data
1323
+ const versionData = {
1324
+ name: processorConfig.name,
1325
+ version: newVersion,
1326
+ description: processorData.description || processorConfig.description || '',
1327
+ context: processorData.context || processorConfig.context || '',
1328
+ preprocessorId: preprocessorId,
1329
+ code: processorData.code,
1330
+ executeFunction: processorData.executeFunction,
1331
+ async: Boolean(processorData.async ?? false)
1332
+ };
1333
+ // Push version
1334
+ const result = await preprocessorService.pushPreProcessor(preprocessorId, versionData);
1335
+ if (!result.success) {
1336
+ throw new Error(result.error?.message || 'Failed to push preprocessor');
1337
+ }
1338
+ // Update YAML
1339
+ updateProcessorVersionInYaml('preprocessors', processorConfig.name, newVersion);
1340
+ results.preprocessors.push({ name: processorConfig.name, version: newVersion });
1341
+ writeSuccess(` ✅ ${processorConfig.name} v${newVersion} pushed`);
1342
+ // Queue for deployment if requested
1343
+ if (options.autoDeploy) {
1344
+ toDeployPreprocessors.push({ preprocessorId, version: newVersion, name: processorConfig.name });
1345
+ }
1346
+ }
1347
+ catch (error) {
1348
+ console.error(` ❌ Failed to push ${processorConfig.name}:`, error.message);
1349
+ }
1350
+ }
1351
+ }
1352
+ // Step 8: Push all postprocessors
1353
+ if (config.postprocessors && config.postprocessors.length > 0) {
1354
+ writeProgress(`\n📤 Pushing ${config.postprocessors.length} postprocessor(s)...`);
1355
+ const postprocessorService = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
1356
+ for (const processorConfig of config.postprocessors) {
1357
+ try {
1358
+ const processorData = bundledPostprocessors.find((p) => p.name === processorConfig.name);
1359
+ if (!processorData) {
1360
+ console.warn(`⚠️ Postprocessor "${processorConfig.name}" not found in compiled data, skipping`);
1361
+ continue;
1362
+ }
1363
+ // Validate postprocessorId and version exist
1364
+ const postprocessorId = processorConfig.postprocessorId;
1365
+ const currentVersion = processorConfig.version;
1366
+ if (!postprocessorId) {
1367
+ console.warn(`⚠️ Postprocessor "${processorConfig.name}" has no postprocessorId, skipping`);
1368
+ continue;
1369
+ }
1370
+ if (!currentVersion) {
1371
+ console.warn(`⚠️ Postprocessor "${processorConfig.name}" has no version, skipping`);
1372
+ continue;
1373
+ }
1374
+ // Auto-bump patch version
1375
+ const newVersion = bumpPatchVersion(currentVersion);
1376
+ writeInfo(` 📝 ${processorConfig.name}: ${currentVersion} → ${newVersion}`);
1377
+ // Prepare version data
1378
+ const versionData = {
1379
+ name: processorConfig.name,
1380
+ version: newVersion,
1381
+ description: processorData.description || processorConfig.description || '',
1382
+ context: processorData.context || processorConfig.context || '',
1383
+ postprocessorId: postprocessorId,
1384
+ code: processorData.code,
1385
+ executeFunction: processorData.executeFunction,
1386
+ async: Boolean(processorData.async ?? false)
1387
+ };
1388
+ // Push version
1389
+ const result = await postprocessorService.pushPostProcessor(postprocessorId, versionData);
1390
+ if (!result.success) {
1391
+ throw new Error(result.error?.message || 'Failed to push postprocessor');
1392
+ }
1393
+ // Update YAML
1394
+ updateProcessorVersionInYaml('postprocessors', processorConfig.name, newVersion);
1395
+ results.postprocessors.push({ name: processorConfig.name, version: newVersion });
1396
+ writeSuccess(` ✅ ${processorConfig.name} v${newVersion} pushed`);
1397
+ // Queue for deployment if requested
1398
+ if (options.autoDeploy) {
1399
+ toDeployPostprocessors.push({ postprocessorId, version: newVersion, name: processorConfig.name });
1400
+ }
1401
+ }
1402
+ catch (error) {
1403
+ console.error(` ❌ Failed to push ${processorConfig.name}:`, error.message);
1404
+ }
1405
+ }
1406
+ }
1407
+ // Step 9: Deploy all components if autoDeploy is enabled
1408
+ if (options.autoDeploy && (toDeploySkills.length > 0 || toDeployWebhooks.length > 0 || toDeployJobs.length > 0 || toDeployPreprocessors.length > 0 || toDeployPostprocessors.length > 0)) {
1409
+ writeProgress('\n🚀 Deploying all pushed versions to production...');
1410
+ writeInfo('⏱️ Waiting for server to process versions (5 seconds)...\n');
1411
+ // Wait for server to process all pushed versions
1412
+ await new Promise(resolve => setTimeout(resolve, 5000));
1413
+ // Deploy all skills
1414
+ if (toDeploySkills.length > 0) {
1415
+ writeProgress(`📦 Deploying ${toDeploySkills.length} skill(s)...`);
1416
+ for (const skill of toDeploySkills) {
1417
+ const deployed = await retryDeploy(() => publishVersion(apiKey, agentId, skill.skillId, skill.version), skill.name, skill.version, 2 // Only 2 retries since we already waited
1418
+ );
1419
+ if (deployed) {
1420
+ writeSuccess(` 🚀 ${skill.name} v${skill.version} deployed`);
1421
+ }
1422
+ else {
1423
+ console.warn(` ⚠️ ${skill.name} deployment failed`);
1424
+ }
1425
+ }
1426
+ }
1427
+ // Deploy all webhooks
1428
+ if (toDeployWebhooks.length > 0) {
1429
+ writeProgress(`🪝 Deploying ${toDeployWebhooks.length} webhook(s)...`);
1430
+ for (const webhook of toDeployWebhooks) {
1431
+ const deployed = await retryDeploy(async () => {
1432
+ const response = await fetch(`${BASE_URLS.API}/developer/webhooks/${agentId}/${webhook.webhookId}/${webhook.version}/publish`, {
1433
+ method: 'PUT',
1434
+ headers: {
1435
+ 'Authorization': `Bearer ${apiKey}`,
1436
+ 'Content-Type': 'application/json'
1437
+ }
1438
+ });
1439
+ if (!response.ok) {
1440
+ throw new Error(`HTTP ${response.status}`);
1441
+ }
1442
+ }, webhook.name, webhook.version, 2);
1443
+ if (deployed) {
1444
+ writeSuccess(` 🚀 ${webhook.name} v${webhook.version} deployed`);
1445
+ }
1446
+ else {
1447
+ console.warn(` ⚠️ ${webhook.name} deployment failed`);
1448
+ }
1449
+ }
1450
+ }
1451
+ // Deploy all jobs
1452
+ if (toDeployJobs.length > 0) {
1453
+ writeProgress(`⏰ Deploying ${toDeployJobs.length} job(s)...`);
1454
+ for (const job of toDeployJobs) {
1455
+ const deployed = await retryDeploy(async () => {
1456
+ const response = await fetch(`${BASE_URLS.API}/developer/jobs/${agentId}/${job.jobId}/${job.version}/publish`, {
1457
+ method: 'PUT',
1458
+ headers: {
1459
+ 'Authorization': `Bearer ${apiKey}`,
1460
+ 'Content-Type': 'application/json'
1461
+ }
1462
+ });
1463
+ if (!response.ok) {
1464
+ throw new Error(`HTTP ${response.status}`);
1465
+ }
1466
+ }, job.name, job.version, 2);
1467
+ if (deployed) {
1468
+ writeSuccess(` 🚀 ${job.name} v${job.version} deployed`);
1469
+ }
1470
+ else {
1471
+ console.warn(` ⚠️ ${job.name} deployment failed`);
1472
+ }
1473
+ }
1474
+ }
1475
+ // Deploy all preprocessors
1476
+ if (toDeployPreprocessors.length > 0) {
1477
+ writeProgress(`📥 Deploying ${toDeployPreprocessors.length} preprocessor(s)...`);
1478
+ const preprocessorService = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
1479
+ for (const processor of toDeployPreprocessors) {
1480
+ const deployed = await retryDeploy(() => preprocessorService.publishPreProcessorVersion(processor.preprocessorId, processor.version), processor.name, processor.version, 2);
1481
+ if (deployed) {
1482
+ writeSuccess(` 🚀 ${processor.name} v${processor.version} deployed`);
1483
+ }
1484
+ else {
1485
+ console.warn(` ⚠️ ${processor.name} deployment failed`);
1486
+ }
1487
+ }
1488
+ }
1489
+ // Deploy all postprocessors
1490
+ if (toDeployPostprocessors.length > 0) {
1491
+ writeProgress(`📤 Deploying ${toDeployPostprocessors.length} postprocessor(s)...`);
1492
+ const postprocessorService = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
1493
+ for (const processor of toDeployPostprocessors) {
1494
+ const deployed = await retryDeploy(() => postprocessorService.publishPostProcessorVersion(processor.postprocessorId, processor.version), processor.name, processor.version, 2);
1495
+ if (deployed) {
1496
+ writeSuccess(` 🚀 ${processor.name} v${processor.version} deployed`);
1497
+ }
1498
+ else {
1499
+ console.warn(` ⚠️ ${processor.name} deployment failed`);
1500
+ }
1501
+ }
1502
+ }
1503
+ }
1504
+ // Step 10: Print summary
1505
+ writeSuccess('\n✅ Push All Complete!\n');
1506
+ if (results.skills.length > 0) {
1507
+ console.log(`🛠️ Skills (${results.skills.length}):`);
1508
+ results.skills.forEach(s => console.log(` • ${s.name} v${s.version}`));
1509
+ }
1510
+ if (results.webhooks.length > 0) {
1511
+ console.log(`🪝 Webhooks (${results.webhooks.length}):`);
1512
+ results.webhooks.forEach(w => console.log(` • ${w.name} v${w.version}`));
1513
+ }
1514
+ if (results.jobs.length > 0) {
1515
+ console.log(`⏰ Jobs (${results.jobs.length}):`);
1516
+ results.jobs.forEach(j => console.log(` • ${j.name} v${j.version}`));
1517
+ }
1518
+ if (results.preprocessors.length > 0) {
1519
+ console.log(`📥 PreProcessors (${results.preprocessors.length}):`);
1520
+ results.preprocessors.forEach(p => console.log(` • ${p.name} v${p.version}`));
1521
+ }
1522
+ if (results.postprocessors.length > 0) {
1523
+ console.log(`📤 PostProcessors (${results.postprocessors.length}):`);
1524
+ results.postprocessors.forEach(p => console.log(` • ${p.name} v${p.version}`));
1525
+ }
1526
+ if (options.autoDeploy) {
1527
+ writeSuccess('\n🚀 All components deployed to production!');
1528
+ }
1529
+ console.log('');
1530
+ }
1531
+ /**
1532
+ * Bumps the patch version of a semantic version string
1533
+ * e.g., "1.2.3" -> "1.2.4"
1534
+ */
1535
+ function bumpPatchVersion(version) {
1536
+ const parts = version.split('.');
1537
+ if (parts.length !== 3) {
1538
+ // If not a valid semver, just return incremented version
1539
+ return version + '.1';
1540
+ }
1541
+ const [major, minor, patch] = parts;
1542
+ const newPatch = parseInt(patch, 10) + 1;
1543
+ return `${major}.${minor}.${newPatch}`;
1544
+ }
1545
+ /**
1546
+ * Retry deployment with exponential backoff
1547
+ * The server needs time to process pushed versions before they can be deployed
1548
+ */
1549
+ async function retryDeploy(deployFn, componentName, version, maxRetries = 3) {
1550
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1551
+ try {
1552
+ const delay = attempt * 2000; // 2s, 4s, 6s (longer delays)
1553
+ await new Promise(resolve => setTimeout(resolve, delay));
1554
+ await deployFn();
1555
+ return true;
1556
+ }
1557
+ catch (error) {
1558
+ if (attempt === maxRetries) {
1559
+ console.error(` [Retry ${attempt}/${maxRetries}] Deploy failed: ${error.message}`);
1560
+ return false;
1561
+ }
1562
+ // Continue to next retry silently
1563
+ }
1564
+ }
1565
+ return false;
1566
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lua-cli",
3
- "version": "3.0.0-alpha.4",
3
+ "version": "3.0.0-alpha.6",
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.3
39
+ version: 0.0.4
18
40
  skillId: 1faf9b3a-e352-4e63-a6c4-a3deca815361
19
41
  - name: user-data-skill
20
- version: 0.0.1
42
+ version: 0.0.12
21
43
  skillId: e0c382c1-f469-4880-962a-a756ea3c1411
22
44
  - name: product-skill
23
- version: 0.0.1
45
+ version: 0.0.12
24
46
  skillId: d4cdc7bc-6d42-4232-902d-2b9cf68bd74a
25
47
  - name: basket-skill
26
- version: 0.0.1
48
+ version: 0.0.11
27
49
  skillId: 5b06c5ff-7cf3-49c4-8641-142270c81db4
28
50
  - name: order-skill
29
- version: 0.0.1
51
+ version: 0.0.11
30
52
  skillId: d4045304-7c30-4750-9edd-340eb1357a39
31
53
  - name: custom-data-skill
32
- version: 0.0.1
54
+ version: 0.0.10
33
55
  skillId: 83fe411c-90a1-4bd3-9271-ac8e03d6a3be
34
56
  - name: payment-skill
35
- version: 0.0.1
57
+ version: 0.0.10
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.9
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.8
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.4",
23
+ "lua-cli": "^3.0.0-alpha.6",
24
24
  "openai": "^5.23.0",
25
25
  "uuid": "^13.0.0",
26
26
  "zod": "^3.24.1"