use crate::app::window_state::WindowState;
use crate::config::Config;
use par_term_mcp::{
SCREENSHOT_REQUEST_FILENAME, SCREENSHOT_RESPONSE_FILENAME, TerminalScreenshotRequest,
TerminalScreenshotResponse,
};
impl WindowState {
pub(crate) fn init_config_watcher(&mut self) {
let config_path = Config::config_path();
if !config_path.exists() {
debug_info!("CONFIG", "Config file does not exist, skipping watcher");
return;
}
match crate::config::watcher::ConfigWatcher::new(&config_path, 500) {
Ok(watcher) => {
debug_info!("CONFIG", "Config watcher initialized");
self.watcher_state.config_watcher = Some(watcher);
}
Err(e) => {
debug_info!("CONFIG", "Failed to initialize config watcher: {}", e);
}
}
}
pub(crate) fn init_config_update_watcher(&mut self) {
let update_path = Config::config_dir().join(".config-update.json");
if !update_path.exists() {
if let Some(parent) = update_path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let _ = std::fs::write(&update_path, "");
}
match crate::config::watcher::ConfigWatcher::new(&update_path, 200) {
Ok(watcher) => {
debug_info!("CONFIG", "Config-update watcher initialized");
self.watcher_state.config_update_watcher = Some(watcher);
}
Err(e) => {
debug_info!(
"CONFIG",
"Failed to initialize config-update watcher: {}",
e
);
}
}
}
pub(crate) fn init_screenshot_request_watcher(&mut self) {
let request_path = Config::config_dir().join(SCREENSHOT_REQUEST_FILENAME);
if !request_path.exists() {
if let Some(parent) = request_path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let _ = std::fs::write(&request_path, "");
}
let response_path = Config::config_dir().join(SCREENSHOT_RESPONSE_FILENAME);
if !response_path.exists() {
if let Some(parent) = response_path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let _ = std::fs::write(&response_path, "");
}
match crate::config::watcher::ConfigWatcher::new(&request_path, 100) {
Ok(watcher) => {
debug_info!("CONFIG", "Screenshot-request watcher initialized");
self.watcher_state.screenshot_request_watcher = Some(watcher);
}
Err(e) => {
debug_info!(
"CONFIG",
"Failed to initialize screenshot-request watcher: {}",
e
);
}
}
}
pub(crate) fn check_config_update_file(&mut self) {
let Some(watcher) = &self.watcher_state.config_update_watcher else {
return;
};
if watcher.try_recv().is_none() {
return;
}
let update_path = Config::config_dir().join(".config-update.json");
let content = match std::fs::read_to_string(&update_path) {
Ok(c) if c.trim().is_empty() => return,
Ok(c) => c,
Err(e) => {
log::warn!("CONFIG: failed to read config-update file: {e}");
return;
}
};
match serde_json::from_str::<std::collections::HashMap<String, serde_json::Value>>(&content)
{
Ok(updates) => {
log::info!(
"CONFIG: applying MCP config update ({} keys): {:?}",
updates.len(),
updates
);
if let Err(e) = self.apply_agent_config_updates(&updates) {
log::error!("CONFIG: MCP config update failed: {e}");
} else {
self.render_loop.config_changed_by_agent = true;
}
self.focus_state.needs_redraw = true;
}
Err(e) => {
log::error!("CONFIG: invalid JSON in config-update file: {e}");
}
}
let _ = std::fs::write(&update_path, "");
}
pub(crate) fn check_screenshot_request_file(&mut self) {
let Some(watcher) = &self.watcher_state.screenshot_request_watcher else {
return;
};
if watcher.try_recv().is_none() {
return;
}
let request_path = Config::config_dir().join(SCREENSHOT_REQUEST_FILENAME);
let response_path = Config::config_dir().join(SCREENSHOT_RESPONSE_FILENAME);
let content = match std::fs::read_to_string(&request_path) {
Ok(c) if c.trim().is_empty() => return,
Ok(c) => c,
Err(e) => {
log::warn!("ACP screenshot: failed to read request file: {e}");
return;
}
};
let request = match serde_json::from_str::<TerminalScreenshotRequest>(&content) {
Ok(req) => req,
Err(e) => {
log::error!("ACP screenshot: invalid JSON in request file: {e}");
let _ = std::fs::write(&request_path, "");
return;
}
};
let response = match self.capture_terminal_screenshot_mcp_response(&request.request_id) {
Ok(resp) => resp,
Err(e) => TerminalScreenshotResponse {
request_id: request.request_id.clone(),
ok: false,
error: Some(e),
mime_type: None,
data_base64: None,
width: None,
height: None,
},
};
match serde_json::to_vec_pretty(&response) {
Ok(bytes) => {
let tmp = response_path.with_extension("json.tmp");
if let Err(e) =
std::fs::write(&tmp, &bytes).and_then(|_| std::fs::rename(&tmp, &response_path))
{
let _ = std::fs::remove_file(&tmp);
log::error!(
"ACP screenshot: failed to write response {}: {}",
response_path.display(),
e
);
}
}
Err(e) => {
log::error!("ACP screenshot: failed to serialize response: {e}");
}
}
let _ = std::fs::write(&request_path, "");
}
}