diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/pane.rs | 110 |
1 files changed, 94 insertions, 16 deletions
diff --git a/src/pane.rs b/src/pane.rs index 485b226c..9d75c21c 100644 --- a/src/pane.rs +++ b/src/pane.rs @@ -96,7 +96,25 @@ fn apply_pane_terminal_env(cmd: &mut CommandBuilder) { // when the remote side lacks matching terminfo entries. cmd.env("TERM", PANE_TERM); cmd.env("COLORTERM", PANE_COLORTERM); - cmd.env_remove("WT_SESSION"); + cmd.env("TERM_PROGRAM", "herdr"); + cmd.env("TERM_PROGRAM_VERSION", crate::build_info::version()); + // Host handles refer to the outer terminal, never to this pane. + for key in [ + "ITERM_SESSION_ID", + "LC_TERMINAL", + "LC_TERMINAL_VERSION", + "WEZTERM_PANE", + "KITTY_WINDOW_ID", + "WT_SESSION", + "TMUX", + "TMUX_PANE", + "STY", + "ZELLIJ", + "ZELLIJ_SESSION_NAME", + "ZELLIJ_PANE_ID", + ] { + cmd.env_remove(key); + } } #[derive(Debug, Clone, Default, PartialEq, Eq)] @@ -148,10 +166,18 @@ impl PaneLaunchEnv { fn apply_pane_launch_env(cmd: &mut CommandBuilder, launch_env: &PaneLaunchEnv) { #[cfg(unix)] crate::platform::ssh_agent::apply_pane_env(cmd); - cmd.env_remove("CODEX_THREAD_ID"); - // OMP sets OMPCODE for shells it spawns. A pane launched from inside OMP - // must not inherit it or its root agent would look like a nested session. - cmd.env_remove("OMPCODE"); + // A new pane is not a child agent of the process that started the server. + // Explicit launch env below can opt back into an intentional child session. + for key in [ + "CODEX_THREAD_ID", + "OMPCODE", + "CLAUDECODE", + "CLAUDE_CODE_CHILD_SESSION", + "CLAUDE_CODE_SESSION_ID", + "CLAUDE_CODE_MESSAGING_TOKEN", + ] { + cmd.env_remove(key); + } for (key, value) in &launch_env.extra { cmd.env(key, value); } @@ -3715,6 +3741,7 @@ impl PaneRuntime { #[cfg(test)] mod tests { use super::*; + use std::ffi::OsStr; #[tokio::test] async fn clear_pane_preserves_wrapped_input_and_unfinished_vt_sequence() { @@ -3824,33 +3851,84 @@ mod tests { } #[test] - fn pane_launch_env_removes_outer_codex_thread_id() { + fn pane_launch_env_removes_outer_agent_identity() { + let keys = [ + "CODEX_THREAD_ID", + "OMPCODE", + "CLAUDECODE", + "CLAUDE_CODE_CHILD_SESSION", + "CLAUDE_CODE_SESSION_ID", + "CLAUDE_CODE_MESSAGING_TOKEN", + ]; let mut cmd = CommandBuilder::new("shell"); - cmd.env("CODEX_THREAD_ID", "outer-session"); + for key in keys { + cmd.env(key, "outer-session"); + } + cmd.env("ANTHROPIC_API_KEY", "fake-api-key"); + cmd.env("DISPLAY", ":42"); apply_pane_launch_env(&mut cmd, &PaneLaunchEnv::default()); - assert!(cmd.get_env("CODEX_THREAD_ID").is_none()); + for key in keys { + assert!(cmd.get_env(key).is_none(), "{key} must not leak into panes"); + } + assert_eq!( + cmd.get_env("ANTHROPIC_API_KEY"), + Some(OsStr::new("fake-api-key")) + ); + assert_eq!(cmd.get_env("DISPLAY"), Some(OsStr::new(":42"))); } #[test] - fn pane_launch_env_removes_outer_ompcode_marker() { + fn pane_terminal_identity_removes_outer_terminal_identity() { + let keys = [ + "ITERM_SESSION_ID", + "LC_TERMINAL", + "LC_TERMINAL_VERSION", + "WEZTERM_PANE", + "KITTY_WINDOW_ID", + "WT_SESSION", + "TMUX", + "TMUX_PANE", + "STY", + "ZELLIJ", + "ZELLIJ_SESSION_NAME", + "ZELLIJ_PANE_ID", + ]; let mut cmd = CommandBuilder::new("shell"); - cmd.env("OMPCODE", "1"); + for key in keys { + cmd.env(key, "outer-session"); + } + cmd.env("TERM_PROGRAM", "iTerm.app"); + cmd.env("TERM_PROGRAM_VERSION", "outer-version"); - apply_pane_launch_env(&mut cmd, &PaneLaunchEnv::default()); + apply_pane_terminal_env(&mut cmd); - assert!(cmd.get_env("OMPCODE").is_none()); + for key in keys { + assert!(cmd.get_env(key).is_none(), "{key} must not leak into panes"); + } + assert_eq!(cmd.get_env("TERM_PROGRAM"), Some(OsStr::new("herdr"))); + assert_eq!( + cmd.get_env("TERM_PROGRAM_VERSION"), + Some(OsStr::new(&crate::build_info::version())) + ); } #[test] - fn pane_terminal_identity_removes_outer_windows_terminal_session() { + fn pane_launch_env_allows_explicit_session_identity() { + let extra = vec![ + ("CLAUDE_CODE_CHILD_SESSION".into(), "1".into()), + ("CLAUDE_CODE_SESSION_ID".into(), "intentional-child".into()), + ("CLAUDE_CODE_MESSAGING_TOKEN".into(), "fake-token".into()), + ("ITERM_SESSION_ID".into(), "intentional-host".into()), + ]; let mut cmd = CommandBuilder::new("shell"); - cmd.env("WT_SESSION", "outer-session"); - apply_pane_terminal_env(&mut cmd); + apply_pane_launch_env(&mut cmd, &PaneLaunchEnv::from_extra(extra.clone())); - assert!(cmd.get_env("WT_SESSION").is_none()); + for (key, value) in extra { + assert_eq!(cmd.get_env(key), Some(OsStr::new(&value))); + } } #[tokio::test] |
