UNPKG

@sethdouglasford/claude-flow

Version:

Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology

218 lines 8.11 kB
/** * Claude Flow SPARC Executor * Executes tasks using the full claude-flow SPARC system in non-interactive mode */ import { Logger } from "../core/logger.js"; import { spawn } from "node:child_process"; export class ClaudeFlowExecutor { logger; claudeFlowPath; enableSparc; verbose; timeoutMinutes; constructor(config = {}) { this.logger = config.logger ?? new Logger({ level: "info", format: "text", destination: "console" }, { component: "ClaudeFlowExecutor" }); this.claudeFlowPath = config.claudeFlowPath ?? "/workspaces/claude-code-flow/bin/claude-flow"; this.enableSparc = config.enableSparc ?? true; this.verbose = config.verbose ?? false; this.timeoutMinutes = config.timeoutMinutes ?? 59; } async executeTask(task, agent, targetDir) { this.logger.info("Executing task with Claude Flow SPARC", { taskId: typeof task.id === "string" ? task.id : task.id.id, taskName: task.name, agentType: agent.type, targetDir, }); const startTime = Date.now(); try { // Determine the SPARC mode based on task type and agent type const sparcMode = this.determineSparcMode(task, agent); // Build the command const command = this.buildSparcCommand(task, sparcMode, targetDir); this.logger.info("Executing SPARC command", { mode: sparcMode, command: command.join(" "), }); // Execute the command const result = await this.executeCommand(command); const endTime = Date.now(); const executionTime = endTime - startTime; return { output: result.output, artifacts: result.artifacts || {}, metadata: { sparcMode, command: command.join(" "), exitCode: result.exitCode, }, quality: 0.95, completeness: 0.9, accuracy: 0.85, executionTime, resourcesUsed: { memory: 0, cpu: 0 }, validated: true, error: result.error, }; } catch (error) { this.logger.error("Failed to execute Claude Flow SPARC command", { error: error.message, taskId: typeof task.id === "string" ? task.id : task.id.id, }); return { output: "", artifacts: {}, metadata: {}, quality: 0, completeness: 0, accuracy: 0, executionTime: Date.now() - startTime, resourcesUsed: { memory: 0, cpu: 0 }, validated: false, error: error.message, }; } } determineSparcMode(task, agent) { // Map task types and agent types to SPARC modes const modeMap = { // Task type mappings "coding": "code", "testing": "tdd", "analysis": "spec-pseudocode", "documentation": "docs-writer", "research": "spec-pseudocode", "review": "refinement-optimization-mode", "deployment": "devops", "optimization": "refinement-optimization-mode", "integration": "integration", // Agent type overrides "developer": "code", "tester": "tdd", "analyzer": "spec-pseudocode", "documenter": "docs-writer", "reviewer": "refinement-optimization-mode", "researcher": "spec-pseudocode", "coordinator": "architect", }; // Check for specific keywords in task description const description = task.description.toLowerCase(); if (description.includes("architecture") || description.includes("design")) { return "architect"; } if (description.includes("security")) { return "security-review"; } if (description.includes("debug")) { return "debug"; } if (description.includes("test")) { return "tdd"; } if (description.includes("document")) { return "docs-writer"; } if (description.includes("integrate")) { return "integration"; } // Use agent type first, then task type return modeMap[agent.type] || modeMap[task.type] || "code"; } buildSparcCommand(task, mode, targetDir) { const command = [ this.claudeFlowPath, "sparc", "run", mode, `"${this.formatTaskDescription(task)}"`, ]; // Add options if (targetDir) { command.push("--target-dir", targetDir); } if (this.verbose) { command.push("--verbose"); } // Add non-interactive flag command.push("--non-interactive"); // Add auto-confirm flag command.push("--yes"); return command; } formatTaskDescription(task) { // Format the task description for SPARC command let { description } = task; // If the task has specific instructions, include them if (task.instructions && task.instructions !== task.description) { description = `${task.description}. ${task.instructions}`; } // Add context if available if (task.context?.targetDir) { description += ` in ${String(task.context.targetDir)}`; } return description.replace(/"/g, "\\\""); } async executeCommand(command) { return new Promise((resolve, reject) => { const [cmd, ...args] = command; const proc = spawn(cmd, args, { shell: true, env: { ...process.env, CLAUDE_FLOW_NON_INTERACTIVE: "true", CLAUDE_FLOW_AUTO_CONFIRM: "true", }, }); let stdout = ""; let stderr = ""; const artifacts = {}; proc.stdout.on("data", (data) => { const chunk = data.toString(); stdout += chunk; // Parse artifacts from output const artifactMatch = chunk.match(/Created file: (.+)/g); if (artifactMatch) { artifactMatch.forEach((match) => { const filePath = match.replace("Created file: ", "").trim(); artifacts[filePath] = true; }); } }); proc.stderr.on("data", (data) => { stderr += data.toString(); }); proc.on("close", (code) => { clearTimeout(timeoutId); // Clear timeout when process completes if (code === 0) { resolve({ output: stdout, artifacts, exitCode: code, error: null, }); } else { resolve({ output: stdout, artifacts, exitCode: code, error: stderr || `Command exited with code ${code}`, }); } }); proc.on("error", (err) => { reject(err); }); // Handle timeout - configurable for SPARC operations const timeoutMs = this.timeoutMinutes * 60 * 1000; const timeoutId = setTimeout(() => { proc.kill("SIGTERM"); reject(new Error("Command execution timeout")); }, timeoutMs); }); } } // Export for use in swarm coordinator export default ClaudeFlowExecutor; //# sourceMappingURL=claude-flow-executor.js.map