From a0597b1065ac1a2978ac8f0c1b96387276848724 Mon Sep 17 00:00:00 2001 From: Tom <42646381+panzeyu2013@users.noreply.github.com> Date: Sat, 13 Jun 2026 03:54:39 +0800 Subject: [PATCH] fix: prevent cascade rollback from restoring deleted session descendants (#1555) The OpenCode server cascade-deletes all child sessions when a parent is removed. The client was sending individual DELETE requests for each descendant, which returned 404 after the parent's cascade removed them. The 404 triggered rollback in deleteSessionAction, restoring already- deleted sessions back into the global store. Changes: - executeDeleteSession: only send the root session delete; the server cascade handles descendants. - deleteSession / deleteSessionInDirectory: treat 404 in catch as success, acting as a safety net for remaining paths (e.g. sidebar bulk action bar when parent and child are both selected). --- .../sidebar/hooks/useSessionActions.ts | 22 ++++++++++--------- packages/ui/src/sync/session-actions.ts | 9 ++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/components/session/sidebar/hooks/useSessionActions.ts b/packages/ui/src/components/session/sidebar/hooks/useSessionActions.ts index 7b4bc9ac..11eb1337 100644 --- a/packages/ui/src/components/session/sidebar/hooks/useSessionActions.ts +++ b/packages/ui/src/components/session/sidebar/hooks/useSessionActions.ts @@ -214,16 +214,18 @@ export const useSessionActions = (args: Args) => { const ids = [session.id, ...descendantIds]; if (shouldHardDelete) { - const { deletedIds, failedIds } = await args.deleteSessions(ids); - if (deletedIds.length > 0) { - toast.success(deletedIds.length === 1 - ? t('sessions.sidebar.bulkActions.deletedSingle', { count: deletedIds.length }) - : t('sessions.sidebar.bulkActions.deletedPlural', { count: deletedIds.length })); - } - if (failedIds.length > 0) { - toast.error(failedIds.length === 1 - ? t('sessions.sidebar.bulkActions.failedDeleteSingle', { count: failedIds.length }) - : t('sessions.sidebar.bulkActions.failedDeletePlural', { count: failedIds.length })); + // The server cascade-deletes all descendant sessions when the parent + // is removed. Only send the root session delete request; sending + // individual requests for each descendant would hit 404 (already + // deleted by cascade) and trigger rollback that restores them. + const success = await args.deleteSession(session.id); + if (success) { + const totalDeleted = descendantIds.length + 1; + toast.success(totalDeleted === 1 + ? t('sessions.sidebar.bulkActions.deletedSingle', { count: totalDeleted }) + : t('sessions.sidebar.bulkActions.deletedPlural', { count: totalDeleted })); + } else { + toast.error(t('sessions.sidebar.session.delete.error')); } return; } diff --git a/packages/ui/src/sync/session-actions.ts b/packages/ui/src/sync/session-actions.ts index 5e5af61c..2b7fadb4 100644 --- a/packages/ui/src/sync/session-actions.ts +++ b/packages/ui/src/sync/session-actions.ts @@ -483,6 +483,12 @@ export async function deleteSession(sessionId: string, _options?: Record