diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-01 15:48:22 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-01 15:48:22 +0300 |
| commit | 207be3c771d281baae6e5fa0fb74be9a056e97a2 (patch) | |
| tree | d7b037ecdf629224a048c841d11659efdc23507d /src/main.rs | |
| parent | 8a6d697308162874a236c84aac0b0f8c7ac01f83 (diff) | |
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
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 182 |
1 files changed, 5 insertions, 177 deletions
diff --git a/src/main.rs b/src/main.rs index a6ba1c03..91a6b2e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,5 @@ use std::io; -use crossterm::event::{ - DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste, - EnableFocusChange, EnableMouseCapture, -}; -#[cfg(not(windows))] -use crossterm::event::{PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}; -use crossterm::execute; - pub(crate) const HERDR_ENV_VAR: &str = "HERDR_ENV"; pub(crate) const HERDR_ENV_VALUE: &str = "1"; const NESTED_HERDR_MESSAGES: [&str; 6] = [ @@ -19,41 +11,6 @@ const NESTED_HERDR_MESSAGES: [&str; 6] = [ "recursion detected. base case not found. aborting.", ]; -#[cfg(not(windows))] -fn push_keyboard_enhancement_flags() -> io::Result<()> { - execute!( - io::stdout(), - PushKeyboardEnhancementFlags(crate::input::ime_compatible_keyboard_enhancement_flags()) - ) -} - -#[cfg(windows)] -fn push_keyboard_enhancement_flags() -> io::Result<()> { - Ok(()) -} - -#[cfg(not(windows))] -fn pop_keyboard_enhancement_flags() -> io::Result<()> { - execute!(io::stdout(), PopKeyboardEnhancementFlags) -} - -#[cfg(windows)] -fn pop_keyboard_enhancement_flags() -> io::Result<()> { - Ok(()) -} - -fn set_host_color_scheme_reports(enabled: bool) -> io::Result<()> { - use std::io::Write; - - let sequence = if enabled { - crate::terminal_theme::HOST_COLOR_SCHEME_REPORT_ENABLE_SEQUENCE - } else { - crate::terminal_theme::HOST_COLOR_SCHEME_REPORT_DISABLE_SEQUENCE - }; - io::stdout().write_all(sequence.as_bytes())?; - io::stdout().flush() -} - mod agent_resume; mod api; mod app; @@ -62,6 +19,7 @@ mod checksum; mod cli; mod client; mod config; +mod copy_mode; mod detect; mod events; mod ghostty; @@ -103,10 +61,6 @@ mod update; mod workspace; mod worktree; -fn init_logging() { - crate::logging::init_file_logging("herdr.log"); -} - const DEFAULT_CONFIG: &str = r##"# herdr configuration # Place this file at ~/.config/herdr/config.toml @@ -718,7 +672,6 @@ fn main() -> io::Result<()> { println!(" {:<32} Run as headless server", "herdr server"); println!(); println!("Options:"); - println!(" --no-session Run monolithically (no server/client, escape hatch)"); println!(" --session <name> Use or create a named persistent session"); println!(" --remote <target> Attach through SSH to a remote Herdr server"); println!(" --remote-keybindings <local|server>"); @@ -758,7 +711,6 @@ fn main() -> io::Result<()> { // Reject unknown flags let known_flags = [ - "--no-session", "--session", "--remote", "--remote-keybindings", @@ -812,135 +764,11 @@ fn main() -> io::Result<()> { let loaded_config = config::Config::load(); exit_if_nested_disabled(&loaded_config.config); - let no_session = args.iter().any(|a| a == "--no-session"); - - // Auto-detect launch: when --no-session is NOT set, use server/client mode. - // Check if a server is running, spawn one if needed, then attach as client. - if !no_session { - if let Err(err) = server::autodetect::auto_detect_launch() { - eprintln!("herdr: {err}"); - std::process::exit(1); - } - return Ok(()); + if let Err(err) = server::autodetect::auto_detect_launch() { + eprintln!("herdr: {err}"); + std::process::exit(1); } - - // --- Monolithic mode (--no-session escape hatch) --- - // This is the pre-mission single-process behavior. - - init_logging(); - - let (api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); - let event_hub = api::EventHub::default(); - let _api_server = match api::start_server_with_capabilities(api_tx, event_hub.clone(), None) { - Ok(server) => server, - Err(err) if err.kind() == io::ErrorKind::AddrInUse => { - eprintln!("error: herdr is already running"); - eprintln!("socket: {}", api::socket_path().display()); - std::process::exit(1); - } - Err(err) => return Err(err), - }; - - let modify_other_keys_mode = crate::input::host_modify_other_keys_mode(); - - let original_hook = std::panic::take_hook(); - let panic_resets_modify_other_keys = modify_other_keys_mode.is_some(); - std::panic::set_hook(Box::new(move |info| { - tracing::error!("PANIC: {info}"); - if panic_resets_modify_other_keys { - let _ = std::io::Write::write_all(&mut io::stdout(), b"\x1b[>4;0m"); - } - if crate::kitty_graphics::is_enabled() { - let _ = crate::kitty_graphics::clear_all_host_graphics(); - } - let _ = execute!( - io::stdout(), - DisableFocusChange, - DisableBracketedPaste, - DisableMouseCapture - ); - let _ = crate::terminal_modes::clear_host_mouse_reporting(&mut io::stdout()); - let _ = set_host_color_scheme_reports(false); - let _ = pop_keyboard_enhancement_flags(); - ratatui::restore(); - original_hook(info); - })); - - let config = &loaded_config.config; - let config_diagnostic = config::config_diagnostic_summary(&loaded_config.diagnostics); - logging::startup("app"); - - // Background update check (non-blocking, best-effort) - // Only checks for newer versions and notifies the TUI. - // Skipped in --no-session mode (testing). - - let rt = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("failed to create tokio runtime"); - - let result = rt.block_on(async { - let mut terminal = ratatui::init(); - crate::terminal_modes::clear_host_mouse_reporting(&mut io::stdout())?; - if config.ui.mouse_capture { - execute!(io::stdout(), EnableMouseCapture)?; - } else { - execute!(io::stdout(), DisableMouseCapture)?; - } - execute!(io::stdout(), EnableBracketedPaste, EnableFocusChange)?; - set_host_color_scheme_reports(true)?; - push_keyboard_enhancement_flags()?; - - // Some hosts do not honor Kitty keyboard enhancement pushes for - // Shift+Enter. Enable xterm modifyOtherKeys only on hosts where we - // know it is needed and parseable, so modified Enter stays distinct. - if let Some(mode) = modify_other_keys_mode { - use std::io::Write; - std::io::stdout().write_all(mode.set_sequence())?; - std::io::stdout().flush()?; - } - - let mut app = app::App::new( - config, - true, // no_session — monolithic mode never saves/restores sessions - config_diagnostic, - api_rx, - event_hub, - ); - let result = app.run(&mut terminal).await; - - // Reset modifyOtherKeys if we enabled it. - if modify_other_keys_mode.is_some() { - use std::io::Write; - std::io::stdout().write_all(b"\x1b[>4;0m")?; - std::io::stdout().flush()?; - } - - if crate::kitty_graphics::is_enabled() { - crate::kitty_graphics::clear_all_host_graphics()?; - } - pop_keyboard_enhancement_flags()?; - execute!( - io::stdout(), - DisableFocusChange, - DisableBracketedPaste, - DisableMouseCapture - )?; - crate::terminal_modes::clear_host_mouse_reporting(&mut io::stdout())?; - set_host_color_scheme_reports(false)?; - ratatui::restore(); - - // Drop app (and all workspaces/panes) before runtime shuts down - drop(app); - - result - }); - - // Shut down runtime immediately — kills lingering PTY reader/writer tasks - rt.shutdown_timeout(std::time::Duration::from_millis(100)); - - logging::shutdown("app"); - result + Ok(()) } #[cfg(test)] |
