@@ -41,7 +41,7 @@ use mappings::mouse::{
 
 use collections::{HashMap, VecDeque};
 use futures::StreamExt;
-use pty_info::PtyProcessInfo;
+use pty_info::{ProcessIdGetter, PtyProcessInfo};
 use serde::{Deserialize, Serialize};
 use settings::Settings;
 use smol::channel::{Receiver, Sender};
@@ -340,27 +340,74 @@ pub struct TerminalBuilder {
 
 impl TerminalBuilder {
     pub fn new_display_only(
-        working_directory: Option<PathBuf>,
         cursor_shape: CursorShape,
         alternate_scroll: AlternateScroll,
         max_scroll_history_lines: Option<usize>,
         window_id: u64,
-        cx: &App,
     ) -> Result<TerminalBuilder> {
-        Self::new(
-            working_directory,
-            None,
-            Shell::System,
-            HashMap::default(),
-            cursor_shape,
-            alternate_scroll,
-            max_scroll_history_lines,
-            false,
-            window_id,
-            None,
-            cx,
-            Vec::new(),
-        )
+        // Create a display-only terminal (no actual PTY).
+        let default_cursor_style = AlacCursorStyle::from(cursor_shape);
+        let scrolling_history = max_scroll_history_lines
+            .unwrap_or(DEFAULT_SCROLL_HISTORY_LINES)
+            .min(MAX_SCROLL_HISTORY_LINES);
+        let config = Config {
+            scrolling_history,
+            default_cursor_style,
+            ..Config::default()
+        };
+
+        let (events_tx, events_rx) = unbounded();
+        let mut term = Term::new(
+            config.clone(),
+            &TerminalBounds::default(),
+            ZedListener(events_tx),
+        );
+
+        if let AlternateScroll::Off = alternate_scroll {
+            term.unset_private_mode(PrivateMode::Named(NamedPrivateMode::AlternateScroll));
+        }
+
+        let term = Arc::new(FairMutex::new(term));
+
+        let terminal = Terminal {
+            task: None,
+            terminal_type: TerminalType::DisplayOnly,
+            completion_tx: None,
+            term,
+            term_config: config,
+            title_override: None,
+            events: VecDeque::with_capacity(10),
+            last_content: Default::default(),
+            last_mouse: None,
+            matches: Vec::new(),
+            selection_head: None,
+            breadcrumb_text: String::new(),
+            scroll_px: px(0.),
+            next_link_id: 0,
+            selection_phase: SelectionPhase::Ended,
+            hyperlink_regex_searches: RegexSearches::new(),
+            vi_mode_enabled: false,
+            is_ssh_terminal: false,
+            last_mouse_move_time: Instant::now(),
+            last_hyperlink_search_position: None,
+            #[cfg(windows)]
+            shell_program: None,
+            activation_script: Vec::new(),
+            template: CopyTemplate {
+                shell: Shell::System,
+                env: HashMap::default(),
+                cursor_shape,
+                alternate_scroll,
+                max_scroll_history_lines,
+                window_id,
+            },
+            child_exited: None,
+        };
+
+        Ok(TerminalBuilder {
+            terminal,
+            events_rx,
+        })
     }
     pub fn new(
         working_directory: Option<PathBuf>,
@@ -533,7 +580,10 @@ impl TerminalBuilder {
 
         let mut terminal = Terminal {
             task,
-            pty_tx: Notifier(pty_tx),
+            terminal_type: TerminalType::Pty {
+                pty_tx: Notifier(pty_tx),
+                info: pty_info,
+            },
             completion_tx,
             term,
             term_config: config,
@@ -543,12 +593,10 @@ impl TerminalBuilder {
             last_mouse: None,
             matches: Vec::new(),
             selection_head: None,
-            pty_info,
             breadcrumb_text: String::new(),
             scroll_px: px(0.),
             next_link_id: 0,
             selection_phase: SelectionPhase::Ended,
-            // hovered_word: false,
             hyperlink_regex_searches: RegexSearches::new(),
             vi_mode_enabled: false,
             is_ssh_terminal,
@@ -733,8 +781,16 @@ pub enum SelectionPhase {
     Ended,
 }
 
+enum TerminalType {
+    Pty {
+        pty_tx: Notifier,
+        info: PtyProcessInfo,
+    },
+    DisplayOnly,
+}
+
 pub struct Terminal {
-    pty_tx: Notifier,
+    terminal_type: TerminalType,
     completion_tx: Option<Sender<Option<ExitStatus>>>,
     term: Arc<FairMutex<Term<ZedListener>>>,
     term_config: Config,
@@ -745,7 +801,6 @@ pub struct Terminal {
     pub last_content: TerminalContent,
     pub selection_head: Option<AlacPoint>,
     pub breadcrumb_text: String,
-    pub pty_info: PtyProcessInfo,
     title_override: Option<SharedString>,
     scroll_px: Pixels,
     next_link_id: usize,
@@ -862,8 +917,10 @@ impl Terminal {
             AlacTermEvent::Wakeup => {
                 cx.emit(Event::Wakeup);
 
-                if self.pty_info.has_changed() {
-                    cx.emit(Event::TitleChanged);
+                if let TerminalType::Pty { info, .. } = &mut self.terminal_type {
+                    if info.has_changed() {
+                        cx.emit(Event::TitleChanged);
+                    }
                 }
             }
             AlacTermEvent::ColorRequest(index, format) => {
@@ -905,7 +962,9 @@ impl Terminal {
 
                 self.last_content.terminal_bounds = new_bounds;
 
-                self.pty_tx.0.send(Msg::Resize(new_bounds.into())).ok();
+                if let TerminalType::Pty { pty_tx, .. } = &self.terminal_type {
+                    pty_tx.0.send(Msg::Resize(new_bounds.into())).ok();
+                }
 
                 term.resize(new_bounds);
             }
@@ -1288,9 +1347,12 @@ impl Terminal {
         }
     }
 
-    ///Write the Input payload to the tty.
+    /// Write the Input payload to the PTY, if applicable.
+    /// (This is a no-op for display-only terminals.)
     fn write_to_pty(&self, input: impl Into<Cow<'static, [u8]>>) {
-        self.pty_tx.notify(input.into());
+        if let TerminalType::Pty { pty_tx, .. } = &self.terminal_type {
+            pty_tx.notify(input.into());
+        }
     }
 
     pub fn input(&mut self, input: impl Into<Cow<'static, [u8]>>) {
@@ -1594,7 +1656,7 @@ impl Terminal {
                 && let Some(bytes) =
                     mouse_moved_report(point, e.pressed_button, e.modifiers, self.last_content.mode)
             {
-                self.pty_tx.notify(bytes);
+                self.write_to_pty(bytes);
             }
         } else if e.modifiers.secondary() {
             self.word_from_position(e.position);
@@ -1701,7 +1763,7 @@ impl Terminal {
             if let Some(bytes) =
                 mouse_button_report(point, e.button, e.modifiers, true, self.last_content.mode)
             {
-                self.pty_tx.notify(bytes);
+                self.write_to_pty(bytes);
             }
         } else {
             match e.button {
@@ -1760,7 +1822,7 @@ impl Terminal {
             if let Some(bytes) =
                 mouse_button_report(point, e.button, e.modifiers, false, self.last_content.mode)
             {
-                self.pty_tx.notify(bytes);
+                self.write_to_pty(bytes);
             }
         } else {
             if e.button == MouseButton::Left && setting.copy_on_select {
@@ -1799,7 +1861,7 @@ impl Terminal {
                 if let Some(scrolls) = scroll_report(point, scroll_lines, e, self.last_content.mode)
                 {
                     for scroll in scrolls {
-                        self.pty_tx.notify(scroll);
+                        self.write_to_pty(scroll);
                     }
                 };
             } else if self
@@ -1808,7 +1870,7 @@ impl Terminal {
                 .contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL)
                 && !e.shift
             {
-                self.pty_tx.notify(alt_scroll(scroll_lines))
+                self.write_to_pty(alt_scroll(scroll_lines));
             } else if scroll_lines != 0 {
                 let scroll = AlacScroll::Delta(scroll_lines);
 
@@ -1879,10 +1941,12 @@ impl Terminal {
     /// This does *not* return the working directory of the shell that runs on the
     /// remote host, in case Zed is connected to a remote host.
     fn client_side_working_directory(&self) -> Option<PathBuf> {
-        self.pty_info
-            .current
-            .as_ref()
-            .map(|process| process.cwd.clone())
+        match &self.terminal_type {
+            TerminalType::Pty { info, .. } => {
+                info.current.as_ref().map(|process| process.cwd.clone())
+            }
+            TerminalType::DisplayOnly => None,
+        }
     }
 
     pub fn title(&self, truncate: bool) -> String {
@@ -1899,8 +1963,8 @@ impl Terminal {
                 .title_override
                 .as_ref()
                 .map(|title_override| title_override.to_string())
-                .unwrap_or_else(|| {
-                    self.pty_info
+                .unwrap_or_else(|| match &self.terminal_type {
+                    TerminalType::Pty { info, .. } => info
                         .current
                         .as_ref()
                         .map(|fpi| {
@@ -1930,7 +1994,8 @@ impl Terminal {
                             };
                             format!("{process_file} — {process_name}")
                         })
-                        .unwrap_or_else(|| "Terminal".to_string())
+                        .unwrap_or_else(|| "Terminal".to_string()),
+                    TerminalType::DisplayOnly => "Terminal".to_string(),
                 }),
         }
     }
@@ -1939,7 +2004,23 @@ impl Terminal {
         if let Some(task) = self.task()
             && task.status == TaskStatus::Running
         {
-            self.pty_info.kill_current_process();
+            if let TerminalType::Pty { info, .. } = &mut self.terminal_type {
+                info.kill_current_process();
+            }
+        }
+    }
+
+    pub fn pid(&self) -> Option<sysinfo::Pid> {
+        match &self.terminal_type {
+            TerminalType::Pty { info, .. } => info.pid(),
+            TerminalType::DisplayOnly => None,
+        }
+    }
+
+    pub fn pid_getter(&self) -> Option<&ProcessIdGetter> {
+        match &self.terminal_type {
+            TerminalType::Pty { info, .. } => Some(info.pid_getter()),
+            TerminalType::DisplayOnly => None,
         }
     }
 
@@ -2134,7 +2215,9 @@ unsafe fn append_text_to_term(term: &mut Term<ZedListener>, text_lines: &[&str])
 
 impl Drop for Terminal {
     fn drop(&mut self) {
-        self.pty_tx.0.send(Msg::Shutdown).ok();
+        if let TerminalType::Pty { pty_tx, .. } = &self.terminal_type {
+            pty_tx.0.send(Msg::Shutdown).ok();
+        }
     }
 }