Description
In crates/zeph-subagent/src/manager.rs:1271–1279, when a worktree is allocated for a sub-agent,
the cleanup sequence is:
let result = run_agent_loop(agent_loop_args).await;
drop(guard); // cwd restored, mutex released
wm.remove(&handle, prune_branch_on_remove).await // stale if run_agent_loop panics
If run_agent_loop panics (async task unwind), guard drops via RAII (cwd restored, mutex released — correct),
but wm.remove(...) is never reached. The worktree directory is left on disk indefinitely.
Recovery happens at the next agent startup via reconcile(), but if the process never restarts
cleanly the stale worktree accumulates disk space.
Reproduction Steps
- Configure
worktree.enabled = true.
- Spawn a sub-agent with
permissions_worktree = true.
- Trigger a panic inside
run_agent_loop (e.g. via debug assert or injected panic in tests).
- Observe the worktree directory remains on disk after the task completes.
Expected Behavior
Worktree is removed on both normal and panic paths.
Actual Behavior
Worktree is not removed when run_agent_loop panics; cleanup only runs on the happy path.
Environment
- Crate:
zeph-subagent
- File:
crates/zeph-subagent/src/manager.rs:1271–1279
Fix
Move wm.remove into a RAII scopeguard or a dedicated cleanup struct so it runs on both normal
return and panic unwind:
let _cleanup = scopeguard::defer(|| {
// spawn a blocking task or call synchronous remove
});
Alternatively, wrap the body in std::panic::AssertUnwindSafe + catch_unwind, remove, then
propagate the panic.
Description
In
crates/zeph-subagent/src/manager.rs:1271–1279, when a worktree is allocated for a sub-agent,the cleanup sequence is:
If
run_agent_looppanics (async task unwind),guarddrops via RAII (cwd restored, mutex released — correct),but
wm.remove(...)is never reached. The worktree directory is left on disk indefinitely.Recovery happens at the next agent startup via
reconcile(), but if the process never restartscleanly the stale worktree accumulates disk space.
Reproduction Steps
worktree.enabled = true.permissions_worktree = true.run_agent_loop(e.g. via debug assert or injected panic in tests).Expected Behavior
Worktree is removed on both normal and panic paths.
Actual Behavior
Worktree is not removed when
run_agent_looppanics; cleanup only runs on the happy path.Environment
zeph-subagentcrates/zeph-subagent/src/manager.rs:1271–1279Fix
Move
wm.removeinto a RAIIscopeguardor a dedicated cleanup struct so it runs on both normalreturn and panic unwind:
Alternatively, wrap the body in
std::panic::AssertUnwindSafe+catch_unwind, remove, thenpropagate the panic.