Files
codeg/src-tauri/src/acp/error.rs
2026-03-07 18:04:36 +08:00

72 lines
2.2 KiB
Rust

use serde::Serialize;
#[derive(Debug, thiserror::Error)]
pub enum AcpError {
#[error("agent process failed to spawn: {0}")]
SpawnFailed(String),
#[error("connection not found: {0}")]
ConnectionNotFound(String),
#[error("ACP protocol error: {0}")]
Protocol(String),
#[error("agent process exited unexpectedly")]
ProcessExited,
#[error("binary download failed: {0}")]
DownloadFailed(String),
#[error("platform not supported: {0}")]
PlatformNotSupported(String),
}
impl AcpError {
pub fn protocol(raw: impl Into<String>) -> Self {
let raw = raw.into();
let sanitized = sanitize_protocol_message(&raw);
if is_executable_format_error(&sanitized) {
return Self::Protocol(
"Agent executable appears incompatible or corrupted. Please retry to re-download it."
.into(),
);
}
Self::Protocol(sanitized)
}
}
impl Serialize for AcpError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
fn sanitize_protocol_message(raw: &str) -> String {
let without_spawned_at = regex::Regex::new(r#"\s*,?\s*"spawned_at"\s*:\s*"[^"]*"\s*,?"#)
.ok()
.map(|re| re.replace_all(raw, "").into_owned())
.unwrap_or_else(|| raw.to_string());
let without_dangling_comma = regex::Regex::new(r#",\s*([}\]])"#)
.ok()
.map(|re| re.replace_all(&without_spawned_at, "$1").into_owned())
.unwrap_or(without_spawned_at);
regex::Regex::new(r#"/(?:Users|home)/[^"\s]+"#)
.ok()
.map(|re| {
re.replace_all(&without_dangling_comma, "<local-path>")
.into_owned()
})
.unwrap_or(without_dangling_comma)
}
fn is_executable_format_error(message: &str) -> bool {
let lowered = message.to_lowercase();
lowered.contains("malformed mach-o file")
|| lowered.contains("exec format error")
|| lowered.contains("bad cpu type in executable")
|| lowered.contains("not a valid win32 application")
|| lowered.contains("is not a valid application for this os platform")
}