| 82 | // --------------------------------------------------------------------------- |
| 83 | |
| 84 | function cloneState(s: KimiClientState): KimiClientState { |
| 85 | return { |
| 86 | ...s, |
| 87 | // Reuse the `sessions` array reference when an event does not touch it. |
| 88 | // Every session-mutating case below already builds its own array via |
| 89 | // `[...]` / `.map` / `.filter`, so sharing the reference is safe — and it |
| 90 | // keeps `rawState.sessions` stable for events that don't change sessions, |
| 91 | // so the sidebar computeds (sessionsForView / workspaceGroups / |
| 92 | // mergedWorkspaces) are not dirtied by unrelated events. |
| 93 | sessions: s.sessions, |
| 94 | messagesBySession: { ...s.messagesBySession }, |
| 95 | approvalsBySession: { ...s.approvalsBySession }, |
| 96 | planReviewByToolCallId: { ...s.planReviewByToolCallId }, |
| 97 | questionsBySession: { ...s.questionsBySession }, |
| 98 | tasksBySession: { ...s.tasksBySession }, |
| 99 | goalBySession: { ...s.goalBySession }, |
| 100 | lastSeqBySession: { ...s.lastSeqBySession }, |
| 101 | compactionBySession: { ...s.compactionBySession }, |
| 102 | warnings: [...s.warnings], |
| 103 | }; |
| 104 | } |
| 105 | |
| 106 | function advanceSeq(state: KimiClientState, sessionId: string | undefined, seq: number | undefined): void { |
| 107 | if (sessionId !== undefined && seq !== undefined && seq > 0) { |