Files
metabuilder/workflow/executor/ts/registry/node-executor-registry.ts
johndoe6345789 c670b8f911 refactor: Move core engine into executor/ts
The TypeScript core engine now lives inside executor/ts/ alongside the
TypeScript runtime, creating a cleaner structure where each executor
folder is self-contained.

Structure:
  executor/ts/         # TypeScript runtime + core engine
    ├── executor/      # DAG executor
    ├── registry/      # Plugin registry
    ├── utils/         # Priority queue, template engine
    ├── types.ts       # Type definitions
    └── index.ts       # Main exports
  executor/python/     # Python runtime
  executor/cpp/        # C++ runtime (Phase 3)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 16:10:33 +00:00

154 lines
3.5 KiB
TypeScript

/**
* Node Executor Registry & Plugin System
* Manages dynamic loading and registration of node executors
*/
import { INodeExecutor, WorkflowNode, WorkflowContext, ExecutionState, NodeResult } from '../types';
export interface NodeExecutorPlugin {
nodeType: string;
version: string;
executor: INodeExecutor;
metadata?: {
description?: string;
category?: string;
icon?: string;
author?: string;
};
}
export class NodeExecutorRegistry {
private executors: Map<string, INodeExecutor> = new Map();
private plugins: Map<string, NodeExecutorPlugin> = new Map();
/**
* Register a node executor
*/
register(nodeType: string, executor: INodeExecutor, plugin?: NodeExecutorPlugin): void {
if (this.executors.has(nodeType)) {
console.warn(`Overwriting existing executor for node type: ${nodeType}`);
}
this.executors.set(nodeType, executor);
if (plugin) {
this.plugins.set(nodeType, plugin);
console.log(`Registered plugin: ${plugin.nodeType} v${plugin.version}`);
}
}
/**
* Register multiple executors at once
*/
registerBatch(
executors: Array<{ nodeType: string; executor: INodeExecutor; plugin?: NodeExecutorPlugin }>
): void {
executors.forEach(({ nodeType, executor, plugin }) => {
this.register(nodeType, executor, plugin);
});
}
/**
* Get executor for node type
*/
get(nodeType: string): INodeExecutor | undefined {
return this.executors.get(nodeType);
}
/**
* Check if executor exists
*/
has(nodeType: string): boolean {
return this.executors.has(nodeType);
}
/**
* List all registered executors
*/
listExecutors(): string[] {
return Array.from(this.executors.keys());
}
/**
* List all registered plugins
*/
listPlugins(): NodeExecutorPlugin[] {
return Array.from(this.plugins.values());
}
/**
* Get plugin metadata
*/
getPluginInfo(nodeType: string): NodeExecutorPlugin | undefined {
return this.plugins.get(nodeType);
}
/**
* Execute node with registered executor
*/
async execute(
nodeType: string,
node: WorkflowNode,
context: WorkflowContext,
state: ExecutionState
): Promise<NodeResult> {
const executor = this.get(nodeType);
if (!executor) {
throw new Error(`No executor registered for node type: ${nodeType}`);
}
// Validate node before execution
const validation = executor.validate(node);
if (!validation.valid) {
throw new Error(`Node validation failed: ${validation.errors.join(', ')}`);
}
// Log warnings if any
if (validation.warnings.length > 0) {
console.warn(`Node validation warnings for ${node.id}:`, validation.warnings);
}
// Execute node
return await executor.execute(node, context, state);
}
/**
* Unregister an executor
*/
unregister(nodeType: string): boolean {
const had = this.executors.has(nodeType);
this.executors.delete(nodeType);
this.plugins.delete(nodeType);
return had;
}
/**
* Clear all registered executors
*/
clear(): void {
this.executors.clear();
this.plugins.clear();
}
}
/**
* Global registry singleton
*/
let globalRegistry: NodeExecutorRegistry | null = null;
export function getNodeExecutorRegistry(): NodeExecutorRegistry {
if (!globalRegistry) {
globalRegistry = new NodeExecutorRegistry();
}
return globalRegistry;
}
export function setNodeExecutorRegistry(registry: NodeExecutorRegistry): void {
globalRegistry = registry;
}
export function resetNodeExecutorRegistry(): void {
globalRegistry = null;
}