Skip to content

fix: UI/UX improvements, mode/branch fixes, and docs update#6

Merged
ChrisRomp merged 5 commits intomainfrom
fix/more-things-2
Mar 2, 2026
Merged

fix: UI/UX improvements, mode/branch fixes, and docs update#6
ChrisRomp merged 5 commits intomainfrom
fix/more-things-2

Conversation

@ChrisRomp
Copy link
Owner

Changes

UI/UX Improvements

  • Mobile scrolling: Added overflow-hidden + overscroll-behavior: none on html/body, overflow-x-hidden on chat panel, content containment on message bubbles
  • Mobile sidebar: Auto-closes on session selection using direct window.matchMedia check (avoids stale closure)
  • Scroll to bottom: Double requestAnimationFrame ensures scroll after DOM renders history
  • Branch display: Moved from session cards to folder list (DirectoryPicker), shown below folder name in muted color with git icon
  • Background tasks: Track subagent.started/completed events, broadcast via WS, show count badge in header

Session State Sync

  • Handle session.mode_changed events from events.jsonl (data.newMode field)
  • config_changed WS broadcast when mode changes
  • sessionConfigs fallback map for CLI-owned sessions where bridge RPCs return stale defaults
  • ensureConfigSeeded() lazy reader to handle REST/WS timing race
  • /directories endpoint uses getLiveBranch() for real git branch instead of stale metadata
  • Graceful defaults when RPC and fallback both unavailable

Documentation

  • README: Added 5 missing env vars
  • AGENTS.md: Added TLS vars, fixed event types (assistant.turn_end not session.idle)
  • API.md: Added 3 missing REST endpoints, 8 missing WS message types
  • ARCHITECTURE.md: Added DirectoryPicker to component listing

Testing

  • Build passes (npm run build)
  • All 61 tests pass (npx vitest run)
  • Adversarial code review caught and fixed: wrong event field names (data.modedata.newMode), stale idle-refetch race, missing sessionId validation on config_changed

ChrisRomp and others added 4 commits March 1, 2026 22:15
- 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>
Copilot AI review requested due to automatic review settings March 2, 2026 07:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.jsonl to the UI via new config_changed WS messages; add tasks_changed WS messages for background task count.
  • Move git branch display to the directory picker and enrich /directories with 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_changed handler can use the strongly-typed msg.sessionId/msg.mode/msg.modelId/msg.agent fields directly instead of casting to any. 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>
@ChrisRomp ChrisRomp merged commit 1c93b72 into main Mar 2, 2026
5 checks passed
@ChrisRomp ChrisRomp deleted the fix/more-things-2 branch March 2, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants