UNPKG

kist

Version:

Lightweight Package Pipeline Processor with Plugin Architecture

185 lines (163 loc) 6.65 kB
// ============================================================================ // Import // ============================================================================ import { AbstractProcess } from "./core/abstract/AbstractProcess.js"; import { ConfigStore } from "./core/config/ConfigStore.js"; import { ActionRegistry } from "./core/pipeline/ActionRegistry.js"; import { PipelineManager } from "./core/pipeline/PipelineManager.js"; import { PluginManager } from "./core/plugin/PluginManager.js"; import { LiveServer } from "./live/LiveServer.js"; import { LiveWatcher } from "./live/LiveWatcher.js"; // ============================================================================ // Class // ============================================================================ /** * The Kist class encapsulates the kist CLI functionality. * It manages the pipeline execution, configuration loading, and live reload. */ export class Kist extends AbstractProcess { // Constructor // ======================================================================== /** * Constructs the Kist class instance and initializes necessary components. */ constructor() { super(); this.logDebug("Kist initialized."); } // Methods // ======================================================================== /** * Executes the Kist workflow. * * This method orchestrates the execution of the Kist pipeline, starting * from initializing the ActionRegistry, loading configuration settings, * running the pipeline stages through the `PipelineManager`, and * optionally enabling live reload for real-time updates. * * @returns {Promise<void>} Resolves when the workflow completes successfully. * @example * const Kist = new Kist(); * Kist.run().then(() => console.log("Pipeline execution complete.")); */ public async run(): Promise<void> { this.logInfo("Starting Kist workflow..."); try { // Initialize the ActionRegistry with available actions await this.initializeActionRegistry(); // Create and run the PipelineManager const liveReloadEnabled = ConfigStore.getInstance().get<boolean>( "options.live.enabled", ); const liveReloadServer = liveReloadEnabled ? new LiveServer() : null; const pipelineManager = new PipelineManager(liveReloadServer!); await pipelineManager.runPipeline(); // Setup live reload if enabled if (liveReloadEnabled) { this.setupLiveReload(pipelineManager, liveReloadServer!); } } catch (error) { this.handleError(error); } } /** * Initializes the ActionRegistry with available actions. * Automatically registers core actions and discovers external plugins. */ private async initializeActionRegistry(): Promise<void> { this.logInfo("Initializing plugin system..."); // Initialize and discover plugins first const pluginManager = PluginManager.getInstance(); await pluginManager.discoverPlugins({ pluginPrefixes: ["@getkist/action-", "kist-plugin-"], }); // Log loaded plugins const plugins = pluginManager.getLoadedPlugins(); if (plugins.length > 0) { this.logInfo(`Loaded ${plugins.length} plugin(s):`); plugins.forEach((plugin) => { this.logInfo( ` - ${plugin.name} v${plugin.version} (${plugin.actions.length} actions)`, ); }); } else { this.logDebug("No external plugins found."); } // Initialize ActionRegistry (will register core + plugin actions) this.logInfo("Initializing ActionRegistry..."); ActionRegistry.initialize(); this.logInfo("ActionRegistry initialized successfully."); } /** * Sets up live reload functionality. * Monitors file changes and restarts the pipeline when updates are detected. * * @param pipelineManager - The manager responsible for the pipeline process. * @param liveReloadServer - The server for live reload connections. */ private setupLiveReload( pipelineManager: PipelineManager, liveReloadServer: LiveServer, ): void { this.logInfo("Enabling live reload functionality..."); new LiveWatcher((filePath) => { this.logInfo( `Detected change in: ${filePath}. Restarting pipeline...`, ); pipelineManager.restartPipelineWithDelay(500); }); pipelineManager.restartPipeline(); this.registerShutdownHandlers(pipelineManager, liveReloadServer); } /** * Registers handlers for graceful shutdown signals. * * @param pipelineManager - The manager responsible for the pipeline process. * @param liveReloadServer - The server for live reload connections. */ private registerShutdownHandlers( pipelineManager: PipelineManager, liveReloadServer: LiveServer, ): void { process.on("SIGINT", () => this.handleShutdown(pipelineManager, liveReloadServer), ); process.on("SIGTERM", () => this.handleShutdown(pipelineManager, liveReloadServer), ); } /** * Handles graceful shutdown of the pipeline and live reload server. * * @param pipelineManager - The manager responsible for the pipeline process. * @param liveReloadServer - The server for live reload connections. */ private async handleShutdown( pipelineManager: PipelineManager, liveReloadServer: LiveServer, ): Promise<void> { this.logInfo("Shutdown signal received. Shutting down..."); try { await pipelineManager.stopPipeline(); await liveReloadServer.shutdown(); this.logInfo("Shutdown completed successfully."); } catch (error) { this.logError("Error during shutdown.", error); } finally { process.exit(0); } } /** * Handles errors occurring during the execution of the Kist workflow. * * @param error - The error object to log and handle. */ private handleError(error: unknown): void { const errorMessage = error instanceof Error ? error.message : String(error); this.logError(`An error occurred: ${errorMessage}`, error); process.exit(1); } }