lua-cli 1.1.3 → 1.1.4-beta.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.
- package/dist/commands/deploy.js +189 -3
- package/dist/skill.d.ts +1 -0
- package/package.json +1 -1
package/dist/commands/deploy.js
CHANGED
|
@@ -50,10 +50,10 @@ export async function deployCommand() {
|
|
|
50
50
|
}
|
|
51
51
|
async function extractSkillInfo(indexContent) {
|
|
52
52
|
const tools = [];
|
|
53
|
-
// Find
|
|
54
|
-
const
|
|
53
|
+
// Find inline addTool calls: skill.addTool({...})
|
|
54
|
+
const inlineAddToolRegex = /skill\.addTool\(\s*\{([\s\S]*?)\}\s*\)/g;
|
|
55
55
|
let match;
|
|
56
|
-
while ((match =
|
|
56
|
+
while ((match = inlineAddToolRegex.exec(indexContent)) !== null) {
|
|
57
57
|
const toolContent = match[1];
|
|
58
58
|
// Extract tool properties
|
|
59
59
|
const nameMatch = toolContent.match(/name:\s*["']([^"']+)["']/);
|
|
@@ -81,6 +81,17 @@ async function extractSkillInfo(indexContent) {
|
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
// Find class-based addTool calls: skill.addTool(new SomeTool())
|
|
85
|
+
const classAddToolRegex = /skill\.addTool\(\s*new\s+(\w+)\(\)\s*\)/g;
|
|
86
|
+
let classMatch;
|
|
87
|
+
while ((classMatch = classAddToolRegex.exec(indexContent)) !== null) {
|
|
88
|
+
const className = classMatch[1];
|
|
89
|
+
// Find the tool class definition
|
|
90
|
+
const toolInfo = await extractToolFromClass(className, indexContent);
|
|
91
|
+
if (toolInfo) {
|
|
92
|
+
tools.push(toolInfo);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
84
95
|
return tools;
|
|
85
96
|
}
|
|
86
97
|
function convertSchemaToJSON(schemaVar, indexContent) {
|
|
@@ -532,3 +543,178 @@ const axios = {
|
|
|
532
543
|
};
|
|
533
544
|
`;
|
|
534
545
|
}
|
|
546
|
+
async function extractToolFromClass(className, indexContent) {
|
|
547
|
+
// Find the import statement for this class
|
|
548
|
+
const importRegex = new RegExp(`import\\s+${className}\\s+from\\s+["']([^"']+)["']`, 'g');
|
|
549
|
+
const importMatch = importRegex.exec(indexContent);
|
|
550
|
+
if (!importMatch) {
|
|
551
|
+
console.warn(`Warning: Could not find import for class ${className}`);
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
const importPath = importMatch[1];
|
|
555
|
+
// Read the tool file
|
|
556
|
+
const toolFilePath = path.join(process.cwd(), importPath.replace('./', '') + '.ts');
|
|
557
|
+
if (!fs.existsSync(toolFilePath)) {
|
|
558
|
+
console.warn(`Warning: Tool file not found: ${toolFilePath}`);
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
const toolContent = fs.readFileSync(toolFilePath, 'utf8');
|
|
562
|
+
// Extract tool properties from the class
|
|
563
|
+
const nameMatch = toolContent.match(/this\.name\s*=\s*["']([^"']+)["']/);
|
|
564
|
+
const descriptionMatch = toolContent.match(/this\.description\s*=\s*["']([^"']+)["']/);
|
|
565
|
+
if (!nameMatch || !descriptionMatch) {
|
|
566
|
+
console.warn(`Warning: Could not extract name or description from ${className}`);
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
569
|
+
const toolName = nameMatch[1];
|
|
570
|
+
const toolDescription = descriptionMatch[1];
|
|
571
|
+
// Extract schemas
|
|
572
|
+
const inputSchemaMatch = toolContent.match(/const\s+(\w+)\s*=\s*z\.object\(/);
|
|
573
|
+
const outputSchemaMatch = toolContent.match(/const\s+(\w+)\s*=\s*z\.object\(/);
|
|
574
|
+
if (!inputSchemaMatch) {
|
|
575
|
+
console.warn(`Warning: Could not find input schema in ${className}`);
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
// Convert schemas to JSON Schema format
|
|
579
|
+
const inputSchema = convertSchemaToJSON(inputSchemaMatch[1], toolContent);
|
|
580
|
+
const outputSchema = outputSchemaMatch ? convertSchemaToJSON(outputSchemaMatch[1], toolContent) : { type: "object" };
|
|
581
|
+
// Extract execute method
|
|
582
|
+
const executeMatch = toolContent.match(/async\s+execute\s*\([^)]*\)\s*\{([\s\S]*?)\}/);
|
|
583
|
+
if (!executeMatch) {
|
|
584
|
+
console.warn(`Warning: Could not find execute method in ${className}`);
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
const executeBody = executeMatch[1];
|
|
588
|
+
// For class-based tools, we need to create a self-contained function that includes:
|
|
589
|
+
// 1. The service classes
|
|
590
|
+
// 2. Class instantiation
|
|
591
|
+
// 3. The execute logic
|
|
592
|
+
const selfContainedExecute = await createClassBasedExecute(executeBody, toolContent, className);
|
|
593
|
+
return {
|
|
594
|
+
name: toolName,
|
|
595
|
+
description: toolDescription,
|
|
596
|
+
inputSchema,
|
|
597
|
+
outputSchema,
|
|
598
|
+
execute: selfContainedExecute
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
async function createClassBasedExecute(executeBody, toolContent, className) {
|
|
602
|
+
const dependencies = [];
|
|
603
|
+
const bundledPackages = new Set();
|
|
604
|
+
// 1. Parse imports from the tool file
|
|
605
|
+
const importRegex = /import\s+(?:(?:\{([^}]+)\})|(\w+))\s+from\s+["']([^"']+)["']/g;
|
|
606
|
+
let importMatch;
|
|
607
|
+
while ((importMatch = importRegex.exec(toolContent)) !== null) {
|
|
608
|
+
const namedImports = importMatch[1];
|
|
609
|
+
const defaultImport = importMatch[2];
|
|
610
|
+
const packagePath = importMatch[3];
|
|
611
|
+
// Skip lua-cli imports
|
|
612
|
+
if (packagePath.startsWith('lua-cli')) {
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
// Handle zod
|
|
616
|
+
if (packagePath === 'zod') {
|
|
617
|
+
if (namedImports) {
|
|
618
|
+
const importsList = namedImports.split(',').map(imp => imp.trim());
|
|
619
|
+
const usedImports = importsList.filter(imp => executeBody.includes(imp) || toolContent.includes(`${imp}.`));
|
|
620
|
+
if (usedImports.length > 0) {
|
|
621
|
+
const requireStatement = usedImports.length === 1
|
|
622
|
+
? `const { ${usedImports[0]} } = require('zod');`
|
|
623
|
+
: `const { ${usedImports.join(', ')} } = require('zod');`;
|
|
624
|
+
bundledPackages.add(requireStatement);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
else if (defaultImport) {
|
|
628
|
+
bundledPackages.add(`const ${defaultImport} = require('zod');`);
|
|
629
|
+
}
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
// Handle axios
|
|
633
|
+
if (packagePath === 'axios') {
|
|
634
|
+
bundledPackages.add(`const axios = require('axios');`);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
// Handle local service imports
|
|
638
|
+
if (packagePath.startsWith('./') || packagePath.startsWith('../')) {
|
|
639
|
+
// The tool files are in tools/ subdirectory, so we need to resolve from there
|
|
640
|
+
const toolDir = path.join(process.cwd(), 'tools');
|
|
641
|
+
const serviceFilePath = path.resolve(toolDir, packagePath + '.ts');
|
|
642
|
+
if (fs.existsSync(serviceFilePath)) {
|
|
643
|
+
const serviceContent = fs.readFileSync(serviceFilePath, 'utf8');
|
|
644
|
+
// Check for axios import in service file
|
|
645
|
+
if (serviceContent.includes("import axios from \"axios\"")) {
|
|
646
|
+
bundledPackages.add(`const axios = require('axios');`);
|
|
647
|
+
}
|
|
648
|
+
// Extract the service class with proper brace matching
|
|
649
|
+
const classRegex = /class\s+(\w+)(?:\s+extends\s+\w+)?\s*\{/g;
|
|
650
|
+
let classMatch = classRegex.exec(serviceContent);
|
|
651
|
+
if (classMatch) {
|
|
652
|
+
const serviceClassName = classMatch[1];
|
|
653
|
+
const startIndex = classMatch.index + classMatch[0].length - 1; // Position of opening brace
|
|
654
|
+
// Find matching closing brace
|
|
655
|
+
let braceCount = 1;
|
|
656
|
+
let endIndex = startIndex + 1;
|
|
657
|
+
while (endIndex < serviceContent.length && braceCount > 0) {
|
|
658
|
+
if (serviceContent[endIndex] === '{')
|
|
659
|
+
braceCount++;
|
|
660
|
+
else if (serviceContent[endIndex] === '}')
|
|
661
|
+
braceCount--;
|
|
662
|
+
endIndex++;
|
|
663
|
+
}
|
|
664
|
+
if (braceCount === 0) {
|
|
665
|
+
const serviceClassBody = serviceContent.substring(startIndex + 1, endIndex - 1);
|
|
666
|
+
// Clean up the class body (remove TypeScript types)
|
|
667
|
+
const cleanClassBody = serviceClassBody
|
|
668
|
+
.replace(/:\s*string/g, '')
|
|
669
|
+
.replace(/:\s*number/g, '')
|
|
670
|
+
.replace(/:\s*boolean/g, '')
|
|
671
|
+
.replace(/:\s*any/g, '')
|
|
672
|
+
.replace(/:\s*void/g, '')
|
|
673
|
+
.replace(/:\s*Promise<[^>]+>/g, '')
|
|
674
|
+
.replace(/:\s*Record<[^>]+>/g, '');
|
|
675
|
+
// Create the service class
|
|
676
|
+
const serviceClass = `class ${serviceClassName} {\n${cleanClassBody}\n}`;
|
|
677
|
+
dependencies.push(serviceClass);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
// Bundle other external packages
|
|
684
|
+
if (namedImports || defaultImport) {
|
|
685
|
+
const packageCode = await bundlePackageCode(packagePath, namedImports, defaultImport);
|
|
686
|
+
if (packageCode) {
|
|
687
|
+
bundledPackages.add(packageCode);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
// 2. Extract class instantiation from constructor
|
|
692
|
+
const constructorMatch = toolContent.match(/constructor\s*\([^)]*\)\s*\{([\s\S]*?)\}/);
|
|
693
|
+
if (constructorMatch) {
|
|
694
|
+
const constructorBody = constructorMatch[1];
|
|
695
|
+
// Extract service instantiation
|
|
696
|
+
const serviceInstantiationMatch = constructorBody.match(/this\.(\w+)\s*=\s*new\s+(\w+)\([^)]*\);/);
|
|
697
|
+
if (serviceInstantiationMatch) {
|
|
698
|
+
const serviceProperty = serviceInstantiationMatch[1];
|
|
699
|
+
const serviceClass = serviceInstantiationMatch[2];
|
|
700
|
+
dependencies.push(`const ${serviceProperty} = new ${serviceClass}();`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
// 3. Create the self-contained execute function
|
|
704
|
+
const allDependencies = [...Array.from(bundledPackages), ...dependencies];
|
|
705
|
+
const dependencyCode = allDependencies.join('\n');
|
|
706
|
+
// Clean the execute body (remove TypeScript types)
|
|
707
|
+
const cleanExecuteBody = executeBody
|
|
708
|
+
.replace(/:\s*string/g, '')
|
|
709
|
+
.replace(/:\s*number/g, '')
|
|
710
|
+
.replace(/:\s*boolean/g, '')
|
|
711
|
+
.replace(/:\s*any/g, '')
|
|
712
|
+
.replace(/:\s*void/g, '')
|
|
713
|
+
.replace(/:\s*Promise<[^>]+>/g, '')
|
|
714
|
+
.replace(/:\s*Record<[^>]+>/g, '');
|
|
715
|
+
// Replace this.serviceProperty with the instantiated service
|
|
716
|
+
const finalExecuteBody = cleanExecuteBody.replace(/this\.(\w+)/g, '$1');
|
|
717
|
+
return `async (input) => {
|
|
718
|
+
${dependencyCode ? dependencyCode + '\n' : ''}${finalExecuteBody}
|
|
719
|
+
}`;
|
|
720
|
+
}
|
package/dist/skill.d.ts
CHANGED
package/package.json
CHANGED