status, doctor: finalize sessions whose agent has exited
Commit

Extract endSessionNow — the markSessionEnded + eager-condense sequence the SessionStop hook already runs — and share it with a new finalizeExitedSessions sweep, so the hook and the sweep stay in lockstep. markSessionEnded gains an optional guard so the sweep re-checks OwnerExited on the freshly-loaded state under the session-state lock, closing a TOCTOU race where a turn could revive a session between the list snapshot and the finalize.
entire status (human and --json) and entire doctor run the sweep up front, finalizing any ACTIVE session whose owner process is gone instead of leaving it "active" until the 1h StuckActiveThreshold. After finalizing, the sweep reloads each session from disk so callers see the true post-finalize state (condense is fail-open, so StepCount/ FullyCondensed are never assumed). Both surfaces also label such sessions "exited" (human output, status --json, doctor's stuck-session reason) as a fallback when finalization can't run.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com Entire-Checkpoint: 3ee2f4dbe270