lua-cli 1.2.0 → 1.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/README.md +83 -56
- package/dist/commands/agents.js +20 -16
- package/dist/commands/apiKey.js +24 -19
- package/dist/commands/compile.d.ts +1 -0
- package/dist/commands/compile.js +822 -0
- package/dist/commands/configure.js +93 -68
- package/dist/commands/deploy-new.d.ts +20 -0
- package/dist/commands/deploy-new.js +128 -0
- package/dist/commands/deploy.d.ts +19 -0
- package/dist/commands/deploy.js +102 -756
- package/dist/commands/destroy.js +26 -21
- package/dist/commands/index.d.ts +3 -2
- package/dist/commands/index.js +3 -2
- package/dist/commands/init.js +108 -61
- package/dist/commands/push.d.ts +22 -0
- package/dist/commands/push.js +138 -0
- package/dist/commands/test.js +14 -15
- package/dist/index.js +29 -19
- package/dist/services/auth.d.ts +20 -0
- package/dist/services/auth.js +43 -4
- package/dist/skill.d.ts +22 -1
- package/dist/skill.js +21 -1
- package/dist/types/index.d.ts +16 -2
- package/dist/types/index.js +16 -1
- package/dist/utils/cli.d.ts +34 -0
- package/dist/utils/cli.js +58 -0
- package/dist/utils/files.d.ts +1 -1
- package/dist/utils/files.js +4 -3
- package/package.json +4 -4
- package/template/.lua/deploy.json +3 -0
- package/template/index.ts +4 -1
- package/template/tools/AdvancedMathTool.ts +1 -1
- package/template/tools/CalculatorTool.ts +1 -1
package/dist/commands/deploy.js
CHANGED
|
@@ -1,779 +1,125 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
function
|
|
7
|
-
const compressed = gzipSync(code);
|
|
8
|
-
return compressed.toString('base64');
|
|
9
|
-
}
|
|
10
|
-
function decompressCode(compressedCode) {
|
|
11
|
-
const buffer = Buffer.from(compressedCode, 'base64');
|
|
12
|
-
return gunzipSync(buffer).toString('utf8');
|
|
13
|
-
}
|
|
14
|
-
export async function deployCommand() {
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { loadApiKey, checkApiKey } from '../services/auth.js';
|
|
5
|
+
import { withErrorHandling, clearPromptLines, writeProgress, writeSuccess } from '../utils/cli.js';
|
|
6
|
+
export async function fetchVersions(apiKey, agentId, skillId) {
|
|
15
7
|
try {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
23
|
-
const version = packageJson.version || "1.0.0";
|
|
24
|
-
const skillsName = packageJson.name || "lua-skill";
|
|
25
|
-
// Read index.ts file
|
|
26
|
-
const indexPath = path.join(process.cwd(), "index.ts");
|
|
27
|
-
if (!fs.existsSync(indexPath)) {
|
|
28
|
-
throw new Error("index.ts not found in current directory");
|
|
29
|
-
}
|
|
30
|
-
const indexContent = fs.readFileSync(indexPath, "utf8");
|
|
31
|
-
// Extract skill information
|
|
32
|
-
const skillInfo = await extractSkillInfo(indexContent);
|
|
33
|
-
// Create deployment data with compressed execute code
|
|
34
|
-
const deployData = {
|
|
35
|
-
version,
|
|
36
|
-
skillsName,
|
|
37
|
-
tools: skillInfo.map(tool => ({
|
|
38
|
-
...tool,
|
|
39
|
-
execute: compressCode(tool.execute)
|
|
40
|
-
}))
|
|
41
|
-
};
|
|
42
|
-
// Create .lua directory
|
|
43
|
-
const luaDir = path.join(process.cwd(), ".lua");
|
|
44
|
-
if (!fs.existsSync(luaDir)) {
|
|
45
|
-
fs.mkdirSync(luaDir, { recursive: true });
|
|
46
|
-
}
|
|
47
|
-
// Write JSON output to .lua directory
|
|
48
|
-
const jsonOutputPath = path.join(luaDir, "deploy.json");
|
|
49
|
-
fs.writeFileSync(jsonOutputPath, JSON.stringify(deployData, null, 2));
|
|
50
|
-
// Write individual tool files to .lua directory
|
|
51
|
-
for (const tool of skillInfo) {
|
|
52
|
-
const toolFilePath = path.join(luaDir, `${tool.name}.js`);
|
|
53
|
-
fs.writeFileSync(toolFilePath, tool.execute);
|
|
54
|
-
}
|
|
55
|
-
console.log(`📁 Compiled files written to: ${luaDir}`);
|
|
56
|
-
console.log(`📄 JSON output: ${jsonOutputPath}`);
|
|
57
|
-
console.log(`🔧 Tool files: ${skillInfo.map(t => `${t.name}.js`).join(', ')}`);
|
|
58
|
-
console.log("✅ Skill compilation completed successfully!");
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
console.error("❌ Compilation failed:", error.message);
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
async function extractSkillInfo(indexContent) {
|
|
66
|
-
const tools = [];
|
|
67
|
-
// Find inline addTool calls: skill.addTool({...})
|
|
68
|
-
const inlineAddToolRegex = /skill\.addTool\(\s*\{([\s\S]*?)\}\s*\)/g;
|
|
69
|
-
let match;
|
|
70
|
-
while ((match = inlineAddToolRegex.exec(indexContent)) !== null) {
|
|
71
|
-
const toolContent = match[1];
|
|
72
|
-
// Extract tool properties
|
|
73
|
-
const nameMatch = toolContent.match(/name:\s*["']([^"']+)["']/);
|
|
74
|
-
const descriptionMatch = toolContent.match(/description:\s*["']([^"']+)["']/);
|
|
75
|
-
const inputSchemaMatch = toolContent.match(/inputSchema:\s*(\w+)/);
|
|
76
|
-
const outputSchemaMatch = toolContent.match(/outputSchema:\s*(\w+)/);
|
|
77
|
-
const executeMatch = toolContent.match(/execute:\s*async\s*\([^)]*\)\s*=>\s*\{([\s\S]*?)\}/);
|
|
78
|
-
if (nameMatch && descriptionMatch && inputSchemaMatch && outputSchemaMatch && executeMatch) {
|
|
79
|
-
const toolName = nameMatch[1];
|
|
80
|
-
const toolDescription = descriptionMatch[1];
|
|
81
|
-
const inputSchemaVar = inputSchemaMatch[1];
|
|
82
|
-
const outputSchemaVar = outputSchemaMatch[1];
|
|
83
|
-
const executeBody = executeMatch[1];
|
|
84
|
-
// Convert schemas to JSON Schema format
|
|
85
|
-
const inputSchema = convertSchemaToJSON(inputSchemaVar, indexContent);
|
|
86
|
-
const outputSchema = convertSchemaToJSON(outputSchemaVar, indexContent);
|
|
87
|
-
// Create self-contained execute function
|
|
88
|
-
const selfContainedExecute = await createSelfContainedExecute(executeBody, indexContent);
|
|
89
|
-
tools.push({
|
|
90
|
-
name: toolName,
|
|
91
|
-
description: toolDescription,
|
|
92
|
-
inputSchema,
|
|
93
|
-
outputSchema,
|
|
94
|
-
execute: selfContainedExecute
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
// Find class-based addTool calls: skill.addTool(new SomeTool())
|
|
99
|
-
const classAddToolRegex = /skill\.addTool\(\s*new\s+(\w+)\(\)\s*\)/g;
|
|
100
|
-
let classMatch;
|
|
101
|
-
while ((classMatch = classAddToolRegex.exec(indexContent)) !== null) {
|
|
102
|
-
const className = classMatch[1];
|
|
103
|
-
// Find the tool class definition
|
|
104
|
-
const toolInfo = await extractToolFromClass(className, indexContent);
|
|
105
|
-
if (toolInfo) {
|
|
106
|
-
tools.push(toolInfo);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return tools;
|
|
110
|
-
}
|
|
111
|
-
function convertSchemaToJSON(schemaVar, indexContent) {
|
|
112
|
-
// Find the schema definition
|
|
113
|
-
const schemaRegex = new RegExp(`const\\s+${schemaVar}\\s*=\\s*z\\.object\\(\\{([\\s\\S]*?)\\}\\\);`, 'g');
|
|
114
|
-
const match = schemaRegex.exec(indexContent);
|
|
115
|
-
if (match) {
|
|
116
|
-
const schemaContent = match[1];
|
|
117
|
-
// Convert Zod schema to JSON Schema format
|
|
118
|
-
return {
|
|
119
|
-
type: "object",
|
|
120
|
-
properties: parseZodProperties(schemaContent),
|
|
121
|
-
required: extractRequiredFields(schemaContent)
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
// If no match found, return empty schema
|
|
125
|
-
return { type: "object", properties: {} };
|
|
126
|
-
}
|
|
127
|
-
function parseZodProperties(schemaContent) {
|
|
128
|
-
const properties = {};
|
|
129
|
-
// Simple regex to find z.string(), z.number(), etc.
|
|
130
|
-
const fieldRegex = /(\w+):\s*z\.(\w+)\(\)/g;
|
|
131
|
-
let match;
|
|
132
|
-
while ((match = fieldRegex.exec(schemaContent)) !== null) {
|
|
133
|
-
const fieldName = match[1];
|
|
134
|
-
const fieldType = match[2];
|
|
135
|
-
switch (fieldType) {
|
|
136
|
-
case 'string':
|
|
137
|
-
properties[fieldName] = { type: 'string' };
|
|
138
|
-
break;
|
|
139
|
-
case 'number':
|
|
140
|
-
properties[fieldName] = { type: 'number' };
|
|
141
|
-
break;
|
|
142
|
-
case 'boolean':
|
|
143
|
-
properties[fieldName] = { type: 'boolean' };
|
|
144
|
-
break;
|
|
145
|
-
default:
|
|
146
|
-
properties[fieldName] = { type: 'string' };
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return properties;
|
|
150
|
-
}
|
|
151
|
-
function extractRequiredFields(schemaContent) {
|
|
152
|
-
const required = [];
|
|
153
|
-
const fieldRegex = /(\w+):\s*z\.(\w+)\(\)/g;
|
|
154
|
-
let match;
|
|
155
|
-
while ((match = fieldRegex.exec(schemaContent)) !== null) {
|
|
156
|
-
required.push(match[1]);
|
|
157
|
-
}
|
|
158
|
-
return required;
|
|
159
|
-
}
|
|
160
|
-
async function createSelfContainedExecute(executeBody, indexContent) {
|
|
161
|
-
const dependencies = [];
|
|
162
|
-
const bundledPackages = new Set();
|
|
163
|
-
// 1. Parse external package imports and bundle their code
|
|
164
|
-
const allImportRegex = /import\s+(?:(?:\{([^}]+)\})|(\w+))\s+from\s+["']([^"']+)["']/g;
|
|
165
|
-
let importMatch;
|
|
166
|
-
while ((importMatch = allImportRegex.exec(indexContent)) !== null) {
|
|
167
|
-
const namedImports = importMatch[1]; // Named imports like { z }
|
|
168
|
-
const defaultImport = importMatch[2]; // Default import like axios
|
|
169
|
-
const packagePath = importMatch[3];
|
|
170
|
-
// Skip local imports (relative paths)
|
|
171
|
-
if (packagePath.startsWith('./') || packagePath.startsWith('../')) {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
// Skip lua-cli imports (these are handled separately)
|
|
175
|
-
if (packagePath.startsWith('lua-cli')) {
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
// Skip zod - assume it's always available on target machine
|
|
179
|
-
if (packagePath === 'zod') {
|
|
180
|
-
// Add require statement for zod instead of bundling
|
|
181
|
-
if (namedImports) {
|
|
182
|
-
const importsList = namedImports.split(',').map(imp => imp.trim());
|
|
183
|
-
const usedImports = importsList.filter(imp => executeBody.includes(imp) || indexContent.includes(`${imp}.`));
|
|
184
|
-
if (usedImports.length > 0) {
|
|
185
|
-
const requireStatement = usedImports.length === 1
|
|
186
|
-
? `const { ${usedImports[0]} } = require('zod');`
|
|
187
|
-
: `const { ${usedImports.join(', ')} } = require('zod');`;
|
|
188
|
-
bundledPackages.add(requireStatement);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else if (defaultImport) {
|
|
192
|
-
bundledPackages.add(`const ${defaultImport} = require('zod');`);
|
|
193
|
-
}
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
// Bundle other external packages
|
|
197
|
-
if (namedImports || defaultImport) {
|
|
198
|
-
const packageCode = await bundlePackageCode(packagePath, namedImports, defaultImport);
|
|
199
|
-
if (packageCode) {
|
|
200
|
-
bundledPackages.add(packageCode);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
// 2. Extract class definitions with proper brace matching
|
|
205
|
-
const classRegex = /class\s+(\w+)(?:\s+extends\s+\w+)?\s*\{/g;
|
|
206
|
-
let classMatch;
|
|
207
|
-
while ((classMatch = classRegex.exec(indexContent)) !== null) {
|
|
208
|
-
const className = classMatch[1];
|
|
209
|
-
const classStart = classMatch.index;
|
|
210
|
-
// Find the matching closing brace
|
|
211
|
-
let braceCount = 0;
|
|
212
|
-
let classEnd = classStart;
|
|
213
|
-
let found = false;
|
|
214
|
-
for (let i = classStart; i < indexContent.length; i++) {
|
|
215
|
-
if (indexContent[i] === '{') {
|
|
216
|
-
braceCount++;
|
|
217
|
-
}
|
|
218
|
-
else if (indexContent[i] === '}') {
|
|
219
|
-
braceCount--;
|
|
220
|
-
if (braceCount === 0) {
|
|
221
|
-
classEnd = i;
|
|
222
|
-
found = true;
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (found) {
|
|
228
|
-
const fullClass = indexContent.substring(classStart, classEnd + 1);
|
|
229
|
-
// Check if this class is used in the execute function
|
|
230
|
-
let isUsed = false;
|
|
231
|
-
// Direct usage in execute body
|
|
232
|
-
if (executeBody.includes(`new ${className}`) ||
|
|
233
|
-
executeBody.includes(`${className}.`) ||
|
|
234
|
-
executeBody.includes(`${className}(`)) {
|
|
235
|
-
isUsed = true;
|
|
8
|
+
const response = await fetch(`https://api.lua.dev/developer/skills/${agentId}/${skillId}/versions`, {
|
|
9
|
+
method: "GET",
|
|
10
|
+
headers: {
|
|
11
|
+
"accept": "application/json",
|
|
12
|
+
"Authorization": `Bearer ${apiKey}`
|
|
236
13
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
while ((varMatch = variableRegex.exec(indexContent)) !== null) {
|
|
241
|
-
const varName = varMatch[1];
|
|
242
|
-
if (executeBody.includes(varName)) {
|
|
243
|
-
isUsed = true;
|
|
244
|
-
break;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
if (isUsed) {
|
|
248
|
-
dependencies.push(fullClass);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
// 3. Extract function definitions
|
|
253
|
-
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\([^)]*\)\s*\{([\s\S]*?)\n\}/g;
|
|
254
|
-
let functionMatch;
|
|
255
|
-
while ((functionMatch = functionRegex.exec(indexContent)) !== null) {
|
|
256
|
-
const functionName = functionMatch[1];
|
|
257
|
-
const functionBody = functionMatch[2];
|
|
258
|
-
if (executeBody.includes(functionName)) {
|
|
259
|
-
dependencies.push(`function ${functionName}() {\n${functionBody}\n}`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
// 4. Extract const/let/var declarations (avoid duplicates)
|
|
263
|
-
const varRegex = /(?:const|let|var)\s+(\w+)\s*=\s*([^;]+);/g;
|
|
264
|
-
const declaredVars = new Set();
|
|
265
|
-
let varMatch;
|
|
266
|
-
while ((varMatch = varRegex.exec(indexContent)) !== null) {
|
|
267
|
-
const varName = varMatch[1];
|
|
268
|
-
const varValue = varMatch[2];
|
|
269
|
-
// Skip if it's a class instantiation (we'll handle that separately)
|
|
270
|
-
if (varValue.includes('new ') && varValue.includes('()')) {
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
// Skip if already declared
|
|
274
|
-
if (declaredVars.has(varName)) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (executeBody.includes(varName)) {
|
|
278
|
-
declaredVars.add(varName);
|
|
279
|
-
dependencies.push(`const ${varName} = ${varValue};`);
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error(`Failed to fetch versions: ${response.status} ${response.statusText}`);
|
|
280
17
|
}
|
|
18
|
+
return await response.json();
|
|
281
19
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
while ((instantiationMatch = instantiationRegex.exec(indexContent)) !== null) {
|
|
286
|
-
const instanceName = instantiationMatch[1];
|
|
287
|
-
const className = instantiationMatch[2];
|
|
288
|
-
// Skip if already declared
|
|
289
|
-
if (declaredVars.has(instanceName)) {
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
if (executeBody.includes(instanceName)) {
|
|
293
|
-
declaredVars.add(instanceName);
|
|
294
|
-
dependencies.push(`const ${instanceName} = new ${className}();`);
|
|
295
|
-
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error("❌ Error fetching versions:", error);
|
|
22
|
+
throw error;
|
|
296
23
|
}
|
|
297
|
-
// 6. Create the self-contained execute function
|
|
298
|
-
const allDependencies = [...Array.from(bundledPackages), ...dependencies];
|
|
299
|
-
const dependencyCode = allDependencies.join('\n');
|
|
300
|
-
// Strip TypeScript type annotations for JavaScript compatibility (only for local code)
|
|
301
|
-
const cleanDependencyCode = allDependencies.map(dep => {
|
|
302
|
-
// Only strip TypeScript from local dependencies, not bundled packages
|
|
303
|
-
if (dep.includes('require(') || dep.includes('import ')) {
|
|
304
|
-
return dep; // Skip bundled packages
|
|
305
|
-
}
|
|
306
|
-
return dep
|
|
307
|
-
.replace(/:\s*string/g, '') // Remove : string
|
|
308
|
-
.replace(/:\s*number/g, '') // Remove : number
|
|
309
|
-
.replace(/:\s*boolean/g, '') // Remove : boolean
|
|
310
|
-
.replace(/:\s*any/g, '') // Remove : any
|
|
311
|
-
.replace(/:\s*void/g, '') // Remove : void
|
|
312
|
-
.replace(/:\s*object/g, '') // Remove : object
|
|
313
|
-
.replace(/:\s*Array<[^>]+>/g, '') // Remove : Array<Type>
|
|
314
|
-
.replace(/:\s*Promise<[^>]+>/g, '') // Remove : Promise<Type>
|
|
315
|
-
.replace(/:\s*Record<[^>]+>/g, ''); // Remove : Record<Type>
|
|
316
|
-
}).join('\n');
|
|
317
|
-
const cleanExecuteBody = executeBody
|
|
318
|
-
.replace(/:\s*string/g, '') // Remove : string
|
|
319
|
-
.replace(/:\s*number/g, '') // Remove : number
|
|
320
|
-
.replace(/:\s*boolean/g, '') // Remove : boolean
|
|
321
|
-
.replace(/:\s*any/g, '') // Remove : any
|
|
322
|
-
.replace(/:\s*void/g, '') // Remove : void
|
|
323
|
-
.replace(/:\s*object/g, '') // Remove : object
|
|
324
|
-
.replace(/:\s*Array<[^>]+>/g, '') // Remove : Array<Type>
|
|
325
|
-
.replace(/:\s*Promise<[^>]+>/g, '') // Remove : Promise<Type>
|
|
326
|
-
.replace(/:\s*Record<[^>]+>/g, ''); // Remove : Record<Type>
|
|
327
|
-
const selfContainedExecute = `async (input) => {
|
|
328
|
-
${cleanDependencyCode ? ` ${cleanDependencyCode.split('\n').join('\n ')}\n` : ''} ${cleanExecuteBody.trim()}
|
|
329
|
-
}`;
|
|
330
|
-
return selfContainedExecute;
|
|
331
24
|
}
|
|
332
|
-
async function
|
|
25
|
+
export async function publishVersion(apiKey, agentId, skillId, version) {
|
|
333
26
|
try {
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const entryFile = path.join(luaDir, `${packagePath}-entry.cjs`);
|
|
341
|
-
const outputFile = path.join(luaDir, `${packagePath}-bundle.cjs`);
|
|
342
|
-
// Create entry file based on import type
|
|
343
|
-
let entryContent = '';
|
|
344
|
-
if (defaultImport) {
|
|
345
|
-
// For default imports like `import axios from 'axios'`
|
|
346
|
-
entryContent = `import ${defaultImport} from '${packagePath}';\nmodule.exports = ${defaultImport};`;
|
|
347
|
-
}
|
|
348
|
-
else if (namedImports) {
|
|
349
|
-
// For named imports like `import { z } from 'zod'`
|
|
350
|
-
const importsList = namedImports.split(',').map(imp => imp.trim());
|
|
351
|
-
entryContent = `import { ${importsList.join(', ')} } from '${packagePath}';\nmodule.exports = { ${importsList.join(', ')} };`;
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
// Fallback - import everything
|
|
355
|
-
entryContent = `import * as ${packagePath.replace(/[^a-zA-Z0-9]/g, '_')} from '${packagePath}';\nmodule.exports = ${packagePath.replace(/[^a-zA-Z0-9]/g, '_')};`;
|
|
356
|
-
}
|
|
357
|
-
// Write entry file
|
|
358
|
-
fs.writeFileSync(entryFile, entryContent);
|
|
359
|
-
// Bundle with esbuild
|
|
360
|
-
const result = await build({
|
|
361
|
-
entryPoints: [entryFile],
|
|
362
|
-
bundle: true,
|
|
363
|
-
format: 'cjs', // CommonJS format
|
|
364
|
-
platform: 'node',
|
|
365
|
-
target: 'node16',
|
|
366
|
-
outfile: outputFile,
|
|
367
|
-
external: [], // Bundle everything
|
|
368
|
-
minify: false, // Keep readable for debugging
|
|
369
|
-
sourcemap: false,
|
|
370
|
-
write: true,
|
|
371
|
-
resolveExtensions: ['.js', '.ts', '.json'],
|
|
372
|
-
mainFields: ['main', 'module', 'browser'],
|
|
373
|
-
conditions: ['node'],
|
|
374
|
-
nodePaths: [
|
|
375
|
-
path.join(process.cwd(), 'node_modules'),
|
|
376
|
-
path.join(process.cwd(), '..', 'node_modules'),
|
|
377
|
-
path.join(process.cwd(), '..', '..', 'node_modules')
|
|
378
|
-
],
|
|
379
|
-
absWorkingDir: process.cwd(),
|
|
27
|
+
const response = await fetch(`https://api.lua.dev/developer/skills/${agentId}/${skillId}/${version}/publish`, {
|
|
28
|
+
method: "PUT",
|
|
29
|
+
headers: {
|
|
30
|
+
"accept": "application/json",
|
|
31
|
+
"Authorization": `Bearer ${apiKey}`
|
|
32
|
+
}
|
|
380
33
|
});
|
|
381
|
-
if (
|
|
382
|
-
|
|
383
|
-
return null;
|
|
384
|
-
}
|
|
385
|
-
// Read the bundled output
|
|
386
|
-
if (!fs.existsSync(outputFile)) {
|
|
387
|
-
console.warn(`Warning: Bundle output not found for package ${packagePath}`);
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
390
|
-
const bundledContent = fs.readFileSync(outputFile, 'utf8');
|
|
391
|
-
// Clean up temporary files
|
|
392
|
-
try {
|
|
393
|
-
fs.unlinkSync(entryFile);
|
|
394
|
-
fs.unlinkSync(outputFile);
|
|
395
|
-
}
|
|
396
|
-
catch (cleanupError) {
|
|
397
|
-
// Ignore cleanup errors
|
|
398
|
-
}
|
|
399
|
-
// Create the final bundled code
|
|
400
|
-
let finalCode = '';
|
|
401
|
-
if (defaultImport) {
|
|
402
|
-
finalCode = `const ${defaultImport} = (function() {\n${bundledContent}\n return module.exports;\n})();\n`;
|
|
403
|
-
}
|
|
404
|
-
else if (namedImports) {
|
|
405
|
-
const importsList = namedImports.split(',').map(imp => imp.trim());
|
|
406
|
-
finalCode = `(function() {\n${bundledContent}\n})();\n`;
|
|
407
|
-
finalCode += `const { ${importsList.join(', ')} } = module.exports;\n`;
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Failed to publish version: ${response.status} ${response.statusText}`);
|
|
408
36
|
}
|
|
409
|
-
|
|
410
|
-
finalCode = `(function() {\n${bundledContent}\n})();\n`;
|
|
411
|
-
}
|
|
412
|
-
return finalCode;
|
|
37
|
+
return await response.json();
|
|
413
38
|
}
|
|
414
39
|
catch (error) {
|
|
415
|
-
console.
|
|
416
|
-
|
|
417
|
-
if (packagePath === 'axios') {
|
|
418
|
-
return createWorkingAxiosImplementation();
|
|
419
|
-
}
|
|
420
|
-
return null;
|
|
40
|
+
console.error("❌ Error publishing version:", error);
|
|
41
|
+
throw error;
|
|
421
42
|
}
|
|
422
43
|
}
|
|
423
|
-
function
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const axios = {
|
|
427
|
-
get: async (url, config = {}) => {
|
|
428
|
-
const searchParams = new URLSearchParams(config.params || {});
|
|
429
|
-
const fullUrl = searchParams.toString() ? \`\${url}?\${searchParams}\` : url;
|
|
430
|
-
|
|
431
|
-
const response = await fetch(fullUrl, {
|
|
432
|
-
method: 'GET',
|
|
433
|
-
headers: {
|
|
434
|
-
'Content-Type': 'application/json',
|
|
435
|
-
...config.headers
|
|
436
|
-
}
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
if (!response.ok) {
|
|
440
|
-
const error = new Error(\`Request failed with status \${response.status}\`);
|
|
441
|
-
error.response = { status: response.status, statusText: response.statusText };
|
|
442
|
-
throw error;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const data = await response.json();
|
|
446
|
-
return {
|
|
447
|
-
data,
|
|
448
|
-
status: response.status,
|
|
449
|
-
statusText: response.statusText,
|
|
450
|
-
headers: response.headers,
|
|
451
|
-
config: config
|
|
452
|
-
};
|
|
453
|
-
},
|
|
454
|
-
|
|
455
|
-
post: async (url, data, config = {}) => {
|
|
456
|
-
const response = await fetch(url, {
|
|
457
|
-
method: 'POST',
|
|
458
|
-
headers: {
|
|
459
|
-
'Content-Type': 'application/json',
|
|
460
|
-
...config.headers
|
|
461
|
-
},
|
|
462
|
-
body: JSON.stringify(data)
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
if (!response.ok) {
|
|
466
|
-
const error = new Error(\`Request failed with status \${response.status}\`);
|
|
467
|
-
error.response = { status: response.status, statusText: response.statusText };
|
|
468
|
-
throw error;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
const responseData = await response.json();
|
|
472
|
-
return {
|
|
473
|
-
data: responseData,
|
|
474
|
-
status: response.status,
|
|
475
|
-
statusText: response.statusText,
|
|
476
|
-
headers: response.headers,
|
|
477
|
-
config: config
|
|
478
|
-
};
|
|
479
|
-
},
|
|
480
|
-
|
|
481
|
-
put: async (url, data, config = {}) => {
|
|
482
|
-
const response = await fetch(url, {
|
|
483
|
-
method: 'PUT',
|
|
484
|
-
headers: {
|
|
485
|
-
'Content-Type': 'application/json',
|
|
486
|
-
...config.headers
|
|
487
|
-
},
|
|
488
|
-
body: JSON.stringify(data)
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
if (!response.ok) {
|
|
492
|
-
const error = new Error(\`Request failed with status \${response.status}\`);
|
|
493
|
-
error.response = { status: response.status, statusText: response.statusText };
|
|
494
|
-
throw error;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const responseData = await response.json();
|
|
498
|
-
return {
|
|
499
|
-
data: responseData,
|
|
500
|
-
status: response.status,
|
|
501
|
-
statusText: response.statusText,
|
|
502
|
-
headers: response.headers,
|
|
503
|
-
config: config
|
|
504
|
-
};
|
|
505
|
-
},
|
|
506
|
-
|
|
507
|
-
delete: async (url, config = {}) => {
|
|
508
|
-
const response = await fetch(url, {
|
|
509
|
-
method: 'DELETE',
|
|
510
|
-
headers: {
|
|
511
|
-
'Content-Type': 'application/json',
|
|
512
|
-
...config.headers
|
|
513
|
-
}
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
if (!response.ok) {
|
|
517
|
-
const error = new Error(\`Request failed with status \${response.status}\`);
|
|
518
|
-
error.response = { status: response.status, statusText: response.statusText };
|
|
519
|
-
throw error;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
const responseData = await response.json();
|
|
523
|
-
return {
|
|
524
|
-
data: responseData,
|
|
525
|
-
status: response.status,
|
|
526
|
-
statusText: response.statusText,
|
|
527
|
-
headers: response.headers,
|
|
528
|
-
config: config
|
|
529
|
-
};
|
|
530
|
-
},
|
|
531
|
-
|
|
532
|
-
patch: async (url, data, config = {}) => {
|
|
533
|
-
const response = await fetch(url, {
|
|
534
|
-
method: 'PATCH',
|
|
535
|
-
headers: {
|
|
536
|
-
'Content-Type': 'application/json',
|
|
537
|
-
...config.headers
|
|
538
|
-
},
|
|
539
|
-
body: JSON.stringify(data)
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
if (!response.ok) {
|
|
543
|
-
const error = new Error(\`Request failed with status \${response.status}\`);
|
|
544
|
-
error.response = { status: response.status, statusText: response.statusText };
|
|
545
|
-
throw error;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
const responseData = await response.json();
|
|
549
|
-
return {
|
|
550
|
-
data: responseData,
|
|
551
|
-
status: response.status,
|
|
552
|
-
statusText: response.statusText,
|
|
553
|
-
headers: response.headers,
|
|
554
|
-
config: config
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
`;
|
|
559
|
-
}
|
|
560
|
-
async function extractToolFromClass(className, indexContent) {
|
|
561
|
-
// Find the import statement for this class
|
|
562
|
-
const importRegex = new RegExp(`import\\s+${className}\\s+from\\s+["']([^"']+)["']`, 'g');
|
|
563
|
-
const importMatch = importRegex.exec(indexContent);
|
|
564
|
-
if (!importMatch) {
|
|
565
|
-
console.warn(`Warning: Could not find import for class ${className}`);
|
|
44
|
+
function readTomlData() {
|
|
45
|
+
const tomlPath = path.join(process.cwd(), 'lua.skill.toml');
|
|
46
|
+
if (!fs.existsSync(tomlPath)) {
|
|
566
47
|
return null;
|
|
567
48
|
}
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
const
|
|
571
|
-
if (!
|
|
572
|
-
console.warn(`Warning: Tool file not found: ${toolFilePath}`);
|
|
49
|
+
const tomlContent = fs.readFileSync(tomlPath, 'utf8');
|
|
50
|
+
const agentIdMatch = tomlContent.match(/agentId\s*=\s*["']([^"']+)["']/);
|
|
51
|
+
const skillIdMatch = tomlContent.match(/skillId\s*=\s*["']([^"']+)["']/);
|
|
52
|
+
if (!agentIdMatch || !skillIdMatch) {
|
|
573
53
|
return null;
|
|
574
54
|
}
|
|
575
|
-
const toolContent = fs.readFileSync(toolFilePath, 'utf8');
|
|
576
|
-
// Extract tool properties from the class
|
|
577
|
-
const nameMatch = toolContent.match(/this\.name\s*=\s*["']([^"']+)["']/);
|
|
578
|
-
const descriptionMatch = toolContent.match(/this\.description\s*=\s*["']([^"']+)["']/);
|
|
579
|
-
if (!nameMatch || !descriptionMatch) {
|
|
580
|
-
console.warn(`Warning: Could not extract name or description from ${className}`);
|
|
581
|
-
return null;
|
|
582
|
-
}
|
|
583
|
-
const toolName = nameMatch[1];
|
|
584
|
-
const toolDescription = descriptionMatch[1];
|
|
585
|
-
// Extract schemas
|
|
586
|
-
const inputSchemaMatch = toolContent.match(/const\s+(\w+)\s*=\s*z\.object\(/);
|
|
587
|
-
const outputSchemaMatch = toolContent.match(/const\s+(\w+)\s*=\s*z\.object\(/);
|
|
588
|
-
if (!inputSchemaMatch) {
|
|
589
|
-
console.warn(`Warning: Could not find input schema in ${className}`);
|
|
590
|
-
return null;
|
|
591
|
-
}
|
|
592
|
-
// Convert schemas to JSON Schema format
|
|
593
|
-
const inputSchema = convertSchemaToJSON(inputSchemaMatch[1], toolContent);
|
|
594
|
-
const outputSchema = outputSchemaMatch ? convertSchemaToJSON(outputSchemaMatch[1], toolContent) : { type: "object" };
|
|
595
|
-
// Extract execute method
|
|
596
|
-
const executeMatch = toolContent.match(/async\s+execute\s*\([^)]*\)\s*\{([\s\S]*?)\}/);
|
|
597
|
-
if (!executeMatch) {
|
|
598
|
-
console.warn(`Warning: Could not find execute method in ${className}`);
|
|
599
|
-
return null;
|
|
600
|
-
}
|
|
601
|
-
const executeBody = executeMatch[1];
|
|
602
|
-
// For class-based tools, we need to create a self-contained function that includes:
|
|
603
|
-
// 1. The service classes
|
|
604
|
-
// 2. Class instantiation
|
|
605
|
-
// 3. The execute logic
|
|
606
|
-
const selfContainedExecute = await createClassBasedExecute(executeBody, toolContent, className);
|
|
607
55
|
return {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
inputSchema,
|
|
611
|
-
outputSchema,
|
|
612
|
-
execute: selfContainedExecute
|
|
56
|
+
agentId: agentIdMatch[1],
|
|
57
|
+
skillId: skillIdMatch[1]
|
|
613
58
|
};
|
|
614
59
|
}
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
if (
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
//
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
60
|
+
function formatVersionChoice(version) {
|
|
61
|
+
const currentIndicator = version.isCurrent ? ' (CURRENT)' : '';
|
|
62
|
+
const date = new Date(version.createdDate).toLocaleDateString();
|
|
63
|
+
return `${version.version}${currentIndicator} - Created: ${date} by ${version.createdByEmail}`;
|
|
64
|
+
}
|
|
65
|
+
export async function deployCommand() {
|
|
66
|
+
return withErrorHandling(async () => {
|
|
67
|
+
// Check if we're in a skill directory
|
|
68
|
+
const tomlData = readTomlData();
|
|
69
|
+
if (!tomlData) {
|
|
70
|
+
console.error("❌ No lua.skill.toml found or missing agentId/skillId. Please run this command from a skill directory.");
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
// Load API key
|
|
74
|
+
const apiKey = await loadApiKey();
|
|
75
|
+
if (!apiKey) {
|
|
76
|
+
console.error("❌ No API key found. Please run 'lua configure' to set up your API key.");
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
// Validate API key
|
|
80
|
+
const userData = await checkApiKey(apiKey);
|
|
81
|
+
writeProgress("✅ Authenticated");
|
|
82
|
+
// Fetch available versions
|
|
83
|
+
writeProgress("🔄 Fetching available versions...");
|
|
84
|
+
const versionsResponse = await fetchVersions(apiKey, tomlData.agentId, tomlData.skillId);
|
|
85
|
+
if (!versionsResponse.versions || versionsResponse.versions.length === 0) {
|
|
86
|
+
console.log("❌ No versions found for this skill.");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
// Sort versions by creation date (newest first)
|
|
90
|
+
const sortedVersions = versionsResponse.versions.sort((a, b) => new Date(b.createdDate).getTime() - new Date(a.createdDate).getTime());
|
|
91
|
+
// Let user select a version
|
|
92
|
+
const { selectedVersion } = await inquirer.prompt([
|
|
93
|
+
{
|
|
94
|
+
type: "list",
|
|
95
|
+
name: "selectedVersion",
|
|
96
|
+
message: "Select a version to deploy:",
|
|
97
|
+
choices: sortedVersions.map(version => ({
|
|
98
|
+
name: formatVersionChoice(version),
|
|
99
|
+
value: version.version
|
|
100
|
+
}))
|
|
651
101
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
const serviceContent = fs.readFileSync(serviceFilePath, 'utf8');
|
|
663
|
-
// Process all imports in the service file
|
|
664
|
-
const serviceImportRegex = /import\s+(?:(?:\{([^}]+)\})|(\w+))\s+from\s+["']([^"']+)["']/g;
|
|
665
|
-
let serviceImportMatch;
|
|
666
|
-
while ((serviceImportMatch = serviceImportRegex.exec(serviceContent)) !== null) {
|
|
667
|
-
const namedImports = serviceImportMatch[1];
|
|
668
|
-
const defaultImport = serviceImportMatch[2];
|
|
669
|
-
const packagePath = serviceImportMatch[3];
|
|
670
|
-
// Skip lua-cli imports
|
|
671
|
-
if (packagePath.startsWith('lua-cli')) {
|
|
672
|
-
continue;
|
|
673
|
-
}
|
|
674
|
-
// Handle zod
|
|
675
|
-
if (packagePath === 'zod') {
|
|
676
|
-
if (namedImports) {
|
|
677
|
-
const importsList = namedImports.split(',').map(imp => imp.trim());
|
|
678
|
-
const usedImports = importsList.filter(imp => serviceContent.includes(`${imp}.`));
|
|
679
|
-
if (usedImports.length > 0) {
|
|
680
|
-
const requireStatement = usedImports.length === 1
|
|
681
|
-
? `const { ${usedImports[0]} } = require('zod');`
|
|
682
|
-
: `const { ${usedImports.join(', ')} } = require('zod');`;
|
|
683
|
-
bundledPackages.add(requireStatement);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
else if (defaultImport) {
|
|
687
|
-
bundledPackages.add(`const ${defaultImport} = require('zod');`);
|
|
688
|
-
}
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
691
|
-
// Handle axios - bundle it properly
|
|
692
|
-
if (packagePath === 'axios') {
|
|
693
|
-
const packageCode = await bundlePackageCode(packagePath, namedImports, defaultImport);
|
|
694
|
-
if (packageCode) {
|
|
695
|
-
bundledPackages.add(packageCode);
|
|
696
|
-
}
|
|
697
|
-
continue;
|
|
698
|
-
}
|
|
699
|
-
// Bundle other external packages
|
|
700
|
-
if (namedImports || defaultImport) {
|
|
701
|
-
const packageCode = await bundlePackageCode(packagePath, namedImports, defaultImport);
|
|
702
|
-
if (packageCode) {
|
|
703
|
-
bundledPackages.add(packageCode);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
// Extract the service class with proper brace matching
|
|
708
|
-
const classRegex = /class\s+(\w+)(?:\s+extends\s+\w+)?\s*\{/g;
|
|
709
|
-
let classMatch = classRegex.exec(serviceContent);
|
|
710
|
-
if (classMatch) {
|
|
711
|
-
const serviceClassName = classMatch[1];
|
|
712
|
-
const startIndex = classMatch.index + classMatch[0].length - 1; // Position of opening brace
|
|
713
|
-
// Find matching closing brace
|
|
714
|
-
let braceCount = 1;
|
|
715
|
-
let endIndex = startIndex + 1;
|
|
716
|
-
while (endIndex < serviceContent.length && braceCount > 0) {
|
|
717
|
-
if (serviceContent[endIndex] === '{')
|
|
718
|
-
braceCount++;
|
|
719
|
-
else if (serviceContent[endIndex] === '}')
|
|
720
|
-
braceCount--;
|
|
721
|
-
endIndex++;
|
|
722
|
-
}
|
|
723
|
-
if (braceCount === 0) {
|
|
724
|
-
const serviceClassBody = serviceContent.substring(startIndex + 1, endIndex - 1);
|
|
725
|
-
// Clean up the class body (remove TypeScript types)
|
|
726
|
-
const cleanClassBody = serviceClassBody
|
|
727
|
-
.replace(/:\s*string/g, '')
|
|
728
|
-
.replace(/:\s*number/g, '')
|
|
729
|
-
.replace(/:\s*boolean/g, '')
|
|
730
|
-
.replace(/:\s*any/g, '')
|
|
731
|
-
.replace(/:\s*void/g, '')
|
|
732
|
-
.replace(/:\s*Promise<[^>]+>/g, '')
|
|
733
|
-
.replace(/:\s*Record<[^>]+>/g, '');
|
|
734
|
-
// Create the service class
|
|
735
|
-
const serviceClass = `class ${serviceClassName} {\n${cleanClassBody}\n}`;
|
|
736
|
-
dependencies.push(serviceClass);
|
|
737
|
-
}
|
|
738
|
-
}
|
|
102
|
+
]);
|
|
103
|
+
// Clear the selection prompt lines
|
|
104
|
+
clearPromptLines(2);
|
|
105
|
+
// Show warning and confirm deployment
|
|
106
|
+
const { confirmed } = await inquirer.prompt([
|
|
107
|
+
{
|
|
108
|
+
type: "confirm",
|
|
109
|
+
name: "confirmed",
|
|
110
|
+
message: "⚠️ Warning: This version will be deployed to all users. Do you want to proceed?",
|
|
111
|
+
default: false
|
|
739
112
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
if (
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
if (constructorMatch) {
|
|
753
|
-
const constructorBody = constructorMatch[1];
|
|
754
|
-
// Extract service instantiation
|
|
755
|
-
const serviceInstantiationMatch = constructorBody.match(/this\.(\w+)\s*=\s*new\s+(\w+)\([^)]*\);/);
|
|
756
|
-
if (serviceInstantiationMatch) {
|
|
757
|
-
const serviceProperty = serviceInstantiationMatch[1];
|
|
758
|
-
const serviceClass = serviceInstantiationMatch[2];
|
|
759
|
-
dependencies.push(`const ${serviceProperty} = new ${serviceClass}();`);
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
// 3. Create the self-contained execute function
|
|
763
|
-
const allDependencies = [...Array.from(bundledPackages), ...dependencies];
|
|
764
|
-
const dependencyCode = allDependencies.join('\n');
|
|
765
|
-
// Clean the execute body (remove TypeScript types)
|
|
766
|
-
const cleanExecuteBody = executeBody
|
|
767
|
-
.replace(/:\s*string/g, '')
|
|
768
|
-
.replace(/:\s*number/g, '')
|
|
769
|
-
.replace(/:\s*boolean/g, '')
|
|
770
|
-
.replace(/:\s*any/g, '')
|
|
771
|
-
.replace(/:\s*void/g, '')
|
|
772
|
-
.replace(/:\s*Promise<[^>]+>/g, '')
|
|
773
|
-
.replace(/:\s*Record<[^>]+>/g, '');
|
|
774
|
-
// Replace this.serviceProperty with the instantiated service
|
|
775
|
-
const finalExecuteBody = cleanExecuteBody.replace(/this\.(\w+)/g, '$1');
|
|
776
|
-
return `async (input) => {
|
|
777
|
-
${dependencyCode ? dependencyCode + '\n' : ''}${finalExecuteBody}
|
|
778
|
-
}`;
|
|
113
|
+
]);
|
|
114
|
+
// Clear the confirmation prompt lines
|
|
115
|
+
clearPromptLines(2);
|
|
116
|
+
if (!confirmed) {
|
|
117
|
+
console.log("❌ Deployment cancelled.");
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
// Publish the selected version
|
|
121
|
+
writeProgress("🔄 Publishing version...");
|
|
122
|
+
const publishResponse = await publishVersion(apiKey, tomlData.agentId, tomlData.skillId, selectedVersion);
|
|
123
|
+
writeSuccess(`✅ Version ${publishResponse.activeVersionId} deployed successfully`);
|
|
124
|
+
}, "deployment");
|
|
779
125
|
}
|