aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-01 15:48:22 +0300
committerGitHub <noreply@github.com>2026-09-01 15:48:22 +0300
commit207be3c771d281baae6e5fa0fb74be9a056e97a2 (patch)
treed7b037ecdf629224a048c841d11659efdc23507d /src/main.rs
parent8a6d697308162874a236c84aac0b0f8c7ac01f83 (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.rs182
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)]