@@ -20,7 +20,7 @@ import {
2020 * invariants + the on-disk edit, never model prose. Opt-in: each arm self-skips
2121 * unless `POSTHOG_CODE_E2E_GATEWAY_PERSONAL_API_KEY` is set (codex also needs the native binary).
2222 */
23- const ADAPTERS : Adapter [ ] = [ "claude" , "codex" ] ;
23+ const ADAPTERS : Adapter [ ] = [ "claude" , "codex" , "hog" ] ;
2424
2525const EDIT_PROMPT =
2626 "Do exactly these steps and nothing else: 1) Read the file target.txt. " +
@@ -31,8 +31,10 @@ const EDIT_PROMPT =
3131for ( const adapter of ADAPTERS ) {
3232 const skip = E2E . skipReason ( adapter ) ;
3333 const title = `session lifecycle (${ adapter } )${ skip ? ` — SKIPPED (${ skip } )` : "" } ` ;
34- // Codex-only; skipped on the claude arm so the gap is visible .
34+ // Adapter-specific coverage where the other harnesses do not implement the feature .
3535 const itCodex = adapter === "codex" ? it : it . skip ;
36+ const itWithModes = adapter !== "hog" ? it : it . skip ;
37+ const itNativeSteer = adapter === "codex" || adapter === "hog" ? it : it . skip ;
3638 // Read-only profile only tightens per-turn on macOS + non-cloud (elsewhere the
3739 // spawn is danger-full-access / no profile), so gate to where it actually applies.
3840 const itCodexSandbox =
@@ -46,6 +48,7 @@ for (const adapter of ADAPTERS) {
4648 let repo : string ;
4749 const codexOptions = ( ) =>
4850 adapter === "codex" ? E2E . codexOptions ( repo ) : undefined ;
51+ const hogGateway = ( ) => ( adapter === "hog" ? E2E . hogGateway ( ) : undefined ) ;
4952 const meta = ( extra : Record < string , unknown > = { } ) => ( {
5053 systemPrompt : "You are a coding assistant in a tiny test repo." ,
5154 model : E2E . model ( adapter ) ,
@@ -69,6 +72,7 @@ for (const adapter of ADAPTERS) {
6972 adapter,
7073 cwd : repo ,
7174 codexOptions : codexOptions ( ) ,
75+ hogGateway : hogGateway ( ) ,
7276 meta : meta ( ) ,
7377 } ) ;
7478 sessionId = s . sessionId ;
@@ -153,6 +157,7 @@ for (const adapter of ADAPTERS) {
153157 adapter,
154158 cwd : repo ,
155159 codexOptions : codexOptions ( ) ,
160+ hogGateway : hogGateway ( ) ,
156161 meta : meta ( ) ,
157162 } ) ;
158163 try {
@@ -190,37 +195,42 @@ for (const adapter of ADAPTERS) {
190195 }
191196 } , 90_000 ) ;
192197
193- // Cloud host switches mode only via setSessionConfigOption(configId:"mode"), so exercise both arms.
194- it ( "emits current_mode_update when the mode is switched via setSessionConfigOption" , async ( ) => {
195- const s = await openSession ( {
196- adapter,
197- cwd : repo ,
198- codexOptions : codexOptions ( ) ,
199- meta : meta ( ) ,
200- } ) ;
201- try {
202- // codex synthesizes modes; claude exposes a "mode" configOption — pick an alternate value.
203- let value = "read-only" ;
204- if ( adapter === "claude" ) {
205- const modeOpt = ( s . newSession . configOptions ?? [ ] ) . find (
206- ( o ) => o . id === "mode" ,
207- ) ;
208- value =
209- ( modeOpt ?. options ?. find ( ( v ) => v . value !== modeOpt . currentValue )
210- ?. value as string ) ?? "plan" ;
211- }
212- await s . conn . setSessionConfigOption ( {
213- sessionId : s . sessionId ,
214- configId : "mode" ,
215- value,
198+ // Cloud host switches mode only via setSessionConfigOption(configId:"mode"), so exercise every harness that exposes a mode picker.
199+ itWithModes (
200+ "emits current_mode_update when the mode is switched via setSessionConfigOption" ,
201+ async ( ) => {
202+ const s = await openSession ( {
203+ adapter,
204+ cwd : repo ,
205+ codexOptions : codexOptions ( ) ,
206+ hogGateway : hogGateway ( ) ,
207+ meta : meta ( ) ,
216208 } ) ;
217- expect ( s . capture . updates ( "current_mode_update" ) . length ) . toBeGreaterThan (
218- 0 ,
219- ) ;
220- } finally {
221- await s . cleanup ( ) ;
222- }
223- } , 60_000 ) ;
209+ try {
210+ // codex synthesizes modes; claude exposes a "mode" configOption — pick an alternate value.
211+ let value = "read-only" ;
212+ if ( adapter === "claude" ) {
213+ const modeOpt = ( s . newSession . configOptions ?? [ ] ) . find (
214+ ( o ) => o . id === "mode" ,
215+ ) ;
216+ value =
217+ ( modeOpt ?. options ?. find ( ( v ) => v . value !== modeOpt . currentValue )
218+ ?. value as string ) ?? "plan" ;
219+ }
220+ await s . conn . setSessionConfigOption ( {
221+ sessionId : s . sessionId ,
222+ configId : "mode" ,
223+ value,
224+ } ) ;
225+ expect (
226+ s . capture . updates ( "current_mode_update" ) . length ,
227+ ) . toBeGreaterThan ( 0 ) ;
228+ } finally {
229+ await s . cleanup ( ) ;
230+ }
231+ } ,
232+ 60_000 ,
233+ ) ;
224234
225235 // Proves the mode picker isn't cosmetic: read-only maps to an OS-level
226236 // :read-only profile that blocks the write even though the host auto-approves.
@@ -322,6 +332,7 @@ for (const adapter of ADAPTERS) {
322332 adapter,
323333 cwd : repo ,
324334 codexOptions : codexOptions ( ) ,
335+ hogGateway : hogGateway ( ) ,
325336 meta : meta ( ) ,
326337 } ) ;
327338 try {
@@ -351,6 +362,7 @@ for (const adapter of ADAPTERS) {
351362 adapter,
352363 cwd : repo ,
353364 codexOptions : codexOptions ( ) ,
365+ hogGateway : hogGateway ( ) ,
354366 meta : meta ( ) ,
355367 } ) ;
356368 try {
@@ -377,7 +389,7 @@ for (const adapter of ADAPTERS) {
377389 }
378390 } , 120_000 ) ;
379391
380- itCodex (
392+ itNativeSteer (
381393 "folds a mid-turn prompt into the running turn via steering" ,
382394 async ( ) => {
383395 const s = await openSession ( {
@@ -431,13 +443,14 @@ for (const adapter of ADAPTERS) {
431443 120_000 ,
432444 ) ;
433445
434- itCodex (
446+ itNativeSteer (
435447 "lists the session and forks it" ,
436448 async ( ) => {
437449 const b = openConnection ( {
438450 adapter,
439451 cwd : repo ,
440452 codexOptions : codexOptions ( ) ,
453+ hogGateway : hogGateway ( ) ,
441454 } ) ;
442455 try {
443456 await b . conn . initialize ( INIT_PARAMS ) ;
@@ -468,6 +481,7 @@ for (const adapter of ADAPTERS) {
468481 adapter,
469482 cwd : repo ,
470483 codexOptions : codexOptions ( ) ,
484+ hogGateway : hogGateway ( ) ,
471485 meta : meta ( ) ,
472486 } ) ;
473487 try {
@@ -509,6 +523,7 @@ for (const adapter of ADAPTERS) {
509523 adapter,
510524 cwd : repo ,
511525 codexOptions : codexOptions ( ) ,
526+ hogGateway : hogGateway ( ) ,
512527 } ) ;
513528 try {
514529 await b . conn . initialize ( INIT_PARAMS ) ;
@@ -530,6 +545,7 @@ for (const adapter of ADAPTERS) {
530545 adapter,
531546 cwd : repo ,
532547 codexOptions : codexOptions ( ) ,
548+ hogGateway : hogGateway ( ) ,
533549 } ) ;
534550 try {
535551 await b . conn . initialize ( INIT_PARAMS ) ;
0 commit comments