11import { observable } from "@trpc/server/observable"
22import { eq } from "drizzle-orm"
33import { app , BrowserWindow , safeStorage } from "electron"
4- import { readFileSync } from "fs"
54import * as fs from "fs/promises"
65import * as os from "os"
7- import path , { join } from "path"
6+ import path from "path"
87import { z } from "zod"
8+ import { setConnectionMethod } from "../../analytics"
99import {
1010 buildClaudeEnv ,
1111 checkOfflineFallback ,
@@ -20,7 +20,6 @@ import { chats, claudeCodeCredentials, getDatabase, subChats } from "../../db"
2020import { createRollbackStash } from "../../git/stash"
2121import { ensureMcpTokensFresh , fetchMcpTools , fetchMcpToolsStdio , getMcpAuthStatus , startMcpOAuth } from "../../mcp-auth"
2222import { fetchOAuthMetadata , getMcpBaseUrl } from "../../oauth"
23- import { setConnectionMethod } from "../../analytics"
2423import { publicProcedure , router } from "../index"
2524import { buildAgentsOption } from "./agent-utils"
2625
@@ -1504,7 +1503,7 @@ ${prompt}
15041503
15051504 // When result arrives, assign the last assistant UUID to metadata
15061505 // It will be emitted as part of the merged message-metadata chunk below
1507- if ( msgAny . type === "result" && historyEnabled && lastAssistantUuid ) {
1506+ if ( msgAny . type === "result" && historyEnabled && lastAssistantUuid && ! abortController . signal . aborted ) {
15081507 metadata . sdkMessageUuid = lastAssistantUuid
15091508 }
15101509
@@ -1832,6 +1831,8 @@ ${prompt}
18321831 parts . push ( { type : "text" , text : currentText } )
18331832 }
18341833
1834+ const savedSessionId = metadata . sessionId
1835+
18351836 if ( parts . length > 0 ) {
18361837 const assistantMessage = {
18371838 id : crypto . randomUUID ( ) ,
@@ -1845,7 +1846,7 @@ ${prompt}
18451846 db . update ( subChats )
18461847 . set ( {
18471848 messages : JSON . stringify ( finalMessages ) ,
1848- sessionId : metadata . sessionId ,
1849+ sessionId : savedSessionId ,
18491850 streamId : null ,
18501851 updatedAt : new Date ( ) ,
18511852 } )
@@ -1855,7 +1856,7 @@ ${prompt}
18551856 // No assistant response - just clear streamId
18561857 db . update ( subChats )
18571858 . set ( {
1858- sessionId : metadata . sessionId ,
1859+ sessionId : savedSessionId ,
18591860 streamId : null ,
18601861 updatedAt : new Date ( ) ,
18611862 } )
@@ -1896,14 +1897,13 @@ ${prompt}
18961897 activeSessions . delete ( input . subChatId )
18971898 clearPendingApprovals ( "Session ended." , input . subChatId )
18981899
1899- // Save sessionId on abort so conversation can be resumed
1900- // Clear streamId since we're no longer streaming
1900+ // Clear streamId since we're no longer streaming.
1901+ // sessionId is NOT saved here — the save block in the async function
1902+ // handles it (saves on normal completion, clears on abort). This avoids
1903+ // a redundant DB write that the cancel mutation would then overwrite.
19011904 const db = getDatabase ( )
19021905 db . update ( subChats )
1903- . set ( {
1904- streamId : null ,
1905- ...( currentSessionId && { sessionId : currentSessionId } )
1906- } )
1906+ . set ( { streamId : null } )
19071907 . where ( eq ( subChats . id , input . subChatId ) )
19081908 . run ( )
19091909 }
@@ -1964,9 +1964,10 @@ ${prompt}
19641964 controller . abort ( )
19651965 activeSessions . delete ( input . subChatId )
19661966 clearPendingApprovals ( "Session cancelled." , input . subChatId )
1967- return { cancelled : true }
19681967 }
1969- return { cancelled : false }
1968+
1969+
1970+ return { cancelled : ! ! controller }
19701971 } ) ,
19711972
19721973 /**
0 commit comments