mirror of
https://github.com/microsoft/vscode.git
synced 2026-10-10 12:42:25 +01:00
* sessions: Add shared chat layout ownership contract Freeze the experimental presentation setting for each window and invalidate queued owner snapshots across focus and phone-presentation transitions. Expose exact confirmed chat deletion identities and provider-neutral graduation mapping for layout and terminal consumers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add captureSidePaneComposition/restoreSidePaneComposition API to Workbench Adds a narrow public API on IAgentWorkbenchLayoutService and Workbench for capturing and restoring a per-chat Editor/Details side pane composition (ISidePaneState) without forcing visibility during capture and without a controller needing direct access to private cache/storage. restoreSidePaneComposition reuses the existing setEditorHidden/_setAuxiliaryBarHidden primitives (editor-before- auxiliaryBar ordering, suppressEditorPartAutoVisibility wrapping, reveal-event gating matching toggleSidePane), so shared grid geometry, maximize/transient state, and all legacy callers are unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Scope terminals and tasks to chat ownership Capture immutable terminal origins before asynchronous work, persist backend-qualified ownership, scope terminal/task reuse and cleanup to exact chat pairs, and preserve presentation, focus, reconnect, and runtime protections. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * terminal: Initialize BasePty ownership properties Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: chat-owned desktop layout composition (R5/R8/R13) Adds per-chat (owner-key) Editor/Details side-pane composition tracking to the desktop layout controller, on top of the chat-layout-ownership contract and captureSidePaneComposition/restoreSidePaneComposition APIs: - chatLayoutOwnerKeys.ts: computes/compares the stable owner key for a session's active chat (main chat maps to the session resource unchanged; peer chat maps to the chat resource), including replacement-safe remapping. - desktop/desktopOwnerCompositionStore.ts: per-owner last-open editor/auxiliaryBar composition store (ResourceMap-backed, storage persisted, versioned by workspace/machine). - desktopExistingSessionStrategy.ts: resolves/applies/captures the active owner's composition instead of always the single shared profile; restores composition on same-session peer-chat switches; reconciles on owner changes, including a phone-suspension entry or exit (owner key flips to/from undefined). While chat-owned layout is in effect, captures are written only to the active owner, leaving the shared legacy "Existing" profile untouched so it still reflects the last composition seen outside chat ownership (used by the disabled baseline and while phone-suspended). - baseSessionLayoutController.ts: chatLayoutActive(reader) reads the live, phone-aware ChatLayoutContext presentation instead of the frozen startup flag, so phone transitions reactively suspend/resume chat ownership; owner-key resolution threads an optional reader. - desktopLayoutController.ts / desktopLayoutStrategy.ts: wires chatLayoutActive(reader)/ownerKeyFor(reader)/compositionStore through IDesktopLayoutContext; compositionStore field made protected for test subclassing. - desktopDockedTabsCoordinator.ts: scopes tab-reconciliation intents by owner key instead of only by session. New test/browser/chatLayoutOwnership.test.ts covers: R1 disabled baseline (same-session chat switch never touches the shared composition), R5 same-session A/B/A distinct compositions, all four Editor/Details compositions round-tripping per owner, R8 confirmed peer-chat deletion clearing only that owner's composition, R8 draft promotion carrying a peer chat's composition to its new owner key, and R13 a phone transition suspending chat-owned composition and resuming the focused chat's own composition on exit. 150/150 layout tests passing (144 existing + 6 new), native browser typecheck clean, valid-layers-check clean, eslint clean on all changed files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Harden chat-owned layout: legacy seeding, stale-owner guard, same-key remap no-op - [R-seed] DesktopLayoutController seeds its chat-layout key from the disabled-mode key once (never removing the legacy snapshot), so enabling chat layout for the first time inherits existing per-session state instead of regressing to defaults. - [R4] BaseLayoutController captures the chat-layout owner snapshot before a working-set apply is queued, and checks it after every await inside the apply, so a superseded apply can no longer publish editor-part reveal/hide once the owner has moved on while it was in flight (the queued apply itself still always runs to completion). - Same-key remap in BaseLayoutController._remapOwnerKeyState and DesktopOwnerCompositionStore.remap is now a documented no-op, avoiding a self-delete hazard when old and new owner keys coincide. - Documents the flat synthetic chat-layout-owner-key scheme's rationale for reusing the base controller's existing session-keyed maps instead of introducing a nested resource-pair map. Tests: [R-seed] legacy-key inheritance/non-removal, [R4] stale-owner race (verified to genuinely fail with the guard disabled), new DesktopOwnerCompositionStore suite covering remap/forget including the same-key no-op. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: suspend chat-owned layout ownership during phone presentation (R13) Correct a bug where a desktop window crossing into a phone-sized presentation silently collapsed per-chat layout ownership onto the plain session resource instead of suspending it: capture/restore and reconcile-intent lookups keyed on that collapsed resource, which is also the main chat's own owner key, so a peer chat's working set, side-pane composition, or panel state could read or overwrite the main chat's stored state the moment the window narrowed, and panel restore/intent-scoping autoruns could apply a stale default on the suspend transition itself. - _ownerKeyForChat/_ownerKeyFor (BaseLayoutController) and IDesktopLayoutContext.ownerKeyFor now return URI | undefined: undefined means the per-chat owner exists but must be treated as unavailable while suspended; callers that WRITE/CAPTURE/DELETE skip on undefined, callers that RESTORE/APPLY (panel visibility/view autoruns, the working-set derive, composition reapply, docked-tab intent scoping) explicitly check suspension so they freeze the dormant owner's state rather than falling back to a shared default. - DesktopExistingSessionStrategy's ownerChanged no longer treats entering suspension (a real key becoming undefined) as an owner change, so suspend-entry leaves the on-screen composition undisturbed; resuming (undefined becoming a real key) still reapplies the then-focused chat's own composition. - The working-set derive's suspend branch freezes the last resolved owner by reference, so neither the suspend transition nor a session/chat switch during suspension captures or restores a working set; resuming recomputes the key for whichever chat is then focused. New tests (chatLayoutOwnership.test.ts, baseSessionLayoutController.test.ts) prove composition, working-set, and panel-visibility state survive a phone suspend/resume cycle undisturbed and that resuming applies the then-focused chat's own state, not the one focused when suspension began. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix phone-suspension state conversion and strip added comments Follow-up to b056819bf02 (not amended, per coordinator instruction), addressing coordinator rejection points: - Genuine bug: entering phone presentation no longer collapses the chat-layout owner key to the plain session resource or re-resolves Existing-strategy composition against the session default. Phone suspension now freezes the owner key and composition snapshot in place instead of converting/restoring state, so dormant per-chat data is never overwritten and no legacy profile is applied while phone presentation is active. - Removed all comments added in the prior (rejected) commit across production and test files; none remain. - Added coverage for same-session A/B/A distinct editor working sets plus panel view, and for a peer chat not inheriting the legacy session-keyed working set on its first visit. Validation this commit: full compile clean; targeted layout suite 162/162 passing (0 failing); native browser typecheck (node build/npm/electronTypes.ts && node node_modules/@typescript/native/bin/tsc --project build/checker/tsconfig.browser.json --pretty false) clean; eslint clean on touched files; npm run valid-layers-check clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix cross-owner side-pane toggle-reopen staleness and strip added comments Fixes a genuine bug exposed by driving the real toggleSidePane() API in a test: closing the side pane on chat A, visiting chat B, then reopening the side pane on A could restore B's stale global pre-hide cache instead of A's own composition, because the native toggle's reopen fallback (_sidePaneStateBeforeHide) is a single workbench-wide cache with no owner awareness. Adds a per-owner, transient (non-persisted) _preHideComposition map to DesktopExistingSessionStrategy, captured on onWillToggleSidePane and used on onDidToggleSidePane to correct a reopen via the existing restoreSidePaneComposition() API when it diverges from the owner's own remembered pre-hide state. Wires remap/forget through desktopLayoutController's owner-key lifecycle hooks alongside the existing composition store. Adds missing captureSidePaneComposition()/restoreSidePaneComposition() stubs to the test harness's mock layout service (previously entirely absent). Removes residual added code comments left over from prior commits in this task (mandatory copyright headers retained). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix multi-visible focused-owner restore and add resume-same-owner-key regression test - desktopExistingSessionStrategy.ts: the multi-visible branch of the side-pane visibility autorun used _reveal() (show-only) instead of _apply() (show+hide) whenever an owner key was present, so focusing a second owner while both sessions stayed visible never hid what the previously focused owner had shown. - chatLayoutOwnership.test.ts: add dedicated multi-visible-session tests for composition, editor working set, and panel visibility/view round-trips, plus a resume test proving that returning from a phone-layout suspension re-applies the focused owner's own composition even when the owner key is unchanged across the suspension. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix Draft strategy multi-visible capture suppression; prove fresh-restart composition restore - Remove DesktopDraftSessionStrategy's unconditional multipleSessionsVisibleObs block in _captureOwnerCompositionIfApplicable(), which silently dropped composition capture for a focused draft owner whenever any other session was simultaneously visible. The existing _activeOwnerKey() gate (chatLayoutActive + isCreated + isQuickChat) already correctly no-ops in disabled/no-owner cases, so the redundant multi-visible block only ever suppressed valid enabled-mode, multi-visible captures, mirroring the already-fixed DesktopExistingSessionStrategy pattern. - Add a regression test proving a focused draft owner's composition changes are captured while another session is simultaneously visible. - Add a fresh-controller-restart test proving a newly constructed DesktopLayoutController restores a session's side-pane composition, editor working set, and panel view together from storage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: prove preHideComposition lifecycle, Quick Chat precedence, and strip a leftover divider comment - Add 3 regression-proved tests covering the normal-toggle last-open composition cache lifecycle: deletion forgets it, draft promotion remaps it to the new owner key, and phone suspension neither writes a stale entry nor loses the one captured before suspension. - Add a Quick Chat test proving a saved working set keeps its recorded shared side-pane profile instead of being forced through the reload editorless-hide default (the Quick Chat analog of the existing New Session entry-default precedence tests; Quick Chat is not part of the new per-owner composition catalog and continues to use the pre-existing shared profile store, confirmed by code inspection across all owning files). - Remove a leftover '--- Owner composition ---' divider comment found during a cumulative git diff b095329b3e1..HEAD comment sweep; no other added comments beyond copyright headers remain. All 184 tests across the 7 layout test files pass. ESLint, the native browser typecheck, and the layers check are clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: persist normal-toggle last-open side pane composition across reload The side pane's normal-toggle last-open composition (captured on toggle close so a later toggle open reopens the same editor/auxiliary-bar state) was tracked only in an in-memory map on the owning strategy. A fresh controller (e.g. after a workbench reload) lost that cache and fell back to the owner's current/default composition instead of its own last-open one, violating R5/R7 (no geometry, but reopen preference must persist). Route pre-hide composition reads/writes through a second persisted slot on DesktopOwnerCompositionStore (storage key sessions.chatLayout.sidePanePreHideComposition), alongside the existing current-composition slot, and remove the strategy's private in-memory map in favor of the store. Added a regression test proving a freshly constructed controller restores owner A's own last-open composition after a real toggle close, not owner B's, and that B's own last-open composition also survives the same recreation unaffected. Validation: - npm run transpile-client - scripts/test.sh --run src/vs/sessions/contrib/layout/test/browser/{baseSessionLayoutController,chatLayoutOwnership,desktopLayoutController,desktopOwnerCompositionStore,desktopStrategies,mobileSessionLayoutController,sessions.layout.contribution}.test.ts -> 179 passing - npx eslint on touched files -> clean - node build/npm/electronTypes.ts && node node_modules/@typescript/native/bin/tsc --project build/checker/tsconfig.browser.json --pretty false -> clean - npm run valid-layers-check -> clean This is a bounded follow-up slice (R5 reload-persistence), not a claim of full task completion; other outstanding items reported separately remain to be addressed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Quick Chat own-composition precedence; genuine independent-storage reload proofs - DesktopDraftSessionStrategy now includes Quick Chat sessions in its owner-composition gate (previously excluded entirely), restoring a Quick Chat's own recorded composition on re-entry and on reload before falling back to the shared visibility profile default. - Fixed a feedback-loop bug where applying an owner's own composition did not suppress the shared-profile capture listener, causing an incidental overwrite of the shared profile. - Strengthened the R5 normal-toggle reload test and the R-seed peer working-set/panel-view restore test to reconstruct storage through a brand-new, independently seeded TestStorageService instance (keyed off raw serialized strings) instead of reusing the same live storage object across controller instances. - Added a regression test proving Quick Chat re-entry restores its own recorded composition rather than the shared profile default. All changes regression-proved via targeted sabotage/restore cycles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: persist per-chat bottomVisible (panel visibility) across reload - Add panelVisible to ISessionLayoutEntry and a new _isPanelVisibilityPersisted getter (base: false, Desktop: chatLayoutEnabled) so the existing per-session _panelVisibilityBySession runtime map is also written to and restored from the typed per-chat storage key when chat layout is enabled, independent of panelView restoration. - Add matching delete/remap handling for _panelVisibilityBySession alongside the existing per-session maps (session delete/archive, draft promotion, owner key remap, peer chat forget). - Update the R-seed fresh-controller test to assert the peer's persisted bottomVisible is now genuinely restored (and its panel view immediately re-opened) rather than asserting the prior unpersisted gap. - Add an [R7] test proving a fresh controller restores a saved peer chat's own bottomVisible independently of the main chat and of its panel view, using an independently reconstructed storage service. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Version owner composition storage and prove hidden-bottom view retention - DesktopOwnerCompositionStore now persists both the current and preHide/last-open composition slots in an explicit versioned {version, entries} schema instead of a bare array, and logs via ILogService (matching the repository's catch (error) { logService.error(error) } pattern) before discarding storage on a malformed or unsupported-version payload, rather than silently removing it. - Add round-trip, unsupported-version, and pre-versioned-bare-array tests for the new schema. - Update the two pre-existing tests that seeded the old bare-array format directly so they match the new schema. - Add an [R7] test proving a fresh controller keeps a saved peer's hidden bottom hidden (without opening its remembered view) across reconstruction, and restores that exact remembered view once the bottom is shown. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: revert Quick Chat durable owner-composition routing Quick Chat sessions must never receive a durable owner-composition key; restore the original exclusion in _activeOwnerKey() and drop the now-dead stored-composition branches in _registerQuickChatVisibility() that only existed to serve that routing. The _changingVisibility guard added alongside that change is unrelated to Quick Chat scope and is kept, since it still guards the legitimate Draft-session composition capture/apply pipeline. Remove the regression test that asserted the now-reverted behaviour. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Version the chat layout state storage schema and prove peer editor resources survive restart Adds a versioned {version, entries} schema, a runtime type guard, and ILogService-based corruption diagnostics to the experimental-only chat layout storage key (DESKTOP_CHAT_LAYOUT_STATE_KEY), leaving the disabled/legacy raw-array serialization untouched. panelVisible is now validated as a boolean rather than accepted as any non-undefined value. Also strengthens the test harness's saveWorkingSet/applyWorkingSet fakes to round-trip the active group's real editor resources and active tab (previously an opaque id/name spy only), and extends the fresh-controller peer restoration test to assert on those genuine editor resources and active tab, not just working-set object equality. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Prove and fix working-set/panel-map lifetime through deletion and promotion Add R8 tests proving a confirmed chat deletion forgets a peer's captured editor working set and panel visibility/view (not only its composition), and that a draft promotion carries those same maps to the replacement session's owner key while forgetting the stale draft key. The promotion test exposed a real gap: the switch-away listener that eagerly saves the outgoing chat's working set recomputes its owner key from the live session object, so it could resave the working set under a draft's now-remapped key after onDidReplaceSession already moved its state to the committed session's key, leaking a stale, permanently unreachable owner-key entry. Track replaced session resources and skip the eager save for them. Also correct a stale assertion message in the desktop reload test that claimed panel visibility is runtime-only, not itself persisted - true before persisted panelVisible existed, but no longer accurate since that reload scenario specifically exercises the legacy-migrated layoutState entry, which has no panelVisible field of its own. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix remaining Quick Chat durable-catalog leak and composition-store partial-apply corruption - desktopExistingSessionStrategy: exclude Quick Chat sessions from _activeOwnerKey() so toggling the side pane while a Quick Chat is active no longer writes/reads its composition into the durable per-owner composition/preHide catalog (a second, independent instance of the Quick Chat exclusion bug, unrelated to the one already fixed in the Draft strategy). - desktopOwnerCompositionStore: validate every persisted entry into a staging map before publishing to the live owner map, so a malformed entry can no longer leave earlier valid entries half-applied in memory while the backing storage record is removed. Entry shape is now checked strictly (tuple length, URI string, exact booleans) before any destructuring. Error messages for both the composition store and the base layout controller's session layout state no longer dump the full persisted payload, reporting only the storage key and version instead. - Add regression tests for both fixes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Validate layout entries atomically and fix same-resource promotion blacklist leak - isValidSessionLayoutEntry now validates editorWorkingSet, viewState, and sessionResource URI scheme; _parseVersionedSessionLayoutEntries rejects the whole record (logged once, index-only message) on any single malformed entry instead of silently filtering it out, matching the already-accepted desktopOwnerCompositionStore staged-validation precedent. - _replacedSessionResources no longer blacklists a session resource indefinitely: the switch-away guard now consumes the entry with delete() instead of has(), and _onSessionReplaced only adds an entry for cross-resource promotions (a same-resource promotion never triggers the switch-away race the blacklist exists to guard against), so a committed session's next outgoing working-set save is no longer silently suppressed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Consume replacement blacklist marker outside the Untitled short-circuit The switch-away listener's save-suppression check combined the Untitled/isRestoringSessionLayout gates with the one-shot _replacedSessionResources.delete() call using &&, so delete() only ran when both gates were false. A cross-resource promotion while the draft is Untitled (the common case) left its blacklist marker unconsumed on the draft's own switch-away, so it could persist indefinitely and incorrectly suppress a later, unrelated session's outgoing save if that session ever reused the same resource. Hoist the delete() into an unconditionally evaluated variable so the marker is always consumed on the very next switch-away for that resource, regardless of the Untitled/isRestoringSessionLayout gates. No feature-gating is needed: _replacedSessionResources and this switch-away guard are not scoped to chat-layout-enabled mode already, so the fix applies uniformly to both the disabled/legacy and enabled paths, matching the existing same-resource regression test. Add a regression test proving a cross-resource promotion's blacklist marker is consumed even when the draft is Untitled, so a later session reusing that resource still gets its own outgoing working-set save. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add real working-set handle lifetime and delayed-hydration proofs Extend the test harness to track real deleteWorkingSet calls and to make workspace-folder readiness mutable/firable instead of a frozen closure, then use that to add two genuine production-path proofs: - a confirmed peer-chat deletion now asserts, via the real IEditorGroupsService.deleteWorkingSet call list, that only the deleted peer's own working-set handle is deleted, leaving the main chat's working-set handle untouched and still applicable when switching back to it. - the workspace-gated working-set apply, previously only proven to hold back while a session's workspace folder is unregistered, is now also proven to fire correctly for the still-current session's own previously-saved working set once that folder later arrives, rather than staying stuck or applying a stale/empty one. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix main-chat deletion from destroying shared working-set handle; prove delayed peer catalog hydration - onDidDeleteChat no longer treats deletion of a session's own main-chat entity as session-level cleanup; it now early-returns, leaving the shared/legacy working-set handle intact. Genuine session removal/archive continues to delete it via the existing onDidChangeSessions path. - Add a test proving the fix (handle survives main-chat-only deletion, still deleted on session removal) and a test proving promotion that collapses a peer key onto an already-used owner key never calls the destructive deleteWorkingSet API. - Add a test proving a persisted peer-chat owner record (working set, panel view, panel visibility, composition) survives controller startup before the peer chat is observed in the session's chat catalog, and is correctly applied once the peer is added and focused. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Implement reference-counted working-set handle lifetime; restore R8 main-chat deletion clearing Replace the unconditional destructive deleteWorkingSet call in _deleteWorkingSet with reference-counted release semantics: a working-set handle id carried forward from the frozen legacy (disabled-mode) storage key, or still tracked under another live owner key, is never destroyed; only a genuinely unreferenced handle is. Apply the same release logic to _remapOwnerKeyState's promotion-collision overwrite so an orphaned pre-existing destination handle is correctly freed instead of leaked. Revert the previous commit's main-chat deletion no-op exemption in onDidDeleteChat back to always computing and forgetting the owner key (matching R8: deletion clears the exact owner's refs, with no main-chat exemption); this is now safe because the underlying delete is reference-counted. Replace the two stale tests from the prior commit with three that prove the corrected behaviour: a legacy-referenced handle survives an ordinary outgoing overwrite while its fresh replacement is still freed once unreferenced; deleting a session's main chat entity now clears its own tracked working set per R8 while leaving a legacy-referenced handle untouched; and a promotion collision frees the orphaned pre-existing destination handle exactly once while never destroying the incoming handle, with the surviving handle still cleaned up exactly once later. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Collect legacy-referenced working-set ids unconditionally on load Previously _legacyReferencedWorkingSetIds was only populated inside the legacy-fallback branch of _loadState(), which is skipped whenever the versioned chat-layout key already has its own entries and returns early. On a reload where both the frozen legacy key and the versioned key reference the same working-set handle, the handle would lose its legacy-referenced protection and could be destroyed on the next outgoing overwrite or delete. _collectLegacyReferencedWorkingSetIds() now performs a read-only scan of the legacy storage key, independent of which _loadState() branch subsequently loads or returns, and is invoked unconditionally as the first step of _loadState(). Also removes the two JSDoc comments previously added to _legacyReferencedWorkingSetIds and _isWorkingSetStillReferenced. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove extra blank line at EOF in chatLayoutOwnership.test.ts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Document chat-specific layout ownership and persistence contracts Define focused-chat layout and terminal ownership, startup presentation and phone suspension, legacy compatibility, versioned persistence, and confirmed-delete/remap lifecycles. Preserve shared geometry and transient Quick Chat behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make experimental chat-specific layout window scoped Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove chat-specific layout reload notification Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Implement shared and per-chat layout modes Freeze the unreleased window setting as disabled, shared, or per-chat until manual reload. Keep editor working sets, selected panel views, and terminal ownership per chat while sharing existing-workspace pane composition and bottom visibility in shared mode, with independent mode persistence. Capture outgoing ordinary editors on same-session chat switches and prove lifecycle, managed-tab, reload isolation, suspension, and terminal/task ownership paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Document shared and per-chat layout modes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rename chat layout setting to sessions.layout.mode Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify experimental session layout scope setting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Align chat-scoped layout with session behavior Reuse session visibility defaults and lifecycle transitions with chat owner keys; preserve saved owner state and shared visibility mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Restore original terminals and fix scoped layout restoration Keep terminal and task behavior unchanged across layout scopes. Preserve pinned editors when queued Details-only collapse becomes stale, and support isolated recorded layout validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Preserve chat layout state through owner lifecycle changes Retain collapsed editors per chat, transfer main owner state on promotion, and register persisted peer keys independently of catalog hydration. Cover regressions and both hydration visibility states. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Make workspace hydration pane-state assertions explicit Verify default managed tabs after restoring an empty editor group with Details visible, with and without Editor content. Preserve the existing empty-group and Details-only rules. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Clarify shared-visibility layout mode names Rename the unchanged default to session-shared alongside chat-shared and chat. Keep all layout policies and persistence unchanged; update enum descriptions, tests and documentation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Hide the bottom panel when no chat owns the layout Preserve saved visibility when the active session clears, and align first-visit documentation with Existing defaults. Add regressions for both chat modes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Isolate layout schema tests from registry resets Capture registered configuration before other suites clear the shared registry, following existing Sessions schema-test patterns. Reproduces and fixes Linux Electron and macOS WebKit CI failures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>