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.
@@ -50,10 +50,10 @@ export async function deployCommand() {
50
50
  }
51
51
  async function extractSkillInfo(indexContent) {
52
52
  const tools = [];
53
- // Find all addTool calls
54
- const addToolRegex = /skill\.addTool\(\s*\{([\s\S]*?)\}\s*\)/g;
53
+ // Find inline addTool calls: skill.addTool({...})
54
+ const inlineAddToolRegex = /skill\.addTool\(\s*\{([\s\S]*?)\}\s*\)/g;
55
55
  let match;
56
- while ((match = addToolRegex.exec(indexContent)) !== null) {
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
@@ -1,5 +1,6 @@
1
1
  import { ZodType } from "zod";
2
2
  import { LuaTool } from "./types/index.js";
3
+ export { LuaTool };
3
4
  export declare class LuaSkill {
4
5
  private readonly apiKey;
5
6
  private readonly tools;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lua-cli",
3
- "version": "1.1.3",
3
+ "version": "1.1.4-beta.0",
4
4
  "description": "Command-line interface for Lua AI platform - manage agents, organizations, and skills",
5
5
  "readmeFilename": "README.md",
6
6
  "main": "dist/index.js",