use super::AppServerSession;use base64::Engine;use base64::engine::general_purpose::STANDARD;use codex_app_server_client::AppServerPath;use codex_app_server_client::AppServerRequestHandle;use codex_app_server_protocol::ClientRequest;use codex_app_server_protocol::FsCreateDirectoryParams;use codex_app_server_protocol::FsCreateDirectoryResponse;use codex_app_server_protocol::FsReadFileParams;use codex_app_server_protocol::FsReadFileResponse;use codex_app_server_protocol::FsRemoveParams;use codex_app_server_protocol::FsRemoveResponse;use codex_app_server_protocol::FsWriteFileParams;use codex_app_server_protocol::FsWriteFileResponse;use codex_app_server_protocol::JSONRPCRequest;use codex_app_server_protocol::RequestId;use codex_utils_absolute_path::AbsolutePathBuf;use color_eyre::eyre::Result;use color_eyre::eyre::WrapErr;use serde::de::DeserializeOwned;use serde_json::json;impl AppServerSession { pub(crate) async fn fs_create_directory_all_path( &mut self, path: &AppServerPath, ) -> Result<()> { self.request_fs_path::<FsCreateDirectoryResponse>( "fs/createDirectory", path, |request_id, path| ClientRequest::FsCreateDirectory { request_id, params: FsCreateDirectoryParams { path, recursive: Some(true), }, }, json!({ "path": path.as_str(), "recursive": true }), ) .await .map(drop) } pub(crate) async fn fs_write_file_path( &mut self, path: &AppServerPath, bytes: Vec<u8>, ) -> Result<()> { let data_base64 = STANDARD.encode(bytes); self.request_fs_path::<FsWriteFileResponse>( "fs/writeFile", path, |request_id, path| ClientRequest::FsWriteFile { request_id, params: FsWriteFileParams { path, data_base64: data_base64.clone(), }, }, json!({ "path": path.as_str(), "dataBase64": data_base64 }), ) .await .map(drop) } pub(crate) async fn fs_read_file_path(&mut self, path: &AppServerPath) -> Result<Vec<u8>> { let response: FsReadFileResponse = self .request_fs_path( "fs/readFile", path, |request_id, path| ClientRequest::FsReadFile { request_id, params: FsReadFileParams { path }, }, json!({ "path": path.as_str() }), ) .await?; STANDARD .decode(response.data_base64) .wrap_err("fs/readFile returned invalid base64 data") } pub(crate) async fn fs_remove_path(&mut self, path: &AppServerPath) -> Result<()> { self.request_fs_path::<FsRemoveResponse>( "fs/remove", path, |request_id, path| ClientRequest::FsRemove { request_id, params: FsRemoveParams { path, recursive: None, force: None, }, }, json!({ "path": path.as_str() }), ) .await .map(drop) } async fn request_fs_path<T: DeserializeOwned>( &mut self, method: &str, path: &AppServerPath, local_request: impl FnOnce(RequestId, AbsolutePathBuf) -> ClientRequest, remote_params: serde_json::Value, ) -> Result<T> { let request_id = self.next_request_id(); match self.request_handle() { AppServerRequestHandle::Remote(handle) => { let response = handle .request_json_rpc(JSONRPCRequest { id: request_id, method: method.to_string(), params: Some(remote_params), trace: None, }) .await .wrap_err_with(|| format!("{method} failed in TUI"))?; serde_json::from_value(response.map_err(|source| { color_eyre::eyre::eyre!("{method} failed in TUI: {}", source.message) })?) .wrap_err_with(|| format!("{method} returned invalid data")) } AppServerRequestHandle::InProcess(_) => { let path = AbsolutePathBuf::from_absolute_path_checked(path.as_str()) .wrap_err_with(|| format!("invalid local app-server fs path {path}"))?; self.client .request_typed(local_request(request_id, path)) .await .wrap_err_with(|| format!("{method} failed in TUI")) } } }}