From 207be3c771d281baae6e5fa0fb74be9a056e97a2 Mon Sep 17 00:00:00 2001 From: Can Celik Date: Tue, 1 Sep 2026 15:48:22 +0300 Subject: refactor: render the shell in the client (#3487) * feat: add opt-in client-rendered shell * feat: add client-owned shell mouse controls * feat: complete client-owned shell chrome * feat: add client-owned shell settings and notifications * feat: run client shell custom commands * feat: render popup terminals in client shell * feat: add client-owned scrollback and copy mode * fix: preserve client worktree trust defaults * feat: render startup diagnostics in client shell * feat: render onboarding in client shell * feat: render product announcements in client shell * feat: render release notes in client shell * feat: render mobile switcher in client shell * feat: render kitty graphics in client shell * fix: preserve client shell lifecycle coherence * refactor: route client shell commands through endpoint connections * refactor: make the client-rendered shell the default * refactor: remove monolithic launch mode * refactor: complete client-rendered shell cutover * perf: retain client pane surface updates * perf: scale retained pane surface updates * perf: remove remote pane input latency * test: make client shell checks platform-independent * fix: prevent client timer starvation * test: fix client shell platform gates * test: accept retained surfaces in cross-area checks * test: make client mode assertions platform-neutral * fix: badge only outdated integrations --- src/workspace/aggregate.rs | 111 ++------------------------------------------ src/workspace/git/mod.rs | 3 -- src/workspace/git/status.rs | 19 -------- src/workspace/tab.rs | 30 ------------ 4 files changed, 5 insertions(+), 158 deletions(-) (limited to 'src/workspace') diff --git a/src/workspace/aggregate.rs b/src/workspace/aggregate.rs index 29621d4d..3fd45fca 100644 --- a/src/workspace/aggregate.rs +++ b/src/workspace/aggregate.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::detect::{Agent, AgentState}; +use crate::detect::AgentState; use crate::layout::PaneId; use crate::terminal::{TerminalId, TerminalState}; @@ -10,18 +10,10 @@ use super::{Tab, Workspace}; pub struct PaneDetail { pub pane_id: PaneId, pub tab_idx: usize, - pub tab_label: String, - pub label: String, - pub pane_label: Option, - pub terminal_title: Option, - pub terminal_title_stripped: Option, - pub agent_label: String, pub agent_kind_label: Option, - pub agent: Option, pub state: AgentState, pub seen: bool, pub last_agent_state_change_seq: Option, - pub state_labels: HashMap, pub tokens: HashMap, } @@ -30,7 +22,6 @@ impl Tab { &self, terminals: &HashMap, tab_idx: usize, - tab_label: &str, ) -> Vec { self.layout .pane_ids() @@ -39,32 +30,16 @@ impl Tab { let pane = self.panes.get(id)?; let terminal = terminals.get(&pane.attached_terminal_id)?; let agent_kind_label = terminal.effective_agent_label().map(str::to_string); - let fallback_agent_label = terminal - .agent_name - .as_deref() - .or(agent_kind_label.as_deref())? - .to_string(); - let agent_label = terminal - .effective_display_agent() - .unwrap_or_else(|| fallback_agent_label.clone()); - let presentation = terminal.effective_presentation(); + if terminal.agent_name.is_none() && agent_kind_label.is_none() { + return None; + } Some(PaneDetail { pane_id: *id, tab_idx, - tab_label: tab_label.to_string(), - label: agent_label.clone(), - pane_label: terminal - .effective_title() - .or_else(|| terminal.manual_label.clone()), - terminal_title: terminal.terminal_title.clone(), - terminal_title_stripped: terminal.terminal_title_stripped(), - agent_label, agent_kind_label, - agent: terminal.effective_known_agent(), state: terminal.state, seen: pane.seen, last_agent_state_change_seq: terminal.last_agent_state_change_seq, - state_labels: presentation.state_labels, tokens: terminal.metadata_tokens.values(), }) }) @@ -100,22 +75,10 @@ impl Workspace { } pub fn pane_details(&self, terminals: &HashMap) -> Vec { - let multi_tab = self.tabs.len() > 1; self.tabs .iter() .enumerate() - .flat_map(|(tab_idx, tab)| { - let tab_label = self - .tab_display_name(tab_idx) - .unwrap_or_else(|| (tab_idx + 1).to_string()); - tab.pane_details(terminals, tab_idx, &tab_label).into_iter() - }) - .map(|mut detail| { - if multi_tab { - detail.label = format!("{}·{}", detail.tab_label, detail.agent_label); - } - detail - }) + .flat_map(|(tab_idx, tab)| tab.pane_details(terminals, tab_idx)) .collect() } } @@ -193,70 +156,6 @@ mod tests { assert!(!seen); } - #[test] - fn pane_details_prefers_agent_name_over_detected_agent_label() { - let ws = Workspace::test_new("test"); - let root_pane = ws.tabs[0].root_pane; - let mut terminals = HashMap::new(); - let mut terminal = terminal_for_pane(&ws, root_pane); - terminal.set_detected_state(Some(Agent::Pi), AgentState::Working); - terminal.set_agent_name("planner".into()); - terminals.insert(terminal.id.clone(), terminal); - - let labels: Vec<_> = ws - .pane_details(&terminals) - .into_iter() - .map(|detail| (detail.label, detail.agent_label, detail.agent)) - .collect(); - - assert_eq!( - labels, - vec![("planner".into(), "planner".into(), Some(Agent::Pi))] - ); - } - - #[test] - fn pane_details_includes_tab_context_for_multi_tab_workspace() { - let mut ws = Workspace::test_new("test"); - ws.tabs[0].custom_name = Some("main".into()); - let root_pane = ws.tabs[0].root_pane; - let second_tab = ws.test_add_tab(Some("review")); - let review_pane = ws.tabs[second_tab].root_pane; - let mut terminals = HashMap::new(); - let mut root_terminal = terminal_for_pane(&ws, root_pane); - root_terminal.set_hook_authority( - "test".into(), - "pi".into(), - AgentState::Working, - None, - None, - ); - terminals.insert(root_terminal.id.clone(), root_terminal); - let mut review_terminal = terminal_for_pane(&ws, review_pane); - review_terminal.set_hook_authority( - "test".into(), - "claude".into(), - AgentState::Idle, - None, - None, - ); - terminals.insert(review_terminal.id.clone(), review_terminal); - - let labels: Vec<_> = ws - .pane_details(&terminals) - .into_iter() - .map(|detail| (detail.label, detail.agent_label, detail.agent)) - .collect(); - - assert_eq!( - labels, - vec![ - ("main·pi".into(), "pi".into(), Some(Agent::Pi)), - ("review·claude".into(), "claude".into(), Some(Agent::Claude)), - ] - ); - } - #[test] fn pane_details_use_tab_vector_index_not_stable_public_tab_number() { let mut ws = Workspace::test_new("test"); diff --git a/src/workspace/git/mod.rs b/src/workspace/git/mod.rs index b00cf3b3..b17cd347 100644 --- a/src/workspace/git/mod.rs +++ b/src/workspace/git/mod.rs @@ -18,6 +18,3 @@ pub use self::{ git_status_snapshot_for_cwd_with_demand, GitStatusCacheEntry, GitStatusRefreshDemand, }, }; - -#[cfg(test)] -pub(super) use self::status::git_ahead_behind; diff --git a/src/workspace/git/status.rs b/src/workspace/git/status.rs index 9f40170c..1c29d75c 100644 --- a/src/workspace/git/status.rs +++ b/src/workspace/git/status.rs @@ -314,25 +314,6 @@ fn read_upstream(repo: &mut RepoContext, branch: &str) -> Option Option<(usize, usize)> { - super::discovery::git_repo_root(cwd)?; - - let output = std::process::Command::new("git") - .arg("-C") - .arg(cwd) - .args(["rev-list", "--left-right", "--count", "HEAD...@{upstream}"]) - .output() - .ok()?; - - if !output.status.success() { - return None; - } - - let stdout = String::from_utf8(output.stdout).ok()?; - parse_git_ahead_behind_output(&stdout) -} - fn git_ahead_behind_between( cwd: &Path, head_oid: &str, diff --git a/src/workspace/tab.rs b/src/workspace/tab.rs index 6f0fa75e..79d7f94d 100644 --- a/src/workspace/tab.rs +++ b/src/workspace/tab.rs @@ -205,36 +205,6 @@ impl Tab { self.custom_name = Some(name); } - #[cfg(test)] - pub fn split_focused( - &mut self, - direction: Direction, - rows: u16, - cols: u16, - cwd: Option, - scrollback_limit_bytes: usize, - host_terminal_theme: crate::terminal_theme::TerminalTheme, - host_terminal_appearance: Option, - shell_config: crate::pane::PaneShellConfig<'_>, - launch_env: &PaneLaunchEnv, - ) -> std::io::Result { - self.split_pane_with_runtime( - self.layout.focused(), - true, - direction, - None, - rows, - cols, - cwd, - scrollback_limit_bytes, - host_terminal_theme, - host_terminal_appearance, - shell_config, - launch_env, - None, - ) - } - pub fn split_focused_command( &mut self, direction: Direction, -- cgit v1.2.3