@@ -13,7 +13,7 @@ import {
1313import type { ServerNotification } from "../../app-server" ;
1414import type { SessionState } from "../../CodexAcpServer" ;
1515import { AgentMode } from "../../AgentMode" ;
16- import type { Model , ReviewStartResponse , TurnCompletedNotification , TurnStartParams } from "../../app-server/v2" ;
16+ import type { Model , ReviewStartResponse , ThreadGoal , TurnCompletedNotification , TurnStartParams } from "../../app-server/v2" ;
1717import type { RateLimitsMap } from "../../RateLimitsMap" ;
1818import { ModelId } from "../../ModelId" ;
1919
@@ -1100,6 +1100,68 @@ describe('ACP server test', { timeout: 40_000 }, () => {
11001100 expect ( mockFixture . getAcpConnectionDump ( [ ] ) ) . toContain ( "Context compacted" ) ;
11011101 } ) ;
11021102
1103+ it ( 'handles goal slash commands through Codex app server' , async ( ) => {
1104+ const { mockFixture, turnStartSpy } = setupPromptFixture ( ) ;
1105+ const goalSetSpy = vi . spyOn ( mockFixture . getCodexAppServerClient ( ) , "threadGoalSet" )
1106+ . mockResolvedValue ( { goal : createThreadGoal ( ) } ) ;
1107+ const goalClearSpy = vi . spyOn ( mockFixture . getCodexAppServerClient ( ) , "threadGoalClear" )
1108+ . mockResolvedValue ( { cleared : true } ) ;
1109+
1110+ await mockFixture . getCodexAcpAgent ( ) . prompt ( {
1111+ sessionId : "session-id" ,
1112+ prompt : [ { type : "text" , text : "/goal Ship the migration and keep tests green" } ] ,
1113+ } ) ;
1114+ await mockFixture . getCodexAcpAgent ( ) . prompt ( {
1115+ sessionId : "session-id" ,
1116+ prompt : [ { type : "text" , text : "/goal pause" } ] ,
1117+ } ) ;
1118+ await mockFixture . getCodexAcpAgent ( ) . prompt ( {
1119+ sessionId : "session-id" ,
1120+ prompt : [ { type : "text" , text : "/goal resume" } ] ,
1121+ } ) ;
1122+ await mockFixture . getCodexAcpAgent ( ) . prompt ( {
1123+ sessionId : "session-id" ,
1124+ prompt : [ { type : "text" , text : "/goal clear" } ] ,
1125+ } ) ;
1126+
1127+ expect ( goalSetSpy ) . toHaveBeenNthCalledWith ( 1 , {
1128+ threadId : "session-id" ,
1129+ objective : "Ship the migration and keep tests green" ,
1130+ status : "active" ,
1131+ } ) ;
1132+ expect ( goalSetSpy ) . toHaveBeenNthCalledWith ( 2 , {
1133+ threadId : "session-id" ,
1134+ status : "paused" ,
1135+ } ) ;
1136+ expect ( goalSetSpy ) . toHaveBeenNthCalledWith ( 3 , {
1137+ threadId : "session-id" ,
1138+ status : "active" ,
1139+ } ) ;
1140+ expect ( goalClearSpy ) . toHaveBeenCalledWith ( { threadId : "session-id" } ) ;
1141+ expect ( turnStartSpy ) . not . toHaveBeenCalled ( ) ;
1142+ } ) ;
1143+
1144+ it ( 'reports missing goal slash command input' , async ( ) => {
1145+ const { mockFixture } = setupPromptFixture ( ) ;
1146+ const goalSetSpy = vi . spyOn ( mockFixture . getCodexAppServerClient ( ) , "threadGoalSet" )
1147+ . mockResolvedValue ( { goal : createThreadGoal ( ) } ) ;
1148+ const goalClearSpy = vi . spyOn ( mockFixture . getCodexAppServerClient ( ) , "threadGoalClear" )
1149+ . mockResolvedValue ( { cleared : true } ) ;
1150+
1151+ await mockFixture . getCodexAcpAgent ( ) . prompt ( {
1152+ sessionId : "session-id" ,
1153+ prompt : [ { type : "text" , text : "/goal" } ] ,
1154+ } ) ;
1155+
1156+ expect ( goalSetSpy ) . not . toHaveBeenCalled ( ) ;
1157+ expect ( goalClearSpy ) . not . toHaveBeenCalled ( ) ;
1158+ const [ event ] = mockFixture . getAcpConnectionEvents ( [ ] ) ;
1159+ expect ( event ) . toBeDefined ( ) ;
1160+ expect ( event ! . args [ 0 ] . update . content . text ) . toBe (
1161+ 'Command "/goal" requires [<objective>|clear|edit|pause|resume].'
1162+ ) ;
1163+ } ) ;
1164+
11031165 it ( 'reports missing review slash command input' , async ( ) => {
11041166 const { mockFixture } = setupPromptFixture ( ) ;
11051167 const reviewStartSpy = vi . spyOn ( mockFixture . getCodexAppServerClient ( ) , "reviewStart" )
@@ -1335,6 +1397,20 @@ describe('ACP server test', { timeout: 40_000 }, () => {
13351397 } ;
13361398 }
13371399
1400+ function createThreadGoal ( overrides ?: Partial < ThreadGoal > ) : ThreadGoal {
1401+ return {
1402+ threadId : "session-id" ,
1403+ objective : "Ship the migration and keep tests green" ,
1404+ status : "active" ,
1405+ tokenBudget : null ,
1406+ tokensUsed : 0 ,
1407+ timeUsedSeconds : 0 ,
1408+ createdAt : 1710000000 ,
1409+ updatedAt : 1710000000 ,
1410+ ...overrides ,
1411+ } ;
1412+ }
1413+
13381414 it ( 'should disable reasoning.summary if key authorization is used' , async ( ) => {
13391415 const { mockFixture, turnStartSpy } = setupPromptFixture ( { account : { type : "apiKey" } } ) ;
13401416
0 commit comments