fix: UI/UX improvements, mode/branch fixes, and docs update#6
Merged
fix: UI/UX improvements, mode/branch fixes, and docs update#6
Conversation
- Fix agent/mode/model selectors not reflecting local CLI state: Handle session.mode_changed events from events.jsonl, broadcast via WebSocket, and re-fetch on idle transitions with stale guards - Fix mobile scrolling: prevent page-level overscroll, add overflow-x-hidden to chat, constrain wide content in messages - Fix mobile sidebar not closing on session select: use direct window.matchMedia check instead of potentially stale closure - Fix scroll-to-bottom after history load: use double RAF for reliable DOM layout timing - Move branch info from session cards to directory picker: add branch aggregation to /directories endpoint - Add background task indicator: wire subagent.started/completed events through server to client, show task count badge in header Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix session.mode_changed event parsing: use data.newMode (not data.mode) - Add sessionConfigs fallback map for mode when bridge RPCs fail on CLI-owned sessions (seeded from events.jsonl on subscribe) - Return graceful defaults instead of throwing when RPC fallback has no data (empty mode hides switcher; empty agent shows default) - Fix /directories endpoint: use getLiveBranch() for real git branch instead of stale session metadata snapshot - Restyle DirectoryPicker: branch shown below folder name in muted color instead of inline with session count Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bridge RPC returns the secondary handle's default mode ("interactive"),
not the actual CLI mode. Also, REST getSessionMode could fire before
WS subscribe triggers startPolling/seedStateFromFile, leaving the
sessionConfigs map empty.
- Invert priority: check sessionConfigs (events.jsonl truth) before RPC
- Add ensureConfigSeeded() to lazily read events.jsonl on first RPC call
- Same treatment for getSessionAgent for consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tate - README: add missing env vars (CLI_URL, MCP_SERVERS, EXCLUDED_TOOLS, AGENT_PLUGIN_DIRS) - AGENTS.md: add TLS env vars, fix event types (assistant.turn_end not session.idle), add session.mode_changed and subagent events - API.md: add missing endpoints (GET /agents, GET /status, POST /reload-agents), add 8 missing WS server→client message types (history, config_changed, tasks_changed, reasoning, plan_changed, etc.) - ARCHITECTURE.md: add DirectoryPicker to sessions component list Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves the web UI’s mobile usability and keeps the UI in sync with CLI-driven session state by expanding the server/client WebSocket protocol (config + background task count) and updating documentation accordingly.
Changes:
- Add mobile scrolling/layout fixes (scroll containment, markdown overflow handling, double-RAF scroll-to-bottom).
- Sync session mode changes from
events.jsonlto the UI via newconfig_changedWS messages; addtasks_changedWS messages for background task count. - Move git branch display to the directory picker and enrich
/directorieswith live branch resolution; update docs (API/events/env vars).
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| server/src/types.ts | Adds new event + WS message types for config_changed and tasks_changed. |
| server/src/core/session-manager.ts | Tracks session config fallback from events.jsonl; emits new WS events; tracks subagent task counts. |
| server/src/channels/web/ws-handler.ts | Broadcasts new config_changed / tasks_changed events to subscribed clients. |
| server/src/channels/web/routes.ts | Enriches /directories response with live git branch values. |
| client/src/types.ts | Extends client WS message union + directory info shape with branch. |
| client/src/hooks/useWebSocket.ts | Handles new WS message types and exposes activeTaskCount + onConfigChanged. |
| client/src/components/layout/AppShell.tsx | Reacts to config updates, improves mobile sidebar closing, refetches config on idle transitions, shows background task badge. |
| client/src/components/sessions/SessionList.tsx | Removes branch display from session cards. |
| client/src/components/sessions/DirectoryPicker.tsx | Displays branch beneath directory name with git icon. |
| client/src/components/chat/ChatPanel.tsx | Improves scroll-to-bottom reliability and horizontal overflow behavior. |
| client/src/components/chat/MessageBubble.tsx | Improves markdown overflow/word-breaking; adds table scrolling behavior. |
| client/src/app.css | Locks body/html scrolling and overscroll behavior for mobile. |
| docs/API.md | Documents additional REST endpoints and WS message types. |
| docs/ARCHITECTURE.md | Updates component listing to include DirectoryPicker. |
| README.md | Documents additional environment variables. |
| AGENTS.md | Updates env var list and corrects CLI event type guidance. |
Comments suppressed due to low confidence (2)
client/src/hooks/useWebSocket.ts:249
- Similarly, this
config_changedhandler can use the strongly-typedmsg.sessionId/msg.mode/msg.modelId/msg.agentfields directly instead of casting toany. Keeping the typed access helps catch server/client protocol drift at compile time.
case 'config_changed':
if (configChangedCallback.current) {
configChangedCallback.current({
sessionId: (msg as any).sessionId,
mode: (msg as any).mode,
modelId: (msg as any).modelId,
agent: (msg as any).agent,
});
}
break;
server/src/core/session-manager.ts:848
- getSessionAgent() claims to prefer an events.jsonl-derived agent, but sessionConfigs is never populated with an agent anywhere (only mode is seeded/updated). As written,
if (config?.agent)can never be true, and the comment/field are misleading. Either implement seeding/updating agent from an event that carries it, or remove the agent fallback path and related sessionConfigs.agent field/comment to avoid confusion.
async getSessionAgent(sessionId: string): Promise<{ name?: string; displayName?: string }> {
// Prefer events.jsonl value — ground truth for CLI-owned sessions
this.ensureConfigSeeded(sessionId);
const config = this.sessionConfigs.get(sessionId);
if (config?.agent) return { name: config.agent };
try {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix API.md: plan_changed has no content field, task_complete uses summary not description - Remove unnecessary 'as any' casts in useWebSocket.ts — types already include the fields for tasks_changed and config_changed - Mark sessionConfigs as seeded with empty entry after ensureConfigSeeded to avoid repeated disk I/O on sessions with no mode_changed events Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
UI/UX Improvements
overflow-hidden+overscroll-behavior: noneon html/body,overflow-x-hiddenon chat panel, content containment on message bubbleswindow.matchMediacheck (avoids stale closure)requestAnimationFrameensures scroll after DOM renders historysubagent.started/completedevents, broadcast via WS, show count badge in headerSession State Sync
session.mode_changedevents from events.jsonl (data.newModefield)config_changedWS broadcast when mode changessessionConfigsfallback map for CLI-owned sessions where bridge RPCs return stale defaultsensureConfigSeeded()lazy reader to handle REST/WS timing race/directoriesendpoint usesgetLiveBranch()for real git branch instead of stale metadataDocumentation
assistant.turn_endnotsession.idle)Testing
npm run build)npx vitest run)data.mode→data.newMode), stale idle-refetch race, missing sessionId validation on config_changed