Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).

Starting from 0.2.0, CLI / Extension / DSH Plugin share the same version number.

## [Unreleased]

### Fixed

- Windows auto-update now falls back to a supervised foreground daemon when the host Job Object denies process breakaway, preventing an upgrade from leaving the browser pipeline disconnected.

## [0.3.1] - 2026-09-23

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ Finish active browser tasks, then update the CLI:
bsk update --yes
```

For the default local setup, this restarts a running daemon when an update is installed. If Windows reports a staged update, wait for replacement to finish. If you use the installer to replace the binary, restart the daemon afterwards with `bsk daemon restart`.
For the default local setup, this restarts a running daemon when an update is installed. On Windows, the update helper first tries a detached daemon restart. If the host Job Object denies breakaway, it falls back to a supervised `bsk daemon start --foreground` process and remains its parent until the daemon exits. Set `BSK_AUTO_UPDATE=off` to disable daemon-side auto-update while keeping manual `bsk update` available. If you use the installer to replace the binary, restart the daemon afterwards with `bsk daemon restart`.

Update the extension through its browser store. Update the DSH plugin separately, then restart its profile:

Expand Down
24 changes: 18 additions & 6 deletions crates/bsk-cli/src/cli/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -831,11 +831,18 @@ fn windows_replacement_script(restart_args: Option<&StartArgs>, attempts: u32) -
// Only fixed switches and numeric values go into the ASCII script. Paths
// stay in Unicode environment variables, including %, ! and shell symbols.
let restart = restart_args.map_or_else(String::new, |args| {
format!(
"\"%BSK_UPDATE_TARGET%\" daemon start --port {} --session-idle {}ms --daemon-idle {}ms\r\nif errorlevel 1 goto failed_restart\r\n",
let flags = format!(
"--port {} --session-idle {}ms --daemon-idle {}ms",
args.resolved_port(),
args.resolved_session_idle().as_millis(),
args.resolved_daemon_idle().as_millis(),
);
format!(
"\"%BSK_UPDATE_TARGET%\" daemon start {flags}\r\n\
if not errorlevel 1 goto restarted\r\n\
echo Detached daemon restart failed; retrying in foreground mode.\r\n\
\"%BSK_UPDATE_TARGET%\" daemon start --foreground {flags}\r\n\
if errorlevel 1 goto failed_restart\r\n",
)
});
format!(
Expand All @@ -857,6 +864,7 @@ fn windows_replacement_script(restart_args: Option<&StartArgs>, attempts: u32) -
goto failed\r\n\
:replaced\r\n\
{restart}\
:restarted\r\n\
del /F /Q \"%BSK_UPDATE_LOG%\" >nul 2>nul\r\n\
(del /F /Q \"%BSK_UPDATE_SCRIPT%\" >nul 2>nul & exit 0)\r\n\
:failed_restart\r\n\
Expand Down Expand Up @@ -1060,11 +1068,15 @@ mod tests {
..Default::default()
};
let script = windows_replacement_script(Some(&args), 120);
let detached = "daemon start --port 54321 --session-idle 1234ms --daemon-idle 75000ms";
let foreground =
"daemon start --foreground --port 54321 --session-idle 1234ms --daemon-idle 75000ms";
assert!(script.is_ascii());
assert!(
script
.contains("daemon start --port 54321 --session-idle 1234ms --daemon-idle 75000ms")
);
assert!(script.contains(detached));
assert!(script.contains(foreground));
assert!(script.contains("Detached daemon restart failed; retrying in foreground mode."));
assert!(script.find(detached) < script.find(foreground));
assert!(script.find(foreground) < script.find(":restarted"));
assert!(!windows_replacement_script(None, 120).contains("daemon start"));
}

Expand Down
12 changes: 9 additions & 3 deletions crates/bsk-cli/tests/windows_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,6 @@ fn automatic_update_exits_old_daemon_and_restarts_on_the_same_port() {
.is_some(),
"old daemon must exit"
);
fixture.wait_for("helper cleanup", || {
fs::read_dir(fixture.exe.parent().unwrap()).unwrap().count() == 1
});
let status = fixture
.command()
.args(["--json", "status"])
Expand All @@ -332,6 +329,15 @@ fn automatic_update_exits_old_daemon_and_restarts_on_the_same_port() {
1,
"the replacement must not stage another update immediately"
);
let stop = fixture.command().args(["daemon", "stop"]).output().unwrap();
assert!(
stop.status.success(),
"{}",
String::from_utf8_lossy(&stop.stderr)
);
fixture.wait_for("replacement daemon stop", || fixture.info().is_none());
// A foreground fallback intentionally keeps the update helper alive as its
// parent until the daemon stops, so helper-file cleanup is not required here.
}

fn unused_port() -> u16 {
Expand Down
Loading