feat(mcp): enhance MCP server registration with error handling and improve transport process management

refactor: update various tools for better error handling and path resolution
fix: improve markdown rendering and input display in TUI
This commit is contained in:
asepharyana
2026-07-20 13:12:04 +07:00
parent 89ee213454
commit 148ba4e07b
17 changed files with 242 additions and 82 deletions
+31 -20
View File
@@ -69,31 +69,42 @@ impl CastOr<u32> for u128 {
/// Atomically write serializable `data` to `path`.
///
/// Flow: serialize to pretty JSON -> write to `path.tmp` -> fsync -> rename
/// Flow: serialize to pretty JSON -> write to `path.tmp.<uuid>` -> fsync -> rename
/// -> fsync parent. If `mode` is `Some`, set permissions before rename (Unix only).
///
/// A UUID-based temporary filename avoids collisions from concurrent writes.
/// Orphaned tmp files are cleaned up on any error after creation.
pub fn write_json_atomic<T: Serialize>(path: &Path, data: &T, mode: Option<u32>) -> std::io::Result<()> {
let tmp = path.with_extension("tmp");
let bytes = serde_json::to_vec_pretty(data)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
{
let mut f = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&tmp)?;
f.write_all(&bytes)?;
f.sync_all()?;
}
if let Some(m) = mode {
#[cfg(unix)]
let tmp = path.with_extension(format!("tmp.{}", uuid::Uuid::new_v4()));
let result = (|| -> std::io::Result<()> {
let bytes = serde_json::to_vec_pretty(data)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(m))?;
let mut f = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&tmp)?;
f.write_all(&bytes)?;
f.sync_all()?;
}
#[cfg(not(unix))]
{ let _ = m; }
if let Some(m) = mode {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(m))?;
}
#[cfg(not(unix))]
{ let _ = m; }
}
std::fs::rename(&tmp, path)?;
Ok(())
})();
// Clean up orphaned temp file on error after creation
if let Err(e) = result {
let _ = std::fs::remove_file(&tmp);
return Err(e);
}
std::fs::rename(&tmp, path)?;
if let Some(parent) = path.parent() {
let _ = std::fs::File::open(parent).and_then(|d| d.sync_all());
}