@@ -29,6 +29,7 @@ import { taskViewedApi } from "@features/sidebar/hooks/useTaskViewed";
2929import { DEFAULT_GATEWAY_MODEL } from "@posthog/agent/gateway-models" ;
3030import { getIsOnline } from "@renderer/stores/connectivityStore" ;
3131import { trpcClient } from "@renderer/trpc/client" ;
32+ import { getGhUserTokenOrThrow } from "@renderer/utils/github" ;
3233import { toast } from "@renderer/utils/toast" ;
3334import { getCloudUrlFromRegion } from "@shared/constants/oauth" ;
3435import {
@@ -39,6 +40,7 @@ import {
3940 type Task ,
4041} from "@shared/types" ;
4142import { ANALYTICS_EVENTS } from "@shared/types/analytics" ;
43+ import type { CloudRunSource , PrAuthorshipMode } from "@shared/types/cloud" ;
4244import type { AcpMessage , StoredLogEntry } from "@shared/types/session-events" ;
4345import { isJsonRpcRequest } from "@shared/types/session-events" ;
4446import { buildPermissionToolMetadata , track } from "@utils/analytics" ;
@@ -1269,6 +1271,35 @@ export class SessionService {
12691271 throw new Error ( "Authentication required for cloud commands" ) ;
12701272 }
12711273
1274+ const [ previousRun , task ] = await Promise . all ( [
1275+ client . getTaskRun ( session . taskId , session . taskRunId ) ,
1276+ client . getTask ( session . taskId ) ,
1277+ ] ) ;
1278+ const hasGitHubRepo = ! ! task . repository && ! ! task . github_integration ;
1279+ const previousState = previousRun . state as Record < string , unknown > ;
1280+ const previousOutput = ( previousRun . output ?? { } ) as Record <
1281+ string ,
1282+ unknown
1283+ > ;
1284+ // Prefer the actual working branch the agent last pushed to (synced by
1285+ // agent-server after each turn), then the run-level branch field, then
1286+ // the original base branch from state. This preserves unmerged work when
1287+ // the snapshot has expired and the sandbox is rebuilt from scratch.
1288+ const previousBaseBranch =
1289+ ( typeof previousOutput . head_branch === "string"
1290+ ? previousOutput . head_branch
1291+ : null ) ??
1292+ previousRun . branch ??
1293+ ( typeof previousState . pr_base_branch === "string"
1294+ ? previousState . pr_base_branch
1295+ : null ) ??
1296+ session . cloudBranch ;
1297+ const prAuthorshipMode = this . getCloudPrAuthorshipMode ( previousState ) ;
1298+ const githubUserToken =
1299+ prAuthorshipMode === "user" && hasGitHubRepo
1300+ ? await getGhUserTokenOrThrow ( )
1301+ : undefined ;
1302+
12721303 log . info ( "Creating resume run for terminal cloud task" , {
12731304 taskId : session . taskId ,
12741305 previousRunId : session . taskRunId ,
@@ -1280,11 +1311,21 @@ export class SessionService {
12801311 // The agent will load conversation history and restore the sandbox snapshot.
12811312 const updatedTask = await client . runTaskInCloud (
12821313 session . taskId ,
1283- session . cloudBranch ,
1314+ previousBaseBranch ,
12841315 {
12851316 resumeFromRunId : session . taskRunId ,
12861317 pendingUserMessage : promptText ,
12871318 } ,
1319+ undefined ,
1320+ {
1321+ prAuthorshipMode,
1322+ runSource : this . getCloudRunSource ( previousState ) ,
1323+ signalReportId :
1324+ typeof previousState . signal_report_id === "string"
1325+ ? previousState . signal_report_id
1326+ : undefined ,
1327+ githubUserToken,
1328+ } ,
12881329 ) ;
12891330 const newRun = updatedTask . latest_run ;
12901331 if ( ! newRun ?. id ) {
@@ -2007,6 +2048,20 @@ export class SessionService {
20072048 }
20082049 }
20092050
2051+ private getCloudPrAuthorshipMode (
2052+ state : Record < string , unknown > ,
2053+ ) : PrAuthorshipMode {
2054+ const explicitMode = state . pr_authorship_mode ;
2055+ if ( explicitMode === "user" || explicitMode === "bot" ) {
2056+ return explicitMode ;
2057+ }
2058+ return state . run_source === "signal_report" ? "bot" : "user" ;
2059+ }
2060+
2061+ private getCloudRunSource ( state : Record < string , unknown > ) : CloudRunSource {
2062+ return state . run_source === "signal_report" ? "signal_report" : "manual" ;
2063+ }
2064+
20102065 /**
20112066 * Filter out session/prompt events that should be skipped during resume.
20122067 * When resuming a cloud run, the initial session/prompt from the new run's
0 commit comments