UNPKG

claude-flow-tbowman01

Version:

Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)

193 lines 7.84 kB
import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); import * as fs from 'fs/promises'; import * as path from 'path'; import { Worker } from 'worker_threads'; import { PromptCopier } from './prompt-copier.js'; import { logger } from '../core/logger.js'; export class EnhancedPromptCopier extends PromptCopier { workerPool; workerResults = new Map(); constructor(options) { super(options); } async copyFilesParallel() { const workerCount = Math.min(this.options.maxWorkers, this.fileQueue.length); // Initialize worker pool this.workerPool = await this.initializeWorkerPool(workerCount); try { // Process files using worker pool await this.processWithWorkerPool(); } finally { // Cleanup workers await this.terminateWorkers(); } } async initializeWorkerPool(workerCount) { const workers = []; const pool = { workers, busy: new Set(), queue: [], }; // Create workers for (let i = 0; i < workerCount; i++) { const worker = new Worker(path.join(__dirname, 'workers', 'copy-worker.js'), { workerData: { workerId: i }, }); // Setup worker message handler worker.on('message', (result) => { this.handleWorkerResult(result, i, pool); }); worker.on('error', (error) => { logger.error(`Worker ${i} error:`, error); this.errors.push({ file: 'worker', error: error instanceof Error ? error.message : String(error), phase: 'write', }); }); workers.push(worker); } return pool; } async processWithWorkerPool() { const chunkSize = Math.max(1, Math.floor(this.fileQueue.length / this.workerPool.workers.length / 2)); const chunks = []; // Create chunks for better distribution for (let i = 0; i < this.fileQueue.length; i += chunkSize) { chunks.push(this.fileQueue.slice(i, i + chunkSize)); } // Process chunks const promises = []; for (const chunk of chunks) { promises.push(this.processChunkWithWorker(chunk)); } await Promise.all(promises); } async processChunkWithWorker(chunk) { return new Promise((resolve, reject) => { const pool = this.workerPool; const tryAssignWork = () => { // Find available worker const availableWorkerIndex = pool.workers.findIndex((_, index) => !pool.busy.has(index)); if (availableWorkerIndex === -1) { // No workers available, queue the work pool.queue.push(tryAssignWork); return; } // Mark worker as busy pool.busy.add(availableWorkerIndex); // Prepare worker data const workerData = { files: chunk.map((file) => ({ sourcePath: file.path, destPath: path.join(this.options.destination, file.relativePath), permissions: this.options.preservePermissions ? file.permissions : undefined, verify: this.options.verify, })), workerId: availableWorkerIndex, }; let remainingFiles = chunk.length; const chunkResults = []; // Setup temporary message handler for this chunk const messageHandler = (result) => { chunkResults.push(result); remainingFiles--; if (remainingFiles === 0) { // Chunk complete pool.workers[availableWorkerIndex].off('message', messageHandler); pool.busy.delete(availableWorkerIndex); // Process next queued work if (pool.queue.length > 0) { const nextWork = pool.queue.shift(); nextWork(); } // Process results this.processChunkResults(chunk, chunkResults); resolve(); } }; pool.workers[availableWorkerIndex].on('message', messageHandler); pool.workers[availableWorkerIndex].postMessage(workerData); }; tryAssignWork(); }); } processChunkResults(chunk, results) { for (const result of results) { if (result.success) { this.copiedFiles.add(result.file); if (result.hash) { this.workerResults.set(result.file, { hash: result.hash }); } } else { this.errors.push({ file: result.file, error: result.error, phase: 'write', }); } } // Report progress through the callback if available if (this.options.progressCallback) { this.options.progressCallback(this.copiedFiles.size, this.totalFiles); } } handleWorkerResult(result, workerId, pool) { // This is a fallback handler, actual handling happens in processChunkWithWorker logger.debug(`Worker ${workerId} result:`, result); } async terminateWorkers() { if (!this.workerPool) return; const terminationPromises = this.workerPool.workers.map((worker) => worker.terminate()); await Promise.all(terminationPromises); this.workerPool = undefined; } // Override verification to use worker results async verifyFiles() { logger.info('Verifying copied files...'); for (const file of this.fileQueue) { if (!this.copiedFiles.has(file.path)) continue; try { const destPath = path.join(this.options.destination, file.relativePath); // Verify file exists if (!(await this.fileExists(destPath))) { throw new Error('Destination file not found'); } // Verify size const destStats = await fs.stat(destPath); const sourceStats = await fs.stat(file.path); if (destStats.size !== sourceStats.size) { throw new Error(`Size mismatch: ${destStats.size} != ${sourceStats.size}`); } // Use hash from worker if available const workerResult = this.workerResults.get(file.path); if (workerResult?.hash) { const sourceHash = await this.calculateFileHash(file.path); if (sourceHash !== workerResult.hash) { throw new Error(`Hash mismatch: ${sourceHash} != ${workerResult.hash}`); } } } catch (error) { this.errors.push({ file: file.path, error: error instanceof Error ? error.message : String(error), phase: 'verify', }); } } } } // Export enhanced copy function export async function copyPromptsEnhanced(options) { const copier = new EnhancedPromptCopier(options); return copier.copy(); } //# sourceMappingURL=prompt-copier-enhanced.js.map