Skip to content

feat(cli): add workspace sleep and keep slept tabs on the desktop - #920

Merged
leynier merged 2 commits into
mainfrom
feat/cli-workspace-sleep
Oct 6, 2026
Merged

leynier merged 2 commits into
mainfrom
feat/cli-workspace-sleep

Conversation

@leynier

@leynier leynier commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • alera workspace sleep --id <id>: the CLI form of the app's Sleep action. It sends the existing workspace.sleep host verb: the workspace's terminal sessions stop, while tabs, layout, branch, and files stay and the workspace remains visible. Unlike archive it does not hide the workspace, and unlike remove/unregister it deletes nothing. It validates the workspace (unknown, removed, archived, or on an SSH host fail) and refuses the workspace of the calling terminal. Every host request has a deadline. When no host is running it records the sleep in the runtime store, and it fails instead when a host is alive but does not answer. --json reports the stopped terminal tab ids from the host's own record.
  • Fix: Sleep no longer deletes tabs on the desktop. The host ends slept sessions before it answers, and terminalRuntimeExitCoordinator treated each of those exits as a shell that quit and deleted the tab. This affected every Sleep, from the UI as well as the CLI. terminalSessionRemoved now carries reason: "workspaceSleep" and one sleepId per sleep (additive; no protocol bump). The desktop maps them to TerminalExitCause and keeps the tab, releasing or keeping its exited handle depending on whether the workspace is on screen. It closes the workspace view only on the first removal of each sleep. Against an older host it falls back to workspace.sleptTabs.
  • Docs: skills/alera-cli/references/workspaces.md and docs/workspace-storage.md.

Validation

  • Dart: flutter analyze is clean, and the full flutter test run passes (4396).
  • Rust: cargo clippy --workspace --all-targets -D warnings is clean, cargo test -p alera-cli --bins passes (1868), and terminal_host_sleep_conformance passes. The conformance test runs the real CLI against a real host: it stops only the target workspace's sessions, keeps tabs and branch, leaves the workspace unarchived, and checks the removal reason and sleepId. terminal_host_conformance passes too.
  • The race regressions in workbench_controller_sleep_exit*_test_cases.dart were each confirmed to fail with their fix reverted.
  • An iterative Codex review (gpt-6.1-sol, high) ended with no findings. Codegen was regenerated and the max-lines ratchet passes.

Risks

  • The tab fix only applies once the app ships with this sidecar. A desktop attached to an older host relies on the workspace.sleptTabs fallback, which can still lose a tab if a sibling wakes the workspace mid-lookup.
  • A workspace that stays on screen across a sleep keeps its exited handles until it is left, so those terminals need a manual restart while it stays open.
  • Manual E2E with the real app and a paired phone is still pending.

# Conflicts:
#	lib/src/features/workbench/infra/terminal_host/terminal_host_protocol.dart
#	rust/alera-cli/src/terminal_host/protocol_capabilities.rs
#	test/unit/workbench_controller_test.dart

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

Reviewed the new alera workspace sleep command and the desktop fix that keeps a slept workspace's terminal tabs.

  • CLI sleep: alera workspace sleep --id sends the existing workspace.sleep verb. It refuses the calling terminal, and unknown, removed, archived, and SSH-host workspaces. It records the sleep in the store only when no host is running, and fails instead when a live host does not answer.
  • Sleep removal cause: the host adds reason: "workspaceSleep" and one sleepId per sleep on terminalSessionRemoved before it answers the verb. Additive, no protocol bump. The desktop keeps that tab and releases the handle instead of treating the host's session end as a shell quit.
  • Reopen during a sleep: only the first removal of a sleepId closes the workspace view. A reopen before the remaining removals arrive stays open, and an exited handle that is still on screen is released only after that workspace is left.
  • Older hosts: a removal without the reason still checks workspace.sleptTabs, which the host records before it ends sessions, before the tab is closed.

Pullfrog  | View workflow run | Using grok-4.7 | 𝕏

@leynier
leynier merged commit 4a7d371 into main Oct 6, 2026
23 checks passed
@leynier
leynier deleted the feat/cli-workspace-sleep branch October 6, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant