@@ -3,12 +3,14 @@ package codexadapter_test
33import (
44 "encoding/json"
55 "errors"
6+ "fmt"
67 "os"
78 "path/filepath"
89 "reflect"
910 "runtime"
1011 "strings"
1112 "testing"
13+ "time"
1214
1315 "github.com/hecatehq/acp-adapter-kit/acptest"
1416 "github.com/hecatehq/acp-adapter-kit/adaptertest"
@@ -655,6 +657,70 @@ printf '{"method":"item/completed","params":{"item":{"type":"agent_message","id"
655657 }
656658}
657659
660+ func TestNewServerStopsCodexStreamWhenPermissionDenied (t * testing.T ) {
661+ tests := []struct {
662+ name string
663+ option acptest.LiveClientOption
664+ wantReason string
665+ }{
666+ {
667+ name : "rejected" ,
668+ option : acptest .WithAutoRejectPermissions (),
669+ wantReason : "permission rejected for Run tests" ,
670+ },
671+ {
672+ name : "cancelled" ,
673+ option : acptest .WithAutoCancelPermissions (),
674+ wantReason : "permission cancelled for Run tests" ,
675+ },
676+ }
677+ for _ , tt := range tests {
678+ t .Run (tt .name , func (t * testing.T ) {
679+ installFakeCommand (t , "codex" , `
680+ if [ "$1" != "exec" ]; then
681+ echo "unexpected command: $*" >&2
682+ exit 64
683+ fi
684+ printf '{"method":"permission/requested","params":{"toolCall":{"toolCallId":"tool-1","title":"Run tests","kind":"execute","rawInput":{"command":"go test ./..."}},"options":[{"optionId":"allow","name":"Allow","kind":"allow_once"},{"optionId":"reject","name":"Reject","kind":"reject_once"}]}}\n'
685+ printf '{"method":"item/completed","params":{"item":{"type":"agent_message","id":"msg-1","text":"should not continue"}}}\n'
686+ ` )
687+ client := acptest .NewLiveClient (t , codexadapter .NewServer ("test" ), tt .option )
688+ client .Request ("initialize" , "initialize" , map [string ]any {}, time .Second )
689+ createdResponses := client .Request ("new-session" , "session/new" , map [string ]any {"cwd" : t .TempDir ()}, time .Second )
690+ var session struct {
691+ SessionID string `json:"sessionId"`
692+ }
693+ createdResponses [len (createdResponses )- 1 ].ResultInto (t , & session )
694+
695+ responses := client .PromptText ("prompt" , session .SessionID , "hello" , time .Second )
696+ if len (responses ) < 3 {
697+ t .Fatalf ("responses = %#v, want tool start + permission request + prompt error" , responses )
698+ }
699+ permission := decodePermissionRequest (t , responses [1 ])
700+ if permission .ToolCall .ToolCallID != "tool-1" ||
701+ permission .ToolCall .Title != "Run tests" ||
702+ permission .ToolCall .Kind != "execute" {
703+ t .Fatalf ("permission = %#v, want Codex stream permission request" , permission )
704+ }
705+ for _ , response := range responses {
706+ if response .Method != "session/update" {
707+ continue
708+ }
709+ update := decodeSessionUpdate (t , response )
710+ if update .Update .SessionUpdate == "agent_message_chunk" {
711+ t .Fatalf ("responses = %#v, did not expect assistant continuation after denied permission" , responses )
712+ }
713+ }
714+ final := responses [len (responses )- 1 ]
715+ if final .Error == nil ||
716+ final .Error .Message != "prompt command failed" ||
717+ ! strings .Contains (fmt .Sprint (final .Error .Data ), tt .wantReason ) {
718+ t .Fatalf ("final response = %#v, want prompt command failed with %q" , final , tt .wantReason )
719+ }
720+ })
721+ }
722+ }
723+
658724func TestPromptCommandRequiresWorkspace (t * testing.T ) {
659725 _ , err := codexadapter .PromptCommand (commandbridge.Session {}, runtimeacp.PromptParams {
660726 Prompt : []runtimeacp.ContentBlock {{Type : "text" , Text : "hello" }},
0 commit comments