diff --git a/src/cli/commands.rs b/src/cli/commands.rs index efac12a..1aa398b 100644 --- a/src/cli/commands.rs +++ b/src/cli/commands.rs @@ -840,15 +840,14 @@ pub async fn cmd_register(config: &Config, pid: Option, name: Option { - // Print shell commands for the hook to eval. - // Use tee-based capture (same as adopted sessions) to preserve - // the terminal's direct relationship with the shell — tab titles, - // CWD tracking, colors, and all shell integrations work normally. - let escaped_path = capture_path.replace('\'', "'\\''"); + Response::Ok(ResponseData::SessionRegistered { id, .. }) => { + // Only export the session ID — no exec, no redirect, no child + // processes. The shell continues completely unmodified so titles, + // CWD, colors, isatty(), and TUI apps all work normally. + // Output capture is not available for hooked sessions (snag output + // won't have scrollback), but ls/cwd/ps/attach/send all work via + // /proc and the stolen master fd. println!("export SNAG_SESSION={id}"); - println!("export SNAG_CAPTURE='{escaped_path}'"); - println!("exec > >(tee -a '{escaped_path}') 2>&1"); Ok(()) } Response::Error { message, .. } => { diff --git a/src/daemon/pty.rs b/src/daemon/pty.rs index ccc30c0..55d4be4 100644 --- a/src/daemon/pty.rs +++ b/src/daemon/pty.rs @@ -4,7 +4,7 @@ use nix::pty::openpty; use nix::sys::wait::WaitStatus; use nix::unistd::{close, dup2, fork, setsid, ForkResult, Pid}; use std::ffi::CString; -use std::os::fd::{AsRawFd, OwnedFd, RawFd}; +use std::os::fd::{AsFd, AsRawFd, OwnedFd, RawFd}; use std::path::{Path, PathBuf}; pub struct SpawnResult { @@ -184,3 +184,14 @@ pub fn fg_process(pts_path: &Path) -> Vec<(u32, String)> { results } + +/// Get the foreground process name for a PTY via tcgetpgrp. +/// Returns "idle" if the shell is in the foreground, the command name +/// if another process is running, or None on error. +pub fn fg_process_name(master_fd: &impl AsFd, shell_pid: Option) -> Option { + let pgid = nix::unistd::tcgetpgrp(master_fd).ok()?; + if shell_pid.is_some_and(|sp| sp == pgid) { + return Some("idle".to_string()); + } + read_comm(pgid.as_raw() as u32).or(Some("idle".to_string())) +} diff --git a/src/daemon/session.rs b/src/daemon/session.rs index dd9c024..253088b 100644 --- a/src/daemon/session.rs +++ b/src/daemon/session.rs @@ -100,22 +100,7 @@ impl Session { .and_then(|pid| pty::read_cwd(pid.as_raw() as u32)) .unwrap_or_else(|| "?".to_string()); - let fg = pty::fg_process(&self.pts_path); - let fg_process = fg - .iter() - .find(|(pid, _)| { - self.child_pid - .map(|cp| *pid != cp.as_raw() as u32) - .unwrap_or(true) - }) - .map(|(_, cmd)| cmd.clone()) - .or_else(|| { - if fg.is_empty() { - None - } else { - Some("idle".to_string()) - } - }); + let fg_process = pty::fg_process_name(&self.master_fd, self.child_pid); SessionInfo { id: self.id.clone(),