@@ -16,7 +16,6 @@ import { EmptyMessages } from '@/components/EmptyMessages';
1616import { SessionActionsAnchor , SessionActionsPopover } from '@/components/SessionActionsPopover' ;
1717import { VoiceAssistantStatusBar } from '@/components/VoiceAssistantStatusBar' ;
1818import { useDraft } from '@/hooks/useDraft' ;
19- import { useSessionQuickActions } from '@/hooks/useSessionQuickActions' ;
2019import { Modal } from '@/modal' ;
2120import { voiceHooks } from '@/realtime/hooks/voiceHooks' ;
2221import { startRealtimeSession , stopRealtimeSession } from '@/realtime/RealtimeSession' ;
@@ -30,7 +29,7 @@ import { t } from '@/text';
3029import { tracking , trackMessageSent } from '@/track' ;
3130import { isRunningOnMac } from '@/utils/platform' ;
3231import { useDeviceType , useHeaderHeight , useIsLandscape , useIsTablet } from '@/utils/responsive' ;
33- import { formatPathRelativeToHome , getResumeCommand , getSessionAvatarId , getSessionName , useSessionStatus } from '@/utils/sessionUtils' ;
32+ import { formatPathRelativeToHome , getResumeCommandBlock , getSessionAvatarId , getSessionName , useSessionStatus } from '@/utils/sessionUtils' ;
3433import { isVersionSupported , MINIMUM_CLI_VERSION } from '@/utils/versionUtils' ;
3534import * as Clipboard from 'expo-clipboard' ;
3635import { Ionicons } from '@expo/vector-icons' ;
@@ -236,14 +235,10 @@ function SessionViewLoaded({ sessionId, session }: { sessionId: string, session:
236235 const alwaysShowContextSize = useSetting ( 'alwaysShowContextSize' ) ;
237236 const experiments = useSetting ( 'experiments' ) ;
238237 const expResumeSession = useSetting ( 'expResumeSession' ) ;
239- const resumeCommand = getResumeCommand ( session ) ;
240- const {
241- canResume,
242- canShowResume,
243- resumeSession,
244- resumeSessionSubtitle,
245- resumingSession,
246- } = useSessionQuickActions ( session ) ;
238+ const isArchivedSession = session . metadata ?. lifecycleState === 'archived' ;
239+ const isDisconnected = ! sessionStatus . isConnected ;
240+ const isInactiveArchivedSession = isArchivedSession && isDisconnected ;
241+ const resumeCommandBlock = getResumeCommandBlock ( session ) ;
247242
248243 // Use draft hook for auto-saving message drafts
249244 const { clearDraft } = useDraft ( sessionId , message , setMessage ) ;
@@ -340,7 +335,7 @@ function SessionViewLoaded({ sessionId, session }: { sessionId: string, session:
340335 </ >
341336 ) : null ;
342337
343- const input = sessionStatus . isConnected ? (
338+ const composer = (
344339 < AgentInput
345340 placeholder = { t ( 'session.inputPlaceholder' ) }
346341 value = { message }
@@ -359,6 +354,7 @@ function SessionViewLoaded({ sessionId, session }: { sessionId: string, session:
359354 dotColor : sessionStatus . statusDotColor ,
360355 isPulsing : sessionStatus . isPulsing
361356 } }
357+ blockSend = { isDisconnected }
362358 onSend = { ( ) => {
363359 if ( message . trim ( ) ) {
364360 setMessage ( '' ) ;
@@ -367,9 +363,9 @@ function SessionViewLoaded({ sessionId, session }: { sessionId: string, session:
367363 trackMessageSent ( ) ;
368364 }
369365 } }
370- onMicPress = { micButtonState . onMicPress }
371- isMicActive = { micButtonState . isMicActive }
372- onAbort = { ( ) => sessionAbort ( sessionId ) }
366+ onMicPress = { isDisconnected ? undefined : micButtonState . onMicPress }
367+ isMicActive = { isDisconnected ? false : micButtonState . isMicActive }
368+ onAbort = { isDisconnected ? undefined : ( ) => sessionAbort ( sessionId ) }
373369 showAbortButton = { sessionStatus . state === 'thinking' || sessionStatus . state === 'waiting' }
374370 onFileViewerPress = { experiments ? ( ) => router . push ( `/session/${ sessionId } /files` ) : undefined }
375371 autocompletePrefixes = { [ '@' , '/' ] }
@@ -389,61 +385,32 @@ function SessionViewLoaded({ sessionId, session }: { sessionId: string, session:
389385 } : undefined }
390386 alwaysShowContextSize = { alwaysShowContextSize }
391387 />
392- ) : canShowResume && expResumeSession ? (
393- < CenteredInputWidth horizontalPadding = { sessionInputHorizontalPadding } >
394- < View style = { {
395- paddingHorizontal : 16 ,
396- paddingTop : 12 ,
397- paddingBottom : 10 ,
398- gap : 10 ,
399- } } >
400- < Pressable
401- onPress = { resumeSession }
402- style = { {
403- minHeight : 48 ,
404- borderRadius : 14 ,
405- backgroundColor : canResume ? theme . colors . button . primary . background : theme . colors . surfaceHigh ,
406- alignItems : 'center' ,
407- justifyContent : 'center' ,
408- flexDirection : 'row' ,
409- gap : 8 ,
410- opacity : resumingSession ? 0.7 : 1 ,
411- } }
412- >
413- { resumingSession ? (
414- < ActivityIndicator size = "small" color = { canResume ? theme . colors . button . primary . tint : theme . colors . textSecondary } />
415- ) : (
416- < Ionicons
417- name = "play-circle-outline"
418- size = { 18 }
419- color = { canResume ? theme . colors . button . primary . tint : theme . colors . textSecondary }
420- />
421- ) }
422- < Text style = { {
423- color : canResume ? theme . colors . button . primary . tint : theme . colors . textSecondary ,
424- fontSize : 15 ,
425- fontWeight : '600' ,
426- } } >
427- { t ( 'sessionInfo.resumeSession' ) }
428- </ Text >
429- </ Pressable >
430- < Text style = { {
431- color : theme . colors . textSecondary ,
432- fontSize : 13 ,
433- lineHeight : 18 ,
434- textAlign : 'center' ,
435- paddingHorizontal : 8 ,
436- } } >
437- { resumeSessionSubtitle }
438- </ Text >
439- </ View >
440- </ CenteredInputWidth >
441- ) : ! sessionStatus . isConnected && resumeCommand ? (
388+ ) ;
389+
390+ const archivedHint = isInactiveArchivedSession ? (
442391 < CenteredInputWidth horizontalPadding = { sessionInputHorizontalPadding } >
443- < ResumeCommandHint command = { resumeCommand } />
392+ < InactiveArchivedHint
393+ resumeCommandBlock = { expResumeSession ? resumeCommandBlock : null }
394+ />
444395 </ CenteredInputWidth >
445396 ) : null ;
446397
398+ const input = isInactiveArchivedSession ? (
399+ < >
400+ { archivedHint }
401+ { composer }
402+ </ >
403+ ) : (
404+ < >
405+ { expResumeSession && isDisconnected && resumeCommandBlock && (
406+ < CenteredInputWidth horizontalPadding = { sessionInputHorizontalPadding } >
407+ < ResumeCommandHint resumeCommandBlock = { resumeCommandBlock } />
408+ </ CenteredInputWidth >
409+ ) }
410+ { composer }
411+ </ >
412+ ) ;
413+
447414
448415 return (
449416 < >
@@ -531,43 +498,14 @@ function SessionViewLoaded({ sessionId, session }: { sessionId: string, session:
531498 )
532499}
533500
534- function ResumeCommandHint ( { command } : { command : string } ) {
501+ function ResumeCommandHint ( { resumeCommandBlock } : {
502+ resumeCommandBlock : NonNullable < ReturnType < typeof getResumeCommandBlock > > ;
503+ } ) {
535504 const { theme } = useUnistyles ( ) ;
536- const [ copied , setCopied ] = React . useState ( false ) ;
505+
537506 return (
538507 < View style = { { paddingHorizontal : 16 , paddingTop : 12 , paddingBottom : 10 , gap : 8 } } >
539- < Pressable
540- onPress = { async ( ) => {
541- await Clipboard . setStringAsync ( command ) ;
542- setCopied ( true ) ;
543- setTimeout ( ( ) => setCopied ( false ) , 2000 ) ;
544- } }
545- style = { {
546- minHeight : 48 ,
547- borderRadius : 14 ,
548- backgroundColor : theme . colors . surfaceHigh ,
549- alignItems : 'center' ,
550- justifyContent : 'center' ,
551- flexDirection : 'row' ,
552- gap : 8 ,
553- paddingHorizontal : 16 ,
554- } }
555- >
556- < Ionicons name = "terminal-outline" size = { 16 } color = { theme . colors . textSecondary } />
557- < Text style = { {
558- color : theme . colors . text ,
559- fontSize : 13 ,
560- fontFamily : Platform . OS === 'ios' ? 'Menlo' : 'monospace' ,
561- flex : 1 ,
562- } } numberOfLines = { 1 } >
563- { command }
564- </ Text >
565- < Ionicons
566- name = { copied ? 'checkmark' : 'copy-outline' }
567- size = { 16 }
568- color = { copied ? '#30D158' : theme . colors . textSecondary }
569- />
570- </ Pressable >
508+ < ResumeCommandCopyBlock resumeCommandBlock = { resumeCommandBlock } />
571509 < Text style = { {
572510 color : theme . colors . textSecondary ,
573511 fontSize : 12 ,
@@ -581,6 +519,90 @@ function ResumeCommandHint({ command }: { command: string }) {
581519 ) ;
582520}
583521
522+ function InactiveArchivedHint ( props : {
523+ resumeCommandBlock : NonNullable < ReturnType < typeof getResumeCommandBlock > > | null ;
524+ } ) {
525+ const { theme } = useUnistyles ( ) ;
526+ const hintTextStyle = {
527+ color : theme . colors . agentEventText ,
528+ fontSize : 13 ,
529+ lineHeight : 18 ,
530+ textAlign : 'left' as const ,
531+ } ;
532+
533+ return (
534+ < View style = { {
535+ paddingTop : 12 ,
536+ paddingBottom : 10 ,
537+ gap : 10 ,
538+ alignItems : 'stretch' ,
539+ } } >
540+ < View style = { { paddingHorizontal : 8 , gap : 4 } } >
541+ < Text style = { hintTextStyle } >
542+ { t ( 'session.inactiveArchived' ) }
543+ </ Text >
544+ { props . resumeCommandBlock && (
545+ < Text style = { hintTextStyle } >
546+ { t ( 'session.resumeFromTerminal' ) }
547+ </ Text >
548+ ) }
549+ </ View >
550+ { props . resumeCommandBlock && (
551+ < ResumeCommandCopyBlock resumeCommandBlock = { props . resumeCommandBlock } />
552+ ) }
553+ </ View >
554+ ) ;
555+ }
556+
557+ function ResumeCommandCopyBlock ( { resumeCommandBlock } : {
558+ resumeCommandBlock : NonNullable < ReturnType < typeof getResumeCommandBlock > > ;
559+ } ) {
560+ const { theme } = useUnistyles ( ) ;
561+ const [ copied , setCopied ] = React . useState ( false ) ;
562+
563+ return (
564+ < Pressable
565+ onPress = { async ( ) => {
566+ await Clipboard . setStringAsync ( resumeCommandBlock . copyText ) ;
567+ setCopied ( true ) ;
568+ setTimeout ( ( ) => setCopied ( false ) , 2000 ) ;
569+ } }
570+ style = { {
571+ minHeight : 48 ,
572+ borderRadius : 14 ,
573+ backgroundColor : theme . colors . surfaceHigh ,
574+ flexDirection : 'row' ,
575+ gap : 8 ,
576+ paddingHorizontal : 16 ,
577+ paddingVertical : 12 ,
578+ alignItems : 'flex-start' ,
579+ } }
580+ >
581+ < View style = { { flex : 1 } } >
582+ { resumeCommandBlock . lines . map ( ( line , index ) => (
583+ < Text
584+ key = { `${ line } -${ index } ` }
585+ style = { {
586+ color : theme . colors . text ,
587+ fontSize : 13 ,
588+ lineHeight : 18 ,
589+ fontFamily : Platform . OS === 'ios' ? 'Menlo' : 'monospace' ,
590+ } }
591+ >
592+ { line }
593+ </ Text >
594+ ) ) }
595+ </ View >
596+ < Ionicons
597+ name = { copied ? 'checkmark' : 'copy-outline' }
598+ size = { 16 }
599+ color = { copied ? '#30D158' : theme . colors . textSecondary }
600+ style = { { marginTop : 1 } }
601+ />
602+ </ Pressable >
603+ ) ;
604+ }
605+
584606function CenteredInputWidth ( props : {
585607 children : React . ReactNode ;
586608 horizontalPadding : number ;
0 commit comments