@@ -3043,6 +3043,84 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
30433043 } ) . pipe ( Effect . provide ( NodeHttpServer . layerTest ) ) ,
30443044 ) ;
30453045
3046+ it . effect ( "checks session status before archiving removes the thread from active lookups" , ( ) =>
3047+ Effect . gen ( function * ( ) {
3048+ const threadId = ThreadId . make ( "thread-archive-precheck" ) ;
3049+ const effects : string [ ] = [ ] ;
3050+ const dispatchedCommands : Array < OrchestrationCommand > = [ ] ;
3051+ const now = new Date ( ) . toISOString ( ) ;
3052+ let archived = false ;
3053+
3054+ yield * buildAppUnderTest ( {
3055+ layers : {
3056+ terminalManager : {
3057+ close : ( input ) =>
3058+ Effect . sync ( ( ) => {
3059+ effects . push ( `terminal.close:${ input . threadId } ` ) ;
3060+ } ) ,
3061+ } ,
3062+ orchestrationEngine : {
3063+ dispatch : ( command ) =>
3064+ Effect . sync ( ( ) => {
3065+ dispatchedCommands . push ( command ) ;
3066+ effects . push ( `dispatch:${ command . type } ` ) ;
3067+ if ( command . type === "thread.archive" ) {
3068+ archived = true ;
3069+ }
3070+ return { sequence : dispatchedCommands . length } ;
3071+ } ) ,
3072+ } ,
3073+ projectionSnapshotQuery : {
3074+ getThreadShellById : ( ) =>
3075+ Effect . sync ( ( ) => {
3076+ effects . push ( `query:thread-shell:${ archived ? "archived" : "active" } ` ) ;
3077+ return archived
3078+ ? Option . none ( )
3079+ : Option . some (
3080+ makeDefaultOrchestrationThreadShell ( {
3081+ id : threadId ,
3082+ updatedAt : now ,
3083+ session : {
3084+ threadId,
3085+ status : "ready" ,
3086+ providerName : "claudeAgent" ,
3087+ runtimeMode : "full-access" ,
3088+ activeTurnId : null ,
3089+ lastError : null ,
3090+ updatedAt : now ,
3091+ } ,
3092+ } ) ,
3093+ ) ;
3094+ } ) ,
3095+ } ,
3096+ } ,
3097+ } ) ;
3098+
3099+ const wsUrl = yield * getWsServerUrl ( "/ws" ) ;
3100+ const dispatchResult = yield * Effect . scoped (
3101+ withWsRpcClient ( wsUrl , ( client ) =>
3102+ client [ ORCHESTRATION_WS_METHODS . dispatchCommand ] ( {
3103+ type : "thread.archive" ,
3104+ commandId : CommandId . make ( "cmd-thread-archive-precheck" ) ,
3105+ threadId,
3106+ } ) ,
3107+ ) ,
3108+ ) ;
3109+
3110+ assert . equal ( dispatchResult . sequence , 1 ) ;
3111+ assert . deepEqual ( effects , [
3112+ "query:thread-shell:active" ,
3113+ "dispatch:thread.archive" ,
3114+ "dispatch:thread.session.stop" ,
3115+ `terminal.close:${ threadId } ` ,
3116+ ] ) ;
3117+ assert . deepEqual (
3118+ dispatchedCommands . map ( ( command ) => command . type ) ,
3119+ [ "thread.archive" , "thread.session.stop" ] ,
3120+ ) ;
3121+ } ) . pipe ( Effect . provide ( NodeHttpServer . layerTest ) ) ,
3122+ ) ;
3123+
30463124 it . effect ( "archives without dispatching session stop when the thread has no session" , ( ) =>
30473125 Effect . gen ( function * ( ) {
30483126 const threadId = ThreadId . make ( "thread-archive-no-session" ) ;
0 commit comments