Skip to content

Commit cd09db1

Browse files
[Fix] Child task view returns to Home during state updates (#1458)
* fix(webview): preserve task state publication order * test(webview): use complete state fixtures * test(webview): complete message fixture --------- Co-authored-by: Roomote <roomote@roomote.dev>
1 parent edaf7a1 commit cd09db1

2 files changed

Lines changed: 42 additions & 4 deletions

File tree

src/core/webview/ClineProvider.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,9 +2398,9 @@ export class ClineProvider
23982398
}
23992399

24002400
async postStateToWebview() {
2401+
const clineMessagesSeq = ++this.clineMessagesSeq
24012402
const state = await this.getStateToPostToWebview()
2402-
this.clineMessagesSeq++
2403-
state.clineMessagesSeq = this.clineMessagesSeq
2403+
state.clineMessagesSeq = clineMessagesSeq
24042404
await this.postMessageToWebview({ type: "state", state })
24052405
}
24062406

@@ -2413,9 +2413,9 @@ export class ClineProvider
24132413
* `taskHistoryUpdated` / `taskHistoryItemUpdated`.
24142414
*/
24152415
async postStateToWebviewWithoutTaskHistory(): Promise<void> {
2416+
const clineMessagesSeq = ++this.clineMessagesSeq
24162417
const state = await this.getStateToPostToWebview({ includeTaskHistory: false })
2417-
this.clineMessagesSeq++
2418-
state.clineMessagesSeq = this.clineMessagesSeq
2418+
state.clineMessagesSeq = clineMessagesSeq
24192419
const { taskHistory: _omit, ...rest } = state
24202420
await this.postMessageToWebview({ type: "state", state: rest })
24212421
}

src/core/webview/__tests__/ClineProvider.spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,44 @@ describe("ClineProvider", () => {
884884
expect(statePostSettled).toBe(true)
885885
})
886886

887+
test.each([
888+
["postStateToWebview", (currentProvider: ClineProvider) => currentProvider.postStateToWebview()],
889+
[
890+
"postStateToWebviewWithoutTaskHistory",
891+
(currentProvider: ClineProvider) => currentProvider.postStateToWebviewWithoutTaskHistory(),
892+
],
893+
])("%s assigns message sequence numbers before asynchronous state construction", async (_methodName, postState) => {
894+
let releaseOlderSnapshot!: (state: ExtensionState) => void
895+
const olderSnapshot = new Promise<ExtensionState>((resolve) => {
896+
releaseOlderSnapshot = resolve
897+
})
898+
const baseState = await provider.getStateToPostToWebview({ includeTaskHistory: false })
899+
const emptyState: ExtensionState = { ...baseState, taskHistory: [], clineMessages: [] }
900+
const readyState: ExtensionState = {
901+
...baseState,
902+
taskHistory: [],
903+
clineMessages: [{ ts: 1, type: "say", say: "text", text: "child ready" }],
904+
}
905+
906+
vi.spyOn(provider, "getStateToPostToWebview")
907+
.mockReturnValueOnce(olderSnapshot)
908+
.mockResolvedValueOnce(readyState)
909+
const postMessageSpy = vi.spyOn(provider, "postMessageToWebview").mockResolvedValue(undefined)
910+
911+
const olderPost = postState(provider)
912+
await Promise.resolve()
913+
const newerPost = postState(provider)
914+
await newerPost
915+
releaseOlderSnapshot(emptyState)
916+
await olderPost
917+
918+
expect(postMessageSpy.mock.calls.map(([message]) => message.state?.clineMessages)).toEqual([
919+
readyState.clineMessages,
920+
emptyState.clineMessages,
921+
])
922+
expect(postMessageSpy.mock.calls.map(([message]) => message.state?.clineMessagesSeq)).toEqual([2, 1])
923+
})
924+
887925
test.each([
888926
[
889927
"postStateToWebviewWithoutTaskHistory",

0 commit comments

Comments
 (0)