@@ -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"
1617import { dropSessionCaches } from "./session-cache"
@@ -174,99 +175,41 @@ export function applyDirectoryEvent(input: {
174175 input . setStore ( "session_status" , props . sessionID , reconcile ( props . status ) )
175176 break
176177 }
177- case "message.updated" : {
178- const info = ( event . properties as { info : Message } ) . info
179- const messages = input . store . message [ info . sessionID ]
180- if ( ! messages ) {
181- input . setStore ( "message" , info . sessionID , [ info ] )
182- break
178+ case "message.updated" :
179+ case "message.removed" :
180+ case "message.part.updated" :
181+ case "message.part.removed" :
182+ case "message.part.delta" : {
183+ const currentStore : MessageStore = {
184+ messages : input . store . message as Record < string , Message [ ] > ,
185+ parts : input . store . part as Record < string , Part [ ] > ,
183186 }
184- const result = Binary . search ( messages , info . id , ( m ) => m . id )
185- if ( result . found ) {
186- input . setStore ( "message" , info . sessionID , result . index , reconcile ( info ) )
187- break
187+ const next = applyMessageEvent ( currentStore , event )
188+ if ( ! next ) break
189+ // Apply changed message lists to Solid store
190+ for ( const sessionID of Object . keys ( next . messages ) as string [ ] ) {
191+ if ( next . messages [ sessionID ] !== currentStore . messages [ sessionID ] ) {
192+ input . setStore ( "message" , sessionID , reconcile ( next . messages [ sessionID ] , { key : "id" } ) )
193+ }
188194 }
189- input . setStore (
190- "message" ,
191- info . sessionID ,
192- produce ( ( draft ) => {
193- draft . splice ( result . index , 0 , info )
194- } ) ,
195- )
196- break
197- }
198- case "message.removed" : {
199- const props = event . properties as { sessionID : string ; messageID : string }
200- input . setStore (
201- produce ( ( draft ) => {
202- const messages = draft . message [ props . sessionID ]
203- if ( messages ) {
204- const result = Binary . search ( messages , props . messageID , ( m ) => m . id )
205- if ( result . found ) messages . splice ( result . index , 1 )
206- }
207- delete draft . part [ props . messageID ]
208- } ) ,
209- )
210- break
211- }
212- case "message.part.updated" : {
213- const part = ( event . properties as { part : Part } ) . part
214- const parts = input . store . part [ part . messageID ]
215- if ( ! parts ) {
216- input . setStore ( "part" , part . messageID , [ part ] )
217- break
195+ for ( const sessionID of Object . keys ( currentStore . messages ) as string [ ] ) {
196+ if ( ! ( sessionID in next . messages ) ) {
197+ input . setStore ( produce ( ( draft ) => { delete draft . message [ sessionID ] } ) )
198+ }
218199 }
219- const result = Binary . search ( parts , part . id , ( p ) => p . id )
220- if ( result . found ) {
221- input . setStore ( "part" , part . messageID , result . index , reconcile ( part ) )
222- break
200+ // Apply changed part lists to Solid store
201+ for ( const messageID of Object . keys ( next . parts ) as string [ ] ) {
202+ if ( next . parts [ messageID ] !== currentStore . parts [ messageID ] ) {
203+ input . setStore ( "part" , messageID , reconcile ( next . parts [ messageID ] , { key : "id" } ) )
204+ }
223205 }
224- input . setStore (
225- "part" ,
226- part . messageID ,
227- produce ( ( draft ) => {
228- draft . splice ( result . index , 0 , part )
229- } ) ,
230- )
231- break
232- }
233- case "message.part.removed" : {
234- const props = event . properties as { messageID : string ; partID : string }
235- const parts = input . store . part [ props . messageID ]
236- if ( ! parts ) break
237- const result = Binary . search ( parts , props . partID , ( p ) => p . id )
238- if ( result . found ) {
239- input . setStore (
240- produce ( ( draft ) => {
241- const list = draft . part [ props . messageID ]
242- if ( ! list ) return
243- const next = Binary . search ( list , props . partID , ( p ) => p . id )
244- if ( ! next . found ) return
245- list . splice ( next . index , 1 )
246- if ( list . length === 0 ) delete draft . part [ props . messageID ]
247- } ) ,
248- )
206+ for ( const messageID of Object . keys ( currentStore . parts ) as string [ ] ) {
207+ if ( ! ( messageID in next . parts ) ) {
208+ input . setStore ( produce ( ( draft ) => { delete draft . part [ messageID ] } ) )
209+ }
249210 }
250211 break
251212 }
252- case "message.part.delta" : {
253- const props = event . properties as { messageID : string ; partID : string ; field : string ; delta : string }
254- const parts = input . store . part [ props . messageID ]
255- if ( ! parts ) break
256- const result = Binary . search ( parts , props . partID , ( p ) => p . id )
257- if ( ! result . found ) break
258- input . setStore (
259- "part" ,
260- props . messageID ,
261- produce ( ( draft ) => {
262- const part = draft [ result . index ]
263- const field = props . field as keyof typeof part
264- const existing = part [ field ] as string | undefined
265- ; ( part [ field ] as string ) = ( existing ?? "" ) + props . delta
266- } ) ,
267- )
268- break
269- }
270213 case "vcs.branch.updated" : {
271214 const props = event . properties as { branch : string }
272215 if ( input . store . vcs ?. branch === props . branch ) break
0 commit comments