diff --git a/server/src/agents/pty.rs b/server/src/agents/pty.rs index ded825b8..d84ba647 100644 --- a/server/src/agents/pty.rs +++ b/server/src/agents/pty.rs @@ -209,7 +209,22 @@ fn run_agent_pty_blocking( cmd.env_remove("CLAUDECODE"); cmd.env_remove("CLAUDE_CODE_ENTRYPOINT"); - slog!("[agent:{story_id}:{agent_name}] Spawning {command} in {cwd} with args: {args:?}"); + // Count existing session files for this worktree to detect budget exhaustion. + let session_dir = format!( + "/home/huskies/.claude/projects/-workspace--huskies-worktrees-{}/", + story_id.replace('_', "-").replace('.', "-") + ); + let session_count = std::fs::read_dir(&session_dir) + .map(|d| d.filter(|e| e.as_ref().map(|e| e.path().extension().is_some_and(|ext| ext == "jsonl")).unwrap_or(false)).count()) + .unwrap_or(0); + let session_bytes: u64 = std::fs::read_dir(&session_dir) + .map(|d| d.filter_map(|e| e.ok()).filter(|e| e.path().extension().is_some_and(|ext| ext == "jsonl")).filter_map(|e| e.metadata().ok()).map(|m| m.len()).sum()) + .unwrap_or(0); + + slog!( + "[agent:{story_id}:{agent_name}] Spawning {command} in {cwd} with args: {args:?} \ + (prior_sessions={session_count}, session_log_bytes={session_bytes})" + ); let mut child = pair .slave @@ -429,7 +444,19 @@ fn run_agent_pty_blocking( } let _ = child.kill(); - let _ = child.wait(); + let wait_result = child.wait(); + match &wait_result { + Ok(status) => { + slog!( + "[agent:{story_id}:{agent_name}] Child exited: {status:?}" + ); + } + Err(e) => { + slog!( + "[agent:{story_id}:{agent_name}] Child wait error: {e}" + ); + } + } // Wait for the reader thread to finish so it releases the cloned PTY // master fd before we return. Without this, the next PTY spawn for the @@ -438,6 +465,17 @@ fn run_agent_pty_blocking( slog!("[agent:{story_id}:{agent_name}] Reader thread panicked: {e:?}"); } + // Log whether session was created — Session: None indicates CLI died + // before emitting any events (possible causes: rate limit, budget + // exhaustion, PTY write failure, CLI crash). + if session_id.is_none() { + slog_warn!( + "[agent:{story_id}:{agent_name}] SESSION NONE: CLI exited without creating a session. \ + Check for 'fatal runtime error' in agent logs. \ + prior_sessions={session_count}, session_log_bytes={session_bytes}" + ); + } + slog!( "[agent:{story_id}:{agent_name}] Done. Session: {:?}", session_id