fix(home-session-switch): 修复 Home 左栏 Sessions 单击无法切换的死链 - #544
Merged
ThreeFish-AI merged 3 commits intoMay 16, 2026
Conversation
- 表因:Home 页左栏单击会话条目后 URL 不更新、对话区被清空、顶部仍显示旧会话——出现"清空但未切换"错位。
- 根因:Next.js 16.2.3 useRouter().replace(target, { scroll: false }) 在「同 pathname、仅 query 变更」场景下会输出 history.replaceState({__NA: true}, "", 旧URL) 的 no-op 路径,浏览器 URL 不更新→useSearchParams 不重派生→sessionId/agent/activeSession 全部维持旧值。
- 处理:app/page.tsx 的 setSessionId 与 useSessionListService 的 setSessionListView 改走 window.history.replaceState 直写浏览器 URL,由 Next.js 14+ App Router 中 useSearchParams 监听 history API 触发派生重渲染;移除两文件不再使用的 useRouter import;单测同步迁移到 spy on window.history.replaceState + 从 window.location.search 派生 useSearchParams,新增 ISSUE-088 / ISSUE-061 v2-D 两条断言。
- 验证:pnpm lint / typecheck / typecheck:test / 644 项单元 + 集成测试全绿;实机用户主 Chrome 真实登录态走 7 个正交场景(初始单击 / 连续切换 / 回到原会话 / Archived 视图切换 / 双击重命名 / 刷新保持 / + New),URL、active 高亮、对话区、State Snapshot、Event Timeline 全链路同步刷新,全部 __NA: true 痕迹消失。
- 文档:docs/issue.md 追加 ISSUE-088 摘要(含 __NA 抓包证据 + 后续防范 + 与 ISSUE-061/062/066 同源关联)。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
…/fix-session-switch-click
…后的相对链接; 合并 origin/feature/1.x.x 后 issue.md 被搬迁到 docs/agents/, 将本期新增 ISSUE-088 中 `../apps/...` 与 `./agents/browser-validation.md` 分别修正为 `../../apps/...` 与 `./browser-validation.md`,恢复跳转有效性。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.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.
背景
/) 左栏 Sessions 列表单击会话条目后 URL 不更新、对话区被清空、顶部仍显示旧会话——出现「清空但未切换」错位状态,单击成为死链;该问题在 Next.js 16.2.3 dev 模式下用mcp__chrome_devtools__click、element.click()、手动dispatchEvent(mousedown→mouseup→click)三种触发方式均稳定复现。feedback_router_replace_race.md。核心变更
history.replaceState抓包验证,Next.js 16.2.3useRouter().replace(target, { scroll: false })在「同 pathname、仅 query 变更」场景下会输出history.replaceState({__NA: true}, "", 旧URL)的 no-op 路径——__NA即 Navigation Aborted,浏览器 URL 不更新 →useSearchParams不重派生 →sessionId/agent/activeSession维持旧值,但handleSessionChange已同步执行clearSessionState()清空 projection,造成「清空但未切换」错位。app/page.tsx的setSessionId与features/session/hooks/useSessionListService.ts的setSessionListView改走window.history.replaceState(null, "", target)直写浏览器 URL,绕开 Next.js 的 RSC 导航判定;由 Next.js 14+ App Router 中useSearchParams监听 history API 变更触发派生重渲染。移除两文件不再使用的useRouterimport 与useCallbackdeps 中的router。router.replace调用(admin/layout.tsx、interface/layout.tsx、interface/task-models/page.tsx、interface/models/page.tsx)都是 pathname 跳转,不在 bug 影响面,保持原样。tests/unit/features/session/useSessionListService.test.ts取消routerReplacemock,改 spy onwindow.history.replaceState+ 从真实window.location.search派生useSearchParams;新增ISSUE-088双路径用例(archived / active)。docs/issue.md追加 ISSUE-088 摘要(含__NA: true抓包证据、后续防范守则、与 061/062/066 的同源关联)。风险与回滚
window.history.replaceState不会触发 Next.js RSC fetch / route cache 刷新——本场景下 sessionId / view 都不绑定服务器渲染段(数据全靠客户端 fetch),因此无影响;如未来某入口同型迁移时其依赖 RSC 重渲,需要保留router.replace走 pathname 级跳转。git revert <commit>即可,仅触及 4 文件、零迁移;回滚后回到「router.replace + __NA no-op」状态(即修复前 bug)。验证证据
pnpm --filter negentropy-ui test全量 87 test files / 644 tests 全绿;其中useSessionListService.test.ts新增「ISSUE-088 archived / active 双路径」断言验证window.history.replaceState调用形状与window.location.search落盘。pnpm --filter negentropy-ui test -- home-flow全绿(未 mock router,使用注入setCurrentSession装具,与本次 wiring 改动正交)。?view=archived入出);⑤双击重命名(onClick + onDoubleClick 双 handler 共存正常);⑥刷新保持 sessionId;⑦+ New 创建新会话并展示空态。每个场景window.__historyCalls抓包显示我们的直写均为naFlag: null+ 正确新 URL,无__NA: true残留。影响范围
apps/negentropy-ui/app/page.tsx、apps/negentropy-ui/features/session/hooks/useSessionListService.ts、apps/negentropy-ui/tests/unit/features/session/useSessionListService.test.ts。docs/issue.md追加 ISSUE-088 摘要;无 CI 配置变更。Next Best Action
useUrlQueryUpdater())放到apps/negentropy-ui/hooks/,让后续 Knowledge / Memory / Interface 页加入?tab=.../?filter=...入口时直接复用,避免每个新入口都踩同一个 Next.js 16 router.replace 坑。