@herbcaudill/ralph 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/components/App.tsx","../src/components/SessionRunner.tsx","../src/components/EnhancedTextInput.tsx","../src/components/findPreviousWordBoundary.ts","../src/components/findNextWordBoundary.ts","../src/lib/addTodo.ts","../src/lib/insertTodo.ts","../src/lib/getProgress.ts","../src/lib/getBeadsProgress.ts","../src/lib/getTodoProgress.ts","../src/lib/captureStartupSnapshot.ts","../src/lib/captureBeadsSnapshot.ts","../src/lib/captureTodoSnapshot.ts","../src/components/ProgressBar.tsx","../src/lib/beadsClient.ts","../src/lib/debug.ts","../src/lib/createUserMessage.ts","../src/lib/MessageQueue.ts","../src/lib/useTerminalSize.ts","../src/lib/getTerminalSize.ts","../src/lib/getNextLogFile.ts","../src/lib/findMaxLogNumber.ts","../src/lib/parseTaskLifecycle.ts","../src/lib/getPromptContent.ts","../src/lib/sdkMessageToEvent.ts","../src/lib/rel.ts","../src/lib/getBaseCwd.ts","../src/lib/shortenTempPaths.ts","../src/components/eventToBlocks.ts","../src/lib/processEvents.ts","../src/components/renderStaticItem.tsx","../src/components/Header.tsx","../src/lib/formatText.ts","../src/lib/formatToolUse.ts","../src/lib/formatUserMessage.ts","../src/lib/formatContentBlock.ts","../src/components/ReplayLog.tsx","../src/components/EventDisplay.tsx","../src/lib/formatSessionHeader.ts","../src/components/processEvents.ts","../src/components/blocksToLines.ts","../src/components/FullScreenLayout.tsx","../src/components/useContentHeight.ts","../src/components/JsonOutput.tsx","../src/lib/parseStdinCommand.ts","../src/lib/createStdinCommandHandler.ts","../src/lib/outputEvent.ts","../src/components/InitRalph.tsx","../src/lib/copyTemplates.ts","../src/lib/getClaudeVersion.ts","../src/lib/getOpenIssueCount.ts","../src/lib/getDefaultSessions.ts","../src/lib/getLatestLogFile.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\"\nimport { render } from \"ink\"\nimport React from \"react\"\nimport { App } from \"./components/App.js\"\nimport { InitRalph } from \"./components/InitRalph.js\"\nimport { getClaudeVersion } from \"./lib/getClaudeVersion.js\"\nimport { getDefaultSessions } from \"./lib/getDefaultSessions.js\"\nimport { addTodo } from \"./lib/addTodo.js\"\nimport { getLatestLogFile } from \"./lib/getLatestLogFile.js\"\nimport packageJson from \"../package.json\" with { type: \"json\" }\n\nexport const program = new Command()\n .name(\"ralph\")\n .description(\"Autonomous AI session engine for Claude CLI\")\n .version(packageJson.version)\n .argument(\n \"[sessions]\",\n \"number of sessions (default: 120% of open issues, min 10, max 100)\",\n val => parseInt(val, 10),\n )\n .option(\"--replay [file]\", \"replay events from log file\")\n .option(\"--watch\", \"watch for new beads issues after completion\")\n .option(\"--json\", \"output events as newline-delimited JSON to stdout\")\n .option(\"--agent <name>\", \"agent to use (e.g., claude, codex)\", \"claude\")\n .action(\n (\n /** The number of sessions to run, or undefined to use default */\n sessionsArg: number | undefined,\n /** Command options including replay, watch, json, and agent */\n options,\n ) => {\n const sessions = sessionsArg ?? getDefaultSessions()\n const replayFile =\n options.replay !== undefined ?\n typeof options.replay === \"string\" ?\n options.replay\n : getLatestLogFile()\n : undefined\n\n const claudeVersion = getClaudeVersion()\n const ralphVersion = packageJson.version\n const watch = options.watch === true\n const json = options.json === true\n const agent = options.agent as string\n\n // Validate agent selection\n const validAgents = [\"claude\", \"codex\"]\n if (!validAgents.includes(agent)) {\n console.error(\n `Error: Invalid agent \"${agent}\". Available agents: ${validAgents.join(\", \")}`,\n )\n process.exit(1)\n }\n\n // Clear the screen on startup (skip in JSON mode)\n if (!json) {\n process.stdout.write(\"\\x1B[2J\\x1B[H\")\n }\n\n render(\n React.createElement(App, {\n sessions,\n replayFile,\n claudeVersion,\n ralphVersion,\n watch,\n json,\n agent,\n }),\n )\n },\n )\n\nprogram\n .command(\"init\")\n .description(\"initialize .ralph directory with templates\")\n /**\n * Initialize the .ralph directory with templates\n */\n .action(() => {\n render(React.createElement(InitRalph))\n })\n\nprogram\n .command(\"todo [description...]\")\n .description(\"add a todo item and commit it (safe to use while ralph is running)\")\n /**\n * Add a todo item and commit it. If description is provided as arguments,\n * use that; otherwise prompt interactively.\n */\n .action(\n async (\n /** The description parts from command arguments */\n descriptionParts: string[],\n ) => {\n let description = descriptionParts.join(\" \").trim()\n\n if (!description) {\n // Prompt for description interactively\n const readline = await import(\"readline\")\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n\n description = await new Promise<string>(resolve => {\n rl.question(\"Todo: \", answer => {\n rl.close()\n resolve(answer.trim())\n })\n })\n\n if (!description) {\n console.error(\"No todo description provided\")\n process.exit(1)\n }\n }\n\n try {\n addTodo(description)\n } catch (error) {\n console.error(`Failed to add todo: ${error instanceof Error ? error.message : error}`)\n process.exit(1)\n }\n },\n )\n","import React from \"react\"\nimport { SessionRunner } from \"./SessionRunner.js\"\nimport { ReplayLog } from \"./ReplayLog.js\"\nimport { JsonOutput } from \"./JsonOutput.js\"\n\n/**\n * Root application component that routes to the appropriate mode based on props.\n * Supports replay mode, JSON output mode, and normal session mode.\n */\nexport const App = ({\n sessions,\n replayFile,\n claudeVersion,\n ralphVersion,\n watch,\n json,\n agent,\n}: Props) => {\n if (replayFile) {\n return <ReplayLog filePath={replayFile} />\n }\n\n if (json) {\n return <JsonOutput totalSessions={sessions} agent={agent} />\n }\n\n return (\n <SessionRunner\n totalSessions={sessions}\n claudeVersion={claudeVersion}\n ralphVersion={ralphVersion}\n watch={watch}\n agent={agent}\n />\n )\n}\n\ntype Props = {\n sessions: number\n replayFile?: string\n claudeVersion: string\n ralphVersion: string\n watch?: boolean\n json?: boolean\n agent: string\n}\n","import React, { useState, useEffect, useRef } from \"react\"\nimport { Box, Text, useApp, Static, useInput } from \"ink\"\nimport Spinner from \"ink-spinner\"\nimport { EnhancedTextInput } from \"./EnhancedTextInput.js\"\nimport { appendFileSync, writeFileSync, readFileSync, existsSync } from \"fs\"\nimport { join, basename } from \"path\"\nimport { query } from \"@anthropic-ai/claude-agent-sdk\"\nimport { eventToBlocks } from \"./eventToBlocks.js\"\nimport { addTodo } from \"../lib/addTodo.js\"\nimport { getProgress } from \"../lib/getProgress.js\"\nimport { captureStartupSnapshot } from \"../lib/captureStartupSnapshot.js\"\nimport type { ProgressData, StartupSnapshot } from \"../lib/types.js\"\nimport { ProgressBar } from \"./ProgressBar.js\"\nimport { watchForNewIssues, type MutationEvent } from \"../lib/beadsClient.js\"\nimport { MessageQueue, createUserMessage } from \"../lib/MessageQueue.js\"\nimport { createDebugLogger } from \"../lib/debug.js\"\nimport { useTerminalSize } from \"../lib/useTerminalSize.js\"\nimport { getNextLogFile } from \"../lib/getNextLogFile.js\"\nimport { parseTaskLifecycleEvent } from \"../lib/parseTaskLifecycle.js\"\nimport { getPromptContent } from \"../lib/getPromptContent.js\"\nimport { sdkMessageToEvent } from \"../lib/sdkMessageToEvent.js\"\nimport { processEvents } from \"../lib/processEvents.js\"\nimport { renderStaticItem } from \"./renderStaticItem.js\"\nimport { type StaticItem, type SessionRunnerProps } from \"./SessionRunner.types.js\"\n\n/** Debug logger for session lifecycle events */\nconst log = createDebugLogger(\"session\")\n\n/** The .ralph directory path in the current working directory */\nconst ralphDir = join(process.cwd(), \".ralph\")\n\n/** Path to the todo.md file in the .ralph directory */\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/** The name of the current repository (basename of cwd) */\nconst repoName = basename(process.cwd())\n\n/**\n * Orchestrates the iterative execution of Claude AI sessions.\n *\n * Spawns Claude CLI with prompts, captures streaming output, displays formatted UI,\n * and handles user input during session execution.\n */\nexport const SessionRunner = ({\n totalSessions,\n claudeVersion,\n ralphVersion,\n watch,\n agent,\n}: SessionRunnerProps) => {\n const { exit } = useApp()\n const { columns } = useTerminalSize()\n const [currentSession, setCurrentSession] = useState(1)\n const [events, setEvents] = useState<Array<Record<string, unknown>>>([])\n const eventsRef = useRef<Array<Record<string, unknown>>>([])\n const [error, setError] = useState<string>()\n const [isRunning, setIsRunning] = useState(false)\n const [isAddingTodo, setIsAddingTodo] = useState(false)\n const [todoText, setTodoText] = useState(\"\")\n const [todoMessage, setTodoMessage] = useState<{\n type: \"success\" | \"error\"\n text: string\n } | null>(null)\n const [userMessageText, setUserMessageText] = useState(\"\")\n const [userMessageStatus, setUserMessageStatus] = useState<{\n type: \"success\" | \"error\" | \"pending\"\n text: string\n } | null>(null)\n const [hasTodoFile, setHasTodoFile] = useState(false)\n const [startupSnapshot] = useState<StartupSnapshot | undefined>(() => captureStartupSnapshot())\n const [progressData, setProgressData] = useState<ProgressData>(() => {\n const snapshot = captureStartupSnapshot()\n if (!snapshot) return { type: \"none\", completed: 0, total: 0 }\n return { type: snapshot.type, completed: 0, total: snapshot.initialCount }\n })\n const [isWatching, setIsWatching] = useState(false)\n const [detectedIssue, setDetectedIssue] = useState<MutationEvent | null>(null)\n const watchCleanupRef = useRef<(() => void) | null>(null)\n const [watchCycle, setWatchCycle] = useState(0) // Increments to force useEffect re-run\n const [stopAfterCurrent, setStopAfterCurrent] = useState(false) // Stop gracefully after current session\n const stopAfterCurrentRef = useRef(false) // Ref to access in async callbacks\n const [isPaused, setIsPaused] = useState(false) // Pause after current session completes\n const isPausedRef = useRef(false) // Ref to access in async callbacks\n const [currentTaskId, setCurrentTaskId] = useState<string | null>(null)\n const [currentTaskTitle, setCurrentTaskTitle] = useState<string | null>(null)\n\n // Track static items that have been rendered (for Ink's Static component)\n const [staticItems, setStaticItems] = useState<StaticItem[]>([\n { type: \"header\", claudeVersion, ralphVersion, key: \"header\" },\n ])\n const renderedBlocksRef = useRef<Set<string>>(new Set())\n const lastSessionRef = useRef<number>(0)\n // Message queue for sending user messages to Claude while running\n const messageQueueRef = useRef<MessageQueue | null>(null)\n // Log file path for this run (set once at startup, persisted across sessions)\n const logFileRef = useRef<string | null>(null)\n\n /** Whether stdin supports raw mode (required for keyboard input handling) */\n const stdinSupportsRawMode = process.stdin.isTTY === true\n\n /**\n * Handle adding a new todo when Ctrl-T is pressed.\n */\n const handleTodoSubmit = (\n /** The todo text to add */\n text: string,\n ) => {\n const trimmed = text.trim()\n if (!trimmed) {\n setIsAddingTodo(false)\n setTodoText(\"\")\n return\n }\n\n try {\n addTodo(trimmed)\n setTodoMessage({ type: \"success\", text: \"✅ added\" })\n setTodoText(\"\")\n setIsAddingTodo(false)\n // Clear success message after 2 seconds\n setTimeout(() => setTodoMessage(null), 2000)\n } catch (err) {\n setTodoMessage({\n type: \"error\",\n text: `Failed to add todo: ${err instanceof Error ? err.message : String(err)}`,\n })\n setTodoText(\"\")\n setIsAddingTodo(false)\n // Clear error message after 5 seconds\n setTimeout(() => setTodoMessage(null), 5000)\n }\n }\n\n /**\n * Handle submitting a user message to Claude during session.\n */\n const handleUserMessageSubmit = (\n /** The message text from the user */\n text: string,\n ) => {\n const trimmed = text.trim()\n if (!trimmed) {\n setUserMessageText(\"\")\n return\n }\n\n // Send the message to Claude via the SDK's streamInput\n if (messageQueueRef.current && isRunning) {\n const userMessage = createUserMessage(trimmed)\n messageQueueRef.current.push(userMessage)\n\n // Also add the user message to events for display\n const displayEvent = {\n type: \"user\",\n message: {\n id: `user-injected-${Date.now()}`,\n role: \"user\",\n content: [{ type: \"text\", text: trimmed }],\n },\n }\n setEvents(prev => [...prev, displayEvent])\n\n // No confirmation message - the user message appears directly in the stream\n } else {\n setUserMessageStatus({\n type: \"error\",\n text: \"Unable to send message - Claude is not running\",\n })\n }\n\n setUserMessageText(\"\")\n // Clear status message after 3 seconds\n setTimeout(() => setUserMessageStatus(null), 3000)\n }\n\n /**\n * Handle keyboard input for Ctrl-T (todo), Ctrl-S (stop), Ctrl-P (pause), and Escape (cancel).\n */\n useInput(\n (\n /** The input character */\n input,\n /** The key information including modifiers */\n key,\n ) => {\n // Ctrl-T to start adding a todo (only if todo.md exists)\n if (key.ctrl && input === \"t\" && hasTodoFile) {\n setIsAddingTodo(true)\n setTodoText(\"\")\n setTodoMessage(null)\n }\n // Ctrl-S to request stop after current session\n if (key.ctrl && input === \"s\" && isRunning && !stopAfterCurrent) {\n setStopAfterCurrent(true)\n }\n // Ctrl-P to toggle pause state\n if (key.ctrl && input === \"p\") {\n if (isPaused) {\n // Resume - if we were paused between sessions, trigger next session\n setIsPaused(false)\n if (!isRunning) {\n setTimeout(() => setCurrentSession(i => i + 1), 100)\n }\n } else if (isRunning) {\n // Request pause after current session\n setIsPaused(true)\n }\n }\n // Escape to cancel todo input\n if (key.escape) {\n if (isAddingTodo) {\n // Cancel todo input\n setIsAddingTodo(false)\n setTodoText(\"\")\n }\n }\n },\n { isActive: stdinSupportsRawMode },\n )\n\n // Keep ref in sync with events state for access in callbacks\n useEffect(() => {\n eventsRef.current = events\n }, [events])\n\n // Keep stopAfterCurrent ref in sync with state for access in async callbacks\n useEffect(() => {\n stopAfterCurrentRef.current = stopAfterCurrent\n }, [stopAfterCurrent])\n\n // Keep isPaused ref in sync with state for access in async callbacks\n useEffect(() => {\n isPausedRef.current = isPaused\n }, [isPaused])\n\n // Update progress data when session changes or running stops\n useEffect(() => {\n if (!isRunning && startupSnapshot) {\n setProgressData(getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp))\n }\n }, [currentSession, isRunning, startupSnapshot])\n\n // Poll progress data periodically while running to catch newly created/closed issues\n useEffect(() => {\n if (!isRunning || !startupSnapshot) return\n\n const pollInterval = setInterval(() => {\n setProgressData(getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp))\n }, 5000) // Poll every 5 seconds\n\n return () => clearInterval(pollInterval)\n }, [isRunning, startupSnapshot])\n\n // Watch for new issues when in watch mode\n useEffect(() => {\n if (!isWatching) return\n\n // Start watching for new issues\n const cleanup = watchForNewIssues(issue => {\n setDetectedIssue(issue)\n // Refresh progress data to pick up the new issue\n // The timestamp-based counting will automatically include it\n if (startupSnapshot) {\n setProgressData(getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp))\n }\n // Brief pause to show the detected issue, then resume\n setTimeout(() => {\n setIsWatching(false)\n setDetectedIssue(null)\n // Reset rendered blocks for new cycle\n renderedBlocksRef.current.clear()\n // Increment round number when picking up new issue\n setCurrentSession(i => i + 1)\n setWatchCycle(c => c + 1)\n }, 1500)\n })\n\n watchCleanupRef.current = cleanup\n\n return () => {\n cleanup()\n watchCleanupRef.current = null\n }\n }, [isWatching, startupSnapshot])\n\n // Convert events to static items as they arrive\n useEffect(() => {\n const newItems: StaticItem[] = []\n\n // Add session header if this is a new session\n if (currentSession > lastSessionRef.current) {\n newItems.push({\n type: \"session\",\n session: currentSession,\n key: `session-${currentSession}`,\n })\n lastSessionRef.current = currentSession\n }\n\n // Process current events into blocks\n const blocks = processEvents(events)\n\n // Add any new blocks that haven't been rendered yet\n for (const block of blocks) {\n // Use the block's ID which is generated from message ID + block index\n // This ensures the same logical block always has the same key\n const blockKey = block.id\n\n if (!renderedBlocksRef.current.has(blockKey)) {\n renderedBlocksRef.current.add(blockKey)\n newItems.push({ type: \"block\", block, key: blockKey })\n }\n }\n\n if (newItems.length > 0) {\n setStaticItems(prev => [...prev, ...newItems])\n }\n }, [events, currentSession])\n\n useEffect(() => {\n if (currentSession > totalSessions) {\n exit()\n return\n }\n\n // Check if there are any tasks available before starting a round\n // This avoids running Claude unnecessarily when there's no work to do\n const currentProgress =\n startupSnapshot ?\n getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp)\n : { type: \"none\" as const, completed: 0, total: 0 }\n // All tasks are complete when completed equals total\n if (currentProgress.completed >= currentProgress.total && currentProgress.type !== \"none\") {\n // No tasks available - go straight to watching if enabled\n if (watch) {\n setIsWatching(true)\n } else {\n exit()\n process.exit(0)\n }\n return\n }\n\n // Get or create the log file path for this run\n // Only create a new sequential log file on the first session\n if (!logFileRef.current) {\n logFileRef.current = getNextLogFile()\n writeFileSync(logFileRef.current, \"\")\n }\n const logFile = logFileRef.current\n setEvents([])\n\n // Read prompt (from .ralph/prompt.md or falling back to templates)\n const promptContent = getPromptContent()\n const todoExists = existsSync(todoFile)\n setHasTodoFile(todoExists)\n const todoContent = todoExists ? readFileSync(todoFile, \"utf-8\") : \"\"\n const roundHeader = `# Ralph, round ${currentSession}\\n\\n`\n const fullPrompt =\n todoContent ?\n `${roundHeader}${promptContent}\\n\\n## Current Todo List\\n\\n${todoContent}`\n : `${roundHeader}${promptContent}`\n\n const abortController = new AbortController()\n setIsRunning(true)\n\n // Create a message queue for this session\n // This allows us to send user messages to Claude while it's running\n const messageQueue = new MessageQueue()\n messageQueueRef.current = messageQueue\n\n // Push the initial prompt as the first message\n messageQueue.push(createUserMessage(fullPrompt))\n\n /**\n * Execute a query to Claude and handle the streaming response.\n */\n const runQuery = async () => {\n let finalResult = \"\"\n log(`Starting session ${currentSession}`)\n\n try {\n log(`Beginning query() loop`)\n for await (const message of query({\n prompt: messageQueue,\n options: {\n abortController,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n includePartialMessages: true,\n env: {\n ...process.env,\n // Disable LSP plugins to avoid crashes when TypeScript LSP server errors\n ENABLE_LSP_TOOL: \"0\",\n // Signal that tests should use minimal reporters (dots)\n RALPH_QUIET: \"1\",\n },\n },\n })) {\n log(`Received message type: ${message.type}`)\n // Log raw message to file (JSONL format - one JSON object per line)\n appendFileSync(logFile, JSON.stringify(message) + \"\\n\")\n\n // Convert to event format for display\n const event = sdkMessageToEvent(message)\n if (event) {\n setEvents(prev => [...prev, event])\n }\n\n // Check for task lifecycle events in assistant messages\n if (message.type === \"assistant\") {\n const assistantMessage = message.message as Record<string, unknown> | undefined\n const content = assistantMessage?.content as Array<Record<string, unknown>> | undefined\n if (content) {\n for (const block of content) {\n if (block.type === \"text\" && typeof block.text === \"string\") {\n const taskInfo = parseTaskLifecycleEvent(block.text)\n if (taskInfo) {\n if (taskInfo.action === \"starting\") {\n setCurrentTaskId(taskInfo.taskId ?? null)\n setCurrentTaskTitle(taskInfo.taskTitle ?? null)\n log(\n `Task started: ${taskInfo.taskId}${taskInfo.taskTitle ? ` - ${taskInfo.taskTitle}` : \"\"}`,\n )\n // Emit ralph_task_started event to log file\n const taskStartedEvent = {\n type: \"ralph_task_started\",\n taskId: taskInfo.taskId,\n taskTitle: taskInfo.taskTitle,\n session: currentSession,\n }\n appendFileSync(logFile, JSON.stringify(taskStartedEvent) + \"\\n\")\n } else if (taskInfo.action === \"completed\") {\n log(\n `Task completed: ${taskInfo.taskId}${taskInfo.taskTitle ? ` - ${taskInfo.taskTitle}` : \"\"}`,\n )\n // Emit ralph_task_completed event to log file\n const taskCompletedEvent = {\n type: \"ralph_task_completed\",\n taskId: taskInfo.taskId,\n taskTitle: taskInfo.taskTitle,\n session: currentSession,\n }\n appendFileSync(logFile, JSON.stringify(taskCompletedEvent) + \"\\n\")\n // Keep tracking the same task until a new one starts\n }\n }\n }\n }\n }\n }\n\n // Capture the final result message\n if (\n message.type === \"result\" &&\n \"result\" in message &&\n typeof message.result === \"string\"\n ) {\n log(`Received result message`)\n finalResult = message.result\n // Close the message queue immediately when we get the result.\n // This is critical to prevent hangs: the SDK's streamInput() needs\n // to complete iterating our queue before it can call endInput(),\n // which signals EOF to the CLI. If we wait until after the for-await\n // loop exits, we create a circular dependency that can cause hangs.\n log(`Closing message queue on result`)\n messageQueue.close()\n }\n }\n\n log(`query() loop completed normally`)\n setIsRunning(false)\n // MessageQueue should already be closed when we received the result message.\n // We ensure it's closed here as a safety measure (close() is idempotent).\n log(`Ensuring message queue is closed`)\n messageQueue.close()\n messageQueueRef.current = null\n\n // Check for stop-after-current request\n if (stopAfterCurrentRef.current) {\n log(`Stop after current requested - exiting gracefully`)\n exit()\n process.exit(0)\n return\n }\n\n // Check for completion\n if (finalResult.includes(\"<promise>COMPLETE</promise>\")) {\n if (watch) {\n // Enter watch mode instead of exiting\n setIsWatching(true)\n } else {\n exit()\n process.exit(0)\n }\n return\n }\n\n // Check for pause request - if paused, we wait for resume via Ctrl-P\n if (isPausedRef.current) {\n log(`Paused after session ${currentSession}`)\n // Don't move to next session - the resume handler (Ctrl-P) will trigger it\n return\n }\n\n // Move to next session\n setTimeout(() => setCurrentSession(i => i + 1), 500)\n } catch (err) {\n log(`query() loop error: ${err instanceof Error ? err.message : String(err)}`)\n setIsRunning(false)\n log(`Closing message queue after error`)\n messageQueue.close()\n messageQueueRef.current = null\n if (abortController.signal.aborted) {\n log(`Abort signal detected`)\n return // Intentionally aborted\n }\n setError(`Error running Claude: ${err instanceof Error ? err.message : String(err)}`)\n setTimeout(() => {\n exit()\n process.exit(1)\n }, 100)\n }\n }\n\n runQuery()\n\n return () => {\n log(`Cleanup: aborting and closing queue for session ${currentSession}`)\n abortController.abort()\n messageQueue.close()\n messageQueueRef.current = null\n }\n }, [currentSession, totalSessions, exit, watch, watchCycle])\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n {/* Static content that has already been rendered - won't re-render */}\n <Static items={staticItems}>\n {item => (\n <Box key={item.key} flexDirection=\"column\">\n {renderStaticItem(item)}\n </Box>\n )}\n </Static>\n\n {/* Todo input (shown when Ctrl-T is pressed) */}\n {isAddingTodo && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"yellow\">Todo:</Text>\n <EnhancedTextInput value={todoText} onChange={setTodoText} onSubmit={handleTodoSubmit} />\n <Text dimColor>(Enter to add, Esc to cancel)</Text>\n </Box>\n )}\n\n {/* Todo message (success or error) */}\n {todoMessage && (\n <Box marginTop={1}>\n <Text color={todoMessage.type === \"success\" ? \"green\" : \"red\"}>{todoMessage.text}</Text>\n </Box>\n )}\n\n {/* User message input - visible when running, hidden when watching for new issues */}\n {!isWatching && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text dimColor>{\"─\".repeat(columns)}</Text>\n <Box>\n <Text color={isRunning ? \"yellow\" : \"gray\"}>❯ </Text>\n <EnhancedTextInput\n value={userMessageText}\n placeholder={\n isRunning ? \"Type a message for Ralph...\" : \"Waiting for Ralph to start...\"\n }\n onChange={setUserMessageText}\n onSubmit={handleUserMessageSubmit}\n focus={isRunning && !isAddingTodo}\n />\n </Box>\n {userMessageStatus && (\n <Text\n color={\n userMessageStatus.type === \"success\" ? \"green\"\n : userMessageStatus.type === \"error\" ?\n \"red\"\n : \"yellow\"\n }\n >\n {userMessageStatus.text}\n </Text>\n )}\n <Text dimColor>{\"─\".repeat(columns)}</Text>\n </Box>\n )}\n\n {/* Dynamic footer with spinner and progress bar */}\n <Box marginTop={1} justifyContent=\"space-between\">\n {isWatching ?\n detectedIssue ?\n <Text color=\"green\">\n <Spinner type=\"dots\" /> New issue: <Text color=\"yellow\">{detectedIssue.IssueID}</Text>\n {detectedIssue.Title ? ` - ${detectedIssue.Title}` : \"\"}\n </Text>\n : <Text color=\"cyan\">\n Waiting for new issues <Spinner type=\"simpleDotsScrolling\" />\n </Text>\n\n : isPaused && !isRunning ?\n <Text color=\"magenta\">\n ⏸ Paused after round <Text color=\"yellow\">{currentSession}</Text>{\" \"}\n <Text dimColor>(Ctrl-P to resume)</Text>\n </Text>\n : isRunning ?\n stopAfterCurrent ?\n <Text color=\"yellow\">\n <Spinner type=\"dots\" /> Stopping after round{\" \"}\n <Text color=\"yellow\">{currentSession}</Text> completes...{\" \"}\n <Text dimColor>(Ctrl-S pressed)</Text>\n </Text>\n : isPaused ?\n <Text color=\"magenta\">\n <Spinner type=\"dots\" /> Pausing after round{\" \"}\n <Text color=\"yellow\">{currentSession}</Text> completes...{\" \"}\n <Text dimColor>(Ctrl-P pressed)</Text>\n </Text>\n : <Text color=\"cyan\">\n <Spinner type=\"dots\" /> Running round <Text color=\"yellow\">{currentSession}</Text>{\" \"}\n (max {totalSessions})\n </Text>\n\n : <Text color=\"cyan\">\n <Spinner type=\"simpleDotsScrolling\" /> Waiting for Ralph to start...\n </Text>\n }\n {progressData.type !== \"none\" && progressData.total > 0 && (\n <ProgressBar\n completed={progressData.completed}\n total={progressData.total}\n repoName={repoName}\n />\n )}\n </Box>\n </Box>\n )\n}\n","import React, { useState, useEffect } from \"react\"\nimport { Text, useInput } from \"ink\"\nimport chalk from \"chalk\"\nimport { findPreviousWordBoundary } from \"./findPreviousWordBoundary.js\"\nimport { findNextWordBoundary } from \"./findNextWordBoundary.js\"\n\n/**\n * Enhanced text input component with standard text editing shortcuts:\n * - Option+Left/Right: Move cursor by word\n * - Option+Backspace: Delete previous word\n * - Ctrl+A: Move to beginning of line\n * - Ctrl+E: Move to end of line\n * - Ctrl+K: Kill (delete) from cursor to end of line\n * - Ctrl+U: Kill (delete) from cursor to beginning of line\n * - Ctrl+W: Delete previous word\n */\nexport const EnhancedTextInput = ({\n value: originalValue,\n placeholder = \"\",\n focus = true,\n showCursor = true,\n onChange,\n onSubmit,\n}: Props) => {\n const [cursorOffset, setCursorOffset] = useState(originalValue.length)\n\n useEffect(() => {\n if (!focus || !showCursor) {\n return\n }\n // Ensure cursor stays within bounds when value changes externally\n if (cursorOffset > originalValue.length) {\n setCursorOffset(originalValue.length)\n }\n }, [originalValue, focus, showCursor, cursorOffset])\n\n // Render the value with cursor\n let renderedValue = originalValue\n let renderedPlaceholder = placeholder ? chalk.grey(placeholder) : undefined\n\n if (showCursor && focus) {\n renderedPlaceholder =\n placeholder.length > 0 ?\n chalk.inverse(placeholder[0]) + chalk.grey(placeholder.slice(1))\n : chalk.inverse(\" \")\n\n renderedValue = originalValue.length > 0 ? \"\" : chalk.inverse(\" \")\n\n for (let i = 0; i < originalValue.length; i++) {\n const char = originalValue[i]!\n renderedValue += i === cursorOffset ? chalk.inverse(char) : char\n }\n\n if (originalValue.length > 0 && cursorOffset === originalValue.length) {\n renderedValue += chalk.inverse(\" \")\n }\n }\n\n useInput(\n (input, key) => {\n // Ignore control sequences we don't handle\n if (key.upArrow || key.downArrow || (key.ctrl && input === \"c\") || key.tab) {\n return\n }\n\n if (key.return) {\n onSubmit?.(originalValue)\n return\n }\n\n let nextCursorOffset = cursorOffset\n let nextValue = originalValue\n\n // Option+Left: Move cursor to previous word boundary\n if (key.meta && key.leftArrow) {\n nextCursorOffset = findPreviousWordBoundary(originalValue, cursorOffset)\n }\n // Option+Right: Move cursor to next word boundary\n else if (key.meta && key.rightArrow) {\n nextCursorOffset = findNextWordBoundary(originalValue, cursorOffset)\n }\n // Ctrl+A: Move to beginning of line\n else if (key.ctrl && input === \"a\") {\n nextCursorOffset = 0\n }\n // Ctrl+E: Move to end of line\n else if (key.ctrl && input === \"e\") {\n nextCursorOffset = originalValue.length\n }\n // Ctrl+K: Kill from cursor to end of line\n else if (key.ctrl && input === \"k\") {\n nextValue = originalValue.slice(0, cursorOffset)\n // Cursor stays in place\n }\n // Ctrl+U: Kill from cursor to beginning of line\n else if (key.ctrl && input === \"u\") {\n nextValue = originalValue.slice(cursorOffset)\n nextCursorOffset = 0\n }\n // Ctrl+W or Option+Backspace: Delete previous word\n else if (key.ctrl && input === \"w\") {\n const wordStart = findPreviousWordBoundary(originalValue, cursorOffset)\n nextValue = originalValue.slice(0, wordStart) + originalValue.slice(cursorOffset)\n nextCursorOffset = wordStart\n }\n // Option+Backspace (sent as meta + backspace)\n else if (key.meta && key.backspace) {\n const wordStart = findPreviousWordBoundary(originalValue, cursorOffset)\n nextValue = originalValue.slice(0, wordStart) + originalValue.slice(cursorOffset)\n nextCursorOffset = wordStart\n }\n // Regular left arrow\n else if (key.leftArrow) {\n if (showCursor && cursorOffset > 0) {\n nextCursorOffset = cursorOffset - 1\n }\n }\n // Regular right arrow\n else if (key.rightArrow) {\n if (showCursor && cursorOffset < originalValue.length) {\n nextCursorOffset = cursorOffset + 1\n }\n }\n // Backspace\n else if (key.backspace || key.delete) {\n if (cursorOffset > 0) {\n nextValue = originalValue.slice(0, cursorOffset - 1) + originalValue.slice(cursorOffset)\n nextCursorOffset = cursorOffset - 1\n }\n }\n // Regular character input\n else if (input && !key.ctrl && !key.meta) {\n nextValue = originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset)\n nextCursorOffset = cursorOffset + input.length\n }\n\n // Clamp cursor to valid range\n nextCursorOffset = Math.max(0, Math.min(nextCursorOffset, nextValue.length))\n\n setCursorOffset(nextCursorOffset)\n\n if (nextValue !== originalValue) {\n onChange(nextValue)\n }\n },\n { isActive: focus },\n )\n\n return (\n <Text>\n {placeholder ?\n originalValue.length > 0 ?\n renderedValue\n : renderedPlaceholder\n : renderedValue}\n </Text>\n )\n}\n\ntype Props = {\n value: string\n placeholder?: string\n focus?: boolean\n showCursor?: boolean\n onChange: (value: string) => void\n onSubmit?: (value: string) => void\n}\n","/**\n * Find the start of the previous word from cursor position.\n * A word is a sequence of non-whitespace characters.\n */\nexport const findPreviousWordBoundary = (\n /** The text to search */\n text: string,\n /** The current cursor position */\n cursorOffset: number,\n): number => {\n if (cursorOffset <= 0) return 0\n\n let pos = cursorOffset\n\n // Skip any whitespace immediately before cursor\n while (pos > 0 && /\\s/.test(text[pos - 1]!)) {\n pos--\n }\n\n // Skip the word (non-whitespace) characters\n while (pos > 0 && !/\\s/.test(text[pos - 1]!)) {\n pos--\n }\n\n return pos\n}\n","/**\n * Find the end of the next word from cursor position.\n * A word is a sequence of non-whitespace characters.\n */\nexport const findNextWordBoundary = (\n /** The text to search */\n text: string,\n /** The current cursor position */\n cursorOffset: number,\n): number => {\n if (cursorOffset >= text.length) return text.length\n\n let pos = cursorOffset\n\n // Skip any whitespace immediately after cursor\n while (pos < text.length && /\\s/.test(text[pos]!)) {\n pos++\n }\n\n // Skip the word (non-whitespace) characters\n while (pos < text.length && !/\\s/.test(text[pos]!)) {\n pos++\n }\n\n return pos\n}\n","import { execSync } from \"child_process\"\nimport { existsSync, readFileSync, writeFileSync } from \"fs\"\nimport { join } from \"path\"\nimport { insertTodo } from \"./insertTodo.js\"\n\n/**\n * Adds a todo item to the todo.md file and commits just that line.\n * Inserts the todo into the working directory, stages only that line, and commits.\n * Creates the file if it doesn't exist.\n */\nexport const addTodo = (\n /** The description of the todo item to add */\n description: string,\n /** The working directory to use (defaults to current directory) */\n cwd: string = process.cwd(),\n): void => {\n const todoPath = join(cwd, \".ralph\", \"todo.md\")\n\n // Read current working directory file (or empty string if it doesn't exist) and insert the new todo\n const content = existsSync(todoPath) ? readFileSync(todoPath, \"utf-8\") : \"\"\n const newContent = insertTodo(content, description)\n\n // Write updated content to working directory\n writeFileSync(todoPath, newContent)\n\n // Get what's currently in the index for this file (or HEAD if not staged, or empty if new)\n let indexContent = \"\"\n try {\n indexContent = execSync(\n \"git show :0:.ralph/todo.md 2>/dev/null || git show HEAD:.ralph/todo.md 2>/dev/null || echo ''\",\n {\n cwd,\n encoding: \"utf-8\",\n },\n )\n } catch {\n // File doesn't exist in git yet, use empty string\n indexContent = \"\"\n }\n\n // Create a blob with just the todo added to the index version\n const indexWithTodo = insertTodo(indexContent, description)\n const blobHash = execSync(\"git hash-object -w --stdin\", {\n cwd,\n encoding: \"utf-8\",\n input: indexWithTodo,\n }).trim()\n\n // Stage just our change by updating the index to this blob\n // Use --add flag to handle new files\n execSync(`git update-index --add --cacheinfo 100644,${blobHash},.ralph/todo.md`, {\n cwd,\n stdio: \"pipe\",\n })\n\n // Commit just the staged change - escape double quotes and backslashes in description\n const escapedDescription = description.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')\n execSync(`git commit -m \"todo: ${escapedDescription}\"`, { cwd, stdio: \"pipe\" })\n\n console.log(`✅ added`)\n}\n","/** Inserts a todo item into the content, right after the \"To do\" header. */\nexport const insertTodo = (\n /** The current content of the todo file */\n content: string,\n /** The description of the todo item to insert */\n description: string,\n): string => {\n const lines = content.split(\"\\n\")\n const todoHeaderIndex = lines.findIndex(line => /^###?\\s*To\\s*do/i.test(line))\n\n if (todoHeaderIndex === -1) {\n // No \"To do\" section found, add one at the beginning\n return `### To do\\n\\n- [ ] ${description}\\n\\n${content}`\n }\n\n // Find the first line after the header (skip empty lines)\n let insertIndex = todoHeaderIndex + 1\n while (insertIndex < lines.length && lines[insertIndex].trim() === \"\") {\n insertIndex++\n }\n\n // Insert the new todo item\n lines.splice(insertIndex, 0, `- [ ] ${description}`)\n\n return lines.join(\"\\n\")\n}\n","import { existsSync } from \"fs\"\nimport { join } from \"path\"\nimport { getBeadsProgress } from \"./getBeadsProgress.js\"\nimport { getTodoProgress } from \"./getTodoProgress.js\"\nimport type { ProgressData } from \"./types.js\"\n\nconst beadsDir = join(process.cwd(), \".beads\")\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/**\n * Get progress data from the workspace.\n *\n * For beads workspaces: Uses timestamp-based counting to accurately track\n * issues closed and created since startup.\n * For todo.md workspaces: completed = checked items, total = all items\n */\nexport const getProgress = (\n /** Initial count of open + in_progress issues at startup */\n initialCount: number,\n /** RFC3339 timestamp for counting issues created after this time */\n startupTimestamp: string,\n): ProgressData => {\n // Check for beads workspace first\n if (existsSync(beadsDir)) {\n return getBeadsProgress(initialCount, startupTimestamp)\n }\n\n // Check for todo.md\n if (existsSync(todoFile)) {\n return getTodoProgress()\n }\n\n return { type: \"none\", completed: 0, total: 0 }\n}\n","import { execSync } from \"child_process\"\nimport type { ProgressData } from \"./types.js\"\n\n/** Get progress for a beads workspace by counting issues created and closed since startup. */\nexport const getBeadsProgress = (\n /** Initial count of open + in_progress issues */\n initialCount: number,\n /** RFC3339 timestamp for counting issues created after this time */\n startupTimestamp: string,\n): ProgressData => {\n try {\n // Count issues created since startup\n const createdSinceStartup = parseInt(\n execSync(`bd count --created-after=\"${startupTimestamp}\"`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n\n // Count current open + in_progress issues\n const currentOpen = parseInt(\n execSync(\"bd count --status=open\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n const currentInProgress = parseInt(\n execSync(\"bd count --status=in_progress\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n const currentRemaining = currentOpen + currentInProgress\n\n // Total = initial open+in_progress + any new issues created\n const total = initialCount + createdSinceStartup\n // Completed = total - remaining (accounts for issues closed by any means)\n const completed = total - currentRemaining\n\n return { type: \"beads\", completed, total }\n } catch {\n // If bd command fails, return no progress\n return { type: \"none\", completed: 0, total: 0 }\n }\n}\n","import { readFileSync } from \"fs\"\nimport { join } from \"path\"\nimport type { ProgressData } from \"./types.js\"\n\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/** Get progress for a todo.md workspace by counting checked and unchecked items. */\nexport const getTodoProgress = (): ProgressData => {\n try {\n const content = readFileSync(todoFile, \"utf-8\")\n\n // Count unchecked items: - [ ]\n const uncheckedMatches = content.match(/- \\[ \\]/g)\n const unchecked = uncheckedMatches ? uncheckedMatches.length : 0\n\n // Count checked items: - [x] or - [X]\n const checkedMatches = content.match(/- \\[[xX]\\]/g)\n const checked = checkedMatches ? checkedMatches.length : 0\n\n const total = unchecked + checked\n\n return { type: \"todo\", completed: checked, total }\n } catch {\n return { type: \"none\", completed: 0, total: 0 }\n }\n}\n","import { existsSync } from \"fs\"\nimport { join } from \"path\"\nimport { captureBeadsSnapshot } from \"./captureBeadsSnapshot.js\"\nimport { captureTodoSnapshot } from \"./captureTodoSnapshot.js\"\nimport type { StartupSnapshot } from \"./types.js\"\n\nconst beadsDir = join(process.cwd(), \".beads\")\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/**\n * Capture a startup snapshot for beads workspaces.\n * Call this once at startup to capture the baseline count and timestamp.\n * Returns undefined if not a beads workspace.\n */\nexport const captureStartupSnapshot = (): StartupSnapshot | undefined => {\n // Check for beads workspace\n if (existsSync(beadsDir)) {\n return captureBeadsSnapshot()\n }\n\n // Check for todo.md workspace\n if (existsSync(todoFile)) {\n return captureTodoSnapshot()\n }\n\n return undefined\n}\n\n/** @deprecated Use captureStartupSnapshot instead */\nexport const getInitialBeadsCount = (): number | undefined => {\n const snapshot = captureStartupSnapshot()\n return snapshot?.initialCount\n}\n","import { execSync } from \"child_process\"\nimport type { StartupSnapshot } from \"./types.js\"\n\n/** Capture a startup snapshot for a beads workspace. */\nexport const captureBeadsSnapshot = (): StartupSnapshot | undefined => {\n try {\n const timestamp = new Date().toISOString()\n\n const openCount = parseInt(\n execSync(\"bd count --status=open\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n const inProgressCount = parseInt(\n execSync(\"bd count --status=in_progress\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n\n return {\n initialCount: openCount + inProgressCount,\n timestamp,\n type: \"beads\",\n }\n } catch {\n return undefined\n }\n}\n","import { readFileSync } from \"fs\"\nimport { join } from \"path\"\nimport type { StartupSnapshot } from \"./types.js\"\n\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/** Capture a startup snapshot for a todo.md workspace. */\nexport const captureTodoSnapshot = (): StartupSnapshot | undefined => {\n try {\n const content = readFileSync(todoFile, \"utf-8\")\n\n // Count all items (checked + unchecked)\n const uncheckedMatches = content.match(/- \\[ \\]/g)\n const unchecked = uncheckedMatches ? uncheckedMatches.length : 0\n\n const checkedMatches = content.match(/- \\[[xX]\\]/g)\n const checked = checkedMatches ? checkedMatches.length : 0\n\n return {\n initialCount: unchecked + checked,\n timestamp: new Date().toISOString(),\n type: \"todo\",\n }\n } catch {\n return undefined\n }\n}\n","import React from \"react\"\nimport { Text } from \"ink\"\n\n/**\n * A simple progress bar component using Unicode block characters.\n * Shows completion progress: completed / total\n */\nexport const ProgressBar = ({ completed, total, width = 12, repoName }: Props) => {\n if (total === 0) {\n return null\n }\n\n // Progress is how much is done: completed / total\n const progress = Math.min(1, Math.max(0, completed / total))\n const filledWidth = Math.round(progress * width)\n const emptyWidth = width - filledWidth\n\n const filled = \"▰\".repeat(filledWidth)\n const empty = \"▱\".repeat(emptyWidth)\n\n return (\n <Text>\n {repoName && (\n <>\n <Text color=\"cyan\">{repoName}</Text>\n <Text dimColor> │ </Text>\n </>\n )}\n <Text color=\"yellow\">{filled}</Text>\n <Text dimColor>{empty}</Text>\n <Text dimColor>\n {\" \"}\n {completed}/{total}{\" \"}\n </Text>\n </Text>\n )\n}\n\ntype Props = {\n /** Number of items completed (closed issues or checked tasks) */\n completed: number\n /** Total number of items seen since startup */\n total: number\n /** Width of the progress bar in characters (default: 12) */\n width?: number\n /** Repository name to display before the progress bar */\n repoName?: string\n}\n","import { createConnection, Socket } from \"net\"\nimport { join } from \"path\"\nimport { existsSync } from \"fs\"\nimport type { MutationEvent } from \"@herbcaudill/ralph-shared\"\n\n/** Re-export MutationEvent for backward compatibility */\nexport type { MutationEvent } from \"@herbcaudill/ralph-shared\"\n\nconst SOCKET_PATH = join(process.cwd(), \".beads\", \"bd.sock\")\n\ntype RPCRequest = {\n operation: string\n args: Record<string, unknown>\n}\n\ntype RPCResponse = {\n success: boolean\n data?: unknown\n error?: string\n}\n\n/**\n * Simple RPC client for beads daemon.\n * Connects to .beads/bd.sock and sends JSON-over-newline requests.\n */\nexport class BeadsClient {\n private socket: Socket | null = null\n private connected = false\n\n /**\n * Check if the beads daemon socket exists.\n */\n static socketExists(): boolean {\n return existsSync(SOCKET_PATH)\n }\n\n /**\n * Connect to the beads daemon.\n */\n async connect(): Promise<boolean> {\n if (!BeadsClient.socketExists()) {\n return false\n }\n\n return new Promise(resolve => {\n this.socket = createConnection(SOCKET_PATH)\n\n const timeout = setTimeout(() => {\n this.socket?.destroy()\n this.socket = null\n resolve(false)\n }, 2000)\n\n this.socket.on(\"connect\", () => {\n clearTimeout(timeout)\n this.connected = true\n resolve(true)\n })\n\n this.socket.on(\"error\", () => {\n clearTimeout(timeout)\n this.socket = null\n resolve(false)\n })\n })\n }\n\n /**\n * Send an RPC request and wait for response.\n */\n private async execute<T>(\n operation: string,\n args: Record<string, unknown> = {},\n ): Promise<T | null> {\n if (!this.socket || !this.connected) {\n return null\n }\n\n return new Promise(resolve => {\n const request: RPCRequest = { operation, args }\n const requestLine = JSON.stringify(request) + \"\\n\"\n\n let responseData = \"\"\n\n const onData = (chunk: Buffer) => {\n responseData += chunk.toString()\n if (responseData.includes(\"\\n\")) {\n cleanup()\n try {\n const response: RPCResponse = JSON.parse(responseData.trim())\n if (response.success && response.data) {\n resolve(response.data as T)\n } else {\n resolve(null)\n }\n } catch {\n resolve(null)\n }\n }\n }\n\n const onError = () => {\n cleanup()\n resolve(null)\n }\n\n const timeout = setTimeout(() => {\n cleanup()\n resolve(null)\n }, 5000)\n\n const cleanup = () => {\n clearTimeout(timeout)\n this.socket?.off(\"data\", onData)\n this.socket?.off(\"error\", onError)\n }\n\n this.socket!.on(\"data\", onData)\n this.socket!.on(\"error\", onError)\n this.socket!.write(requestLine)\n })\n }\n\n /**\n * Get mutations since a given timestamp.\n */\n async getMutations(\n /** Unix timestamp in milliseconds (0 for all recent) */\n since: number = 0,\n ): Promise<MutationEvent[]> {\n const result = await this.execute<MutationEvent[]>(\"get_mutations\", { since })\n return result ?? []\n }\n\n /**\n * Get ready issues (no blockers).\n */\n async getReady(): Promise<{ id: string; title: string }[]> {\n const result = await this.execute<{ id: string; title: string }[]>(\"ready\", {})\n return result ?? []\n }\n\n /**\n * Close the connection.\n */\n close(): void {\n if (this.socket) {\n this.socket.destroy()\n this.socket = null\n this.connected = false\n }\n }\n}\n\n/**\n * Poll for new issue creation events.\n * Returns a cleanup function.\n */\nexport function watchForNewIssues(\n onNewIssue: (issue: MutationEvent) => void,\n interval: number = 5000,\n): () => void {\n let lastTimestamp = Date.now()\n let client: BeadsClient | null = null\n let timeoutId: NodeJS.Timeout | null = null\n let stopped = false\n\n const poll = async () => {\n if (stopped) return\n\n if (!client) {\n client = new BeadsClient()\n const connected = await client.connect()\n if (!connected) {\n // Retry connection later\n timeoutId = setTimeout(poll, interval)\n return\n }\n }\n\n try {\n const mutations = await client.getMutations(lastTimestamp)\n\n for (const mutation of mutations) {\n if (mutation.Type === \"create\") {\n onNewIssue(mutation)\n }\n // Update timestamp to avoid re-processing\n const mutationTime = new Date(mutation.Timestamp).getTime()\n if (mutationTime > lastTimestamp) {\n lastTimestamp = mutationTime\n }\n }\n } catch {\n // Connection may have been lost, reset client\n client?.close()\n client = null\n }\n\n if (!stopped) {\n timeoutId = setTimeout(poll, interval)\n }\n }\n\n // Start polling\n poll()\n\n // Return cleanup function\n return () => {\n stopped = true\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n client?.close()\n }\n}\n","type DebugNamespace = \"messagequeue\" | \"session\" | \"sdk\" | \"stdin-command\" | \"worktree\"\n\n/**\n * Check if debug logging is enabled for the given namespace.\n * Controlled by RALPH_DEBUG environment variable:\n * - RALPH_DEBUG=1 or RALPH_DEBUG=true or RALPH_DEBUG=all - enable all logging\n * - RALPH_DEBUG=messagequeue - enable only that namespace\n * - RALPH_DEBUG=messagequeue,session - enable multiple namespaces\n */\nconst isDebugEnabled = (\n /** The debug namespace to check, or undefined to check global debug setting */\n namespace?: DebugNamespace,\n): boolean => {\n const debugEnv = process.env.RALPH_DEBUG\n\n if (!debugEnv) return false\n\n const value = debugEnv.toLowerCase()\n\n // Enable all debugging\n if (value === \"1\" || value === \"true\" || value === \"all\" || value === \"*\") {\n return true\n }\n\n // Enable specific namespace\n if (namespace && value === namespace.toLowerCase()) {\n return true\n }\n\n // Comma-separated list of namespaces\n if (namespace && value.includes(\",\")) {\n return value.split(\",\").some(ns => ns.trim().toLowerCase() === namespace.toLowerCase())\n }\n\n return false\n}\n\n/** Log a debug message if debugging is enabled for the given namespace. */\nexport const debug = (\n /** The debug namespace for this message */\n namespace: DebugNamespace,\n /** The message to log */\n message: string,\n /** Additional arguments to log after the message */\n ...args: unknown[]\n): void => {\n if (isDebugEnabled(namespace)) {\n const timestamp = new Date().toISOString()\n const prefix = `[${timestamp}] [RALPH:${namespace.toUpperCase()}]`\n // eslint-disable-next-line no-console\n console.error(prefix, message, ...args)\n }\n}\n\n/** Create a namespaced debug logger that captures the namespace for all logs. */\nexport const createDebugLogger = (\n /** The debug namespace to use for all logged messages */\n namespace: DebugNamespace,\n) => {\n return (\n /** The message to log */\n message: string,\n /** Additional arguments to log after the message */\n ...args: unknown[]\n ) => debug(namespace, message, ...args)\n}\n","import type { SDKUserMessage } from \"@anthropic-ai/claude-agent-sdk\"\n\n/** Create an SDKUserMessage from text. */\nexport const createUserMessage = (\n /** The text content of the message */\n text: string,\n): SDKUserMessage => ({\n type: \"user\",\n session_id: \"\",\n message: {\n role: \"user\",\n content: [{ type: \"text\", text }],\n },\n parent_tool_use_id: null,\n})\n","import type { SDKUserMessage } from \"@anthropic-ai/claude-agent-sdk\"\nimport { createDebugLogger } from \"./debug.js\"\nimport { createUserMessage } from \"./createUserMessage.js\"\n\nconst log = createDebugLogger(\"messagequeue\")\n\n/**\n * A message queue that can be used as an async iterable for the SDK's streamInput.\n * Allows pushing messages dynamically while iterating.\n */\nexport class MessageQueue implements AsyncIterable<SDKUserMessage> {\n private queue: SDKUserMessage[] = []\n private resolvers: Array<(result: IteratorResult<SDKUserMessage>) => void> = []\n private closed = false\n private nextCallCount = 0\n\n /**\n * Push a message to the queue. If there are pending resolvers waiting for the next message,\n * resolve immediately. Otherwise, add to queue.\n */\n push(\n /** The message to push to the queue */\n message: SDKUserMessage,\n ): void {\n const messagePreview = this.getMessagePreview(message)\n log(`push() called with message: ${messagePreview}`)\n\n if (this.closed) {\n log(`push() ignored - queue is closed`)\n return\n }\n\n if (this.resolvers.length > 0) {\n const resolve = this.resolvers.shift()!\n log(`push() resolving pending next() call (${this.resolvers.length} resolvers remaining)`)\n resolve({ value: message, done: false })\n } else {\n this.queue.push(message)\n log(`push() added to queue (queue length: ${this.queue.length})`)\n }\n }\n\n /**\n * Close the queue. Resolve any pending resolvers with done=true.\n */\n close(): void {\n if (this.closed) {\n log(`close() called but already closed - no-op`)\n return\n }\n log(`close() called - resolving ${this.resolvers.length} pending resolvers`)\n this.closed = true\n // Resolve any pending iterators\n for (const resolve of this.resolvers) {\n log(`close() resolving pending resolver with done=true`)\n resolve({ value: undefined as unknown as SDKUserMessage, done: true })\n }\n this.resolvers = []\n log(`close() complete`)\n }\n\n /**\n * Get a preview string of a message for debug logging.\n */\n private getMessagePreview(\n /** The message to extract a preview from */\n message: SDKUserMessage,\n ): string {\n const content = message.message?.content\n if (Array.isArray(content) && content.length > 0) {\n const firstBlock = content[0]\n if (\"text\" in firstBlock && typeof firstBlock.text === \"string\") {\n const text = firstBlock.text.slice(0, 50)\n return text.length < firstBlock.text.length ? `\"${text}...\"` : `\"${text}\"`\n }\n }\n return `[${message.type} message]`\n }\n\n /**\n * Implement the async iterable protocol to allow session with for-await-of.\n */\n [Symbol.asyncIterator](): AsyncIterator<SDKUserMessage> {\n return {\n next: (): Promise<IteratorResult<SDKUserMessage>> => {\n this.nextCallCount++\n const callId = this.nextCallCount\n\n if (this.queue.length > 0) {\n const message = this.queue.shift()!\n log(`next() #${callId}: returning queued message (${this.queue.length} remaining)`)\n return Promise.resolve({ value: message, done: false })\n }\n if (this.closed) {\n log(`next() #${callId}: queue closed, returning done=true`)\n return Promise.resolve({ value: undefined as unknown as SDKUserMessage, done: true })\n }\n log(\n `next() #${callId}: queue empty, creating pending resolver (${this.resolvers.length + 1} total)`,\n )\n return new Promise(resolve => {\n this.resolvers.push(resolve)\n })\n },\n }\n }\n}\n\nexport { createUserMessage }\n","import { useState, useEffect } from \"react\"\nimport { useStdout } from \"ink\"\nimport { getTerminalSize } from \"./getTerminalSize.js\"\n\n/** Hook to get the current terminal size and subscribe to resize events. */\nexport const useTerminalSize = () => {\n const { stdout } = useStdout()\n const [size, setSize] = useState(() => getTerminalSize(stdout))\n\n useEffect(() => {\n const handleResize = () => {\n setSize(getTerminalSize(stdout))\n }\n\n stdout?.on(\"resize\", handleResize)\n\n return () => {\n stdout?.off(\"resize\", handleResize)\n }\n }, [stdout])\n\n return size\n}\n","/** Get the current terminal size with sensible defaults. */\nexport function getTerminalSize(\n /** The stdout object from Ink's useStdout hook */\n stdout: any,\n) {\n return {\n columns: stdout?.columns ?? 80,\n rows: stdout?.rows ?? 24,\n }\n}\n","import { existsSync, mkdirSync } from \"fs\"\nimport { join } from \"path\"\nimport { findMaxLogNumber } from \"./findMaxLogNumber.js\"\n\n/**\n * Get the path to the next sequential log file in the .ralph directory.\n * Files are named events-1.jsonl, events-2.jsonl, etc.\n * Returns the path for the next available number (highest existing + 1).\n */\nexport const getNextLogFile = (): string => {\n const ralphDir = join(process.cwd(), \".ralph\")\n\n // Ensure .ralph directory exists\n if (!existsSync(ralphDir)) {\n mkdirSync(ralphDir, { recursive: true })\n }\n\n const maxNumber = findMaxLogNumber()\n return join(ralphDir, `events-${maxNumber + 1}.jsonl`)\n}\n","import { readdirSync, existsSync } from \"fs\"\nimport { join } from \"path\"\n\nconst EVENT_LOG_PATTERN = /^events-(\\d+)\\.jsonl$/\n\n/**\n * Find the highest numbered event log file that exists in the .ralph directory.\n * Returns 0 if no event logs exist.\n */\nexport const findMaxLogNumber = (): number => {\n const ralphDir = join(process.cwd(), \".ralph\")\n\n if (!existsSync(ralphDir)) {\n return 0\n }\n\n const files = readdirSync(ralphDir)\n let maxNumber = 0\n\n for (const file of files) {\n const match = file.match(EVENT_LOG_PATTERN)\n if (match) {\n const num = parseInt(match[1], 10)\n if (num > maxNumber) {\n maxNumber = num\n }\n }\n }\n\n return maxNumber\n}\n","/**\n * Parse a text message to detect task lifecycle events.\n * Returns TaskLifecycleInfo if the text matches the pattern, null otherwise.\n *\n * Patterns recognized:\n * - \"<start_task>task-id</start_task>\"\n * - \"<end_task>task-id</end_task>\"\n */\nexport function parseTaskLifecycleEvent(\n /** The text message to parse */\n text: string,\n): TaskLifecycleInfo | null {\n // Match starting pattern: <start_task>task-id</start_task>\n const startingMatch = text.match(/<start_task>([a-z]+-[a-z0-9]+(?:\\.[a-z0-9]+)*)<\\/start_task>/i)\n if (startingMatch) {\n return {\n action: \"starting\",\n taskId: startingMatch[1],\n }\n }\n\n // Match completed pattern: <end_task>task-id</end_task>\n const completedMatch = text.match(/<end_task>([a-z]+-[a-z0-9]+(?:\\.[a-z0-9]+)*)<\\/end_task>/i)\n if (completedMatch) {\n return {\n action: \"completed\",\n taskId: completedMatch[1],\n }\n }\n\n return null\n}\n\n/** Result of parsing a task lifecycle event. */\nexport interface TaskLifecycleInfo {\n action: \"starting\" | \"completed\"\n taskId?: string\n taskTitle?: string\n}\n","import { readFileSync, existsSync } from \"fs\"\nimport { join, dirname } from \"path\"\nimport { fileURLToPath } from \"url\"\n\n/**\n * Get the prompt content, falling back to templates if .ralph/prompt.md doesn't exist.\n * Uses the appropriate template based on the project setup:\n * - If .beads directory exists OR no .ralph/todo.md: use prompt-beads.md\n * - If .ralph/todo.md exists: use prompt-todos.md (todo-based workflow)\n */\nexport const getPromptContent = (): string => {\n const __dirname = dirname(fileURLToPath(import.meta.url))\n const ralphDir = join(process.cwd(), \".ralph\")\n const promptFile = join(ralphDir, \"prompt.md\")\n const todoFile = join(ralphDir, \"todo.md\")\n const beadsDir = join(process.cwd(), \".beads\")\n const templatesDir = join(__dirname, \"..\", \"..\", \"templates\")\n\n // First, try to read from .ralph/prompt.md\n if (existsSync(promptFile)) {\n return readFileSync(promptFile, \"utf-8\")\n }\n\n // Fall back to templates based on project setup\n const useBeadsTemplate = existsSync(beadsDir) || !existsSync(todoFile)\n const templateFile = useBeadsTemplate ? \"prompt-beads.md\" : \"prompt-todos.md\"\n const templatePath = join(templatesDir, templateFile)\n\n if (existsSync(templatePath)) {\n return readFileSync(templatePath, \"utf-8\")\n }\n\n // Last resort: return a minimal prompt\n return \"Work on the highest-priority task.\"\n}\n","import { type SDKMessage } from \"@anthropic-ai/claude-agent-sdk\"\n\n/** Convert SDK message to event format for display. */\nexport const sdkMessageToEvent = (\n /** The SDK message to convert */\n message: SDKMessage,\n): Record<string, unknown> | null => {\n // Pass through messages that have the structure we expect\n if (message.type === \"assistant\" || message.type === \"user\" || message.type === \"result\") {\n return message as unknown as Record<string, unknown>\n }\n // Skip system and stream_event messages for display\n return null\n}\n","import { isAbsolute, relative } from \"path\"\nimport { getBaseCwd } from \"./getBaseCwd.js\"\n\n/**\n * Convert an absolute path to a relative path from the base working directory.\n * For temp files, returns just the filename. Leaves relative paths unchanged.\n */\nexport const rel = (\n /** The path to convert */\n path: string,\n) => {\n if (!isAbsolute(path)) {\n return path\n }\n // For temp files, just show the filename\n if (path.includes(\"/var/folders/\") || path.includes(\"/tmp/\")) {\n return path.split(\"/\").pop() || path\n }\n return relative(getBaseCwd(), path) || path\n}\n","/**\n * Get the base working directory for relative path calculations.\n * Respects RALPH_CWD environment variable if set, otherwise uses current working directory.\n */\nexport const getBaseCwd = () => process.env.RALPH_CWD ?? process.cwd()\n","/**\n * Replace temp file paths with just the filename.\n * Shortens macOS and Linux temporary paths to be more readable in output.\n */\nexport const shortenTempPaths = (\n /** The text to process */\n text: string,\n) => {\n return text\n .replace(/\\/var\\/folders\\/[^\\s]+/g, match => match.split(\"/\").pop() || match)\n .replace(/\\/tmp\\/[^\\s]+/g, match => match.split(\"/\").pop() || match)\n}\n","import { rel } from \"../lib/rel.js\"\nimport { shortenTempPaths } from \"../lib/shortenTempPaths.js\"\n\n/**\n * Transform an event from the Claude SDK into display blocks.\n * Extracts text content and tool use information from assistant and user messages.\n */\nexport const eventToBlocks = (\n /** The event object from Claude SDK containing message data */\n event: Record<string, unknown>,\n): ContentBlock[] => {\n // Handle user messages\n if (event.type === \"user\") {\n const message = event.message as Record<string, unknown> | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n const messageId = (message?.id as string | undefined) ?? `user-${Date.now()}`\n\n if (!content) {\n return []\n }\n\n // Extract text from user message content\n const textContent = content\n .filter(block => block.type === \"text\")\n .map(block => block.text as string)\n .join(\"\")\n\n if (textContent) {\n return [{ type: \"user\", content: textContent, id: messageId }]\n }\n return []\n }\n\n if (event.type !== \"assistant\") {\n return []\n }\n\n const message = event.message as Record<string, unknown> | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n\n if (!content) {\n return []\n }\n\n const blocks: ContentBlock[] = []\n const messageId = (message?.id as string | undefined) ?? \"unknown\"\n let blockIndex = 0\n\n let textBuffer = \"\" // Accumulate consecutive text blocks\n\n for (const block of content) {\n if (block.type === \"text\") {\n const text = block.text as string | undefined\n if (text) {\n textBuffer += text\n }\n } else if (block.type === \"tool_use\") {\n // Flush accumulated text before processing tool\n if (textBuffer) {\n blocks.push({ type: \"text\", content: textBuffer, id: `${messageId}-${blockIndex++}` })\n textBuffer = \"\"\n }\n const input = block.input as Record<string, unknown> | undefined\n const name = block.name as string\n\n if (name === \"Read\") {\n const filePath = input?.file_path as string | undefined\n if (filePath) {\n blocks.push({\n type: \"tool\",\n name: \"Read\",\n arg: rel(filePath),\n id: `${messageId}-${blockIndex++}`,\n })\n }\n } else if (name === \"Edit\" || name === \"Write\") {\n const filePath = input?.file_path as string | undefined\n if (filePath) {\n blocks.push({\n type: \"tool\",\n name,\n arg: rel(filePath),\n id: `${messageId}-${blockIndex++}`,\n })\n }\n } else if (name === \"Bash\") {\n const command = input?.command as string | undefined\n if (command) {\n blocks.push({\n type: \"tool\",\n name: \"$\",\n arg: shortenTempPaths(command),\n id: `${messageId}-${blockIndex++}`,\n })\n }\n } else if (name === \"Grep\") {\n const pattern = input?.pattern as string | undefined\n const path = input?.path as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"Grep\",\n arg: `${pattern}${path ? ` in ${rel(path)}` : \"\"}`,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"Glob\") {\n const pattern = input?.pattern as string | undefined\n const path = input?.path as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"Glob\",\n arg: `${pattern}${path ? ` in ${rel(path)}` : \"\"}`,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"TodoWrite\") {\n const todos = input?.todos as Array<{ content: string; status: string }> | undefined\n if (todos?.length) {\n const summary = todos\n .map(\n t =>\n `[${\n t.status === \"completed\" ? \"x\"\n : t.status === \"in_progress\" ? \"~\"\n : \" \"\n }] ${t.content}`,\n )\n .join(\"\\n \")\n blocks.push({\n type: \"tool\",\n name: \"TodoWrite\",\n arg: \"\\n \" + summary,\n id: `${messageId}-${blockIndex++}`,\n })\n } else {\n blocks.push({ type: \"tool\", name: \"TodoWrite\", id: `${messageId}-${blockIndex++}` })\n }\n } else if (name === \"WebFetch\") {\n const url = input?.url as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"WebFetch\",\n arg: url,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"WebSearch\") {\n const query = input?.query as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"WebSearch\",\n arg: query,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"Task\") {\n const description = input?.description as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"Task\",\n arg: description,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"Skill\") {\n const skill = input?.skill as string | undefined\n blocks.push({ type: \"tool\", name: \"Skill\", arg: skill, id: `${messageId}-${blockIndex++}` })\n }\n }\n }\n\n // Flush any remaining text at the end\n if (textBuffer) {\n blocks.push({ type: \"text\", content: textBuffer, id: `${messageId}-${blockIndex++}` })\n }\n\n return blocks\n}\n\nexport type ContentBlock =\n | { type: \"text\"; content: string; id: string }\n | { type: \"tool\"; name: string; arg?: string; id: string }\n | { type: \"user\"; content: string; id: string }\n","import { eventToBlocks, type ContentBlock } from \"../components/eventToBlocks.js\"\n\n/**\n * Process raw events into content blocks.\n *\n * With includePartialMessages: true, we receive multiple snapshots of the same message\n * as it builds up. Each snapshot may contain different parts of the message content,\n * so we need to merge them and deduplicate.\n */\nexport const processEvents = (\n /** Array of raw event objects from the SDK */\n events: Array<Record<string, unknown>>,\n): ContentBlock[] => {\n const blocks: ContentBlock[] = []\n\n // First pass: collect all assistant message content and track message order\n const assistantEvents = events.filter(event => event.type === \"assistant\")\n\n // Collect all content blocks from all snapshots of the same message\n const messageMap = new Map<string, Array<Record<string, unknown>>>()\n for (const event of assistantEvents) {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = message?.id as string | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n\n if (messageId && content) {\n if (!messageMap.has(messageId)) {\n messageMap.set(messageId, [])\n }\n messageMap.get(messageId)!.push(...content)\n }\n }\n\n // Create merged events with deduplicated content\n const mergedEvents = Array.from(messageMap.entries()).map(([messageId, allContent]) => {\n // Deduplicate content blocks by their ID (for tool_use) or text (for text blocks)\n const seenBlocks = new Set<string>()\n const uniqueContent: Array<Record<string, unknown>> = []\n\n for (const block of allContent) {\n const blockType = block.type as string\n let blockKey: string\n\n if (blockType === \"tool_use\") {\n // Tool use blocks are unique by their ID\n blockKey = `tool:${block.id}`\n } else if (blockType === \"text\") {\n // For text blocks, check if this is a prefix of or prefixed by existing text\n // This handles incremental text updates where each snapshot has more content\n const text = block.text as string\n let isDuplicate = false\n\n for (const seenKey of seenBlocks) {\n if (seenKey.startsWith(\"text:\")) {\n const seenText = seenKey.substring(5)\n // If existing text starts with this text, or this text starts with existing,\n // keep only the longer one\n if (seenText.startsWith(text)) {\n // Existing is longer, this is a duplicate\n isDuplicate = true\n break\n } else if (text.startsWith(seenText)) {\n // This is longer, remove the old one and add this\n seenBlocks.delete(seenKey)\n // Also remove from uniqueContent\n const idx = uniqueContent.findIndex(b => b.type === \"text\" && b.text === seenText)\n if (idx >= 0) uniqueContent.splice(idx, 1)\n break\n }\n }\n }\n\n if (isDuplicate) continue\n blockKey = `text:${text}`\n } else {\n blockKey = JSON.stringify(block)\n }\n\n if (!seenBlocks.has(blockKey)) {\n seenBlocks.add(blockKey)\n uniqueContent.push(block)\n }\n }\n\n return {\n type: \"assistant\",\n message: {\n id: messageId,\n content: uniqueContent,\n },\n }\n })\n\n const assistantBlocks = mergedEvents.flatMap(event => eventToBlocks(event))\n\n // Second pass: process events in order, including user messages\n // Track which user messages and assistant messages we've already seen\n const processedUserIds = new Set<string>()\n const processedAssistantIds = new Set<string>()\n\n for (const event of events) {\n if (event.type === \"user\") {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = (message?.id as string | undefined) ?? `user-${Date.now()}`\n if (!processedUserIds.has(messageId)) {\n processedUserIds.add(messageId)\n blocks.push(...eventToBlocks(event))\n }\n } else if (event.type === \"assistant\") {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = message?.id as string | undefined\n if (messageId && !processedAssistantIds.has(messageId)) {\n processedAssistantIds.add(messageId)\n // Find the merged version of this message\n const merged = assistantBlocks.filter(b => b.id.startsWith(messageId))\n blocks.push(...merged)\n }\n }\n }\n\n return blocks\n}\n","import React from \"react\"\nimport { Box, Text } from \"ink\"\nimport BigText from \"ink-big-text\"\nimport Gradient from \"ink-gradient\"\nimport { Header } from \"./Header.js\"\nimport { formatContentBlock } from \"../lib/formatContentBlock.js\"\nimport { type StaticItem } from \"./SessionRunner.types.js\"\n\n/** Render a static item (header, session header, or content block). */\nexport const renderStaticItem = (\n /** The static item to render */\n item: StaticItem,\n): React.ReactNode => {\n if (item.type === \"header\") {\n return <Header claudeVersion={item.claudeVersion} ralphVersion={item.ralphVersion} />\n }\n if (item.type === \"session\") {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Gradient colors={[\"#30A6E4\", \"#EBC635\"]}>\n <BigText text={`R${item.session}`} font=\"tiny\" />\n </Gradient>\n </Box>\n )\n }\n // Content block\n const lines = formatContentBlock(item.block)\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n {lines.map((line, i) => (\n <Text key={i}>{line || \" \"}</Text>\n ))}\n </Box>\n )\n}\n","import React from \"react\"\nimport { Box, Text } from \"ink\"\nimport BigText from \"ink-big-text\"\nimport Gradient from \"ink-gradient\"\n\n/** Display the Ralph header with version information and branding. */\nexport const Header = ({\n /** The Claude CLI version */\n claudeVersion,\n /** The Ralph version */\n ralphVersion,\n /** Optional box width */\n width,\n}: Props) => {\n return (\n <Box\n flexDirection=\"column\"\n marginBottom={1}\n borderStyle=\"single\"\n alignItems=\"center\"\n width={width}\n paddingX={2}\n >\n <Gradient colors={[\"#30A6E4\", \"#EBC635\"]}>\n <BigText text=\"Ralph\" font=\"tiny\" />\n </Gradient>\n <Text dimColor>\n @herbcaudill/ralph v{ralphVersion} • Claude Code v{claudeVersion}\n </Text>\n </Box>\n )\n}\n\ntype Props = {\n claudeVersion: string\n ralphVersion: string\n width?: number\n}\n","import chalk from \"chalk\"\n\n/** Format a text string with markdown-style formatting (bold and inline code) */\nexport const formatText = (\n /** The content to format */\n content: string,\n): string => {\n let result = \"\"\n let i = 0\n let inBold = false\n let inCode = false\n\n while (i < content.length) {\n if (content[i] === \"*\" && content[i + 1] === \"*\") {\n inBold = !inBold\n i += 2\n } else if (content[i] === \"`\") {\n inCode = !inCode\n i++\n } else {\n let char = content[i]\n\n if (inCode) {\n char = chalk.yellow(char)\n } else if (inBold) {\n char = chalk.bold(char)\n }\n\n result += char\n i++\n }\n }\n\n return result\n}\n","import chalk from \"chalk\"\n\n/** Format a tool use block as a string */\nexport const formatToolUse = (\n /** The name of the tool */\n name: string,\n /** Optional argument for the tool */\n arg?: string,\n): string => {\n const formattedName = chalk.blue(name)\n if (arg) {\n return ` ${formattedName} ${chalk.dim(arg)}`\n }\n return ` ${formattedName}`\n}\n","import chalk from \"chalk\"\n\n/** Format a user message */\nexport const formatUserMessage = (\n /** The message content to format */\n content: string,\n): string => {\n return chalk.green(content)\n}\n","import type { ContentBlock } from \"../components/eventToBlocks.js\"\nimport { formatText } from \"./formatText.js\"\nimport { formatToolUse } from \"./formatToolUse.js\"\nimport { formatUserMessage } from \"./formatUserMessage.js\"\n\n/** Convert a content block to formatted string lines */\nexport const formatContentBlock = (\n /** Content block to format */\n block: ContentBlock,\n): string[] => {\n if (block.type === \"text\") {\n const formatted = formatText(block.content)\n // Split into lines, preserving empty lines for paragraph breaks\n return formatted.split(\"\\n\")\n }\n\n if (block.type === \"user\") {\n return [formatUserMessage(block.content)]\n }\n\n return [formatToolUse(block.name, block.arg)]\n}\n","import React, { useState, useEffect } from \"react\"\nimport { Box, Text, useApp } from \"ink\"\nimport { readFileSync } from \"fs\"\nimport { EventDisplay } from \"./EventDisplay.js\"\nimport { FullScreenLayout } from \"./FullScreenLayout.js\"\nimport { useContentHeight } from \"./useContentHeight.js\"\n\nexport const ReplayLog = ({\n /** The path to the replay log file */\n filePath,\n}: Props) => {\n const { exit } = useApp()\n const [events, setEvents] = useState<Array<Record<string, unknown>>>([])\n const [error, setError] = useState<string>()\n\n /**\n * Load and parse the replay log file on mount.\n * Parses pretty-printed JSON objects separated by blank lines.\n */\n useEffect(() => {\n try {\n const content = readFileSync(filePath, \"utf-8\")\n // Log file contains pretty-printed JSON objects separated by blank lines\n const eventStrings = content.split(/\\n\\n+/).filter(s => s.trim())\n\n const parsedEvents: Array<Record<string, unknown>> = []\n for (const eventStr of eventStrings) {\n try {\n const event = JSON.parse(eventStr)\n parsedEvents.push(event)\n } catch {\n // Skip malformed entries\n }\n }\n\n setEvents(parsedEvents)\n setTimeout(() => {\n exit()\n process.exit(0)\n }, 100)\n } catch (err) {\n setError(`Failed to read replay file: ${err instanceof Error ? err.message : String(err)}`)\n setTimeout(() => {\n exit()\n process.exit(1)\n }, 100)\n }\n }, [filePath, exit])\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n const footer = <Text dimColor>Replaying: {filePath}</Text>\n const contentHeight = useContentHeight(true)\n\n return (\n <FullScreenLayout title=\"Ralph\" footer={footer}>\n <EventDisplay events={events} session={1} completedSessions={[]} height={contentHeight} />\n </FullScreenLayout>\n )\n}\n\ntype Props = {\n filePath: string\n}\n","import React, { useMemo, useState, useEffect, useRef } from \"react\"\nimport { Box, Text, useInput } from \"ink\"\nimport { formatSessionHeader } from \"../lib/formatSessionHeader.js\"\nimport { processEvents } from \"./processEvents.js\"\nimport { blocksToLines } from \"./blocksToLines.js\"\n\nexport const EventDisplay = ({ events, session, completedSessions, height }: Props) => {\n // Scroll offset from bottom (0 = at bottom, positive = scrolled up)\n const [scrollOffset, setScrollOffset] = useState(0)\n // Track if user has manually scrolled\n const userScrolledRef = useRef(false)\n // Track previous line count for auto-scroll\n const prevLineCountRef = useRef(0)\n\n // Convert all content to lines for virtual scrolling\n const allLines = useMemo(() => {\n const lines: string[] = []\n\n // Add completed sessions\n for (const completed of completedSessions) {\n lines.push(\"\")\n lines.push(\"\")\n lines.push(formatSessionHeader(completed.session))\n lines.push(\"\")\n const blocks = processEvents(completed.events)\n lines.push(...blocksToLines(blocks))\n }\n\n // Add current session\n lines.push(\"\")\n lines.push(\"\")\n lines.push(formatSessionHeader(session))\n lines.push(\"\")\n const currentBlocks = processEvents(events)\n lines.push(...blocksToLines(currentBlocks))\n\n return lines\n }, [events, session, completedSessions])\n\n // Auto-scroll to bottom when new content arrives (unless user scrolled up)\n useEffect(() => {\n if (allLines.length > prevLineCountRef.current && !userScrolledRef.current) {\n setScrollOffset(0)\n }\n prevLineCountRef.current = allLines.length\n }, [allLines.length])\n\n // Handle keyboard input for scrolling\n useInput((input, key) => {\n if (!height) return\n\n const maxOffset = Math.max(0, allLines.length - height)\n const pageSize = Math.max(1, height - 2)\n\n if (key.upArrow || input === \"k\") {\n userScrolledRef.current = true\n setScrollOffset(prev => Math.min(maxOffset, prev + 1))\n } else if (key.downArrow || input === \"j\") {\n const newOffset = Math.max(0, scrollOffset - 1)\n setScrollOffset(newOffset)\n if (newOffset === 0) {\n userScrolledRef.current = false\n }\n } else if (key.pageUp) {\n userScrolledRef.current = true\n setScrollOffset(prev => Math.min(maxOffset, prev + pageSize))\n } else if (key.pageDown) {\n const newOffset = Math.max(0, scrollOffset - pageSize)\n setScrollOffset(newOffset)\n if (newOffset === 0) {\n userScrolledRef.current = false\n }\n } else if (input === \"g\" && key.shift) {\n // Shift+G = go to bottom\n setScrollOffset(0)\n userScrolledRef.current = false\n } else if (input === \"g\") {\n // g = go to top\n userScrolledRef.current = true\n setScrollOffset(maxOffset)\n }\n })\n\n // Calculate visible lines based on scroll position\n const visibleLines = useMemo(() => {\n if (!height || allLines.length <= height) {\n return allLines\n }\n const endIndex = allLines.length - scrollOffset\n const startIndex = Math.max(0, endIndex - height)\n return allLines.slice(startIndex, endIndex)\n }, [allLines, height, scrollOffset])\n\n return (\n <Box flexDirection=\"column\">\n {visibleLines.map((line, index) => (\n <Text key={index} wrap=\"wrap\">\n {line || \" \"}\n </Text>\n ))}\n </Box>\n )\n}\n\ntype SessionEvents = {\n session: number\n events: Array<Record<string, unknown>>\n}\n\ntype Props = {\n events: Array<Record<string, unknown>>\n session: number\n completedSessions: SessionEvents[]\n height?: number\n}\n","import chalk from \"chalk\"\n\n/** Format a round header */\nexport const formatSessionHeader = (\n /** Session number to display */\n session: number,\n): string => {\n return chalk.cyan.bold(`─── Round ${session} ───`)\n}\n","import type { ContentBlock } from \"./eventToBlocks.js\"\nimport { eventToBlocks } from \"./eventToBlocks.js\"\n\n/**\n * Process raw events into content blocks.\n * With includePartialMessages: true, we receive multiple snapshots of the same message\n * as it builds up. Each snapshot may contain different parts of the message content,\n * so we need to merge them and deduplicate.\n */\nexport const processEvents = (\n /** Events to process */\n events: Array<Record<string, unknown>>,\n): ContentBlock[] => {\n // Filter to only show complete assistant messages, not streaming events\n // streaming events are incomplete and cause duplicate/disappearing content\n const assistantEvents = events.filter(event => event.type === \"assistant\")\n\n // Collect all content blocks from all snapshots of the same message\n const messageMap = new Map<string, Array<Record<string, unknown>>>()\n for (const event of assistantEvents) {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = message?.id as string | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n\n if (messageId && content) {\n if (!messageMap.has(messageId)) {\n messageMap.set(messageId, [])\n }\n messageMap.get(messageId)!.push(...content)\n }\n }\n\n // Create merged events with deduplicated content\n const mergedEvents = Array.from(messageMap.entries()).map(([messageId, allContent]) => {\n // Deduplicate content blocks by their ID (for tool_use) or text (for text blocks)\n const seenBlocks = new Set<string>()\n const uniqueContent: Array<Record<string, unknown>> = []\n\n for (const block of allContent) {\n const blockType = block.type as string\n let blockKey: string\n\n if (blockType === \"tool_use\") {\n // Tool use blocks are unique by their ID\n blockKey = `tool:${block.id}`\n } else if (blockType === \"text\") {\n // For text blocks, check if this is a prefix of or prefixed by existing text\n // This handles incremental text updates where each snapshot has more content\n const text = block.text as string\n let isDuplicate = false\n\n for (const seenKey of seenBlocks) {\n if (seenKey.startsWith(\"text:\")) {\n const seenText = seenKey.substring(5)\n // If existing text starts with this text, or this text starts with existing,\n // keep only the longer one\n if (seenText.startsWith(text)) {\n // Existing is longer, this is a duplicate\n isDuplicate = true\n break\n } else if (text.startsWith(seenText)) {\n // This is longer, remove the old one and add this\n seenBlocks.delete(seenKey)\n // Also remove from uniqueContent\n const idx = uniqueContent.findIndex(b => b.type === \"text\" && b.text === seenText)\n if (idx >= 0) uniqueContent.splice(idx, 1)\n break\n }\n }\n }\n\n if (isDuplicate) continue\n blockKey = `text:${text}`\n } else {\n blockKey = JSON.stringify(block)\n }\n\n if (!seenBlocks.has(blockKey)) {\n seenBlocks.add(blockKey)\n uniqueContent.push(block)\n }\n }\n\n return {\n type: \"assistant\",\n message: {\n id: messageId,\n content: uniqueContent,\n },\n }\n })\n\n return mergedEvents.flatMap(event => eventToBlocks(event))\n}\n","import type { ContentBlock } from \"./eventToBlocks.js\"\nimport { formatContentBlock } from \"../lib/formatContentBlock.js\"\n\n/** Convert content blocks to lines of formatted text. */\nexport const blocksToLines = (\n /** Content blocks to convert */\n blocks: ContentBlock[],\n): string[] => {\n const lines: string[] = []\n for (const block of blocks) {\n const blockLines = formatContentBlock(block)\n lines.push(...blockLines)\n // Add blank line after each block\n lines.push(\"\")\n }\n return lines\n}\n","import React, { ReactNode } from \"react\"\nimport { Box, Text } from \"ink\"\nimport BigText from \"ink-big-text\"\nimport Gradient from \"ink-gradient\"\nimport { useTerminalSize } from \"../lib/useTerminalSize.js\"\nimport { useContentHeight, HEADER_HEIGHT, FOOTER_HEIGHT } from \"./useContentHeight.js\"\n\n/** Full-screen layout component with header, content area, and optional footer */\nexport const FullScreenLayout = ({ title, children, footer, version }: Props) => {\n const { columns, rows } = useTerminalSize()\n const contentHeight = useContentHeight(!!footer)\n\n return (\n <Box\n flexDirection=\"column\"\n width={columns}\n height={rows}\n borderStyle=\"round\"\n borderColor=\"gray\"\n >\n {/* Header section */}\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n justifyContent=\"center\"\n height={HEADER_HEIGHT}\n borderStyle=\"single\"\n borderTop={false}\n borderLeft={false}\n borderRight={false}\n borderColor=\"gray\"\n >\n <Gradient colors={[\"#30A6E4\", \"#EBC635\"]}>\n <BigText text={title} font=\"tiny\" />\n </Gradient>\n </Box>\n\n {/* Content section */}\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n paddingX={1}\n height={contentHeight}\n overflowY=\"hidden\"\n >\n {children}\n </Box>\n\n {/* Footer section */}\n {footer && (\n <Box\n paddingX={1}\n height={FOOTER_HEIGHT}\n borderStyle=\"single\"\n borderTop\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor=\"gray\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n >\n <Box>{footer}</Box>\n {version && <Text dimColor>{version}</Text>}\n </Box>\n )}\n </Box>\n )\n}\n\ntype Props = {\n /** Title text displayed in the header */\n title: string\n /** Content to render in the main area */\n children: ReactNode\n /** Optional footer content */\n footer?: ReactNode\n /** Optional version string displayed in the footer */\n version?: string\n}\n","import { useTerminalSize } from \"../lib/useTerminalSize.js\"\n\n/** BigText \"tiny\" font takes 4 rows, plus 1 for separator */\nexport const HEADER_HEIGHT = 5\n\n/** Separator plus content row */\nexport const FOOTER_HEIGHT = 2\n\n/** Top and bottom borders */\nconst BORDER_HEIGHT = 2\n\n/** Calculate the available content height based on terminal size */\nexport const useContentHeight = (\n /** Whether the layout includes a footer */\n hasFooter: boolean = true,\n): number => {\n const { rows } = useTerminalSize()\n const footerHeight = hasFooter ? FOOTER_HEIGHT : 0\n return Math.max(1, rows - HEADER_HEIGHT - footerHeight - BORDER_HEIGHT)\n}\n","import React, { useState, useEffect, useRef } from \"react\"\nimport { useApp, Text } from \"ink\"\nimport { writeFileSync, readFileSync, existsSync } from \"fs\"\nimport { join, basename } from \"path\"\nimport { query, type SDKMessage } from \"@anthropic-ai/claude-agent-sdk\"\nimport { MessageQueue, createUserMessage } from \"../lib/MessageQueue.js\"\nimport { getProgress } from \"../lib/getProgress.js\"\nimport { captureStartupSnapshot } from \"../lib/captureStartupSnapshot.js\"\nimport type { StartupSnapshot } from \"../lib/types.js\"\nimport { createDebugLogger } from \"../lib/debug.js\"\nimport { getNextLogFile } from \"../lib/getNextLogFile.js\"\nimport { createStdinCommandHandler } from \"../lib/createStdinCommandHandler.js\"\nimport { parseTaskLifecycleEvent } from \"../lib/parseTaskLifecycle.js\"\nimport { getPromptContent } from \"../lib/getPromptContent.js\"\nimport { outputEvent } from \"../lib/outputEvent.js\"\n\n/** Debug logger for session lifecycle events */\nconst log = createDebugLogger(\"session\")\n\n/** Path to the todo.md file in the .ralph directory */\nconst todoFile = join(process.cwd(), \".ralph\", \"todo.md\")\n\n/** Name of the current repository */\nconst repoName = basename(process.cwd())\n\n/**\n * Component that runs Claude Agent SDK sessions in JSON output mode.\n * Manages message queues, task lifecycle tracking, pause/resume, and\n * streams SDK events to stdout as newline-delimited JSON.\n */\nexport const JsonOutput = ({ totalSessions, agent }: Props) => {\n const { exit } = useApp()\n const [currentSession, setCurrentSession] = useState(1)\n const [error, setError] = useState<string>()\n const [isRunning, setIsRunning] = useState(false)\n const [startupSnapshot] = useState<StartupSnapshot | undefined>(() => captureStartupSnapshot())\n const messageQueueRef = useRef<MessageQueue | null>(null)\n // Log file path for this run (set once at startup, persisted across sessions)\n const logFileRef = useRef<string | null>(null)\n const [stopAfterCurrent, setStopAfterCurrent] = useState(false) // Stop gracefully after current session\n const stopAfterCurrentRef = useRef(false) // Ref to access in async callbacks\n const [isPaused, setIsPaused] = useState(false) // Pause after current session completes\n const isPausedRef = useRef(false) // Ref to access in async callbacks\n const stdinCleanupRef = useRef<(() => void) | null>(null)\n const currentTaskIdRef = useRef<string | null>(null)\n const currentTaskTitleRef = useRef<string | null>(null)\n\n // Keep stopAfterCurrent ref in sync with state\n useEffect(() => {\n stopAfterCurrentRef.current = stopAfterCurrent\n }, [stopAfterCurrent])\n\n // Keep isPaused ref in sync with state\n useEffect(() => {\n isPausedRef.current = isPaused\n }, [isPaused])\n\n // Set up stdin command handler for receiving commands via piped input\n useEffect(() => {\n const cleanup = createStdinCommandHandler(() => ({\n messageQueue: messageQueueRef.current,\n onStop: () => {\n setStopAfterCurrent(true)\n outputEvent({ type: \"ralph_stop_requested\" })\n },\n onPause: () => {\n setIsPaused(true)\n outputEvent({ type: \"ralph_pause_requested\" })\n },\n onResume: () => {\n const wasPaused = isPausedRef.current\n setIsPaused(false)\n outputEvent({ type: \"ralph_resumed\" })\n // If we were paused between sessions, trigger the next session\n if (wasPaused && !isRunning) {\n setTimeout(() => setCurrentSession(i => i + 1), 100)\n }\n },\n onMessage: (text: string) => {\n // Output event showing we received a message command\n outputEvent({\n type: \"ralph_message_received\",\n text: text.slice(0, 100) + (text.length > 100 ? \"...\" : \"\"),\n })\n },\n }))\n stdinCleanupRef.current = cleanup\n\n return () => {\n cleanup()\n stdinCleanupRef.current = null\n }\n }, [])\n\n useEffect(() => {\n if (currentSession > totalSessions) {\n outputEvent({ type: \"ralph_exit\", reason: \"max_sessions\" })\n exit()\n return\n }\n\n // Check if there are any tasks available before starting a round\n const currentProgress =\n startupSnapshot ?\n getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp)\n : { type: \"none\" as const, completed: 0, total: 0 }\n\n // All tasks are complete when completed equals total\n if (currentProgress.completed >= currentProgress.total && currentProgress.type !== \"none\") {\n outputEvent({ type: \"ralph_exit\", reason: \"all_tasks_complete\" })\n exit()\n process.exit(0)\n return\n }\n\n // Get or create the log file path for this run\n // Only create a new sequential log file on the first session\n if (!logFileRef.current) {\n logFileRef.current = getNextLogFile()\n writeFileSync(logFileRef.current, \"\")\n }\n\n // Read prompt (from .ralph/prompt.md or falling back to templates)\n const promptContent = getPromptContent()\n const todoExists = existsSync(todoFile)\n const todoContent = todoExists ? readFileSync(todoFile, \"utf-8\") : \"\"\n const fullPrompt =\n todoContent ? `${promptContent}\\n\\n## Current Todo List\\n\\n${todoContent}` : promptContent\n\n const abortController = new AbortController()\n setIsRunning(true)\n\n // Output session start event\n outputEvent({\n type: \"ralph_session_start\",\n session: currentSession,\n totalSessions,\n repo: repoName,\n taskId: currentTaskIdRef.current,\n taskTitle: currentTaskTitleRef.current,\n })\n\n // Create a message queue for this session\n const messageQueue = new MessageQueue()\n messageQueueRef.current = messageQueue\n\n // Push the initial prompt as the first message\n messageQueue.push(createUserMessage(fullPrompt))\n\n const runQuery = async () => {\n let finalResult = \"\"\n log(`Starting session ${currentSession}`)\n\n try {\n log(`Beginning query() loop`)\n for await (const message of query({\n prompt: messageQueue,\n options: {\n abortController,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n includePartialMessages: false, // Only complete messages for JSON output\n env: {\n ...process.env,\n // Disable LSP plugins to avoid crashes when TypeScript LSP server errors\n ENABLE_LSP_TOOL: \"0\",\n },\n },\n })) {\n log(`Received message type: ${message.type}`)\n\n // Output the raw SDK message as JSON\n outputEvent(message as unknown as Record<string, unknown>)\n\n // Check for task lifecycle events in assistant messages\n if (message.type === \"assistant\") {\n const assistantMessage = message.message as Record<string, unknown> | undefined\n const content = assistantMessage?.content as Array<Record<string, unknown>> | undefined\n if (content) {\n for (const block of content) {\n if (block.type === \"text\" && typeof block.text === \"string\") {\n const taskInfo = parseTaskLifecycleEvent(block.text)\n if (taskInfo) {\n if (taskInfo.action === \"starting\") {\n currentTaskIdRef.current = taskInfo.taskId ?? null\n currentTaskTitleRef.current = taskInfo.taskTitle ?? null\n log(\n `Task started: ${taskInfo.taskId}${taskInfo.taskTitle ? ` - ${taskInfo.taskTitle}` : \"\"}`,\n )\n // Emit ralph_task_started event\n outputEvent({\n type: \"ralph_task_started\",\n taskId: taskInfo.taskId,\n taskTitle: taskInfo.taskTitle,\n session: currentSession,\n })\n } else if (taskInfo.action === \"completed\") {\n log(\n `Task completed: ${taskInfo.taskId}${taskInfo.taskTitle ? ` - ${taskInfo.taskTitle}` : \"\"}`,\n )\n // Emit ralph_task_completed event\n outputEvent({\n type: \"ralph_task_completed\",\n taskId: taskInfo.taskId,\n taskTitle: taskInfo.taskTitle,\n session: currentSession,\n })\n }\n }\n }\n }\n }\n }\n\n // Capture the final result message\n if (\n message.type === \"result\" &&\n \"result\" in message &&\n typeof message.result === \"string\"\n ) {\n log(`Received result message`)\n finalResult = message.result\n // Close the message queue immediately when we get the result.\n log(`Closing message queue on result`)\n messageQueue.close()\n }\n }\n\n log(`query() loop completed normally`)\n setIsRunning(false)\n log(`Ensuring message queue is closed`)\n messageQueue.close()\n messageQueueRef.current = null\n\n // Output session end event\n outputEvent({\n type: \"ralph_session_end\",\n session: currentSession,\n taskId: currentTaskIdRef.current,\n taskTitle: currentTaskTitleRef.current,\n })\n\n // Check for stop-after-current request\n if (stopAfterCurrentRef.current) {\n log(`Stop after current requested - exiting gracefully`)\n outputEvent({ type: \"ralph_exit\", reason: \"stop_requested\" })\n exit()\n process.exit(0)\n return\n }\n\n // Check for completion\n if (finalResult.includes(\"<promise>COMPLETE</promise>\")) {\n outputEvent({ type: \"ralph_exit\", reason: \"task_complete\" })\n exit()\n process.exit(0)\n return\n }\n\n // Check for pause request - if paused, we wait for resume via stdin\n if (isPausedRef.current) {\n log(`Paused after session ${currentSession}`)\n outputEvent({ type: \"ralph_paused\", session: currentSession })\n // Don't move to next session - the resume handler will trigger it\n return\n }\n\n // Move to next session\n setTimeout(() => setCurrentSession(i => i + 1), 500)\n } catch (err) {\n log(`query() loop error: ${err instanceof Error ? err.message : String(err)}`)\n setIsRunning(false)\n log(`Closing message queue after error`)\n messageQueue.close()\n messageQueueRef.current = null\n if (abortController.signal.aborted) {\n log(`Abort signal detected`)\n return // Intentionally aborted\n }\n const errorMsg = `Error running Claude: ${err instanceof Error ? err.message : String(err)}`\n setError(errorMsg)\n outputEvent({ type: \"ralph_error\", error: errorMsg })\n setTimeout(() => {\n exit()\n process.exit(1)\n }, 100)\n }\n }\n\n runQuery()\n\n return () => {\n log(`Cleanup: aborting and closing queue for session ${currentSession}`)\n abortController.abort()\n messageQueue.close()\n messageQueueRef.current = null\n }\n }, [currentSession, totalSessions, exit, startupSnapshot])\n\n // In JSON mode, we output to stdout, so no visual rendering needed\n // Just return an empty component (Ink requires something to render)\n if (error) {\n return <Text>{\"\"}</Text>\n }\n\n return <Text>{\"\"}</Text>\n}\n\ntype Props = {\n totalSessions: number\n agent: string\n}\n","import { createDebugLogger } from \"./debug.js\"\n\nconst log = createDebugLogger(\"stdin-command\")\n\n/**\n * Stdin command types:\n * - {\"type\": \"message\", \"text\": \"...\"} - Send a message to Claude\n * - {\"type\": \"stop\"} - Request graceful stop after current session\n * - {\"type\": \"pause\"} - Pause after current session completes\n * - {\"type\": \"resume\"} - Resume from paused state\n */\nexport type StdinCommand =\n | { type: \"message\"; text: string }\n | { type: \"stop\" }\n | { type: \"pause\" }\n | { type: \"resume\" }\n\n/**\n * Parse a JSON string into a StdinCommand.\n * Returns null if parsing fails or the command is invalid.\n */\nexport const parseStdinCommand = (\n /** The line to parse as JSON */\n line: string,\n): StdinCommand | null => {\n const trimmed = line.trim()\n if (!trimmed) return null\n\n try {\n const parsed = JSON.parse(trimmed)\n\n if (typeof parsed !== \"object\" || parsed === null) {\n log(`Invalid command - not an object: ${trimmed}`)\n return null\n }\n\n if (parsed.type === \"message\") {\n if (typeof parsed.text !== \"string\") {\n log(`Invalid message command - missing or invalid text: ${trimmed}`)\n return null\n }\n return { type: \"message\", text: parsed.text }\n }\n\n if (parsed.type === \"stop\") {\n return { type: \"stop\" }\n }\n\n if (parsed.type === \"pause\") {\n return { type: \"pause\" }\n }\n\n if (parsed.type === \"resume\") {\n return { type: \"resume\" }\n }\n\n log(`Unknown command type: ${parsed.type}`)\n return null\n } catch (err) {\n log(`Failed to parse command: ${err instanceof Error ? err.message : String(err)}`)\n return null\n }\n}\n","import { createDebugLogger } from \"./debug.js\"\nimport { MessageQueue, createUserMessage } from \"./MessageQueue.js\"\nimport { parseStdinCommand } from \"./parseStdinCommand.js\"\nimport { createInterface } from \"readline\"\n\nconst log = createDebugLogger(\"stdin-command\")\n\n/**\n * Creates a stdin command handler that reads JSON commands from stdin.\n * Returns a cleanup function to stop reading.\n *\n * Commands:\n * - {\"type\": \"message\", \"text\": \"...\"} - Send a message to Claude\n * - {\"type\": \"stop\"} - Request graceful stop after current session\n * - {\"type\": \"pause\"} - Pause after current session completes\n * - {\"type\": \"resume\"} - Resume from paused state\n */\nexport const createStdinCommandHandler = (\n /** Getter for handler options; called when a command is received */\n getOptions: () => StdinCommandHandlerOptions,\n): (() => void) => {\n // Don't set up stdin handler if stdin is a TTY (interactive mode handles input differently)\n // This handler is for piped input in JSON mode\n if (process.stdin.isTTY) {\n log(`stdin is TTY - skipping stdin command handler`)\n return () => {}\n }\n\n log(`Setting up stdin command handler`)\n\n const rl = createInterface({\n input: process.stdin,\n terminal: false,\n })\n\n const lineHandler = (line: string) => {\n const command = parseStdinCommand(line)\n if (!command) return\n\n const options = getOptions()\n log(`Received command: ${command.type}`)\n\n if (command.type === \"message\") {\n if (options.messageQueue) {\n const userMessage = createUserMessage(command.text)\n options.messageQueue.push(userMessage)\n log(`Pushed message to queue: ${command.text.slice(0, 50)}...`)\n options.onMessage?.(command.text)\n } else {\n log(`Cannot send message - no active message queue`)\n }\n } else if (command.type === \"stop\") {\n log(`Stop command received`)\n options.onStop()\n } else if (command.type === \"pause\") {\n log(`Pause command received`)\n options.onPause?.()\n } else if (command.type === \"resume\") {\n log(`Resume command received`)\n options.onResume?.()\n }\n }\n\n rl.on(\"line\", lineHandler)\n\n return () => {\n log(`Cleaning up stdin command handler`)\n rl.off(\"line\", lineHandler)\n rl.close()\n }\n}\n\n/** Options for the stdin command handler */\nexport type StdinCommandHandlerOptions = {\n /** The message queue to push user messages to, or null if not active */\n messageQueue: MessageQueue | null\n /** Callback invoked when a stop command is received */\n onStop: () => void\n /** Optional callback invoked when a pause command is received */\n onPause?: () => void\n /** Optional callback invoked when a resume command is received */\n onResume?: () => void\n /** Optional callback invoked when a user message is processed */\n onMessage?: (text: string) => void\n}\n","/** Output an event as newline-delimited JSON to stdout. */\nexport const outputEvent = (\n /** The event object to output */\n event: Record<string, unknown>,\n) => {\n process.stdout.write(JSON.stringify(event) + \"\\n\")\n}\n","import { Text, Box } from \"ink\"\nimport React, { useEffect, useState } from \"react\"\nimport { existsSync, readFileSync, appendFileSync, writeFileSync } from \"fs\"\nimport { join, dirname } from \"path\"\nimport { fileURLToPath } from \"url\"\nimport { copyTemplates } from \"../lib/copyTemplates.js\"\n\n/**\n * Initializes Ralph by copying workflow templates and agent configurations to the project.\n * Creates .ralph/workflow.md, .claude/skills/, and .claude/agents/ directories with default files.\n * Also adds .ralph/events-*.jsonl to .gitignore.\n */\nexport function InitRalph() {\n const __dirname = dirname(fileURLToPath(import.meta.url))\n const [status, setStatus] = useState<InitStatus>(\"checking\")\n const [createdFiles, setCreatedFiles] = useState<string[]>([])\n const [skippedFiles, setSkippedFiles] = useState<string[]>([])\n const [errors, setErrors] = useState<string[]>([])\n\n // Check if .ralph already exists and run initialization\n useEffect(() => {\n const ralphDir = join(process.cwd(), \".ralph\")\n const claudeDir = join(process.cwd(), \".claude\")\n\n // Check if already initialized\n if (existsSync(join(ralphDir, \"workflow.md\"))) {\n setStatus(\"exists\")\n return\n }\n\n // Run initialization\n const initialize = async () => {\n const templatesDir = join(__dirname, \"..\", \"..\", \"templates\")\n\n setStatus(\"creating\")\n\n try {\n const allCreated: string[] = []\n const allSkipped: string[] = []\n const allErrors: string[] = []\n\n // Copy workflow to .ralph/\n const ralphResult = copyTemplates(templatesDir, ralphDir, [\n { src: \"workflow.md\", dest: \"workflow.md\" },\n ])\n allCreated.push(...ralphResult.created.map(f => `.ralph/${f}`))\n allSkipped.push(...ralphResult.skipped.map(f => `.ralph/${f}`))\n allErrors.push(...ralphResult.errors)\n\n // Copy skills to .claude/skills/\n const skillsResult = copyTemplates(templatesDir, claudeDir, [\n { src: \"skills/manage-tasks/SKILL.md\", dest: \"skills/manage-tasks/SKILL.md\" },\n ])\n allCreated.push(...skillsResult.created.map(f => `.claude/${f}`))\n allSkipped.push(...skillsResult.skipped.map(f => `.claude/${f}`))\n allErrors.push(...skillsResult.errors)\n\n // Copy agents to .claude/agents/\n const agentsResult = copyTemplates(templatesDir, claudeDir, [\n { src: \"agents/make-tests.md\", dest: \"agents/make-tests.md\" },\n { src: \"agents/write-docs.md\", dest: \"agents/write-docs.md\" },\n { src: \"agents/run-tests.md\", dest: \"agents/run-tests.md\" },\n ])\n allCreated.push(...agentsResult.created.map(f => `.claude/${f}`))\n allSkipped.push(...agentsResult.skipped.map(f => `.claude/${f}`))\n allErrors.push(...agentsResult.errors)\n\n // Add events log pattern to .gitignore\n const gitignorePath = join(process.cwd(), \".gitignore\")\n const eventsLogEntry = \".ralph/events-*.jsonl\"\n if (existsSync(gitignorePath)) {\n const content = readFileSync(gitignorePath, \"utf-8\")\n if (!content.includes(eventsLogEntry)) {\n const newline = content.endsWith(\"\\n\") ? \"\" : \"\\n\"\n appendFileSync(gitignorePath, `${newline}${eventsLogEntry}\\n`)\n allCreated.push(\"(added .ralph/events-*.jsonl to .gitignore)\")\n }\n } else {\n writeFileSync(gitignorePath, `${eventsLogEntry}\\n`)\n allCreated.push(\"(created .gitignore with .ralph/events-*.jsonl)\")\n }\n\n setCreatedFiles(allCreated)\n setSkippedFiles(allSkipped)\n setErrors(allErrors)\n setStatus(\"done\")\n\n // Exit after a brief delay so user can see success message\n setTimeout(() => process.exit(0), 100)\n } catch (error) {\n setErrors([`Failed to initialize: ${error}`])\n setStatus(\"done\")\n setTimeout(() => process.exit(1), 100)\n }\n }\n\n initialize()\n }, [])\n\n if (status === \"checking\") {\n return <Text>Checking directories...</Text>\n }\n\n if (status === \"exists\") {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"yellow\">Ralph is already initialized</Text>\n <Text dimColor>To reinitialize, remove the workflow first: rm .ralph/workflow.md</Text>\n </Box>\n )\n }\n\n if (status === \"creating\") {\n return <Text color=\"cyan\">Initializing ralph...</Text>\n }\n\n return (\n <Box flexDirection=\"column\">\n {createdFiles.map(file => (\n <Text key={file}>\n <Text color=\"green\">✓</Text> Created <Text dimColor>{file}</Text>\n </Text>\n ))}\n {skippedFiles.map(file => (\n <Text key={file}>\n <Text color=\"yellow\">○</Text> Skipped <Text dimColor>{file}</Text>\n <Text dimColor> (already exists)</Text>\n </Text>\n ))}\n {errors.map((error, i) => (\n <Text key={i}>\n <Text color=\"red\">✗</Text> {error}\n </Text>\n ))}\n {errors.length === 0 && (\n <>\n <Text color=\"green\">{\"\\n\"}Ralph initialized successfully!</Text>\n <Text bold>{\"\\n\"}Next steps:</Text>\n <Text>\n <Text color=\"cyan\"> 1. Edit .ralph/workflow.md</Text>\n <Text dimColor> - Customize build commands for your project</Text>\n </Text>\n <Text>\n <Text color=\"cyan\"> 2. Initialize beads</Text>\n <Text dimColor> - Run `bd init` to set up the issue tracker</Text>\n </Text>\n <Text>\n <Text color=\"cyan\"> 3. Create issues</Text>\n <Text dimColor> - Run `bd create --title=\"...\" --type=task` to add work</Text>\n </Text>\n <Text>\n <Text bold>{\"\\n\"}Then run: </Text>\n <Text color=\"cyan\">ralph</Text>\n {\"\\n\"}\n </Text>\n </>\n )}\n </Box>\n )\n}\n\ntype InitStatus = \"checking\" | \"exists\" | \"creating\" | \"done\"\n","import { existsSync, mkdirSync, copyFileSync } from \"fs\"\nimport { join, dirname } from \"path\"\n\n/** Copy files from templates to destination, creating directories as needed. */\nexport function copyTemplates(\n /** Directory containing template files */\n templatesDir: string,\n /** Destination directory for copied files */\n destDir: string,\n /** Array of source and destination path pairs */\n files: Array<{ src: string; dest: string }>,\n): CopyResult {\n const result: CopyResult = { created: [], skipped: [], errors: [] }\n\n for (const { src, dest } of files) {\n const srcPath = join(templatesDir, src)\n const destPath = join(destDir, dest)\n\n const destDirPath = dirname(destPath)\n if (!existsSync(destDirPath)) {\n mkdirSync(destDirPath, { recursive: true })\n }\n\n if (existsSync(destPath)) {\n result.skipped.push(dest)\n } else if (existsSync(srcPath)) {\n copyFileSync(srcPath, destPath)\n result.created.push(dest)\n } else {\n result.errors.push(`Template not found: ${src}`)\n }\n }\n\n return result\n}\n\n/** Result of copying template files. */\ninterface CopyResult {\n /** Files successfully created */\n created: string[]\n /** Files that already existed and were skipped */\n skipped: string[]\n /** Error messages for files that could not be copied */\n errors: string[]\n}\n","import { execSync } from \"child_process\"\n\n/**\n * Get the installed Claude CLI version by executing `claude --version`.\n * Returns the version string (e.g., \"2.1.5\") or \"unknown\" if unable to determine.\n */\nexport const getClaudeVersion = (): string => {\n try {\n const output = execSync(\"claude --version\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim()\n\n // Output format: \"2.1.5 (Claude Code)\"\n // Extract the version number\n const match = output.match(/^([\\d.]+)/)\n return match ? match[1] : \"unknown\"\n } catch {\n return \"unknown\"\n }\n}\n","import { execSync } from \"child_process\"\n\n/**\n * Get the number of open issues from beads.\n * Returns 0 if beads is not available or there are no issues.\n */\nexport const getOpenIssueCount = (): number => {\n try {\n const output = execSync(\"bd list --status=open --json\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim()\n\n const issues = JSON.parse(output)\n return Array.isArray(issues) ? issues.length : 0\n } catch {\n return 0\n }\n}\n","import { getOpenIssueCount } from \"./getOpenIssueCount.js\"\n\n/**\n * Calculate the default number of sessions based on open issues.\n * Returns 120% of open issues, with a minimum of 10 and maximum of 100.\n */\nexport const getDefaultSessions = (): number => {\n const openIssues = getOpenIssueCount()\n if (openIssues === 0) {\n return 10 // Fallback when no issues or bd not available\n }\n const calculated = Math.ceil(openIssues * 1.2)\n return Math.max(10, Math.min(100, calculated))\n}\n","import { join } from \"path\"\nimport { findMaxLogNumber } from \"./findMaxLogNumber.js\"\n\n/**\n * Get the path to the most recent (highest numbered) log file in the .ralph directory.\n * Returns undefined if no event logs exist.\n */\nexport const getLatestLogFile = (): string | undefined => {\n const maxNumber = findMaxLogNumber()\n if (maxNumber === 0) {\n return undefined\n }\n\n const ralphDir = join(process.cwd(), \".ralph\")\n return join(ralphDir, `events-${maxNumber}.jsonl`)\n}\n","{\n \"name\": \"@herbcaudill/ralph\",\n \"version\": \"1.0.2\",\n \"description\": \"Autonomous AI session engine for Claude CLI\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"ralph\": \"./bin/ralph.js\"\n },\n \"files\": [\n \"dist\",\n \"bin\",\n \"templates\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsc --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"ralph\": \"tsx src/index.ts\",\n \"test:all\": \"pnpm typecheck && vitest run\",\n \"test\": \"vitest run\",\n \"test:e2e\": \"vitest --config vitest.e2e.config.ts\",\n \"test:watch\": \"vitest --watch\",\n \"test:ui\": \"vitest --ui\",\n \"format\": \"prettier --write . --log-level silent\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"claude\",\n \"ai\",\n \"automation\",\n \"cli\",\n \"session\",\n \"autonomous\"\n ],\n \"author\": \"Herb Caudill\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/HerbCaudill/ralph.git\"\n },\n \"dependencies\": {\n \"@anthropic-ai/claude-agent-sdk\": \"^0.2.7\",\n \"chalk\": \"^5.6.2\",\n \"commander\": \"^14.0.2\",\n \"ink\": \"^6.6.0\",\n \"ink-big-text\": \"^2.0.0\",\n \"ink-gradient\": \"^3.0.0\",\n \"ink-select-input\": \"^6.2.0\",\n \"ink-spinner\": \"^5.0.0\",\n \"ink-text-input\": \"^6.0.0\",\n \"react\": \"^19.2.3\"\n },\n \"devDependencies\": {\n \"@herbcaudill/ralph-shared\": \"workspace:*\",\n \"@types/node\": \"^24.10.1\",\n \"@types/react\": \"^19.2.8\",\n \"@vitest/ui\": \"^4.0.17\",\n \"execa\": \"^9.6.1\",\n \"ink-testing-library\": \"^4.0.0\",\n \"prettier\": \"^3.5.3\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"~5.9.3\",\n \"vitest\": \"^4.0.17\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n }\n}\n","import { program } from \"./cli.js\"\n\n/** Parse and execute the CLI program with command-line arguments. */\nexport const run = () => {\n program.parse(process.argv)\n}\n\n/** Run if called directly as a script. */\nif (import.meta.url === `file://${process.argv[1]}`) {\n run()\n}\n"],"mappings":"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","names":["React","React","React","useState","useEffect","Box","Text","useInput","writeFileSync","readFileSync","existsSync","join","existsSync","join","execSync","readFileSync","join","join","ralphDir","todoFile","existsSync","existsSync","join","execSync","readFileSync","join","ralphDir","todoFile","beadsDir","join","ralphDir","todoFile","existsSync","React","Text","repoName","join","existsSync","useState","useEffect","useState","useEffect","existsSync","join","existsSync","join","ralphDir","ralphDir","join","existsSync","readFileSync","existsSync","join","ralphDir","todoFile","beadsDir","message","content","messageId","query","React","Box","Text","BigText","Gradient","React","Text","chalk","chalk","chalk","React","Box","Gradient","BigText","Text","log","ralphDir","join","todoFile","useState","useInput","useEffect","writeFileSync","existsSync","readFileSync","React","Box","Text","React","useState","useEffect","Box","Text","useApp","readFileSync","React","useState","useEffect","useRef","Box","Text","useInput","chalk","processEvents","useState","useRef","processEvents","useEffect","useInput","React","Box","Text","React","Box","Text","BigText","Gradient","React","Box","Gradient","BigText","Text","useApp","useState","useEffect","readFileSync","React","Box","Text","React","useState","useEffect","useRef","useApp","Text","writeFileSync","readFileSync","existsSync","join","basename","query","log","log","log","todoFile","join","repoName","basename","useApp","useState","useRef","useEffect","writeFileSync","existsSync","readFileSync","query","React","Text","React","Text","Box","React","useEffect","useState","existsSync","readFileSync","appendFileSync","writeFileSync","join","dirname","fileURLToPath","existsSync","mkdirSync","join","dirname","dirname","fileURLToPath","useState","useEffect","ralphDir","join","existsSync","readFileSync","appendFileSync","writeFileSync","React","Text","Box","execSync","execSync","join","ralphDir","join","React"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/components/App.tsx","../src/components/SessionRunner.tsx","../src/components/EnhancedTextInput.tsx","../src/components/findPreviousWordBoundary.ts","../src/components/findNextWordBoundary.ts","../../shared/src/persistence/SessionPersister.ts","../../shared/src/persistence/getDefaultStorageDir.ts","../src/lib/addTodo.ts","../src/lib/insertTodo.ts","../src/lib/getProgress.ts","../src/lib/getBeadsProgress.ts","../src/lib/getTodoProgress.ts","../src/lib/captureStartupSnapshot.ts","../src/lib/captureBeadsSnapshot.ts","../src/lib/captureTodoSnapshot.ts","../src/components/ProgressBar.tsx","../../../../beads-sdk/src/exec.ts","../../../../beads-sdk/src/socket.ts","../src/lib/beadsClient.ts","../src/lib/debug.ts","../src/lib/createUserMessage.ts","../src/lib/MessageQueue.ts","../src/lib/useTerminalSize.ts","../src/lib/getTerminalSize.ts","../src/lib/parseTaskLifecycle.ts","../src/lib/getPromptContent.ts","../../shared/src/prompts/loadPrompt.ts","../../shared/src/prompts/getWorkspaceRoot.ts","../../shared/src/prompts/templatesDir.ts","../src/lib/sdkMessageToEvent.ts","../src/lib/rel.ts","../src/lib/getBaseCwd.ts","../src/lib/shortenTempPaths.ts","../src/components/eventToBlocks.ts","../src/lib/processEvents.ts","../src/components/renderStaticItem.tsx","../src/components/Header.tsx","../src/lib/formatText.ts","../src/lib/formatToolUse.ts","../src/lib/formatUserMessage.ts","../src/lib/formatContentBlock.ts","../src/components/ReplayLog.tsx","../src/components/EventDisplay.tsx","../src/lib/formatSessionHeader.ts","../src/components/processEvents.ts","../src/components/blocksToLines.ts","../src/components/FullScreenLayout.tsx","../src/components/useContentHeight.ts","../src/components/JsonOutput.tsx","../src/lib/parseStdinCommand.ts","../src/lib/createStdinCommandHandler.ts","../src/lib/outputEvent.ts","../src/components/InitRalph.tsx","../src/lib/copyTemplates.ts","../src/lib/getClaudeVersion.ts","../src/lib/getOpenIssueCount.ts","../src/lib/getDefaultSessions.ts","../src/lib/getLatestLogFile.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\"\nimport { render } from \"ink\"\nimport React from \"react\"\nimport { App } from \"./components/App.js\"\nimport { InitRalph } from \"./components/InitRalph.js\"\nimport { getClaudeVersion } from \"./lib/getClaudeVersion.js\"\nimport { getDefaultSessions } from \"./lib/getDefaultSessions.js\"\nimport { addTodo } from \"./lib/addTodo.js\"\nimport { getLatestLogFile } from \"./lib/getLatestLogFile.js\"\nimport packageJson from \"../package.json\" with { type: \"json\" }\n\nexport const program = new Command()\n .name(\"ralph\")\n .description(\"Autonomous AI session engine for Claude CLI\")\n .version(packageJson.version)\n .argument(\n \"[sessions]\",\n \"number of sessions (default: 120% of open issues, min 10, max 100)\",\n val => parseInt(val, 10),\n )\n .option(\"--replay [file]\", \"replay events from log file\")\n .option(\"--watch\", \"watch for new beads issues after completion\")\n .option(\"--json\", \"output events as newline-delimited JSON to stdout\")\n .option(\"--agent <name>\", \"agent to use (e.g., claude, codex)\", \"claude\")\n .action(\n (\n /** The number of sessions to run, or undefined to use default */\n sessionsArg: number | undefined,\n /** Command options including replay, watch, json, and agent */\n options,\n ) => {\n const sessions = sessionsArg ?? getDefaultSessions()\n const replayFile =\n options.replay !== undefined ?\n typeof options.replay === \"string\" ?\n options.replay\n : getLatestLogFile()\n : undefined\n\n const claudeVersion = getClaudeVersion()\n const ralphVersion = packageJson.version\n const watch = options.watch === true\n const json = options.json === true\n const agent = options.agent as string\n\n // Validate agent selection\n const validAgents = [\"claude\", \"codex\"]\n if (!validAgents.includes(agent)) {\n console.error(\n `Error: Invalid agent \"${agent}\". Available agents: ${validAgents.join(\", \")}`,\n )\n process.exit(1)\n }\n\n // Clear the screen on startup (skip in JSON mode)\n if (!json) {\n process.stdout.write(\"\\x1B[2J\\x1B[H\")\n }\n\n render(\n React.createElement(App, {\n sessions,\n replayFile,\n claudeVersion,\n ralphVersion,\n watch,\n json,\n agent,\n }),\n )\n },\n )\n\nprogram\n .command(\"init\")\n .description(\"initialize .ralph directory with templates\")\n /**\n * Initialize the .ralph directory with templates\n */\n .action(() => {\n render(React.createElement(InitRalph))\n })\n\nprogram\n .command(\"todo [description...]\")\n .description(\"add a todo item and commit it (safe to use while ralph is running)\")\n /**\n * Add a todo item and commit it. If description is provided as arguments,\n * use that; otherwise prompt interactively.\n */\n .action(\n async (\n /** The description parts from command arguments */\n descriptionParts: string[],\n ) => {\n let description = descriptionParts.join(\" \").trim()\n\n if (!description) {\n // Prompt for description interactively\n const readline = await import(\"readline\")\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n\n description = await new Promise<string>(resolve => {\n rl.question(\"Todo: \", answer => {\n rl.close()\n resolve(answer.trim())\n })\n })\n\n if (!description) {\n console.error(\"No todo description provided\")\n process.exit(1)\n }\n }\n\n try {\n addTodo(description)\n } catch (error) {\n console.error(`Failed to add todo: ${error instanceof Error ? error.message : error}`)\n process.exit(1)\n }\n },\n )\n","import React from \"react\"\nimport { SessionRunner } from \"./SessionRunner.js\"\nimport { ReplayLog } from \"./ReplayLog.js\"\nimport { JsonOutput } from \"./JsonOutput.js\"\n\n/**\n * Root application component that routes to the appropriate mode based on props.\n * Supports replay mode, JSON output mode, and normal session mode.\n */\nexport const App = ({\n sessions,\n replayFile,\n claudeVersion,\n ralphVersion,\n watch,\n json,\n agent,\n}: Props) => {\n if (replayFile) {\n return <ReplayLog filePath={replayFile} />\n }\n\n if (json) {\n return <JsonOutput totalSessions={sessions} agent={agent} />\n }\n\n return (\n <SessionRunner\n totalSessions={sessions}\n claudeVersion={claudeVersion}\n ralphVersion={ralphVersion}\n watch={watch}\n agent={agent}\n />\n )\n}\n\ntype Props = {\n sessions: number\n replayFile?: string\n claudeVersion: string\n ralphVersion: string\n watch?: boolean\n json?: boolean\n agent: string\n}\n","import React, { useState, useEffect, useRef } from \"react\"\nimport { Box, Text, useApp, Static, useInput } from \"ink\"\nimport Spinner from \"ink-spinner\"\nimport { EnhancedTextInput } from \"./EnhancedTextInput.js\"\nimport { appendFileSync, readFileSync, existsSync, mkdirSync } from \"fs\"\nimport { join, basename } from \"path\"\nimport { getDefaultStorageDir } from \"@herbcaudill/ralph-shared/server\"\nimport { query } from \"@anthropic-ai/claude-agent-sdk\"\nimport { eventToBlocks } from \"./eventToBlocks.js\"\nimport { addTodo } from \"../lib/addTodo.js\"\nimport { getProgress } from \"../lib/getProgress.js\"\nimport { captureStartupSnapshot } from \"../lib/captureStartupSnapshot.js\"\nimport type { ProgressData, StartupSnapshot } from \"../lib/types.js\"\nimport { ProgressBar } from \"./ProgressBar.js\"\nimport { watchForNewIssues, type MutationEvent } from \"../lib/beadsClient.js\"\nimport { MessageQueue, createUserMessage } from \"../lib/MessageQueue.js\"\nimport { createDebugLogger } from \"../lib/debug.js\"\nimport { useTerminalSize } from \"../lib/useTerminalSize.js\"\nimport { parseTaskLifecycleEvent } from \"../lib/parseTaskLifecycle.js\"\nimport { getPromptContent } from \"../lib/getPromptContent.js\"\nimport { sdkMessageToEvent } from \"../lib/sdkMessageToEvent.js\"\nimport { processEvents } from \"../lib/processEvents.js\"\nimport { renderStaticItem } from \"./renderStaticItem.js\"\nimport { type StaticItem, type SessionRunnerProps } from \"./SessionRunner.types.js\"\n\n/** Debug logger for session lifecycle events */\nconst log = createDebugLogger(\"session\")\n\n/** The .ralph directory path in the current working directory */\nconst ralphDir = join(process.cwd(), \".ralph\")\n\n/** Path to the todo.md file in the .ralph directory */\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/** The name of the current repository (basename of cwd) */\nconst repoName = basename(process.cwd())\n\n/**\n * Orchestrates the iterative execution of Claude AI sessions.\n *\n * Spawns Claude CLI with prompts, captures streaming output, displays formatted UI,\n * and handles user input during session execution.\n */\nexport const SessionRunner = ({\n totalSessions,\n claudeVersion,\n ralphVersion,\n watch,\n agent,\n}: SessionRunnerProps) => {\n const { exit } = useApp()\n const { columns } = useTerminalSize()\n const [currentSession, setCurrentSession] = useState(1)\n const [events, setEvents] = useState<Array<Record<string, unknown>>>([])\n const eventsRef = useRef<Array<Record<string, unknown>>>([])\n const [error, setError] = useState<string>()\n const [isRunning, setIsRunning] = useState(false)\n const [isAddingTodo, setIsAddingTodo] = useState(false)\n const [todoText, setTodoText] = useState(\"\")\n const [todoMessage, setTodoMessage] = useState<{\n type: \"success\" | \"error\"\n text: string\n } | null>(null)\n const [userMessageText, setUserMessageText] = useState(\"\")\n const [userMessageStatus, setUserMessageStatus] = useState<{\n type: \"success\" | \"error\" | \"pending\"\n text: string\n } | null>(null)\n const [hasTodoFile, setHasTodoFile] = useState(false)\n const [startupSnapshot] = useState<StartupSnapshot | undefined>(() => captureStartupSnapshot())\n const [progressData, setProgressData] = useState<ProgressData>(() => {\n const snapshot = captureStartupSnapshot()\n if (!snapshot) return { type: \"none\", completed: 0, total: 0 }\n return { type: snapshot.type, completed: 0, total: snapshot.initialCount }\n })\n const [isWatching, setIsWatching] = useState(false)\n const [detectedIssue, setDetectedIssue] = useState<MutationEvent | null>(null)\n const watchCleanupRef = useRef<(() => void) | null>(null)\n const [watchCycle, setWatchCycle] = useState(0) // Increments to force useEffect re-run\n const [stopAfterCurrent, setStopAfterCurrent] = useState(false) // Stop gracefully after current session\n const stopAfterCurrentRef = useRef(false) // Ref to access in async callbacks\n const [isPaused, setIsPaused] = useState(false) // Pause after current session completes\n const isPausedRef = useRef(false) // Ref to access in async callbacks\n const [currentTaskId, setCurrentTaskId] = useState<string | null>(null)\n const [sessionId, setSessionId] = useState<string | null>(null)\n const sessionIdRef = useRef<string | null>(null)\n const taskCompletedAbortRef = useRef(false) // Tracks abort triggered by task completion\n\n // Track static items that have been rendered (for Ink's Static component)\n const [staticItems, setStaticItems] = useState<StaticItem[]>([\n { type: \"header\", claudeVersion, ralphVersion, key: \"header\" },\n ])\n const renderedBlocksRef = useRef<Set<string>>(new Set())\n const lastSessionRef = useRef<number>(0)\n // Message queue for sending user messages to Claude while running\n const messageQueueRef = useRef<MessageQueue | null>(null)\n // Log file path for the current session (set when we receive the session_id from the SDK)\n const logFileRef = useRef<string | null>(null)\n\n /** Whether stdin supports raw mode (required for keyboard input handling) */\n const stdinSupportsRawMode = process.stdin.isTTY === true\n\n /**\n * Handle adding a new todo when Ctrl-T is pressed.\n */\n const handleTodoSubmit = (\n /** The todo text to add */\n text: string,\n ) => {\n const trimmed = text.trim()\n if (!trimmed) {\n setIsAddingTodo(false)\n setTodoText(\"\")\n return\n }\n\n try {\n addTodo(trimmed)\n setTodoMessage({ type: \"success\", text: \"✅ added\" })\n setTodoText(\"\")\n setIsAddingTodo(false)\n // Clear success message after 2 seconds\n setTimeout(() => setTodoMessage(null), 2000)\n } catch (err) {\n setTodoMessage({\n type: \"error\",\n text: `Failed to add todo: ${err instanceof Error ? err.message : String(err)}`,\n })\n setTodoText(\"\")\n setIsAddingTodo(false)\n // Clear error message after 5 seconds\n setTimeout(() => setTodoMessage(null), 5000)\n }\n }\n\n /**\n * Handle submitting a user message to Claude during session.\n */\n const handleUserMessageSubmit = (\n /** The message text from the user */\n text: string,\n ) => {\n const trimmed = text.trim()\n if (!trimmed) {\n setUserMessageText(\"\")\n return\n }\n\n // Send the message to Claude via the SDK's streamInput\n if (messageQueueRef.current && isRunning) {\n const userMessage = createUserMessage(trimmed)\n messageQueueRef.current.push(userMessage)\n\n // Also add the user message to events for display\n const displayEvent = {\n type: \"user\",\n message: {\n id: `user-injected-${Date.now()}`,\n role: \"user\",\n content: [{ type: \"text\", text: trimmed }],\n },\n }\n setEvents(prev => [...prev, displayEvent])\n\n // No confirmation message - the user message appears directly in the stream\n } else {\n setUserMessageStatus({\n type: \"error\",\n text: \"Unable to send message - Claude is not running\",\n })\n }\n\n setUserMessageText(\"\")\n // Clear status message after 3 seconds\n setTimeout(() => setUserMessageStatus(null), 3000)\n }\n\n /**\n * Handle keyboard input for Ctrl-T (todo), Ctrl-S (stop), Ctrl-P (pause), and Escape (cancel).\n */\n useInput(\n (\n /** The input character */\n input,\n /** The key information including modifiers */\n key,\n ) => {\n // Ctrl-T to start adding a todo (only if todo.md exists)\n if (key.ctrl && input === \"t\" && hasTodoFile) {\n setIsAddingTodo(true)\n setTodoText(\"\")\n setTodoMessage(null)\n }\n // Ctrl-S to request stop after current session\n if (key.ctrl && input === \"s\" && isRunning && !stopAfterCurrent) {\n setStopAfterCurrent(true)\n }\n // Ctrl-P to toggle pause state\n if (key.ctrl && input === \"p\") {\n if (isPaused) {\n // Resume - if we were paused between sessions, trigger next session\n setIsPaused(false)\n if (!isRunning) {\n setTimeout(() => setCurrentSession(i => i + 1), 100)\n }\n } else if (isRunning) {\n // Request pause after current session\n setIsPaused(true)\n }\n }\n // Escape to cancel todo input\n if (key.escape) {\n if (isAddingTodo) {\n // Cancel todo input\n setIsAddingTodo(false)\n setTodoText(\"\")\n }\n }\n },\n { isActive: stdinSupportsRawMode },\n )\n\n // Keep ref in sync with events state for access in callbacks\n useEffect(() => {\n eventsRef.current = events\n }, [events])\n\n // Keep stopAfterCurrent ref in sync with state for access in async callbacks\n useEffect(() => {\n stopAfterCurrentRef.current = stopAfterCurrent\n }, [stopAfterCurrent])\n\n // Keep isPaused ref in sync with state for access in async callbacks\n useEffect(() => {\n isPausedRef.current = isPaused\n }, [isPaused])\n\n // Update progress data when session changes or running stops\n useEffect(() => {\n if (!isRunning && startupSnapshot) {\n setProgressData(getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp))\n }\n }, [currentSession, isRunning, startupSnapshot])\n\n // Poll progress data periodically while running to catch newly created/closed issues\n useEffect(() => {\n if (!isRunning || !startupSnapshot) return\n\n const pollInterval = setInterval(() => {\n setProgressData(getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp))\n }, 5000) // Poll every 5 seconds\n\n return () => clearInterval(pollInterval)\n }, [isRunning, startupSnapshot])\n\n // Watch for new issues when in watch mode\n useEffect(() => {\n if (!isWatching) return\n\n // Start watching for new issues\n const cleanup = watchForNewIssues(issue => {\n setDetectedIssue(issue)\n // Refresh progress data to pick up the new issue\n // The timestamp-based counting will automatically include it\n if (startupSnapshot) {\n setProgressData(getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp))\n }\n // Brief pause to show the detected issue, then resume\n setTimeout(() => {\n setIsWatching(false)\n setDetectedIssue(null)\n // Reset rendered blocks for new cycle\n renderedBlocksRef.current.clear()\n // Increment round number when picking up new issue\n setCurrentSession(i => i + 1)\n setWatchCycle(c => c + 1)\n }, 1500)\n })\n\n watchCleanupRef.current = cleanup\n\n return () => {\n cleanup()\n watchCleanupRef.current = null\n }\n }, [isWatching, startupSnapshot])\n\n // Convert events to static items as they arrive\n useEffect(() => {\n const newItems: StaticItem[] = []\n\n // Add session header once we have the session ID from the SDK\n if (currentSession > lastSessionRef.current && sessionId) {\n newItems.push({\n type: \"session\",\n session: currentSession,\n sessionId,\n key: `session-${currentSession}`,\n })\n lastSessionRef.current = currentSession\n }\n\n // Process current events into blocks\n const blocks = processEvents(events)\n\n // Add any new blocks that haven't been rendered yet\n for (const block of blocks) {\n // Use the block's ID which is generated from message ID + block index\n // This ensures the same logical block always has the same key\n const blockKey = block.id\n\n if (!renderedBlocksRef.current.has(blockKey)) {\n renderedBlocksRef.current.add(blockKey)\n newItems.push({ type: \"block\", block, key: blockKey })\n }\n }\n\n if (newItems.length > 0) {\n setStaticItems(prev => [...prev, ...newItems])\n }\n }, [events, currentSession, sessionId])\n\n useEffect(() => {\n if (currentSession > totalSessions) {\n exit()\n return\n }\n\n // Check if there are any tasks available before starting a round\n // This avoids running Claude unnecessarily when there's no work to do\n const currentProgress =\n startupSnapshot ?\n getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp)\n : { type: \"none\" as const, completed: 0, total: 0 }\n // All tasks are complete when completed equals total\n if (currentProgress.completed >= currentProgress.total && currentProgress.type !== \"none\") {\n // No tasks available - go straight to watching if enabled\n if (watch) {\n setIsWatching(true)\n } else {\n exit()\n process.exit(0)\n }\n return\n }\n\n // Reset log file for this session — will be set when we get the SDK session_id\n logFileRef.current = null\n setEvents([])\n\n // Read prompt (from .ralph/prompt.md or falling back to templates)\n const promptContent = getPromptContent()\n const todoExists = existsSync(todoFile)\n setHasTodoFile(todoExists)\n const todoContent = todoExists ? readFileSync(todoFile, \"utf-8\") : \"\"\n const roundHeader = `# Ralph, round ${currentSession}\\n\\n`\n const fullPrompt =\n todoContent ?\n `${roundHeader}${promptContent}\\n\\n## Current Todo List\\n\\n${todoContent}`\n : `${roundHeader}${promptContent}`\n\n const abortController = new AbortController()\n taskCompletedAbortRef.current = false\n setIsRunning(true)\n\n // Session ID will be set from the SDK init message\n sessionIdRef.current = null\n setSessionId(null)\n\n // Create a message queue for this session\n // This allows us to send follow-up user messages to Claude while it's running\n const messageQueue = new MessageQueue()\n messageQueueRef.current = messageQueue\n\n // Push the initial prompt as the first message\n messageQueue.push(createUserMessage(fullPrompt))\n\n /**\n * Execute a query to Claude and handle the streaming response.\n */\n const runQuery = async () => {\n let finalResult = \"\"\n log(`Starting session ${currentSession}`)\n\n try {\n log(`Beginning query() loop`)\n for await (const message of query({\n prompt: messageQueue,\n options: {\n abortController,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n includePartialMessages: true,\n env: {\n ...process.env,\n // Disable LSP plugins to avoid crashes when TypeScript LSP server errors\n ENABLE_LSP_TOOL: \"0\",\n // Signal that tests should use minimal reporters (dots)\n RALPH_QUIET: \"1\",\n },\n },\n })) {\n log(`Received message type: ${message.type}`)\n\n // Extract session_id from the SDK init message and create the log file\n if (\n !logFileRef.current &&\n message.type === \"system\" &&\n \"session_id\" in message &&\n typeof message.session_id === \"string\"\n ) {\n const storageDir = join(getDefaultStorageDir(), \"ralph\")\n if (!existsSync(storageDir)) {\n mkdirSync(storageDir, { recursive: true })\n }\n logFileRef.current = join(storageDir, `${message.session_id.slice(0, 8)}.jsonl`)\n sessionIdRef.current = message.session_id\n setSessionId(message.session_id)\n }\n\n // Log raw message to file (JSONL format - one JSON object per line)\n if (logFileRef.current) {\n appendFileSync(logFileRef.current, JSON.stringify(message) + \"\\n\")\n }\n\n // Convert to event format for display\n const event = sdkMessageToEvent(message)\n if (event) {\n setEvents(prev => [...prev, event])\n }\n\n // Check for task lifecycle events in assistant messages\n if (message.type === \"assistant\") {\n const assistantMessage = message.message as Record<string, unknown> | undefined\n const content = assistantMessage?.content as Array<Record<string, unknown>> | undefined\n if (content) {\n for (const block of content) {\n if (block.type === \"text\" && typeof block.text === \"string\") {\n const taskInfo = parseTaskLifecycleEvent(block.text)\n if (taskInfo) {\n if (taskInfo.action === \"starting\") {\n setCurrentTaskId(taskInfo.taskId ?? null)\n log(`Task started: ${taskInfo.taskId}`)\n // Emit ralph_task_started event to log file\n if (logFileRef.current) {\n const taskStartedEvent = {\n type: \"ralph_task_started\",\n taskId: taskInfo.taskId,\n session: currentSession,\n sessionId: sessionIdRef.current,\n }\n appendFileSync(logFileRef.current, JSON.stringify(taskStartedEvent) + \"\\n\")\n }\n } else if (taskInfo.action === \"completed\") {\n log(`Task completed: ${taskInfo.taskId}`)\n // Emit ralph_task_completed event to log file\n if (logFileRef.current) {\n const taskCompletedEvent = {\n type: \"ralph_task_completed\",\n taskId: taskInfo.taskId,\n session: currentSession,\n sessionId: sessionIdRef.current,\n }\n appendFileSync(\n logFileRef.current,\n JSON.stringify(taskCompletedEvent) + \"\\n\",\n )\n }\n // Abort the current query to enforce one-task-per-session.\n // Without this, Claude may ignore \"end your turn\" and loop\n // through bd ready to pick up additional tasks in one session.\n log(`Aborting session after task completion to enforce session boundary`)\n taskCompletedAbortRef.current = true\n abortController.abort()\n }\n }\n }\n }\n }\n }\n\n // Capture the final result message\n if (\n message.type === \"result\" &&\n \"result\" in message &&\n typeof message.result === \"string\"\n ) {\n log(`Received result message`)\n finalResult = message.result\n // Close the message queue immediately when we get the result.\n // This is critical to prevent hangs: the SDK's streamInput() needs\n // to complete iterating our queue before it can call endInput(),\n // which signals EOF to the CLI. If we wait until after the for-await\n // loop exits, we create a circular dependency that can cause hangs.\n log(`Closing message queue on result`)\n messageQueue.close()\n }\n }\n\n log(`query() loop completed normally`)\n setIsRunning(false)\n // MessageQueue should already be closed when we received the result message.\n // We ensure it's closed here as a safety measure (close() is idempotent).\n log(`Ensuring message queue is closed`)\n messageQueue.close()\n messageQueueRef.current = null\n\n // Check for stop-after-current request\n if (stopAfterCurrentRef.current) {\n log(`Stop after current requested - exiting gracefully`)\n exit()\n process.exit(0)\n return\n }\n\n // Check for completion\n if (finalResult.includes(\"<promise>COMPLETE</promise>\")) {\n if (watch) {\n // Enter watch mode instead of exiting\n setIsWatching(true)\n } else {\n exit()\n process.exit(0)\n }\n return\n }\n\n // Check for pause request - if paused, we wait for resume via Ctrl-P\n if (isPausedRef.current) {\n log(`Paused after session ${currentSession}`)\n // Don't move to next session - the resume handler (Ctrl-P) will trigger it\n return\n }\n\n // Move to next session\n setTimeout(() => setCurrentSession(i => i + 1), 500)\n } catch (err) {\n log(`query() loop error: ${err instanceof Error ? err.message : String(err)}`)\n setIsRunning(false)\n log(`Closing message queue after error`)\n messageQueue.close()\n messageQueueRef.current = null\n if (abortController.signal.aborted) {\n // Check if the abort was triggered by task completion\n if (taskCompletedAbortRef.current) {\n log(`Session aborted after task completion — advancing to next session`)\n taskCompletedAbortRef.current = false\n\n if (stopAfterCurrentRef.current) {\n log(`Stop after current requested - exiting gracefully`)\n exit()\n process.exit(0)\n return\n }\n if (isPausedRef.current) {\n log(`Paused after session ${currentSession}`)\n return\n }\n // Advance to the next session\n setTimeout(() => setCurrentSession(i => i + 1), 500)\n return\n }\n log(`Abort signal detected`)\n return // Intentionally aborted (e.g. cleanup)\n }\n setError(`Error running Claude: ${err instanceof Error ? err.message : String(err)}`)\n setTimeout(() => {\n exit()\n process.exit(1)\n }, 100)\n }\n }\n\n runQuery()\n\n return () => {\n log(`Cleanup: aborting and closing queue for session ${currentSession}`)\n abortController.abort()\n messageQueue.close()\n messageQueueRef.current = null\n }\n }, [currentSession, totalSessions, exit, watch, watchCycle])\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n {/* Static content that has already been rendered - won't re-render */}\n <Static items={staticItems}>\n {item => (\n <Box key={item.key} flexDirection=\"column\">\n {renderStaticItem(item)}\n </Box>\n )}\n </Static>\n\n {/* Todo input (shown when Ctrl-T is pressed) */}\n {isAddingTodo && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"yellow\">Todo:</Text>\n <EnhancedTextInput value={todoText} onChange={setTodoText} onSubmit={handleTodoSubmit} />\n <Text dimColor>(Enter to add, Esc to cancel)</Text>\n </Box>\n )}\n\n {/* Todo message (success or error) */}\n {todoMessage && (\n <Box marginTop={1}>\n <Text color={todoMessage.type === \"success\" ? \"green\" : \"red\"}>{todoMessage.text}</Text>\n </Box>\n )}\n\n {/* User message input - visible when running, hidden when watching for new issues */}\n {!isWatching && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text dimColor>{\"─\".repeat(columns)}</Text>\n <Box>\n <Text color={isRunning ? \"yellow\" : \"gray\"}>❯ </Text>\n <EnhancedTextInput\n value={userMessageText}\n placeholder={\n isRunning ? \"Type a message for Ralph...\" : \"Waiting for Ralph to start...\"\n }\n onChange={setUserMessageText}\n onSubmit={handleUserMessageSubmit}\n focus={isRunning && !isAddingTodo}\n />\n </Box>\n {userMessageStatus && (\n <Text\n color={\n userMessageStatus.type === \"success\" ? \"green\"\n : userMessageStatus.type === \"error\" ?\n \"red\"\n : \"yellow\"\n }\n >\n {userMessageStatus.text}\n </Text>\n )}\n <Text dimColor>{\"─\".repeat(columns)}</Text>\n </Box>\n )}\n\n {/* Dynamic footer with spinner and progress bar */}\n <Box marginTop={1} justifyContent=\"space-between\">\n {isWatching ?\n detectedIssue ?\n <Text color=\"green\">\n <Spinner type=\"dots\" /> New issue: <Text color=\"yellow\">{detectedIssue.IssueID}</Text>\n {detectedIssue.Title ? ` - ${detectedIssue.Title}` : \"\"}\n </Text>\n : <Text color=\"cyan\">\n Waiting for new issues <Spinner type=\"simpleDotsScrolling\" />\n </Text>\n\n : isPaused && !isRunning ?\n <Text color=\"magenta\">\n ⏸ Paused after round <Text color=\"yellow\">{currentSession}</Text>{\" \"}\n <Text dimColor>(Ctrl-P to resume)</Text>\n </Text>\n : isRunning ?\n stopAfterCurrent ?\n <Text color=\"yellow\">\n <Spinner type=\"dots\" /> Stopping after round{\" \"}\n <Text color=\"yellow\">{currentSession}</Text> completes...{\" \"}\n <Text dimColor>(Ctrl-S pressed)</Text>\n </Text>\n : isPaused ?\n <Text color=\"magenta\">\n <Spinner type=\"dots\" /> Pausing after round{\" \"}\n <Text color=\"yellow\">{currentSession}</Text> completes...{\" \"}\n <Text dimColor>(Ctrl-P pressed)</Text>\n </Text>\n : <Text color=\"cyan\">\n <Spinner type=\"dots\" /> Running round <Text color=\"yellow\">{currentSession}</Text>{\" \"}\n (max {totalSessions}){sessionId && <Text dimColor> {sessionId.slice(0, 8)}</Text>}\n </Text>\n\n : <Text color=\"cyan\">\n <Spinner type=\"simpleDotsScrolling\" /> Waiting for Ralph to start...\n </Text>\n }\n {progressData.type !== \"none\" && progressData.total > 0 && (\n <ProgressBar\n completed={progressData.completed}\n total={progressData.total}\n repoName={repoName}\n />\n )}\n </Box>\n </Box>\n )\n}\n","import React, { useState, useEffect } from \"react\"\nimport { Text, useInput } from \"ink\"\nimport chalk from \"chalk\"\nimport { findPreviousWordBoundary } from \"./findPreviousWordBoundary.js\"\nimport { findNextWordBoundary } from \"./findNextWordBoundary.js\"\n\n/**\n * Enhanced text input component with standard text editing shortcuts:\n * - Option+Left/Right: Move cursor by word\n * - Option+Backspace: Delete previous word\n * - Ctrl+A: Move to beginning of line\n * - Ctrl+E: Move to end of line\n * - Ctrl+K: Kill (delete) from cursor to end of line\n * - Ctrl+U: Kill (delete) from cursor to beginning of line\n * - Ctrl+W: Delete previous word\n */\nexport const EnhancedTextInput = ({\n value: originalValue,\n placeholder = \"\",\n focus = true,\n showCursor = true,\n onChange,\n onSubmit,\n}: Props) => {\n const [cursorOffset, setCursorOffset] = useState(originalValue.length)\n\n useEffect(() => {\n if (!focus || !showCursor) {\n return\n }\n // Ensure cursor stays within bounds when value changes externally\n if (cursorOffset > originalValue.length) {\n setCursorOffset(originalValue.length)\n }\n }, [originalValue, focus, showCursor, cursorOffset])\n\n // Render the value with cursor\n let renderedValue = originalValue\n let renderedPlaceholder = placeholder ? chalk.grey(placeholder) : undefined\n\n if (showCursor && focus) {\n renderedPlaceholder =\n placeholder.length > 0 ?\n chalk.inverse(placeholder[0]) + chalk.grey(placeholder.slice(1))\n : chalk.inverse(\" \")\n\n renderedValue = originalValue.length > 0 ? \"\" : chalk.inverse(\" \")\n\n for (let i = 0; i < originalValue.length; i++) {\n const char = originalValue[i]!\n renderedValue += i === cursorOffset ? chalk.inverse(char) : char\n }\n\n if (originalValue.length > 0 && cursorOffset === originalValue.length) {\n renderedValue += chalk.inverse(\" \")\n }\n }\n\n useInput(\n (input, key) => {\n // Ignore control sequences we don't handle\n if (key.upArrow || key.downArrow || (key.ctrl && input === \"c\") || key.tab) {\n return\n }\n\n if (key.return) {\n onSubmit?.(originalValue)\n return\n }\n\n let nextCursorOffset = cursorOffset\n let nextValue = originalValue\n\n // Option+Left: Move cursor to previous word boundary\n if (key.meta && key.leftArrow) {\n nextCursorOffset = findPreviousWordBoundary(originalValue, cursorOffset)\n }\n // Option+Right: Move cursor to next word boundary\n else if (key.meta && key.rightArrow) {\n nextCursorOffset = findNextWordBoundary(originalValue, cursorOffset)\n }\n // Ctrl+A: Move to beginning of line\n else if (key.ctrl && input === \"a\") {\n nextCursorOffset = 0\n }\n // Ctrl+E: Move to end of line\n else if (key.ctrl && input === \"e\") {\n nextCursorOffset = originalValue.length\n }\n // Ctrl+K: Kill from cursor to end of line\n else if (key.ctrl && input === \"k\") {\n nextValue = originalValue.slice(0, cursorOffset)\n // Cursor stays in place\n }\n // Ctrl+U: Kill from cursor to beginning of line\n else if (key.ctrl && input === \"u\") {\n nextValue = originalValue.slice(cursorOffset)\n nextCursorOffset = 0\n }\n // Ctrl+W or Option+Backspace: Delete previous word\n else if (key.ctrl && input === \"w\") {\n const wordStart = findPreviousWordBoundary(originalValue, cursorOffset)\n nextValue = originalValue.slice(0, wordStart) + originalValue.slice(cursorOffset)\n nextCursorOffset = wordStart\n }\n // Option+Backspace (sent as meta + backspace)\n else if (key.meta && key.backspace) {\n const wordStart = findPreviousWordBoundary(originalValue, cursorOffset)\n nextValue = originalValue.slice(0, wordStart) + originalValue.slice(cursorOffset)\n nextCursorOffset = wordStart\n }\n // Regular left arrow\n else if (key.leftArrow) {\n if (showCursor && cursorOffset > 0) {\n nextCursorOffset = cursorOffset - 1\n }\n }\n // Regular right arrow\n else if (key.rightArrow) {\n if (showCursor && cursorOffset < originalValue.length) {\n nextCursorOffset = cursorOffset + 1\n }\n }\n // Backspace\n else if (key.backspace || key.delete) {\n if (cursorOffset > 0) {\n nextValue = originalValue.slice(0, cursorOffset - 1) + originalValue.slice(cursorOffset)\n nextCursorOffset = cursorOffset - 1\n }\n }\n // Regular character input\n else if (input && !key.ctrl && !key.meta) {\n nextValue = originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset)\n nextCursorOffset = cursorOffset + input.length\n }\n\n // Clamp cursor to valid range\n nextCursorOffset = Math.max(0, Math.min(nextCursorOffset, nextValue.length))\n\n setCursorOffset(nextCursorOffset)\n\n if (nextValue !== originalValue) {\n onChange(nextValue)\n }\n },\n { isActive: focus },\n )\n\n return (\n <Text>\n {placeholder ?\n originalValue.length > 0 ?\n renderedValue\n : renderedPlaceholder\n : renderedValue}\n </Text>\n )\n}\n\ntype Props = {\n value: string\n placeholder?: string\n focus?: boolean\n showCursor?: boolean\n onChange: (value: string) => void\n onSubmit?: (value: string) => void\n}\n","/**\n * Find the start of the previous word from cursor position.\n * A word is a sequence of non-whitespace characters.\n */\nexport const findPreviousWordBoundary = (\n /** The text to search */\n text: string,\n /** The current cursor position */\n cursorOffset: number,\n): number => {\n if (cursorOffset <= 0) return 0\n\n let pos = cursorOffset\n\n // Skip any whitespace immediately before cursor\n while (pos > 0 && /\\s/.test(text[pos - 1]!)) {\n pos--\n }\n\n // Skip the word (non-whitespace) characters\n while (pos > 0 && !/\\s/.test(text[pos - 1]!)) {\n pos--\n }\n\n return pos\n}\n","/**\n * Find the end of the next word from cursor position.\n * A word is a sequence of non-whitespace characters.\n */\nexport const findNextWordBoundary = (\n /** The text to search */\n text: string,\n /** The current cursor position */\n cursorOffset: number,\n): number => {\n if (cursorOffset >= text.length) return text.length\n\n let pos = cursorOffset\n\n // Skip any whitespace immediately after cursor\n while (pos < text.length && /\\s/.test(text[pos]!)) {\n pos++\n }\n\n // Skip the word (non-whitespace) characters\n while (pos < text.length && !/\\s/.test(text[pos]!)) {\n pos++\n }\n\n return pos\n}\n","import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync } from \"node:fs\"\nimport { appendFile, readFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\n\n/**\n * JSONL-based event persistence for chat sessions.\n * Each session gets its own `.jsonl` file in the storage directory.\n * Sessions can be namespaced by app (e.g., \"ralph\", \"task-chat\").\n */\nexport class SessionPersister {\n /** Directory where session JSONL files are stored. */\n private storageDir: string\n\n constructor(\n /** Directory to store session JSONL files in. */\n storageDir: string,\n ) {\n this.storageDir = storageDir\n if (!existsSync(storageDir)) {\n mkdirSync(storageDir, { recursive: true })\n }\n }\n\n /** Append an event to a session's JSONL file. */\n async appendEvent(\n /** The session ID. */\n sessionId: string,\n /** The event object to persist. */\n event: Record<string, unknown>,\n /** Optional app namespace. */\n app?: string,\n ): Promise<void> {\n const filePath = this.sessionPath(sessionId, app)\n // Ensure parent directory exists for app-namespaced sessions\n const dir = this.getAppDir(app)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n const line = JSON.stringify(event) + \"\\n\"\n await appendFile(filePath, line, \"utf-8\")\n }\n\n /** Read all events for a session. */\n async readEvents(\n /** The session ID. */\n sessionId: string,\n /** Optional app namespace. */\n app?: string,\n ): Promise<Record<string, unknown>[]> {\n const filePath = this.sessionPath(sessionId, app)\n if (!existsSync(filePath)) return []\n\n const content = await readFile(filePath, \"utf-8\")\n return content\n .split(\"\\n\")\n .filter(line => line.trim())\n .map(line => JSON.parse(line) as Record<string, unknown>)\n }\n\n /** Read events since a given timestamp. */\n async readEventsSince(\n /** The session ID. */\n sessionId: string,\n /** Only return events with timestamp >= this value. */\n since: number,\n /** Optional app namespace. */\n app?: string,\n ): Promise<Record<string, unknown>[]> {\n const events = await this.readEvents(sessionId, app)\n return events.filter(e => (e.timestamp as number) >= since)\n }\n\n /**\n * List all session IDs (derived from JSONL filenames).\n * If app is provided, lists sessions only from that app's directory.\n * If app is undefined, lists sessions from all directories including root.\n */\n listSessions(app?: string): string[] {\n return this.listSessionsWithApp(app).map(s => s.sessionId)\n }\n\n /**\n * List all sessions with their app namespace.\n * If app is provided, lists sessions only from that app's directory.\n * If app is undefined, lists sessions from all directories including root.\n */\n listSessionsWithApp(app?: string): Array<{ sessionId: string; app?: string }> {\n if (!existsSync(this.storageDir)) return []\n\n if (app !== undefined) {\n // List sessions only from the app's directory\n const appDir = this.getAppDir(app)\n if (!existsSync(appDir)) return []\n return readdirSync(appDir)\n .filter(f => f.endsWith(\".jsonl\"))\n .map(f => ({ sessionId: f.replace(/\\.jsonl$/, \"\"), app }))\n }\n\n // List sessions from all directories\n const sessions: Array<{ sessionId: string; app?: string }> = []\n\n // Get root-level sessions\n const entries = readdirSync(this.storageDir, { withFileTypes: true })\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n sessions.push({ sessionId: entry.name.replace(/\\.jsonl$/, \"\"), app: undefined })\n } else if (entry.isDirectory()) {\n // Get sessions from app subdirectories\n const appDir = join(this.storageDir, entry.name)\n for (const file of readdirSync(appDir)) {\n if (file.endsWith(\".jsonl\")) {\n sessions.push({ sessionId: file.replace(/\\.jsonl$/, \"\"), app: entry.name })\n }\n }\n }\n }\n\n return sessions\n }\n\n /** Get the most recently created session ID, or null if none. */\n getLatestSessionId(app?: string): string | null {\n const sessions = this.listSessions(app)\n if (sessions.length === 0) return null\n\n let latest: { id: string; birthtime: number } | null = null\n for (const id of sessions) {\n // Try app-specific path first, then root\n const filePath = app ? this.sessionPath(id, app) : this.findSessionPath(id)\n if (!filePath || !existsSync(filePath)) continue\n const stat = statSync(filePath)\n if (!latest || stat.birthtimeMs > latest.birthtime) {\n latest = { id, birthtime: stat.birthtimeMs }\n }\n }\n return latest?.id ?? null\n }\n\n /** Delete a session's JSONL file. */\n deleteSession(\n /** The session ID. */\n sessionId: string,\n /** Optional app namespace. */\n app?: string,\n ): void {\n const filePath = this.sessionPath(sessionId, app)\n if (existsSync(filePath)) {\n unlinkSync(filePath)\n }\n }\n\n /** Read session metadata from the first event (session_created) in the JSONL file. */\n readSessionMetadata(\n /** The session ID. */\n sessionId: string,\n /** Optional app namespace. */\n app?: string,\n ): {\n adapter: string\n cwd?: string\n createdAt: number\n app?: string\n systemPrompt?: string\n } | null {\n const filePath = this.sessionPath(sessionId, app)\n if (!existsSync(filePath)) return null\n\n try {\n const content = readFileSync(filePath, \"utf-8\")\n const firstLine = content.split(\"\\n\").find(line => line.trim())\n if (!firstLine) return null\n\n const event = JSON.parse(firstLine) as Record<string, unknown>\n if (event.type === \"session_created\") {\n return {\n adapter: (event.adapter as string) ?? \"claude\",\n cwd: event.cwd as string | undefined,\n createdAt: (event.timestamp as number) ?? 0,\n app: event.app as string | undefined,\n systemPrompt: event.systemPrompt as string | undefined,\n }\n }\n return null\n } catch {\n return null\n }\n }\n\n /** Check if a session exists. */\n hasSession(\n /** The session ID. */\n sessionId: string,\n /** Optional app namespace. */\n app?: string,\n ): boolean {\n return existsSync(this.sessionPath(sessionId, app))\n }\n\n /** Get the full file path for a session. */\n getSessionPath(\n /** The session ID. */\n sessionId: string,\n /** Optional app namespace. */\n app?: string,\n ): string {\n return this.sessionPath(sessionId, app)\n }\n\n /** Get the directory for an app. */\n private getAppDir(app?: string): string {\n return app ? join(this.storageDir, app) : this.storageDir\n }\n\n /** Get the file path for a session. */\n private sessionPath(sessionId: string, app?: string): string {\n return join(this.getAppDir(app), `${sessionId}.jsonl`)\n }\n\n /** Find the session path by searching root and app directories. */\n private findSessionPath(sessionId: string): string | null {\n // Check root first\n const rootPath = join(this.storageDir, `${sessionId}.jsonl`)\n if (existsSync(rootPath)) return rootPath\n\n // Check app subdirectories\n if (existsSync(this.storageDir)) {\n const entries = readdirSync(this.storageDir, { withFileTypes: true })\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const appPath = join(this.storageDir, entry.name, `${sessionId}.jsonl`)\n if (existsSync(appPath)) return appPath\n }\n }\n }\n return null\n }\n}\n","import { homedir, platform } from \"node:os\"\nimport { join } from \"node:path\"\n\n/**\n * Get the default storage directory for agent sessions.\n *\n * Returns a system-appropriate location that doesn't pollute the repository:\n * - Linux/macOS: ~/.local/share/ralph/agent-sessions\n * - Windows: %LOCALAPPDATA%\\ralph\\agent-sessions\n */\nexport function getDefaultStorageDir(): string {\n if (platform() === \"win32\") {\n // Windows: use LOCALAPPDATA\n const localAppData = process.env.LOCALAPPDATA ?? join(homedir(), \"AppData\", \"Local\")\n return join(localAppData, \"ralph\", \"agent-sessions\")\n }\n\n // Linux/macOS: use ~/.local/share following XDG Base Directory Specification\n return join(homedir(), \".local\", \"share\", \"ralph\", \"agent-sessions\")\n}\n","import { execSync } from \"child_process\"\nimport { existsSync, readFileSync, writeFileSync } from \"fs\"\nimport { join } from \"path\"\nimport { insertTodo } from \"./insertTodo.js\"\n\n/**\n * Adds a todo item to the todo.md file and commits just that line.\n * Inserts the todo into the working directory, stages only that line, and commits.\n * Creates the file if it doesn't exist.\n */\nexport const addTodo = (\n /** The description of the todo item to add */\n description: string,\n /** The working directory to use (defaults to current directory) */\n cwd: string = process.cwd(),\n): void => {\n const todoPath = join(cwd, \".ralph\", \"todo.md\")\n\n // Read current working directory file (or empty string if it doesn't exist) and insert the new todo\n const content = existsSync(todoPath) ? readFileSync(todoPath, \"utf-8\") : \"\"\n const newContent = insertTodo(content, description)\n\n // Write updated content to working directory\n writeFileSync(todoPath, newContent)\n\n // Get what's currently in the index for this file (or HEAD if not staged, or empty if new)\n let indexContent = \"\"\n try {\n indexContent = execSync(\n \"git show :0:.ralph/todo.md 2>/dev/null || git show HEAD:.ralph/todo.md 2>/dev/null || echo ''\",\n {\n cwd,\n encoding: \"utf-8\",\n },\n )\n } catch {\n // File doesn't exist in git yet, use empty string\n indexContent = \"\"\n }\n\n // Create a blob with just the todo added to the index version\n const indexWithTodo = insertTodo(indexContent, description)\n const blobHash = execSync(\"git hash-object -w --stdin\", {\n cwd,\n encoding: \"utf-8\",\n input: indexWithTodo,\n }).trim()\n\n // Stage just our change by updating the index to this blob\n // Use --add flag to handle new files\n execSync(`git update-index --add --cacheinfo 100644,${blobHash},.ralph/todo.md`, {\n cwd,\n stdio: \"pipe\",\n })\n\n // Commit just the staged change - escape double quotes and backslashes in description\n const escapedDescription = description.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')\n execSync(`git commit -m \"todo: ${escapedDescription}\"`, { cwd, stdio: \"pipe\" })\n\n console.log(`✅ added`)\n}\n","/** Inserts a todo item into the content, right after the \"To do\" header. */\nexport const insertTodo = (\n /** The current content of the todo file */\n content: string,\n /** The description of the todo item to insert */\n description: string,\n): string => {\n const lines = content.split(\"\\n\")\n const todoHeaderIndex = lines.findIndex(line => /^###?\\s*To\\s*do/i.test(line))\n\n if (todoHeaderIndex === -1) {\n // No \"To do\" section found, add one at the beginning\n return `### To do\\n\\n- [ ] ${description}\\n\\n${content}`\n }\n\n // Find the first line after the header (skip empty lines)\n let insertIndex = todoHeaderIndex + 1\n while (insertIndex < lines.length && lines[insertIndex].trim() === \"\") {\n insertIndex++\n }\n\n // Insert the new todo item\n lines.splice(insertIndex, 0, `- [ ] ${description}`)\n\n return lines.join(\"\\n\")\n}\n","import { existsSync } from \"fs\"\nimport { join } from \"path\"\nimport { getBeadsProgress } from \"./getBeadsProgress.js\"\nimport { getTodoProgress } from \"./getTodoProgress.js\"\nimport type { ProgressData } from \"./types.js\"\n\nconst beadsDir = join(process.cwd(), \".beads\")\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/**\n * Get progress data from the workspace.\n *\n * For beads workspaces: Uses timestamp-based counting to accurately track\n * issues closed and created since startup.\n * For todo.md workspaces: completed = checked items, total = all items\n */\nexport const getProgress = (\n /** Initial count of open + in_progress issues at startup */\n initialCount: number,\n /** RFC3339 timestamp for counting issues created after this time */\n startupTimestamp: string,\n): ProgressData => {\n // Check for beads workspace first\n if (existsSync(beadsDir)) {\n return getBeadsProgress(initialCount, startupTimestamp)\n }\n\n // Check for todo.md\n if (existsSync(todoFile)) {\n return getTodoProgress()\n }\n\n return { type: \"none\", completed: 0, total: 0 }\n}\n","import { execSync } from \"child_process\"\nimport type { ProgressData } from \"./types.js\"\n\n/** Get progress for a beads workspace by counting issues created and closed since startup. */\nexport const getBeadsProgress = (\n /** Initial count of open + in_progress issues */\n initialCount: number,\n /** RFC3339 timestamp for counting issues created after this time */\n startupTimestamp: string,\n): ProgressData => {\n try {\n // Count issues created since startup\n const createdSinceStartup = parseInt(\n execSync(`bd count --created-after=\"${startupTimestamp}\"`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n\n // Count current open + in_progress issues\n const currentOpen = parseInt(\n execSync(\"bd count --status=open\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n const currentInProgress = parseInt(\n execSync(\"bd count --status=in_progress\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n const currentRemaining = currentOpen + currentInProgress\n\n // Total = initial open+in_progress + any new issues created\n const total = initialCount + createdSinceStartup\n // Completed = total - remaining (accounts for issues closed by any means)\n const completed = total - currentRemaining\n\n return { type: \"beads\", completed, total }\n } catch {\n // If bd command fails, return no progress\n return { type: \"none\", completed: 0, total: 0 }\n }\n}\n","import { readFileSync } from \"fs\"\nimport { join } from \"path\"\nimport type { ProgressData } from \"./types.js\"\n\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/** Get progress for a todo.md workspace by counting checked and unchecked items. */\nexport const getTodoProgress = (): ProgressData => {\n try {\n const content = readFileSync(todoFile, \"utf-8\")\n\n // Count unchecked items: - [ ]\n const uncheckedMatches = content.match(/- \\[ \\]/g)\n const unchecked = uncheckedMatches ? uncheckedMatches.length : 0\n\n // Count checked items: - [x] or - [X]\n const checkedMatches = content.match(/- \\[[xX]\\]/g)\n const checked = checkedMatches ? checkedMatches.length : 0\n\n const total = unchecked + checked\n\n return { type: \"todo\", completed: checked, total }\n } catch {\n return { type: \"none\", completed: 0, total: 0 }\n }\n}\n","import { existsSync } from \"fs\"\nimport { join } from \"path\"\nimport { captureBeadsSnapshot } from \"./captureBeadsSnapshot.js\"\nimport { captureTodoSnapshot } from \"./captureTodoSnapshot.js\"\nimport type { StartupSnapshot } from \"./types.js\"\n\nconst beadsDir = join(process.cwd(), \".beads\")\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/**\n * Capture a startup snapshot for beads workspaces.\n * Call this once at startup to capture the baseline count and timestamp.\n * Returns undefined if not a beads workspace.\n */\nexport const captureStartupSnapshot = (): StartupSnapshot | undefined => {\n // Check for beads workspace\n if (existsSync(beadsDir)) {\n return captureBeadsSnapshot()\n }\n\n // Check for todo.md workspace\n if (existsSync(todoFile)) {\n return captureTodoSnapshot()\n }\n\n return undefined\n}\n\n/** @deprecated Use captureStartupSnapshot instead */\nexport const getInitialBeadsCount = (): number | undefined => {\n const snapshot = captureStartupSnapshot()\n return snapshot?.initialCount\n}\n","import { execSync } from \"child_process\"\nimport type { StartupSnapshot } from \"./types.js\"\n\n/** Capture a startup snapshot for a beads workspace. */\nexport const captureBeadsSnapshot = (): StartupSnapshot | undefined => {\n try {\n const timestamp = new Date().toISOString()\n\n const openCount = parseInt(\n execSync(\"bd count --status=open\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n const inProgressCount = parseInt(\n execSync(\"bd count --status=in_progress\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim(),\n 10,\n )\n\n return {\n initialCount: openCount + inProgressCount,\n timestamp,\n type: \"beads\",\n }\n } catch {\n return undefined\n }\n}\n","import { readFileSync } from \"fs\"\nimport { join } from \"path\"\nimport type { StartupSnapshot } from \"./types.js\"\n\nconst ralphDir = join(process.cwd(), \".ralph\")\nconst todoFile = join(ralphDir, \"todo.md\")\n\n/** Capture a startup snapshot for a todo.md workspace. */\nexport const captureTodoSnapshot = (): StartupSnapshot | undefined => {\n try {\n const content = readFileSync(todoFile, \"utf-8\")\n\n // Count all items (checked + unchecked)\n const uncheckedMatches = content.match(/- \\[ \\]/g)\n const unchecked = uncheckedMatches ? uncheckedMatches.length : 0\n\n const checkedMatches = content.match(/- \\[[xX]\\]/g)\n const checked = checkedMatches ? checkedMatches.length : 0\n\n return {\n initialCount: unchecked + checked,\n timestamp: new Date().toISOString(),\n type: \"todo\",\n }\n } catch {\n return undefined\n }\n}\n","import React from \"react\"\nimport { Text } from \"ink\"\n\n/**\n * A simple progress bar component using Unicode block characters.\n * Shows completion progress: completed / total\n */\nexport const ProgressBar = ({ completed, total, width = 12, repoName }: Props) => {\n if (total === 0) {\n return null\n }\n\n // Progress is how much is done: completed / total\n const progress = Math.min(1, Math.max(0, completed / total))\n const filledWidth = Math.round(progress * width)\n const emptyWidth = width - filledWidth\n\n const filled = \"▰\".repeat(filledWidth)\n const empty = \"▱\".repeat(emptyWidth)\n\n return (\n <Text>\n {repoName && (\n <>\n <Text color=\"cyan\">{repoName}</Text>\n <Text dimColor> │ </Text>\n </>\n )}\n <Text color=\"yellow\">{filled}</Text>\n <Text dimColor>{empty}</Text>\n <Text dimColor>\n {\" \"}\n {completed}/{total}{\" \"}\n </Text>\n </Text>\n )\n}\n\ntype Props = {\n /** Number of items completed (closed issues or checked tasks) */\n completed: number\n /** Total number of items seen since startup */\n total: number\n /** Width of the progress bar in characters (default: 12) */\n width?: number\n /** Repository name to display before the progress bar */\n repoName?: string\n}\n","import { spawn, type SpawnOptions } from \"node:child_process\"\n\n/** Function signature for spawning child processes. */\nexport type SpawnFn = (\n command: string,\n args: string[],\n options: SpawnOptions,\n) => ReturnType<typeof spawn>\n\n/** Options for the exec helper. */\nexport interface ExecOptions {\n /** Command to run (default: \"bd\") */\n command?: string\n /** Working directory for bd commands */\n cwd?: string\n /** Additional environment variables */\n env?: Record<string, string>\n /** Custom spawn function (for testing) */\n spawn?: SpawnFn\n /** Timeout in ms (default: 30000) */\n timeout?: number\n}\n\n/** Resolved options with defaults applied. */\nexport interface ResolvedExecOptions {\n command: string\n cwd: string\n env: Record<string, string>\n spawn: SpawnFn\n timeout: number\n}\n\n/** Apply defaults to exec options. */\nexport function resolveExecOptions(options: ExecOptions = {}): ResolvedExecOptions {\n return {\n command: options.command ?? \"bd\",\n cwd: options.cwd ?? process.cwd(),\n env: options.env ?? {},\n spawn: options.spawn ?? spawn,\n timeout: options.timeout ?? 30_000,\n }\n}\n\n/**\n * Execute a bd command and return stdout.\n * Spawns a child process, collects stdout/stderr, and resolves with stdout on exit code 0.\n */\nexport function exec(\n /** Command arguments to pass to bd */\n args: string[],\n /** Resolved execution options */\n options: ResolvedExecOptions,\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const proc = options.spawn(options.command, args, {\n cwd: options.cwd,\n env: { ...process.env, ...options.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n })\n\n let stdout = \"\"\n let stderr = \"\"\n\n const timeoutId = setTimeout(() => {\n proc.kill(\"SIGKILL\")\n reject(new Error(`bd command timed out after ${options.timeout}ms`))\n }, options.timeout)\n\n proc.stdout?.on(\"data\", (data: Buffer) => {\n stdout += data.toString()\n })\n\n proc.stderr?.on(\"data\", (data: Buffer) => {\n stderr += data.toString()\n })\n\n proc.on(\"error\", err => {\n clearTimeout(timeoutId)\n reject(err)\n })\n\n proc.on(\"close\", code => {\n clearTimeout(timeoutId)\n if (code === 0) {\n resolve(stdout)\n } else {\n reject(new Error(`bd exited with code ${code}: ${stderr.trim() || stdout.trim()}`))\n }\n })\n })\n}\n","import { createConnection, type Socket } from \"node:net\"\nimport { join } from \"node:path\"\nimport { existsSync } from \"node:fs\"\nimport type { MutationEvent } from \"./types.js\"\n\n/**\n * Client for communicating with the beads daemon via Unix socket.\n * Provides mutation events and ready-issue queries via RPC.\n */\nexport class DaemonSocket {\n private socket: Socket | null = null\n private connected = false\n private socketPath: string\n private connectTimeout: number\n private requestTimeout: number\n\n constructor(options: DaemonSocketOptions = {}) {\n const cwd = options.cwd ?? process.cwd()\n this.socketPath = join(cwd, \".beads\", \"bd.sock\")\n this.connectTimeout = options.connectTimeout ?? 2000\n this.requestTimeout = options.requestTimeout ?? 5000\n }\n\n /** Check if the beads daemon socket file exists. */\n socketExists(): boolean {\n return existsSync(this.socketPath)\n }\n\n /** Check if connected to the daemon. */\n get isConnected(): boolean {\n return this.connected && this.socket !== null\n }\n\n /** Connect to the beads daemon. Returns true if connected, false otherwise. */\n async connect(): Promise<boolean> {\n if (!this.socketExists()) return false\n\n if (this.connected && this.socket) return true\n\n return new Promise(resolve => {\n this.socket = createConnection(this.socketPath)\n\n const timeout = setTimeout(() => {\n this.socket?.destroy()\n this.socket = null\n resolve(false)\n }, this.connectTimeout)\n\n this.socket.on(\"connect\", () => {\n clearTimeout(timeout)\n this.connected = true\n resolve(true)\n })\n\n this.socket.on(\"error\", () => {\n clearTimeout(timeout)\n this.socket = null\n this.connected = false\n resolve(false)\n })\n\n this.socket.on(\"close\", () => {\n this.socket = null\n this.connected = false\n })\n })\n }\n\n /** Send an RPC request and wait for response. */\n private async execute<T>(\n /** RPC operation name */\n operation: string,\n /** RPC arguments */\n args: Record<string, unknown> = {},\n ): Promise<T | null> {\n if (!this.socket || !this.connected) {\n return null\n }\n\n return new Promise(resolve => {\n const request: RPCRequest = { operation, args }\n const requestLine = JSON.stringify(request) + \"\\n\"\n\n let responseData = \"\"\n\n const onData = (chunk: Buffer) => {\n responseData += chunk.toString()\n if (responseData.includes(\"\\n\")) {\n cleanup()\n try {\n const response: RPCResponse = JSON.parse(responseData.trim())\n if (response.success && response.data !== undefined) {\n resolve(response.data as T)\n } else {\n resolve(null)\n }\n } catch {\n resolve(null)\n }\n }\n }\n\n const onError = () => {\n cleanup()\n resolve(null)\n }\n\n const timeout = setTimeout(() => {\n cleanup()\n resolve(null)\n }, this.requestTimeout)\n\n const cleanup = () => {\n clearTimeout(timeout)\n this.socket?.off(\"data\", onData)\n this.socket?.off(\"error\", onError)\n }\n\n this.socket!.on(\"data\", onData)\n this.socket!.on(\"error\", onError)\n this.socket!.write(requestLine)\n })\n }\n\n /**\n * Get mutations since a given timestamp.\n * Returns all mutation events that occurred after the specified timestamp.\n */\n async getMutations(\n /** Unix timestamp in milliseconds (0 for all recent) */\n since: number = 0,\n ): Promise<MutationEvent[]> {\n const result = await this.execute<MutationEvent[]>(\"get_mutations\", { since })\n return result ?? []\n }\n\n /** Get ready issues (open and unblocked). */\n async getReady(): Promise<{ id: string; title: string }[]> {\n const result = await this.execute<{ id: string; title: string }[]>(\"ready\", {})\n return result ?? []\n }\n\n /** Close the connection to the daemon. */\n close(): void {\n if (this.socket) {\n this.socket.destroy()\n this.socket = null\n this.connected = false\n }\n }\n}\n\n/** Options for watching mutations. */\nexport interface WatchMutationsOptions {\n /** Working directory for socket location */\n cwd?: string\n /** Polling interval in ms (default: 1000) */\n interval?: number\n /** Initial timestamp to start watching from (default: now) */\n since?: number\n}\n\n/**\n * Watch for mutation events from the beads daemon.\n * Polls the daemon periodically for new mutations and calls the callback\n * for each event. Returns a cleanup function to stop watching.\n */\nexport function watchMutations(\n /** Callback for each mutation event */\n onMutation: (event: MutationEvent) => void,\n /** Watch options */\n options: WatchMutationsOptions = {},\n): () => void {\n const { cwd, interval = 1000, since } = options\n\n let lastTimestamp = since ?? Date.now()\n let client: DaemonSocket | null = null\n let timeoutId: NodeJS.Timeout | null = null\n let stopped = false\n\n const poll = async () => {\n if (stopped) return\n\n if (!client) {\n client = new DaemonSocket({ cwd })\n const connected = await client.connect()\n if (!connected) {\n if (!stopped) timeoutId = setTimeout(poll, interval)\n return\n }\n }\n\n try {\n const mutations = await client.getMutations(lastTimestamp)\n\n for (const mutation of mutations) {\n onMutation(mutation)\n const mutationTime = new Date(mutation.Timestamp).getTime()\n if (mutationTime > lastTimestamp) lastTimestamp = mutationTime\n }\n } catch {\n client?.close()\n client = null\n }\n\n if (!stopped) timeoutId = setTimeout(poll, interval)\n }\n\n poll()\n\n return () => {\n stopped = true\n if (timeoutId) {\n clearTimeout(timeoutId)\n timeoutId = null\n }\n client?.close()\n client = null\n }\n}\n\n/** RPC request format for beads daemon. */\ninterface RPCRequest {\n operation: string\n args: Record<string, unknown>\n}\n\n/** RPC response format from beads daemon. */\ninterface RPCResponse {\n success: boolean\n data?: unknown\n error?: string\n}\n\n/** Options for the daemon socket connection. */\nexport interface DaemonSocketOptions {\n /** Workspace directory path (used to locate .beads/bd.sock) */\n cwd?: string\n /** Connection timeout in ms (default: 2000) */\n connectTimeout?: number\n /** Request timeout in ms (default: 5000) */\n requestTimeout?: number\n}\n","/**\n * Re-exports from @herbcaudill/beads-sdk with backward-compatible names for CLI.\n */\nimport {\n DaemonSocket,\n watchMutations as sdkWatchMutations,\n type MutationEvent,\n} from \"@herbcaudill/beads-sdk\"\n\n/** Re-export MutationEvent for backward compatibility. */\nexport type { MutationEvent } from \"@herbcaudill/beads-sdk\"\n\n/** Re-export DaemonSocket as BeadsClient for backward compatibility. */\nexport { DaemonSocket as BeadsClient } from \"@herbcaudill/beads-sdk\"\n\n/**\n * Poll for new issue creation events.\n * Returns a cleanup function.\n */\nexport function watchForNewIssues(\n /** Callback for each new issue event */\n onNewIssue: (issue: MutationEvent) => void,\n /** Polling interval in ms (default: 5000) */\n interval: number = 5000,\n): () => void {\n return sdkWatchMutations(\n (event: MutationEvent) => {\n if (event.Type === \"create\") {\n onNewIssue(event)\n }\n },\n { interval },\n )\n}\n","type DebugNamespace = \"messagequeue\" | \"session\" | \"sdk\" | \"stdin-command\" | \"worktree\"\n\n/**\n * Check if debug logging is enabled for the given namespace.\n * Controlled by RALPH_DEBUG environment variable:\n * - RALPH_DEBUG=1 or RALPH_DEBUG=true or RALPH_DEBUG=all - enable all logging\n * - RALPH_DEBUG=messagequeue - enable only that namespace\n * - RALPH_DEBUG=messagequeue,session - enable multiple namespaces\n */\nconst isDebugEnabled = (\n /** The debug namespace to check, or undefined to check global debug setting */\n namespace?: DebugNamespace,\n): boolean => {\n const debugEnv = process.env.RALPH_DEBUG\n\n if (!debugEnv) return false\n\n const value = debugEnv.toLowerCase()\n\n // Enable all debugging\n if (value === \"1\" || value === \"true\" || value === \"all\" || value === \"*\") {\n return true\n }\n\n // Enable specific namespace\n if (namespace && value === namespace.toLowerCase()) {\n return true\n }\n\n // Comma-separated list of namespaces\n if (namespace && value.includes(\",\")) {\n return value.split(\",\").some(ns => ns.trim().toLowerCase() === namespace.toLowerCase())\n }\n\n return false\n}\n\n/** Log a debug message if debugging is enabled for the given namespace. */\nexport const debug = (\n /** The debug namespace for this message */\n namespace: DebugNamespace,\n /** The message to log */\n message: string,\n /** Additional arguments to log after the message */\n ...args: unknown[]\n): void => {\n if (isDebugEnabled(namespace)) {\n const timestamp = new Date().toISOString()\n const prefix = `[${timestamp}] [RALPH:${namespace.toUpperCase()}]`\n // eslint-disable-next-line no-console\n console.error(prefix, message, ...args)\n }\n}\n\n/** Create a namespaced debug logger that captures the namespace for all logs. */\nexport const createDebugLogger = (\n /** The debug namespace to use for all logged messages */\n namespace: DebugNamespace,\n) => {\n return (\n /** The message to log */\n message: string,\n /** Additional arguments to log after the message */\n ...args: unknown[]\n ) => debug(namespace, message, ...args)\n}\n","import type { SDKUserMessage } from \"@anthropic-ai/claude-agent-sdk\"\n\n/** Create an SDKUserMessage from text. */\nexport const createUserMessage = (\n /** The text content of the message */\n text: string,\n): SDKUserMessage => ({\n type: \"user\",\n session_id: \"\",\n message: {\n role: \"user\",\n content: [{ type: \"text\", text }],\n },\n parent_tool_use_id: null,\n})\n","import type { SDKUserMessage } from \"@anthropic-ai/claude-agent-sdk\"\nimport { createDebugLogger } from \"./debug.js\"\nimport { createUserMessage } from \"./createUserMessage.js\"\n\nconst log = createDebugLogger(\"messagequeue\")\n\n/**\n * A message queue that can be used as an async iterable for the SDK's streamInput.\n * Allows pushing messages dynamically while iterating.\n */\nexport class MessageQueue implements AsyncIterable<SDKUserMessage> {\n private queue: SDKUserMessage[] = []\n private resolvers: Array<(result: IteratorResult<SDKUserMessage>) => void> = []\n private closed = false\n private nextCallCount = 0\n\n /**\n * Push a message to the queue. If there are pending resolvers waiting for the next message,\n * resolve immediately. Otherwise, add to queue.\n */\n push(\n /** The message to push to the queue */\n message: SDKUserMessage,\n ): void {\n const messagePreview = this.getMessagePreview(message)\n log(`push() called with message: ${messagePreview}`)\n\n if (this.closed) {\n log(`push() ignored - queue is closed`)\n return\n }\n\n if (this.resolvers.length > 0) {\n const resolve = this.resolvers.shift()!\n log(`push() resolving pending next() call (${this.resolvers.length} resolvers remaining)`)\n resolve({ value: message, done: false })\n } else {\n this.queue.push(message)\n log(`push() added to queue (queue length: ${this.queue.length})`)\n }\n }\n\n /**\n * Close the queue. Resolve any pending resolvers with done=true.\n */\n close(): void {\n if (this.closed) {\n log(`close() called but already closed - no-op`)\n return\n }\n log(`close() called - resolving ${this.resolvers.length} pending resolvers`)\n this.closed = true\n // Resolve any pending iterators\n for (const resolve of this.resolvers) {\n log(`close() resolving pending resolver with done=true`)\n resolve({ value: undefined as unknown as SDKUserMessage, done: true })\n }\n this.resolvers = []\n log(`close() complete`)\n }\n\n /**\n * Get a preview string of a message for debug logging.\n */\n private getMessagePreview(\n /** The message to extract a preview from */\n message: SDKUserMessage,\n ): string {\n const content = message.message?.content\n if (Array.isArray(content) && content.length > 0) {\n const firstBlock = content[0]\n if (\"text\" in firstBlock && typeof firstBlock.text === \"string\") {\n const text = firstBlock.text.slice(0, 50)\n return text.length < firstBlock.text.length ? `\"${text}...\"` : `\"${text}\"`\n }\n }\n return `[${message.type} message]`\n }\n\n /**\n * Implement the async iterable protocol to allow session with for-await-of.\n */\n [Symbol.asyncIterator](): AsyncIterator<SDKUserMessage> {\n return {\n next: (): Promise<IteratorResult<SDKUserMessage>> => {\n this.nextCallCount++\n const callId = this.nextCallCount\n\n if (this.queue.length > 0) {\n const message = this.queue.shift()!\n log(`next() #${callId}: returning queued message (${this.queue.length} remaining)`)\n return Promise.resolve({ value: message, done: false })\n }\n if (this.closed) {\n log(`next() #${callId}: queue closed, returning done=true`)\n return Promise.resolve({ value: undefined as unknown as SDKUserMessage, done: true })\n }\n log(\n `next() #${callId}: queue empty, creating pending resolver (${this.resolvers.length + 1} total)`,\n )\n return new Promise(resolve => {\n this.resolvers.push(resolve)\n })\n },\n }\n }\n}\n\nexport { createUserMessage }\n","import { useState, useEffect } from \"react\"\nimport { useStdout } from \"ink\"\nimport { getTerminalSize } from \"./getTerminalSize.js\"\n\n/** Hook to get the current terminal size and subscribe to resize events. */\nexport const useTerminalSize = () => {\n const { stdout } = useStdout()\n const [size, setSize] = useState(() => getTerminalSize(stdout))\n\n useEffect(() => {\n const handleResize = () => {\n setSize(getTerminalSize(stdout))\n }\n\n stdout?.on(\"resize\", handleResize)\n\n return () => {\n stdout?.off(\"resize\", handleResize)\n }\n }, [stdout])\n\n return size\n}\n","/** Get the current terminal size with sensible defaults. */\nexport function getTerminalSize(\n /** The stdout object from Ink's useStdout hook */\n stdout: any,\n) {\n return {\n columns: stdout?.columns ?? 80,\n rows: stdout?.rows ?? 24,\n }\n}\n","/**\n * Parse a text message to detect task lifecycle events.\n * Returns TaskLifecycleInfo if the text matches the pattern, null otherwise.\n *\n * Patterns recognized:\n * - \"<start_task>task-id</start_task>\"\n * - \"<end_task>task-id</end_task>\"\n */\nexport function parseTaskLifecycleEvent(\n /** The text message to parse */\n text: string,\n): TaskLifecycleInfo | null {\n // Match starting pattern: <start_task>task-id</start_task>\n const startingMatch = text.match(/<start_task>([a-z]+-[a-z0-9]+(?:\\.[a-z0-9]+)*)<\\/start_task>/i)\n if (startingMatch) {\n return {\n action: \"starting\",\n taskId: startingMatch[1],\n }\n }\n\n // Match completed pattern: <end_task>task-id</end_task>\n const completedMatch = text.match(/<end_task>([a-z]+-[a-z0-9]+(?:\\.[a-z0-9]+)*)<\\/end_task>/i)\n if (completedMatch) {\n return {\n action: \"completed\",\n taskId: completedMatch[1],\n }\n }\n\n return null\n}\n\n/** Result of parsing a task lifecycle event. */\nexport interface TaskLifecycleInfo {\n action: \"starting\" | \"completed\"\n taskId?: string\n}\n","import { existsSync, readFileSync } from \"fs\"\nimport { join, dirname } from \"path\"\nimport { fileURLToPath } from \"url\"\nimport { loadSessionPrompt, getWorkspaceRoot } from \"@herbcaudill/ralph-shared/prompts\"\n\n/**\n * Get the prompt content by combining core.prompt.md with workflow.prompt.md.\n *\n * First checks for a custom prompt at .ralph/prompt.prompt.md. If that exists, uses it directly.\n * Otherwise, loads the session prompt which combines:\n * - core.prompt.md (always from templates)\n * - workflow.prompt.md (from .ralph/workflow.prompt.md if it exists, otherwise from templates)\n */\nexport const getPromptContent = (): string => {\n const __dirname = dirname(fileURLToPath(import.meta.url))\n const workspaceRoot = getWorkspaceRoot(process.cwd())\n const ralphDir = join(workspaceRoot, \".ralph\")\n const promptFile = join(ralphDir, \"prompt.prompt.md\")\n\n // Resolve templates directory relative to this file's location.\n // In source (src/lib/): ../../templates → packages/cli/templates ✓\n // In bundle (dist/): ../../templates → packages/templates ✗\n // We try both paths to support both dev and bundled modes.\n let templatesDir = join(__dirname, \"..\", \"..\", \"templates\")\n if (!existsSync(join(templatesDir, \"core.prompt.md\"))) {\n templatesDir = join(__dirname, \"..\", \"templates\")\n }\n\n // First, try to read from .ralph/prompt.prompt.md (custom override)\n if (existsSync(promptFile)) {\n return readFileSync(promptFile, \"utf-8\")\n }\n\n // Load session prompt (combines core.prompt.md with workflow.prompt.md)\n const { content } = loadSessionPrompt({\n templatesDir,\n cwd: workspaceRoot,\n })\n\n return content\n}\n","import { existsSync, readFileSync, copyFileSync, mkdirSync } from \"node:fs\"\nimport { join, dirname } from \"node:path\"\nimport { getWorkspaceRoot } from \"./getWorkspaceRoot.js\"\n\n/** Placeholder in core prompt for workflow content */\nconst WORKFLOW_PLACEHOLDER = \"{WORKFLOW}\"\n\n/** Get the path to a custom prompt file. */\nexport function getCustomPromptPath(\n /** Configuration options */\n options: {\n filename: string\n customDir: string\n cwd?: string\n },\n): string {\n const { filename, customDir, cwd = process.cwd() } = options\n return join(cwd, customDir, filename)\n}\n\n/**\n * Load a prompt file with fallback to default.\n *\n * First checks for a customized prompt in the custom directory.\n * Falls back to the default prompt if no customization exists.\n */\nexport function loadPrompt(\n /** Configuration for loading the prompt */\n options: LoadPromptOptions,\n): LoadPromptResult {\n const { filename, customDir, defaultPath, cwd = process.cwd() } = options\n const customPath = getCustomPromptPath({ filename, customDir, cwd })\n\n // Try to load customized prompt first\n if (existsSync(customPath)) {\n return {\n content: readFileSync(customPath, \"utf-8\"),\n path: customPath,\n isCustom: true,\n }\n }\n\n // Fall back to default prompt\n if (existsSync(defaultPath)) {\n return {\n content: readFileSync(defaultPath, \"utf-8\"),\n path: defaultPath,\n isCustom: false,\n }\n }\n\n throw new Error(`Prompt file not found at ${customPath} or ${defaultPath}`)\n}\n\n/**\n * Initialize a prompt by copying the default to the custom directory if it doesn't exist.\n *\n * This allows users to customize the prompt on a per-project basis.\n */\nexport function initPrompt(\n /** Configuration for initializing the prompt */\n options: LoadPromptOptions,\n): {\n path: string\n created: boolean\n} {\n const { filename, customDir, defaultPath, cwd = process.cwd() } = options\n const customPath = getCustomPromptPath({ filename, customDir, cwd })\n\n // Already exists - no need to copy\n if (existsSync(customPath)) {\n return { path: customPath, created: false }\n }\n\n // Ensure custom directory exists\n const customDirPath = dirname(customPath)\n if (!existsSync(customDirPath)) {\n mkdirSync(customDirPath, { recursive: true })\n }\n\n // Copy default prompt to custom directory\n if (existsSync(defaultPath)) {\n copyFileSync(defaultPath, customPath)\n return { path: customPath, created: true }\n }\n\n throw new Error(`Default prompt not found at ${defaultPath}`)\n}\n\n/** Check if a custom prompt file exists. */\nexport function hasCustomPrompt(\n /** Configuration options */\n options: {\n filename: string\n customDir: string\n cwd?: string\n },\n): boolean {\n const customPath = getCustomPromptPath(options)\n return existsSync(customPath)\n}\n\n/**\n * Load the session prompt by combining core.prompt.md with workflow.prompt.md.\n *\n * The core prompt is always loaded from templates (bundled).\n * The workflow is loaded from .ralph/workflow.prompt.md if it exists, otherwise from templates.\n * The workflow content replaces {WORKFLOW} placeholder in the core prompt.\n */\nexport function loadSessionPrompt(\n /** Configuration for loading the prompt */\n options: LoadSessionPromptOptions,\n): LoadSessionPromptResult {\n const { templatesDir, cwd = process.cwd() } = options\n const workspaceRoot = getWorkspaceRoot(cwd)\n\n // Load core prompt (always from templates)\n const corePromptPath = join(templatesDir, \"core.prompt.md\")\n if (!existsSync(corePromptPath)) {\n throw new Error(`Core prompt not found at ${corePromptPath}`)\n }\n const corePrompt = readFileSync(corePromptPath, \"utf-8\")\n\n // Try custom workflow first, then fall back to template\n const customWorkflowPath = join(workspaceRoot, \".ralph\", \"workflow.prompt.md\")\n const defaultWorkflowPath = join(templatesDir, \"workflow.prompt.md\")\n\n let workflowContent: string\n let hasCustomWorkflow: boolean\n let workflowPath: string\n\n if (existsSync(customWorkflowPath)) {\n workflowContent = readFileSync(customWorkflowPath, \"utf-8\")\n hasCustomWorkflow = true\n workflowPath = customWorkflowPath\n } else if (existsSync(defaultWorkflowPath)) {\n workflowContent = readFileSync(defaultWorkflowPath, \"utf-8\")\n hasCustomWorkflow = false\n workflowPath = defaultWorkflowPath\n } else {\n throw new Error(`Workflow file not found at ${customWorkflowPath} or ${defaultWorkflowPath}`)\n }\n\n // Combine by replacing placeholder\n const content = corePrompt.replace(WORKFLOW_PLACEHOLDER, workflowContent)\n\n return {\n content,\n hasCustomWorkflow,\n workflowPath,\n }\n}\n\n/** Check if a custom workflow exists. */\nexport function hasCustomWorkflow(\n /** Working directory (defaults to process.cwd()) */\n cwd: string = process.cwd(),\n): boolean {\n return existsSync(join(getWorkspaceRoot(cwd), \".ralph\", \"workflow.prompt.md\"))\n}\n\n/** Get the path to the custom workflow file. */\nexport function getCustomWorkflowPath(\n /** Working directory (defaults to process.cwd()) */\n cwd: string = process.cwd(),\n): string {\n return join(getWorkspaceRoot(cwd), \".ralph\", \"workflow.prompt.md\")\n}\n\n/** Configuration for loading a prompt file. */\nexport type LoadPromptOptions = {\n /** Name of the prompt file (e.g., \"prompt.prompt.md\" or \"task-chat-system.prompt.md\") */\n filename: string\n /** Path to the custom prompt directory (e.g., \".ralph\") */\n customDir: string\n /** Path to the default prompt file */\n defaultPath: string\n /** Working directory to search for custom prompt (defaults to process.cwd()) */\n cwd?: string\n}\n\n/** Result from loading a prompt file. */\nexport type LoadPromptResult = {\n /** The prompt content */\n content: string\n /** The path from which the prompt was loaded */\n path: string\n /** Whether the prompt was loaded from a custom location */\n isCustom: boolean\n}\n\n/** Configuration for loading session prompts. */\nexport type LoadSessionPromptOptions = {\n /** Path to the templates directory containing core.prompt.md and workflow.prompt.md */\n templatesDir: string\n /** Working directory to search for custom workflow (defaults to process.cwd()) */\n cwd?: string\n}\n\n/** Result from loading session prompt. */\nexport type LoadSessionPromptResult = {\n /** The combined prompt content (core + workflow) */\n content: string\n /** Whether a custom workflow was used */\n hasCustomWorkflow: boolean\n /** Path to the workflow file that was used */\n workflowPath: string\n}\n","import { existsSync } from \"node:fs\"\nimport { dirname, resolve } from \"node:path\"\n\n/**\n * Find the repository root by walking up from a starting directory.\n */\nexport function getWorkspaceRoot(\n /** Directory to start searching from */\n cwd: string = process.cwd(),\n): string {\n const start = resolve(cwd)\n let current = start\n\n while (true) {\n const gitPath = resolve(current, \".git\")\n if (existsSync(gitPath)) {\n return current\n }\n\n const parent = dirname(current)\n if (parent === current) {\n return start\n }\n current = parent\n }\n}\n","import { dirname, join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\n/** Path to the shared templates directory containing core.prompt.md and workflow.prompt.md. */\nexport const TEMPLATES_DIR = join(dirname(fileURLToPath(import.meta.url)), \"..\", \"..\", \"templates\")\n","import { type SDKMessage } from \"@anthropic-ai/claude-agent-sdk\"\n\n/** Convert SDK message to event format for display. */\nexport const sdkMessageToEvent = (\n /** The SDK message to convert */\n message: SDKMessage,\n): Record<string, unknown> | null => {\n // Pass through assistant and result messages for display.\n // User messages are NOT passed through because:\n // - The initial prompt doesn't need display (session header suffices)\n // - User-injected messages are added directly to events in handleUserMessageSubmit\n // - Sub-agent user messages (Task tool prompts) would repeat on every partial update\n if (message.type === \"assistant\" || message.type === \"result\") {\n return message as unknown as Record<string, unknown>\n }\n // Skip system and stream_event messages for display\n return null\n}\n","import { isAbsolute, relative } from \"path\"\nimport { getBaseCwd } from \"./getBaseCwd.js\"\n\n/**\n * Convert an absolute path to a relative path from the base working directory.\n * For temp files, returns just the filename. Leaves relative paths unchanged.\n */\nexport const rel = (\n /** The path to convert */\n path: string,\n) => {\n if (!isAbsolute(path)) {\n return path\n }\n // For temp files, just show the filename\n if (path.includes(\"/var/folders/\") || path.includes(\"/tmp/\")) {\n return path.split(\"/\").pop() || path\n }\n return relative(getBaseCwd(), path) || path\n}\n","/**\n * Get the base working directory for relative path calculations.\n * Respects RALPH_CWD environment variable if set, otherwise uses current working directory.\n */\nexport const getBaseCwd = () => process.env.RALPH_CWD ?? process.cwd()\n","/**\n * Replace temp file paths with just the filename.\n * Shortens macOS and Linux temporary paths to be more readable in output.\n */\nexport const shortenTempPaths = (\n /** The text to process */\n text: string,\n) => {\n return text\n .replace(/\\/var\\/folders\\/[^\\s]+/g, match => match.split(\"/\").pop() || match)\n .replace(/\\/tmp\\/[^\\s]+/g, match => match.split(\"/\").pop() || match)\n}\n","import { rel } from \"../lib/rel.js\"\nimport { shortenTempPaths } from \"../lib/shortenTempPaths.js\"\n\n/**\n * Transform an event from the Claude SDK into display blocks.\n * Extracts text content and tool use information from assistant and user messages.\n */\nexport const eventToBlocks = (\n /** The event object from Claude SDK containing message data */\n event: Record<string, unknown>,\n): ContentBlock[] => {\n // Handle user messages\n if (event.type === \"user\") {\n const message = event.message as Record<string, unknown> | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n const messageId = (message?.id as string | undefined) ?? `user-${Date.now()}`\n\n if (!content) {\n return []\n }\n\n // Extract text from user message content\n const textContent = content\n .filter(block => block.type === \"text\")\n .map(block => block.text as string)\n .join(\"\")\n\n if (textContent) {\n return [{ type: \"user\", content: textContent, id: messageId }]\n }\n return []\n }\n\n if (event.type !== \"assistant\") {\n return []\n }\n\n const message = event.message as Record<string, unknown> | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n\n if (!content) {\n return []\n }\n\n const blocks: ContentBlock[] = []\n const messageId = (message?.id as string | undefined) ?? \"unknown\"\n let blockIndex = 0\n\n let textBuffer = \"\" // Accumulate consecutive text blocks\n\n for (const block of content) {\n if (block.type === \"text\") {\n const text = block.text as string | undefined\n if (text) {\n textBuffer += text\n }\n } else if (block.type === \"tool_use\") {\n // Flush accumulated text before processing tool\n if (textBuffer) {\n blocks.push({ type: \"text\", content: textBuffer, id: `${messageId}-${blockIndex++}` })\n textBuffer = \"\"\n }\n const input = block.input as Record<string, unknown> | undefined\n const name = block.name as string\n\n if (name === \"Read\") {\n const filePath = input?.file_path as string | undefined\n if (filePath) {\n blocks.push({\n type: \"tool\",\n name: \"Read\",\n arg: rel(filePath),\n id: `${messageId}-${blockIndex++}`,\n })\n }\n } else if (name === \"Edit\" || name === \"Write\") {\n const filePath = input?.file_path as string | undefined\n if (filePath) {\n blocks.push({\n type: \"tool\",\n name,\n arg: rel(filePath),\n id: `${messageId}-${blockIndex++}`,\n })\n }\n } else if (name === \"Bash\") {\n const command = input?.command as string | undefined\n if (command) {\n blocks.push({\n type: \"tool\",\n name: \"$\",\n arg: shortenTempPaths(command),\n id: `${messageId}-${blockIndex++}`,\n })\n }\n } else if (name === \"Grep\") {\n const pattern = input?.pattern as string | undefined\n const path = input?.path as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"Grep\",\n arg: `${pattern}${path ? ` in ${rel(path)}` : \"\"}`,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"Glob\") {\n const pattern = input?.pattern as string | undefined\n const path = input?.path as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"Glob\",\n arg: `${pattern}${path ? ` in ${rel(path)}` : \"\"}`,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"TodoWrite\") {\n const todos = input?.todos as Array<{ content: string; status: string }> | undefined\n if (todos?.length) {\n const summary = todos\n .map(\n t =>\n `[${\n t.status === \"completed\" ? \"x\"\n : t.status === \"in_progress\" ? \"~\"\n : \" \"\n }] ${t.content}`,\n )\n .join(\"\\n \")\n blocks.push({\n type: \"tool\",\n name: \"TodoWrite\",\n arg: \"\\n \" + summary,\n id: `${messageId}-${blockIndex++}`,\n })\n } else {\n blocks.push({ type: \"tool\", name: \"TodoWrite\", id: `${messageId}-${blockIndex++}` })\n }\n } else if (name === \"WebFetch\") {\n const url = input?.url as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"WebFetch\",\n arg: url,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"WebSearch\") {\n const query = input?.query as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"WebSearch\",\n arg: query,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"Task\") {\n const description = input?.description as string | undefined\n blocks.push({\n type: \"tool\",\n name: \"Task\",\n arg: description,\n id: `${messageId}-${blockIndex++}`,\n })\n } else if (name === \"Skill\") {\n const skill = input?.skill as string | undefined\n blocks.push({ type: \"tool\", name: \"Skill\", arg: skill, id: `${messageId}-${blockIndex++}` })\n }\n }\n }\n\n // Flush any remaining text at the end\n if (textBuffer) {\n blocks.push({ type: \"text\", content: textBuffer, id: `${messageId}-${blockIndex++}` })\n }\n\n return blocks\n}\n\nexport type ContentBlock =\n | { type: \"text\"; content: string; id: string }\n | { type: \"tool\"; name: string; arg?: string; id: string }\n | { type: \"user\"; content: string; id: string }\n","import { eventToBlocks, type ContentBlock } from \"../components/eventToBlocks.js\"\n\n/**\n * Process raw events into content blocks.\n *\n * With includePartialMessages: true, we receive multiple snapshots of the same message\n * as it builds up. Each snapshot may contain different parts of the message content,\n * so we need to merge them and deduplicate.\n */\nexport const processEvents = (\n /** Array of raw event objects from the SDK */\n events: Array<Record<string, unknown>>,\n): ContentBlock[] => {\n const blocks: ContentBlock[] = []\n\n // First pass: collect all assistant message content and track message order\n const assistantEvents = events.filter(event => event.type === \"assistant\")\n\n // Collect all content blocks from all snapshots of the same message\n const messageMap = new Map<string, Array<Record<string, unknown>>>()\n for (const event of assistantEvents) {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = message?.id as string | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n\n if (messageId && content) {\n if (!messageMap.has(messageId)) {\n messageMap.set(messageId, [])\n }\n messageMap.get(messageId)!.push(...content)\n }\n }\n\n // Create merged events with deduplicated content\n const mergedEvents = Array.from(messageMap.entries()).map(([messageId, allContent]) => {\n // Deduplicate content blocks by their ID (for tool_use) or text (for text blocks)\n const seenBlocks = new Set<string>()\n const uniqueContent: Array<Record<string, unknown>> = []\n\n for (const block of allContent) {\n const blockType = block.type as string\n let blockKey: string\n\n if (blockType === \"tool_use\") {\n // Tool use blocks are unique by their ID\n blockKey = `tool:${block.id}`\n } else if (blockType === \"text\") {\n // For text blocks, check if this is a prefix of or prefixed by existing text\n // This handles incremental text updates where each snapshot has more content\n const text = block.text as string\n let isDuplicate = false\n\n for (const seenKey of seenBlocks) {\n if (seenKey.startsWith(\"text:\")) {\n const seenText = seenKey.substring(5)\n // If existing text starts with this text, or this text starts with existing,\n // keep only the longer one\n if (seenText.startsWith(text)) {\n // Existing is longer, this is a duplicate\n isDuplicate = true\n break\n } else if (text.startsWith(seenText)) {\n // This is longer, remove the old one and add this\n seenBlocks.delete(seenKey)\n // Also remove from uniqueContent\n const idx = uniqueContent.findIndex(b => b.type === \"text\" && b.text === seenText)\n if (idx >= 0) uniqueContent.splice(idx, 1)\n break\n }\n }\n }\n\n if (isDuplicate) continue\n blockKey = `text:${text}`\n } else {\n blockKey = JSON.stringify(block)\n }\n\n if (!seenBlocks.has(blockKey)) {\n seenBlocks.add(blockKey)\n uniqueContent.push(block)\n }\n }\n\n return {\n type: \"assistant\",\n message: {\n id: messageId,\n content: uniqueContent,\n },\n }\n })\n\n const assistantBlocks = mergedEvents.flatMap(event => eventToBlocks(event))\n\n // Second pass: process events in order, including user messages\n // Track which user messages and assistant messages we've already seen\n const processedUserIds = new Set<string>()\n const processedAssistantIds = new Set<string>()\n\n for (const event of events) {\n if (event.type === \"user\") {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = (message?.id as string | undefined) ?? `user-${Date.now()}`\n if (!processedUserIds.has(messageId)) {\n processedUserIds.add(messageId)\n blocks.push(...eventToBlocks(event))\n }\n } else if (event.type === \"assistant\") {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = message?.id as string | undefined\n if (messageId && !processedAssistantIds.has(messageId)) {\n processedAssistantIds.add(messageId)\n // Find the merged version of this message\n const merged = assistantBlocks.filter(b => b.id.startsWith(messageId))\n blocks.push(...merged)\n }\n }\n }\n\n return blocks\n}\n","import React from \"react\"\nimport { Box, Text } from \"ink\"\nimport BigText from \"ink-big-text\"\nimport Gradient from \"ink-gradient\"\nimport { Header } from \"./Header.js\"\nimport { formatContentBlock } from \"../lib/formatContentBlock.js\"\nimport { type StaticItem } from \"./SessionRunner.types.js\"\n\n/** Render a static item (header, session header, or content block). */\nexport const renderStaticItem = (\n /** The static item to render */\n item: StaticItem,\n): React.ReactNode => {\n if (item.type === \"header\") {\n return <Header claudeVersion={item.claudeVersion} ralphVersion={item.ralphVersion} />\n }\n if (item.type === \"session\") {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Gradient colors={[\"#30A6E4\", \"#EBC635\"]}>\n <BigText text={`R${item.session}`} font=\"tiny\" />\n </Gradient>\n {item.sessionId && (\n <>\n <Text dimColor>session {item.sessionId.slice(0, 8)}</Text>\n <Text> </Text>\n </>\n )}\n </Box>\n )\n }\n // Content block\n const lines = formatContentBlock(item.block)\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n {lines.map((line, i) => (\n <Text key={i}>{line || \" \"}</Text>\n ))}\n </Box>\n )\n}\n","import React from \"react\"\nimport { Box, Text } from \"ink\"\nimport BigText from \"ink-big-text\"\nimport Gradient from \"ink-gradient\"\n\n/** Display the Ralph header with version information and branding. */\nexport const Header = ({\n /** The Claude CLI version */\n claudeVersion,\n /** The Ralph version */\n ralphVersion,\n /** Optional box width */\n width,\n}: Props) => {\n return (\n <Box\n flexDirection=\"column\"\n marginBottom={1}\n borderStyle=\"single\"\n alignItems=\"center\"\n width={width}\n paddingX={2}\n >\n <Gradient colors={[\"#30A6E4\", \"#EBC635\"]}>\n <BigText text=\"Ralph\" font=\"tiny\" />\n </Gradient>\n <Text dimColor>\n @herbcaudill/ralph v{ralphVersion} • Claude Code v{claudeVersion}\n </Text>\n </Box>\n )\n}\n\ntype Props = {\n claudeVersion: string\n ralphVersion: string\n width?: number\n}\n","import chalk from \"chalk\"\n\n/** Format a text string with markdown-style formatting (bold and inline code) */\nexport const formatText = (\n /** The content to format */\n content: string,\n): string => {\n let result = \"\"\n let i = 0\n let inBold = false\n let inCode = false\n\n while (i < content.length) {\n if (content[i] === \"*\" && content[i + 1] === \"*\") {\n inBold = !inBold\n i += 2\n } else if (content[i] === \"`\") {\n inCode = !inCode\n i++\n } else {\n let char = content[i]\n\n if (inCode) {\n char = chalk.yellow(char)\n } else if (inBold) {\n char = chalk.bold(char)\n }\n\n result += char\n i++\n }\n }\n\n return result\n}\n","import chalk from \"chalk\"\n\n/** Format a tool use block as a string */\nexport const formatToolUse = (\n /** The name of the tool */\n name: string,\n /** Optional argument for the tool */\n arg?: string,\n): string => {\n const formattedName = chalk.blue(name)\n if (arg) {\n return ` ${formattedName} ${chalk.dim(arg)}`\n }\n return ` ${formattedName}`\n}\n","import chalk from \"chalk\"\n\n/** Format a user message */\nexport const formatUserMessage = (\n /** The message content to format */\n content: string,\n): string => {\n return chalk.green(content)\n}\n","import type { ContentBlock } from \"../components/eventToBlocks.js\"\nimport { formatText } from \"./formatText.js\"\nimport { formatToolUse } from \"./formatToolUse.js\"\nimport { formatUserMessage } from \"./formatUserMessage.js\"\n\n/** Convert a content block to formatted string lines */\nexport const formatContentBlock = (\n /** Content block to format */\n block: ContentBlock,\n): string[] => {\n if (block.type === \"text\") {\n const formatted = formatText(block.content)\n // Split into lines, preserving empty lines for paragraph breaks\n return formatted.split(\"\\n\")\n }\n\n if (block.type === \"user\") {\n return [formatUserMessage(block.content)]\n }\n\n return [formatToolUse(block.name, block.arg)]\n}\n","import React, { useState, useEffect } from \"react\"\nimport { Box, Text, useApp } from \"ink\"\nimport { readFileSync } from \"fs\"\nimport { EventDisplay } from \"./EventDisplay.js\"\nimport { FullScreenLayout } from \"./FullScreenLayout.js\"\nimport { useContentHeight } from \"./useContentHeight.js\"\n\nexport const ReplayLog = ({\n /** The path to the replay log file */\n filePath,\n}: Props) => {\n const { exit } = useApp()\n const [events, setEvents] = useState<Array<Record<string, unknown>>>([])\n const [error, setError] = useState<string>()\n\n /**\n * Load and parse the replay log file on mount.\n * Parses pretty-printed JSON objects separated by blank lines.\n */\n useEffect(() => {\n try {\n const content = readFileSync(filePath, \"utf-8\")\n // Log file contains pretty-printed JSON objects separated by blank lines\n const eventStrings = content.split(/\\n\\n+/).filter(s => s.trim())\n\n const parsedEvents: Array<Record<string, unknown>> = []\n for (const eventStr of eventStrings) {\n try {\n const event = JSON.parse(eventStr)\n parsedEvents.push(event)\n } catch {\n // Skip malformed entries\n }\n }\n\n setEvents(parsedEvents)\n setTimeout(() => {\n exit()\n process.exit(0)\n }, 100)\n } catch (err) {\n setError(`Failed to read replay file: ${err instanceof Error ? err.message : String(err)}`)\n setTimeout(() => {\n exit()\n process.exit(1)\n }, 100)\n }\n }, [filePath, exit])\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n const footer = <Text dimColor>Replaying: {filePath}</Text>\n const contentHeight = useContentHeight(true)\n\n return (\n <FullScreenLayout title=\"Ralph\" footer={footer}>\n <EventDisplay events={events} session={1} completedSessions={[]} height={contentHeight} />\n </FullScreenLayout>\n )\n}\n\ntype Props = {\n filePath: string\n}\n","import React, { useMemo, useState, useEffect, useRef } from \"react\"\nimport { Box, Text, useInput } from \"ink\"\nimport { formatSessionHeader } from \"../lib/formatSessionHeader.js\"\nimport { processEvents } from \"./processEvents.js\"\nimport { blocksToLines } from \"./blocksToLines.js\"\n\nexport const EventDisplay = ({ events, session, completedSessions, height }: Props) => {\n // Scroll offset from bottom (0 = at bottom, positive = scrolled up)\n const [scrollOffset, setScrollOffset] = useState(0)\n // Track if user has manually scrolled\n const userScrolledRef = useRef(false)\n // Track previous line count for auto-scroll\n const prevLineCountRef = useRef(0)\n\n // Convert all content to lines for virtual scrolling\n const allLines = useMemo(() => {\n const lines: string[] = []\n\n // Add completed sessions\n for (const completed of completedSessions) {\n lines.push(\"\")\n lines.push(\"\")\n lines.push(formatSessionHeader(completed.session))\n lines.push(\"\")\n const blocks = processEvents(completed.events)\n lines.push(...blocksToLines(blocks))\n }\n\n // Add current session\n lines.push(\"\")\n lines.push(\"\")\n lines.push(formatSessionHeader(session))\n lines.push(\"\")\n const currentBlocks = processEvents(events)\n lines.push(...blocksToLines(currentBlocks))\n\n return lines\n }, [events, session, completedSessions])\n\n // Auto-scroll to bottom when new content arrives (unless user scrolled up)\n useEffect(() => {\n if (allLines.length > prevLineCountRef.current && !userScrolledRef.current) {\n setScrollOffset(0)\n }\n prevLineCountRef.current = allLines.length\n }, [allLines.length])\n\n // Handle keyboard input for scrolling\n useInput((input, key) => {\n if (!height) return\n\n const maxOffset = Math.max(0, allLines.length - height)\n const pageSize = Math.max(1, height - 2)\n\n if (key.upArrow || input === \"k\") {\n userScrolledRef.current = true\n setScrollOffset(prev => Math.min(maxOffset, prev + 1))\n } else if (key.downArrow || input === \"j\") {\n const newOffset = Math.max(0, scrollOffset - 1)\n setScrollOffset(newOffset)\n if (newOffset === 0) {\n userScrolledRef.current = false\n }\n } else if (key.pageUp) {\n userScrolledRef.current = true\n setScrollOffset(prev => Math.min(maxOffset, prev + pageSize))\n } else if (key.pageDown) {\n const newOffset = Math.max(0, scrollOffset - pageSize)\n setScrollOffset(newOffset)\n if (newOffset === 0) {\n userScrolledRef.current = false\n }\n } else if (input === \"g\" && key.shift) {\n // Shift+G = go to bottom\n setScrollOffset(0)\n userScrolledRef.current = false\n } else if (input === \"g\") {\n // g = go to top\n userScrolledRef.current = true\n setScrollOffset(maxOffset)\n }\n })\n\n // Calculate visible lines based on scroll position\n const visibleLines = useMemo(() => {\n if (!height || allLines.length <= height) {\n return allLines\n }\n const endIndex = allLines.length - scrollOffset\n const startIndex = Math.max(0, endIndex - height)\n return allLines.slice(startIndex, endIndex)\n }, [allLines, height, scrollOffset])\n\n return (\n <Box flexDirection=\"column\">\n {visibleLines.map((line, index) => (\n <Text key={index} wrap=\"wrap\">\n {line || \" \"}\n </Text>\n ))}\n </Box>\n )\n}\n\ntype SessionEvents = {\n session: number\n events: Array<Record<string, unknown>>\n}\n\ntype Props = {\n events: Array<Record<string, unknown>>\n session: number\n completedSessions: SessionEvents[]\n height?: number\n}\n","import chalk from \"chalk\"\n\n/** Format a round header */\nexport const formatSessionHeader = (\n /** Session number to display */\n session: number,\n): string => {\n return chalk.cyan.bold(`─── Round ${session} ───`)\n}\n","import type { ContentBlock } from \"./eventToBlocks.js\"\nimport { eventToBlocks } from \"./eventToBlocks.js\"\n\n/**\n * Process raw events into content blocks.\n * With includePartialMessages: true, we receive multiple snapshots of the same message\n * as it builds up. Each snapshot may contain different parts of the message content,\n * so we need to merge them and deduplicate.\n */\nexport const processEvents = (\n /** Events to process */\n events: Array<Record<string, unknown>>,\n): ContentBlock[] => {\n // Filter to only show complete assistant messages, not streaming events\n // streaming events are incomplete and cause duplicate/disappearing content\n const assistantEvents = events.filter(event => event.type === \"assistant\")\n\n // Collect all content blocks from all snapshots of the same message\n const messageMap = new Map<string, Array<Record<string, unknown>>>()\n for (const event of assistantEvents) {\n const message = event.message as Record<string, unknown> | undefined\n const messageId = message?.id as string | undefined\n const content = message?.content as Array<Record<string, unknown>> | undefined\n\n if (messageId && content) {\n if (!messageMap.has(messageId)) {\n messageMap.set(messageId, [])\n }\n messageMap.get(messageId)!.push(...content)\n }\n }\n\n // Create merged events with deduplicated content\n const mergedEvents = Array.from(messageMap.entries()).map(([messageId, allContent]) => {\n // Deduplicate content blocks by their ID (for tool_use) or text (for text blocks)\n const seenBlocks = new Set<string>()\n const uniqueContent: Array<Record<string, unknown>> = []\n\n for (const block of allContent) {\n const blockType = block.type as string\n let blockKey: string\n\n if (blockType === \"tool_use\") {\n // Tool use blocks are unique by their ID\n blockKey = `tool:${block.id}`\n } else if (blockType === \"text\") {\n // For text blocks, check if this is a prefix of or prefixed by existing text\n // This handles incremental text updates where each snapshot has more content\n const text = block.text as string\n let isDuplicate = false\n\n for (const seenKey of seenBlocks) {\n if (seenKey.startsWith(\"text:\")) {\n const seenText = seenKey.substring(5)\n // If existing text starts with this text, or this text starts with existing,\n // keep only the longer one\n if (seenText.startsWith(text)) {\n // Existing is longer, this is a duplicate\n isDuplicate = true\n break\n } else if (text.startsWith(seenText)) {\n // This is longer, remove the old one and add this\n seenBlocks.delete(seenKey)\n // Also remove from uniqueContent\n const idx = uniqueContent.findIndex(b => b.type === \"text\" && b.text === seenText)\n if (idx >= 0) uniqueContent.splice(idx, 1)\n break\n }\n }\n }\n\n if (isDuplicate) continue\n blockKey = `text:${text}`\n } else {\n blockKey = JSON.stringify(block)\n }\n\n if (!seenBlocks.has(blockKey)) {\n seenBlocks.add(blockKey)\n uniqueContent.push(block)\n }\n }\n\n return {\n type: \"assistant\",\n message: {\n id: messageId,\n content: uniqueContent,\n },\n }\n })\n\n return mergedEvents.flatMap(event => eventToBlocks(event))\n}\n","import type { ContentBlock } from \"./eventToBlocks.js\"\nimport { formatContentBlock } from \"../lib/formatContentBlock.js\"\n\n/** Convert content blocks to lines of formatted text. */\nexport const blocksToLines = (\n /** Content blocks to convert */\n blocks: ContentBlock[],\n): string[] => {\n const lines: string[] = []\n for (const block of blocks) {\n const blockLines = formatContentBlock(block)\n lines.push(...blockLines)\n // Add blank line after each block\n lines.push(\"\")\n }\n return lines\n}\n","import React, { ReactNode } from \"react\"\nimport { Box, Text } from \"ink\"\nimport BigText from \"ink-big-text\"\nimport Gradient from \"ink-gradient\"\nimport { useTerminalSize } from \"../lib/useTerminalSize.js\"\nimport { useContentHeight, HEADER_HEIGHT, FOOTER_HEIGHT } from \"./useContentHeight.js\"\n\n/** Full-screen layout component with header, content area, and optional footer */\nexport const FullScreenLayout = ({ title, children, footer, version }: Props) => {\n const { columns, rows } = useTerminalSize()\n const contentHeight = useContentHeight(!!footer)\n\n return (\n <Box\n flexDirection=\"column\"\n width={columns}\n height={rows}\n borderStyle=\"round\"\n borderColor=\"gray\"\n >\n {/* Header section */}\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n justifyContent=\"center\"\n height={HEADER_HEIGHT}\n borderStyle=\"single\"\n borderTop={false}\n borderLeft={false}\n borderRight={false}\n borderColor=\"gray\"\n >\n <Gradient colors={[\"#30A6E4\", \"#EBC635\"]}>\n <BigText text={title} font=\"tiny\" />\n </Gradient>\n </Box>\n\n {/* Content section */}\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n paddingX={1}\n height={contentHeight}\n overflowY=\"hidden\"\n >\n {children}\n </Box>\n\n {/* Footer section */}\n {footer && (\n <Box\n paddingX={1}\n height={FOOTER_HEIGHT}\n borderStyle=\"single\"\n borderTop\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor=\"gray\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n >\n <Box>{footer}</Box>\n {version && <Text dimColor>{version}</Text>}\n </Box>\n )}\n </Box>\n )\n}\n\ntype Props = {\n /** Title text displayed in the header */\n title: string\n /** Content to render in the main area */\n children: ReactNode\n /** Optional footer content */\n footer?: ReactNode\n /** Optional version string displayed in the footer */\n version?: string\n}\n","import { useTerminalSize } from \"../lib/useTerminalSize.js\"\n\n/** BigText \"tiny\" font takes 4 rows, plus 1 for separator */\nexport const HEADER_HEIGHT = 5\n\n/** Separator plus content row */\nexport const FOOTER_HEIGHT = 2\n\n/** Top and bottom borders */\nconst BORDER_HEIGHT = 2\n\n/** Calculate the available content height based on terminal size */\nexport const useContentHeight = (\n /** Whether the layout includes a footer */\n hasFooter: boolean = true,\n): number => {\n const { rows } = useTerminalSize()\n const footerHeight = hasFooter ? FOOTER_HEIGHT : 0\n return Math.max(1, rows - HEADER_HEIGHT - footerHeight - BORDER_HEIGHT)\n}\n","import React, { useState, useEffect, useRef } from \"react\"\nimport { useApp, Text } from \"ink\"\nimport { readFileSync, existsSync } from \"fs\"\nimport { join, basename } from \"path\"\nimport { query, type SDKMessage } from \"@anthropic-ai/claude-agent-sdk\"\nimport { MessageQueue, createUserMessage } from \"../lib/MessageQueue.js\"\nimport { getProgress } from \"../lib/getProgress.js\"\nimport { captureStartupSnapshot } from \"../lib/captureStartupSnapshot.js\"\nimport type { StartupSnapshot } from \"../lib/types.js\"\nimport { createDebugLogger } from \"../lib/debug.js\"\nimport { createStdinCommandHandler } from \"../lib/createStdinCommandHandler.js\"\nimport { parseTaskLifecycleEvent } from \"../lib/parseTaskLifecycle.js\"\nimport { getPromptContent } from \"../lib/getPromptContent.js\"\nimport { outputEvent } from \"../lib/outputEvent.js\"\n\n/** Debug logger for session lifecycle events */\nconst log = createDebugLogger(\"session\")\n\n/** Path to the todo.md file in the .ralph directory */\nconst todoFile = join(process.cwd(), \".ralph\", \"todo.md\")\n\n/** Name of the current repository */\nconst repoName = basename(process.cwd())\n\n/**\n * Component that runs Claude Agent SDK sessions in JSON output mode.\n * Manages message queues, task lifecycle tracking, pause/resume, and\n * streams SDK events to stdout as newline-delimited JSON.\n */\nexport const JsonOutput = ({ totalSessions, agent }: Props) => {\n const { exit } = useApp()\n const [currentSession, setCurrentSession] = useState(1)\n const [error, setError] = useState<string>()\n const [isRunning, setIsRunning] = useState(false)\n const [startupSnapshot] = useState<StartupSnapshot | undefined>(() => captureStartupSnapshot())\n const messageQueueRef = useRef<MessageQueue | null>(null)\n const [stopAfterCurrent, setStopAfterCurrent] = useState(false) // Stop gracefully after current session\n const stopAfterCurrentRef = useRef(false) // Ref to access in async callbacks\n const [isPaused, setIsPaused] = useState(false) // Pause after current session completes\n const isPausedRef = useRef(false) // Ref to access in async callbacks\n const stdinCleanupRef = useRef<(() => void) | null>(null)\n const currentTaskIdRef = useRef<string | null>(null)\n const sessionIdRef = useRef<string | null>(null)\n\n // Keep stopAfterCurrent ref in sync with state\n useEffect(() => {\n stopAfterCurrentRef.current = stopAfterCurrent\n }, [stopAfterCurrent])\n\n // Keep isPaused ref in sync with state\n useEffect(() => {\n isPausedRef.current = isPaused\n }, [isPaused])\n\n // Set up stdin command handler for receiving commands via piped input\n useEffect(() => {\n const cleanup = createStdinCommandHandler(() => ({\n messageQueue: messageQueueRef.current,\n onStop: () => {\n setStopAfterCurrent(true)\n outputEvent({ type: \"ralph_stop_requested\" })\n },\n onPause: () => {\n setIsPaused(true)\n outputEvent({ type: \"ralph_pause_requested\" })\n },\n onResume: () => {\n const wasPaused = isPausedRef.current\n setIsPaused(false)\n outputEvent({ type: \"ralph_resumed\" })\n // If we were paused between sessions, trigger the next session\n if (wasPaused && !isRunning) {\n setTimeout(() => setCurrentSession(i => i + 1), 100)\n }\n },\n onMessage: (text: string) => {\n // Output event showing we received a message command\n outputEvent({\n type: \"ralph_message_received\",\n text: text.slice(0, 100) + (text.length > 100 ? \"...\" : \"\"),\n })\n },\n }))\n stdinCleanupRef.current = cleanup\n\n return () => {\n cleanup()\n stdinCleanupRef.current = null\n }\n }, [])\n\n useEffect(() => {\n if (currentSession > totalSessions) {\n outputEvent({ type: \"ralph_exit\", reason: \"max_sessions\" })\n exit()\n return\n }\n\n // Check if there are any tasks available before starting a round\n const currentProgress =\n startupSnapshot ?\n getProgress(startupSnapshot.initialCount, startupSnapshot.timestamp)\n : { type: \"none\" as const, completed: 0, total: 0 }\n\n // All tasks are complete when completed equals total\n if (currentProgress.completed >= currentProgress.total && currentProgress.type !== \"none\") {\n outputEvent({ type: \"ralph_exit\", reason: \"all_tasks_complete\" })\n exit()\n process.exit(0)\n return\n }\n\n // Read prompt (from .ralph/prompt.md or falling back to templates)\n const promptContent = getPromptContent()\n const todoExists = existsSync(todoFile)\n const todoContent = todoExists ? readFileSync(todoFile, \"utf-8\") : \"\"\n const fullPrompt =\n todoContent ? `${promptContent}\\n\\n## Current Todo List\\n\\n${todoContent}` : promptContent\n\n const abortController = new AbortController()\n setIsRunning(true)\n\n // Session ID will be set from the SDK init message\n sessionIdRef.current = null\n\n // Create a message queue for this session\n const messageQueue = new MessageQueue()\n messageQueueRef.current = messageQueue\n\n // Push the initial prompt as the first message\n messageQueue.push(createUserMessage(fullPrompt))\n\n const runQuery = async () => {\n let finalResult = \"\"\n log(`Starting session ${currentSession}`)\n\n try {\n log(`Beginning query() loop`)\n for await (const message of query({\n prompt: messageQueue,\n options: {\n abortController,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n includePartialMessages: false, // Only complete messages for JSON output\n env: {\n ...process.env,\n // Disable LSP plugins to avoid crashes when TypeScript LSP server errors\n ENABLE_LSP_TOOL: \"0\",\n },\n },\n })) {\n log(`Received message type: ${message.type}`)\n\n // Extract session_id from the SDK init message\n if (\n !sessionIdRef.current &&\n message.type === \"system\" &&\n \"session_id\" in message &&\n typeof message.session_id === \"string\"\n ) {\n sessionIdRef.current = message.session_id\n // Emit session start event now that we have the SDK session ID\n outputEvent({\n type: \"ralph_session_start\",\n session: currentSession,\n totalSessions,\n repo: repoName,\n taskId: currentTaskIdRef.current,\n sessionId: message.session_id,\n })\n }\n\n // Output the raw SDK message as JSON\n outputEvent(message as unknown as Record<string, unknown>)\n\n // Check for task lifecycle events in assistant messages\n if (message.type === \"assistant\") {\n const assistantMessage = message.message as Record<string, unknown> | undefined\n const content = assistantMessage?.content as Array<Record<string, unknown>> | undefined\n if (content) {\n for (const block of content) {\n if (block.type === \"text\" && typeof block.text === \"string\") {\n const taskInfo = parseTaskLifecycleEvent(block.text)\n if (taskInfo) {\n if (taskInfo.action === \"starting\") {\n currentTaskIdRef.current = taskInfo.taskId ?? null\n log(`Task started: ${taskInfo.taskId}`)\n // Emit ralph_task_started event\n outputEvent({\n type: \"ralph_task_started\",\n taskId: taskInfo.taskId,\n session: currentSession,\n sessionId: sessionIdRef.current,\n })\n } else if (taskInfo.action === \"completed\") {\n log(`Task completed: ${taskInfo.taskId}`)\n // Emit ralph_task_completed event\n outputEvent({\n type: \"ralph_task_completed\",\n taskId: taskInfo.taskId,\n session: currentSession,\n sessionId: sessionIdRef.current,\n })\n }\n }\n }\n }\n }\n }\n\n // Capture the final result message\n if (\n message.type === \"result\" &&\n \"result\" in message &&\n typeof message.result === \"string\"\n ) {\n log(`Received result message`)\n finalResult = message.result\n // Close the message queue immediately when we get the result.\n log(`Closing message queue on result`)\n messageQueue.close()\n }\n }\n\n log(`query() loop completed normally`)\n setIsRunning(false)\n log(`Ensuring message queue is closed`)\n messageQueue.close()\n messageQueueRef.current = null\n\n // Output session end event\n outputEvent({\n type: \"ralph_session_end\",\n session: currentSession,\n taskId: currentTaskIdRef.current,\n sessionId: sessionIdRef.current,\n })\n\n // Check for stop-after-current request\n if (stopAfterCurrentRef.current) {\n log(`Stop after current requested - exiting gracefully`)\n outputEvent({ type: \"ralph_exit\", reason: \"stop_requested\" })\n exit()\n process.exit(0)\n return\n }\n\n // Check for completion\n if (finalResult.includes(\"<promise>COMPLETE</promise>\")) {\n outputEvent({ type: \"ralph_exit\", reason: \"task_complete\" })\n exit()\n process.exit(0)\n return\n }\n\n // Check for pause request - if paused, we wait for resume via stdin\n if (isPausedRef.current) {\n log(`Paused after session ${currentSession}`)\n outputEvent({ type: \"ralph_paused\", session: currentSession })\n // Don't move to next session - the resume handler will trigger it\n return\n }\n\n // Move to next session\n setTimeout(() => setCurrentSession(i => i + 1), 500)\n } catch (err) {\n log(`query() loop error: ${err instanceof Error ? err.message : String(err)}`)\n setIsRunning(false)\n log(`Closing message queue after error`)\n messageQueue.close()\n messageQueueRef.current = null\n if (abortController.signal.aborted) {\n log(`Abort signal detected`)\n return // Intentionally aborted\n }\n const errorMsg = `Error running Claude: ${err instanceof Error ? err.message : String(err)}`\n setError(errorMsg)\n outputEvent({ type: \"ralph_error\", error: errorMsg })\n setTimeout(() => {\n exit()\n process.exit(1)\n }, 100)\n }\n }\n\n runQuery()\n\n return () => {\n log(`Cleanup: aborting and closing queue for session ${currentSession}`)\n abortController.abort()\n messageQueue.close()\n messageQueueRef.current = null\n }\n }, [currentSession, totalSessions, exit, startupSnapshot])\n\n // In JSON mode, we output to stdout, so no visual rendering needed\n // Just return an empty component (Ink requires something to render)\n if (error) {\n return <Text>{\"\"}</Text>\n }\n\n return <Text>{\"\"}</Text>\n}\n\ntype Props = {\n totalSessions: number\n agent: string\n}\n","import { createDebugLogger } from \"./debug.js\"\n\nconst log = createDebugLogger(\"stdin-command\")\n\n/**\n * Stdin command types:\n * - {\"type\": \"message\", \"text\": \"...\"} - Send a message to Claude\n * - {\"type\": \"stop\"} - Request graceful stop after current session\n * - {\"type\": \"pause\"} - Pause after current session completes\n * - {\"type\": \"resume\"} - Resume from paused state\n */\nexport type StdinCommand =\n | { type: \"message\"; text: string }\n | { type: \"stop\" }\n | { type: \"pause\" }\n | { type: \"resume\" }\n\n/**\n * Parse a JSON string into a StdinCommand.\n * Returns null if parsing fails or the command is invalid.\n */\nexport const parseStdinCommand = (\n /** The line to parse as JSON */\n line: string,\n): StdinCommand | null => {\n const trimmed = line.trim()\n if (!trimmed) return null\n\n try {\n const parsed = JSON.parse(trimmed)\n\n if (typeof parsed !== \"object\" || parsed === null) {\n log(`Invalid command - not an object: ${trimmed}`)\n return null\n }\n\n if (parsed.type === \"message\") {\n if (typeof parsed.text !== \"string\") {\n log(`Invalid message command - missing or invalid text: ${trimmed}`)\n return null\n }\n return { type: \"message\", text: parsed.text }\n }\n\n if (parsed.type === \"stop\") {\n return { type: \"stop\" }\n }\n\n if (parsed.type === \"pause\") {\n return { type: \"pause\" }\n }\n\n if (parsed.type === \"resume\") {\n return { type: \"resume\" }\n }\n\n log(`Unknown command type: ${parsed.type}`)\n return null\n } catch (err) {\n log(`Failed to parse command: ${err instanceof Error ? err.message : String(err)}`)\n return null\n }\n}\n","import { createDebugLogger } from \"./debug.js\"\nimport { MessageQueue, createUserMessage } from \"./MessageQueue.js\"\nimport { parseStdinCommand } from \"./parseStdinCommand.js\"\nimport { createInterface } from \"readline\"\n\nconst log = createDebugLogger(\"stdin-command\")\n\n/**\n * Creates a stdin command handler that reads JSON commands from stdin.\n * Returns a cleanup function to stop reading.\n *\n * Commands:\n * - {\"type\": \"message\", \"text\": \"...\"} - Send a message to Claude\n * - {\"type\": \"stop\"} - Request graceful stop after current session\n * - {\"type\": \"pause\"} - Pause after current session completes\n * - {\"type\": \"resume\"} - Resume from paused state\n */\nexport const createStdinCommandHandler = (\n /** Getter for handler options; called when a command is received */\n getOptions: () => StdinCommandHandlerOptions,\n): (() => void) => {\n // Don't set up stdin handler if stdin is a TTY (interactive mode handles input differently)\n // This handler is for piped input in JSON mode\n if (process.stdin.isTTY) {\n log(`stdin is TTY - skipping stdin command handler`)\n return () => {}\n }\n\n log(`Setting up stdin command handler`)\n\n const rl = createInterface({\n input: process.stdin,\n terminal: false,\n })\n\n const lineHandler = (line: string) => {\n const command = parseStdinCommand(line)\n if (!command) return\n\n const options = getOptions()\n log(`Received command: ${command.type}`)\n\n if (command.type === \"message\") {\n if (options.messageQueue) {\n const userMessage = createUserMessage(command.text)\n options.messageQueue.push(userMessage)\n log(`Pushed message to queue: ${command.text.slice(0, 50)}...`)\n options.onMessage?.(command.text)\n } else {\n log(`Cannot send message - no active message queue`)\n }\n } else if (command.type === \"stop\") {\n log(`Stop command received`)\n options.onStop()\n } else if (command.type === \"pause\") {\n log(`Pause command received`)\n options.onPause?.()\n } else if (command.type === \"resume\") {\n log(`Resume command received`)\n options.onResume?.()\n }\n }\n\n rl.on(\"line\", lineHandler)\n\n return () => {\n log(`Cleaning up stdin command handler`)\n rl.off(\"line\", lineHandler)\n rl.close()\n }\n}\n\n/** Options for the stdin command handler */\nexport type StdinCommandHandlerOptions = {\n /** The message queue to push user messages to, or null if not active */\n messageQueue: MessageQueue | null\n /** Callback invoked when a stop command is received */\n onStop: () => void\n /** Optional callback invoked when a pause command is received */\n onPause?: () => void\n /** Optional callback invoked when a resume command is received */\n onResume?: () => void\n /** Optional callback invoked when a user message is processed */\n onMessage?: (text: string) => void\n}\n","/** Output an event as newline-delimited JSON to stdout. */\nexport const outputEvent = (\n /** The event object to output */\n event: Record<string, unknown>,\n) => {\n process.stdout.write(JSON.stringify(event) + \"\\n\")\n}\n","import { Text, Box } from \"ink\"\nimport React, { useEffect, useState } from \"react\"\nimport { existsSync } from \"fs\"\nimport { join, dirname } from \"path\"\nimport { fileURLToPath } from \"url\"\nimport { copyTemplates } from \"../lib/copyTemplates.js\"\n\n/**\n * Initializes Ralph by copying workflow templates and agent configurations to the project.\n * Creates .ralph/workflow.md, .claude/skills/, and .claude/agents/ directories with default files.\n * Session logs are stored in ~/.local/share/ralph/agent-sessions/ralph/.\n */\nexport function InitRalph() {\n const __dirname = dirname(fileURLToPath(import.meta.url))\n const [status, setStatus] = useState<InitStatus>(\"checking\")\n const [createdFiles, setCreatedFiles] = useState<string[]>([])\n const [skippedFiles, setSkippedFiles] = useState<string[]>([])\n const [errors, setErrors] = useState<string[]>([])\n\n // Check if .ralph already exists and run initialization\n useEffect(() => {\n const ralphDir = join(process.cwd(), \".ralph\")\n const claudeDir = join(process.cwd(), \".claude\")\n\n // Check if already initialized\n if (existsSync(join(ralphDir, \"workflow.md\"))) {\n setStatus(\"exists\")\n return\n }\n\n // Run initialization\n const initialize = async () => {\n const templatesDir = join(__dirname, \"..\", \"..\", \"templates\")\n\n setStatus(\"creating\")\n\n try {\n const allCreated: string[] = []\n const allSkipped: string[] = []\n const allErrors: string[] = []\n\n // Copy workflow to .ralph/\n const ralphResult = copyTemplates(templatesDir, ralphDir, [\n { src: \"workflow.md\", dest: \"workflow.md\" },\n ])\n allCreated.push(...ralphResult.created.map(f => `.ralph/${f}`))\n allSkipped.push(...ralphResult.skipped.map(f => `.ralph/${f}`))\n allErrors.push(...ralphResult.errors)\n\n // Copy skills to .claude/skills/\n const skillsResult = copyTemplates(templatesDir, claudeDir, [\n { src: \"skills/manage-tasks/SKILL.md\", dest: \"skills/manage-tasks/SKILL.md\" },\n ])\n allCreated.push(...skillsResult.created.map(f => `.claude/${f}`))\n allSkipped.push(...skillsResult.skipped.map(f => `.claude/${f}`))\n allErrors.push(...skillsResult.errors)\n\n // Copy agents to .claude/agents/\n const agentsResult = copyTemplates(templatesDir, claudeDir, [\n { src: \"agents/make-tests.md\", dest: \"agents/make-tests.md\" },\n { src: \"agents/write-docs.md\", dest: \"agents/write-docs.md\" },\n { src: \"agents/run-tests.md\", dest: \"agents/run-tests.md\" },\n ])\n allCreated.push(...agentsResult.created.map(f => `.claude/${f}`))\n allSkipped.push(...agentsResult.skipped.map(f => `.claude/${f}`))\n allErrors.push(...agentsResult.errors)\n\n setCreatedFiles(allCreated)\n setSkippedFiles(allSkipped)\n setErrors(allErrors)\n setStatus(\"done\")\n\n // Exit after a brief delay so user can see success message\n setTimeout(() => process.exit(0), 100)\n } catch (error) {\n setErrors([`Failed to initialize: ${error}`])\n setStatus(\"done\")\n setTimeout(() => process.exit(1), 100)\n }\n }\n\n initialize()\n }, [])\n\n if (status === \"checking\") {\n return <Text>Checking directories...</Text>\n }\n\n if (status === \"exists\") {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"yellow\">Ralph is already initialized</Text>\n <Text dimColor>To reinitialize, remove the workflow first: rm .ralph/workflow.md</Text>\n </Box>\n )\n }\n\n if (status === \"creating\") {\n return <Text color=\"cyan\">Initializing ralph...</Text>\n }\n\n return (\n <Box flexDirection=\"column\">\n {createdFiles.map(file => (\n <Text key={file}>\n <Text color=\"green\">✓</Text> Created <Text dimColor>{file}</Text>\n </Text>\n ))}\n {skippedFiles.map(file => (\n <Text key={file}>\n <Text color=\"yellow\">○</Text> Skipped <Text dimColor>{file}</Text>\n <Text dimColor> (already exists)</Text>\n </Text>\n ))}\n {errors.map((error, i) => (\n <Text key={i}>\n <Text color=\"red\">✗</Text> {error}\n </Text>\n ))}\n {errors.length === 0 && (\n <>\n <Text color=\"green\">{\"\\n\"}Ralph initialized successfully!</Text>\n <Text bold>{\"\\n\"}Next steps:</Text>\n <Text>\n <Text color=\"cyan\"> 1. Edit .ralph/workflow.md</Text>\n <Text dimColor> - Customize build commands for your project</Text>\n </Text>\n <Text>\n <Text color=\"cyan\"> 2. Initialize beads</Text>\n <Text dimColor> - Run `bd init` to set up the issue tracker</Text>\n </Text>\n <Text>\n <Text color=\"cyan\"> 3. Create issues</Text>\n <Text dimColor> - Run `bd create --title=\"...\" --type=task` to add work</Text>\n </Text>\n <Text>\n <Text bold>{\"\\n\"}Then run: </Text>\n <Text color=\"cyan\">ralph</Text>\n {\"\\n\"}\n </Text>\n </>\n )}\n </Box>\n )\n}\n\ntype InitStatus = \"checking\" | \"exists\" | \"creating\" | \"done\"\n","import { existsSync, mkdirSync, copyFileSync } from \"fs\"\nimport { join, dirname } from \"path\"\n\n/** Copy files from templates to destination, creating directories as needed. */\nexport function copyTemplates(\n /** Directory containing template files */\n templatesDir: string,\n /** Destination directory for copied files */\n destDir: string,\n /** Array of source and destination path pairs */\n files: Array<{ src: string; dest: string }>,\n): CopyResult {\n const result: CopyResult = { created: [], skipped: [], errors: [] }\n\n for (const { src, dest } of files) {\n const srcPath = join(templatesDir, src)\n const destPath = join(destDir, dest)\n\n const destDirPath = dirname(destPath)\n if (!existsSync(destDirPath)) {\n mkdirSync(destDirPath, { recursive: true })\n }\n\n if (existsSync(destPath)) {\n result.skipped.push(dest)\n } else if (existsSync(srcPath)) {\n copyFileSync(srcPath, destPath)\n result.created.push(dest)\n } else {\n result.errors.push(`Template not found: ${src}`)\n }\n }\n\n return result\n}\n\n/** Result of copying template files. */\ninterface CopyResult {\n /** Files successfully created */\n created: string[]\n /** Files that already existed and were skipped */\n skipped: string[]\n /** Error messages for files that could not be copied */\n errors: string[]\n}\n","import { execSync } from \"child_process\"\n\n/**\n * Get the installed Claude CLI version by executing `claude --version`.\n * Returns the version string (e.g., \"2.1.5\") or \"unknown\" if unable to determine.\n */\nexport const getClaudeVersion = (): string => {\n try {\n const output = execSync(\"claude --version\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim()\n\n // Output format: \"2.1.5 (Claude Code)\"\n // Extract the version number\n const match = output.match(/^([\\d.]+)/)\n return match ? match[1] : \"unknown\"\n } catch {\n return \"unknown\"\n }\n}\n","import { execSync } from \"child_process\"\n\n/**\n * Get the number of open issues from beads.\n * Returns 0 if beads is not available or there are no issues.\n */\nexport const getOpenIssueCount = (): number => {\n try {\n const output = execSync(\"bd list --status=open --json\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim()\n\n const issues = JSON.parse(output)\n return Array.isArray(issues) ? issues.length : 0\n } catch {\n return 0\n }\n}\n","import { getOpenIssueCount } from \"./getOpenIssueCount.js\"\n\n/**\n * Calculate the default number of sessions based on open issues.\n * Returns 120% of open issues, with a minimum of 10 and maximum of 100.\n */\nexport const getDefaultSessions = (): number => {\n const openIssues = getOpenIssueCount()\n if (openIssues === 0) {\n return 10 // Fallback when no issues or bd not available\n }\n const calculated = Math.ceil(openIssues * 1.2)\n return Math.max(10, Math.min(100, calculated))\n}\n","import { SessionPersister, getDefaultStorageDir } from \"@herbcaudill/ralph-shared/server\"\n\n/**\n * Get the path to the most recent session log file.\n * Returns undefined if no session logs exist.\n */\nexport const getLatestLogFile = (): string | undefined => {\n const persister = new SessionPersister(getDefaultStorageDir())\n const latestId = persister.getLatestSessionId(\"ralph\")\n if (!latestId) return undefined\n return persister.getSessionPath(latestId, \"ralph\")\n}\n","{\n \"name\": \"@herbcaudill/ralph\",\n \"version\": \"1.2.0\",\n \"description\": \"Autonomous AI session engine for Claude CLI\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"ralph\": \"./bin/ralph.js\"\n },\n \"files\": [\n \"dist\",\n \"bin\",\n \"templates\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsc --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"ralph\": \"tsx src/index.ts\",\n \"test\": \"vitest run\",\n \"test:pw\": \"vitest --config vitest.e2e.config.ts\",\n \"test:watch\": \"vitest --watch\",\n \"test:ui\": \"vitest --ui\",\n \"format\": \"prettier --write . --log-level silent\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"claude\",\n \"ai\",\n \"automation\",\n \"cli\",\n \"session\",\n \"autonomous\"\n ],\n \"author\": \"Herb Caudill\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/HerbCaudill/ralph.git\"\n },\n \"dependencies\": {\n \"@anthropic-ai/claude-agent-sdk\": \"^0.2.29\",\n \"chalk\": \"^5.6.2\",\n \"commander\": \"^14.0.2\",\n \"ink\": \"^6.6.0\",\n \"ink-big-text\": \"^2.0.0\",\n \"ink-gradient\": \"^3.0.0\",\n \"ink-select-input\": \"^6.2.0\",\n \"ink-spinner\": \"^5.0.0\",\n \"ink-text-input\": \"^6.0.0\",\n \"react\": \"^19.2.3\"\n },\n \"devDependencies\": {\n \"@herbcaudill/beads-sdk\": \"link:../../../beads-sdk\",\n \"@herbcaudill/ralph-shared\": \"workspace:*\",\n \"@types/node\": \"^24.10.1\",\n \"@types/react\": \"^19.2.8\",\n \"@vitest/ui\": \"^4.0.17\",\n \"execa\": \"^9.6.1\",\n \"ink-testing-library\": \"^4.0.0\",\n \"prettier\": \"^3.5.3\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"~5.9.3\",\n \"vitest\": \"^4.0.17\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n }\n}\n","import { program } from \"./cli.js\"\n\n/** Parse and execute the CLI program with command-line arguments. */\nexport const run = () => {\n program.parse(process.argv)\n}\n\n/** Run if called directly as a script. */\nif (import.meta.url === `file://${process.argv[1]}`) {\n run()\n}\n"],"mappings":"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","names":["React","React","React","useState","useEffect","Box","Text","useInput","readFileSync","existsSync","mkdirSync","join","join","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","join","execSync","readFileSync","join","join","ralphDir","todoFile","existsSync","existsSync","join","execSync","readFileSync","join","ralphDir","todoFile","beadsDir","join","ralphDir","todoFile","existsSync","React","Text","repoName","join","existsSync","resolve","resolve","useState","useEffect","useState","useEffect","existsSync","readFileSync","join","dirname","fileURLToPath","existsSync","readFileSync","mkdirSync","join","dirname","existsSync","join","existsSync","readFileSync","hasCustomWorkflow","dirname","join","dirname","fileURLToPath","ralphDir","join","existsSync","readFileSync","message","content","messageId","query","React","Box","Text","BigText","Gradient","React","Text","chalk","chalk","chalk","React","Box","Gradient","BigText","Text","log","ralphDir","join","todoFile","useState","useInput","useEffect","existsSync","readFileSync","mkdirSync","React","Box","Text","React","useState","useEffect","Box","Text","useApp","readFileSync","React","useState","useEffect","useRef","Box","Text","useInput","chalk","processEvents","useState","useRef","processEvents","useEffect","useInput","React","Box","Text","React","Box","Text","BigText","Gradient","React","Box","Gradient","BigText","Text","useApp","useState","useEffect","readFileSync","React","Box","Text","React","useState","useEffect","useRef","useApp","Text","readFileSync","existsSync","join","basename","query","log","log","log","todoFile","join","repoName","basename","useApp","useState","useRef","useEffect","existsSync","readFileSync","query","React","Text","React","Text","Box","React","useEffect","useState","existsSync","join","dirname","fileURLToPath","existsSync","mkdirSync","copyFileSync","join","dirname","dirname","fileURLToPath","useState","useEffect","ralphDir","join","existsSync","React","Text","Box","execSync","execSync","React","resolve"]}