Preserve restored screen during ticket reattach
ci / test (push) Waiting to run
ci / fuzz-smoke (push) Waiting to run
ci / windows-client (push) Waiting to run
ci / package-release (linux-x86_64, ubuntu-latest) (push) Waiting to run
ci / package-release (macos-aarch64, macos-14) (push) Waiting to run
ci / package-release (macos-x86_64, macos-13) (push) Waiting to run
ci / package-release (windows-x86_64, windows-latest) (push) Waiting to run
ci / publish-gitea-release (push) Blocked by required conditions
ci / remote-bench (push) Waiting to run

This commit is contained in:
DuProcess
2026-07-12 22:54:39 -04:00
parent 6bca98d1ce
commit 52a319fe9d
3 changed files with 68 additions and 2 deletions
+22
View File
@@ -426,6 +426,27 @@ escape_key = "^]"
"@ | Set-Content -NoNewline -Encoding utf8 $clientConfig
}
$hostsConfig = Join-Path $configDir "hosts.toml"
if ($ForceConfig -or -not (Test-Path $hostsConfig)) {
$defaultServer = if ($Server) { $Server } else { "user@example.com" }
$hostUdp = if ($DoshHost) { $DoshHost } else { $defaultServer }
@"
# Example:
# [server]
# ssh = "server"
# dosh_host = "server.example.com"
# port = 50000
# default_command = "tm"
# predict = true
[default]
ssh = "$defaultServer"
dosh_host = "$hostUdp"
port = $Port
predict = true
"@ | Set-Content -NoNewline -Encoding utf8 $hostsConfig
}
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
if (-not (($userPath -split ';') -contains $bindir)) {
[Environment]::SetEnvironmentVariable("Path", "$userPath;$bindir", "User")
@@ -442,5 +463,6 @@ Write-Host " $bindir\dosh.exe update --check"
Write-Host ""
Write-Host "Client config:"
Write-Host " $configDir\client.toml"
Write-Host " $configDir\hosts.toml"
Write-Host ""
Write-Host "Open a new terminal for PATH changes to apply."
+23 -2
View File
@@ -813,6 +813,10 @@ fn attach_snapshot(session: &Session, cols: u16, rows: u16) -> Vec<u8> {
screen_snapshot(session.parser.screen())
}
fn restored_screen_is_pending_reattach(session: &Session) -> bool {
session.restored_screen.is_some()
}
fn mode_allows_terminal_updates(mode: &str) -> bool {
mode != "view-only" && mode != "forward-only"
}
@@ -3707,7 +3711,7 @@ async fn broadcast_output(
// short wall-clock age so low-throughput prompt/TUI changes persist
// quickly while large bursts still avoid per-packet disk writes. The
// actual file write happens after the lock is dropped.
if session.persistent {
if session.persistent && !restored_screen_is_pending_reattach(session) {
session.bytes_since_persist = session
.bytes_since_persist
.saturating_add(output.bytes.len());
@@ -4060,7 +4064,10 @@ fn flush_persistent_screens(state: &Arc<Mutex<ServerState>>) {
let sessions_dir = locked.sessions_dir();
let mut to_write: Vec<(String, u16, u16, u64, Vec<u8>)> = Vec::new();
for (name, session) in locked.sessions.iter_mut() {
if !session.persistent || session.output_seq == session.last_persisted_seq {
if !session.persistent
|| restored_screen_is_pending_reattach(session)
|| session.output_seq == session.last_persisted_seq
{
continue;
}
session.bytes_since_persist = 0;
@@ -4411,6 +4418,20 @@ mod tests {
let session = locked.sessions.get("work").unwrap();
assert!(session.restored_screen.is_some());
assert_eq!(attach_snapshot(session, 80, 24), restored);
assert_eq!(
session.last_persisted_seq, 7,
"pre-reattach PTY output must not overwrite the persisted restored screen"
);
drop(locked);
flush_persistent_screens(&state);
let locked = state.lock().unwrap();
let session = locked.sessions.get("work").unwrap();
assert_eq!(
session.last_persisted_seq, 7,
"periodic flush must not replace restored screen before client-visible output"
);
}
#[test]
+23
View File
@@ -157,6 +157,29 @@ fn installers_generate_same_native_auth_client_defaults() {
}
}
#[test]
fn windows_installer_generates_hosts_config_like_unix() {
let install = include_str!("../install.sh");
let ps1 = include_str!("../install.ps1");
for setting in [
"hosts.toml",
"# default_command = \"tm\"",
"[default]",
"predict = true",
] {
assert!(
install.contains(setting),
"Unix installer missing host config setting {setting}"
);
assert!(
ps1.contains(setting),
"Windows installer missing host config setting {setting}"
);
}
assert!(ps1.contains("$hostUdp = if ($DoshHost) { $DoshHost } else { $defaultServer }"));
assert!(ps1.contains("Set-Content -NoNewline -Encoding utf8 $hostsConfig"));
}
#[test]
fn package_check_verifies_only_artifacts_it_builds() {
let makefile = include_str!("../Makefile");