Durable sessions: save & restore shell sessions across close and crash - #628
Durable sessions: save & restore shell sessions across close and crash#628Yuandi (DDKinger) wants to merge 6 commits into
Conversation
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>
| 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" |
There was a problem hiding this comment.
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, pluswtcli 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.
| 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), |
| { | ||
| "component": { | ||
| "type": "cargo", | ||
| "cargo": { | ||
| "name": "fallible-iterator", | ||
| "version": "0.3.0" | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| "component": { | ||
| "type": "cargo", | ||
| "cargo": { | ||
| "name": "fallible-streaming-iterator", | ||
| "version": "0.1.9" | ||
| } | ||
| } |
…ssion-restore # Conflicts: # src/tools/wtcli/ft_fuzzer/fuzzmain.cpp # tools/wta/src/app.rs # tools/wta/src/app/tab_state.rs # tools/wta/src/app_events.rs # tools/wta/src/master/mod.rs # tools/wta/src/protocol/acp/client.rs # tools/wta/src/protocol/acp/mock_agent_tests.rs # tools/wta/src/session_registry.rs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 181 out of 182 changed files in this pull request and generated no new comments.
Suppressed comments (2)
tools/wta/src/ui/shell_sessions_view.rs:62
- This view introduces new user-visible strings (e.g. the search placeholder) as hard-coded English literals. The rest of WTA uses rust-i18n (
t!(...)) for user-facing text, so these should be localized and added to the locale YAML files to avoid mixed-language UI.
src/cascadia/TerminalApp/TerminalPage.idl:203 - The doc comment for
OnPaneAgentSessionChangeddoesn’t match what the implementation consumes:TerminalPage::OnPaneAgentSessionChangedreadsparams.event,params.pane_bound, and also derivesagentfromagent/cli_source. As written, the IDL comment implies only{pane_id, agent_session_id, resume_commandline}, which is misleading for future callers/maintainers.
This comment has been minimized.
This comment has been minimized.
…ssion-restore # Conflicts: # src/cascadia/TerminalApp/AgentPaneContent.cpp # src/cascadia/TerminalApp/TabManagement.cpp # src/cascadia/TerminalApp/TerminalPage.cpp # src/cascadia/TerminalApp/TerminalPage.h # src/cascadia/WindowsTerminal/TerminalProtocolComServer.h # src/tools/wtcli/main.cpp # src/tools/wtcli/wtcli_functions.h # tools/wta/src/app_tests.rs # tools/wta/src/helper/runtime.rs # tools/wta/src/master/mod.rs # tools/wta/src/master/tests.rs
This comment has been minimized.
This comment has been minimized.
| wil::unique_hfile pipe; | ||
| const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds{ 3 }; | ||
| do | ||
| { |
A saved WSL session reopened in the distro's home directory instead of where the user left it: "Ubuntu test" listed `/home/yuazha/test`, yet restoring it landed in `~`. The two halves of the record disagreed. `active_pane_cwd`, which the list displays, stores the reported path verbatim; the layout the restore actually replays takes it from `TerminalPaneContent::GetNewTerminalArgs`, which only accepts a directory that resolves through `GetFileAttributesExW`. A WSL shell reports a Linux path, which never does, so the layout fell back to the profile's `~` and the restore faithfully replayed it as `wsl.exe --cd "~"`. Such a path is still usable. `MangleStartingDirectoryForWSL` already folds it into `wsl.exe --cd <path>` at launch, which is how a WSL profile honors `~` in the first place. So decide with `IsUsableStartingDirectory`: a real Windows directory, or a path that mangling claims. That leaves out a shell whose non-Windows path nothing would honor -- Git Bash's `/c/Users/...`, an explicit `--cd` on the commandline, a bare `~` that conflicts with it -- where falling back to the profile is still the only thing that launches. Hosted in `Utils` beside `MangleStartingDirectoryForWSL`, for the same reason that one is: the edge cases are worth testing, and TerminalApp has nowhere to test them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8c2ff36b-f306-49d4-94e6-95a6a81e00ab (cherry picked from commit 7be8c02)
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 184 out of 186 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
src/cascadia/TerminalApp/DurableSessionHelpers.h:58
- TryParseShellSessionId wraps the id with braces only when the first character isn’t '{'. If an id ever arrives with a trailing '}' but missing a leading '{' (or vice versa), this produces an invalid GUID string (e.g. "{id}}"), causing IIDFromString to fail unnecessarily. Adding the opening/closing brace checks independently makes the normalization robust.
std::wstring text{ durableShellSessionId };
if (text.front() != L'{')
{
text.insert(text.begin(), L'{');
text.push_back(L'}');
}
tools/wta/src/ui/shell_sessions_view.rs:62
- shell_sessions_view renders multiple user-facing strings as hardcoded English text (e.g. the search placeholder). Other WTA UI surfaces localize via
t!(...)(seeui/layout.rs), so this view should also uset!keys and update locale YAMLs; otherwise this feature will be partially untranslated.
| // ── Target 1: BuildSendEventJson ── | ||
| // Fuzz all three input parameters: eventType, paramsJson, and sessionId. | ||
| { | ||
| Json::Value evt; | ||
| wtcli::BuildSendEventJson(parts[0], parts[2], parts[3], evt); | ||
| wtcli::BuildSendEventJson(parts[0], parts[2], parts[3], !parts[3].empty(), evt); | ||
| } |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
check-spelling-bot Report
|
| Dictionary | Entries | Covers | Uniquely |
|---|---|---|---|
| cspell:csharp/csharp.txt | 32 | 2 | 2 |
| cspell:aws/aws.txt | 232 | 2 | 2 |
| cspell:fonts/fonts.txt | 536 | 1 | 1 |
Consider adding to the extra_dictionaries array (in the .github/actions/spelling/config.json file):
"cspell:csharp/csharp.txt",
"cspell:aws/aws.txt",
"cspell:fonts/fonts.txt",
To stop checking additional dictionaries, put (in the .github/actions/spelling/config.json file):
"check_extra_dictionaries": []Pattern suggestions ✂️ (1)
You could add these patterns to .github/actions/spelling/patterns/8740f3e9310e311276347a1b82eb6b1021ad0c06.txt:
# Automatically suggested patterns
# hit-count: 1 file-count: 1
# container images
image: [-\w./:@]+
Alternatively, if a pattern suggestion doesn't make sense for this project, add a # to the beginning of the line in the candidates file with the pattern to stop suggesting it.
Warnings and Notices ⚠️ (2)
See the 📂 files view, the 📜action log, 👼 SARIF report, or 📝 job summary for details.
| Count | |
|---|---|
| ℹ️ candidate-pattern | 1 |
| 54 |
See
✏️ Contributor please read this
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
If the listed items are:
- ... misspelled, then please correct them instead of using the command.
- ... names, please add them to
.github/actions/spelling/allow/names.txt. - ... APIs, you can add them to a file in
.github/actions/spelling/allow/. - ... just things you're using, please add them to an appropriate file in
.github/actions/spelling/expect/. - ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in
.github/actions/spelling/patterns/.
See the README.md in each directory for more information.
🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉
If the flagged items are 🤯 false positives
If items relate to a ...
-
binary file (or some other file you wouldn't want to check at all).
Please add a file path to the
excludes.txtfile matching the containing file.File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.
^refers to the file's path from the root of the repository, so^README\.md$would exclude README.md (on whichever branch you're using). -
well-formed pattern.
If you can write a pattern that would match it,
try adding it to thepatterns.txtfile.Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 184 out of 185 changed files in this pull request and generated 2 comments.
Suppressed comments (2)
src/cascadia/TerminalApp/SharedWta.cpp:610
SharedWta::Requestuses a hard-coded 3s deadline for the entire JSON-RPC exchange. This is now used by_intellterm.wta/shell_sessions/save(tab close) which may need to move/copy large scrollback sidecars and can legitimately take longer, causing saves to fail intermittently under load/slow disks.
wil::unique_hfile pipe;
const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds{ 3 };
do
{
tools/wta/src/ui/shell_sessions_view.rs:62
- This view introduces multiple user-facing strings as hard-coded English (e.g. search placeholder, loading/empty states, footer hints). Other TUI views in
tools/wta/src/ui/uset!(...)keys; this one should also be localized and have keys added totools/wta/locales/*.ymlto avoid shipping untranslated UI.
| let session_directory = buffer_root.join(&id); | ||
| fs::create_dir_all(&session_directory).with_context(|| { | ||
| format!( | ||
| "failed to create shell-session directory {}", | ||
| session_directory.display() | ||
| ) | ||
| })?; | ||
| let session_directory = fs::canonicalize(&session_directory).with_context(|| { | ||
| format!( | ||
| "failed to canonicalize shell-session directory {}", | ||
| session_directory.display() | ||
| ) | ||
| })?; | ||
| if !session_directory.starts_with(&buffer_root) { | ||
| return Err(anyhow!( | ||
| "shell-session directory escapes buffer root: {}", | ||
| session_directory.display() | ||
| )); | ||
| } |
| <data name="AgentPane_ShellSessionsTitle" xml:space="preserve"> | ||
| <value>Shell sessions</value> | ||
| <comment>Title shown in the agent pane title bar when the saved shell-sessions view is active.</comment> | ||
| </data> |
Summary
First split of #442. This is the save & restore half: a durable, on-disk snapshot of a tab's arrangement, owned by
wta-masterrather 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
WindowEmperorand thewtclidetached-session commands are not here — they stay in #442 and land on top of this.session/loadrather than duplicating it from saved terminal output./tab-historyagent-pane view (async load, search, restore, refresh, confirmed delete) pluswtcli list-shell-sessionsandwtcli restore-shell-session.User experience
/tab-history, search for it, and press Enter. Sessions already on screen are marked so you focus them instead of opening a duplicate.Storage
shell-sessions.dbunder the runtime state directoryshell-sessions/under the same directoryBoth 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
cargo test --target x86_64-pc-windows-msvc— 1601 passed, 0 failed.TerminalApp,WindowsTerminal,TerminalSettingsModel,TerminalControl,wtcli,LocalTests_TerminalApp,UnitTests_SettingsModel,TerminalApp_UnitTests,UnitTests_Controlall build with 0 errors.TerminalApp.LocalTestsTabTests: the durable-session logic tests pass. The page-hosting tests in that binary fail on_initializeTerminalPageonmaintoday as well — that is the breakage Fix TerminalApp local tests after FRE deferral #552 is fixing, not a regression from this PR.WpfTerminalControl/WpfTerminalTestNetCorefail to restoreMicrosoft.*.App.Ref 8.0.30in 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.