Watch
0
0
Fork
You've already forked hyperhive
0

hive-runtime: TurnStop replaces the subagent daemon's Stopper

TurnStop is the enum over hive-claude's Cancel and the ACP Canceller, with
stop() -> bool (false when no turn was in flight). It signals SIGINT only and
never waits. The subagent daemon tracks a TurnStop per turn, so interrupt has
one stop path; whether the name stays claimed afterwards (claude) or is freed
(ACP) still follows the runtime.
This commit is contained in:
atlas 2026-10-11 02:54:00 +02:00 • committed by mara
commit 496f85c8c6
5 changed files with 147 additions and 36 deletions

View file

@ -1029,7 +1029,7 @@ mod tests {
use hive_claude::{Config, NoopSink, PercentPolicy, Sink};
use super::{AcpError, AcpRuntime, Choice, ReportedCost, SessionChoices, Spend, TurnKind};
use crate::{AcpCommand, Error, Runtime};
use crate::{AcpCommand, Error, Runtime, TurnStop};
/// An ACP agent in plain `sh`. It answers `initialize`, numbers its
/// sessions `s1`, `s2`, …, appends every method it is sent to
@ -1422,6 +1422,24 @@ done
assert!(!canceller.cancel(), "the turn is over");
}
#[tokio::test]
async fn a_turn_stop_cancels_only_a_turn_in_flight() {
let dir = tempfile::tempdir().unwrap();
let runtime = runtime(dir.path(), "silent");
let stop = TurnStop::from(runtime.canceller().unwrap());
assert!(!stop.stop(), "no turn is in flight yet");
let config = config(dir.path());
let (done, was_in_flight) = tokio::join!(runtime.run(&config, "one", &NoopSink), async {
prompt_sent(dir.path()).await;
stop.stop()
});
assert!(was_in_flight);
assert!(done.is_ok(), "{done:?}");
assert_eq!(count(dir.path(), "session/cancel"), 1);
assert!(!stop.stop(), "the turn is over");
}
#[tokio::test]
async fn an_agent_ignoring_a_cancel_is_killed() {
let dir = tempfile::tempdir().unwrap();