@@ -2,12 +2,16 @@ import type * as acp from "@agentclientprotocol/sdk";
22import type { AgentSideConnection , AvailableCommand } from "@agentclientprotocol/sdk" ;
33import { ACPSessionConnection } from "./ACPSessionConnection" ;
44import type { CodexAcpClient } from "./CodexAcpClient" ;
5- import type { RateLimitSnapshot , SkillsListEntry } from "./app-server/v2" ;
5+ import type { RateLimitSnapshot , ReviewTarget , SkillsListEntry , TurnCompletedNotification } from "./app-server/v2" ;
66import type { SessionState } from "./CodexAcpServer" ;
77import type { RateLimitsMap } from "./RateLimitsMap" ;
88import type { TokenCount } from "./TokenCount" ;
99import { logger } from "./Logger" ;
1010
11+ type CommandHandlingResult =
12+ | { handled : false }
13+ | { handled : true ; turnCompleted ?: TurnCompletedNotification } ;
14+
1115export class CodexCommands {
1216 private readonly connection : AgentSideConnection ;
1317 private readonly codexAcpClient : CodexAcpClient ;
@@ -41,12 +45,12 @@ export class CodexCommands {
4145 }
4246 }
4347
44- async tryHandle ( prompt : acp . ContentBlock [ ] , sessionState : SessionState ) : Promise < boolean > {
48+ async tryHandle ( prompt : acp . ContentBlock [ ] , sessionState : SessionState ) : Promise < CommandHandlingResult > {
4549 const command = this . parseCommand ( prompt ) ;
4650 if ( command ) {
4751 return this . handleCommand ( command , sessionState ) ;
4852 }
49- return false ;
53+ return { handled : false } ;
5054 }
5155
5256 private buildAvailableCommands ( skillsEntries : SkillsListEntry [ ] ) : AvailableCommand [ ] {
@@ -81,6 +85,11 @@ export class CodexCommands {
8185 description : "List configured Model Context Protocol (MCP) tools." ,
8286 input : null
8387 } ,
88+ {
89+ name : "review" ,
90+ description : "Review uncommitted changes." ,
91+ input : null
92+ } ,
8493 {
8594 name : "skills" ,
8695 description : "List available skills." ,
@@ -119,7 +128,7 @@ export class CodexCommands {
119128 } ;
120129 }
121130
122- async handleCommand ( command : ParsedCommand , sessionState : SessionState ) : Promise < boolean > {
131+ async handleCommand ( command : ParsedCommand , sessionState : SessionState ) : Promise < CommandHandlingResult > {
123132 const sessionId = sessionState . sessionId ;
124133
125134 switch ( command . name ) {
@@ -130,7 +139,7 @@ export class CodexCommands {
130139 sessionUpdate : "agent_message_chunk" ,
131140 content : { type : "text" , text : message }
132141 } ) ;
133- return true ;
142+ return { handled : true } ;
134143 }
135144 case "logout" : {
136145 await this . runWithProcessCheck ( ( ) => this . codexAcpClient . logout ( ) ) ;
@@ -139,7 +148,7 @@ export class CodexCommands {
139148 sessionUpdate : "agent_message_chunk" ,
140149 content : { type : "text" , text : "Logged out from Codex account." }
141150 } ) ;
142- return true ;
151+ return { handled : true } ;
143152 }
144153 case "skills" : {
145154 const response = await this . runWithProcessCheck ( ( ) => this . codexAcpClient . listSkills ( ) ) ;
@@ -156,7 +165,7 @@ export class CodexCommands {
156165 sessionUpdate : "agent_message_chunk" ,
157166 content : { type : "text" , text }
158167 } ) ;
159- return true ;
168+ return { handled : true } ;
160169 }
161170 case "mcp" : {
162171 const servers = await this . runWithProcessCheck ( ( ) => this . codexAcpClient . listMcpServers ( ) ) ;
@@ -177,14 +186,33 @@ export class CodexCommands {
177186 sessionUpdate : "agent_message_chunk" ,
178187 content : { type : "text" , text }
179188 } ) ;
180- return true ;
189+ return { handled : true } ;
190+ }
191+ case "review" : {
192+ if ( command . input !== null ) {
193+ await this . sendCommandMessage ( sessionId , "/review does not accept arguments yet." ) ;
194+ return { handled : true } ;
195+ }
196+ const target : ReviewTarget = { type : "uncommittedChanges" } ;
197+ const turnCompleted = await this . runWithProcessCheck ( ( ) =>
198+ this . codexAcpClient . runReview ( sessionId , target )
199+ ) ;
200+ return { handled : true , turnCompleted } ;
181201 }
182202 default :
183203 await this . sendUnknownCommandMessage ( command . name , sessionId ) ;
184- return true ;
204+ return { handled : true } ;
185205 }
186206 }
187207
208+ private async sendCommandMessage ( sessionId : string , text : string ) : Promise < void > {
209+ const session = new ACPSessionConnection ( this . connection , sessionId ) ;
210+ await session . update ( {
211+ sessionUpdate : "agent_message_chunk" ,
212+ content : { type : "text" , text }
213+ } ) ;
214+ }
215+
188216 private async sendUnknownCommandMessage ( name : string , sessionId : string ) : Promise < void > {
189217 const lines = this . getBuiltinCommands ( ) . map ( command => `- /${ command . name } : ${ command . description } ` ) ;
190218 const text = [
0 commit comments