@@ -11,6 +11,7 @@ import type {
1111 SessionStatus ,
1212 Todo ,
1313} from "@opencode-ai/sdk/v2/client"
14+ import { applyMessageEvent , type MessageStore } from "@opencode-ai/sdk/event-reducer"
1415import type { State , VcsCache } from "./types"
1516import { trimSessions } from "./session-trim"
1617
@@ -164,99 +165,41 @@ export function applyDirectoryEvent(input: {
164165 input . setStore ( "session_status" , props . sessionID , reconcile ( props . status ) )
165166 break
166167 }
167- case "message.updated" : {
168- const info = ( event . properties as { info : Message } ) . info
169- const messages = input . store . message [ info . sessionID ]
170- if ( ! messages ) {
171- input . setStore ( "message" , info . sessionID , [ info ] )
172- break
168+ case "message.updated" :
169+ case "message.removed" :
170+ case "message.part.updated" :
171+ case "message.part.removed" :
172+ case "message.part.delta" : {
173+ const currentStore : MessageStore = {
174+ messages : input . store . message as Record < string , Message [ ] > ,
175+ parts : input . store . part as Record < string , Part [ ] > ,
173176 }
174- const result = Binary . search ( messages , info . id , ( m ) => m . id )
175- if ( result . found ) {
176- input . setStore ( "message" , info . sessionID , result . index , reconcile ( info ) )
177- break
177+ const next = applyMessageEvent ( currentStore , event )
178+ if ( ! next ) break
179+ // Apply changed message lists to Solid store
180+ for ( const sessionID of Object . keys ( next . messages ) as string [ ] ) {
181+ if ( next . messages [ sessionID ] !== currentStore . messages [ sessionID ] ) {
182+ input . setStore ( "message" , sessionID , reconcile ( next . messages [ sessionID ] , { key : "id" } ) )
183+ }
178184 }
179- input . setStore (
180- "message" ,
181- info . sessionID ,
182- produce ( ( draft ) => {
183- draft . splice ( result . index , 0 , info )
184- } ) ,
185- )
186- break
187- }
188- case "message.removed" : {
189- const props = event . properties as { sessionID : string ; messageID : string }
190- input . setStore (
191- produce ( ( draft ) => {
192- const messages = draft . message [ props . sessionID ]
193- if ( messages ) {
194- const result = Binary . search ( messages , props . messageID , ( m ) => m . id )
195- if ( result . found ) messages . splice ( result . index , 1 )
196- }
197- delete draft . part [ props . messageID ]
198- } ) ,
199- )
200- break
201- }
202- case "message.part.updated" : {
203- const part = ( event . properties as { part : Part } ) . part
204- const parts = input . store . part [ part . messageID ]
205- if ( ! parts ) {
206- input . setStore ( "part" , part . messageID , [ part ] )
207- break
185+ for ( const sessionID of Object . keys ( currentStore . messages ) as string [ ] ) {
186+ if ( ! ( sessionID in next . messages ) ) {
187+ input . setStore ( produce ( ( draft ) => { delete draft . message [ sessionID ] } ) )
188+ }
208189 }
209- const result = Binary . search ( parts , part . id , ( p ) => p . id )
210- if ( result . found ) {
211- input . setStore ( "part" , part . messageID , result . index , reconcile ( part ) )
212- break
190+ // Apply changed part lists to Solid store
191+ for ( const messageID of Object . keys ( next . parts ) as string [ ] ) {
192+ if ( next . parts [ messageID ] !== currentStore . parts [ messageID ] ) {
193+ input . setStore ( "part" , messageID , reconcile ( next . parts [ messageID ] , { key : "id" } ) )
194+ }
213195 }
214- input . setStore (
215- "part" ,
216- part . messageID ,
217- produce ( ( draft ) => {
218- draft . splice ( result . index , 0 , part )
219- } ) ,
220- )
221- break
222- }
223- case "message.part.removed" : {
224- const props = event . properties as { messageID : string ; partID : string }
225- const parts = input . store . part [ props . messageID ]
226- if ( ! parts ) break
227- const result = Binary . search ( parts , props . partID , ( p ) => p . id )
228- if ( result . found ) {
229- input . setStore (
230- produce ( ( draft ) => {
231- const list = draft . part [ props . messageID ]
232- if ( ! list ) return
233- const next = Binary . search ( list , props . partID , ( p ) => p . id )
234- if ( ! next . found ) return
235- list . splice ( next . index , 1 )
236- if ( list . length === 0 ) delete draft . part [ props . messageID ]
237- } ) ,
238- )
196+ for ( const messageID of Object . keys ( currentStore . parts ) as string [ ] ) {
197+ if ( ! ( messageID in next . parts ) ) {
198+ input . setStore ( produce ( ( draft ) => { delete draft . part [ messageID ] } ) )
199+ }
239200 }
240201 break
241202 }
242- case "message.part.delta" : {
243- const props = event . properties as { messageID : string ; partID : string ; field : string ; delta : string }
244- const parts = input . store . part [ props . messageID ]
245- if ( ! parts ) break
246- const result = Binary . search ( parts , props . partID , ( p ) => p . id )
247- if ( ! result . found ) break
248- input . setStore (
249- "part" ,
250- props . messageID ,
251- produce ( ( draft ) => {
252- const part = draft [ result . index ]
253- const field = props . field as keyof typeof part
254- const existing = part [ field ] as string | undefined
255- ; ( part [ field ] as string ) = ( existing ?? "" ) + props . delta
256- } ) ,
257- )
258- break
259- }
260203 case "vcs.branch.updated" : {
261204 const props = event . properties as { branch : string }
262205 if ( input . store . vcs ?. branch === props . branch ) break
0 commit comments