UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

637 lines (578 loc) 21.7 kB
/** * Plugin Creator Plugin * * A meta-plugin that creates new plugins with various configurations. * Demonstrates all plugin SDK capabilities including tools, hooks, workers, * swarm integration, and security features. * * @example * ```typescript * import { pluginCreatorPlugin } from '@claude-flow/plugins/examples/plugin-creator'; * import { getDefaultRegistry } from '@claude-flow/plugins'; * * await getDefaultRegistry().register(pluginCreatorPlugin); * ``` */ import { PluginBuilder, MCPToolBuilder, HookBuilder, WorkerBuilder, HookEvent, HookPriority, WorkerFactory, Security, type PluginMetadata, type MCPToolDefinition, type HookDefinition, type WorkerDefinition, type AgentTypeDefinition, type IPlugin, } from '../../src/index.js'; // ============================================================================ // Plugin Creator Types // ============================================================================ export interface PluginTemplate { readonly name: string; readonly description: string; readonly category: 'tools' | 'hooks' | 'workers' | 'swarm' | 'full'; readonly features: string[]; } export interface CreatePluginOptions { readonly name: string; readonly version?: string; readonly description?: string; readonly author?: string; readonly template?: string; readonly features?: { tools?: boolean; hooks?: boolean; workers?: boolean; swarm?: boolean; security?: boolean; providers?: boolean; }; readonly toolNames?: string[]; readonly hookEvents?: HookEvent[]; readonly workerTypes?: string[]; readonly agentTypes?: string[]; } export interface GeneratedPlugin { readonly plugin: IPlugin; readonly code: string; readonly metadata: PluginMetadata; } // ============================================================================ // Plugin Templates // ============================================================================ export const PLUGIN_TEMPLATES: Record<string, PluginTemplate> = { 'minimal': { name: 'Minimal Plugin', description: 'A bare-bones plugin with just metadata', category: 'tools', features: [], }, 'tool-plugin': { name: 'Tool Plugin', description: 'Plugin focused on MCP tools', category: 'tools', features: ['tools'], }, 'hooks-plugin': { name: 'Hooks Plugin', description: 'Plugin focused on lifecycle hooks', category: 'hooks', features: ['hooks'], }, 'worker-plugin': { name: 'Worker Plugin', description: 'Plugin with worker pool integration', category: 'workers', features: ['workers'], }, 'swarm-plugin': { name: 'Swarm Plugin', description: 'Plugin with swarm coordination capabilities', category: 'swarm', features: ['swarm', 'workers', 'hooks'], }, 'full-featured': { name: 'Full Featured Plugin', description: 'Complete plugin with all capabilities', category: 'full', features: ['tools', 'hooks', 'workers', 'swarm', 'security', 'providers'], }, 'security-focused': { name: 'Security Focused Plugin', description: 'Plugin with security features and validation', category: 'tools', features: ['tools', 'hooks', 'security'], }, }; // ============================================================================ // Code Generators // ============================================================================ function generateToolCode(toolName: string): { definition: MCPToolDefinition; code: string } { const sanitizedName = Security.validateString(toolName, { pattern: /^[a-z][a-z0-9-]*$/, maxLength: 50, }) ?? 'custom-tool'; const definition: MCPToolDefinition = { name: sanitizedName, description: `Generated tool: ${sanitizedName}`, inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'Input for the tool', }, }, required: ['input'], }, handler: async (params) => ({ content: [{ type: 'text', text: `Tool ${sanitizedName} executed with: ${JSON.stringify(params)}`, }], }), }; const code = ` const ${camelCase(sanitizedName)}Tool = new MCPToolBuilder('${sanitizedName}') .withDescription('Generated tool: ${sanitizedName}') .addStringParam('input', 'Input for the tool', { required: true }) .withHandler(async (params) => ({ content: [{ type: 'text', text: \`Tool ${sanitizedName} executed with: \${JSON.stringify(params)}\` }] })) .build(); `; return { definition, code }; } function generateHookCode(event: HookEvent): { definition: HookDefinition; code: string } { const definition: HookDefinition = { event, priority: HookPriority.Normal, name: `${event}-handler`, description: `Handler for ${event} event`, handler: async (ctx) => { console.log(`Hook triggered: ${event}`, ctx.data); return { success: true }; }, }; const code = ` const ${camelCase(event)}Hook = new HookBuilder(HookEvent.${getEventEnumName(event)}) .withName('${event}-handler') .withDescription('Handler for ${event} event') .withPriority(HookPriority.Normal) .withHandler(async (ctx) => { console.log('Hook triggered: ${event}', ctx.data); return { success: true }; }) .build(); `; return { definition, code }; } function generateWorkerCode(workerType: string): { definition: WorkerDefinition; code: string } { const validTypes = ['coder', 'reviewer', 'tester', 'researcher', 'planner', 'coordinator', 'security', 'performance']; const type = validTypes.includes(workerType) ? workerType : 'specialized'; let definition: WorkerDefinition; let factoryMethod: string; switch (type) { case 'coder': definition = WorkerFactory.createCoder(`${workerType}-worker`); factoryMethod = 'createCoder'; break; case 'reviewer': definition = WorkerFactory.createReviewer(`${workerType}-worker`); factoryMethod = 'createReviewer'; break; case 'tester': definition = WorkerFactory.createTester(`${workerType}-worker`); factoryMethod = 'createTester'; break; case 'researcher': definition = WorkerFactory.createResearcher(`${workerType}-worker`); factoryMethod = 'createResearcher'; break; case 'planner': definition = WorkerFactory.createPlanner(`${workerType}-worker`); factoryMethod = 'createPlanner'; break; case 'coordinator': definition = WorkerFactory.createCoordinator(`${workerType}-worker`); factoryMethod = 'createCoordinator'; break; case 'security': definition = WorkerFactory.createSecurity(`${workerType}-worker`); factoryMethod = 'createSecurity'; break; case 'performance': definition = WorkerFactory.createPerformance(`${workerType}-worker`); factoryMethod = 'createPerformance'; break; default: definition = WorkerFactory.createSpecialized(`${workerType}-worker`, ['custom']); factoryMethod = 'createSpecialized'; } const code = factoryMethod === 'createSpecialized' ? `const ${camelCase(workerType)}Worker = WorkerFactory.${factoryMethod}('${workerType}-worker', ['custom']);` : `const ${camelCase(workerType)}Worker = WorkerFactory.${factoryMethod}('${workerType}-worker');`; return { definition, code }; } function generateAgentTypeCode(agentType: string): { definition: AgentTypeDefinition; code: string } { const sanitizedType = Security.validateString(agentType, { pattern: /^[a-z][a-z0-9-]*$/, maxLength: 50, }) ?? 'custom-agent'; const definition: AgentTypeDefinition = { type: sanitizedType, name: `${sanitizedType} Agent`, description: `Generated agent type: ${sanitizedType}`, capabilities: ['general'], model: 'claude-sonnet-4-6', systemPrompt: `You are a ${sanitizedType} agent.`, }; const code = ` const ${camelCase(sanitizedType)}Agent: AgentTypeDefinition = { type: '${sanitizedType}', name: '${sanitizedType} Agent', description: 'Generated agent type: ${sanitizedType}', capabilities: ['general'], model: 'claude-sonnet-4-6', systemPrompt: 'You are a ${sanitizedType} agent.', }; `; return { definition, code }; } // ============================================================================ // Plugin Generator // ============================================================================ export function generatePlugin(options: CreatePluginOptions): GeneratedPlugin { const { name, version = '1.0.0', description = `Generated plugin: ${name}`, author = 'Plugin Creator', template = 'minimal', features = {}, toolNames = [], hookEvents = [], workerTypes = [], agentTypes = [], } = options; // Validate plugin name const validName = Security.validateString(name, { pattern: /^[a-z][a-z0-9-]*$/, minLength: 3, maxLength: 50, }); if (!validName) { throw new Error('Invalid plugin name. Use lowercase letters, numbers, and hyphens.'); } // Get template features const templateConfig = PLUGIN_TEMPLATES[template] ?? PLUGIN_TEMPLATES['minimal']; const enabledFeatures = { tools: features.tools ?? templateConfig.features.includes('tools'), hooks: features.hooks ?? templateConfig.features.includes('hooks'), workers: features.workers ?? templateConfig.features.includes('workers'), swarm: features.swarm ?? templateConfig.features.includes('swarm'), security: features.security ?? templateConfig.features.includes('security'), providers: features.providers ?? templateConfig.features.includes('providers'), }; // Generate components const tools: MCPToolDefinition[] = []; const hooks: HookDefinition[] = []; const workers: WorkerDefinition[] = []; const agents: AgentTypeDefinition[] = []; const codeBlocks: string[] = []; // Import statements codeBlocks.push(`import { PluginBuilder,${enabledFeatures.tools ? '\n MCPToolBuilder,' : ''}${enabledFeatures.hooks ? '\n HookBuilder,\n HookEvent,\n HookPriority,' : ''}${enabledFeatures.workers ? '\n WorkerFactory,' : ''}${enabledFeatures.security ? '\n Security,' : ''} type IPlugin,${enabledFeatures.workers ? '\n type WorkerDefinition,' : ''}${agents.length > 0 ? '\n type AgentTypeDefinition,' : ''} } from '@claude-flow/plugins'; `); // Generate tools if (enabledFeatures.tools) { const defaultTools = toolNames.length > 0 ? toolNames : ['default-tool']; for (const toolName of defaultTools) { const { definition, code } = generateToolCode(toolName); tools.push(definition); codeBlocks.push(code); } } // Generate hooks if (enabledFeatures.hooks) { const defaultEvents = hookEvents.length > 0 ? hookEvents : [HookEvent.SessionStart, HookEvent.PostTaskComplete]; for (const event of defaultEvents) { const { definition, code } = generateHookCode(event); hooks.push(definition); codeBlocks.push(code); } } // Generate workers if (enabledFeatures.workers) { const defaultWorkers = workerTypes.length > 0 ? workerTypes : ['coder', 'tester']; for (const workerType of defaultWorkers) { const { definition, code } = generateWorkerCode(workerType); workers.push(definition); codeBlocks.push(code); } } // Generate agents (for swarm plugins) if (enabledFeatures.swarm) { const defaultAgents = agentTypes.length > 0 ? agentTypes : ['coordinator', 'worker']; for (const agentType of defaultAgents) { const { definition, code } = generateAgentTypeCode(agentType); agents.push(definition); codeBlocks.push(code); } } // Build the plugin const builder = new PluginBuilder(validName, version) .withDescription(description) .withAuthor(author); if (tools.length > 0) builder.withMCPTools(tools); if (hooks.length > 0) builder.withHooks(hooks); if (workers.length > 0) builder.withWorkers(workers); if (agents.length > 0) builder.withAgentTypes(agents); const plugin = builder.build(); // Generate plugin builder code codeBlocks.push(` // Create the plugin const ${camelCase(validName)}Plugin = new PluginBuilder('${validName}', '${version}') .withDescription('${description}') .withAuthor('${author}')${tools.length > 0 ? ` .withMCPTools([${tools.map(t => camelCase(t.name) + 'Tool').join(', ')}])` : ''}${hooks.length > 0 ? ` .withHooks([${hooks.map(h => camelCase(h.event) + 'Hook').join(', ')}])` : ''}${workers.length > 0 ? ` .withWorkers([${workers.map(w => camelCase(w.name.replace('-worker', '')) + 'Worker').join(', ')}])` : ''}${agents.length > 0 ? ` .withAgentTypes([${agents.map(a => camelCase(a.type) + 'Agent').join(', ')}])` : ''} .build(); export default ${camelCase(validName)}Plugin; `); return { plugin, code: codeBlocks.join('\n'), metadata: plugin.metadata, }; } // ============================================================================ // Helper Functions // ============================================================================ function camelCase(str: string): string { return str .replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase()) .replace(/^./, (chr) => chr.toLowerCase()); } function getEventEnumName(event: HookEvent): string { // Mapping from HookEvent enum values to their TypeScript enum names const mapping: Record<string, string> = { // Tool lifecycle (from types/index.ts HookEvent enum) 'hook:pre-tool-use': 'PreToolUse', 'hook:post-tool-use': 'PostToolUse', // Session lifecycle 'hook:session-start': 'SessionStart', 'hook:session-end': 'SessionEnd', 'hook:session-restore': 'SessionRestore', // Task execution 'hook:pre-task-execute': 'PreTaskExecute', 'hook:post-task-complete': 'PostTaskComplete', 'hook:task-failed': 'TaskFailed', // File operations 'hook:pre-file-write': 'PreFileWrite', 'hook:post-file-write': 'PostFileWrite', 'hook:pre-file-delete': 'PreFileDelete', // Command execution 'hook:pre-command': 'PreCommand', 'hook:post-command': 'PostCommand', // Agent operations 'hook:agent-spawned': 'AgentSpawned', 'hook:agent-terminated': 'AgentTerminated', // Memory operations 'hook:pre-memory-store': 'PreMemoryStore', 'hook:post-memory-store': 'PostMemoryStore', // Learning 'hook:pattern-detected': 'PatternDetected', 'hook:strategy-updated': 'StrategyUpdated', // Plugin lifecycle 'hook:plugin-loaded': 'PluginLoaded', 'hook:plugin-unloaded': 'PluginUnloaded', }; return mapping[event] ?? event; } // ============================================================================ // Plugin Creator Plugin // ============================================================================ /** * The Plugin Creator Plugin itself - demonstrates all capabilities. */ export const pluginCreatorPlugin = new PluginBuilder('plugin-creator', '1.0.0') .withDescription('A meta-plugin that creates new plugins with various configurations') .withAuthor('Claude Flow Team') .withTags(['meta', 'generator', 'developer-tools']) .withMCPTools([ // Tool: Create Plugin new MCPToolBuilder('create-plugin') .withDescription('Create a new plugin with specified options') .addStringParam('name', 'Plugin name (lowercase, hyphens allowed)', { required: true }) .addStringParam('version', 'Plugin version', { default: '1.0.0' }) .addStringParam('description', 'Plugin description') .addStringParam('template', 'Template to use', { enum: Object.keys(PLUGIN_TEMPLATES), default: 'minimal', }) .addBooleanParam('includeTools', 'Include MCP tools', { default: false }) .addBooleanParam('includeHooks', 'Include lifecycle hooks', { default: false }) .addBooleanParam('includeWorkers', 'Include workers', { default: false }) .addBooleanParam('includeSwarm', 'Include swarm capabilities', { default: false }) .withHandler(async (params) => { try { const result = generatePlugin({ name: params.name as string, version: params.version as string, description: params.description as string, template: params.template as string, features: { tools: params.includeTools as boolean, hooks: params.includeHooks as boolean, workers: params.includeWorkers as boolean, swarm: params.includeSwarm as boolean, }, }); return { content: [{ type: 'text', text: `✅ Plugin "${result.metadata.name}" created successfully!\n\n` + `**Metadata:**\n` + `- Name: ${result.metadata.name}\n` + `- Version: ${result.metadata.version}\n` + `- Description: ${result.metadata.description}\n\n` + `**Generated Code:**\n\`\`\`typescript\n${result.code}\n\`\`\``, }], }; } catch (error) { return { content: [{ type: 'text', text: `❌ Error creating plugin: ${error instanceof Error ? error.message : String(error)}`, }], isError: true, }; } }) .build(), // Tool: List Templates new MCPToolBuilder('list-plugin-templates') .withDescription('List available plugin templates') .withHandler(async () => { const templateList = Object.entries(PLUGIN_TEMPLATES) .map(([key, tmpl]) => `- **${key}**: ${tmpl.name}\n ${tmpl.description}\n Features: ${tmpl.features.join(', ') || 'none'}` ) .join('\n\n'); return { content: [{ type: 'text', text: `📦 **Available Plugin Templates:**\n\n${templateList}`, }], }; }) .build(), // Tool: Generate Tool new MCPToolBuilder('generate-tool') .withDescription('Generate a single MCP tool definition') .addStringParam('name', 'Tool name', { required: true }) .addStringParam('description', 'Tool description') .addStringParam('params', 'Comma-separated parameter names') .withHandler(async (params) => { const { definition, code } = generateToolCode(params.name as string); return { content: [{ type: 'text', text: `🔧 **Generated Tool: ${definition.name}**\n\n` + `**Code:**\n\`\`\`typescript\n${code}\n\`\`\``, }], }; }) .build(), // Tool: Generate Hook new MCPToolBuilder('generate-hook') .withDescription('Generate a lifecycle hook definition') .addStringParam('event', 'Hook event type', { required: true, enum: Object.values(HookEvent), }) .addStringParam('priority', 'Hook priority', { enum: ['Critical', 'High', 'Normal', 'Low', 'Deferred'], default: 'Normal', }) .withHandler(async (params) => { const { definition, code } = generateHookCode(params.event as HookEvent); return { content: [{ type: 'text', text: `🎣 **Generated Hook: ${definition.name}**\n\n` + `Event: ${definition.event}\n` + `Priority: ${definition.priority}\n\n` + `**Code:**\n\`\`\`typescript\n${code}\n\`\`\``, }], }; }) .build(), // Tool: Generate Worker new MCPToolBuilder('generate-worker') .withDescription('Generate a worker definition') .addStringParam('type', 'Worker type', { required: true, enum: ['coder', 'reviewer', 'tester', 'researcher', 'planner', 'coordinator', 'security', 'performance', 'specialized'], }) .addStringParam('capabilities', 'Comma-separated capabilities') .withHandler(async (params) => { const { definition, code } = generateWorkerCode(params.type as string); return { content: [{ type: 'text', text: `👷 **Generated Worker: ${definition.name}**\n\n` + `Type: ${definition.type}\n` + `Capabilities: ${definition.capabilities.join(', ')}\n` + `Max Concurrent Tasks: ${definition.maxConcurrentTasks}\n` + `Timeout: ${definition.timeout}ms\n\n` + `**Code:**\n\`\`\`typescript\n${code}\n\`\`\``, }], }; }) .build(), ]) .withHooks([ // Hook: Log plugin creation new HookBuilder(HookEvent.PostToolUse) .withName('plugin-creator-logger') .withDescription('Log plugin creation events') .withPriority(HookPriority.Low) .withHandler(async (ctx) => { const data = ctx.data as { toolName?: string } | undefined; // Only log if this is from the create-plugin tool if (data?.toolName === 'create-plugin') { console.log('[Plugin Creator] Plugin created:', ctx.data); } return { success: true }; }) .build(), ]) .withWorkers([ WorkerFactory.createCoder('plugin-code-generator', ['code-generation', 'typescript']), ]) .onInitialize(async (ctx) => { ctx.logger.info('Plugin Creator initialized'); ctx.logger.info(`Available templates: ${Object.keys(PLUGIN_TEMPLATES).join(', ')}`); }) .build(); // ============================================================================ // Exports // ============================================================================ export default pluginCreatorPlugin; export { generateToolCode, generateHookCode, generateWorkerCode, generateAgentTypeCode, };