fix(sbx): make /sbx save work on a live multipass sandbox
CI / rust client (hh) (macos-latest) (push) Waiting to run
CI / rust client (hh) (ubuntu-latest) (push) Waiting to run
CI / rust coverage (push) Waiting to run
CI / python server (3.10) (push) Waiting to run
CI / python server (3.11) (push) Waiting to run
CI / python server (3.12) (push) Waiting to run
CI / headless e2e smoke (push) Waiting to run
CI / dependency audit (push) Waiting to run
CI / secret scanning (push) Waiting to run
CI / rust client (hh) (macos-latest) (push) Waiting to run
CI / rust client (hh) (ubuntu-latest) (push) Waiting to run
CI / rust coverage (push) Waiting to run
CI / python server (3.10) (push) Waiting to run
CI / python server (3.11) (push) Waiting to run
CI / python server (3.12) (push) Waiting to run
CI / headless e2e smoke (push) Waiting to run
CI / dependency audit (push) Waiting to run
CI / secret scanning (push) Waiting to run
Multipass can only snapshot a powered-off instance, so `/sbx save` on a running multipass sandbox previously just surfaced multipass's "instance must be stopped" error — making the snapshot that `/sbx load` needs impossible to create through the UI. Now multipass save powers the instance down before snapshotting, and the handler tears the shared session down first (same as `/sbx stop`, but WITHOUT purging so the instance — and thus the snapshot — survives for a later `/sbx load`). Docker is unchanged: `docker commit` captures a live container, so its save stays non-disruptive. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1673,6 +1673,20 @@ fn handle_command(
|
||||
"saving sandbox state as '{label}'{}…",
|
||||
if local { " (+ local copy)" } else { "" }
|
||||
));
|
||||
// Docker commits a *live* container, so its save is non-
|
||||
// disruptive. Multipass can only snapshot a powered-off
|
||||
// instance, so saving it necessarily stops the shared shell —
|
||||
// tear the live session down (same as `/sbx stop`, but WITHOUT
|
||||
// purging: the instance must survive so the snapshot does too).
|
||||
if be == sbx::Backend::Multipass {
|
||||
if let Some(mut sb) = broker.take() {
|
||||
sb.stop();
|
||||
}
|
||||
broker_meta.take();
|
||||
*announced_dims = None;
|
||||
send_frame(out_tx, room, json!({"_sbx":"status","state":"stopped"}));
|
||||
app.sys("multipass must power off to snapshot — stopping the shared shell, then saving (reload it with `/sbx load`)");
|
||||
}
|
||||
let (tx, lbl) = (app_tx.clone(), label.clone());
|
||||
tokio::spawn(async move {
|
||||
let res = tokio::task::spawn_blocking(move || sbx::save_state(be, &name, &label, local)).await;
|
||||
|
||||
Reference in New Issue
Block a user