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
text/typescript
/**
* 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,
};