use crate::VerbosityLevel;
use claude_core::process::find_claude_processes;
use std::path::PathBuf;
pub( super ) fn gate_dir() -> PathBuf
{
std::env::var( "CLR_GATE_DIR" )
.ok()
.filter( |s| !s.is_empty() )
.map_or_else( || PathBuf::from( "/tmp/clr-gate" ), PathBuf::from )
}
pub( super ) fn unix_now() -> u64
{
std::time::SystemTime::now()
.duration_since( std::time::UNIX_EPOCH )
.map_or( 0, |d| d.as_secs() )
}
struct GateFile( PathBuf );
impl Drop for GateFile
{
fn drop( &mut self )
{
let _ = std::fs::remove_file( &self.0 );
}
}
pub( super ) fn wait_for_session_slot( max : u32, verbosity : VerbosityLevel, cli : &super::parse::CliArgs )
{
if max == 0 { return; }
let poll = core::time::Duration::from_secs( 30 );
let max_attempts = 100_u32;
let pid = std::process::id();
let dir = gate_dir();
let _ = std::fs::create_dir_all( &dir );
let state_path = dir.join( format!( "{pid}.json" ) );
let cwd = std::env::current_dir()
.map( |p| p.display().to_string() )
.unwrap_or_default();
let since = unix_now();
let _ = std::fs::write(
&state_path,
format!( r#"{{"cwd":"{cwd}","since":{since},"attempt":0,"message":"waiting for session slot"}}"# ),
);
let _guard = GateFile( state_path.clone() );
let mut runner_attempt = 0u32;
loop
{
for attempt in 1..=max_attempts
{
let count = find_claude_processes().len();
if u32::try_from( count ).unwrap_or( u32::MAX ) < max
{
return; }
if attempt == max_attempts
{
let e = std::io::Error::other(
format!( "session gate timed out — {count} active sessions, max-sessions={max}" )
);
super::execution::apply_runner_retry( cli, &e, &mut runner_attempt );
break; }
if verbosity.shows_warnings()
{
eprintln!(
"Info: {count}/{max} sessions active; waiting 30s for a slot... (attempt {attempt}/{max_attempts})"
);
}
let _ = std::fs::write(
&state_path,
format!( r#"{{"cwd":"{cwd}","since":{since},"attempt":{attempt},"message":"waiting for session slot"}}"# ),
);
std::thread::sleep( poll );
}
}
}