* Debt: Remove workspacePickerInput from chatInputPart
* Remove dead renderTrigger code
* Cleanup: Consolidate into a single pickeractionviewitem class
* signing commit
Add best practice: never anchor :has() on body or a workbench-wide root
A body:has() selector forces the style engine to re-evaluate against the whole
document on nearly every DOM mutation, degrading workbench interaction perf even
in builds where the feature is disabled. Document the class-on-container
alternative under the Styling best practices.
* sessions: rename single-pane detail context key to HasDockedDetailsContext
Rename SinglePaneDetailChangesOrFilesActiveContext (raw key
agentSessionsSinglePaneDetailChangesOrFiles) to HasDockedDetailsContext
(raw key agentSessionsHasDockedDetails) to better convey its meaning:
whether the single-pane active editor has a docked detail panel. Updates
the producer, both consumers (Toggle Details, Hide Editor), tests and docs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: align docs and test terminology with HasDockedDetailsContext
Address review feedback: update SINGLE_PANE_SCENARIOS.md to describe the
new intent (active editor has a docked detail panel — a managed
Changes/Files tab or a text file editor) instead of the old
Changes/Files-target wording, and rename the test helpers
(isChangesOrFilesActive -> hasDockedDetails) and snapshot property
(gatedOnChangesOrFilesTab -> gatedOnDockedDetails).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* editor: reuse toggle.diff.renderSideBySide in the Agents window Changes editor
Introduce IDiffEditorCommandsService so the workbench toggle.diff.renderSideBySide
command works in the Agents window multi-diff Changes editor, fixing #324765 (a
user's keybinding for that command now carries over). The base impl is registered
by a workbench-only contribution (diffEditor.workbench.contribution) and the Agents
window contributes its own impl (diffEditor.sessions.contribution) that flips the
workspace diffEditor.renderSideBySide setting, which the Changes editor observes.
The Changes header button and command palette entry now use the shared command id
instead of a custom action, and the accessibility help references it.
Only toggleRenderSideBySide is extracted for now; a follow-up will move the
remaining diff-editor command handlers into the service.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: add behavioral tests for the diff toggle override
Addresses CCR feedback: the menu tests only checked the shared command id
was referenced. Add focused tests for SessionsDiffEditorCommandsService that
invoke toggleRenderSideBySide with a SessionChangesEditor active and assert the
workspace diffEditor.renderSideBySide setting is flipped (both directions), and
that a non-Changes editor falls back to the base path.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: align read-only chat banner with the tab strip
Inset the read-only chat banner's left edge to match the chat tab
strip's padding-left so the banner begins under the first tab rather
than under the header's status-icon column. The right edge already
matched the tab strip's padding-right, so the banner now starts and
ends flush with the tabs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: trim read-only banner alignment comment
Condense the verbose comment on the banner's margin per CCR feedback;
keep only the non-obvious intent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix Modern UI tab decoration color on full label.
Modern UI style overrides forced tab label link colors with !important, which overrode file decoration colors so only badges stayed tinted. Skip decorated labels and inherit the decoration color across the full tab label.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Stop defaulting to copilot
* Render the SessionTypePicker
* Automations: Wire in the sessiontypepicker
* Remove session type binder in favor of session type picker
* Permission label updates when selecting a new session type
* Use MobileSessionTypePicker for phone-layout bottom sheet support
The automation dialog was using the desktop-only SessionTypePicker
directly. The rest of the codebase uses MobileSessionTypePicker which
renders a bottom sheet on phone layouts and falls back to the desktop
action-widget popup otherwise. Swap to the mobile-aware subclass so
the automation picker behaves consistently on all viewports.
* Allow clearing provider and session type
* Prevent automations session type pick to change new session store
* Keep picker in sync when late providers advertise session types
* signing commit
`TokenStore._getSessionFromToken` derived a session's scopes with a truthiness
check on `token.scope`. When a session is created for an empty scope request,
`createSession` (and the refresh path) overwrite `token.scope` with the requested
value, i.e. the empty string. Because `''` is falsy, the deriver ignored the
stored value and fell back to the granted scopes embedded in the JWT claims.
For a server that advertises no scopes but still grants some (e.g. Descope-backed
MCP servers), this produced a session whose scopes were non-empty even though the
request — and every subsequent lookup — used empty scopes. `getSessions` filters
by exact scope-array equality, so the session could never be found: each request
re-triggered a full sign-in, looping forever. Servers that advertise scopes, or
that don't embed scopes in the token's JWT, never hit the seam.
Honor an explicitly-set (possibly empty) `token.scope` and only fall back to the
JWT claims when `scope` is genuinely absent (`undefined`).
Adds a TokenStore unit test covering all three cases (empty, absent, non-empty
scope) through the public `sessions` getter.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* sessions: move Create Pull Request bar to the editor tabs title
Host the Changes 'Create Pull Request' button bar (ChangesActionsBar) in
the single-pane editor tabs title (the editor-actions area of the docked
tab bar, Menus.SessionsEditorTitle) instead of the session title bar.
- Contribute the CHANGES_HEADER_ACTIONS_ID anchor action to
Menus.SessionsEditorTitle, gated on the Changes editor being active in
single-pane (singlePaneChangesEditorTitle) + SessionHasChangesContext.
- Provide the custom action view item (ChangesActionsBarActionViewItem)
from SessionChangesEditor.getActionViewItem so the group's editor-actions
toolbar renders it.
- Collapse the button labels to icon-only when the tabs title is narrow: a
ResizeObserver on the tab-bar ancestor drives a compact observable that
the button-bar widgets read to strip labels, freeing room for tabs.
- Adjust the ChangesActionsBar CSS comments/scoping for the editor tabs
title host.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Make the button responsive
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com>
* sessions: model docked (Changes/Files) editors as DockedEditorInput
Replace the ad-hoc reveal-suppression predicate (setEditorRevealOnOpenExclusion) with a proper DockedEditorInput base class that the Changes and Files editors extend. The single-pane workbench owns the policy: revealEditorOnOpen (renamed from _handleWillOpenEditor, now protected) is overridden so activating a docked editor does not reveal the editor area only while the detail panel is open and the editor area is closed. When the detail panel is closed, opening a docked editor reveals it as usual.
Also drive the editor-area collapse strategy off 'instanceof DockedEditorInput' instead of the coordinator's isManagedEditor heuristic, and close every non-docked editor when the editor area hides (restoring the ones that can be re-resolved from a resource; non-restorable ones such as an untitled Search editor are dropped since they can neither be serialized nor reopened after disposal).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address CCR feedback on docked-editor docs/comments
Fix stale references left by the DockedEditorInput refactor:
- workbench.ts onWillOpenEditor comment now describes the base reveal and points to the SinglePaneWorkbench.revealEditorOnOpen override (the base no longer special-cases the Files tab).
- LAYOUT.md editor-area tab collapse now references SinglePaneEditorAreaCollapseStrategy._collapseNonManagedTabs / _restoreCollapsedTabs instead of the non-existent SinglePaneLayoutController._registerEditorAreaTabCollapse.
- SKILL.md 'Explicit managed-editor opens' entry now describes DockedEditorInput / the SinglePaneWorkbench override instead of the removed _handleWillOpenEditor exclusion.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* MCP: preserve authorization server context on auth re-validation
When AuthenticationService fires onDidChangeSessions for a provider,
MainThreadMcp re-validates every tracked MCP server using that provider. That
re-validation was calling _getSessionForProvider with authorizationServer (and
resource/clientId/audience/clientSecret) dropped, so the silent token request
lost the tenant-specific authority the session was created with and fell back
to the provider default -- e.g. the Microsoft provider's `organizations`
tenant. Depending on the account/tenant relationship this either silently
targets the wrong authority or, for a single-tenant app with a B2B guest,
fails and tears down an otherwise-working MCP server.
Capture the auth context (authorization server, client id, resource, audience,
and the secret-storage key -- not the secret value) when a server's session is
established, and replay it on re-validation. The secret is re-read from storage
by key so a secret rotated via the "Set Client Secret" code lens takes effect
immediately instead of replaying a stale value.
Adds a McpServerAuthTracker unit test covering context round-trip, replacement,
and untracking.
Fixes#324925
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Address review: drop inert client-secret replay, add re-validation test
- The re-read-secret-by-key logic did not actually update a dynamic DCR
provider: DynamicAuthProvider.getSessions ignores its options and the
refresh-token exchange uses the constructor-cached secret. So replaying a
freshly-read secret on re-validation was inert and misleading. Remove the
clientSecretKey tracking; the authorization server / resource / client id /
audience replay (the actual #324925 fix) is unchanged.
- Add a MainThreadMcp re-validation test that drives _onDidChangeAuthSessions
and asserts the tracked context is forwarded to getSessions. The original
regression (dropping an argument) would leave the tracker-only tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Reveal Files view when empty file editor is opened in single-pane layout
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: reveal Files detail when the empty Files editor becomes active
In the single-pane layout, the empty Files editor placeholder shows a
"Select a file..." landing tab whose content (the Files tree) lives in
the detail panel (auxiliary bar). Opening it while the detail was closed
was a dead end. The detail-panel strategy now reveals the Files detail
when the placeholder becomes the active editor, so the `+` Files action
and selecting the Files tab both surface the Files view.
Keyed on the active-editor signal so the managed auto-ensured Files tab
(opened inactive as a background tab) never triggers it, preserving the
Editor-only default; hiding the detail sticks; and it is skipped while
the whole side pane is closed or during a session-switch restore.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: trim inline comment on the Files-detail reveal listener
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: add Open Pull Request to session context menu
Right-clicking a session in the sessions list now shows an Open Pull
Request action (in the top navigation/open group) when the session is
associated with a GitHub pull request, gated on the new
sessionHasPullRequest context key overlay.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: use shared Menus registry for context menu id; trim comment
Address PR feedback: alias SessionItemContextMenu in the shared
Menus registry (browser/menus.ts) instead of importing MenuId.* directly,
and remove the redundant inline comment narrating the fallback logic.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: remember Changes editor view state across scenarios
The Agents-window single-pane Changes editor (SessionChangesEditor) extended
plain EditorPane and never persisted its multi-diff view state, so per-file
collapsed state, scroll position, selections and the active file were lost on
window reload, session switch, side-pane toggle, and reopening the editor.
- SessionChangesEditor now extends AbstractEditorWithViewState, keyed by the
per-session multiDiffSource resource, tracking disposed state so it survives
the tab being closed/disposed on a session switch. It also persists on hide
and defers focus until the active diff editor renders.
- Persist the active diff item in IMultiDiffEditorViewState and restore it once
the (possibly async) diffs load, which suppresses the widget's automatic
first-change navigation so restored scroll/collapsed state wins.
- Apply the view model and restored view state in a single transaction so the
first-change navigation sees the restored active item instead of navigating to
and focusing the first file. This also fixes the same latent ordering bug in
the standard workbench MultiDiffEditor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address Changes editor view-state review feedback
- Restore the saved scroll offset as pending state applied once the scrollable
dimensions are known, instead of inside the model transaction. On a fresh or
reloaded widget scrollHeight is 0 at that point, so the offset was clamped to 0
and the overall scroll position was lost on reload.
- Clear the cached restoration state (documents, active item, scroll) when a new
model is installed without a view state, so a session with no saved state can
no longer inherit the previous model's collapsed/selection/scroll state for
overlapping diff keys (common within the same workspace).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: single source of truth for single-pane layout enablement
Introduce a dedicated SinglePaneLayoutEnabledContext context key and route
all single-pane layout gating through the workbench's decision instead of
reading the sessions.layout.singlePaneDetailPanel setting in many places.
- The setting is now read exactly once, in createSessionsWorkbench, which
picks the workbench variant. That choice is published as
IAgentWorkbenchLayoutService.isSinglePaneLayoutEnabled (for imperative code)
and the new SinglePaneLayoutEnabledContext context key (for declarative
when clauses only).
- Declarative when consumers (layoutActions, editor/codeReview/changes
contributions, responsive sidebar) now gate on the context key.
- Imperative consumers (editorParts, paneCompositePartService,
sessionChangesService, sessionChangesEditor, layout contribution) now read
isSinglePaneLayoutEnabled off the layout service.
- Removed the redundant shouldUseSinglePaneLayout helper (inlined into the
factory) so the setting is not re-evaluated at multiple construction sites.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address PR feedback
- Check single-pane layout before the mobile branch so single-pane parts get
their strategies on mobile web >= 640px.
- Trim JSDoc/inline comments per the sessions comment guidelines.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: bridge extension editor/title actions into single-pane editor menu
In the single-pane layout the editor group renders its title actions from
Menus.SessionsEditorTitle instead of the core MenuId.EditorTitle, which dropped
editor/title actions contributed by extensions. Add EditorTitleMenuBridgeContribution
(in the common editor.contribution.ts) that mirrors only the extension-contributed
items (identified by command.source) from MenuId.EditorTitle into
Menus.SessionsEditorTitle, kept in sync as extensions register/unregister.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: bridge extension editor/title submenus and shorten JSDoc
Also mirror extension-contributed submenus (identified by their api:-prefixed
submenu id) into the single-pane editor title menu, not just command items.
Shorten the contribution JSDoc per repo guidance (details live in LAYOUT.md).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: default the single-pane side pane to 60% and persist its width reliably
Make the single-pane side pane (docked editor part) open at a comfortable
60% of the window width and keep its size workbench-wide across session
switches and reloads.
- First reveal of the side pane uses 60% of the window width
(`INITIAL_EDITOR_WIDTH_RATIO`) instead of a 50% main-area split.
- Side-pane width is workbench-global (`workbench.sessions.partSizes`), so
switching sessions keeps the same width; hiding the pane in one session no
longer resets another session's width on return.
- Fix persistence: `_persistedGridViewSize` is a single overridable read for
all parts, and single-pane returns its docked auxiliary-bar width from the
docked layout state instead of the grid (the docked aux bar is not a grid
view, so reading it threw 'View not found' and aborted the whole save,
losing the editor width).
- Restore-side guards a stale/corrupt sub-minimum saved editor width (e.g. a
persisted 0) by falling back to the default instead of collapsing to the
300px minimum on reload.
- `_persistedEditorWidth` subtracts the docked detail width only when the
detail is visible, mirroring the grid descriptor, so an Editor-only session
no longer shrinks by the detail width on every reload.
- Double-clicking the chat/side-pane sash resets the side pane to 60% via a
`preferredWidth` on `SinglePaneMainEditorPart` (single-pane only; the
classic layout keeps the standard distribute).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address side-pane sizing review feedback
- Move editor/side-pane sizing constants into a shared leaf module
(parts/editorPartSizing.ts) so the reveal split and the sash
double-click reset can't drift apart.
- Keep the base grid layout's classic even split of the main area; scope
the 60%-of-window side-pane split to the single-pane override.
- Preserve the last valid global editor width whenever a measurement is
sub-minimum (e.g. editor hidden with detail visible), instead of only
when the editor part is visible, so a hidden editor never persists 0.
- Remove a duplicate JSDoc opener on _applyEditorSplitSize.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In the single-pane (docked detail) layout, the editor tab strip scrolls
horizontally when there are more tabs than fit. The sticky "+" add-tab
button had a transparent background, so overflowing tabs rendered on top
of / bled through it. Give the sticky add-tab an opaque editor-background
so tabs scrolling underneath are properly occluded.
Also move the agent-sessions editor tab styling out of the generic
browser/media/style.css into a dedicated editorTabs.css next to the
sessions editor contribution that owns the tab strip + add-tab control.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>