@@ -6,13 +6,16 @@ import type {
66 CommandExecutionRequestApprovalResponse ,
77 FileChangeRequestApprovalParams ,
88 FileChangeRequestApprovalResponse ,
9+ FileUpdateChange ,
910 McpServerElicitationRequestParams ,
1011 McpServerElicitationRequestResponse
1112} from "./app-server/v2" ;
1213import type { JsonValue } from "./app-server/serde_json/JsonValue" ;
1314import type { ToolCallContent } from "@agentclientprotocol/sdk/dist/schema/types.gen" ;
1415import { logger } from "./Logger" ;
1516import { stripShellPrefix } from "./CodexEventHandler" ;
17+ import type { ApprovalContextStore } from "./CodexApprovalContext" ;
18+ import { createFileChangeContents } from "./CodexToolCallMapper" ;
1619
1720const APPROVAL_OPTIONS : acp . PermissionOption [ ] = [
1821 { optionId : "allow_once" , name : "Allow Once" , kind : "allow_once" } ,
@@ -31,13 +34,16 @@ type JsonObject = { [key: string]: JsonValue };
3134export class CodexApprovalHandler implements ApprovalHandler {
3235 private readonly connection : acp . AgentSideConnection ;
3336 private readonly sessionState : SessionState ;
37+ private readonly approvalContext : ApprovalContextStore ;
3438
3539 constructor (
3640 connection : acp . AgentSideConnection ,
37- sessionState : SessionState
41+ sessionState : SessionState ,
42+ approvalContext : ApprovalContextStore ,
3843 ) {
3944 this . connection = connection ;
4045 this . sessionState = sessionState ;
46+ this . approvalContext = approvalContext ;
4147 }
4248
4349 async handleCommandExecution (
@@ -59,7 +65,7 @@ export class CodexApprovalHandler implements ApprovalHandler {
5965 ) : Promise < FileChangeRequestApprovalResponse > {
6066 try {
6167 const sessionId = this . sessionState . sessionId ;
62- const acpRequest = this . buildFileChangePermissionRequest ( sessionId , params ) ;
68+ const acpRequest = await this . buildFileChangePermissionRequest ( sessionId , params ) ;
6369 const response = await this . connection . requestPermission ( acpRequest ) ;
6470 return this . convertFileChangeResponse ( response ) ;
6571 } catch ( error ) {
@@ -120,19 +126,43 @@ export class CodexApprovalHandler implements ApprovalHandler {
120126 return contents . length > 0 ? contents : null
121127 }
122128
123- private buildFileChangePermissionRequest (
129+ private async buildFileChangePermissionRequest (
124130 sessionId : string ,
125131 params : FileChangeRequestApprovalParams
126- ) : acp . RequestPermissionRequest {
132+ ) : Promise < acp . RequestPermissionRequest > {
127133 const reasonContent = this . createTextContent ( params . reason ?? null ) ;
134+ const fileChange = this . approvalContext . fileChangesByItemId . get ( params . itemId ) ;
135+ const diffContent = fileChange ? await createFileChangeContents ( fileChange . changes ) : [ ] ;
136+ const toolCall : acp . ToolCallUpdate = {
137+ toolCallId : params . itemId ,
138+ kind : "edit" ,
139+ status : "pending" ,
140+ } ;
141+ const content = [
142+ ...( reasonContent ? [ reasonContent ] : [ ] ) ,
143+ ...diffContent ,
144+ ] ;
145+ if ( content . length > 0 ) {
146+ toolCall . content = content ;
147+ }
148+ if ( fileChange ) {
149+ toolCall . locations = dedupePaths ( fileChange . changes ) . map ( path => ( { path } ) ) ;
150+ toolCall . rawInput = {
151+ changes : fileChange . changes . map ( change => ( {
152+ path : change . path ,
153+ kind : change . kind . type ,
154+ diff : change . diff ,
155+ } ) ) ,
156+ } ;
157+ } else {
158+ const turnDiff = this . approvalContext . turnDiffsByTurnId . get ( params . turnId ) ;
159+ if ( turnDiff ) {
160+ toolCall . rawInput = { unifiedDiff : turnDiff } ;
161+ }
162+ }
128163 return {
129164 sessionId,
130- toolCall : {
131- toolCallId : params . itemId ,
132- kind : "edit" ,
133- status : "pending" ,
134- content : reasonContent ? [ reasonContent ] : null ,
135- } ,
165+ toolCall,
136166 options : APPROVAL_OPTIONS ,
137167 } ;
138168 }
@@ -320,3 +350,7 @@ export class CodexApprovalHandler implements ApprovalHandler {
320350 return { action : "cancel" , content : null , _meta : null }
321351 }
322352}
353+
354+ function dedupePaths ( changes : Array < FileUpdateChange > ) : Array < string > {
355+ return Array . from ( new Set ( changes . map ( change => change . path ) ) ) ;
356+ }
0 commit comments