@@ -19,6 +19,7 @@ import {
1919 getDiffHead ,
2020 getDiffStats ,
2121 getFileAtHead ,
22+ getGitBusyState ,
2223 getLatestCommit ,
2324 getRemoteUrl ,
2425 getStagedDiff ,
@@ -40,6 +41,7 @@ import { inject, injectable } from "inversify";
4041import { MAIN_TOKENS } from "../../di/tokens" ;
4142import { logger } from "../../utils/logger" ;
4243import { TypedEventEmitter } from "../../utils/typed-event-emitter" ;
44+ import type { AgentService } from "../agent/service" ;
4345import type { LlmGatewayService } from "../llm-gateway/service" ;
4446import type { SidebarPrState } from "../workspace/schemas" ;
4547import type { WorkspaceService } from "../workspace/service" ;
@@ -57,6 +59,7 @@ import type {
5759 GetPrTemplateOutput ,
5860 GhAuthTokenOutput ,
5961 GhStatusOutput ,
62+ GitBusyState ,
6063 GitCommitInfo ,
6164 GitFileStatus ,
6265 GithubRef ,
@@ -134,10 +137,31 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
134137 private readonly llmGateway : LlmGatewayService ,
135138 @inject ( MAIN_TOKENS . WorkspaceService )
136139 private readonly workspaceService : WorkspaceService ,
140+ @inject ( MAIN_TOKENS . AgentService )
141+ private readonly agentService : AgentService ,
137142 ) {
138143 super ( ) ;
139144 }
140145
146+ /**
147+ * Resolve env-var overrides set by the agent's SessionStart hooks for the
148+ * given task. Used so UI-triggered git/gh operations (Commit, Create PR)
149+ * see the same env (notably `SSH_AUTH_SOCK` re-pointed at Secretive) as
150+ * the agent's bash tool. Returns `undefined` if there's nothing to apply.
151+ */
152+ private async getSessionEnv (
153+ taskId : string | undefined ,
154+ ) : Promise < Record < string , string > | undefined > {
155+ if ( ! taskId ) return undefined ;
156+ try {
157+ const env = await this . agentService . getSessionEnvForTask ( taskId ) ;
158+ return Object . keys ( env ) . length > 0 ? env : undefined ;
159+ } catch ( err ) {
160+ log . warn ( "Failed to load session env for task" , { taskId, err } ) ;
161+ return undefined ;
162+ }
163+ }
164+
141165 private async getStateSnapshot (
142166 directoryPath : string ,
143167 options ?: {
@@ -285,6 +309,10 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
285309 return getAllBranches ( directoryPath ) ;
286310 }
287311
312+ public async getGitBusyState ( directoryPath : string ) : Promise < GitBusyState > {
313+ return getGitBusyState ( directoryPath ) ;
314+ }
315+
288316 public async createBranch (
289317 directoryPath : string ,
290318 branchName : string ,
@@ -475,6 +503,7 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
475503 branch ?: string ,
476504 setUpstream = false ,
477505 signal ?: AbortSignal ,
506+ env ?: Record < string , string > ,
478507 ) : Promise < PushOutput > {
479508 const saga = new PushSaga ( ) ;
480509 const result = await saga . run ( {
@@ -483,6 +512,7 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
483512 branch : branch || undefined ,
484513 setUpstream,
485514 signal,
515+ env,
486516 } ) ;
487517 if ( ! result . success ) {
488518 return { success : false , message : result . error } ;
@@ -532,6 +562,7 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
532562 directoryPath : string ,
533563 remote = "origin" ,
534564 signal ?: AbortSignal ,
565+ env ?: Record < string , string > ,
535566 ) : Promise < PublishOutput > {
536567 const currentBranch = await getCurrentBranch ( directoryPath ) ;
537568 if ( ! currentBranch ) {
@@ -544,6 +575,7 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
544575 currentBranch ,
545576 true ,
546577 signal ,
578+ env ,
547579 ) ;
548580 return {
549581 success : pushResult . success ,
@@ -617,6 +649,8 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
617649 } ) ;
618650 } ;
619651
652+ const sessionEnv = await this . getSessionEnv ( input . taskId ) ;
653+
620654 const saga = new CreatePrSaga (
621655 {
622656 getCurrentBranch : ( dir ) => getCurrentBranch ( dir ) ,
@@ -625,14 +659,16 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
625659 getChangedFilesHead : ( dir ) => this . getChangedFilesHead ( dir ) ,
626660 generateCommitMessage : ( dir ) =>
627661 this . generateCommitMessage ( dir , input . conversationContext ) ,
628- commit : ( dir , msg , opts ) => this . commit ( dir , msg , opts ) ,
662+ commit : ( dir , msg , opts ) =>
663+ this . commit ( dir , msg , { ...opts , envOverride : sessionEnv } ) ,
629664 getSyncStatus : ( dir ) => this . getGitSyncStatus ( dir ) ,
630- push : ( dir ) => this . push ( dir ) ,
631- publish : ( dir ) => this . publish ( dir ) ,
665+ push : ( dir ) =>
666+ this . push ( dir , "origin" , undefined , false , undefined , sessionEnv ) ,
667+ publish : ( dir ) => this . publish ( dir , "origin" , undefined , sessionEnv ) ,
632668 generatePrTitleAndBody : ( dir ) =>
633669 this . generatePrTitleAndBody ( dir , input . conversationContext ) ,
634670 createPr : ( dir , title , body , draft ) =>
635- this . createPrViaGh ( dir , title , body , draft ) ,
671+ this . createPrViaGh ( dir , title , body , draft , sessionEnv ) ,
636672 onProgress : emitProgress ,
637673 } ,
638674 log ,
@@ -723,6 +759,8 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
723759 allowEmpty ?: boolean ;
724760 stagedOnly ?: boolean ;
725761 taskId ?: string ;
762+ /** Pre-resolved session env. Internal — used by createPr to avoid re-loading. */
763+ envOverride ?: Record < string , string > ;
726764 } ,
727765 ) : Promise < CommitOutput > {
728766 const fail = ( msg : string ) : CommitOutput => ( {
@@ -734,11 +772,15 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
734772
735773 if ( ! message . trim ( ) ) return fail ( "Commit message is required" ) ;
736774
775+ const { envOverride, ...sagaOptions } = options ?? { } ;
776+ const env = envOverride ?? ( await this . getSessionEnv ( options ?. taskId ) ) ;
777+
737778 const saga = new CommitSaga ( ) ;
738779 const result = await saga . run ( {
739780 baseDir : directoryPath ,
740781 message : message . trim ( ) ,
741- ...options ,
782+ env,
783+ ...sagaOptions ,
742784 } ) ;
743785
744786 if ( ! result . success ) return fail ( result . error ) ;
@@ -949,6 +991,7 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
949991 title ?: string ,
950992 body ?: string ,
951993 draft ?: boolean ,
994+ env ?: Record < string , string > ,
952995 ) : Promise < { success : boolean ; message : string ; prUrl : string | null } > {
953996 const prFooter =
954997 "\n\n---\n*Created with [PostHog Code](https://posthog.com/code?ref=pr)*" ;
@@ -962,7 +1005,7 @@ export class GitService extends TypedEventEmitter<GitServiceEvents> {
9621005 }
9631006 if ( draft ) args . push ( "--draft" ) ;
9641007
965- const result = await execGh ( args , { cwd : directoryPath } ) ;
1008+ const result = await execGh ( args , { cwd : directoryPath , env } ) ;
9661009 if ( result . exitCode !== 0 ) {
9671010 return {
9681011 success : false ,
0 commit comments