sessions: Add mobile-compatible layout for agent sessions#309344
sessions: Add mobile-compatible layout for agent sessions#309344
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a mobile/PWA-friendly layout to the Agents Sessions standalone window (vs/sessions) and extends the web sessions entrypoint to discover/connect remote agent hosts in browser contexts.
Changes:
- Introduces a mobile layout policy + mobile chrome (top bar, drawer sidebar, viewport/keyboard context keys) and a phone-first CSS layer.
- Gates several desktop-only views/actions on mobile via
IsMobileLayoutContext.negate(). - Adds browser implementations for remote agent host connectivity (WebSocket transport + service) and web host discovery wiring in
sessions.web.main.ts.
Show a summary per file
| File | Description |
|---|---|
| src/vs/sessions/sessions.web.main.ts | Registers browser remote-agent-host services and sessions web contributions. |
| src/vs/sessions/MOBILE.md | Documents the mobile architecture, parts, gating, and remaining work. |
| src/vs/sessions/contrib/welcome/browser/welcome.contribution.ts | Skips welcome overlay when an existing GitHub session is detected. |
| src/vs/sessions/contrib/welcome/browser/sessionsWalkthrough.ts | Adds fallback device-code sign-in flow and remote host connection bootstrap. |
| src/vs/sessions/contrib/webHostDiscovery/browser/webHostDiscovery.contribution.ts | New workbench contribution to discover hosts from registry on web. |
| src/vs/sessions/contrib/terminal/browser/sessionsTerminalContribution.ts | Hides “Open session in terminal” action on mobile layout. |
| src/vs/sessions/contrib/sessions/browser/media/sessionsList.css | Makes list inline actions always visible + touch feedback on mobile. |
| src/vs/sessions/contrib/logs/browser/logs.contribution.ts | Gating logs view container off on mobile. |
| src/vs/sessions/contrib/files/browser/files.contribution.ts | Gating files view off on mobile. |
| src/vs/sessions/contrib/codeReview/browser/codeReview.contributions.ts | Gating code-review toolbar actions off on mobile. |
| src/vs/sessions/contrib/chat/browser/chat.contribution.ts | Gating “Open in VS Code” action off on mobile. |
| src/vs/sessions/contrib/changes/browser/changesView.contribution.ts | Gating changes view off on mobile. |
| src/vs/sessions/common/contextkeys.ts | Adds viewport/mobile/keyboard context keys for mobile layout. |
| src/vs/sessions/browser/workbench.ts | Core mobile layout integration: classes, top bar, drawer behavior, theme-color updates. |
| src/vs/sessions/browser/parts/mobile/mobileTopBar.ts | New mobile top bar component. |
| src/vs/sessions/browser/parts/mobile/mobileSidebarPart.ts | Mobile sidebar part variant with reduced inline styling. |
| src/vs/sessions/browser/parts/mobile/mobilePanelPart.ts | Mobile panel part variant with full-bleed layout behavior. |
| src/vs/sessions/browser/parts/mobile/mobileChatShell.css | New phone-layout CSS source-of-truth. |
| src/vs/sessions/browser/parts/mobile/mobileChatBarPart.ts | Mobile chat bar part variant with full-bleed layout behavior. |
| src/vs/sessions/browser/parts/mobile/mobileAuxiliaryBarPart.ts | Mobile auxiliary bar part variant with full-bleed layout behavior. |
| src/vs/sessions/browser/parts/media/titlebarpart.css | Phone overrides for titlebar structure (even though hidden on phone). |
| src/vs/sessions/browser/parts/media/sidebarPart.css | Implements phone sidebar drawer overlay + backdrop styling. |
| src/vs/sessions/browser/parts/chatBarPart.ts | Makes _lastLayout protected for mobile subclass access. |
| src/vs/sessions/browser/paneCompositePartService.ts | Chooses mobile vs desktop part classes at construction for phone widths. |
| src/vs/sessions/browser/mobileNavigationStack.ts | New history-backed overlay stack for Android back button behavior. |
| src/vs/sessions/browser/media/style.css | Mobile quick pick/context menu/dialog/toast/editor-modal styling. |
| src/vs/sessions/browser/layoutPolicy.ts | New SessionsLayoutPolicy for viewport classification and defaults. |
| src/vs/platform/agentHost/common/state/sessionTransport.ts | Extends transport send typing to include JSON-RPC notifications. |
| src/vs/platform/agentHost/browser/webSocketClientTransport.ts | New browser WebSocket transport for agent-host protocol messages. |
| src/vs/platform/agentHost/browser/remoteAgentHostServiceImpl.ts | New browser remote agent host service implementation. |
| src/vs/platform/agentHost/browser/remoteAgentHostProtocolClient.ts | New protocol client wrapping transport + JSON-RPC request/notify handling. |
| src/vs/platform/agentHost/browser/nullSshRemoteAgentHostService.ts | Browser null service for SSH remote agent host support. |
| src/vs/code/browser/workbench/workbench.html | Adds viewport-fit=cover and an Apple startup image link. |
| resources/server/manifest.json | Adds PWA theme/background/orientation metadata. |
| extensions/copilot/package-lock.json | Lockfile updates (dev flags added on some deps). |
Copilot's findings
Files not reviewed (1)
- extensions/copilot/package-lock.json: Language not supported
Comments suppressed due to low confidence (5)
src/vs/sessions/browser/parts/mobile/mobileTopBar.ts:52
- The default session title string
'New Session'is user-facing and should be localized (and ideally wired to the active session title when available).
this.sessionTitleElement = append(this.element, $('div.mobile-session-title'));
this.sessionTitleElement.textContent = 'New Session';
this.sessionTitleElement.addEventListener('click', () => this._onDidClickTitle.fire());
src/vs/sessions/browser/parts/mobile/mobileTopBar.ts:57
- The new session button’s
aria-labelis user-facing text but is not localized. Please externalize it vialocalize(...).
const newSession = append(this.element, $('button.mobile-top-bar-button'));
newSession.setAttribute('aria-label', 'New session');
const newSessionIcon = append(newSession, $('span'));
src/vs/sessions/contrib/welcome/browser/welcome.contribution.ts:107
- Same floating-promise issue here:
_hasExistingGitHubSession().then(...)is not awaited and has no.catch(...). Considervoid ...and a rejection handler to avoid unhandled rejections.
src/vs/sessions/contrib/welcome/browser/sessionsWalkthrough.ts:344 - The access token is included in the WebSocket proxy URL as a query parameter (
token=...). Tokens in URLs can leak via logs, intermediaries, and referrers. Prefer passing tokens via headers during the WebSocket upgrade (if supported) or using a short-lived one-time code instead of the raw token in the URL.
src/vs/sessions/contrib/webHostDiscovery/browser/webHostDiscovery.contribution.ts:118 _waitForToken()pollslocalStoragefor a token. Since this token is security-sensitive, prefer reading fromISecretStorageService(encrypted) or another protected channel rather than relying on plainlocalStorage.
- Files reviewed: 34/35 changed files
- Comments generated: 10
2b01d20 to
d21ff73
Compare
1841ffb to
2c61bc5
Compare
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (1)
src/vs/sessions/browser/parts/mobile/mobileTopBar.ts:52
- The mobile top bar title is always initialized to "New Session" and never updated, so it will be incorrect once a real session becomes active. Since
ISessionsManagementService.activeSessionalready exists, consider wiringMobileTopBar.setTitle(...)to the active session (and/or active chat) so the top bar reflects the current session.
// Session title
this.sessionTitleElement = append(this.element, $('div.mobile-session-title'));
this.sessionTitleElement.textContent = 'New Session';
this.sessionTitleElement.addEventListener('click', () => this._onDidClickTitle.fire());
- Files reviewed: 25/25 changed files
- Comments generated: 5
Introduce a responsive mobile layout for the agent sessions window, enabling a native app-like experience when accessed via mobile browsers or installed as a PWA. The implementation uses mobile Part subclasses, a MobileTopBar chrome component, CSS overrides, and when-clause gating to progressively enhance the desktop sessions workbench for phone viewports. Key changes: Layout policy & viewport detection: - SessionsLayoutPolicy with observable viewport classification (phone <640px, tablet 640-1024, desktop >1024) - Context keys: ViewportClassContext, IsMobileLayoutContext, KeyboardVisibleContext - Runtime viewport class change detection in layout() Mobile chrome components: - MobileTopBar: hamburger + session title + new session (+) - MobileNavigationStack: history.pushState integration for Android back button - Sidebar drawer overlay with backdrop dismiss Mobile Part subclasses: - MobileChatBarPart, MobileSidebarPart, MobileAuxiliaryBarPart, MobilePanelPart override layout()/updateStyles() only - AgenticPaneCompositePartService conditionally instantiates mobile vs desktop Parts View gating: - Desktop-only views hidden on mobile via IsMobileLayoutContext: Changes, Files, Logs, Terminal, Code Review, Open in VS Code - Customization toolbar hidden via CSS on phone CSS & PWA: - Edge-to-edge chat (no card chrome on phone) - Safe area insets, touch targets (44px min), overscroll containment - PWA manifest with standalone display mode - viewport-fit=cover meta tag - Dynamic theme-color meta created programmatically Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove agentHost WebSocket implementation, webHostDiscovery contribution, welcome/walkthrough OAuth flow changes, PWA manifest updates, and lock file noise — none of these are related to mobile layout components for the agents workbench. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These files exist in main and were not introduced by this PR. They were mistakenly removed during out-of-scope cleanup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Revert copilot package-lock.json to main (unrelated npm artifact) - Revert agentHost remoteAgentHostProtocolClient.ts (diffs field not mobile-related) - Revert agentHost sessionTransport.ts (protocol cleanup not mobile-related) - Remove theme-color meta element creation and dynamic updates (PWA) - Remove apple-touch-startup-image link injection (PWA) - Remove PWA & Viewport section from MOBILE.md - Keep viewport-fit=cover as it is needed for safe-area-inset CSS on mobile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The mobile phone-layout CSS targeted non-existent class names (chat-full-welcome*) instead of the actual DOM classes used by newChatViewPane.ts and newChatInput.ts. This caused the welcome page to render without the Copilot logo, centering, or bottom-pinned input on phone viewports. Also fixes the logo SVG path and adds dark/light theme support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix isVisible(TITLEBAR_PART) to return false on phone layout where the grid titlebar is hidden and replaced by MobileTopBar - Fix computeContainerOffset() to use MobileTopBar height on phone layout so overlays (quick picks, hovers) are positioned correctly - Add CSS comment block documenting the .mobile-layout vs .phone-layout class hierarchy and when to use each - Add code comment in MobileAuxiliaryBarPart explaining why inline style clearing is needed (parent sets them via JS, CSS can't override) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sal hygiene - Mobile Parts now dispatch at runtime (isPhoneLayout): phone uses mobile layout math, tablet/desktop delegates to super. Fixes 35px chat overlap after phone→landscape rotation across the 640px breakpoint. - Workbench calls updateStyles() on pane composite parts after viewport class transitions so card-chrome inline styles re-apply/clear correctly. - MobileNavigationStack: replace _suppressNextPop boolean with pending counter to handle concurrent popSilently calls and rapid back taps. - Drop redundant Part.prototype.layout.call in mobile Part overrides (AbstractPaneCompositePart.layout already cascades to Part.layout). - Virtual keyboard detection: use mainWindow.innerHeight as baseline instead of captured initialViewportHeight; threshold 150→100. - Sidebar drawer backdrop: managed via DisposableStore with addDisposableListener for its click handler. - MobileTopBar: switch raw addEventListener to addDisposableListener; register element removal before parent.prepend so exceptions still clean up. - Remove redundant matchMedia orientation listener; the window resize listener already handles orientation changes.
f96a8eb to
06f0285
Compare
3177f04 to
6e0dbc9
Compare
| * only applied on actual mobile devices so that resizing a desktop window | ||
| * below 640px does not switch the agents workbench into phone mode. | ||
| */ | ||
| const isMobilePlatform = isIOS || isAndroid; |
There was a problem hiding this comment.
we may want to use platform.isMobile.
There was a problem hiding this comment.
Updated in commit 41760a28: SessionsLayoutPolicy now uses platform.isMobile for mobile layout gating instead of the local iOS/Android check.
Screenshot: https://github.com/user-attachments/assets/538e657c-c808-429c-9c64-a6b8f0eae021
|
@copilot review all the |
…latform flag Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/987a91a6-5cc8-4bb9-8943-ad08b4d6fdca Co-authored-by: rebornix <876920+rebornix@users.noreply.github.com>
Completed in commit Screenshot: https://github.com/user-attachments/assets/538e657c-c808-429c-9c64-a6b8f0eae021 |
|
@copilot are |
Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/e418098f-fd9a-4936-ad37-87b4f6a3a60c Co-authored-by: rebornix <876920+rebornix@users.noreply.github.com>
Not all of them are required, and I already removed the unnecessary ones in Screenshot: https://github.com/user-attachments/assets/9bbef325-dc41-4f1e-8c98-57e1beb3e5f1 |
# Conflicts: # src/vs/sessions/contrib/changes/browser/changes.contribution.ts # src/vs/sessions/contrib/files/browser/files.contribution.ts # src/vs/sessions/contrib/logs/browser/logs.contribution.ts
# Conflicts: # src/vs/sessions/browser/workbench.ts


Revert: #310552
Revert: #310849
Summary
Introduces a responsive mobile layout for the agent sessions window, enabling a native app-like experience when accessed via mobile browsers or installed as a PWA. The implementation uses mobile Part subclasses, a
MobileTopBarchrome component, CSS overrides, andwhen-clause gating to progressively enhance the desktop sessions workbench for phone viewports (<640px).Architecture
The approach avoids forking the workbench — instead it layers mobile behavior on top:
SessionsLayoutPolicy— Observable viewport classification (phone/tablet/desktop) using width breakpoints + platform flagsMobileChatBarPart,MobileSidebarPart,MobileAuxiliaryBarPart,MobilePanelPart) — Override onlylayout()andupdateStyles(), keeping desktop Parts untouchedAgenticPaneCompositePartService— Conditionally instantiates mobile vs desktop Part classes at constructionMobileTopBar— Phone top bar chrome: hamburger (☰) + session title + new session (+)MobileNavigationStack—history.pushStateintegration for Android back button supportwhenclause gating — Desktop-only views (Changes, Files, Logs, Terminal, Code Review, "Open in VS Code") hidden on mobile viaIsMobileLayoutContext.negate()mobileChatShell.css— Single source of truth for all phone-layout CSSKey Changes
SessionsLayoutPolicywith observable viewport class, 3 context keysMobileTopBarwith hamburger/title/+ buttonsMobileNavigationStackwithhistory.pushState/popstateviewport-fit=cover, dynamictheme-colormetaContext Keys Added
ViewportClassContext—'phone'/'tablet'/'desktop'IsMobileLayoutContext—truewhen phone or tabletKeyboardVisibleContext—truewhen virtual keyboard is openTesting
Tested via
npm run servefromsrc/vs/sessions/test/e2ewith Chrome DevTools device emulation (iPhone 14 Pro, Pixel 7). Verified:Known Limitations
MobileTopBarshows hardcoded "New Session" — not yet wired tosessionsManagementService.activeSessionDocumentation
See
src/vs/sessions/MOBILE.mdfor full architecture docs, file map, and remaining work items.