diff --git a/packages/app/src/context/global-sync/event-reducer.test.ts b/packages/app/src/context/global-sync/event-reducer.test.ts index 892129788e6c..2931c0403ca7 100644 --- a/packages/app/src/context/global-sync/event-reducer.test.ts +++ b/packages/app/src/context/global-sync/event-reducer.test.ts @@ -517,6 +517,75 @@ describe("applyDirectoryEvent", () => { expect(cacheStore.value).toEqual({ branch: "feature/test", default_branch: "main" }) }) + test("session.diff stores array diffs in session_diff", () => { + const [store, setStore] = createStore(baseState()) + + applyDirectoryEvent({ + event: { + type: "session.diff", + properties: { + sessionID: "ses_1", + diff: [{ file: "a.txt", before: "", after: "hello", additions: 1, deletions: 0, status: "added" }], + }, + }, + store, + setStore, + push() {}, + directory: "/tmp", + loadLsp() {}, + }) + + expect(Array.isArray(store.session_diff.ses_1)).toBe(true) + expect(store.session_diff.ses_1?.length).toBe(1) + expect(store.session_diff.ses_1?.[0]?.file).toBe("a.txt") + }) + + test("session.diff handles undefined diff gracefully", () => { + const [store, setStore] = createStore(baseState()) + + applyDirectoryEvent({ + event: { + type: "session.diff", + properties: { + sessionID: "ses_1", + diff: undefined, + }, + }, + store, + setStore, + push() {}, + directory: "/tmp", + loadLsp() {}, + }) + + const result = store.session_diff.ses_1 + expect(Array.isArray(result)).toBe(true) + expect(result?.length).toBe(0) + }) + + test("session.diff handles non-array diff gracefully", () => { + const [store, setStore] = createStore(baseState()) + + applyDirectoryEvent({ + event: { + type: "session.diff", + properties: { + sessionID: "ses_1", + diff: { file: "a.txt" } as any, + }, + }, + store, + setStore, + push() {}, + directory: "/tmp", + loadLsp() {}, + }) + + const result = store.session_diff.ses_1 + expect(Array.isArray(result)).toBe(true) + expect(result?.length).toBe(0) + }) + test("routes disposal and lsp events to side-effect handlers", () => { const [store, setStore] = createStore(baseState()) const pushes: string[] = [] diff --git a/packages/app/src/context/global-sync/event-reducer.ts b/packages/app/src/context/global-sync/event-reducer.ts index 4af636553526..06b767b7d5b9 100644 --- a/packages/app/src/context/global-sync/event-reducer.ts +++ b/packages/app/src/context/global-sync/event-reducer.ts @@ -162,7 +162,8 @@ export function applyDirectoryEvent(input: { } case "session.diff": { const props = event.properties as { sessionID: string; diff: FileDiff[] } - input.setStore("session_diff", props.sessionID, reconcile(props.diff, { key: "file" })) + const diff = Array.isArray(props.diff) ? props.diff : [] + input.setStore("session_diff", props.sessionID, reconcile(diff, { key: "file" })) break } case "todo.updated": { diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx index 2274e93a34b5..dfc1f0e93933 100644 --- a/packages/ui/src/components/session-review.tsx +++ b/packages/ui/src/components/session-review.tsx @@ -150,7 +150,8 @@ export const SessionReview = (props: SessionReviewProps) => { const opened = () => store.opened const open = () => props.open ?? store.open - const files = createMemo(() => props.diffs.map((diff) => diff.file)) + const safeDiffs = () => (Array.isArray(props.diffs) ? props.diffs : []) + const files = createMemo(() => safeDiffs().map((diff) => diff.file)) const diffStyle = () => props.diffStyle ?? (props.split ? "split" : "unified") const hasDiffs = () => files().length > 0 @@ -281,7 +282,7 @@ export const SessionReview = (props: SessionReviewProps) => {
- + {(diff) => { let wrapper: HTMLDivElement | undefined const file = diff.file