@@ -40,6 +40,7 @@ type SessionConfig = {
4040 model : string ;
4141 variant ?: string | null ;
4242} ;
43+ type ActiveSessionType = 'cloud-agent' | 'cli' ;
4344type StandaloneQuestion = { requestId : string ; questions : QuestionInfo [ ] } ;
4445type StandalonePermission = {
4546 requestId : string ;
@@ -95,6 +96,8 @@ type SessionManagerConfig = {
9596 onComplete ?: ( ) => void ;
9697 onBranchChanged ?: ( branch : string ) => void ;
9798 onSendFailed ?: ( messageText : string ) => void ;
99+ onRemoteSessionOpened ?: ( data : { kiloSessionId : KiloSessionId } ) => void ;
100+ onRemoteSessionMessageSent ?: ( data : { kiloSessionId : KiloSessionId } ) => void ;
98101} ;
99102
100103// Writable/read-only atom aliases for the public atoms record
@@ -299,6 +302,7 @@ function createSessionManager(config: SessionManagerConfig): SessionManager {
299302 // Private mutable state
300303 let activeSessionId : KiloSessionId | null = null ;
301304 let currentSession : CloudAgentSession | null = null ;
305+ let activeSessionType : ActiveSessionType | null = null ;
302306 let stateUnsub : ( ( ) => void ) | null = null ;
303307 let indicatorTimer : ReturnType < typeof setTimeout > | null = null ;
304308
@@ -418,6 +422,7 @@ function createSessionManager(config: SessionManagerConfig): SessionManager {
418422
419423 async function switchSession ( kiloSessionId : KiloSessionId ) : Promise < void > {
420424 activeSessionId = kiloSessionId ;
425+ activeSessionType = null ;
421426 stateUnsub ?.( ) ;
422427 stateUnsub = null ;
423428 currentSession ?. destroy ( ) ;
@@ -500,6 +505,10 @@ function createSessionManager(config: SessionManagerConfig): SessionManager {
500505 const ap = store . get ( activePermissionAtom ) ;
501506 if ( ap ?. requestId === requestId ) store . set ( activePermissionAtom , null ) ;
502507 } ,
508+ onResolved : resolved => {
509+ if ( resolved . cloudAgentSessionId ) activeSessionType = 'cloud-agent' ;
510+ else if ( resolved . isLive ) activeSessionType = 'cli' ;
511+ } ,
503512 onBranchChanged : branch => {
504513 const currentFetched = store . get ( fetchedSessionDataAtom ) ;
505514 if ( currentFetched ) {
@@ -538,6 +547,9 @@ function createSessionManager(config: SessionManagerConfig): SessionManager {
538547 // Fallback: clear loading when events flow even if no root
539548 // session.created was replayed (e.g. CLI snapshot failure).
540549 store . set ( isLoadingAtom , false ) ;
550+ if ( activeSessionType === 'cli' ) {
551+ config . onRemoteSessionOpened ?.( { kiloSessionId } ) ;
552+ }
541553 } ,
542554 } ) ;
543555 session . connect ( ) ;
@@ -567,12 +579,18 @@ function createSessionManager(config: SessionManagerConfig): SessionManager {
567579 } satisfies StoredMessage ) ;
568580 try {
569581 if ( ! currentSession ) throw new Error ( 'No active session' ) ;
582+ // Snapshot before await — switchSession() can overwrite these while send is in flight.
583+ const sessionType = activeSessionType ;
584+ const kiloSessionId = activeSessionId ;
570585 await currentSession . send ( {
571586 prompt : payload . prompt ,
572587 mode : payload . mode ,
573588 model : payload . model ,
574589 variant : payload . variant ,
575590 } ) ;
591+ if ( sessionType === 'cli' && kiloSessionId ) {
592+ config . onRemoteSessionMessageSent ?.( { kiloSessionId } ) ;
593+ }
576594 } catch ( err ) {
577595 store . set ( optimisticMessageAtom , null ) ;
578596 store . set ( failedPromptAtom , payload . prompt ) ;
@@ -635,6 +653,7 @@ function createSessionManager(config: SessionManagerConfig): SessionManager {
635653 }
636654 clearAllAtoms ( ) ;
637655 activeSessionId = null ;
656+ activeSessionType = null ;
638657 }
639658
640659 return {
0 commit comments