diff --git a/hive-ag3nt/src/mcp.rs b/hive-ag3nt/src/mcp.rs index 6bbdeb60..d73fa4d5 100644 --- a/hive-ag3nt/src/mcp.rs +++ b/hive-ag3nt/src/mcp.rs @@ -84,10 +84,23 @@ impl From for SocketReply { hive_sh4re::Response::HostJournal { content } => Self::HostJournal(content), hive_sh4re::Response::Schedules { schedules } => Self::Schedules(schedules), hive_sh4re::Response::Containers { containers } => Self::Containers(containers), - // A graceful stop is pending — the inbox is fenced. If claude polls - // `recv` during its stop-checkpoint turn, present it as an empty - // inbox (the serve loop is the real handler of this signal). - hive_sh4re::Response::GracefulStop => Self::Messages(Vec::new()), + // A graceful stop is pending — the inbox is fenced. Returning an + // *empty* inbox here is ambiguous: claude's "park on recv" habit + // makes it long-poll again instead of ending the turn, so the + // stop-checkpoint turn never finishes and the drain wait times out + // into a hard stop. Return a single explicit directive instead, so + // every recv during the stop unmissably tells claude to flush + end. + hive_sh4re::Response::GracefulStop => Self::Messages(vec![hive_sh4re::DeliveredMessage { + from: "graceful-stop".into(), + body: "⛔ GRACEFUL STOP IN PROGRESS — the container shuts down as soon as this turn \ + ends. Flush anything worth keeping to your durable /state files, then END \ + YOUR TURN now. Do NOT call recv again: the inbox is fenced and recv will \ + only keep returning this same notice." + .into(), + id: 0, + redelivered: false, + in_reply_to: None, + }]), hive_sh4re::Response::AgentMeta { name, running,