fix(web): show forked session in sidebar immediately#174
Conversation
doFork read the result of request() as the bare SessionInfo, but
request() resolves to the daemon's `response.ok` envelope
({type, requestId, data}) — the fork's SessionInfo is at `.data`. So the
`"id" in data` check was always false: mergeSession/focusSession never
fired and the new fork never entered the store, leaving the sidebar
unchanged (this also hit forking an already-forked session).
Unwrap `.data` before merging + focusing, with a refreshSessions()
fallback for an older daemon (mirrors NewSessionModal). Fork test mocks
now resolve the real response.ok envelope and assert the fork lands in
the store and becomes focused, so the shape mismatch can't regress.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Gemini code reviewThis PR fixes a bug where newly created session forks do not appear in the sidebar or get focused immediately. The issue was caused by Findings: 🔴 0 · 🟠 0 · 🟡 0 · 🟢 0 Tokens spent · ⬆️ Input: 2,570 · ⬇️ Output: 126 · Σ Total: 3,375 |
Exercise the older-daemon path (response.ok with no `.data`) so both branches of doFork's result handling are covered and codecov patch stays green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #174 +/- ##
=======================================
Coverage 84.90% 84.90%
=======================================
Files 106 106
Lines 18678 18678
=======================================
Hits 15858 15858
Misses 2820 2820
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Problem
Forking a session from the web UI did nothing visible — the new fork never appeared in the left sidebar and wasn't focused. Reproduced by forking a session (including forking an already-forked session, e.g. "Exelexis (fork)").
Root cause
request()resolves to the daemon'sresponse.okenvelope ({type, requestId, data}), not the bare payload.ForkButton.doForkchecked"id" in dataon the envelope, but the fork'sSessionInfois nested at.data. So the check was always false →mergeSession/focusSessionnever fired → the fork never entered the store and the sidebar stayed unchanged.NewSessionModalhas the same dead primary branch but survives via arefreshSessions()fallback;doForkhad no fallback, so forks silently vanished.The existing fork tests mocked
requestto resolve the unwrappedSessionInfo, which is why they passed while prod was broken.Fix
doForkunwraps.datafrom the envelope before merging + focusing, with arefreshSessions()fallback for an older daemon / unexpected shape (mirrorsNewSessionModal).response.okenvelope, and the default-fork test asserts the fork lands in the store (getSession("fork-1")) and becomes focused (focusedSession()?.id === "fork-1"), and that the fallback was not taken — so the shape mismatch can't regress.Scope note (follow-up, not this PR)
A brand-new session reaches other attached clients only via their own
session.listrefresh — the daemon broadcastssession.info_updateonly to clients already attached to a session. This is symmetric between create and fork (not a fork regression). A workspace-level "session created" broadcast so a second tab/TUI updates live is a separate enhancement.Verification
web: 220/220 tests pass (32 in SessionControls incl. the new regression assertion).tsc --noEmit: clean.🤖 Generated with Claude Code