lua-cli 3.2.0 → 3.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 (121) hide show
  1. package/dist/api/logs.api.service.d.ts +1 -1
  2. package/dist/api/logs.api.service.js.map +1 -1
  3. package/dist/api/products.api.service.d.ts +17 -5
  4. package/dist/api/products.api.service.js +21 -9
  5. package/dist/api/products.api.service.js.map +1 -1
  6. package/dist/api/webhook.api.service.d.ts +4 -0
  7. package/dist/api/webhook.api.service.js.map +1 -1
  8. package/dist/api-exports.d.ts +19 -7
  9. package/dist/api-exports.js +20 -5
  10. package/dist/api-exports.js.map +1 -1
  11. package/dist/cli/command-definitions.js +323 -88
  12. package/dist/cli/command-definitions.js.map +1 -1
  13. package/dist/commands/apiKey.d.ts +5 -2
  14. package/dist/commands/apiKey.js +8 -2
  15. package/dist/commands/apiKey.js.map +1 -1
  16. package/dist/commands/channels.d.ts +4 -9
  17. package/dist/commands/channels.js +140 -84
  18. package/dist/commands/channels.js.map +1 -1
  19. package/dist/commands/chat.d.ts +4 -2
  20. package/dist/commands/chat.js +126 -32
  21. package/dist/commands/chat.js.map +1 -1
  22. package/dist/commands/chatClear.d.ts +3 -2
  23. package/dist/commands/chatClear.js +16 -15
  24. package/dist/commands/chatClear.js.map +1 -1
  25. package/dist/commands/compile.d.ts +5 -4
  26. package/dist/commands/compile.js +73 -9
  27. package/dist/commands/compile.js.map +1 -1
  28. package/dist/commands/deploy.d.ts +5 -24
  29. package/dist/commands/deploy.js +75 -48
  30. package/dist/commands/deploy.js.map +1 -1
  31. package/dist/commands/destroy.d.ts +5 -2
  32. package/dist/commands/destroy.js +14 -2
  33. package/dist/commands/destroy.js.map +1 -1
  34. package/dist/commands/env.d.ts +3 -1
  35. package/dist/commands/env.js +322 -122
  36. package/dist/commands/env.js.map +1 -1
  37. package/dist/commands/features.d.ts +5 -9
  38. package/dist/commands/features.js +249 -129
  39. package/dist/commands/features.js.map +1 -1
  40. package/dist/commands/init.d.ts +7 -1
  41. package/dist/commands/init.js +242 -59
  42. package/dist/commands/init.js.map +1 -1
  43. package/dist/commands/jobs.d.ts +5 -13
  44. package/dist/commands/jobs.js +523 -360
  45. package/dist/commands/jobs.js.map +1 -1
  46. package/dist/commands/logs.d.ts +5 -10
  47. package/dist/commands/logs.js +259 -103
  48. package/dist/commands/logs.js.map +1 -1
  49. package/dist/commands/marketplace.d.ts +23 -2
  50. package/dist/commands/marketplace.js +530 -7
  51. package/dist/commands/marketplace.js.map +1 -1
  52. package/dist/commands/mcp.d.ts +5 -11
  53. package/dist/commands/mcp.js +304 -294
  54. package/dist/commands/mcp.js.map +1 -1
  55. package/dist/commands/persona.d.ts +5 -9
  56. package/dist/commands/persona.js +349 -232
  57. package/dist/commands/persona.js.map +1 -1
  58. package/dist/commands/postprocessors.d.ts +6 -2
  59. package/dist/commands/postprocessors.js +387 -280
  60. package/dist/commands/postprocessors.js.map +1 -1
  61. package/dist/commands/preprocessors.d.ts +6 -2
  62. package/dist/commands/preprocessors.js +387 -280
  63. package/dist/commands/preprocessors.js.map +1 -1
  64. package/dist/commands/production.d.ts +5 -8
  65. package/dist/commands/production.js +317 -228
  66. package/dist/commands/production.js.map +1 -1
  67. package/dist/commands/push.js +385 -427
  68. package/dist/commands/push.js.map +1 -1
  69. package/dist/commands/resources.d.ts +5 -10
  70. package/dist/commands/resources.js +219 -154
  71. package/dist/commands/resources.js.map +1 -1
  72. package/dist/commands/skills.d.ts +5 -9
  73. package/dist/commands/skills.js +435 -275
  74. package/dist/commands/skills.js.map +1 -1
  75. package/dist/commands/sync.d.ts +10 -8
  76. package/dist/commands/sync.js +110 -19
  77. package/dist/commands/sync.js.map +1 -1
  78. package/dist/commands/test.d.ts +1 -11
  79. package/dist/commands/test.js +395 -438
  80. package/dist/commands/test.js.map +1 -1
  81. package/dist/commands/webhooks.d.ts +5 -11
  82. package/dist/commands/webhooks.js +431 -287
  83. package/dist/commands/webhooks.js.map +1 -1
  84. package/dist/interfaces/index.d.ts +1 -1
  85. package/dist/interfaces/mcp.d.ts +39 -19
  86. package/dist/interfaces/mcp.js +3 -0
  87. package/dist/interfaces/mcp.js.map +1 -1
  88. package/dist/interfaces/product.d.ts +26 -0
  89. package/dist/interfaces/skills.d.ts +5 -0
  90. package/dist/types/api-contracts.d.ts +8 -4
  91. package/dist/types/index.d.ts +1 -1
  92. package/dist/types/index.js.map +1 -1
  93. package/dist/types/skill.d.ts +146 -35
  94. package/dist/types/skill.js +31 -37
  95. package/dist/types/skill.js.map +1 -1
  96. package/dist/utils/bundling.d.ts +17 -0
  97. package/dist/utils/bundling.js +96 -0
  98. package/dist/utils/bundling.js.map +1 -1
  99. package/dist/utils/compile.d.ts +4 -0
  100. package/dist/utils/compile.js +5 -0
  101. package/dist/utils/compile.js.map +1 -1
  102. package/dist/utils/dev-helpers.d.ts +3 -2
  103. package/dist/utils/dev-helpers.js +3 -5
  104. package/dist/utils/dev-helpers.js.map +1 -1
  105. package/dist/utils/job-management.d.ts +4 -1
  106. package/dist/utils/job-management.js +15 -29
  107. package/dist/utils/job-management.js.map +1 -1
  108. package/dist/utils/mcp-server-management.d.ts +5 -2
  109. package/dist/utils/mcp-server-management.js +27 -43
  110. package/dist/utils/mcp-server-management.js.map +1 -1
  111. package/dist/utils/push-helpers.d.ts +1 -1
  112. package/dist/utils/push-helpers.js +5 -1
  113. package/dist/utils/push-helpers.js.map +1 -1
  114. package/dist/utils/skill-management.d.ts +7 -2
  115. package/dist/utils/skill-management.js +21 -30
  116. package/dist/utils/skill-management.js.map +1 -1
  117. package/dist/utils/webhook-management.d.ts +4 -1
  118. package/dist/utils/webhook-management.js +15 -29
  119. package/dist/utils/webhook-management.js.map +1 -1
  120. package/package.json +1 -1
  121. package/template/package.json +1 -1
@@ -10,7 +10,7 @@ import { checkApiKey, loadApiKey } from '../services/auth.js';
10
10
  import { readSkillConfig } from '../utils/files.js';
11
11
  import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
12
12
  import { safePrompt } from '../utils/prompt-handler.js';
13
- import { readDeployJson, validatePushConfig, validateDeployData, promptSkillSelection, promptVersionConfirmOrUpdate, getAvailableSkills, updateSkillVersionInYaml, getSkillDeployData, } from '../utils/push-helpers.js';
13
+ import { readDeployJson, validatePushConfig, validateDeployData, promptVersionConfirmOrUpdate, getAvailableSkills, updateSkillVersionInYaml, getSkillDeployData, } from '../utils/push-helpers.js';
14
14
  import { pushVersion } from '../utils/push-api.js';
15
15
  import { fetchVersions, publishVersion, } from '../utils/deploy-api.js';
16
16
  import { BASE_URLS } from '../config/constants.js';
@@ -18,6 +18,127 @@ import PreProcessorApi from '../api/preprocessor.api.service.js';
18
18
  import PostProcessorApi from '../api/postprocessor.api.service.js';
19
19
  import DeveloperApi from '../api/developer.api.service.js';
20
20
  import { loadPersonaFromCode } from '../utils/agent-code-utils.js';
21
+ // ============================================================================
22
+ // Core Push Helpers (shared by all push functions)
23
+ // ============================================================================
24
+ /**
25
+ * Authenticates the user and returns the API key
26
+ * Exits with error if authentication fails
27
+ */
28
+ async function authenticateOrFail() {
29
+ const apiKey = await loadApiKey();
30
+ if (!apiKey) {
31
+ console.log("❌ 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
+ return apiKey;
36
+ }
37
+ /**
38
+ * Selects an entity from a list, either by options.entityName or interactive prompt
39
+ * @param items - Array of items to select from
40
+ * @param options - Push options with entityName
41
+ * @param config - Configuration for selection behavior
42
+ */
43
+ async function selectEntityOrFail(items, options, config) {
44
+ const { entityType, nameFields = ['id', 'name'], formatChoice } = config;
45
+ if (items.length === 0) {
46
+ console.log(`❌ No ${entityType}s found in lua.skill.yaml.`);
47
+ process.exit(1);
48
+ }
49
+ // Non-interactive: find by name
50
+ if (options.entityName) {
51
+ const found = items.find((item) => nameFields.some(field => item[field] === options.entityName));
52
+ if (!found) {
53
+ console.log(`❌ ${entityType} "${options.entityName}" not found`);
54
+ process.exit(1);
55
+ }
56
+ writeInfo(`📦 Selected ${entityType}: ${found.name}`);
57
+ return found;
58
+ }
59
+ // Single item: use it automatically
60
+ if (items.length === 1) {
61
+ writeInfo(`📦 Pushing ${entityType}: ${items[0].name}`);
62
+ return items[0];
63
+ }
64
+ // Multiple items: prompt for selection
65
+ const answer = await safePrompt([
66
+ {
67
+ type: 'list',
68
+ name: 'selected',
69
+ message: `Select a ${entityType} to push:`,
70
+ choices: items.map((item) => ({
71
+ name: formatChoice ? formatChoice(item) : `${item.name} (v${item.version})`,
72
+ value: item
73
+ }))
74
+ }
75
+ ]);
76
+ if (!answer) {
77
+ console.log("Push cancelled.");
78
+ process.exit(0);
79
+ }
80
+ writeInfo(`📦 Selected ${entityType}: ${answer.selected.name}`);
81
+ return answer.selected;
82
+ }
83
+ /**
84
+ * Resolves version from options or interactive prompt
85
+ * Validates semantic versioning format
86
+ */
87
+ async function resolveVersionOrFail(currentVersion, options) {
88
+ if (options.version) {
89
+ if (!/^\d+\.\d+\.\d+/.test(options.version)) {
90
+ console.log(`❌ Invalid version format: "${options.version}". Use semantic versioning (e.g., 1.0.5)`);
91
+ process.exit(1);
92
+ }
93
+ writeInfo(`📝 Using version: ${options.version}`);
94
+ return options.version;
95
+ }
96
+ return await promptVersionConfirmOrUpdate(currentVersion);
97
+ }
98
+ /**
99
+ * Loads bundled entity data from dist folder
100
+ * @returns The bundled data for the entity, or exits if not found
101
+ */
102
+ function loadBundledEntityData(filename, entityName, entityType) {
103
+ const bundledPath = path.join(process.cwd(), 'dist', filename);
104
+ if (!fs.existsSync(bundledPath)) {
105
+ console.log(`❌ Bundled ${entityType.toLowerCase()} data not found.`);
106
+ console.log("💡 Please ensure your code is properly compiled.");
107
+ process.exit(1);
108
+ }
109
+ const bundled = JSON.parse(fs.readFileSync(bundledPath, 'utf8'));
110
+ const bundledData = bundled.find((item) => item.name === entityName) || {};
111
+ if (!bundledData || Object.keys(bundledData).length === 0) {
112
+ console.log(`\n❌ ${entityType} "${entityName}" not found in compiled code.`);
113
+ console.log("💡 This may have been removed or commented out in your code.");
114
+ console.log(`💡 Please uncomment the ${entityType.toLowerCase()} or remove it from lua.skill.yaml.`);
115
+ process.exit(1);
116
+ }
117
+ return bundledData;
118
+ }
119
+ /**
120
+ * Determines if we should deploy after push based on options or prompt
121
+ */
122
+ async function shouldDeployAfterPush(options) {
123
+ // Auto-deploy flag takes precedence
124
+ if (options.autoDeploy) {
125
+ return true;
126
+ }
127
+ // Force mode skips the prompt (no deploy)
128
+ if (options.force) {
129
+ return false;
130
+ }
131
+ // Interactive: ask user
132
+ const answer = await safePrompt([
133
+ {
134
+ type: 'confirm',
135
+ name: 'deployNow',
136
+ message: 'Would you like to deploy this version to production now?',
137
+ default: false
138
+ }
139
+ ]);
140
+ return answer?.deployNow || false;
141
+ }
21
142
  /**
22
143
  * Main push command - pushes a skill or persona version to the server.
23
144
  *
@@ -42,7 +163,9 @@ export async function pushCommand(type, cmdObj) {
42
163
  // Extract options from Commander command object
43
164
  const options = {
44
165
  force: cmdObj?.force || false,
45
- autoDeploy: cmdObj?.autoDeploy || false
166
+ autoDeploy: cmdObj?.autoDeploy || false,
167
+ entityName: cmdObj?.name || null,
168
+ version: cmdObj?.version || null
46
169
  };
47
170
  let selectedType;
48
171
  // Handle 'all' type with force flag
@@ -56,6 +179,14 @@ export async function pushCommand(type, cmdObj) {
56
179
  }
57
180
  return await pushAllCommand(options);
58
181
  }
182
+ // Validate that entityName without type is not allowed
183
+ if (options.entityName && !type) {
184
+ console.error('❌ Type must be specified when using the --name option.');
185
+ console.log('\nUsage:');
186
+ console.log(' lua push skill --name mySkill --version 1.0.5 Push specific skill');
187
+ console.log(' lua push webhook --name myWebhook --version 2.0.0 Push specific webhook');
188
+ process.exit(1);
189
+ }
59
190
  // Step 1: Check if type was provided as argument
60
191
  if (type) {
61
192
  // Validate the provided type
@@ -101,123 +232,86 @@ export async function pushCommand(type, cmdObj) {
101
232
  }
102
233
  // Step 3: Route to appropriate function
103
234
  if (selectedType === 'skill') {
104
- await pushSkillVersion();
235
+ await pushSkillVersion(options);
105
236
  }
106
237
  else if (selectedType === 'webhook') {
107
- await pushWebhookVersion();
238
+ await pushWebhookVersion(options);
108
239
  }
109
240
  else if (selectedType === 'job') {
110
- await pushJobVersion();
241
+ await pushJobVersion(options);
111
242
  }
112
243
  else if (selectedType === 'preprocessor') {
113
- await pushPreProcessorVersion();
244
+ await pushPreProcessorVersion(options);
114
245
  }
115
246
  else if (selectedType === 'postprocessor') {
116
- await pushPostProcessorVersion();
247
+ await pushPostProcessorVersion(options);
117
248
  }
118
249
  else if (selectedType === 'mcp') {
119
- await pushMCPServerVersion();
250
+ await pushMCPServerVersion(options);
120
251
  }
121
252
  else {
122
- await pushPersonaVersion();
253
+ await pushPersonaVersion(options);
123
254
  }
124
255
  }, "push");
125
256
  }
126
257
  /**
127
258
  * Push skill version to the server.
128
- *
129
- * This function performs the following steps:
130
- * 1. Validates configuration has required fields
131
- * 2. Prompts user to select a skill (if multiple skills exist)
132
- * 3. Prompts to confirm or update version
133
- * 4. Authenticates the user
134
- * 5. Compiles the skill (always, to ensure deploy.json is current)
135
- * 6. Validates deploy.json matches configuration for selected skill
136
- * 7. Extracts the specific skill's deploy data
137
- * 8. Pushes version to server
138
- *
139
- * @returns Promise that resolves when push completes
140
259
  */
141
- async function pushSkillVersion() {
260
+ async function pushSkillVersion(options = {}) {
142
261
  // Step 1: Validate configuration
143
262
  const yamlConfig = readSkillConfig();
144
263
  validatePushConfig(yamlConfig);
145
264
  const config = yamlConfig;
146
- // Step 2: Get available skills and prompt for selection
265
+ // Step 2: Get available skills and select
147
266
  const availableSkills = getAvailableSkills(config);
148
267
  if (availableSkills.length === 0) {
149
- console.error("❌ No skills found in configuration. Please compile your skill first using 'lua compile'.");
268
+ console.log("❌ No skills found in configuration. Please compile your skill first using 'lua compile'.");
150
269
  process.exit(1);
151
270
  }
152
- let selectedSkill;
153
- if (availableSkills.length === 1) {
154
- // Only one skill, use it automatically
155
- selectedSkill = availableSkills[0];
156
- writeInfo(`📦 Pushing skill: ${selectedSkill.name}`);
157
- }
158
- else {
159
- // Multiple skills, prompt for selection
160
- selectedSkill = await promptSkillSelection(availableSkills);
161
- writeInfo(`📦 Selected skill: ${selectedSkill.name}`);
162
- }
163
- // Step 3: Confirm or update version
164
- const confirmedVersion = await promptVersionConfirmOrUpdate(selectedSkill.version);
165
- let versionUpdated = false;
271
+ const selectedSkill = await selectEntityOrFail(availableSkills, options, {
272
+ entityType: 'skill',
273
+ nameFields: ['skillId', 'name']
274
+ });
275
+ // Step 3: Handle version
276
+ const confirmedVersion = await resolveVersionOrFail(selectedSkill.version, options);
166
277
  if (confirmedVersion !== selectedSkill.version) {
167
278
  writeInfo(`📝 Updating version from ${selectedSkill.version} to ${confirmedVersion}`);
168
279
  updateSkillVersionInYaml(selectedSkill.name, confirmedVersion);
169
280
  selectedSkill.version = confirmedVersion;
170
- versionUpdated = true;
171
281
  }
172
282
  // Step 4: Authenticate
173
- const apiKey = await loadApiKey();
174
- if (!apiKey) {
175
- console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
176
- process.exit(1);
177
- }
178
- const userData = await checkApiKey(apiKey);
283
+ const apiKey = await authenticateOrFail();
179
284
  writeProgress("✅ Authenticated");
180
- // Step 5: Compile the skill (always compile to ensure up-to-date, or if version was updated)
285
+ // Step 5: Compile the skill
181
286
  writeProgress("🔄 Compiling skill...");
182
287
  await compileCommand();
183
- // Step 6: Validate deploy data for the selected skill
288
+ // Step 6: Validate and extract deploy data
184
289
  const deployData = readDeployJson();
185
290
  validateDeployData(deployData, selectedSkill);
186
- // Step 7: Extract the specific skill's deploy data
187
291
  const skillDeployData = getSkillDeployData(deployData, selectedSkill.name);
188
- // Step 8: Push version to server
189
- const agentId = config.agent.agentId;
190
- const skillId = selectedSkill.skillId;
292
+ // Step 7: Push version to server
191
293
  writeProgress("🔄 Pushing version to server...");
192
- const result = await pushVersion(apiKey, agentId, skillId, skillDeployData);
294
+ const result = await pushVersion(apiKey, config.agent.agentId, selectedSkill.skillId, skillDeployData);
193
295
  if (result.success && result.data) {
194
296
  const pushedVersion = result.data.version;
195
297
  writeSuccess(`✅ Version ${pushedVersion} of "${selectedSkill.name}" pushed successfully`);
196
- // Update YAML with the version returned from server (in case it's different)
298
+ // Update YAML with the version returned from server
197
299
  if (pushedVersion !== selectedSkill.version) {
198
300
  writeInfo(`📝 Updating YAML with server version: ${pushedVersion}`);
199
301
  updateSkillVersionInYaml(selectedSkill.name, pushedVersion);
200
302
  selectedSkill.version = pushedVersion;
201
303
  }
202
- // Ask if user wants to deploy now
203
- const deployAnswer = await safePrompt([
204
- {
205
- type: 'confirm',
206
- name: 'deployNow',
207
- message: 'Would you like to deploy this version to production now?',
208
- default: false
209
- }
210
- ]);
211
- if (deployAnswer && deployAnswer.deployNow) {
304
+ // Step 8: Deploy if requested
305
+ if (await shouldDeployAfterPush(options)) {
212
306
  await deployVersionAfterPush(apiKey, config.agent.agentId, selectedSkill, pushedVersion);
213
307
  }
214
308
  }
215
309
  else if (result.error) {
216
- console.error(`❌ ${result.error.message}`);
310
+ console.log(`❌ ${result.error.message}`);
217
311
  process.exit(1);
218
312
  }
219
313
  else {
220
- console.error("❌ Failed to push version. Please try again.");
314
+ console.log("❌ Failed to push version. Please try again.");
221
315
  process.exit(1);
222
316
  }
223
317
  }
@@ -233,17 +327,17 @@ async function pushSkillVersion() {
233
327
  *
234
328
  * @returns Promise that resolves when push completes
235
329
  */
236
- async function pushPersonaVersion() {
330
+ async function pushPersonaVersion(options = {}) {
237
331
  // Step 1: Validate configuration
238
332
  const config = readSkillConfig();
239
333
  if (!config || !config.agent?.agentId) {
240
- console.error("❌ No agent configuration found. Please run 'lua init' first.");
334
+ console.log("❌ No agent configuration found. Please run 'lua init' first.");
241
335
  process.exit(1);
242
336
  }
243
337
  // Step 2: Load current persona from code
244
338
  const currentPersona = loadPersonaFromCode();
245
339
  if (!currentPersona || !currentPersona.trim()) {
246
- console.error("❌ No persona found in configuration. Please edit your persona first using 'lua persona'.");
340
+ console.log("❌ No persona found in configuration. Please edit your persona first using 'lua persona'.");
247
341
  process.exit(1);
248
342
  }
249
343
  writeInfo(`📦 Pushing persona for agent: ${config.agent.agentId}`);
@@ -254,26 +348,23 @@ async function pushPersonaVersion() {
254
348
  console.log("\nPersona preview:");
255
349
  console.log(preview);
256
350
  console.log();
257
- // Step 3: Confirm push
258
- const confirmAnswer = await safePrompt([
259
- {
260
- type: 'confirm',
261
- name: 'confirm',
262
- message: 'Create new persona version?',
263
- default: true
351
+ // Step 3: Confirm push (skip if --force provided)
352
+ if (!options.force) {
353
+ const confirmAnswer = await safePrompt([
354
+ {
355
+ type: 'confirm',
356
+ name: 'confirm',
357
+ message: 'Create new persona version?',
358
+ default: true
359
+ }
360
+ ]);
361
+ if (!confirmAnswer || !confirmAnswer.confirm) {
362
+ console.log("\n❌ Push cancelled.\n");
363
+ return;
264
364
  }
265
- ]);
266
- if (!confirmAnswer || !confirmAnswer.confirm) {
267
- console.log("\n❌ Push cancelled.\n");
268
- return;
269
365
  }
270
366
  // Step 4: Authenticate
271
- const apiKey = await loadApiKey();
272
- if (!apiKey) {
273
- console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
274
- process.exit(1);
275
- }
276
- await checkApiKey(apiKey);
367
+ const apiKey = await authenticateOrFail();
277
368
  writeProgress("✅ Authenticated");
278
369
  // Step 5: Push persona version to server
279
370
  writeProgress("🔄 Creating persona version...");
@@ -293,16 +384,8 @@ async function pushPersonaVersion() {
293
384
  const data = await response.json();
294
385
  const versionNum = data.version || data.data?.version || 'N/A';
295
386
  writeSuccess(`✅ Persona version ${versionNum} created successfully`);
296
- // Step 6: Ask if user wants to deploy now
297
- const deployAnswer = await safePrompt([
298
- {
299
- type: 'confirm',
300
- name: 'deployNow',
301
- message: 'Would you like to deploy this persona version to production now?',
302
- default: false
303
- }
304
- ]);
305
- if (deployAnswer && deployAnswer.deployNow) {
387
+ // Step 6: Deploy if requested
388
+ if (await shouldDeployAfterPush(options)) {
306
389
  await deployPersonaVersionAfterPush(apiKey, config.agent.agentId, versionNum);
307
390
  }
308
391
  else {
@@ -310,7 +393,7 @@ async function pushPersonaVersion() {
310
393
  }
311
394
  }
312
395
  catch (error) {
313
- console.error('❌ Error creating persona version:', error);
396
+ console.log('❌ Error creating persona version:', error);
314
397
  process.exit(1);
315
398
  }
316
399
  }
@@ -367,90 +450,53 @@ async function deployPersonaVersionAfterPush(apiKey, agentId, versionNum) {
367
450
  * 5. Push to server
368
451
  * 6. Optionally deploy immediately
369
452
  */
370
- async function pushWebhookVersion() {
453
+ async function pushWebhookVersion(options = {}) {
371
454
  try {
372
- // Step 1: Run compilation
455
+ // Step 1: Compile
373
456
  writeProgress("📦 Compiling project...");
374
457
  await compileCommand();
375
458
  writeSuccess("✅ Compilation complete");
376
459
  // Step 2: Authenticate
377
- const apiKey = await loadApiKey();
378
- if (!apiKey) {
379
- console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
380
- process.exit(1);
381
- }
382
- await checkApiKey(apiKey);
460
+ const apiKey = await authenticateOrFail();
383
461
  writeSuccess("✅ Authentication verified");
384
462
  // Step 3: Read configuration
385
463
  const config = readSkillConfig();
386
464
  if (!config?.agent?.agentId) {
387
- console.error("❌ No agent ID found in lua.skill.yaml. Please run 'lua init' first.");
465
+ console.log("❌ No agent ID found in lua.skill.yaml. Please run 'lua init' first.");
388
466
  process.exit(1);
389
467
  }
390
468
  const webhooks = config.webhooks || [];
391
469
  if (webhooks.length === 0) {
392
- console.error("❌ No webhooks found in lua.skill.yaml.");
470
+ console.log("❌ No webhooks found in lua.skill.yaml.");
393
471
  console.log("💡 Make sure you have created a webhook using LuaWebhook in your code.");
394
472
  process.exit(1);
395
473
  }
396
- // Step 4: Select webhook to push
397
- const webhookAnswer = await safePrompt([
398
- {
399
- type: 'list',
400
- name: 'selectedWebhook',
401
- message: 'Select a webhook to push:',
402
- choices: webhooks.map((webhook) => ({
403
- name: `${webhook.name} (v${webhook.version})`,
404
- value: webhook
405
- }))
406
- }
407
- ]);
408
- if (!webhookAnswer) {
409
- console.log("Push cancelled.");
410
- return;
411
- }
412
- const selectedWebhook = webhookAnswer.selectedWebhook;
413
- // Step 4.5: Load bundled webhook data
414
- const bundledWebhooksPath = path.join(process.cwd(), 'dist', 'webhooks.json');
415
- let bundledWebhookData = {};
416
- if (fs.existsSync(bundledWebhooksPath)) {
417
- const bundledWebhooks = JSON.parse(fs.readFileSync(bundledWebhooksPath, 'utf8'));
418
- bundledWebhookData = bundledWebhooks.find((w) => w.name === selectedWebhook.name) || {};
419
- // Validate that the webhook exists in compiled code
420
- if (!bundledWebhookData || Object.keys(bundledWebhookData).length === 0) {
421
- console.error(`\n❌ Webhook "${selectedWebhook.name}" not found in compiled code.`);
422
- console.log("💡 This webhook may have been removed or commented out in your code.");
423
- console.log("💡 Please uncomment the webhook or remove it from lua.skill.yaml.");
424
- process.exit(1);
425
- }
426
- }
427
- else {
428
- console.error('❌ Bundled webhook data not found.');
429
- console.log("💡 Please ensure your webhook code is properly compiled.");
430
- process.exit(1);
431
- }
432
- // Step 5: Confirm or update version (same as skills)
433
- const confirmedVersion = await promptVersionConfirmOrUpdate(selectedWebhook.version);
434
- let versionToPush = confirmedVersion;
474
+ // Step 4: Select webhook
475
+ const selectedWebhook = await selectEntityOrFail(webhooks, options, {
476
+ entityType: 'webhook',
477
+ nameFields: ['id', 'webhookId', 'name']
478
+ });
479
+ // Step 5: Load and validate bundled data
480
+ const bundledWebhookData = loadBundledEntityData('webhooks.json', selectedWebhook.name, 'Webhook');
481
+ // Step 6: Handle version
482
+ const confirmedVersion = await resolveVersionOrFail(selectedWebhook.version, options);
435
483
  if (confirmedVersion !== selectedWebhook.version) {
436
484
  writeInfo(`📝 Updating version from ${selectedWebhook.version} to ${confirmedVersion}`);
437
485
  updateWebhookVersionInYaml(selectedWebhook.name, confirmedVersion);
438
- versionToPush = confirmedVersion;
439
486
  }
440
- // Step 6: Prepare webhook data for push (include bundled data)
487
+ // Step 7: Prepare and push webhook data
441
488
  const webhookData = {
442
489
  name: selectedWebhook.name,
443
- version: versionToPush,
490
+ version: confirmedVersion,
444
491
  description: bundledWebhookData.description || selectedWebhook.description || `Webhook: ${selectedWebhook.name}`,
445
492
  webhookId: selectedWebhook.webhookId,
446
493
  querySchema: bundledWebhookData.querySchema,
447
494
  headerSchema: bundledWebhookData.headerSchema,
448
495
  bodySchema: bundledWebhookData.bodySchema,
449
- code: bundledWebhookData.code, // Bundled and compressed code for execution
450
- executeFunction: bundledWebhookData.executeFunction // Raw function for display/editing
496
+ code: bundledWebhookData.code,
497
+ executeFunction: bundledWebhookData.executeFunction
451
498
  };
452
- // Step 7: Push to server
453
- writeProgress(`\n🚀 Pushing ${selectedWebhook.name} v${versionToPush} to server...`);
499
+ writeProgress(`\n🚀 Pushing ${selectedWebhook.name} v${confirmedVersion} to server...`);
454
500
  const response = await fetch(`${BASE_URLS.API}/developer/webhooks/${config.agent.agentId}/${selectedWebhook.webhookId}/version`, {
455
501
  method: 'POST',
456
502
  headers: {
@@ -461,31 +507,23 @@ async function pushWebhookVersion() {
461
507
  });
462
508
  if (!response.ok) {
463
509
  const errorText = await response.text();
464
- console.error(`\n❌ Push Error: ${response.status} - ${errorText}\n`);
510
+ console.log(`\n❌ Push Error: ${response.status} - ${errorText}\n`);
465
511
  throw new Error(`HTTP error! status: ${response.status}`);
466
512
  }
467
- const result = await response.json();
468
- writeSuccess(`\n✅ Successfully pushed ${selectedWebhook.name} v${versionToPush}\n`);
513
+ await response.json();
514
+ writeSuccess(`\n✅ Successfully pushed ${selectedWebhook.name} v${confirmedVersion}\n`);
469
515
  writeInfo(`📦 Webhook URL (id): ${BASE_URLS.WEBHOOK}/${config.agent.agentId}/${selectedWebhook.webhookId}`);
470
516
  writeInfo(`🔗 Webhook URL (name): ${BASE_URLS.WEBHOOK}/${config.agent.agentId}/${selectedWebhook.name}`);
471
- // Step 8: Ask if user wants to deploy now
472
- const deployAnswer = await safePrompt([
473
- {
474
- type: 'confirm',
475
- name: 'deployNow',
476
- message: 'Would you like to deploy this webhook version to production now?',
477
- default: false
478
- }
479
- ]);
480
- if (deployAnswer && deployAnswer.deployNow) {
481
- await deployWebhookVersionAfterPush(apiKey, config.agent.agentId, selectedWebhook, versionToPush);
517
+ // Step 8: Deploy if requested
518
+ if (await shouldDeployAfterPush(options)) {
519
+ await deployWebhookVersionAfterPush(apiKey, config.agent.agentId, selectedWebhook, confirmedVersion);
482
520
  }
483
521
  else {
484
522
  writeInfo("💡 You can deploy this version later using: lua webhooks production");
485
523
  }
486
524
  }
487
525
  catch (error) {
488
- console.error('❌ Error pushing webhook version:', error);
526
+ console.log('❌ Error pushing webhook version:', error);
489
527
  process.exit(1);
490
528
  }
491
529
  }
@@ -574,82 +612,53 @@ function updateJobVersionInYaml(jobName, newVersion) {
574
612
  /**
575
613
  * Push job version to the server (simplified version)
576
614
  */
577
- async function pushJobVersion() {
615
+ async function pushJobVersion(options = {}) {
578
616
  try {
617
+ // Step 1: Compile
579
618
  writeProgress("📦 Compiling project...");
580
619
  await compileCommand();
581
620
  writeSuccess("✅ Compilation complete");
582
- const apiKey = await loadApiKey();
583
- if (!apiKey) {
584
- console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
585
- process.exit(1);
586
- }
587
- await checkApiKey(apiKey);
621
+ // Step 2: Authenticate
622
+ const apiKey = await authenticateOrFail();
623
+ // Step 3: Read configuration
588
624
  const config = readSkillConfig();
589
625
  if (!config?.agent?.agentId) {
590
- console.error("❌ No agent ID found in lua.skill.yaml.");
626
+ console.log("❌ No agent ID found in lua.skill.yaml.");
591
627
  process.exit(1);
592
628
  }
593
629
  const jobs = config.jobs || [];
594
630
  if (jobs.length === 0) {
595
- console.error("❌ No jobs found in lua.skill.yaml.");
631
+ console.log("❌ No jobs found in lua.skill.yaml.");
596
632
  console.log("💡 Make sure you have created a job using LuaJob in your code.");
597
633
  process.exit(1);
598
634
  }
599
- const jobAnswer = await safePrompt([
600
- {
601
- type: 'list',
602
- name: 'selectedJob',
603
- message: 'Select a job to push:',
604
- choices: jobs.map((job) => ({
605
- name: `${job.name} (v${job.version})`,
606
- value: job
607
- }))
608
- }
609
- ]);
610
- if (!jobAnswer)
611
- return;
612
- const selectedJob = jobAnswer.selectedJob;
613
- // Load bundled job data
614
- const bundledJobsPath = path.join(process.cwd(), 'dist', 'jobs.json');
615
- let bundledJobData = {};
616
- if (fs.existsSync(bundledJobsPath)) {
617
- const bundledJobs = JSON.parse(fs.readFileSync(bundledJobsPath, 'utf8'));
618
- bundledJobData = bundledJobs.find((j) => j.name === selectedJob.name) || {};
619
- // Validate that the job exists in compiled code
620
- if (!bundledJobData || Object.keys(bundledJobData).length === 0) {
621
- console.error(`\n❌ Job "${selectedJob.name}" not found in compiled code.`);
622
- console.log("💡 This job may have been removed or commented out in your code.");
623
- console.log("💡 Please uncomment the job or remove it from lua.skill.yaml.");
624
- process.exit(1);
625
- }
626
- }
627
- else {
628
- console.error('❌ Bundled job data not found.');
629
- console.log("💡 Please ensure your job code is properly compiled.");
630
- process.exit(1);
631
- }
632
- // Confirm or update version (same as skills and webhooks)
633
- const confirmedVersion = await promptVersionConfirmOrUpdate(selectedJob.version);
634
- let versionToPush = confirmedVersion;
635
+ // Step 4: Select job
636
+ const selectedJob = await selectEntityOrFail(jobs, options, {
637
+ entityType: 'job',
638
+ nameFields: ['id', 'jobId', 'name']
639
+ });
640
+ // Step 5: Load bundled data
641
+ const bundledJobData = loadBundledEntityData('jobs.json', selectedJob.name, 'Job');
642
+ // Step 6: Handle version
643
+ const confirmedVersion = await resolveVersionOrFail(selectedJob.version, options);
635
644
  if (confirmedVersion !== selectedJob.version) {
636
645
  writeInfo(`📝 Updating version from ${selectedJob.version} to ${confirmedVersion}`);
637
646
  updateJobVersionInYaml(selectedJob.name, confirmedVersion);
638
- versionToPush = confirmedVersion;
639
647
  }
648
+ // Step 7: Prepare and push
640
649
  const jobData = {
641
650
  name: selectedJob.name,
642
- version: versionToPush,
651
+ version: confirmedVersion,
643
652
  description: bundledJobData.description || selectedJob.description || `Job: ${selectedJob.name}`,
644
653
  jobId: selectedJob.jobId,
645
654
  schedule: bundledJobData.schedule || selectedJob.schedule,
646
655
  timeout: bundledJobData.timeout,
647
656
  retry: bundledJobData.retry,
648
- code: bundledJobData.code, // Bundled and compressed code for execution
649
- executeFunction: bundledJobData.executeFunction, // Raw function for display/editing
650
- metadata: bundledJobData.metadata || selectedJob.metadata // Optional metadata
657
+ code: bundledJobData.code,
658
+ executeFunction: bundledJobData.executeFunction,
659
+ metadata: bundledJobData.metadata || selectedJob.metadata
651
660
  };
652
- writeProgress(`\n🚀 Pushing ${selectedJob.name} v${selectedJob.version} to server...`);
661
+ writeProgress(`\n🚀 Pushing ${selectedJob.name} v${confirmedVersion} to server...`);
653
662
  const response = await fetch(`${BASE_URLS.API}/developer/jobs/${config.agent.agentId}/${selectedJob.jobId}/version`, {
654
663
  method: 'POST',
655
664
  headers: {
@@ -660,28 +669,20 @@ async function pushJobVersion() {
660
669
  });
661
670
  if (!response.ok) {
662
671
  const errorText = await response.text();
663
- console.error(`\n❌ Push Error: ${response.status} - ${errorText}\n`);
672
+ console.log(`\n❌ Push Error: ${response.status} - ${errorText}\n`);
664
673
  throw new Error(`HTTP error! status: ${response.status}`);
665
674
  }
666
- writeSuccess(`\n✅ Successfully pushed ${selectedJob.name} v${versionToPush}\n`);
667
- // Ask if user wants to deploy now
668
- const deployAnswer = await safePrompt([
669
- {
670
- type: 'confirm',
671
- name: 'deployNow',
672
- message: 'Would you like to deploy this job version to production now?',
673
- default: false
674
- }
675
- ]);
676
- if (deployAnswer && deployAnswer.deployNow) {
677
- await deployJobVersionAfterPush(apiKey, config.agent.agentId, selectedJob, versionToPush);
675
+ writeSuccess(`\n✅ Successfully pushed ${selectedJob.name} v${confirmedVersion}\n`);
676
+ // Step 8: Deploy if requested
677
+ if (await shouldDeployAfterPush(options)) {
678
+ await deployJobVersionAfterPush(apiKey, config.agent.agentId, selectedJob, confirmedVersion);
678
679
  }
679
680
  else {
680
681
  writeInfo("💡 You can deploy this version later using: lua jobs production");
681
682
  }
682
683
  }
683
684
  catch (error) {
684
- console.error('❌ Error pushing job version:', error);
685
+ console.log('❌ Error pushing job version:', error);
685
686
  process.exit(1);
686
687
  }
687
688
  }
@@ -730,96 +731,71 @@ async function deployJobVersionAfterPush(apiKey, agentId, selectedJob, pushedVer
730
731
  /**
731
732
  * Push preprocessor version to the server.
732
733
  */
733
- async function pushPreProcessorVersion() {
734
+ async function pushPreProcessorVersion(options = {}) {
734
735
  try {
736
+ // Step 1: Compile
735
737
  writeProgress("📦 Compiling project...");
736
738
  await compileCommand();
737
739
  writeSuccess("✅ Compilation complete");
738
- const apiKey = await loadApiKey();
739
- if (!apiKey) {
740
- console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
741
- process.exit(1);
742
- }
743
- await checkApiKey(apiKey);
740
+ // Step 2: Authenticate
741
+ const apiKey = await authenticateOrFail();
742
+ // Step 3: Read configuration
744
743
  const config = readSkillConfig();
745
744
  if (!config?.agent?.agentId) {
746
- console.error("❌ No agent ID found in lua.skill.yaml.");
745
+ console.log("❌ No agent ID found in lua.skill.yaml.");
747
746
  process.exit(1);
748
747
  }
749
748
  const preprocessors = config.preprocessors || [];
750
749
  if (preprocessors.length === 0) {
751
- console.error("❌ No preprocessors found in lua.skill.yaml.");
750
+ console.log("❌ No preprocessors found in lua.skill.yaml.");
752
751
  process.exit(1);
753
752
  }
754
- // Load bundled preprocessor data
755
- const preprocessorsPath = path.join(process.cwd(), 'dist', 'preprocessors.json');
756
- let bundledData = {};
757
- if (fs.existsSync(preprocessorsPath)) {
758
- const bundled = JSON.parse(fs.readFileSync(preprocessorsPath, 'utf8'));
759
- // Select preprocessor
760
- const answer = await safePrompt([
761
- {
762
- type: 'list',
763
- name: 'selected',
764
- message: 'Select a preprocessor to push:',
765
- choices: preprocessors.map((p) => ({
766
- name: `${p.name} (v${p.version})`,
767
- value: p
768
- }))
769
- }
770
- ]);
771
- if (!answer)
772
- return;
773
- const selected = answer.selected;
774
- bundledData = bundled.find((p) => p.name === selected.name) || {};
775
- if (!bundledData || !bundledData.code) {
776
- console.error(`❌ PreProcessor "${selected.name}" not found in compiled code.`);
777
- console.log("💡 Please uncomment the preprocessor or remove it from lua.skill.yaml.");
778
- process.exit(1);
779
- }
780
- // Version confirmation
781
- const confirmedVersion = await promptVersionConfirmOrUpdate(selected.version);
782
- if (confirmedVersion !== selected.version) {
783
- writeInfo(`📝 Updating version from ${selected.version} to ${confirmedVersion}`);
784
- updateProcessorVersionInYaml('preprocessors', selected.name, confirmedVersion);
785
- }
786
- const versionData = {
787
- name: selected.name,
788
- version: confirmedVersion,
789
- description: bundledData.description || selected.description,
790
- preprocessorId: selected.preprocessorId,
791
- code: bundledData.code,
792
- executeFunction: bundledData.executeFunction,
793
- async: Boolean(bundledData.async ?? false) // Ensure boolean type
794
- };
795
- writeProgress(`\n🚀 Pushing ${selected.name} v${confirmedVersion}...`);
796
- const api = new PreProcessorApi(BASE_URLS.API, apiKey, config.agent.agentId);
797
- const result = await api.pushPreProcessor(selected.preprocessorId, versionData);
798
- if (result.success) {
799
- writeSuccess(`\n✅ PreProcessor "${selected.name}" v${confirmedVersion} pushed successfully\n`);
800
- // Ask if user wants to deploy now
801
- const deployAnswer = await safePrompt([
802
- {
803
- type: 'confirm',
804
- name: 'deployNow',
805
- message: 'Would you like to deploy this preprocessor version to production now?',
806
- default: false
807
- }
808
- ]);
809
- if (deployAnswer && deployAnswer.deployNow) {
810
- await deployPreProcessorVersionAfterPush(apiKey, config.agent.agentId, selected, confirmedVersion);
811
- }
812
- else {
813
- writeInfo("💡 You can deploy this version later using: lua preprocessors production");
814
- }
753
+ // Step 4: Select preprocessor
754
+ const selected = await selectEntityOrFail(preprocessors, options, {
755
+ entityType: 'preprocessor',
756
+ nameFields: ['id', 'preprocessorId', 'name']
757
+ });
758
+ // Step 5: Load bundled data
759
+ const bundledData = loadBundledEntityData('preprocessors.json', selected.name, 'PreProcessor');
760
+ if (!bundledData.code) {
761
+ console.log(`❌ PreProcessor "${selected.name}" has no code in compiled output.`);
762
+ process.exit(1);
763
+ }
764
+ // Step 6: Handle version
765
+ const confirmedVersion = await resolveVersionOrFail(selected.version, options);
766
+ if (confirmedVersion !== selected.version) {
767
+ writeInfo(`📝 Updating version from ${selected.version} to ${confirmedVersion}`);
768
+ updateProcessorVersionInYaml('preprocessors', selected.name, confirmedVersion);
769
+ }
770
+ // Step 7: Prepare and push
771
+ const versionData = {
772
+ name: selected.name,
773
+ version: confirmedVersion,
774
+ description: bundledData.description || selected.description,
775
+ preprocessorId: selected.preprocessorId,
776
+ code: bundledData.code,
777
+ executeFunction: bundledData.executeFunction,
778
+ async: Boolean(bundledData.async ?? false)
779
+ };
780
+ writeProgress(`\n🚀 Pushing ${selected.name} v${confirmedVersion}...`);
781
+ const api = new PreProcessorApi(BASE_URLS.API, apiKey, config.agent.agentId);
782
+ const result = await api.pushPreProcessor(selected.preprocessorId, versionData);
783
+ if (result.success) {
784
+ writeSuccess(`\n✅ PreProcessor "${selected.name}" v${confirmedVersion} pushed successfully\n`);
785
+ // Step 8: Deploy if requested
786
+ if (await shouldDeployAfterPush(options)) {
787
+ await deployPreProcessorVersionAfterPush(apiKey, config.agent.agentId, selected, confirmedVersion);
815
788
  }
816
789
  else {
817
- console.error(`❌ Failed to push: ${result.error?.message}`);
790
+ writeInfo("💡 You can deploy this version later using: lua preprocessors production");
818
791
  }
819
792
  }
793
+ else {
794
+ console.log(`❌ Failed to push: ${result.error?.message}`);
795
+ }
820
796
  }
821
797
  catch (error) {
822
- console.error('❌ Error pushing preprocessor:', error);
798
+ console.log('❌ Error pushing preprocessor:', error);
823
799
  process.exit(1);
824
800
  }
825
801
  }
@@ -861,95 +837,70 @@ async function deployPreProcessorVersionAfterPush(apiKey, agentId, selected, pus
861
837
  /**
862
838
  * Push postprocessor version to the server.
863
839
  */
864
- async function pushPostProcessorVersion() {
840
+ async function pushPostProcessorVersion(options = {}) {
865
841
  try {
842
+ // Step 1: Compile
866
843
  writeProgress("📦 Compiling project...");
867
844
  await compileCommand();
868
845
  writeSuccess("✅ Compilation complete");
869
- const apiKey = await loadApiKey();
870
- if (!apiKey) {
871
- console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
872
- process.exit(1);
873
- }
874
- await checkApiKey(apiKey);
846
+ // Step 2: Authenticate
847
+ const apiKey = await authenticateOrFail();
848
+ // Step 3: Read configuration
875
849
  const config = readSkillConfig();
876
850
  if (!config?.agent?.agentId) {
877
- console.error("❌ No agent ID found in lua.skill.yaml.");
851
+ console.log("❌ No agent ID found in lua.skill.yaml.");
878
852
  process.exit(1);
879
853
  }
880
854
  const postprocessors = config.postprocessors || [];
881
855
  if (postprocessors.length === 0) {
882
- console.error("❌ No postprocessors found in lua.skill.yaml.");
856
+ console.log("❌ No postprocessors found in lua.skill.yaml.");
883
857
  process.exit(1);
884
858
  }
885
- // Load bundled postprocessor data
886
- const postprocessorsPath = path.join(process.cwd(), 'dist', 'postprocessors.json');
887
- let bundledData = {};
888
- if (fs.existsSync(postprocessorsPath)) {
889
- const bundled = JSON.parse(fs.readFileSync(postprocessorsPath, 'utf8'));
890
- // Select postprocessor
891
- const answer = await safePrompt([
892
- {
893
- type: 'list',
894
- name: 'selected',
895
- message: 'Select a postprocessor to push:',
896
- choices: postprocessors.map((p) => ({
897
- name: `${p.name} (v${p.version})`,
898
- value: p
899
- }))
900
- }
901
- ]);
902
- if (!answer)
903
- return;
904
- const selected = answer.selected;
905
- bundledData = bundled.find((p) => p.name === selected.name) || {};
906
- if (!bundledData || !bundledData.code) {
907
- console.error(`❌ PostProcessor "${selected.name}" not found in compiled code.`);
908
- console.log("💡 Please uncomment the postprocessor or remove it from lua.skill.yaml.");
909
- process.exit(1);
910
- }
911
- // Version confirmation
912
- const confirmedVersion = await promptVersionConfirmOrUpdate(selected.version);
913
- if (confirmedVersion !== selected.version) {
914
- writeInfo(`📝 Updating version from ${selected.version} to ${confirmedVersion}`);
915
- updateProcessorVersionInYaml('postprocessors', selected.name, confirmedVersion);
916
- }
917
- const versionData = {
918
- name: selected.name,
919
- version: confirmedVersion,
920
- description: bundledData.description || selected.description,
921
- postprocessorId: selected.postprocessorId,
922
- code: bundledData.code,
923
- executeFunction: bundledData.executeFunction
924
- };
925
- writeProgress(`\n🚀 Pushing ${selected.name} v${confirmedVersion}...`);
926
- const api = new PostProcessorApi(BASE_URLS.API, apiKey, config.agent.agentId);
927
- const result = await api.pushPostProcessor(selected.postprocessorId, versionData);
928
- if (result.success) {
929
- writeSuccess(`\n✅ PostProcessor "${selected.name}" v${confirmedVersion} pushed successfully\n`);
930
- // Ask if user wants to deploy now
931
- const deployAnswer = await safePrompt([
932
- {
933
- type: 'confirm',
934
- name: 'deployNow',
935
- message: 'Would you like to deploy this postprocessor version to production now?',
936
- default: false
937
- }
938
- ]);
939
- if (deployAnswer && deployAnswer.deployNow) {
940
- await deployPostProcessorVersionAfterPush(apiKey, config.agent.agentId, selected, confirmedVersion);
941
- }
942
- else {
943
- writeInfo("💡 You can deploy this version later using: lua postprocessors production");
944
- }
859
+ // Step 4: Select postprocessor
860
+ const selected = await selectEntityOrFail(postprocessors, options, {
861
+ entityType: 'postprocessor',
862
+ nameFields: ['id', 'postprocessorId', 'name']
863
+ });
864
+ // Step 5: Load bundled data
865
+ const bundledData = loadBundledEntityData('postprocessors.json', selected.name, 'PostProcessor');
866
+ if (!bundledData.code) {
867
+ console.log(`❌ PostProcessor "${selected.name}" has no code in compiled output.`);
868
+ process.exit(1);
869
+ }
870
+ // Step 6: Handle version
871
+ const confirmedVersion = await resolveVersionOrFail(selected.version, options);
872
+ if (confirmedVersion !== selected.version) {
873
+ writeInfo(`📝 Updating version from ${selected.version} to ${confirmedVersion}`);
874
+ updateProcessorVersionInYaml('postprocessors', selected.name, confirmedVersion);
875
+ }
876
+ // Step 7: Prepare and push
877
+ const versionData = {
878
+ name: selected.name,
879
+ version: confirmedVersion,
880
+ description: bundledData.description || selected.description,
881
+ postprocessorId: selected.postprocessorId,
882
+ code: bundledData.code,
883
+ executeFunction: bundledData.executeFunction
884
+ };
885
+ writeProgress(`\n🚀 Pushing ${selected.name} v${confirmedVersion}...`);
886
+ const api = new PostProcessorApi(BASE_URLS.API, apiKey, config.agent.agentId);
887
+ const result = await api.pushPostProcessor(selected.postprocessorId, versionData);
888
+ if (result.success) {
889
+ writeSuccess(`\n✅ PostProcessor "${selected.name}" v${confirmedVersion} pushed successfully\n`);
890
+ // Step 8: Deploy if requested
891
+ if (await shouldDeployAfterPush(options)) {
892
+ await deployPostProcessorVersionAfterPush(apiKey, config.agent.agentId, selected, confirmedVersion);
945
893
  }
946
894
  else {
947
- console.error(`❌ Failed to push: ${result.error?.message}`);
895
+ writeInfo("💡 You can deploy this version later using: lua postprocessors production");
948
896
  }
949
897
  }
898
+ else {
899
+ console.log(`❌ Failed to push: ${result.error?.message}`);
900
+ }
950
901
  }
951
902
  catch (error) {
952
- console.error('❌ Error pushing postprocessor:', error);
903
+ console.log('❌ Error pushing postprocessor:', error);
953
904
  process.exit(1);
954
905
  }
955
906
  }
@@ -1011,65 +962,78 @@ function updateProcessorVersionInYaml(processorType, processorName, newVersion)
1011
962
  /**
1012
963
  * Push MCP Server to the server
1013
964
  */
1014
- async function pushMCPServerVersion() {
965
+ async function pushMCPServerVersion(options = {}) {
1015
966
  try {
1016
- // Step 1: Run compilation
967
+ // Step 1: Compile
1017
968
  writeProgress("📦 Compiling project...");
1018
969
  await compileCommand();
1019
970
  writeSuccess("✅ Compilation complete");
1020
971
  // Step 2: Authenticate
1021
- const apiKey = await loadApiKey();
1022
- if (!apiKey) {
1023
- console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
1024
- process.exit(1);
1025
- }
1026
- await checkApiKey(apiKey);
972
+ const apiKey = await authenticateOrFail();
1027
973
  writeSuccess("✅ Authentication verified");
1028
974
  // Step 3: Read configuration
1029
975
  const config = readSkillConfig();
1030
976
  if (!config?.agent?.agentId) {
1031
- console.error("❌ No agent ID found in lua.skill.yaml. Please run 'lua init' first.");
977
+ console.log("❌ No agent ID found in lua.skill.yaml. Please run 'lua init' first.");
1032
978
  process.exit(1);
1033
979
  }
1034
980
  const mcpServers = config.mcpServers || [];
1035
981
  if (mcpServers.length === 0) {
1036
- console.error("❌ No MCP servers found in lua.skill.yaml.");
982
+ console.log("❌ No MCP servers found in lua.skill.yaml.");
1037
983
  console.log("💡 Make sure you have defined MCP servers in your LuaAgent configuration.");
1038
984
  process.exit(1);
1039
985
  }
1040
- // Step 4: Load bundled MCP server data first (has full config)
986
+ // Step 4: Load bundled MCP server data
1041
987
  const bundledServersPath = path.join(process.cwd(), 'dist', 'mcp-servers.json');
1042
- let bundledServers = [];
1043
- if (fs.existsSync(bundledServersPath)) {
1044
- bundledServers = JSON.parse(fs.readFileSync(bundledServersPath, 'utf8'));
1045
- }
1046
- else {
1047
- console.error('❌ Bundled MCP server data not found.');
988
+ if (!fs.existsSync(bundledServersPath)) {
989
+ console.log('❌ Bundled MCP server data not found.');
1048
990
  console.log("💡 Please ensure your MCP servers are properly compiled.");
1049
991
  process.exit(1);
1050
992
  }
1051
- // Step 5: Select MCP server to push (use bundled data for display, YAML for ID tracking)
1052
- const serverAnswer = await safePrompt([
1053
- {
1054
- type: 'list',
1055
- name: 'selectedServer',
1056
- message: 'Select an MCP server to push:',
1057
- choices: bundledServers.map((server) => {
1058
- const yamlEntry = mcpServers.find((s) => s.name === server.name);
1059
- return {
1060
- name: `${server.name} (${server.transport})`,
1061
- value: { ...server, mcpServerId: yamlEntry?.mcpServerId }
1062
- };
1063
- })
993
+ const bundledServers = JSON.parse(fs.readFileSync(bundledServersPath, 'utf8'));
994
+ // Step 5: Select MCP server (special handling - uses bundled data with YAML IDs)
995
+ let selectedServer;
996
+ let bundledServerData;
997
+ if (options.entityName) {
998
+ bundledServerData = bundledServers.find((s) => s.id === options.entityName || s.mcpServerId === options.entityName || s.name === options.entityName);
999
+ if (!bundledServerData) {
1000
+ console.log(`❌ MCP server "${options.entityName}" not found`);
1001
+ process.exit(1);
1064
1002
  }
1065
- ]);
1066
- if (!serverAnswer) {
1067
- console.log("Push cancelled.");
1068
- return;
1003
+ const yamlEntry = mcpServers.find((s) => s.name === bundledServerData.name);
1004
+ selectedServer = { ...bundledServerData, mcpServerId: yamlEntry?.mcpServerId };
1005
+ writeInfo(`📦 Selected MCP server: ${selectedServer.name}`);
1006
+ }
1007
+ else if (bundledServers.length === 1) {
1008
+ bundledServerData = bundledServers[0];
1009
+ const yamlEntry = mcpServers.find((s) => s.name === bundledServerData.name);
1010
+ selectedServer = { ...bundledServerData, mcpServerId: yamlEntry?.mcpServerId };
1011
+ writeInfo(`📦 Pushing MCP server: ${selectedServer.name}`);
1012
+ }
1013
+ else {
1014
+ const serverAnswer = await safePrompt([
1015
+ {
1016
+ type: 'list',
1017
+ name: 'selectedServer',
1018
+ message: 'Select an MCP server to push:',
1019
+ choices: bundledServers.map((server) => {
1020
+ const yamlEntry = mcpServers.find((s) => s.name === server.name);
1021
+ return {
1022
+ name: `${server.name} (${server.transport})`,
1023
+ value: { ...server, mcpServerId: yamlEntry?.mcpServerId }
1024
+ };
1025
+ })
1026
+ }
1027
+ ]);
1028
+ if (!serverAnswer) {
1029
+ console.log("Push cancelled.");
1030
+ return;
1031
+ }
1032
+ selectedServer = serverAnswer.selectedServer;
1033
+ bundledServerData = selectedServer;
1069
1034
  }
1070
- const selectedServer = serverAnswer.selectedServer;
1071
- const bundledServerData = selectedServer;
1072
1035
  // Step 6: Prepare server data for push
1036
+ // Include resolver fields for function-based env/headers/url resolution
1073
1037
  const serverData = {
1074
1038
  name: bundledServerData.name,
1075
1039
  transport: bundledServerData.transport,
@@ -1077,28 +1041,22 @@ async function pushMCPServerVersion() {
1077
1041
  ...(bundledServerData.transport === 'stdio' ? {
1078
1042
  command: bundledServerData.command,
1079
1043
  args: bundledServerData.args,
1080
- env: bundledServerData.env
1044
+ env: bundledServerData.env,
1045
+ envResolver: bundledServerData.envResolver, // Compressed function for runtime resolution
1081
1046
  } : {
1082
1047
  url: bundledServerData.url,
1083
- headers: bundledServerData.headers
1048
+ urlResolver: bundledServerData.urlResolver, // Compressed function for runtime resolution
1049
+ headers: bundledServerData.headers,
1050
+ headersResolver: bundledServerData.headersResolver, // Compressed function for runtime resolution
1084
1051
  })
1085
1052
  };
1086
- // Step 7: Push to server (upsert)
1087
1053
  writeProgress(`\n🚀 Pushing MCP server "${selectedServer.name}" to server...`);
1088
1054
  const developerApi = new DeveloperApi(BASE_URLS.API, apiKey, config.agent.agentId);
1089
1055
  const result = await developerApi.upsertMCPServer(serverData);
1090
1056
  if (result.success && result.data) {
1091
1057
  writeSuccess(`\n✅ MCP server "${selectedServer.name}" pushed successfully\n`);
1092
- // Ask if user wants to activate now
1093
- const activateAnswer = await safePrompt([
1094
- {
1095
- type: 'confirm',
1096
- name: 'activateNow',
1097
- message: 'Would you like to activate this MCP server now?',
1098
- default: false
1099
- }
1100
- ]);
1101
- if (activateAnswer && activateAnswer.activateNow) {
1058
+ // Step 7: Activate if requested (MCP uses activate instead of deploy)
1059
+ if (await shouldDeployAfterPush(options)) {
1102
1060
  writeProgress("🔄 Activating MCP server...");
1103
1061
  const activateResult = await developerApi.activateMCPServer(result.data.id);
1104
1062
  if (activateResult.success) {
@@ -1106,7 +1064,7 @@ async function pushMCPServerVersion() {
1106
1064
  writeInfo("💡 The server's tools are now available to your agent.");
1107
1065
  }
1108
1066
  else {
1109
- console.error(`❌ Failed to activate: ${activateResult.error?.message}`);
1067
+ console.log(`❌ Failed to activate: ${activateResult.error?.message}`);
1110
1068
  }
1111
1069
  }
1112
1070
  else {
@@ -1114,11 +1072,11 @@ async function pushMCPServerVersion() {
1114
1072
  }
1115
1073
  }
1116
1074
  else {
1117
- console.error(`❌ Failed to push: ${result.error?.message}`);
1075
+ console.log(`❌ Failed to push: ${result.error?.message}`);
1118
1076
  }
1119
1077
  }
1120
1078
  catch (error) {
1121
- console.error('❌ Error pushing MCP server:', error);
1079
+ console.log('❌ Error pushing MCP server:', error);
1122
1080
  process.exit(1);
1123
1081
  }
1124
1082
  }