Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ab503e4f5 | ||
|
|
eaf11a7696 | ||
|
|
fffd2a55f3 | ||
|
|
9dead5652e |
@@ -777,7 +777,7 @@ async fn unpushed_commits_block_kill_and_force_keeps_the_tree() {
|
|||||||
other => panic!("expected a kill_guarded refusal, got {other:?}"),
|
other => panic!("expected a kill_guarded refusal, got {other:?}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force overrides the refusal and nothing else: session gone, tree kept.
|
// Force overrides the refusal: session gone, tree removed.
|
||||||
client.kill_session_forced(s.id).await.expect("forced kill");
|
client.kill_session_forced(s.id).await.expect("forced kill");
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
@@ -789,12 +789,12 @@ async fn unpushed_commits_block_kill_and_force_keeps_the_tree() {
|
|||||||
.any(|x| x.id == s.id),
|
.any(|x| x.id == s.id),
|
||||||
"the forced kill ends the session"
|
"the forced kill ends the session"
|
||||||
);
|
);
|
||||||
assert!(wt.is_dir(), "a guarded worktree must stay on disk");
|
assert!(!wt.is_dir(), "a forced kill removes the worktree");
|
||||||
assert!(
|
assert!(
|
||||||
git_worktree_list(base.path())
|
!git_worktree_list(base.path())
|
||||||
.iter()
|
.iter()
|
||||||
.any(|l| l.contains("feature/local")),
|
.any(|l| l.contains("feature/local")),
|
||||||
"the kept tree stays registered in git"
|
"the removed tree is unregistered from git"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -196,12 +196,24 @@ export function useStructuredSession(
|
|||||||
connect();
|
connect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Mobile browsers suspend timers and silently kill WebSockets in the
|
||||||
|
// background. Kick a fresh connect when the page becomes visible again.
|
||||||
|
const onVisibility = () => {
|
||||||
|
if (document.visibilityState !== "visible" || disposed) return;
|
||||||
|
if (socket && (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING)) return;
|
||||||
|
cancelTimer();
|
||||||
|
setStatus("reconnecting");
|
||||||
|
connect();
|
||||||
|
};
|
||||||
|
document.addEventListener("visibilitychange", onVisibility);
|
||||||
|
|
||||||
setStatus("connecting");
|
setStatus("connecting");
|
||||||
connect();
|
connect();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
disposed = true;
|
disposed = true;
|
||||||
reconnectRef.current = () => {};
|
reconnectRef.current = () => {};
|
||||||
|
document.removeEventListener("visibilitychange", onVisibility);
|
||||||
cancelTimer();
|
cancelTimer();
|
||||||
closeSocket();
|
closeSocket();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -302,6 +302,24 @@ export const TerminalPane = forwardRef<TerminalPaneHandle, TerminalPaneProps>(
|
|||||||
ta?.addEventListener("focus", onTaFocus);
|
ta?.addEventListener("focus", onTaFocus);
|
||||||
ta?.addEventListener("blur", onTaBlur);
|
ta?.addEventListener("blur", onTaBlur);
|
||||||
|
|
||||||
|
// Mobile browsers (Android especially) suspend timers and silently kill
|
||||||
|
// WebSockets when the app goes to background. The backoff timer set by
|
||||||
|
// onclose is frozen too, so recovery stalls until visibility returns. Kick
|
||||||
|
// a fresh connect immediately when the page becomes visible again.
|
||||||
|
const onVisibility = () => {
|
||||||
|
if (document.visibilityState !== "visible" || disposed) return;
|
||||||
|
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) return;
|
||||||
|
// Cancel any pending backoff — we're reconnecting right now.
|
||||||
|
if (reconnectTimer !== null) {
|
||||||
|
window.clearTimeout(reconnectTimer);
|
||||||
|
reconnectTimer = null;
|
||||||
|
}
|
||||||
|
reconnectMs = INITIAL_RECONNECT_MS;
|
||||||
|
onStatusChange?.("reconnecting");
|
||||||
|
connect();
|
||||||
|
};
|
||||||
|
document.addEventListener("visibilitychange", onVisibility);
|
||||||
|
|
||||||
window.addEventListener("resize", onResize);
|
window.addEventListener("resize", onResize);
|
||||||
const visual = window.visualViewport ?? null;
|
const visual = window.visualViewport ?? null;
|
||||||
visual?.addEventListener("resize", onResize);
|
visual?.addEventListener("resize", onResize);
|
||||||
@@ -326,6 +344,7 @@ export const TerminalPane = forwardRef<TerminalPaneHandle, TerminalPaneProps>(
|
|||||||
reconnectTimer = null;
|
reconnectTimer = null;
|
||||||
}
|
}
|
||||||
ro.disconnect();
|
ro.disconnect();
|
||||||
|
document.removeEventListener("visibilitychange", onVisibility);
|
||||||
window.removeEventListener("resize", onResize);
|
window.removeEventListener("resize", onResize);
|
||||||
visual?.removeEventListener("resize", onResize);
|
visual?.removeEventListener("resize", onResize);
|
||||||
ta?.removeEventListener("focus", onTaFocus);
|
ta?.removeEventListener("focus", onTaFocus);
|
||||||
|
|||||||
Reference in New Issue
Block a user