UNPKG

@vooodooo/magic

Version:

Vooodooo - AI orchestration platform

392 lines 14.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PluginManager = void 0; exports.createPluginManager = createPluginManager; const knowledge_system_js_1 = require("../core/knowledge-system.js"); const index_js_1 = require("../index.js"); const extension_registry_js_1 = require("./extension-registry.js"); /** * Manager for Vooodooo plugins */ class PluginManager { constructor(options = {}) { /** Map of plugin ID to plugin instance */ this.plugins = new Map(); /** Plugin configuration storage */ this.config = new Map(); /** Registered CLI commands */ this.commands = new Map(); this.options = { autoEnable: true, config: {}, platformVersion: '0.1.0', ...options, }; // Load initial configuration if (options.config) { for (const [pluginId, pluginConfig] of Object.entries(options.config)) { this.config.set(pluginId, pluginConfig); } } // Initialize extension registry this.extensionRegistry = new extension_registry_js_1.ExtensionRegistry(); // Initialize knowledge system this.knowledgeSystem = new knowledge_system_js_1.KnowledgeSystem(); } /** * Register a plugin with the system */ async registerPlugin(plugin) { const pluginId = plugin.manifest.id; if (this.plugins.has(pluginId)) { throw new Error(`Plugin with ID ${pluginId} is already registered`); } try { // Extract dependencies const dependencies = this.extractDependencies(plugin); // Create API for the plugin const api = { log: this.createLogFunction(pluginId), registerExtension: this.createRegisterExtensionFunction(pluginId), getPlatformVersion: () => this.options.platformVersion || '0.1.0', getConfig: () => this.getPluginConfig(pluginId), setConfig: (config) => this.setPluginConfig(pluginId, config), getKnowledgeSystem: () => this.createKnowledgeSystemAPI(pluginId), registerCommand: (command) => this.registerPluginCommand(pluginId, command), getState: () => this.getPluginState(pluginId), }; // Create plugin instance const pluginInstance = { plugin, state: index_js_1.PluginState.REGISTERED, api, dependencies, dependents: [], }; // Add to registered plugins this.plugins.set(pluginId, pluginInstance); // Update dependents for dependencies for (const depId of dependencies) { const depPlugin = this.plugins.get(depId); if (depPlugin) { depPlugin.dependents.push(pluginId); } } // Auto-enable if configured if (this.options.autoEnable) { await this.enablePlugin(pluginId); } console.log(`Registered plugin: ${plugin.manifest.name} (${pluginId})`); } catch (error) { console.error(`Error registering plugin ${pluginId}:`, error); throw error; } } /** * Enable a plugin */ async enablePlugin(pluginId) { const pluginInstance = this.plugins.get(pluginId); if (!pluginInstance) { throw new Error(`Plugin ${pluginId} is not registered`); } if (pluginInstance.state === index_js_1.PluginState.ACTIVE) { console.log(`Plugin ${pluginId} is already active`); return; } // Check dependencies for (const depId of pluginInstance.dependencies) { if (!this.plugins.has(depId)) { throw new Error(`Plugin ${pluginId} depends on ${depId}, but it is not registered`); } const depPlugin = this.plugins.get(depId); if (depPlugin.state !== index_js_1.PluginState.ACTIVE) { // Enable dependency first await this.enablePlugin(depId); } } try { // Update state to initializing pluginInstance.state = index_js_1.PluginState.INITIALIZING; // Initialize the plugin await pluginInstance.plugin.initialize(pluginInstance.api); // Call onEnable if implemented if (pluginInstance.plugin.onEnable) { await pluginInstance.plugin.onEnable(); } // Update state to active pluginInstance.state = index_js_1.PluginState.ACTIVE; console.log(`Enabled plugin: ${pluginInstance.plugin.manifest.name} (${pluginId})`); } catch (error) { // Update state to error pluginInstance.state = index_js_1.PluginState.ERROR; pluginInstance.error = error; console.error(`Error enabling plugin ${pluginId}:`, error); throw error; } } /** * Disable a plugin */ async disablePlugin(pluginId) { const pluginInstance = this.plugins.get(pluginId); if (!pluginInstance) { throw new Error(`Plugin ${pluginId} is not registered`); } if (pluginInstance.state !== index_js_1.PluginState.ACTIVE) { console.log(`Plugin ${pluginId} is not active`); return; } // Check dependents for (const depId of pluginInstance.dependents) { const depPlugin = this.plugins.get(depId); if (depPlugin && depPlugin.state === index_js_1.PluginState.ACTIVE) { throw new Error(`Cannot disable plugin ${pluginId} because ${depId} depends on it`); } } try { // Call onDisable if implemented if (pluginInstance.plugin.onDisable) { await pluginInstance.plugin.onDisable(); } // Remove all extensions from this plugin this.extensionRegistry.removeExtensionsFromPlugin(pluginId); // Update state to disabled pluginInstance.state = index_js_1.PluginState.DISABLED; console.log(`Disabled plugin: ${pluginInstance.plugin.manifest.name} (${pluginId})`); } catch (error) { // Update state to error pluginInstance.state = index_js_1.PluginState.ERROR; pluginInstance.error = error; console.error(`Error disabling plugin ${pluginId}:`, error); throw error; } } /** * Unregister a plugin from the system */ async unregisterPlugin(pluginId) { const pluginInstance = this.plugins.get(pluginId); if (!pluginInstance) { console.warn(`Plugin ${pluginId} is not registered`); return; } // Check dependents if (pluginInstance.dependents.length > 0) { throw new Error(`Cannot unregister plugin ${pluginId} because other plugins depend on it: ${pluginInstance.dependents.join(', ')}`); } try { // Disable first if active if (pluginInstance.state === index_js_1.PluginState.ACTIVE) { await this.disablePlugin(pluginId); } // Update state to unloading pluginInstance.state = index_js_1.PluginState.UNLOADING; // Clean up the plugin await pluginInstance.plugin.cleanup(); // Remove all extensions from this plugin this.extensionRegistry.removeExtensionsFromPlugin(pluginId); // Remove from dependencies lists for (const depId of pluginInstance.dependencies) { const depPlugin = this.plugins.get(depId); if (depPlugin) { depPlugin.dependents = depPlugin.dependents.filter((id) => id !== pluginId); } } // Remove commands from this plugin for (const [cmdName, cmd] of this.commands.entries()) { if (cmd.pluginId === pluginId) { this.commands.delete(cmdName); } } // Remove the plugin this.plugins.delete(pluginId); console.log(`Unregistered plugin: ${pluginInstance.plugin.manifest.name} (${pluginId})`); } catch (error) { console.error(`Error unregistering plugin ${pluginId}:`, error); throw error; } } /** * Get all registered plugins */ getPlugins() { return Array.from(this.plugins.values()).map((instance) => instance.plugin); } /** * Get plugin state */ getPluginState(pluginId) { const pluginInstance = this.plugins.get(pluginId); return pluginInstance ? pluginInstance.state : index_js_1.PluginState.ERROR; } /** * Get all plugins in a specific state */ getPluginsByState(state) { return Array.from(this.plugins.values()) .filter((instance) => instance.state === state) .map((instance) => instance.plugin); } /** * Get plugin by ID */ getPlugin(pluginId) { const pluginInstance = this.plugins.get(pluginId); return pluginInstance ? pluginInstance.plugin : undefined; } /** * Execute a function on all extensions for a specific extension point */ async executeExtensions(extensionPointId, fn) { return this.extensionRegistry.executeExtensions(extensionPointId, fn); } /** * Get all registered commands */ getCommands() { return Array.from(this.commands.values()); } /** * Get a specific command by name */ getCommand(name) { return this.commands.get(name); } /** * Execute a command */ async executeCommand(name, args, options) { const command = this.commands.get(name); if (!command) { throw new Error(`Command ${name} not found`); } // Ensure plugin is active const pluginId = command.pluginId; if (pluginId && this.getPluginState(pluginId) !== index_js_1.PluginState.ACTIVE) { throw new Error(`Cannot execute command ${name} because plugin ${pluginId} is not active`); } await command.action(args, options); } /** * Extract dependencies from a plugin */ extractDependencies(plugin) { const dependencies = []; if (plugin.manifest.dependencies) { for (const depId of Object.keys(plugin.manifest.dependencies)) { dependencies.push(depId); } } return dependencies; } /** * Create a log function for a plugin */ createLogFunction(pluginId) { return (level, message, data) => { const timestamp = new Date().toISOString(); const logMessage = `[${timestamp}] [${level.toUpperCase()}] [${pluginId}] ${message}`; switch (level) { case 'debug': console.debug(logMessage, data); break; case 'info': console.info(logMessage, data); break; case 'warn': console.warn(logMessage, data); break; case 'error': console.error(logMessage, data); break; } }; } /** * Create a register extension function for a plugin */ createRegisterExtensionFunction(pluginId) { return (extension) => { // Verify plugin is active const pluginInstance = this.plugins.get(pluginId); if (!pluginInstance || pluginInstance.state !== index_js_1.PluginState.ACTIVE) { throw new Error(`Cannot register extension for inactive plugin ${pluginId}`); } this.extensionRegistry.registerExtension(pluginId, extension); }; } /** * Create knowledge system API for a plugin */ createKnowledgeSystemAPI(pluginId) { return { storeKnowledge: (key, data, metadata) => { return this.knowledgeSystem.storeKnowledge(`${pluginId}:${key}`, data, { pluginId, ...metadata, }); }, retrieveKnowledge: (key) => { return this.knowledgeSystem.retrieveKnowledge(`${pluginId}:${key}`); }, contributeToCore: (knowledge, metadata) => { return this.knowledgeSystem.contributeToCore(knowledge, { pluginId, ...metadata, }); }, listKnowledgeKeys: (pattern) => { return this.knowledgeSystem.listKnowledgeKeys(pluginId, pattern); }, }; } /** * Register a CLI command provided by a plugin */ registerPluginCommand(pluginId, command) { // Add pluginId to command const fullCommand = { ...command, pluginId, }; // Check for existing command if (this.commands.has(command.name)) { throw new Error(`Command ${command.name} is already registered`); } this.commands.set(command.name, fullCommand); console.log(`Registered command: ${command.name} from plugin ${pluginId}`); } /** * Get plugin configuration */ getPluginConfig(pluginId) { return this.config.get(pluginId) || {}; } /** * Set plugin configuration */ async setPluginConfig(pluginId, config) { const oldConfig = this.getPluginConfig(pluginId); this.config.set(pluginId, config); // Notify plugin of config change if implemented const pluginInstance = this.plugins.get(pluginId); if (pluginInstance && pluginInstance.state === index_js_1.PluginState.ACTIVE && pluginInstance.plugin.onConfigChange) { await pluginInstance.plugin.onConfigChange(config, oldConfig); } } } exports.PluginManager = PluginManager; /** * Create a plugin manager instance */ function createPluginManager(options) { return new PluginManager(options); } //# sourceMappingURL=plugin-manager.js.map