({
config,
setMessages,
setIsLoading,
onInit,
setToolUseConfirmQueue,
tools,
setStreamingToolUses,
setStreamMode,
setInProgressToolUseIDs,
}: UseRemoteSessionProps)
| 77 | * - Permission request/response flow via existing ToolUseConfirm queue |
| 78 | */ |
| 79 | export function useRemoteSession({ |
| 80 | config, |
| 81 | setMessages, |
| 82 | setIsLoading, |
| 83 | onInit, |
| 84 | setToolUseConfirmQueue, |
| 85 | tools, |
| 86 | setStreamingToolUses, |
| 87 | setStreamMode, |
| 88 | setInProgressToolUseIDs, |
| 89 | }: UseRemoteSessionProps): UseRemoteSessionResult { |
| 90 | const isRemoteMode = !!config |
| 91 | |
| 92 | const setAppState = useSetAppState() |
| 93 | const setConnStatus = useCallback( |
| 94 | (s: AppState['remoteConnectionStatus']) => |
| 95 | setAppState(prev => |
| 96 | prev.remoteConnectionStatus === s |
| 97 | ? prev |
| 98 | : { ...prev, remoteConnectionStatus: s }, |
| 99 | ), |
| 100 | [setAppState], |
| 101 | ) |
| 102 | |
| 103 | // Event-sourced count of subagents running inside the remote daemon child. |
| 104 | // The viewer's own AppState.tasks is empty — tasks live in a different |
| 105 | // process. task_started/task_notification reach us via the bridge WS. |
| 106 | const runningTaskIdsRef = useRef(new Set<string>()) |
| 107 | const writeTaskCount = useCallback(() => { |
| 108 | const n = runningTaskIdsRef.current.size |
| 109 | setAppState(prev => |
| 110 | prev.remoteBackgroundTaskCount === n |
| 111 | ? prev |
| 112 | : { ...prev, remoteBackgroundTaskCount: n }, |
| 113 | ) |
| 114 | }, [setAppState]) |
| 115 | |
| 116 | // Timer for detecting stuck sessions |
| 117 | const responseTimeoutRef = useRef<NodeJS.Timeout | null>(null) |
| 118 | |
| 119 | // Track whether the remote session is compacting. During compaction the |
| 120 | // CLI worker is busy with an API call and won't emit messages for a while; |
| 121 | // use a longer timeout and suppress spurious "unresponsive" warnings. |
| 122 | const isCompactingRef = useRef(false) |
| 123 | |
| 124 | const managerRef = useRef<RemoteSessionManager | null>(null) |
| 125 | |
| 126 | // Track whether we've already updated the session title (for no-initial-prompt sessions) |
| 127 | const hasUpdatedTitleRef = useRef(false) |
| 128 | |
| 129 | // UUIDs of user messages we POSTed locally — the WS echoes them back and |
| 130 | // we must filter them out when convertUserTextMessages is on, or the viewer |
| 131 | // sees every typed message twice (once from local createUserMessage, once |
| 132 | // from the echo). A single POST can echo MULTIPLE times with the same uuid: |
| 133 | // the server may broadcast the POST directly to /subscribe, AND the worker |
| 134 | // (cowork desktop / CLI daemon) echoes it again on its write path. A |
| 135 | // delete-on-first-match Set would let the second echo through — use a |
| 136 | // bounded ring instead. Cap is generous: users don't type 50 messages |
no test coverage detected