Skip to content

Durable sessions: save & restore shell sessions across close and crash - #628

Open
Yuandi (DDKinger) wants to merge 1 commit into
mainfrom
dev/yuazha/durable-session-restore
Open

Durable sessions: save & restore shell sessions across close and crash#628
Yuandi (DDKinger) wants to merge 1 commit into
mainfrom
dev/yuazha/durable-session-restore

Conversation

@DDKinger

Copy link
Copy Markdown
Contributor

Summary

First split of #442. This is the save & restore half: a durable, on-disk snapshot of a tab's arrangement, owned by wta-master rather than by the Terminal process, so it survives a tab close, a window close, an exit and a crash.

Keeping the shells themselves alive (keep-running / detach), the notification-area entry point, the headless WindowEmperor and the wtcli detached-session commands are not here — they stay in #442 and land on top of this.

  • Persist a closing tab's serialized layout, profiles, cwd, agent bindings and — with Restore window layout and content — its scrollback into a master-owned SQLite store plus per-pane buffer sidecars.
  • Gate saving on the existing Settings → Startup → "When Terminal starts" preference, and only save tabs the user actually built: ones with input, an existing durable id, or a resumable agent session. A tab that only ran its profile's startup commands is not a session.
  • Extend startup restore so a replayed persisted layout also restores agent panes and resumes shell agent CLIs, replaying ACP history through session/load rather than duplicating it from saved terminal output.
  • Add the /tab-history agent-pane view (async load, search, restore, refresh, confirmed delete) plus wtcli list-shell-sessions and wtcli restore-shell-session.
  • Make restore idempotent across windows: activating a saved session focuses the tab already bound to that durable id instead of opening a second copy.
  • Fork rather than clobber when a tab's expected revision is stale, and run daily maintenance that prunes expired rows and orphaned sidecars.

User experience

  1. Work in a tab, then close it — or close the window, or let Terminal crash.
  2. With Restore window layout (or …and content), the next launch brings the tab back: same panes, same directories, same agent conversation, and with …and content the same scrollback.
  3. To reach an older session on demand, open the agent pane and run /tab-history, search for it, and press Enter. Sessions already on screen are marked so you focus them instead of opening a duplicate.

Storage

What Where
Session rows shell-sessions.db under the runtime state directory
Scrollback sidecars shell-sessions/ under the same directory

Both resolve through runtime_paths.rs, so packaged builds keep them package-private and unpackaged dev builds fall back to %LOCALAPPDATA%\IntelligentTerminal. Elevated and unelevated sessions share one database but are scoped apart on every read and write.

Design notes: doc/specs/durable-shell-sessions.md.

Verification

  • WTA: explicit-target build clean; cargo test --target x86_64-pc-windows-msvc1601 passed, 0 failed.
  • C++: TerminalApp, WindowsTerminal, TerminalSettingsModel, TerminalControl, wtcli, LocalTests_TerminalApp, UnitTests_SettingsModel, TerminalApp_UnitTests, UnitTests_Control all build with 0 errors.
  • TerminalApp.LocalTests TabTests: the durable-session logic tests pass. The page-hosting tests in that binary fail on _initializeTerminalPage on main today as well — that is the breakage Fix TerminalApp local tests after FRE deferral #552 is fixing, not a regression from this PR.
  • Not verified here: WpfTerminalControl / WpfTerminalTestNetCore fail to restore Microsoft.*.App.Ref 8.0.30 in this environment. Untouched by this PR.

Relationship to #490

#490 restores persisted agent sessions and panes on top of the existing state.json + buffer files, explicitly without SQLite. This PR contains that behaviour plus the durable store and /tab-history, so the two overlap and should not both merge as-is — happy to rebase this onto #490 and keep only the store delta if you prefer that ordering.

Closing a tab throws away its pane layout, working directories, scrollback
and any agent conversation running inside it; restarting Terminal throws
away the same thing for every tab at once. This adds a durable snapshot of
that arrangement, owned by wta-master rather than by the Terminal process,
so it survives a close, an exit and a crash alike.

- Persist a closing tab's serialized layout, profiles, cwd, agent bindings
  and (with "Restore window layout and content") its scrollback into a
  master-owned SQLite store plus per-pane buffer sidecars.
- Gate saving on the existing "When Terminal starts" preference, and only
  save tabs the user actually built - ones with input, a durable id, or a
  resumable agent session.
- Extend startup restore so a replayed persisted layout also restores agent
  panes and resumes shell agent CLIs, replaying ACP history through
  session/load instead of duplicating it from saved terminal output.
- Add the `/tab-history` agent-pane view with async loading, search,
  restore, refresh and confirmed deletion, plus `wtcli list-shell-sessions`
  and `wtcli restore-shell-session` over the terminal protocol.
- Make restore idempotent: activating a saved session focuses the tab
  already bound to that durable id instead of opening a second copy.
- Fork rather than clobber when a tab's expected revision is stale, and run
  daily maintenance that prunes expired rows and orphaned sidecars.

Split out of #442. Keeping the shells themselves alive across a close, the
notification-area entry point and the `wtcli` detached-session commands stay
in that PR and land separately on top of this.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings August 19, 2026 07:40
regHr = RegisterActiveObject(
activeObject.Get(),
__uuidof(TerminalProtocolComServer),
ACTIVEOBJECT_STRONG,
<Link>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>ole32.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ole32.lib;oleaut32.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
app.handle_event(AppEvent::UserMessageReplayChunk {
session_id: "sess-target".to_string(),
message_id: Some("chat-turn".to_string()),
text: "## User Request\nhow is the day".to_string(),
app.handle_event(AppEvent::UserMessageReplayChunk {
session_id: "sess-target".to_string(),
message_id: None,
text: "## User Request\nhow are you".to_string(),
app.handle_event(AppEvent::UserMessageReplayChunk {
session_id: "sess-target".to_string(),
message_id: None,
text: "## User Request\nhow is the day".to_string(),

#[test]
fn search_highlighting_preserves_unicode_boundaries() {
let spans = highlight_matches("İstanbul", "i\u{307}", Style::default());
.iter()
.map(|span| span.content.as_ref())
.collect::<String>(),
"İstanbul"

Copilot AI 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.

Pull request overview

Implements the “save & restore” half of durable shell sessions by adding a master-owned (WTA) persistent store plus UI/CLI/protocol surfaces to list and restore saved tabs (including optional scrollback) across close/exit/crash, while restoring agent panes and agent-session bindings.

Changes:

  • Add a WTA SQLite-backed durable shell-session store, ACP extension method plumbing, and runtime path resolution for persisted session state.
  • Add a new agent-pane view (/tab-history) to browse/search/restore/delete saved tabs, plus wtcli list-shell-sessions / wtcli restore-shell-session.
  • Extend Terminal protocol + args surfaces to carry durable shell-session metadata, restore buffer paths, and agent-pane view state; add input-tracking (HasUserInput) to gate persistence.

Reviewed changes

Copilot reviewed 181 out of 183 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tools/wta/src/ui/mod.rs Exposes the new shell-sessions TUI module.
tools/wta/src/ui/layout.rs Routes rendering to the shell-sessions view; exposes truncate_to_width for reuse.
tools/wta/src/ui/shell_sessions_view.rs New TUI view to list/search/restore/delete saved tabs.
tools/wta/src/slash_command_tests.rs Adds coverage ensuring /tab-history switches to the shell-sessions view.
tools/wta/src/shell/wt_channel/mod.rs Exposes new wtcli spawn helper used by shell-session operations.
tools/wta/src/shell/wt_channel/cli_channel.rs Adds protocol→wtcli mappings for listing/restoring shell sessions.
tools/wta/src/session_registry.rs Adds typed ACP extension request/response parsing for shell-session methods.
tools/wta/src/runtime_paths.rs Adds runtime-root resolution for durable shell-session storage (packaged/unpackaged).
tools/wta/src/protocol/acp/mock_agent_tests.rs Adds regression coverage for ext-request pump behavior and message-id replay plumbing.
tools/wta/src/master/session_mcp.rs Adds capability-registry regression test for session close semantics.
tools/wta/src/main.rs Wires in the new shell-session store module and helper initial-view options.
tools/wta/src/shell_session_store.rs Implements the master-owned SQLite + sidecar storage and maintenance logic.
tools/wta/src/helper/runtime.rs Seeds initial pane position + supports starting in shell-sessions view; adds unit test.
tools/wta/src/helper/config.rs Extends helper config for initial pane position + initial view enum.
tools/wta/src/coordinator.rs Adds delegate-agent “resume” commandline building (Windows + WSL) plus tests.
tools/wta/src/commands.rs Adds /tab-history command registration and parsing/registry tests.
tools/wta/src/cli/args.rs Adds hidden --initial-pane-position and InitialView::ShellSessions.
tools/wta/src/cli_tests.rs Adds coverage for new CLI arg parsing.
tools/wta/src/app/tab_state.rs Adds shell-sessions view state; improves replay chunk grouping with message IDs.
tools/wta/src/app_turn.rs Marks conversation as meaningful on prompt submission and projects updated state.
tools/wta/src/app_status_projection.rs Projects the durable agent session id + new view identifier.
tools/wta/src/app_keys.rs Adds key handling for the shell-sessions view (navigate/search/restore/delete/refresh).
tools/wta/src/app_contracts/event.rs Adds new events for shell-sessions load/restore/delete + replay chunk message-id.
tools/wta/locales/en-US.yml Adds localized summary for /tab-history.
tools/wta/locales/en-GB.yml Adds localized summary for /tab-history.
tools/wta/locales/zh-CN.yml Adds localized summary for /tab-history.
tools/wta/locales/zh-TW.yml Adds localized summary for /tab-history.
tools/wta/locales/vi-VN.yml Adds localized summary for /tab-history.
tools/wta/locales/uz-Latn-UZ.yml Adds localized summary for /tab-history.
tools/wta/locales/ur-PK.yml Adds localized summary for /tab-history.
tools/wta/locales/uk-UA.yml Adds localized summary for /tab-history.
tools/wta/locales/ug-CN.yml Adds localized summary for /tab-history.
tools/wta/locales/tt-RU.yml Adds localized summary for /tab-history.
tools/wta/locales/tr-TR.yml Adds localized summary for /tab-history.
tools/wta/locales/th-TH.yml Adds localized summary for /tab-history.
tools/wta/locales/te-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/ta-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/sv-SE.yml Adds localized summary for /tab-history.
tools/wta/locales/sr-Latn-RS.yml Adds localized summary for /tab-history.
tools/wta/locales/sr-Cyrl-RS.yml Adds localized summary for /tab-history.
tools/wta/locales/sr-Cyrl-BA.yml Adds localized summary for /tab-history.
tools/wta/locales/sq-AL.yml Adds localized summary for /tab-history.
tools/wta/locales/sl-SI.yml Adds localized summary for /tab-history.
tools/wta/locales/sk-SK.yml Adds localized summary for /tab-history.
tools/wta/locales/ru-RU.yml Adds localized summary for /tab-history.
tools/wta/locales/ro-RO.yml Adds localized summary for /tab-history.
tools/wta/locales/quz-PE.yml Adds localized summary for /tab-history.
tools/wta/locales/qps-ploc.yml Adds pseudo-locale summary for /tab-history.
tools/wta/locales/qps-ploca.yml Adds pseudo-locale summary for /tab-history.
tools/wta/locales/qps-plocm.yml Adds pseudo-locale summary for /tab-history.
tools/wta/locales/pt-BR.yml Adds localized summary for /tab-history.
tools/wta/locales/pt-PT.yml Adds localized summary for /tab-history.
tools/wta/locales/pl-PL.yml Adds localized summary for /tab-history.
tools/wta/locales/pa-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/or-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/nn-NO.yml Adds localized summary for /tab-history.
tools/wta/locales/nl-NL.yml Adds localized summary for /tab-history.
tools/wta/locales/ne-NP.yml Adds localized summary for /tab-history.
tools/wta/locales/nb-NO.yml Adds localized summary for /tab-history.
tools/wta/locales/mt-MT.yml Adds localized summary for /tab-history.
tools/wta/locales/ms-MY.yml Adds localized summary for /tab-history.
tools/wta/locales/mr-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/ml-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/mk-MK.yml Adds localized summary for /tab-history.
tools/wta/locales/mi-NZ.yml Adds localized summary for /tab-history.
tools/wta/locales/lv-LV.yml Adds localized summary for /tab-history.
tools/wta/locales/lt-LT.yml Adds localized summary for /tab-history.
tools/wta/locales/lo-LA.yml Adds localized summary for /tab-history.
tools/wta/locales/lb-LU.yml Adds localized summary for /tab-history.
tools/wta/locales/kok-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/ko-KR.yml Adds localized summary for /tab-history.
tools/wta/locales/kn-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/km-KH.yml Adds localized summary for /tab-history.
tools/wta/locales/kk-KZ.yml Adds localized summary for /tab-history.
tools/wta/locales/ka-GE.yml Adds localized summary for /tab-history.
tools/wta/locales/ja-JP.yml Adds localized summary for /tab-history.
tools/wta/locales/it-IT.yml Adds localized summary for /tab-history.
tools/wta/locales/is-IS.yml Adds localized summary for /tab-history.
tools/wta/locales/id-ID.yml Adds localized summary for /tab-history.
tools/wta/locales/hy-AM.yml Adds localized summary for /tab-history.
tools/wta/locales/hu-HU.yml Adds localized summary for /tab-history.
tools/wta/locales/hr-HR.yml Adds localized summary for /tab-history.
tools/wta/locales/hi-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/he-IL.yml Adds localized summary for /tab-history.
tools/wta/locales/gu-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/gl-ES.yml Adds localized summary for /tab-history.
tools/wta/locales/gd-gb.yml Adds localized summary for /tab-history.
tools/wta/locales/ga-IE.yml Adds localized summary for /tab-history.
tools/wta/locales/fr-FR.yml Adds localized summary for /tab-history.
tools/wta/locales/fr-CA.yml Adds localized summary for /tab-history.
tools/wta/locales/fil-PH.yml Adds localized summary for /tab-history.
tools/wta/locales/fi-FI.yml Adds localized summary for /tab-history.
tools/wta/locales/fa-IR.yml Adds localized summary for /tab-history.
tools/wta/locales/eu-ES.yml Adds localized summary for /tab-history.
tools/wta/locales/et-EE.yml Adds localized summary for /tab-history.
tools/wta/locales/es-ES.yml Adds localized summary for /tab-history.
tools/wta/locales/es-MX.yml Adds localized summary for /tab-history.
tools/wta/locales/el-GR.yml Adds localized summary for /tab-history.
tools/wta/locales/de-DE.yml Adds localized summary for /tab-history.
tools/wta/locales/da-DK.yml Adds localized summary for /tab-history.
tools/wta/locales/cy-GB.yml Adds localized summary for /tab-history.
tools/wta/locales/cs-CZ.yml Adds localized summary for /tab-history.
tools/wta/locales/ca-ES.yml Adds localized summary for /tab-history.
tools/wta/locales/ca-Es-VALENCIA.yml Adds localized summary for /tab-history.
tools/wta/locales/bs-Latn-BA.yml Adds localized summary for /tab-history.
tools/wta/locales/bn-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/bg-BG.yml Adds localized summary for /tab-history.
tools/wta/locales/az-Latn-AZ.yml Adds localized summary for /tab-history.
tools/wta/locales/as-IN.yml Adds localized summary for /tab-history.
tools/wta/locales/ar-SA.yml Adds localized summary for /tab-history.
tools/wta/locales/am-ET.yml Adds localized summary for /tab-history.
tools/wta/locales/af-ZA.yml Adds localized summary for /tab-history.
tools/wta/cgmanifest.json Adds CG manifest entries for new Cargo dependencies.
tools/wta/Cargo.toml Adds rusqlite (bundled) and a windows-sys feature used by pipe-based IPC.
tools/wta/Cargo.lock Locks new dependency graph entries for rusqlite and transitive crates.
src/tools/wtcli/wtcli.vcxproj Adds oleaut32.lib to support new functionality.
src/tools/wtcli/wtcli_functions.h Extends event JSON builder to stamp pane_bound.
src/tools/wtcli/main.cpp Adds list/restore shell-session commands + capability checks; stamps pane_bound.
src/tools/wtcli/ft_fuzzer/fuzzmain.cpp Updates fuzzer callsite for new BuildSendEventJson signature.
src/tools/wtcli/Formatting.h Declares a formatter for shell-sessions human output.
src/tools/wtcli/Formatting.cpp Implements human-readable formatting for saved shell sessions.
src/host/proxy/ITerminalProtocol.idl Adds protocol methods for listing/restoring shell sessions (append-only).
src/cascadia/WindowsTerminal/TerminalProtocolComServer.h Declares COM server methods and helpers for shell-session operations.
src/cascadia/UnitTests_SettingsModel/CommandTests.cpp Adds settings model coverage for new agent/durable session args.
src/cascadia/UnitTests_Control/ControlCoreTests.cpp Adds unit test for user-input tracking used to decide persistence.
src/cascadia/TerminalSettingsModel/Resources/uk-UA/Resources.resw Fixes formatting/indentation for an existing localization comment node.
src/cascadia/TerminalSettingsModel/ActionArgs.idl Adds new args fields for agent session + durable shell-session metadata.
src/cascadia/TerminalSettingsModel/ActionArgs.cpp Serializes new args to commandline flags.
src/cascadia/TerminalProtocol/TerminalProtocol.idl Adds durable shell-session id to TabInfo projection.
src/cascadia/TerminalProtocol/ProtocolParsing.h Routes new pane_agent_session_changed events to TerminalPage.
src/cascadia/TerminalControl/TermControl.idl Adds HasUserInput property.
src/cascadia/TerminalControl/TermControl.h Adds HasUserInput() API surface on TermControl.
src/cascadia/TerminalControl/TermControl.cpp Implements HasUserInput() forwarding to ControlCore.
src/cascadia/TerminalControl/ControlCore.idl Adds HasUserInput property.
src/cascadia/TerminalControl/ControlCore.h Adds _hasUserInput tracking and HasUserInput() declaration.
src/cascadia/TerminalControl/ControlCore.cpp Latches _hasUserInput on SendInput and exposes it via getter.
src/cascadia/TerminalApp/TerminalWindow.cpp Ensures startup restore wires agent restore buffer paths consistently.
src/cascadia/TerminalApp/TerminalPage.Protocol.cpp Adds protocol list/focus/restore shell-session operations via SharedWta + layout replay.
src/cascadia/TerminalApp/TerminalPage.idl Exposes protocol shell-session APIs + OnPaneAgentSessionChanged hookless binding event.
src/cascadia/TerminalApp/TerminalPage.h Extends startup action processing + adds durable/agent session tracking helpers.
src/cascadia/TerminalApp/Tab.h Adds durable shell-session id+revision to Tab state.
src/cascadia/TerminalApp/SharedWta.h Adds typed request method to call master via named pipe.
src/cascadia/TerminalApp/SharedWta.cpp Implements named-pipe JSON-RPC request/response plumbing to master.
src/cascadia/TerminalApp/Resources/en-US/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/de-DE/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/es-ES/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/fr-FR/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/it-IT/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/ja-JP/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/ko-KR/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/pt-BR/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/qps-ploc/Resources.resw Adds agent-pane title string for shell-sessions view (pseudo-locale).
src/cascadia/TerminalApp/Resources/qps-ploca/Resources.resw Adds agent-pane title string for shell-sessions view (pseudo-locale).
src/cascadia/TerminalApp/Resources/qps-plocm/Resources.resw Adds agent-pane title string for shell-sessions view (pseudo-locale).
src/cascadia/TerminalApp/Resources/ru-RU/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/sr-Cyrl-RS/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/uk-UA/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/zh-CN/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/Resources/zh-TW/Resources.resw Adds agent-pane title string for shell-sessions view.
src/cascadia/TerminalApp/DurableSessionHelpers.h New helper utilities for durable session close/restore gating and metadata manipulation.
src/cascadia/TerminalApp/AppCommandlineArgs.h Adds hidden CLI flags for agent-session + pane-view restore metadata.
src/cascadia/TerminalApp/AppCommandlineArgs.cpp Parses new hidden CLI flags into NewTerminalArgs.
src/cascadia/TerminalApp/AppActionHandlers.cpp Stamps durable shell-session metadata onto the created tab after restoring.
src/cascadia/TerminalApp/AgentPaneContent.idl Adds shell-sessions view toggles and agent-session-id projection.
src/cascadia/TerminalApp/AgentPaneContent.h Tracks shell-sessions view state + agent session id.
src/cascadia/TerminalApp/AgentPaneContent.cpp Updates label/logo logic for shell-sessions view title.
doc/wtcli-commands.md Documents new wtcli shell-session commands.
doc/specs/durable-shell-sessions.md Adds design spec describing storage, gating, save/restore, and maintenance behavior.
.github/actions/spelling/allow/apis.txt Adds MOVEFILE allowlist entry.
.github/actions/spelling/allow/allow.txt Adds rusqlite allowlist entry.
Suppressed comments (1)

tools/wta/src/ui/shell_sessions_view.rs:96

  • More user-facing strings in this new view are hard-coded (loading/empty states and bottom-bar hints). These should be localized via t!(...) rather than embedded English, otherwise non-en-US users will see an untranslated UI even when locale files exist.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +56 to +63
let search_value = if query.is_empty() {
Span::styled(
if search_focused {
"Search title or CWD"
} else {
"Press / to search title or CWD"
},
Style::default().fg(Color::DarkGray),
Comment thread tools/wta/cgmanifest.json
Comment on lines +643 to +659
{
"component": {
"type": "cargo",
"cargo": {
"name": "fallible-iterator",
"version": "0.3.0"
}
}
},
{
"component": {
"type": "cargo",
"cargo": {
"name": "fallible-streaming-iterator",
"version": "0.1.9"
}
}
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.

3 participants