feat: add ecc2 dashboard quick-spawn action

This commit is contained in:
Affaan Mustafa
2026-04-07 11:53:31 -07:00
parent 2146619845
commit 52fc93180b
2 changed files with 89 additions and 3 deletions

View File

@@ -38,7 +38,7 @@ pub async fn run(db: StateStore, cfg: Config) -> Result<()> {
(_, KeyCode::Char('-')) => dashboard.decrease_pane_size(), (_, KeyCode::Char('-')) => dashboard.decrease_pane_size(),
(_, KeyCode::Char('j')) | (_, KeyCode::Down) => dashboard.scroll_down(), (_, KeyCode::Char('j')) | (_, KeyCode::Down) => dashboard.scroll_down(),
(_, KeyCode::Char('k')) | (_, KeyCode::Up) => dashboard.scroll_up(), (_, KeyCode::Char('k')) | (_, KeyCode::Up) => dashboard.scroll_up(),
(_, KeyCode::Char('n')) => dashboard.new_session(), (_, KeyCode::Char('n')) => dashboard.new_session().await,
(_, KeyCode::Char('s')) => dashboard.stop_selected().await, (_, KeyCode::Char('s')) => dashboard.stop_selected().await,
(_, KeyCode::Char('u')) => dashboard.resume_selected().await, (_, KeyCode::Char('u')) => dashboard.resume_selected().await,
(_, KeyCode::Char('x')) => dashboard.cleanup_selected_worktree().await, (_, KeyCode::Char('x')) => dashboard.cleanup_selected_worktree().await,

View File

@@ -504,8 +504,32 @@ impl Dashboard {
} }
} }
pub fn new_session(&mut self) { pub async fn new_session(&mut self) {
tracing::info!("New session dialog requested"); if self.active_session_count() >= self.cfg.max_parallel_sessions {
tracing::warn!(
"Cannot queue new session: active session limit reached ({})",
self.cfg.max_parallel_sessions
);
return;
}
let task = self.new_session_task();
let agent = self.cfg.default_agent.clone();
let session_id = match manager::create_session(&self.db, &self.cfg, &task, &agent, true).await {
Ok(session_id) => session_id,
Err(error) => {
tracing::warn!("Failed to create new session from dashboard: {error}");
return;
}
};
self.refresh();
self.sync_selection_by_id(Some(&session_id));
self.reset_output_view();
self.sync_selected_output();
self.sync_selected_diff();
self.refresh_logs();
} }
pub async fn stop_selected(&mut self) { pub async fn stop_selected(&mut self) {
@@ -814,6 +838,31 @@ impl Dashboard {
.collect() .collect()
} }
fn active_session_count(&self) -> usize {
self.sessions
.iter()
.filter(|session| {
matches!(
session.state,
SessionState::Pending | SessionState::Running | SessionState::Idle
)
})
.count()
}
fn new_session_task(&self) -> String {
self.sessions
.get(self.selected_session)
.map(|session| {
format!(
"Follow up on {}: {}",
format_session_id(&session.id),
truncate_for_dashboard(&session.task, 96)
)
})
.unwrap_or_else(|| "New ECC 2.0 session".to_string())
}
fn pane_areas(&self, area: Rect) -> PaneAreas { fn pane_areas(&self, area: Rect) -> PaneAreas {
match self.cfg.pane_layout { match self.cfg.pane_layout {
PaneLayout::Horizontal => { PaneLayout::Horizontal => {
@@ -1199,6 +1248,43 @@ mod tests {
); );
} }
#[test]
fn new_session_task_uses_selected_session_context() {
let dashboard = test_dashboard(
vec![sample_session(
"focus-12345678",
"planner",
SessionState::Running,
Some("ecc/focus"),
512,
42,
)],
0,
);
assert_eq!(
dashboard.new_session_task(),
"Follow up on focus-12: Render dashboard rows"
);
}
#[test]
fn active_session_count_only_counts_live_queue_states() {
let dashboard = test_dashboard(
vec![
sample_session("pending-1", "planner", SessionState::Pending, None, 1, 1),
sample_session("running-1", "planner", SessionState::Running, None, 1, 1),
sample_session("idle-1", "planner", SessionState::Idle, None, 1, 1),
sample_session("failed-1", "planner", SessionState::Failed, None, 1, 1),
sample_session("stopped-1", "planner", SessionState::Stopped, None, 1, 1),
sample_session("done-1", "planner", SessionState::Completed, None, 1, 1),
],
0,
);
assert_eq!(dashboard.active_session_count(), 3);
}
#[test] #[test]
fn refresh_preserves_selected_session_by_id() -> Result<()> { fn refresh_preserves_selected_session_by_id() -> Result<()> {
let db_path = std::env::temp_dir().join(format!("ecc2-dashboard-{}.db", Uuid::new_v4())); let db_path = std::env::temp_dir().join(format!("ecc2-dashboard-{}.db", Uuid::new_v4()));