agent_tui/daemon/usecases/
snapshot.rs1use std::sync::Arc;
2
3use crate::common::mutex_lock_or_recover;
4use crate::core::vom::snapshot::{SnapshotOptions, format_snapshot};
5
6use crate::daemon::adapters::{
7 core_cursor_to_domain, core_elements_to_domain, core_snapshot_to_domain,
8};
9use crate::daemon::domain::{
10 AccessibilitySnapshotInput, AccessibilitySnapshotOutput, SnapshotInput, SnapshotOutput,
11};
12use crate::daemon::error::SessionError;
13use crate::daemon::repository::SessionRepository;
14use crate::daemon::session::SessionId;
15
16pub trait SnapshotUseCase: Send + Sync {
17 fn execute(&self, input: SnapshotInput) -> Result<SnapshotOutput, SessionError>;
18}
19
20pub struct SnapshotUseCaseImpl<R: SessionRepository> {
21 repository: Arc<R>,
22}
23
24impl<R: SessionRepository> SnapshotUseCaseImpl<R> {
25 pub fn new(repository: Arc<R>) -> Self {
26 Self { repository }
27 }
28}
29
30impl<R: SessionRepository> SnapshotUseCase for SnapshotUseCaseImpl<R> {
31 fn execute(&self, input: SnapshotInput) -> Result<SnapshotOutput, SessionError> {
36 let session = self.repository.resolve(input.session_id.as_deref())?;
37 let mut session_guard = mutex_lock_or_recover(&session);
38
39 session_guard.update()?;
41
42 let screen = session_guard.screen_text();
43 let session_id = SessionId::from(session_guard.id.as_str());
44
45 let elements = if input.include_elements {
46 Some(core_elements_to_domain(session_guard.detect_elements()))
47 } else {
48 None
49 };
50
51 let cursor = if input.include_cursor {
52 Some(core_cursor_to_domain(&session_guard.cursor()))
53 } else {
54 None
55 };
56
57 Ok(SnapshotOutput {
58 session_id,
59 screen,
60 elements,
61 cursor,
62 })
63 }
64}
65
66pub trait AccessibilitySnapshotUseCase: Send + Sync {
67 fn execute(
68 &self,
69 input: AccessibilitySnapshotInput,
70 ) -> Result<AccessibilitySnapshotOutput, SessionError>;
71}
72
73pub struct AccessibilitySnapshotUseCaseImpl<R: SessionRepository> {
74 repository: Arc<R>,
75}
76
77impl<R: SessionRepository> AccessibilitySnapshotUseCaseImpl<R> {
78 pub fn new(repository: Arc<R>) -> Self {
79 Self { repository }
80 }
81}
82
83impl<R: SessionRepository> AccessibilitySnapshotUseCase for AccessibilitySnapshotUseCaseImpl<R> {
84 fn execute(
90 &self,
91 input: AccessibilitySnapshotInput,
92 ) -> Result<AccessibilitySnapshotOutput, SessionError> {
93 let session = self.repository.resolve(input.session_id.as_deref())?;
94 let mut session_guard = mutex_lock_or_recover(&session);
95
96 session_guard.update()?;
98
99 let session_id = SessionId::from(session_guard.id.as_str());
100 let components = session_guard.analyze_screen();
101
102 let options = SnapshotOptions {
103 interactive_only: input.interactive_only,
104 ..Default::default()
105 };
106 let core_snapshot = format_snapshot(&components, &options);
107 let snapshot = core_snapshot_to_domain(&core_snapshot);
108
109 Ok(AccessibilitySnapshotOutput {
110 session_id,
111 snapshot,
112 })
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::daemon::domain::SessionId;
120 use crate::daemon::test_support::MockSessionRepository;
121
122 #[test]
123 fn test_snapshot_usecase_returns_error_when_no_session() {
124 let repository = Arc::new(MockSessionRepository::new());
125 let usecase = SnapshotUseCaseImpl::new(repository);
126
127 let input = SnapshotInput::default();
128 let result = usecase.execute(input);
129
130 assert!(result.is_err());
131 }
132
133 #[test]
134 fn test_enhanced_snapshot_usecase_returns_error_when_no_session() {
135 let repository = Arc::new(MockSessionRepository::new());
136 let usecase = AccessibilitySnapshotUseCaseImpl::new(repository);
137
138 let input = AccessibilitySnapshotInput::default();
139 let result = usecase.execute(input);
140
141 assert!(result.is_err());
142 }
143
144 #[test]
145 fn test_enhanced_snapshot_input_default() {
146 let input = AccessibilitySnapshotInput::default();
147
148 assert!(input.session_id.is_none());
149 assert!(!input.interactive_only);
150 }
151
152 #[test]
153 fn test_enhanced_snapshot_input_with_options() {
154 let input = AccessibilitySnapshotInput {
155 session_id: Some(SessionId::new("test-session")),
156 interactive_only: true,
157 };
158
159 assert_eq!(input.session_id, Some(SessionId::new("test-session")));
160 assert!(input.interactive_only);
161 }
162}