mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 15:09:42 +02:00
refactor: rename inner-loop-tracker to ralph-tracker with API improvements
- Rename inner-loop-tracker.ts → ralph-tracker.ts throughout codebase - Add ralph-config.ts for parsing .claude/ralph-loop.local.md config - Standardize API error responses using createErrorResponse() - Add input validation for auto-compact/auto-clear thresholds - Update UI labels to "Ralph / Todo Tracker" consistently - Add 46 integration tests for Ralph tracking functionality - Update test badge to 438 total tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+6
-6
@@ -9,7 +9,7 @@
|
||||
* - **Main view**: Active session management with:
|
||||
* - TabBar: Session tabs with switching
|
||||
* - TerminalView: Live terminal output display
|
||||
* - RalphPanel: Inner loop tracking (conditional)
|
||||
* - RalphPanel: Ralph loop tracking (conditional)
|
||||
* - StatusBar: Session info and keyboard hints
|
||||
*
|
||||
* Keyboard shortcuts are handled globally via Ink's useInput hook.
|
||||
@@ -116,8 +116,8 @@ export function App(): React.ReactElement {
|
||||
prevSession,
|
||||
sendInput,
|
||||
terminalOutput,
|
||||
innerLoopState,
|
||||
innerTodos,
|
||||
ralphLoopState,
|
||||
ralphTodos,
|
||||
respawnStatus,
|
||||
cases,
|
||||
lastUsedCase,
|
||||
@@ -427,7 +427,7 @@ export function App(): React.ReactElement {
|
||||
}
|
||||
|
||||
// Check if Ralph panel should be visible (enabled and has data)
|
||||
const showRalphPanel = innerLoopState?.enabled && (innerLoopState.active || innerTodos.length > 0);
|
||||
const showRalphPanel = ralphLoopState?.enabled && (ralphLoopState.active || ralphTodos.length > 0);
|
||||
|
||||
// Adjust terminal height if Ralph panel is shown
|
||||
const adjustedTerminalHeight = showRalphPanel ? terminalHeight - 6 : terminalHeight;
|
||||
@@ -449,8 +449,8 @@ export function App(): React.ReactElement {
|
||||
|
||||
{showRalphPanel && (
|
||||
<RalphPanel
|
||||
loopState={innerLoopState}
|
||||
todos={innerTodos}
|
||||
loopState={ralphLoopState}
|
||||
todos={ralphTodos}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
* - Progress through todos with visual indicators
|
||||
* - Cycle count and elapsed time tracking
|
||||
*
|
||||
* @see {@link file://./../../inner-loop-tracker.ts} for detection logic
|
||||
* @see {@link file://./../../ralph-tracker.ts} for detection logic
|
||||
* @see {@link file://./../../../docs/ralph-wiggum-guide.md} for full documentation
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import type { InnerLoopState, InnerTodoItem } from '../../types.js';
|
||||
import type { RalphTrackerState, RalphTodoItem } from '../../types.js';
|
||||
|
||||
interface RalphPanelProps {
|
||||
loopState: InnerLoopState | null;
|
||||
todos: InnerTodoItem[];
|
||||
loopState: RalphTrackerState | null;
|
||||
todos: RalphTodoItem[];
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ function formatElapsed(hours: number | null): string {
|
||||
* Only renders when loop is enabled and has relevant data to show.
|
||||
*
|
||||
* @param props - Component props
|
||||
* @param props.loopState - Current loop state from InnerLoopTracker
|
||||
* @param props.loopState - Current loop state from RalphTracker
|
||||
* @param props.todos - Array of todo items being tracked
|
||||
* @param props.visible - Whether the panel should be visible (default: true)
|
||||
* @returns The panel element or null if hidden/disabled
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* This hook provides a complete interface for managing Claude sessions:
|
||||
* - Session discovery from ~/.claudeman/screens.json
|
||||
* - Terminal output polling via GNU screen hardcopy
|
||||
* - Inner loop state tracking for Ralph Wiggum loops
|
||||
* - Ralph state tracking for Ralph Wiggum loops
|
||||
* - Respawn status monitoring via the Claudeman API
|
||||
*
|
||||
* @example
|
||||
@@ -29,12 +29,12 @@ import { homedir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { execSync, exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import type { ScreenSession, InnerLoopState, InnerTodoItem, InnerSessionState } from '../../types.js';
|
||||
import type { ScreenSession, RalphTrackerState, RalphTodoItem, RalphSessionState } from '../../types.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
const SCREENS_FILE = join(homedir(), '.claudeman', 'screens.json');
|
||||
const INNER_STATE_FILE = join(homedir(), '.claudeman', 'state-inner.json');
|
||||
const RALPH_STATE_FILE = join(homedir(), '.claudeman', 'state-inner.json');
|
||||
const SETTINGS_FILE = join(homedir(), '.claudeman', 'settings.json');
|
||||
const OUTPUT_POLL_INTERVAL = 300; // Poll terminal output every 300ms (faster refresh)
|
||||
|
||||
@@ -149,8 +149,8 @@ interface SessionManagerState {
|
||||
activeSessionId: string | null;
|
||||
activeSession: ScreenSession | null;
|
||||
terminalOutput: string;
|
||||
innerLoopState: InnerLoopState | null;
|
||||
innerTodos: InnerTodoItem[];
|
||||
ralphLoopState: RalphTrackerState | null;
|
||||
ralphTodos: RalphTodoItem[];
|
||||
respawnStatus: RespawnStatus | null;
|
||||
cases: CaseInfo[];
|
||||
lastUsedCase: string | null;
|
||||
@@ -237,18 +237,18 @@ function loadSessions(): ScreenSession[] {
|
||||
*
|
||||
* @description
|
||||
* Reads ~/.claudeman/state-inner.json which contains per-session
|
||||
* tracking of inner loops, todos, and completion phrases.
|
||||
* tracking of Ralph loops, todos, and completion phrases.
|
||||
*
|
||||
* @param sessionId - The UUID of the session to load state for
|
||||
* @returns The inner session state or null if not found
|
||||
* @returns The Ralph session state or null if not found
|
||||
*/
|
||||
function loadInnerState(sessionId: string): InnerSessionState | null {
|
||||
function loadRalphState(sessionId: string): RalphSessionState | null {
|
||||
try {
|
||||
if (!existsSync(INNER_STATE_FILE)) {
|
||||
if (!existsSync(RALPH_STATE_FILE)) {
|
||||
return null;
|
||||
}
|
||||
const data = readFileSync(INNER_STATE_FILE, 'utf-8');
|
||||
const allStates = JSON.parse(data) as Record<string, InnerSessionState>;
|
||||
const data = readFileSync(RALPH_STATE_FILE, 'utf-8');
|
||||
const allStates = JSON.parse(data) as Record<string, RalphSessionState>;
|
||||
return allStates[sessionId] || null;
|
||||
} catch {
|
||||
return null;
|
||||
@@ -284,7 +284,7 @@ function loadLastUsedCase(): string | null {
|
||||
* Provides complete session lifecycle management:
|
||||
* - Automatic session discovery and status monitoring
|
||||
* - Terminal output polling (500ms interval)
|
||||
* - Inner loop state tracking (500ms interval)
|
||||
* - Ralph state tracking (500ms interval)
|
||||
* - Respawn status polling via API (2000ms interval)
|
||||
* - Session CRUD operations via Claudeman API
|
||||
*
|
||||
@@ -311,8 +311,8 @@ export function useSessionManager(): SessionManagerState {
|
||||
const [sessions, setSessions] = useState<ScreenSession[]>([]);
|
||||
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
|
||||
const [terminalOutput, setTerminalOutput] = useState<string>('');
|
||||
const [innerLoopState, setInnerLoopState] = useState<InnerLoopState | null>(null);
|
||||
const [innerTodos, setInnerTodos] = useState<InnerTodoItem[]>([]);
|
||||
const [ralphLoopState, setRalphTrackerState] = useState<RalphTrackerState | null>(null);
|
||||
const [ralphTodos, setInnerTodos] = useState<RalphTodoItem[]>([]);
|
||||
const [respawnStatus, setRespawnStatus] = useState<RespawnStatus | null>(null);
|
||||
const [cases, setCases] = useState<CaseInfo[]>([]);
|
||||
const [lastUsedCase, setLastUsedCase] = useState<string | null>(loadLastUsedCase);
|
||||
@@ -346,30 +346,30 @@ export function useSessionManager(): SessionManagerState {
|
||||
// Get active session
|
||||
const activeSession = sessions.find((s) => s.sessionId === activeSessionId) || null;
|
||||
|
||||
// Poll inner state for active session
|
||||
// Poll Ralph state for active session
|
||||
useEffect(() => {
|
||||
if (!activeSessionId) {
|
||||
setInnerLoopState(null);
|
||||
setRalphTrackerState(null);
|
||||
setInnerTodos([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const pollInnerState = () => {
|
||||
const state = loadInnerState(activeSessionId);
|
||||
const pollRalphState = () => {
|
||||
const state = loadRalphState(activeSessionId);
|
||||
if (state) {
|
||||
setInnerLoopState(state.loop);
|
||||
setRalphTrackerState(state.loop);
|
||||
setInnerTodos(state.todos);
|
||||
} else {
|
||||
setInnerLoopState(null);
|
||||
setRalphTrackerState(null);
|
||||
setInnerTodos([]);
|
||||
}
|
||||
};
|
||||
|
||||
// Initial poll
|
||||
pollInnerState();
|
||||
pollRalphState();
|
||||
|
||||
// Set up polling interval (same as output polling)
|
||||
const intervalId = setInterval(pollInnerState, OUTPUT_POLL_INTERVAL);
|
||||
const intervalId = setInterval(pollRalphState, OUTPUT_POLL_INTERVAL);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
@@ -809,8 +809,8 @@ export function useSessionManager(): SessionManagerState {
|
||||
activeSessionId,
|
||||
activeSession,
|
||||
terminalOutput,
|
||||
innerLoopState,
|
||||
innerTodos,
|
||||
ralphLoopState,
|
||||
ralphTodos,
|
||||
respawnStatus,
|
||||
cases,
|
||||
lastUsedCase,
|
||||
|
||||
Reference in New Issue
Block a user