@@ -14,7 +14,7 @@ import { fileURLToPath } from "node:url";
1414import { spawn } from "node:child_process" ;
1515import test from "node:test" ;
1616
17- import { ENGINES , agentLaunchArgs } from "../src/engines.mjs" ;
17+ import { ENGINES , agentLaunchArgs , exitReason , ranOk , runCmd } from "../src/engines.mjs" ;
1818
1919const BIN = fileURLToPath ( new URL ( "../bin/moshcode.mjs" , import . meta. url ) ) ;
2020// The autonomous-session bypass flags each engine declares (engine.agentArgs).
@@ -130,3 +130,30 @@ test("bare engine launch remains a raw passthrough", async () => {
130130 assert . deepEqual ( JSON . parse ( result . stdout ) , [ "--model" , "sonnet" ] ) ;
131131 assert . equal ( result . stderr , "" ) ;
132132} ) ;
133+
134+ test ( "a signal-killed child is a failure, not a codeless success" , async ( ) => {
135+ const r = await runCmd ( "bash" , [ "-c" , "kill -9 $$" ] ) ;
136+
137+ // Node reports a signal death with code === null — the old `code == null`
138+ // success check read that as "exited cleanly".
139+ assert . equal ( r . ok , true ) ;
140+ assert . equal ( r . code , null ) ;
141+ assert . equal ( r . signal , "SIGKILL" ) ;
142+
143+ assert . equal ( ranOk ( r ) , false ) ;
144+ assert . equal ( exitReason ( r ) , "SIGKILL" ) ;
145+ } ) ;
146+
147+ test ( "ranOk and exitReason cover clean exits, bad codes, and spawn errors" , async ( ) => {
148+ const clean = await runCmd ( "bash" , [ "-c" , "exit 0" ] ) ;
149+ assert . equal ( ranOk ( clean ) , true ) ;
150+ assert . equal ( exitReason ( clean ) , null ) ;
151+
152+ const bad = await runCmd ( "bash" , [ "-c" , "exit 128" ] ) ;
153+ assert . equal ( ranOk ( bad ) , false ) ;
154+ assert . equal ( exitReason ( bad ) , "code 128" ) ;
155+
156+ const missing = await runCmd ( "moshcode-does-not-exist-xyz" , [ ] ) ;
157+ assert . equal ( ranOk ( missing ) , false ) ;
158+ assert . match ( exitReason ( missing ) , / E N O E N T | n o t f o u n d | s p a w n / i) ;
159+ } ) ;
0 commit comments