Remove fs/join and fs/parent from exec-server protocol (#27700)

## Summary

Path composition is already handled by `PathUri`, leaving `fs/join` and
`fs/parent` as redundant exec-server protocol surface. Because
app-server and exec-server are deployed atomically, these obsolete
methods can be removed without a compatibility shim.

This removes the protocol constants and payloads, public client APIs,
server registrations and handlers, and endpoint-only tests. Existing
in-process `PathUri` join/parent coverage remains.

## Validation

- `just test -p codex-exec-server` (215 passed, 2 skipped)
This commit is contained in:
Adam Perry @ OpenAI
2026-06-11 15:48:53 -07:00
committed by GitHub
Unverified
parent b7a5d81f84
commit e069153f2a
6 changed files with 0 additions and 182 deletions
-17
View File
@@ -48,8 +48,6 @@ use crate::protocol::FS_CANONICALIZE_METHOD;
use crate::protocol::FS_COPY_METHOD;
use crate::protocol::FS_CREATE_DIRECTORY_METHOD;
use crate::protocol::FS_GET_METADATA_METHOD;
use crate::protocol::FS_JOIN_METHOD;
use crate::protocol::FS_PARENT_METHOD;
use crate::protocol::FS_READ_DIRECTORY_METHOD;
use crate::protocol::FS_READ_FILE_METHOD;
use crate::protocol::FS_REMOVE_METHOD;
@@ -62,10 +60,6 @@ use crate::protocol::FsCreateDirectoryParams;
use crate::protocol::FsCreateDirectoryResponse;
use crate::protocol::FsGetMetadataParams;
use crate::protocol::FsGetMetadataResponse;
use crate::protocol::FsJoinParams;
use crate::protocol::FsJoinResponse;
use crate::protocol::FsParentParams;
use crate::protocol::FsParentResponse;
use crate::protocol::FsReadDirectoryParams;
use crate::protocol::FsReadDirectoryResponse;
use crate::protocol::FsReadFileParams;
@@ -463,17 +457,6 @@ impl ExecServerClient {
self.call(FS_CANONICALIZE_METHOD, &params).await
}
pub async fn fs_join(&self, params: FsJoinParams) -> Result<FsJoinResponse, ExecServerError> {
self.call(FS_JOIN_METHOD, &params).await
}
pub async fn fs_parent(
&self,
params: FsParentParams,
) -> Result<FsParentResponse, ExecServerError> {
self.call(FS_PARENT_METHOD, &params).await
}
pub async fn fs_read_directory(
&self,
params: FsReadDirectoryParams,
-4
View File
@@ -71,10 +71,6 @@ pub use protocol::FsCreateDirectoryParams;
pub use protocol::FsCreateDirectoryResponse;
pub use protocol::FsGetMetadataParams;
pub use protocol::FsGetMetadataResponse;
pub use protocol::FsJoinParams;
pub use protocol::FsJoinResponse;
pub use protocol::FsParentParams;
pub use protocol::FsParentResponse;
pub use protocol::FsReadDirectoryEntry;
pub use protocol::FsReadDirectoryParams;
pub use protocol::FsReadDirectoryResponse;
-29
View File
@@ -26,8 +26,6 @@ pub const FS_WRITE_FILE_METHOD: &str = "fs/writeFile";
pub const FS_CREATE_DIRECTORY_METHOD: &str = "fs/createDirectory";
pub const FS_GET_METADATA_METHOD: &str = "fs/getMetadata";
pub const FS_CANONICALIZE_METHOD: &str = "fs/canonicalize";
pub const FS_JOIN_METHOD: &str = "fs/join";
pub const FS_PARENT_METHOD: &str = "fs/parent";
pub const FS_READ_DIRECTORY_METHOD: &str = "fs/readDirectory";
pub const FS_REMOVE_METHOD: &str = "fs/remove";
pub const FS_COPY_METHOD: &str = "fs/copy";
@@ -263,33 +261,6 @@ pub struct FsCanonicalizeResponse {
pub path: PathUri,
}
// TODO(anp): remove fs/join from the protocol.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FsJoinParams {
pub base_path: PathUri,
pub path: PathBuf,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FsJoinResponse {
pub path: PathUri,
}
// TODO(anp): remove fs/parent from the protocol.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FsParentParams {
pub path: PathUri,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FsParentResponse {
pub path: Option<PathUri>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FsReadDirectoryParams {
@@ -3,7 +3,6 @@ use std::io;
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD;
use codex_app_server_protocol::JSONRPCErrorError;
use codex_utils_path_uri::PathUri;
use crate::CopyOptions;
use crate::CreateDirectoryOptions;
@@ -20,10 +19,6 @@ use crate::protocol::FsCreateDirectoryParams;
use crate::protocol::FsCreateDirectoryResponse;
use crate::protocol::FsGetMetadataParams;
use crate::protocol::FsGetMetadataResponse;
use crate::protocol::FsJoinParams;
use crate::protocol::FsJoinResponse;
use crate::protocol::FsParentParams;
use crate::protocol::FsParentResponse;
use crate::protocol::FsReadDirectoryEntry;
use crate::protocol::FsReadDirectoryParams;
use crate::protocol::FsReadDirectoryResponse;
@@ -125,33 +120,6 @@ impl FileSystemHandler {
Ok(FsCanonicalizeResponse { path })
}
pub(crate) async fn join(
&self,
params: FsJoinParams,
) -> Result<FsJoinResponse, JSONRPCErrorError> {
// TODO(anp): remove and migrate callers to PathUri.
let base_path = params.base_path.to_abs_path().map_err(map_fs_error)?;
let path = base_path.join(params.path);
let path = PathUri::from_abs_path(&path).map_err(map_fs_error)?;
Ok(FsJoinResponse { path })
}
pub(crate) async fn parent(
&self,
params: FsParentParams,
) -> Result<FsParentResponse, JSONRPCErrorError> {
// TODO(anp): remove and migrate callers to PathUri.
let path = params
.path
.to_abs_path()
.map_err(map_fs_error)?
.parent()
.map(|path| PathUri::from_abs_path(&path))
.transpose()
.map_err(map_fs_error)?;
Ok(FsParentResponse { path })
}
pub(crate) async fn read_directory(
&self,
params: FsReadDirectoryParams,
@@ -297,68 +265,4 @@ mod tests {
assert_eq!(response.data_base64, STANDARD.encode("ok"));
}
}
#[tokio::test]
async fn protocol_join_and_parent_preserve_native_path_operations() {
let temp_dir = tempfile::tempdir().expect("tempdir");
let runtime_paths = ExecServerRuntimePaths::new(
std::env::current_exe().expect("current exe"),
/*codex_linux_sandbox_exe*/ None,
)
.expect("runtime paths");
let handler = FileSystemHandler::new(runtime_paths);
let native_base =
AbsolutePathBuf::from_absolute_path(temp_dir.path()).expect("absolute tempdir");
let base_path = PathUri::from_abs_path(&native_base).expect("path URI");
let joined = handler
.join(FsJoinParams {
base_path: base_path.clone(),
path: "nested/file.txt".into(),
})
.await
.expect("join path");
assert_eq!(
joined.path,
PathUri::from_abs_path(&native_base.join("nested/file.txt")).expect("joined path URI")
);
let parent = handler
.parent(FsParentParams {
path: joined.path.clone(),
})
.await
.expect("parent path");
assert_eq!(
parent.path,
native_base
.join("nested/file.txt")
.parent()
.map(|path| PathUri::from_abs_path(&path).expect("parent path URI"))
);
let absolute_path = native_base.join("absolute.txt");
let joined = handler
.join(FsJoinParams {
base_path,
path: absolute_path.as_path().to_path_buf(),
})
.await
.expect("join absolute path");
assert_eq!(
joined.path,
PathUri::from_abs_path(&absolute_path).expect("absolute path URI")
);
let native_root = native_base
.ancestors()
.last()
.expect("absolute path should have a root");
let root = PathUri::from_abs_path(&native_root).expect("root path URI");
let parent = handler
.parent(FsParentParams { path: root })
.await
.expect("root parent");
assert_eq!(parent, FsParentResponse { path: None });
}
}
@@ -25,10 +25,6 @@ use crate::protocol::FsCreateDirectoryParams;
use crate::protocol::FsCreateDirectoryResponse;
use crate::protocol::FsGetMetadataParams;
use crate::protocol::FsGetMetadataResponse;
use crate::protocol::FsJoinParams;
use crate::protocol::FsJoinResponse;
use crate::protocol::FsParentParams;
use crate::protocol::FsParentResponse;
use crate::protocol::FsReadDirectoryParams;
use crate::protocol::FsReadDirectoryResponse;
use crate::protocol::FsReadFileParams;
@@ -270,22 +266,6 @@ impl ExecServerHandler {
self.file_system.canonicalize(params).await
}
pub(crate) async fn fs_join(
&self,
params: FsJoinParams,
) -> Result<FsJoinResponse, JSONRPCErrorError> {
self.require_initialized_for("filesystem")?;
self.file_system.join(params).await
}
pub(crate) async fn fs_parent(
&self,
params: FsParentParams,
) -> Result<FsParentResponse, JSONRPCErrorError> {
self.require_initialized_for("filesystem")?;
self.file_system.parent(params).await
}
pub(crate) async fn fs_read_directory(
&self,
params: FsReadDirectoryParams,
@@ -11,8 +11,6 @@ use crate::protocol::FS_CANONICALIZE_METHOD;
use crate::protocol::FS_COPY_METHOD;
use crate::protocol::FS_CREATE_DIRECTORY_METHOD;
use crate::protocol::FS_GET_METADATA_METHOD;
use crate::protocol::FS_JOIN_METHOD;
use crate::protocol::FS_PARENT_METHOD;
use crate::protocol::FS_READ_DIRECTORY_METHOD;
use crate::protocol::FS_READ_FILE_METHOD;
use crate::protocol::FS_REMOVE_METHOD;
@@ -21,8 +19,6 @@ use crate::protocol::FsCanonicalizeParams;
use crate::protocol::FsCopyParams;
use crate::protocol::FsCreateDirectoryParams;
use crate::protocol::FsGetMetadataParams;
use crate::protocol::FsJoinParams;
use crate::protocol::FsParentParams;
use crate::protocol::FsReadDirectoryParams;
use crate::protocol::FsReadFileParams;
use crate::protocol::FsRemoveParams;
@@ -121,18 +117,6 @@ pub(crate) fn build_router() -> RpcRouter<ExecServerHandler> {
handler.fs_canonicalize(params).await
},
);
router.request(
FS_JOIN_METHOD,
|handler: Arc<ExecServerHandler>, params: FsJoinParams| async move {
handler.fs_join(params).await
},
);
router.request(
FS_PARENT_METHOD,
|handler: Arc<ExecServerHandler>, params: FsParentParams| async move {
handler.fs_parent(params).await
},
);
router.request(
FS_READ_DIRECTORY_METHOD,
|handler: Arc<ExecServerHandler>, params: FsReadDirectoryParams| async move {