vtcode_core/tools/registry/
pty_facade.rs1use std::collections::HashSet;
4use std::future::Future;
5use std::sync::Arc;
6
7use anyhow::Result;
8
9use crate::config::PtyConfig;
10use crate::tools::exec_session::ExecSessionManager;
11use crate::tools::pty::PtyManager;
12
13use super::ToolRegistry;
14use super::pty;
15
16impl ToolRegistry {
17 pub fn pty_manager(&self) -> &PtyManager {
18 self.pty_sessions.manager()
19 }
20
21 pub fn pty_config(&self) -> &PtyConfig {
22 self.pty_sessions.config()
23 }
24
25 pub fn can_start_pty_session(&self) -> bool {
26 self.pty_sessions.can_start_session()
27 }
28
29 pub fn start_pty_session(&self) -> Result<pty::PtySessionGuard> {
30 self.pty_sessions.start_session()
31 }
32
33 pub fn end_pty_session(&self) {
34 self.pty_sessions.end_session();
35 }
36
37 pub fn active_pty_sessions(&self) -> usize {
38 self.pty_sessions.active_sessions()
39 }
40
41 pub fn terminate_all_pty_sessions(&self) {
42 self.pty_sessions.terminate_all();
43 }
44
45 pub fn terminate_all_pty_sessions_async(&self) -> impl Future<Output = Result<()>> + '_ {
49 self.pty_sessions.terminate_all_async()
50 }
51
52 pub async fn terminate_all_exec_sessions_async(&self) -> Result<()> {
56 self.terminate_exec_sessions_and_observe_cleanup(false, false).await
57 }
58
59 pub async fn terminate_all_exec_sessions_for_exit_async(&self) -> Result<()> {
63 self.terminate_exec_sessions_and_observe_cleanup(false, true).await
64 }
65
66 pub async fn terminate_active_exec_sessions_async(&self) -> Result<()> {
70 self.terminate_exec_sessions_and_observe_cleanup(true, false).await
71 }
72
73 pub async fn terminate_active_exec_sessions_for_exit_async(&self) -> Result<()> {
76 self.terminate_exec_sessions_and_observe_cleanup(true, true).await
77 }
78
79 async fn terminate_exec_sessions_and_observe_cleanup(&self, active_only: bool, immediate: bool) -> Result<()> {
86 let before = self.scoped_exec_session_ids(active_only).await;
87 let result = if immediate {
88 if active_only {
89 self.exec_sessions.terminate_active_sessions_for_exit_async().await
90 } else {
91 self.exec_sessions.terminate_all_sessions_for_exit_async().await
92 }
93 } else if active_only {
94 self.exec_sessions.terminate_active_sessions_async().await
95 } else {
96 self.exec_sessions.terminate_all_sessions_async().await
97 };
98 self.observe_terminated_exec_sessions(before).await;
99 result
100 }
101
102 pub fn exec_session_manager(&self) -> ExecSessionManager {
103 self.exec_sessions.clone()
104 }
105
106 pub async fn force_cancel_foreground_sessions_and_observe_cleanup(&self) -> (usize, usize, usize) {
113 let before = self.scoped_exec_session_ids(true).await;
114 let counts = self.exec_sessions.force_cancel_foreground_sessions().await;
115 self.observe_terminated_exec_sessions(before).await;
116 counts
117 }
118
119 async fn scoped_exec_session_ids(&self, active_only: bool) -> Vec<String> {
122 self.exec_sessions
123 .list_sessions()
124 .await
125 .into_iter()
126 .filter(|session| !active_only || !session.background)
127 .map(|session| session.id.as_str().to_owned())
128 .collect()
129 }
130
131 async fn observe_terminated_exec_sessions(&self, before: Vec<String>) {
136 if before.is_empty() {
137 return;
138 }
139 let remaining: HashSet<String> = self
140 .exec_sessions
141 .list_sessions()
142 .await
143 .into_iter()
144 .map(|session| session.id.as_str().to_owned())
145 .collect();
146 let terminated: Vec<String> = before.into_iter().filter(|id| !remaining.contains(id)).collect();
147 if !terminated.is_empty() {
148 self.observe_completion_exec_sessions_terminated(&terminated);
149 }
150 }
151
152 pub fn set_active_pty_sessions(&self, counter: Arc<std::sync::atomic::AtomicUsize>) {
154 self.exec_sessions.set_foreground_pty_counter(Arc::clone(&counter));
155 if let Ok(mut guard) = self.active_pty_sessions.write() {
156 *guard = Some(counter);
157 }
158 }
159
160 pub fn increment_active_pty_sessions(&self) {
162 if let Some(counter) = self
163 .active_pty_sessions
164 .read()
165 .unwrap_or_else(|e| e.into_inner())
166 .as_ref()
167 .map(Arc::clone)
168 {
169 counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
170 }
171 }
172
173 pub fn decrement_active_pty_sessions(&self) {
175 if let Some(counter) = self
176 .active_pty_sessions
177 .read()
178 .unwrap_or_else(|e| e.into_inner())
179 .as_ref()
180 .map(Arc::clone)
181 {
182 counter.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
183 }
184 }
185
186 pub fn active_pty_sessions_count(&self) -> usize {
188 self.active_pty_sessions
189 .read()
190 .ok()
191 .and_then(|g| g.as_ref().map(|c| c.load(std::sync::atomic::Ordering::Relaxed)))
192 .unwrap_or(0)
193 }
194}