@@ -4635,9 +4635,9 @@ func TestRun_ExplicitStdinReadError(t *testing.T) {
46354635 if ! strings .Contains (logOutput , "Failed to read stdin: broken stdin" ) {
46364636 t .Fatalf ("log missing read error entry, got %q" , logOutput )
46374637 }
4638- // Log file is always removed after completion (new behavior)
4639- if _ , err := os .Stat (logPath ); ! os . IsNotExist ( err ) {
4640- t .Fatalf ("log file should be removed after completion" )
4638+ // Log file should remain for inspection; cleanup is handled via `codeagent-wrapper cleanup`.
4639+ if _ , err := os .Stat (logPath ); err != nil {
4640+ t .Fatalf ("expected log file to exist after completion: %v" , err )
46414641 }
46424642}
46434643
@@ -4653,6 +4653,51 @@ func TestRun_CommandFails(t *testing.T) {
46534653 }
46544654}
46554655
4656+ func TestRun_NonZeroExitPrintsParsedMessage (t * testing.T ) {
4657+ defer resetTestHooks ()
4658+
4659+ tempDir := t .TempDir ()
4660+ var scriptPath string
4661+ if runtime .GOOS == "windows" {
4662+ scriptPath = filepath .Join (tempDir , "codex.bat" )
4663+ script := "@echo off\r \n " +
4664+ "echo {\" type\" :\" thread.started\" ,\" thread_id\" :\" tid\" }\r \n " +
4665+ "echo {\" type\" :\" item.completed\" ,\" item\" :{\" type\" :\" agent_message\" ,\" text\" :\" parsed-error\" }}\r \n " +
4666+ "exit /b 1\r \n "
4667+ if err := os .WriteFile (scriptPath , []byte (script ), 0o755 ); err != nil {
4668+ t .Fatalf ("failed to write script: %v" , err )
4669+ }
4670+ } else {
4671+ scriptPath = filepath .Join (tempDir , "codex.sh" )
4672+ script := `#!/bin/sh
4673+ printf '%s\n' '{"type":"thread.started","thread_id":"tid"}'
4674+ printf '%s\n' '{"type":"item.completed","item":{"type":"agent_message","text":"parsed-error"}}'
4675+ sleep 0.05
4676+ exit 1
4677+ `
4678+ if err := os .WriteFile (scriptPath , []byte (script ), 0o755 ); err != nil {
4679+ t .Fatalf ("failed to write script: %v" , err )
4680+ }
4681+ }
4682+
4683+ restore := withBackend (scriptPath , func (cfg * Config , targetArg string ) []string { return []string {} })
4684+ defer restore ()
4685+
4686+ os .Args = []string {"codeagent-wrapper" , "task" }
4687+ stdinReader = strings .NewReader ("" )
4688+ isTerminalFn = func () bool { return true }
4689+
4690+ var exitCode int
4691+ output := captureOutput (t , func () { exitCode = run () })
4692+ if exitCode != 1 {
4693+ t .Fatalf ("exit=%d, want 1" , exitCode )
4694+ }
4695+
4696+ if ! strings .Contains (output , "parsed-error" ) {
4697+ t .Fatalf ("stdout=%q, want parsed backend message" , output )
4698+ }
4699+ }
4700+
46564701func TestRun_InvalidBackend (t * testing.T ) {
46574702 defer resetTestHooks ()
46584703 os .Args = []string {"codeagent-wrapper" , "--backend" , "unknown" , "task" }
@@ -4732,9 +4777,9 @@ func TestRun_PipedTaskReadError(t *testing.T) {
47324777 if ! strings .Contains (logOutput , "Failed to read piped stdin: read stdin: pipe failure" ) {
47334778 t .Fatalf ("log missing piped read error, got %q" , logOutput )
47344779 }
4735- // Log file is always removed after completion (new behavior)
4736- if _ , err := os .Stat (logPath ); ! os . IsNotExist ( err ) {
4737- t .Fatalf ("log file should be removed after completion" )
4780+ // Log file should remain for inspection; cleanup is handled via `codeagent-wrapper cleanup`.
4781+ if _ , err := os .Stat (logPath ); err != nil {
4782+ t .Fatalf ("expected log file to exist after completion: %v" , err )
47384783 }
47394784}
47404785
@@ -4788,12 +4833,12 @@ func TestRun_LoggerLifecycle(t *testing.T) {
47884833 if ! fileExisted {
47894834 t .Fatalf ("log file was not present during run" )
47904835 }
4791- if _ , err := os .Stat (logPath ); ! os . IsNotExist ( err ) {
4792- t .Fatalf ("log file should be removed on success, but it exists" )
4836+ if _ , err := os .Stat (logPath ); err != nil {
4837+ t .Fatalf ("expected log file to exist on success: %v" , err )
47934838 }
47944839}
47954840
4796- func TestRun_LoggerRemovedOnSignal (t * testing.T ) {
4841+ func TestRun_LoggerKeptOnSignal (t * testing.T ) {
47974842 if runtime .GOOS == "windows" {
47984843 t .Skip ("signal-based test is not supported on Windows" )
47994844 }
@@ -4807,7 +4852,8 @@ func TestRun_LoggerRemovedOnSignal(t *testing.T) {
48074852 defer signal .Reset (syscall .SIGINT , syscall .SIGTERM )
48084853
48094854 // Set shorter delays for faster test
4810- _ = executor .SetForceKillDelay (1 )
4855+ restoreForceKillDelay := executor .SetForceKillDelay (1 )
4856+ defer restoreForceKillDelay ()
48114857
48124858 tempDir := setTempDirEnv (t , t .TempDir ())
48134859 logPath := filepath .Join (tempDir , fmt .Sprintf ("codeagent-wrapper-%d.log" , os .Getpid ()))
@@ -4830,13 +4876,19 @@ printf '%s\n' '{"type":"item.completed","item":{"type":"agent_message","text":"l
48304876 exitCh := make (chan int , 1 )
48314877 go func () { exitCh <- run () }()
48324878
4833- deadline := time .Now ().Add (1 * time .Second )
4879+ ready := false
4880+ deadline := time .Now ().Add (2 * time .Second )
48344881 for time .Now ().Before (deadline ) {
4835- if _ , err := os .Stat (logPath ); err == nil {
4882+ data , err := os .ReadFile (logPath )
4883+ if err == nil && strings .Contains (string (data ), "Starting " ) {
4884+ ready = true
48364885 break
48374886 }
48384887 time .Sleep (10 * time .Millisecond )
48394888 }
4889+ if ! ready {
4890+ t .Fatalf ("logger did not become ready before deadline" )
4891+ }
48404892
48414893 if proc , err := os .FindProcess (os .Getpid ()); err == nil && proc != nil {
48424894 _ = proc .Signal (syscall .SIGINT )
@@ -4852,9 +4904,9 @@ printf '%s\n' '{"type":"item.completed","item":{"type":"agent_message","text":"l
48524904 if exitCode != 130 {
48534905 t .Fatalf ("exit code = %d, want 130" , exitCode )
48544906 }
4855- // Log file is always removed after completion (new behavior)
4856- if _ , err := os .Stat (logPath ); ! os . IsNotExist ( err ) {
4857- t .Fatalf ("log file should be removed after completion" )
4907+ // Log file should remain for inspection; cleanup is handled via `codeagent-wrapper cleanup`.
4908+ if _ , err := os .Stat (logPath ); err != nil {
4909+ t .Fatalf ("expected log file to exist after completion: %v" , err )
48584910 }
48594911}
48604912
@@ -5115,6 +5167,34 @@ func TestParallelLogPathInSerialMode(t *testing.T) {
51155167 }
51165168}
51175169
5170+ func TestRun_KeptLogFileOnSuccess (t * testing.T ) {
5171+ defer resetTestHooks ()
5172+
5173+ tempDir := setTempDirEnv (t , t .TempDir ())
5174+
5175+ os .Args = []string {"codeagent-wrapper" , "do-stuff" }
5176+ stdinReader = strings .NewReader ("" )
5177+ isTerminalFn = func () bool { return true }
5178+ codexCommand = createFakeCodexScript (t , "cli-session" , "ok" )
5179+ buildCodexArgsFn = func (cfg * Config , targetArg string ) []string { return []string {} }
5180+ cleanupLogsFn = nil
5181+
5182+ var exitCode int
5183+ _ = captureStderr (t , func () {
5184+ _ = captureOutput (t , func () {
5185+ exitCode = run ()
5186+ })
5187+ })
5188+ if exitCode != 0 {
5189+ t .Fatalf ("run() exit = %d, want 0" , exitCode )
5190+ }
5191+
5192+ expectedLog := filepath .Join (tempDir , fmt .Sprintf ("codeagent-wrapper-%d.log" , os .Getpid ()))
5193+ if _ , err := os .Stat (expectedLog ); err != nil {
5194+ t .Fatalf ("expected log file to exist: %v" , err )
5195+ }
5196+ }
5197+
51185198func TestRun_CLI_Success (t * testing.T ) {
51195199 defer resetTestHooks ()
51205200 os .Args = []string {"codeagent-wrapper" , "do-things" }
0 commit comments