mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
feat(tui): integrate RalphPanel with live state polling
- Poll inner loop state from state-inner.json every 500ms - Display RalphPanel when loop is enabled and has data - Auto-adjust terminal height when panel is shown - Add innerLoopState and innerTodos to session manager hook Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+18
-2
@@ -14,6 +14,7 @@ import { TabBar } from './components/TabBar.js';
|
|||||||
import { TerminalView } from './components/TerminalView.js';
|
import { TerminalView } from './components/TerminalView.js';
|
||||||
import { StatusBar } from './components/StatusBar.js';
|
import { StatusBar } from './components/StatusBar.js';
|
||||||
import { HelpOverlay } from './components/HelpOverlay.js';
|
import { HelpOverlay } from './components/HelpOverlay.js';
|
||||||
|
import { RalphPanel } from './components/RalphPanel.js';
|
||||||
import { useSessionManager } from './hooks/useSessionManager.js';
|
import { useSessionManager } from './hooks/useSessionManager.js';
|
||||||
import type { ScreenSession } from '../types.js';
|
import type { ScreenSession } from '../types.js';
|
||||||
|
|
||||||
@@ -42,6 +43,8 @@ export function App(): React.ReactElement {
|
|||||||
prevSession,
|
prevSession,
|
||||||
sendInput,
|
sendInput,
|
||||||
terminalOutput,
|
terminalOutput,
|
||||||
|
innerLoopState,
|
||||||
|
innerTodos,
|
||||||
} = useSessionManager();
|
} = useSessionManager();
|
||||||
|
|
||||||
// Calculate terminal height based on stdout dimensions
|
// Calculate terminal height based on stdout dimensions
|
||||||
@@ -224,7 +227,13 @@ export function App(): React.ReactElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render main view with tabs, terminal, and status bar
|
// Check if Ralph panel should be visible (enabled and has data)
|
||||||
|
const showRalphPanel = innerLoopState?.enabled && (innerLoopState.active || innerTodos.length > 0);
|
||||||
|
|
||||||
|
// Adjust terminal height if Ralph panel is shown
|
||||||
|
const adjustedTerminalHeight = showRalphPanel ? terminalHeight - 6 : terminalHeight;
|
||||||
|
|
||||||
|
// Render main view with tabs, terminal, ralph panel, and status bar
|
||||||
return (
|
return (
|
||||||
<Box flexDirection="column" height="100%">
|
<Box flexDirection="column" height="100%">
|
||||||
<TabBar
|
<TabBar
|
||||||
@@ -235,10 +244,17 @@ export function App(): React.ReactElement {
|
|||||||
|
|
||||||
<TerminalView
|
<TerminalView
|
||||||
output={terminalOutput}
|
output={terminalOutput}
|
||||||
height={terminalHeight}
|
height={adjustedTerminalHeight}
|
||||||
session={activeSession}
|
session={activeSession}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{showRalphPanel && (
|
||||||
|
<RalphPanel
|
||||||
|
loopState={innerLoopState}
|
||||||
|
todos={innerTodos}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<StatusBar session={activeSession} />
|
<StatusBar session={activeSession} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ import { existsSync, readFileSync, writeFileSync, watchFile, unwatchFile, unlink
|
|||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import type { ScreenSession } from '../../types.js';
|
import type { ScreenSession, InnerLoopState, InnerTodoItem, InnerSessionState } from '../../types.js';
|
||||||
|
|
||||||
const SCREENS_FILE = join(homedir(), '.claudeman', 'screens.json');
|
const SCREENS_FILE = join(homedir(), '.claudeman', 'screens.json');
|
||||||
|
const INNER_STATE_FILE = join(homedir(), '.claudeman', 'state-inner.json');
|
||||||
const OUTPUT_POLL_INTERVAL = 500; // Poll terminal output every 500ms
|
const OUTPUT_POLL_INTERVAL = 500; // Poll terminal output every 500ms
|
||||||
|
|
||||||
interface SessionManagerState {
|
interface SessionManagerState {
|
||||||
@@ -22,6 +23,8 @@ interface SessionManagerState {
|
|||||||
activeSessionId: string | null;
|
activeSessionId: string | null;
|
||||||
activeSession: ScreenSession | null;
|
activeSession: ScreenSession | null;
|
||||||
terminalOutput: string;
|
terminalOutput: string;
|
||||||
|
innerLoopState: InnerLoopState | null;
|
||||||
|
innerTodos: InnerTodoItem[];
|
||||||
refreshSessions: () => void;
|
refreshSessions: () => void;
|
||||||
selectSession: (sessionId: string) => void;
|
selectSession: (sessionId: string) => void;
|
||||||
createSession: () => Promise<string | null>;
|
createSession: () => Promise<string | null>;
|
||||||
@@ -65,6 +68,22 @@ function loadSessions(): ScreenSession[] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load inner state for a session
|
||||||
|
*/
|
||||||
|
function loadInnerState(sessionId: string): InnerSessionState | null {
|
||||||
|
try {
|
||||||
|
if (!existsSync(INNER_STATE_FILE)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const data = readFileSync(INNER_STATE_FILE, 'utf-8');
|
||||||
|
const allStates = JSON.parse(data) as Record<string, InnerSessionState>;
|
||||||
|
return allStates[sessionId] || null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for managing sessions in the TUI
|
* Hook for managing sessions in the TUI
|
||||||
*/
|
*/
|
||||||
@@ -72,6 +91,8 @@ export function useSessionManager(): SessionManagerState {
|
|||||||
const [sessions, setSessions] = useState<ScreenSession[]>([]);
|
const [sessions, setSessions] = useState<ScreenSession[]>([]);
|
||||||
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
|
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
|
||||||
const [terminalOutput, setTerminalOutput] = useState<string>('');
|
const [terminalOutput, setTerminalOutput] = useState<string>('');
|
||||||
|
const [innerLoopState, setInnerLoopState] = useState<InnerLoopState | null>(null);
|
||||||
|
const [innerTodos, setInnerTodos] = useState<InnerTodoItem[]>([]);
|
||||||
const outputBufferRef = useRef<string>('');
|
const outputBufferRef = useRef<string>('');
|
||||||
|
|
||||||
// Load sessions on mount and watch for changes
|
// Load sessions on mount and watch for changes
|
||||||
@@ -102,6 +123,36 @@ export function useSessionManager(): SessionManagerState {
|
|||||||
// Get active session
|
// Get active session
|
||||||
const activeSession = sessions.find((s) => s.sessionId === activeSessionId) || null;
|
const activeSession = sessions.find((s) => s.sessionId === activeSessionId) || null;
|
||||||
|
|
||||||
|
// Poll inner state for active session
|
||||||
|
useEffect(() => {
|
||||||
|
if (!activeSessionId) {
|
||||||
|
setInnerLoopState(null);
|
||||||
|
setInnerTodos([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pollInnerState = () => {
|
||||||
|
const state = loadInnerState(activeSessionId);
|
||||||
|
if (state) {
|
||||||
|
setInnerLoopState(state.loop);
|
||||||
|
setInnerTodos(state.todos);
|
||||||
|
} else {
|
||||||
|
setInnerLoopState(null);
|
||||||
|
setInnerTodos([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial poll
|
||||||
|
pollInnerState();
|
||||||
|
|
||||||
|
// Set up polling interval (same as output polling)
|
||||||
|
const intervalId = setInterval(pollInnerState, OUTPUT_POLL_INTERVAL);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
};
|
||||||
|
}, [activeSessionId]);
|
||||||
|
|
||||||
// Poll terminal output for active session
|
// Poll terminal output for active session
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeSessionId || !activeSession) return;
|
if (!activeSessionId || !activeSession) return;
|
||||||
@@ -282,6 +333,8 @@ export function useSessionManager(): SessionManagerState {
|
|||||||
activeSessionId,
|
activeSessionId,
|
||||||
activeSession,
|
activeSession,
|
||||||
terminalOutput,
|
terminalOutput,
|
||||||
|
innerLoopState,
|
||||||
|
innerTodos,
|
||||||
refreshSessions,
|
refreshSessions,
|
||||||
selectSession,
|
selectSession,
|
||||||
createSession,
|
createSession,
|
||||||
|
|||||||
Reference in New Issue
Block a user