@@ -119,7 +119,7 @@ import { ensureLocalKilorulesDirExists } from "../context/instructions/kilo-rule
119119import { getMessagesSinceLastSummary , summarizeConversation } from "../condense"
120120import { Gpt5Metadata , ClineMessageWithMetadata } from "./types"
121121import { MessageQueueService } from "../message-queue/MessageQueueService"
122- import { findPartialAskMessage , findPartialSayMessage } from "../kilocode/task/message-utils" // kilocode_change
122+ import { findPartialAskMessage , findPartialSayMessage , MessageInsertionGuard } from "../kilocode/task/message-utils" // kilocode_change
123123
124124import { AutoApprovalHandler } from "./AutoApprovalHandler"
125125import { isAnyRecognizedKiloCodeError , isPaymentRequiredError } from "../../shared/kilocode/errorUtils"
@@ -221,6 +221,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
221221 private readonly globalStoragePath : string
222222 abort : boolean = false
223223
224+ // kilocode_change start: Message insertion guard to prevent race conditions with checkpoint messages
225+ private readonly messageInsertionGuard = new MessageInsertionGuard ( )
226+ // kilocode_change end
227+
224228 // TaskStatus
225229 idleAsk ?: ClineMessage
226230 resumableAsk ?: ClineMessage
@@ -639,24 +643,32 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
639643 return readTaskMessages ( { taskId : this . taskId , globalStoragePath : this . globalStoragePath } )
640644 }
641645
646+ // kilocode_change start: Guard against concurrent message insertions to prevent
642647 private async addToClineMessages ( message : ClineMessage ) {
643- this . clineMessages . push ( message )
644- const provider = this . providerRef . deref ( )
645- await provider ?. postStateToWebview ( )
646- this . emit ( RooCodeEventName . Message , { action : "created" , message } )
647- await this . saveClineMessages ( )
648+ await this . messageInsertionGuard . waitForClearance ( )
649+ this . messageInsertionGuard . acquire ( )
648650
649- // kilocode_change start: no cloud service
650- // const shouldCaptureMessage = message.partial !== true && CloudService.isEnabled()
651+ try {
652+ this . clineMessages . push ( message )
653+ const provider = this . providerRef . deref ( )
654+ await provider ?. postStateToWebview ( )
655+ this . emit ( RooCodeEventName . Message , { action : "created" , message } )
656+ await this . saveClineMessages ( )
651657
652- // if (shouldCaptureMessage) {
653- // CloudService.instance.captureEvent({
654- // event: TelemetryEventName.TASK_MESSAGE,
655- // properties: { taskId: this.taskId, message },
656- // })
657- // }
658- // kilocode_change end
658+ // kilocode_change start: no cloud service
659+ // const shouldCaptureMessage = message.partial !== true && CloudService.isEnabled()
660+ // if (shouldCaptureMessage) {
661+ // CloudService.instance.captureEvent({
662+ // event: TelemetryEventName.TASK_MESSAGE,
663+ // properties: { taskId: this.taskId, message },
664+ // })
665+ // }
666+ // kilocode_change end
667+ } finally {
668+ this . messageInsertionGuard . release ( )
669+ }
659670 }
671+ // kilocode_change end
660672
661673 public async overwriteClineMessages ( newMessages : ClineMessage [ ] ) {
662674 this . clineMessages = newMessages
0 commit comments