/** * AI Task Registry * * Simple registry pattern for AI tasks. Each task has: * - id: Unique identifier * - run: Async function that executes the task * * This allows adding new AI capabilities without modifying core code. */ const { createNameValidationTask, TASK_ID: NAME_TASK_ID } = require('./nameValidationTask'); const { createDescriptionValidationTask, TASK_ID: DESC_TASK_ID } = require('./descriptionValidationTask'); const { createSanityCheckTask, TASK_ID: SANITY_TASK_ID } = require('./sanityCheckTask'); /** * Task IDs - frozen constants for type safety */ const TASK_IDS = Object.freeze({ // Inline validation (triggered on field blur) VALIDATE_NAME: NAME_TASK_ID, VALIDATE_DESCRIPTION: DESC_TASK_ID, // Batch operations (triggered on user action) SANITY_CHECK: SANITY_TASK_ID }); /** * Task Registry */ class TaskRegistry { constructor() { this.tasks = new Map(); } /** * Register a task * @param {Object} task * @param {string} task.id - Unique task identifier * @param {Function} task.run - Async function: (payload) => result * @param {string} [task.description] - Human-readable description */ register(task) { if (!task?.id) { throw new Error('Task must have an id'); } if (typeof task.run !== 'function') { throw new Error(`Task ${task.id} must have a run function`); } if (this.tasks.has(task.id)) { throw new Error(`Task ${task.id} is already registered`); } this.tasks.set(task.id, task); return this; } /** * Get a task by ID * @param {string} taskId * @returns {Object|null} */ get(taskId) { return this.tasks.get(taskId) || null; } /** * Check if a task exists * @param {string} taskId * @returns {boolean} */ has(taskId) { return this.tasks.has(taskId); } /** * Run a task by ID * @param {string} taskId * @param {Object} payload - Task-specific input * @returns {Promise} Task result */ async runTask(taskId, payload = {}) { const task = this.get(taskId); if (!task) { throw new Error(`Unknown task: ${taskId}`); } try { const result = await task.run(payload); return { success: true, taskId, ...result }; } catch (error) { return { success: false, taskId, error: error.message, code: error.code }; } } /** * List all registered task IDs * @returns {string[]} */ list() { return Array.from(this.tasks.keys()); } /** * Get count of registered tasks * @returns {number} */ size() { return this.tasks.size; } } // Singleton instance let registry = null; /** * Get or create the task registry * @returns {TaskRegistry} */ function getRegistry() { if (!registry) { registry = new TaskRegistry(); } return registry; } /** * Reset the registry (mainly for testing) */ function resetRegistry() { registry = null; } /** * Register all validation tasks with the registry * Call this during initialization after the registry is created * * @param {Object} [logger] - Optional logger */ function registerAllTasks(logger = console) { const reg = getRegistry(); // Register name validation if (!reg.has(TASK_IDS.VALIDATE_NAME)) { reg.register(createNameValidationTask()); logger.info(`[Tasks] Registered: ${TASK_IDS.VALIDATE_NAME}`); } // Register description validation if (!reg.has(TASK_IDS.VALIDATE_DESCRIPTION)) { reg.register(createDescriptionValidationTask()); logger.info(`[Tasks] Registered: ${TASK_IDS.VALIDATE_DESCRIPTION}`); } // Register sanity check if (!reg.has(TASK_IDS.SANITY_CHECK)) { reg.register(createSanityCheckTask()); logger.info(`[Tasks] Registered: ${TASK_IDS.SANITY_CHECK}`); } return reg; } module.exports = { // Constants TASK_IDS, // Registry TaskRegistry, getRegistry, resetRegistry, registerAllTasks, // Task factories (for custom registration) createNameValidationTask, createDescriptionValidationTask, createSanityCheckTask };