UNPKG

@stackmemoryai/stackmemory

Version:

Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.

1,012 lines (1,010 loc) 43.5 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { Command } from "commander"; import { logger } from "../../core/monitoring/logger.js"; import { RalphLoop } from "../../../scripts/ralph-loop-implementation.js"; import { stackMemoryContextLoader } from "../../integrations/ralph/context/stackmemory-context-loader.js"; import { patternLearner } from "../../integrations/ralph/learning/pattern-learner.js"; import { multiLoopOrchestrator } from "../../integrations/ralph/orchestration/multi-loop-orchestrator.js"; import { swarmCoordinator } from "../../integrations/ralph/swarm/swarm-coordinator.js"; import { ralphDebugger } from "../../integrations/ralph/visualization/ralph-debugger.js"; import { existsSync, readFileSync, writeFileSync } from "fs"; import { trace } from "../../core/trace/index.js"; import { SystemError, ErrorCode } from "../../core/errors/index.js"; function createRalphCommand() { const ralph = new Command("ralph").description( "Ralph Wiggum Loop integration with StackMemory" ); ralph.command("init").description("Initialize a new Ralph Wiggum loop").argument("<task>", "Task description").option( "-c, --criteria <criteria>", "Completion criteria (comma separated)" ).option("--max-iterations <n>", "Maximum iterations", "50").option("--use-context", "Load relevant context from StackMemory").option( "--learn-from-similar", "Apply patterns from similar completed tasks" ).action(async (task, options) => { return trace.command("ralph-init", { task, ...options }, async () => { try { console.log("\u{1F3AD} Initializing Ralph Wiggum loop..."); const loop = new RalphLoop({ baseDir: ".ralph", maxIterations: parseInt(options.maxIterations), verbose: true }); const criteria = options.criteria ? options.criteria.split(",").map((c) => `- ${c.trim()}`).join("\n") : "- All tests pass\n- Code works correctly\n- No lint errors"; let enhancedTask = task; if (options.useContext || options.learnFromSimilar) { try { await stackMemoryContextLoader.initialize(); const contextResponse = await stackMemoryContextLoader.loadInitialContext({ task, usePatterns: true, useSimilarTasks: options.learnFromSimilar, maxTokens: 3e3 }); if (contextResponse.context) { enhancedTask = `${task} ${contextResponse.context}`; console.log( `\u{1F4DA} Loaded context from ${contextResponse.sources.length} sources` ); console.log( `\u{1F3AF} Context tokens: ${contextResponse.metadata.totalTokens}` ); } } catch (error) { console.log( `\u26A0\uFE0F Context loading failed: ${error.message}` ); console.log("Proceeding without context..."); } } await loop.initialize(enhancedTask, criteria); console.log("\u2705 Ralph loop initialized!"); console.log(`\u{1F4CB} Task: ${task}`); console.log(`\u{1F3AF} Max iterations: ${options.maxIterations}`); console.log(`\u{1F4C1} Loop directory: .ralph/`); console.log("\nNext steps:"); console.log(" stackmemory ralph run # Start the loop"); console.log(" stackmemory ralph status # Check status"); } catch (error) { logger.error("Failed to initialize Ralph loop", error); console.error("\u274C Initialization failed:", error.message); process.exit(1); } }); }); ralph.command("run").description("Run the Ralph Wiggum loop").option("--verbose", "Verbose output").option("--pause-on-error", "Pause on validation errors").action(async (options) => { return trace.command("ralph-run", options, async () => { try { if (!existsSync(".ralph")) { console.error( '\u274C No Ralph loop found. Run "stackmemory ralph init" first.' ); return; } console.log("\u{1F3AD} Starting Ralph Wiggum loop..."); const loop = new RalphLoop({ baseDir: ".ralph", verbose: options.verbose }); await loop.run(); } catch (error) { logger.error("Failed to run Ralph loop", error); console.error("\u274C Loop execution failed:", error.message); process.exit(1); } }); }); ralph.command("status").description("Show current Ralph loop status").option("--detailed", "Show detailed iteration history").action(async (options) => { return trace.command("ralph-status", options, async () => { try { if (!existsSync(".ralph")) { console.log("\u274C No Ralph loop found in current directory"); return; } const task = readFileSync(".ralph/task.md", "utf8"); const iteration = parseInt( readFileSync(".ralph/iteration.txt", "utf8") || "0" ); const isComplete = existsSync(".ralph/work-complete.txt"); const feedback = existsSync(".ralph/feedback.txt") ? readFileSync(".ralph/feedback.txt", "utf8") : ""; console.log("\u{1F3AD} Ralph Loop Status:"); console.log(` Task: ${task.substring(0, 80)}...`); console.log(` Iteration: ${iteration}`); console.log( ` Status: ${isComplete ? "\u2705 COMPLETE" : "\u{1F504} IN PROGRESS"}` ); if (feedback) { console.log(` Last feedback: ${feedback.substring(0, 100)}...`); } if (options.detailed && existsSync(".ralph/progress.jsonl")) { console.log("\n\u{1F4CA} Iteration History:"); const progressLines = readFileSync(".ralph/progress.jsonl", "utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line)); progressLines.forEach((p) => { const progress = p; const status = progress.validation?.testsPass ? "\u2705" : "\u274C"; console.log( ` ${progress.iteration}: ${status} ${progress.changes} changes, ${progress.errors} errors` ); }); } } catch (error) { logger.error("Failed to get Ralph status", error); console.error("\u274C Status check failed:", error.message); } }); }); ralph.command("resume").description("Resume a crashed or paused Ralph loop").option("--from-stackmemory", "Restore from StackMemory backup").action(async (options) => { return trace.command("ralph-resume", options, async () => { try { console.log("\u{1F504} Resuming Ralph loop..."); const loop = new RalphLoop({ baseDir: ".ralph", verbose: true }); if (options.fromStackmemory) { console.log("\u{1F4DA} StackMemory restore feature coming soon..."); } await loop.run(); } catch (error) { logger.error("Failed to resume Ralph loop", error); console.error("\u274C Resume failed:", error.message); process.exit(1); } }); }); ralph.command("stop").description("Stop the current Ralph loop").option("--save-progress", "Save current progress to StackMemory").action(async (options) => { return trace.command("ralph-stop", options, async () => { try { if (!existsSync(".ralph")) { console.log("\u274C No active Ralph loop found"); return; } console.log("\u{1F6D1} Stopping Ralph loop..."); if (options.saveProgress) { console.log("\u{1F4BE} StackMemory progress save feature coming soon..."); } writeFileSync(".ralph/stop-signal.txt", (/* @__PURE__ */ new Date()).toISOString()); console.log("\u2705 Stop signal sent"); } catch (error) { logger.error("Failed to stop Ralph loop", error); console.error("\u274C Stop failed:", error.message); } }); }); ralph.command("clean").description("Clean up Ralph loop artifacts").option("--keep-history", "Keep iteration history").action(async (options) => { return trace.command("ralph-clean", options, async () => { try { if (!options.keepHistory && existsSync(".ralph/history")) { const { execSync } = await import("child_process"); execSync("rm -rf .ralph/history"); } if (existsSync(".ralph/work-complete.txt")) { const fs = await import("fs"); fs.unlinkSync(".ralph/work-complete.txt"); } console.log("\u{1F9F9} Ralph loop artifacts cleaned"); } catch (error) { logger.error("Failed to clean Ralph artifacts", error); console.error("\u274C Cleanup failed:", error.message); } }); }); ralph.command("debug").description("Debug Ralph loop state and diagnostics").option("--reconcile", "Force state reconciliation").option("--validate-context", "Validate context budget").action(async (options) => { return trace.command("ralph-debug", options, async () => { try { console.log("\u{1F50D} Ralph Loop Debug Information:"); if (options.reconcile) { console.log("\u{1F527} State reconciliation feature coming soon..."); } if (options.validateContext) { console.log("\u{1F4CA} Context validation feature coming soon..."); } if (existsSync(".ralph")) { console.log("\n\u{1F4C1} Ralph directory structure:"); const { execSync } = await import("child_process"); try { const tree = execSync("find .ralph -type f | head -20", { encoding: "utf8" }); console.log(tree); } catch { console.log(" (Unable to show directory tree)"); } } } catch (error) { logger.error("Ralph debug failed", error); console.error("\u274C Debug failed:", error.message); } }); }); ralph.command("swarm").description("Launch a swarm of specialized agents").argument("<project>", "Project description").option( "--agents <agents>", "Comma-separated list of agent roles (architect,developer,tester,etc)", "developer,tester" ).option("--max-agents <n>", "Maximum number of agents", "5").action(async (project, options) => { return trace.command("ralph-swarm", { project, ...options }, async () => { try { console.log("\u{1F9BE} Launching Ralph swarm..."); await swarmCoordinator.initialize(); const agentRoles = options.agents.split(",").map((r) => r.trim()); const agentSpecs = agentRoles.map((role) => ({ role, conflictResolution: "defer_to_expertise", collaborationPreferences: [] })); const swarmId = await swarmCoordinator.launchSwarm( project, agentSpecs ); console.log(`\u2705 Swarm launched with ID: ${swarmId}`); console.log(`\u{1F465} ${agentSpecs.length} agents working on: ${project}`); console.log("\nNext steps:"); console.log( " stackmemory ralph swarm-status <swarmId> # Check progress" ); console.log( " stackmemory ralph swarm-stop <swarmId> # Stop swarm" ); } catch (error) { logger.error("Swarm launch failed", error); console.error("\u274C Swarm launch failed:", error.message); } }); }); ralph.command("swarm-status").description("Check status of all active swarms or a specific swarm").argument("[swarmId]", "Optional specific swarm ID to check").option("--detailed", "Show detailed agent information").action(async (swarmId, options) => { return trace.command( "ralph-swarm-status", { swarmId, ...options }, async () => { try { await swarmCoordinator.initialize(); if (swarmId) { const status = swarmCoordinator.getSwarmStatus(swarmId); if (!status) { console.log(`\u274C Swarm ${swarmId} not found`); return; } console.log(`\u{1F9BE} Swarm Status: ${swarmId}`); console.log(` Status: ${status.state}`); console.log(` Agents: ${status.activeAgents} active`); console.log( ` Started: ${new Date(status.startTime).toLocaleString()}` ); if (options.detailed && status.agents) { console.log("\n\u{1F465} Agent Details:"); status.agents.forEach((agent) => { console.log( ` - ${agent.role}: ${agent.status} (${agent.task})` ); }); } } else { const activeSwarms = swarmCoordinator.getAllActiveSwarms(); if (activeSwarms.length === 0) { console.log("\u{1F4CA} No active swarms"); return; } console.log(`\u{1F4CA} Active Swarms: ${activeSwarms.length}`); activeSwarms.forEach((swarm) => { console.log(` \u{1F194} ${swarm.id}`); console.log( ` Description: ${swarm.description?.substring(0, 60)}...` ); console.log(` Agents: ${swarm.agentCount}`); console.log(` Status: ${swarm.status}`); console.log( ` Running for: ${Math.round((Date.now() - swarm.startTime) / 1e3)}s` ); }); console.log("\nCommands:"); console.log( " stackmemory ralph swarm-status <id> # Check specific swarm" ); console.log( " stackmemory ralph swarm-killall # Stop all swarms" ); } } catch (error) { logger.error("Failed to get swarm status", error); console.error("\u274C Status check failed:", error.message); } } ); }); ralph.command("oracle-worker").description( "Launch Oracle/Worker pattern swarm for cost-effective execution" ).argument("<project>", "Project description for Oracle planning").option( "--oracle <model>", "Oracle model (default: claude-3-opus)", "claude-3-opus-20240229" ).option( "--workers <models>", "Comma-separated worker models", "claude-3-5-haiku-20241022" ).option("--budget <amount>", "Cost budget in USD", "10.0").option("--max-workers <count>", "Maximum worker agents", "5").option("--hints <hints>", "Comma-separated planning hints").action(async (project, options) => { return trace.command( "ralph-oracle-worker", { project, ...options }, async () => { try { console.log("\u{1F9E0} Launching Oracle/Worker swarm..."); console.log(`\u{1F4CB} Project: ${project}`); console.log(`\u{1F4B0} Budget: $${options.budget}`); const { OracleWorkerCoordinator, defaultModelConfigs } = await import("../../../integrations/ralph/patterns/oracle-worker-pattern.js"); const workerModels = options.workers.split(",").map((model) => { const found = defaultModelConfigs.worker.find( (w) => w.model.includes(model.trim()) ); return found || defaultModelConfigs.worker[0]; }); const coordinator = new OracleWorkerCoordinator({ oracle: defaultModelConfigs.oracle[0], workers: workerModels, reviewers: defaultModelConfigs.reviewer, maxWorkers: parseInt(options.maxWorkers), coordinationInterval: 3e4, costBudget: parseFloat(options.budget) }); await coordinator.initialize(); const hints = options.hints ? options.hints.split(",").map((h) => h.trim()) : void 0; const swarmId = await coordinator.launchOracleWorkerSwarm( project, hints ); console.log(`\u2705 Oracle/Worker swarm launched: ${swarmId}`); console.log("\n\u{1F4CA} Pattern Benefits:"); console.log(" \u2022 Oracle handles strategic planning & review"); console.log(" \u2022 Workers execute parallelizable tasks"); console.log(" \u2022 Cost-optimized model selection"); console.log(" \u2022 Scalable multi-agent coordination"); console.log("\nNext steps:"); console.log( ` stackmemory ralph swarm-status ${swarmId} # Check progress` ); console.log( ` stackmemory ralph swarm-stop ${swarmId} # Stop swarm` ); } catch (error) { logger.error("Oracle/Worker swarm failed", error); console.error(`\u274C Oracle/Worker failed: ${error.message}`); throw error; } } ); }); ralph.command("claude-swarm").description("Launch swarm using Claude Code specialized agents").argument("<project>", "Project description for Claude Code agents").option( "--oracle <agent>", "Oracle agent (default: staff-architect)", "staff-architect" ).option( "--workers <agents>", "Comma-separated worker agents", "general-purpose,code-reviewer" ).option( "--reviewers <agents>", "Comma-separated reviewer agents", "code-reviewer" ).option("--budget <amount>", "Cost budget in USD", "10.0").option( "--complexity <level>", "Project complexity (low|medium|high|very_high)", "medium" ).option("--list-agents", "List available Claude Code agents").action(async (project, options) => { return trace.command( "ralph-claude-swarm", { project, ...options }, async () => { try { const { ClaudeCodeAgentBridge, CLAUDE_CODE_AGENTS } = await import("../../integrations/claude-code/agent-bridge.js"); if (options.listAgents) { console.log("\n\u{1F916} Available Claude Code Agents:\n"); const oracles = Object.values(CLAUDE_CODE_AGENTS).filter( (a) => a.type === "oracle" ); const workers = Object.values(CLAUDE_CODE_AGENTS).filter( (a) => a.type === "worker" ); const reviewers = Object.values(CLAUDE_CODE_AGENTS).filter( (a) => a.type === "reviewer" ); console.log("\u{1F9E0} ORACLE AGENTS (Strategic Planning):"); oracles.forEach((agent) => { console.log(` ${agent.name}: ${agent.description}`); console.log( ` Capabilities: ${agent.capabilities.slice(0, 3).join(", ")}...` ); }); console.log("\n\u26A1 WORKER AGENTS (Task Execution):"); workers.forEach((agent) => { console.log(` ${agent.name}: ${agent.description}`); console.log( ` Capabilities: ${agent.capabilities.slice(0, 3).join(", ")}...` ); }); console.log("\n\u{1F50D} REVIEWER AGENTS (Quality Assurance):"); reviewers.forEach((agent) => { console.log(` ${agent.name}: ${agent.description}`); console.log( ` Capabilities: ${agent.capabilities.slice(0, 3).join(", ")}...` ); }); console.log("\nUsage Examples:"); console.log( ' stackmemory ralph claude-swarm "Build REST API" --oracle staff-architect --workers general-purpose,debugger' ); console.log( ' stackmemory ralph claude-swarm "Add user auth" --complexity high --workers general-purpose,qa-workflow-validator' ); return; } console.log("\u{1F9E0} Launching Claude Code Agent Swarm..."); console.log(`\u{1F4CB} Project: ${project}`); console.log(`\u{1F3AF} Oracle: ${options.oracle}`); console.log(`\u26A1 Workers: ${options.workers}`); console.log(`\u{1F50D} Reviewers: ${options.reviewers}`); console.log(`\u{1F4B0} Budget: $${options.budget}`); console.log(`\u{1F4CA} Complexity: ${options.complexity}`); const bridge = new ClaudeCodeAgentBridge(); await bridge.initialize(); const workerAgents = options.workers.split(",").map((s) => s.trim()); const reviewerAgents = options.reviewers.split(",").map((s) => s.trim()); const swarmId = await bridge.launchClaudeCodeSwarm(project, { oracleAgent: options.oracle, workerAgents, reviewerAgents, budget: parseFloat(options.budget), complexity: options.complexity }); console.log(`\u2705 Claude Code swarm launched: ${swarmId}`); console.log("\n\u{1F4CA} Claude Code Benefits:"); console.log(" \u2022 Specialized agents with proven capabilities"); console.log(" \u2022 Seamless integration with Claude Code tools"); console.log(" \u2022 Optimal agent selection for each task type"); console.log(" \u2022 Built-in quality assurance and review processes"); console.log("\nActive Agents:"); console.log(` \u{1F9E0} Oracle: ${options.oracle} (strategic planning)`); workerAgents.forEach((agent) => { const agentConfig = CLAUDE_CODE_AGENTS[agent]; console.log( ` \u26A1 Worker: ${agent} (${agentConfig?.specializations.join(", ") || "execution"})` ); }); reviewerAgents.forEach((agent) => { const agentConfig = CLAUDE_CODE_AGENTS[agent]; console.log( ` \u{1F50D} Reviewer: ${agent} (${agentConfig?.specializations.join(", ") || "review"})` ); }); console.log("\nNext steps:"); console.log( ` stackmemory ralph swarm-status ${swarmId} # Check progress` ); console.log( ` stackmemory ralph swarm-stop ${swarmId} # Stop swarm` ); console.log( " stackmemory ralph claude-swarm --list-agents # See all available agents" ); } catch (error) { logger.error("Claude Code swarm failed", error); console.error(`\u274C Claude Code swarm failed: ${error.message}`); throw error; } } ); }); ralph.command("swarm-killall").description("Stop all active swarms and cleanup resources").option("--force", "Force kill without saving state").action(async (options) => { return trace.command("ralph-swarm-killall", options, async () => { try { await swarmCoordinator.initialize(); const activeSwarms = swarmCoordinator.getAllActiveSwarms(); if (activeSwarms.length === 0) { console.log("\u{1F4CA} No active swarms to stop"); return; } console.log(`\u{1F6D1} Stopping ${activeSwarms.length} active swarm(s)...`); let stoppedCount = 0; let failedCount = 0; for (const swarm of activeSwarms) { try { console.log(` Stopping ${swarm.id}...`); if (options.force) { await swarmCoordinator.forceStopSwarm(swarm.id); } else { await swarmCoordinator.stopSwarm(swarm.id); } stoppedCount++; console.log(` \u2705 Stopped ${swarm.id}`); } catch (error) { failedCount++; console.error( ` \u274C Failed to stop ${swarm.id}: ${error.message}` ); } } try { const { execSync } = await import("child_process"); const branches = execSync('git branch | grep "swarm/"', { encoding: "utf8" }).split("\n").filter(Boolean).map((b) => b.trim()); if (branches.length > 0) { console.log( ` \u{1F500} Cleaning up ${branches.length} swarm branches...` ); for (const branch of branches) { try { execSync(`git branch -D ${branch}`, { stdio: "ignore" }); console.log(` Deleted ${branch}`); } catch { } } } } catch { } console.log(` \u{1F4CA} Summary:`); console.log(` \u2705 Stopped: ${stoppedCount} swarms`); if (failedCount > 0) { console.log(` \u274C Failed: ${failedCount} swarms`); } await swarmCoordinator.cleanup(); console.log("\u{1F9F9} Cleanup completed"); } catch (error) { logger.error("Swarm killall failed", error); console.error("\u274C Killall failed:", error.message); } }); }); ralph.command("orchestrate").description("Orchestrate multiple Ralph loops for complex tasks").argument("<description>", "Complex task description").option("--criteria <criteria>", "Success criteria (comma separated)").option("--max-loops <n>", "Maximum parallel loops", "3").option("--sequential", "Force sequential execution").action(async (description, options) => { return trace.command( "ralph-orchestrate", { description, ...options }, async () => { try { console.log("\u{1F3AD} Orchestrating complex task..."); await multiLoopOrchestrator.initialize(); const criteria = options.criteria ? options.criteria.split(",").map((c) => c.trim()) : [ "Task completed successfully", "All components working", "Tests pass" ]; const result = await multiLoopOrchestrator.orchestrateComplexTask( description, criteria, { maxLoops: parseInt(options.maxLoops), forceSequential: options.sequential } ); console.log("\u2705 Orchestration completed!"); console.log( `\u{1F4CA} Results: ${result.completedLoops.length} successful, ${result.failedLoops.length} failed` ); console.log( `\u23F1\uFE0F Total duration: ${Math.round(result.totalDuration / 1e3)}s` ); if (result.insights.length > 0) { console.log("\n\u{1F4A1} Insights:"); result.insights.forEach( (insight) => console.log(` \u2022 ${insight}`) ); } } catch (error) { logger.error("Orchestration failed", error); console.error("\u274C Orchestration failed:", error.message); } } ); }); ralph.command("learn").description("Learn patterns from completed loops").option("--task-type <type>", "Learn patterns for specific task type").action(async (options) => { return trace.command("ralph-learn", options, async () => { try { console.log("\u{1F9E0} Learning patterns from completed loops..."); await patternLearner.initialize(); const patterns = options.taskType ? await patternLearner.learnForTaskType(options.taskType) : await patternLearner.learnFromCompletedLoops(); console.log(`\u2705 Learned ${patterns.length} patterns`); if (patterns.length > 0) { console.log("\n\u{1F4CA} Top patterns:"); patterns.slice(0, 5).forEach((pattern) => { console.log( ` \u2022 ${pattern.pattern} (${Math.round(pattern.confidence * 100)}% confidence)` ); }); } } catch (error) { logger.error("Pattern learning failed", error); console.error( "\u274C Pattern learning failed:", error.message ); } }); }); ralph.command("debug-enhanced").description("Advanced debugging with visualization").option("--loop-id <id>", "Specific loop to debug").option("--generate-report", "Generate comprehensive debug report").option("--timeline", "Generate timeline visualization").action(async (options) => { return trace.command("ralph-debug-enhanced", options, async () => { try { if (!existsSync(".ralph") && !options.loopId) { console.log( "\u274C No Ralph loop found. Run a loop first or specify --loop-id" ); return; } console.log("\u{1F50D} Starting enhanced debugging..."); await ralphDebugger.initialize(); const loopId = options.loopId || "current"; await ralphDebugger.startDebugSession(loopId, ".ralph"); if (options.generateReport) { const report = await ralphDebugger.generateDebugReport(loopId); console.log(`\u{1F4CB} Debug report generated: ${report.exportPath}`); } if (options.timeline) { const timelinePath = await ralphDebugger.generateLoopTimeline(loopId); console.log(`\u{1F4CA} Timeline visualization: ${timelinePath}`); } console.log("\u{1F50D} Debug analysis complete"); } catch (error) { logger.error("Enhanced debugging failed", error); console.error("\u274C Debug failed:", error.message); } }); }); ralph.command("swarm-test").description("Comprehensive testing and validation for swarm functionality").option("--quick", "Run quick validation tests only").option("--stress", "Run stress tests with multiple parallel swarms").option("--error-injection", "Test error handling with deliberate failures").option("--cleanup-test", "Test cleanup mechanisms").option("--git-test", "Test git workflow integration").option("--report", "Generate detailed test report").action(async (options) => { return trace.command("ralph-swarm-test", options, async () => { try { console.log("\u{1F9EA} Starting swarm testing and validation..."); await swarmCoordinator.initialize(); const testResults = []; let passedTests = 0; let totalTests = 0; if (options.quick || !options.stress) { console.log("\n\u26A1 Running quick validation tests..."); totalTests++; try { await swarmCoordinator.launchSwarm( "Test: Basic functionality validation", [{ role: "developer" }] ); await swarmCoordinator.forceCleanup(); console.log(" \u2705 Basic swarm initialization"); passedTests++; testResults.push({ test: "basic_init", status: "passed", duration: 0 }); } catch (error) { console.log( " \u274C Basic swarm initialization failed:", error.message ); testResults.push({ test: "basic_init", status: "failed", error: error.message }); } totalTests++; try { const usage = swarmCoordinator.getResourceUsage(); console.log( ` \u2705 Resource monitoring: ${usage.activeAgents} agents, ${usage.memoryEstimate}MB` ); passedTests++; testResults.push({ test: "resource_monitoring", status: "passed", data: usage }); } catch (error) { console.log( " \u274C Resource monitoring failed:", error.message ); testResults.push({ test: "resource_monitoring", status: "failed", error: error.message }); } } if (options.stress) { console.log("\n\u{1F525} Running stress tests..."); totalTests++; try { const stressPromises = []; for (let i = 0; i < 3; i++) { stressPromises.push( swarmCoordinator.launchSwarm(`Stress test swarm ${i}`, [ { role: "developer" }, { role: "tester" } ]) ); } await Promise.all(stressPromises); await swarmCoordinator.forceCleanup(); console.log(" \u2705 Parallel swarm stress test"); passedTests++; testResults.push({ test: "stress_parallel", status: "passed" }); } catch (error) { console.log(" \u274C Stress test failed:", error.message); testResults.push({ test: "stress_parallel", status: "failed", error: error.message }); } } if (options.errorInjection) { console.log("\n\u{1F4A5} Testing error handling..."); totalTests++; try { try { await swarmCoordinator.launchSwarm( "Error test: Invalid agents", [] // Empty agents array ); } catch { console.log(" \u2705 Properly handled empty agents array"); passedTests++; testResults.push({ test: "error_handling", status: "passed" }); } } catch (error) { console.log( " \u274C Error handling test failed:", error.message ); testResults.push({ test: "error_handling", status: "failed", error: error.message }); } } if (options.cleanupTest) { console.log("\n\u{1F9F9} Testing cleanup mechanisms..."); totalTests++; try { await swarmCoordinator.launchSwarm("Cleanup test swarm", [ { role: "developer" } ]); await swarmCoordinator.forceCleanup(); const usage = swarmCoordinator.getResourceUsage(); if (usage.activeAgents === 0) { console.log(" \u2705 Cleanup mechanism works correctly"); passedTests++; testResults.push({ test: "cleanup", status: "passed" }); } else { throw new SystemError( `Cleanup failed: ${usage.activeAgents} agents still active`, ErrorCode.RESOURCE_EXHAUSTED, { activeAgents: usage.activeAgents, test: "cleanup" } ); } } catch (error) { console.log( " \u274C Cleanup test failed:", error.message ); testResults.push({ test: "cleanup", status: "failed", error: error.message }); } } if (options.gitTest) { console.log("\n\u{1F500} Testing git workflow integration..."); totalTests++; try { const gitStatus = swarmCoordinator["gitWorkflowManager"].getGitStatus(); console.log( ` \u2705 Git workflow status: ${gitStatus.enabled ? "enabled" : "disabled"}` ); passedTests++; testResults.push({ test: "git_workflow", status: "passed", data: gitStatus }); } catch (error) { console.log( " \u274C Git workflow test failed:", error.message ); testResults.push({ test: "git_workflow", status: "failed", error: error.message }); } } console.log("\n\u{1F4CA} Test Results Summary:"); console.log(` Total tests: ${totalTests}`); console.log(` Passed: ${passedTests} \u2705`); console.log(` Failed: ${totalTests - passedTests} \u274C`); console.log( ` Success rate: ${Math.round(passedTests / totalTests * 100)}%` ); if (options.report) { const reportPath = ".swarm/test-report.json"; const fs = await import("fs"); const reportData = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), summary: { totalTests, passedTests, failedTests: totalTests - passedTests, successRate: passedTests / totalTests * 100 }, testResults, systemInfo: { nodeVersion: process.version, platform: process.platform, arch: process.arch } }; fs.writeFileSync(reportPath, JSON.stringify(reportData, null, 2)); console.log(`\u{1F4CB} Detailed report saved to: ${reportPath}`); } if (passedTests === totalTests) { console.log( "\n\u{1F389} All tests passed! Swarm functionality is working correctly." ); } else { console.log( "\n\u26A0\uFE0F Some tests failed. Check the errors above for details." ); process.exit(1); } } catch (error) { logger.error("Swarm testing failed", error); console.error("\u274C Test suite failed:", error.message); process.exit(1); } }); }); ralph.command("tui").description("Launch TUI monitor for active swarms").option("--swarm-id <id>", "Monitor specific swarm ID").option("--simple", "Use simple text mode instead of full TUI").option("--force-tui", "Force full TUI even with compatibility issues").action(async (options) => { try { const isGhostty = process.env.TERM_PROGRAM === "ghostty" || process.env.TERM?.includes("ghostty"); const isBasicTerm = process.env.TERM === "dumb" || process.env.TERM === "unknown"; const hasCompatibilityIssues = isGhostty || isBasicTerm; const useSimpleMode = options.simple || hasCompatibilityIssues && !options.forceTui; if (useSimpleMode) { console.log("\u{1F9BE} Starting Simple Swarm Monitor (Text Mode)"); if (hasCompatibilityIssues && !options.simple) { console.log( `\u26A0\uFE0F Detected ${isGhostty ? "Ghostty" : "basic"} terminal - using text mode for compatibility` ); console.log( " Use --force-tui to override, or --simple to explicitly use text mode" ); } const { SimpleSwarmMonitor } = await import("../../features/tui/simple-monitor.js"); const monitor = new SimpleSwarmMonitor(); monitor.start(); } else { console.log("\u{1F9BE} Starting Full TUI Monitor"); const { SwarmTUI } = await import("../../features/tui/swarm-monitor.js"); const tui = new SwarmTUI(); await tui.initialize(void 0, options.swarmId); tui.start(); } } catch (error) { logger.error("TUI launch failed", error); console.error("\u274C TUI failed:", error.message); console.log("\u{1F4A1} Try: stackmemory ralph tui --simple"); process.exit(1); } }); ralph.command("linear").description( "Execute Linear tasks via RLM orchestrator (pull \u2192 execute \u2192 update)" ).argument("[action]", "Action: next, all, task <id>, preview [id]", "next").argument("[taskId]", "Task ID for task/preview actions").option( "--priority <level>", "Filter by priority: urgent, high, medium, low" ).option("--tag <tag>", "Filter by tag").option("--dry-run", "Show plan without executing").option( "--max-concurrent <n>", "Max parallel tasks (default: 1, sequential)", "1" ).action( async (action, taskId, options) => { return trace.command( "ralph-linear", { action, taskId, ...options }, async () => { try { const { LinearTaskManager } = await import("../../features/tasks/linear-task-manager.js"); const { RecursiveAgentOrchestrator } = await import("../../skills/recursive-agent-orchestrator.js"); const { SpecGeneratorSkill } = await import("../../skills/spec-generator-skill.js"); const { LinearTaskRunner } = await import("../../skills/linear-task-runner.js"); console.log("\u{1F50C} Initializing Linear task runner..."); const taskManager = new LinearTaskManager(); const loadedCount = await taskManager.loadFromLinear(); console.log(`\u{1F4CB} Loaded ${loadedCount} tasks from Linear`); const specSkill = new SpecGeneratorSkill({ projectId: "cli", userId: "cli-user" }); const { DualStackManager } = await import("../../core/context/dual-stack-manager.js"); const { ContextRetriever } = await import("../../core/retrieval/context-retriever.js"); const { SQLiteAdapter } = await import("../../core/database/sqlite-adapter.js"); const db = new SQLiteAdapter(); await db.initialize(); const dualStack = new DualStackManager(db); const contextRetriever = new ContextRetriever(db); const frameManager = dualStack.getActiveStack(); const rlm = new RecursiveAgentOrchestrator( frameManager, dualStack, contextRetriever, taskManager ); const runner = new LinearTaskRunner( taskManager, rlm, { projectId: "cli", userId: "cli-user" }, specSkill ); let result; const runOpts = { priority: options.priority, tag: options.tag, dryRun: options.dryRun, maxConcurrent: parseInt(options.maxConcurrent) }; switch (action) { case "next": console.log("\u{1F680} Running next task..."); result = await runner.runNext(runOpts); break; case "all": console.log("\u{1F680} Running all tasks..."); result = await runner.runAll(runOpts); break; case "task": if (!taskId) { console.error( "\u274C Task ID required: ralph linear task <id>" ); return; } console.log(`\u{1F680} Running task ${taskId}...`); result = await runner.runTask(taskId, runOpts); break; case "preview": result = await runner.preview(taskId); break; default: console.log("\u{1F680} Running next task..."); result = await runner.runNext(runOpts); break; } if (result.success) { console.log(`\u2705 ${result.message}`); } else { console.log(`\u274C ${result.message}`); } if (result.data) { console.log(JSON.stringify(result.data, null, 2)); } taskManager.destroy(); } catch (error) { logger.error("Linear task execution failed", error); console.error( "\u274C Linear execution failed:", error.message ); } } ); } ); return ralph; } var ralph_default = createRalphCommand; export { createRalphCommand, ralph_default as default }; //# sourceMappingURL=ralph.js.map