fix(mcp): fallback déterministe du runtime dir socket
`unix_runtime_dir` essaie désormais les bases candidates dans l'ordre de priorité ($XDG_RUNTIME_DIR → $TMPDIR → /tmp) et retient la première dont le sous-dossier `idea-mcp` existe ou peut être créé. Un $XDG_RUNTIME_DIR positionné mais inutilisable (sandbox/CI pointant un chemin inexistant ou en lecture seule) ne doit plus dead-end le bind loopback : sans ce fallback le socket ne se liait jamais en silence et la délégation inter-agents mourait. Déterministe pour un environnement donné, donc le côté bind et tout lecteur de `socket_path()` s'accordent sur le même répertoire. Indépendant du Lot E1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -87,13 +87,29 @@ impl McpEndpoint {
|
|||||||
/// per-user runtime dir (`$XDG_RUNTIME_DIR`, falling back to `$TMPDIR`, then
|
/// per-user runtime dir (`$XDG_RUNTIME_DIR`, falling back to `$TMPDIR`, then
|
||||||
/// `/tmp`). Kept short so the full socket path stays well under the ~108-byte
|
/// `/tmp`). Kept short so the full socket path stays well under the ~108-byte
|
||||||
/// `sockaddr_un` limit (`/run/user/<uid>/idea-mcp/<32 hex>.sock` ≈ 50 bytes).
|
/// `sockaddr_un` limit (`/run/user/<uid>/idea-mcp/<32 hex>.sock` ≈ 50 bytes).
|
||||||
|
///
|
||||||
|
/// The candidate bases are tried **in priority order**, returning the first whose
|
||||||
|
/// `idea-mcp` subdir exists or can be created. A set-but-unusable `$XDG_RUNTIME_DIR`
|
||||||
|
/// (e.g. a sandbox/CI where it points at a non-existent or read-only path) must not
|
||||||
|
/// dead-end the loopback bind: without this fallback the socket silently never
|
||||||
|
/// binds and inter-agent delegation dies. Deterministic for a given environment, so
|
||||||
|
/// the bind side and any `socket_path()` reader always agree on the same directory.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn unix_runtime_dir() -> PathBuf {
|
fn unix_runtime_dir() -> PathBuf {
|
||||||
let base = std::env::var_os("XDG_RUNTIME_DIR")
|
let candidates = [
|
||||||
.map(PathBuf::from)
|
std::env::var_os("XDG_RUNTIME_DIR").map(PathBuf::from),
|
||||||
.or_else(|| std::env::var_os("TMPDIR").map(PathBuf::from))
|
std::env::var_os("TMPDIR").map(PathBuf::from),
|
||||||
.unwrap_or_else(|| PathBuf::from("/tmp"));
|
Some(PathBuf::from("/tmp")),
|
||||||
base.join("idea-mcp")
|
];
|
||||||
|
for base in candidates.into_iter().flatten() {
|
||||||
|
let dir = base.join("idea-mcp");
|
||||||
|
if dir.is_dir() || std::fs::create_dir_all(&dir).is_ok() {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Last resort: keep the historical `/tmp` target even if creation just failed
|
||||||
|
// (the bind will surface the real error rather than silently picking nowhere).
|
||||||
|
PathBuf::from("/tmp").join("idea-mcp")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// **Single source of truth.** Computes the deterministic loopback endpoint of a
|
/// **Single source of truth.** Computes the deterministic loopback endpoint of a
|
||||||
|
|||||||
Reference in New Issue
Block a user