@@ -2760,17 +2760,128 @@ it.layer(
27602760 }
27612761 }
27622762
2763- for ( const source of [ "inherited" , "request" , "provider" , "empty" , "unset" ] as const ) {
2763+ for ( const source of [ "inherited" , "request" , "provider" ] as const ) {
2764+ for ( const home of [ "~/legacy" , "~//legacy" ] as const ) {
2765+ for ( const selectedUnsafe of [ true , false ] ) {
2766+ it . effect . skipIf ( ! symlinksSupported ) (
2767+ `checks one-pass native HOME expansion for ${ source } (${ home } , ${ selectedUnsafe ? "selected unsafe" : "unused unsafe" } )` ,
2768+ ( ) =>
2769+ Effect . gen ( function * ( ) {
2770+ const fs = yield * FileSystem . FileSystem ;
2771+ const path = yield * Path . Path ;
2772+ const root = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-native-tilde-" } ) ;
2773+ const selected = path . join ( root , "~" , "legacy" , "legacy" , ".codex" ) ;
2774+ const unexpanded = path . join ( root , "~" , "legacy" , ".codex" ) ;
2775+ for ( const directory of [ selected , unexpanded ] ) {
2776+ yield * fs . makeDirectory ( directory , { recursive : true } ) ;
2777+ }
2778+ const unsafe = selectedUnsafe ? selected : unexpanded ;
2779+ const database = path . join ( root , "database.sqlite" ) ;
2780+ const link = path . join ( unsafe , "state_5.sqlite" ) ;
2781+ yield * fs . writeFileString ( database , "preserved database" ) ;
2782+ yield * fs . symlink ( database , link ) ;
2783+ for ( const sidecar of [ "wal" , "shm" , "journal" ] ) {
2784+ yield * fs . writeFileString ( path . join ( unsafe , `state_5.sqlite-${ sidecar } ` ) , sidecar ) ;
2785+ }
2786+ const providerInstanceId = ProviderInstanceId . make ( "codex_native_tilde" ) ;
2787+ const environment =
2788+ source === "provider" ? [ { name : "HOME" , value : home , sensitive : false } ] : [ ] ;
2789+ const serverSettings = yield * ServerSettings . ServerSettingsService . pipe (
2790+ Effect . provide (
2791+ ServerSettings . layerTest ( {
2792+ providerInstances : {
2793+ [ providerInstanceId ] : {
2794+ driver : ProviderDriverKind . make ( "codex" ) ,
2795+ config : { setupMode : "managed" , homePath : "" , shadowHomePath : "" } ,
2796+ environment,
2797+ } ,
2798+ } ,
2799+ } ) ,
2800+ ) ,
2801+ ) ;
2802+ const inherited = source === "inherited" ? { HOME : home } : { } ;
2803+ const { manager, ptyAdapter } = yield * createManager ( 5 , {
2804+ env : inherited ,
2805+ resolveProviderInstanceEnvironment : (
2806+ rawProviderInstanceId ,
2807+ env ,
2808+ inheritedEnvironment ,
2809+ cwd ,
2810+ ) =>
2811+ TerminalManager . resolveProviderInstanceTerminalEnvironment ( {
2812+ serverSettings,
2813+ path,
2814+ rawProviderInstanceId,
2815+ stateDir : root ,
2816+ cwd,
2817+ env,
2818+ inheritedEnvironment,
2819+ } ) . pipe (
2820+ Effect . provideService ( HostProcess . HomeDirectory , path . join ( root , "server" ) ) ,
2821+ ) ,
2822+ } ) ;
2823+ const input = openInput ( {
2824+ providerInstanceId,
2825+ cwd : root ,
2826+ env : source === "request" ? { HOME : home } : undefined ,
2827+ } ) ;
2828+ const original = JSON . stringify ( [ input , inherited , environment ] ) ;
2829+ for ( let attempt = 0 ; attempt < 2 ; attempt += 1 ) {
2830+ const result = yield * manager . open ( input ) . pipe ( Effect . result ) ;
2831+ expect ( result . _tag ) . toBe ( selectedUnsafe ? "Failure" : "Success" ) ;
2832+ if ( result . _tag === "Failure" ) {
2833+ expect ( result . failure ) . toMatchObject ( {
2834+ _tag : "TerminalProviderEnvironmentError" ,
2835+ cause : { _tag : "CodexShadowHomeSqliteRecoveryRequiredError" , linkPath : link } ,
2836+ } ) ;
2837+ expect ( result . failure . message ) . not . toContain ( root ) ;
2838+ expect ( ptyAdapter . spawnInputs ) . toHaveLength ( 0 ) ;
2839+ } else {
2840+ expect ( ptyAdapter . spawnInputs ) . toHaveLength ( 1 ) ;
2841+ expect ( ptyAdapter . spawnInputs [ 0 ] ?. env . HOME ) . toBe ( home ) ;
2842+ expect ( ptyAdapter . spawnInputs [ 0 ] ?. env . CODEX_HOME ) . toBeUndefined ( ) ;
2843+ expect ( ptyAdapter . spawnInputs [ 0 ] ?. env . CODEX_SQLITE_HOME ) . toBeUndefined ( ) ;
2844+ }
2845+ expect ( yield * fs . readLink ( link ) ) . toBe ( database ) ;
2846+ expect ( yield * fs . readFileString ( database ) ) . toBe ( "preserved database" ) ;
2847+ for ( const sidecar of [ "wal" , "shm" , "journal" ] ) {
2848+ expect (
2849+ yield * fs . readFileString ( path . join ( unsafe , `state_5.sqlite-${ sidecar } ` ) ) ,
2850+ ) . toBe ( sidecar ) ;
2851+ }
2852+ expect ( JSON . stringify ( [ input , inherited , environment ] ) ) . toBe ( original ) ;
2853+ expect ( yield * fs . exists ( path . join ( root , "providers" ) ) ) . toBe ( false ) ;
2854+ }
2855+ } ) . pipe ( Effect . provideService ( HostProcess . Platform , "linux" ) ) ,
2856+ ) ;
2857+ }
2858+ }
2859+ }
2860+
2861+ for ( const source of [
2862+ "inherited" ,
2863+ "request" ,
2864+ "provider" ,
2865+ "empty" ,
2866+ "unset" ,
2867+ "tilde-inherited" ,
2868+ "tilde-request" ,
2869+ "tilde-provider" ,
2870+ ] as const ) {
27642871 it . effect . skipIf ( ! symlinksSupported ) (
27652872 `refuses restart before killing an existing terminal selected through ${ source } HOME` ,
27662873 ( ) =>
27672874 Effect . gen ( function * ( ) {
27682875 const fs = yield * FileSystem . FileSystem ;
27692876 const path = yield * Path . Path ;
27702877 const root = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-terminal-native-home-" } ) ;
2771- const home = path . join ( root , "terminal-home" ) ;
2772- const codexHome = path . join ( home , ".codex" ) ;
2773- const accountFallback = source === "empty" || source === "unset" ;
2878+ const tilde = source . startsWith ( "tilde-" ) ;
2879+ const homeSource = tilde ? source . slice ( 6 ) : source ;
2880+ const home = tilde ? "~/legacy" : path . join ( root , "terminal-home" ) ;
2881+ const codexHome = tilde
2882+ ? path . join ( root , "~" , "legacy" , "legacy" , ".codex" )
2883+ : path . join ( home , ".codex" ) ;
2884+ const accountFallback = homeSource === "empty" || homeSource === "unset" ;
27742885 yield * fs . makeDirectory ( codexHome , { recursive : true } ) ;
27752886 const providerInstanceId = ProviderInstanceId . make ( "codex_native_home" ) ;
27762887 const serverSettings = yield * ServerSettings . ServerSettingsService . pipe (
@@ -2781,7 +2892,7 @@ it.layer(
27812892 driver : ProviderDriverKind . make ( "codex" ) ,
27822893 config : { setupMode : "managed" , homePath : "" , shadowHomePath : "" } ,
27832894 environment :
2784- source === "provider"
2895+ homeSource === "provider"
27852896 ? [ { name : "HOME" , value : home , sensitive : false } ]
27862897 : [ ] ,
27872898 } ,
@@ -2791,9 +2902,9 @@ it.layer(
27912902 ) ;
27922903 const { manager, ptyAdapter } = yield * createManager ( 5 , {
27932904 env :
2794- source === "unset"
2905+ homeSource === "unset"
27952906 ? { }
2796- : { HOME : source === "inherited" ? home : path . join ( root , "server-home" ) } ,
2907+ : { HOME : homeSource === "inherited" ? home : path . join ( root , "server-home" ) } ,
27972908 resolveProviderInstanceEnvironment : (
27982909 rawProviderInstanceId ,
27992910 env ,
@@ -2820,12 +2931,16 @@ it.layer(
28202931 providerInstanceId,
28212932 cwd : root ,
28222933 env :
2823- source === "empty" ? { HOME : "" } : source === "request" ? { HOME : home } : undefined ,
2934+ homeSource === "empty"
2935+ ? { HOME : "" }
2936+ : homeSource === "request"
2937+ ? { HOME : home }
2938+ : undefined ,
28242939 } ) ;
28252940 yield * manager . open ( input ) ;
28262941 expect ( ptyAdapter . spawnInputs ) . toHaveLength ( 1 ) ;
28272942 expect ( ptyAdapter . spawnInputs [ 0 ] ?. env . HOME ) . toBe (
2828- source === "empty" ? "" : source === "unset" ? undefined : home ,
2943+ homeSource === "empty" ? "" : homeSource === "unset" ? undefined : home ,
28292944 ) ;
28302945 expect ( ptyAdapter . spawnInputs [ 0 ] ?. env . CODEX_HOME ) . toBeUndefined ( ) ;
28312946 expect ( ptyAdapter . spawnInputs [ 0 ] ?. env . CODEX_SQLITE_HOME ) . toBeUndefined ( ) ;
0 commit comments