// --------------------------------------------------------------------------- // Tool Registry -- MCP-like typed tool system // --------------------------------------------------------------------------- import fs from 'fs'; import path from 'path'; export interface ToolParams { url?: string; prompt?: string; input?: string; raw?: string; captures?: string[]; [key: string]: unknown; } export interface ToolResult { transcript?: string; downloadUrl?: string; filename?: string; method?: string; message?: string; mock?: boolean; error?: string; [key: string]: unknown; } export type ProgressEmitter = (message: string) => void; export interface ToolDefinition { name: string; description: string; syntax: string; pattern: RegExp; mock: boolean; execute: (params: ToolParams, emitProgress: ProgressEmitter) => Promise; } export interface ToolSummary { name: string; description: string; syntax: string; mock: boolean; } export interface ToolMatch { tool: ToolDefinition; params: ToolParams; } export class ToolRegistry { private tools = new Map(); register(tool: ToolDefinition): void { if (!tool.name || !tool.execute) { throw new Error('Tool must have a name and execute function.'); } this.tools.set(tool.name, tool); console.log(` [ToolRegistry] Registered: ${tool.name}`); } listTools(): ToolSummary[] { return Array.from(this.tools.values()).map((t) => ({ name: t.name, description: t.description, syntax: t.syntax, mock: t.mock, })); } getTool(name: string): ToolDefinition | null { return this.tools.get(name) ?? null; } matchTool(message: string): ToolMatch | null { for (const tool of this.tools.values()) { if (!tool.pattern) continue; const match = message.match(tool.pattern); if (match) { return { tool, params: { ...match.groups, raw: message, captures: match.slice(1) }, }; } } return null; } } export function setupToolRegistry(): ToolRegistry { const registry = new ToolRegistry(); const toolsDir = path.join(__dirname, 'tools'); if (fs.existsSync(toolsDir)) { const files = fs.readdirSync(toolsDir).filter((f) => f.endsWith('.ts') || f.endsWith('.js')); for (const file of files) { try { const mod = require(path.join(toolsDir, file)); if (typeof mod.register === 'function') { mod.register(registry); } } catch (err: any) { console.error(` [ToolRegistry] Failed to load ${file}: ${err.message}`); } } } return registry; }