UNPKG

revit-cli

Version:

A scalable CLI tool for Revit communication and data manipulation

249 lines 9.21 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.PluginManager = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const glob_1 = require("glob"); const logger_1 = require("../utils/logger"); /** * Manages plugin discovery, loading, and tool registration */ class PluginManager { constructor() { this.plugins = new Map(); this.tools = new Map(); this.pluginDirectories = []; this.disabledPlugins = []; this.logger = new logger_1.Logger(); } /** * Initialize the plugin manager */ async initialize() { this.logger.info('Initializing Plugin Manager...'); // Set default plugin directories this.pluginDirectories = [ path.join(__dirname, '..', 'plugins', 'core'), path.join(process.cwd(), 'plugins') ]; await this.discoverAndLoadPlugins(); this.logger.info(`Plugin Manager initialized with ${this.plugins.size} plugins and ${this.tools.size} tools`); } /** * Discover and load all plugins from configured directories */ async discoverAndLoadPlugins() { const discoveryResults = []; for (const directory of this.pluginDirectories) { if (await fs.pathExists(directory)) { const results = await this.discoverPluginsInDirectory(directory); discoveryResults.push(...results); } } // Load valid plugins for (const result of discoveryResults) { if (result.isValid && !this.disabledPlugins.includes(result.metadata.name)) { try { await this.loadPlugin(result.path); } catch (error) { this.logger.error(`Failed to load plugin at ${result.path}:`, error); } } } } /** * Discover plugins in a specific directory */ async discoverPluginsInDirectory(directory) { const results = []; try { // Look for plugin.json files or index.js/ts files const pluginFiles = await (0, glob_1.glob)('**/plugin.json', { cwd: directory }); const indexFiles = await (0, glob_1.glob)('**/index.{js,ts}', { cwd: directory }); // Process plugin.json files for (const pluginFile of pluginFiles) { const pluginPath = path.join(directory, path.dirname(pluginFile)); const result = await this.validatePlugin(pluginPath); results.push(result); } // Process standalone index files (for simple plugins) for (const indexFile of indexFiles) { const pluginPath = path.join(directory, path.dirname(indexFile)); // Skip if already processed via plugin.json if (!results.some(r => r.path === pluginPath)) { const result = await this.validatePlugin(pluginPath); results.push(result); } } } catch (error) { this.logger.error(`Error discovering plugins in ${directory}:`, error); } return results; } /** * Validate a plugin at the given path */ async validatePlugin(pluginPath) { const result = { path: pluginPath, metadata: { name: '', version: '', description: '' }, isValid: false, errors: [] }; try { const pluginJsonPath = path.join(pluginPath, 'plugin.json'); const indexPath = path.join(pluginPath, 'index.js'); const indexTsPath = path.join(pluginPath, 'index.ts'); // Check for plugin.json if (await fs.pathExists(pluginJsonPath)) { const metadata = await fs.readJson(pluginJsonPath); result.metadata = metadata; } else { result.errors?.push('Missing plugin.json file'); } // Check for entry point if (!await fs.pathExists(indexPath) && !await fs.pathExists(indexTsPath)) { result.errors?.push('Missing index.js or index.ts entry point'); } // Validate required metadata fields if (!result.metadata.name) { result.errors?.push('Missing plugin name in metadata'); } if (!result.metadata.version) { result.errors?.push('Missing plugin version in metadata'); } result.isValid = (result.errors?.length || 0) === 0; } catch (error) { result.errors?.push(`Validation error: ${error}`); } return result; } /** * Load a plugin from the specified path */ async loadPlugin(pluginPath) { try { const indexPath = path.join(pluginPath, 'index.js'); const indexTsPath = path.join(pluginPath, 'index.ts'); let entryPoint = indexPath; if (!await fs.pathExists(indexPath) && await fs.pathExists(indexTsPath)) { entryPoint = indexTsPath; } // Dynamic import of the plugin const pluginModule = await Promise.resolve(`${entryPoint}`).then(s => __importStar(require(s))); const plugin = pluginModule.default || pluginModule; // Validate plugin structure if (!plugin.metadata || !plugin.tools) { throw new Error('Invalid plugin structure: missing metadata or tools'); } // Register the plugin this.plugins.set(plugin.metadata.name, plugin); // Register all tools from the plugin for (const tool of plugin.tools) { if (this.tools.has(tool.name)) { this.logger.warn(`Tool '${tool.name}' already exists, skipping from plugin '${plugin.metadata.name}'`); continue; } this.tools.set(tool.name, tool); this.logger.debug(`Registered tool: ${tool.name}`); } this.logger.info(`Loaded plugin: ${plugin.metadata.name} v${plugin.metadata.version}`); } catch (error) { throw new Error(`Failed to load plugin from ${pluginPath}: ${error}`); } } /** * Get all registered tools */ getRegisteredTools() { return Array.from(this.tools.values()); } /** * Get a specific tool by name */ getTool(name) { return this.tools.get(name); } /** * List available tools with optional filtering */ async listTools(typeFilter) { const tools = Array.from(this.tools.values()); return tools .filter(tool => !typeFilter || tool.category === typeFilter) .map(tool => ({ name: tool.name, description: tool.description, category: tool.category })); } /** * Get all loaded plugins */ getLoadedPlugins() { return Array.from(this.plugins.values()); } /** * Reload all plugins */ async reloadPlugins() { this.logger.info('Reloading all plugins...'); // Clear current plugins and tools this.plugins.clear(); this.tools.clear(); // Reload await this.discoverAndLoadPlugins(); } /** * Set plugin directories */ setPluginDirectories(directories) { this.pluginDirectories = directories; } /** * Set disabled plugins */ setDisabledPlugins(plugins) { this.disabledPlugins = plugins; } } exports.PluginManager = PluginManager; //# sourceMappingURL=plugin-manager.js.map