| ... | @@ -10913,6 +10913,45 @@ export default function ChatView(props: ChatViewProps) { | ... | @@ -10913,6 +10913,45 @@ export default function ChatView(props: ChatViewProps) { |
| 10913 | }, [cancelWorktreeSetup, draftId, setupTarget.environmentId, worktreeSetup]); | 10913 | }, [cancelWorktreeSetup, draftId, setupTarget.environmentId, worktreeSetup]); |
| 10914 | const onSendRef = useRef(onSend); | 10914 | const onSendRef = useRef(onSend); |
| 10915 | onSendRef.current = onSend; | 10915 | onSendRef.current = onSend; |
| | 10916 | const onResumeRef = useRef(onResume); |
| | 10917 | onResumeRef.current = onResume; |
| | 10918 | const onCompactContextRef = useRef(onCompactContext); |
| | 10919 | onCompactContextRef.current = onCompactContext; |
| | 10920 | const onComposerSend = useCallback( |
| | 10921 | (...args: Parameters<typeof onSend>) => onSendRef.current(...args), |
| | 10922 | [], |
| | 10923 | ); |
| | 10924 | const onComposerResume = useCallback(() => onResumeRef.current(), []); |
| | 10925 | const onComposerCompactContext = useCallback(() => onCompactContextRef.current(), []); |
| | 10926 | const queuedRunsControl = useMemo( |
| | 10927 | () => |
| | 10928 | isServerThread && activeThread ? ( |
| | 10929 | <QueuedRunsControl |
| | 10930 | ref={queuedRunsControlRef} |
| | 10931 | steerShortcutLabel={shortcutLabelForCommand(keybindings, "thread.steerQueuedMessage", { |
| | 10932 | context: { terminalFocus: false }, |
| | 10933 | })} |
| | 10934 | editShortcutLabel={shortcutLabelForCommand(keybindings, "thread.editQueuedMessage", { |
| | 10935 | context: { composerFocus: true }, |
| | 10936 | })} |
| | 10937 | environmentId={activeThread.environmentId} |
| | 10938 | threadId={activeThread.id} |
| | 10939 | optimisticMessages={optimisticUserMessages} |
| | 10940 | editingRunId={editingQueuedRun?.runId ?? null} |
| | 10941 | onEditQueuedRun={beginEditingQueuedRun} |
| | 10942 | onCancelEdit={cancelEditingQueuedRun} |
| | 10943 | /> |
| | 10944 | ) : null, |
| | 10945 | [ |
| | 10946 | activeThread, |
| | 10947 | beginEditingQueuedRun, |
| | 10948 | cancelEditingQueuedRun, |
| | 10949 | editingQueuedRun?.runId, |
| | 10950 | isServerThread, |
| | 10951 | keybindings, |
| | 10952 | optimisticUserMessages, |
| | 10953 | ], |
| | 10954 | ); |
| 10916 | // Resend once the cancelled dispatch has settled and the composer is free. | 10955 | // Resend once the cancelled dispatch has settled and the composer is free. |
| 10917 | // Every state that makes `onSend` bail and wait is part of the readiness | 10956 | // Every state that makes `onSend` bail and wait is part of the readiness |
| 10918 | // check, so the flag survives a reconnect, a reverting checkpoint, or a | 10957 | // check, so the flag survives a reconnect, a reverting checkpoint, or a |
| ... | @@ -10977,12 +11016,21 @@ export default function ChatView(props: ChatViewProps) { | ... | @@ -10977,12 +11016,21 @@ export default function ChatView(props: ChatViewProps) { |
| 10977 | const onOpenTurnDiff = useCallback( | 11016 | const onOpenTurnDiff = useCallback( |
| 10978 | (runId: RunId, filePath?: string) => { | 11017 | (runId: RunId, filePath?: string) => { |
| 10979 | if (!isServerThread || !activeThreadRef) return; | 11018 | if (!isServerThread || !activeThreadRef) return; |
| | 11019 | const diffOpen = |
| | 11020 | selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, activeThreadRef) === |
| | 11021 | "diff"; |
| 10980 | explicitDiffOpenRef.current = diffOpen ? null : activeThreadRef; | 11022 | explicitDiffOpenRef.current = diffOpen ? null : activeThreadRef; |
| 10981 | useDiffPanelStore.getState().selectTurn(activeThreadRef, runId, filePath); | 11023 | useDiffPanelStore.getState().selectTurn(activeThreadRef, runId, filePath); |
| 10982 | useRightPanelStore.getState().open(activeThreadRef, "diff"); | 11024 | useRightPanelStore.getState().open(activeThreadRef, "diff"); |
| 10983 | onDiffPanelOpen?.(); | 11025 | onDiffPanelOpen?.(); |
| 10984 | }, | 11026 | }, |
| 10985 | [activeThreadRef, diffOpen, isServerThread, onDiffPanelOpen], | 11027 | [activeThreadRef, isServerThread, onDiffPanelOpen], |
| | 11028 | ); |
| | 11029 | const onTimelineRollbackCheckpoint = useCallback( |
| | 11030 | (input: { readonly checkpointId: string; readonly scopeId: string }) => { |
| | 11031 | if (!paintOnlyDisplayedTimeline) void onRollbackCheckpoint(input); |
| | 11032 | }, |
| | 11033 | [onRollbackCheckpoint, paintOnlyDisplayedTimeline], |
| 10986 | ); | 11034 | ); |
| 10987 | // The revert handler is read from a ref at call-time so the callback | 11035 | // The revert handler is read from a ref at call-time so the callback |
| 10988 | // reference is fully stable and never busts TimelineRowCtx identity. | 11036 | // reference is fully stable and never busts TimelineRowCtx identity. |
| ... | @@ -11504,9 +11552,7 @@ export default function ChatView(props: ChatViewProps) { | ... | @@ -11504,9 +11552,7 @@ export default function ChatView(props: ChatViewProps) { |
| 11504 | onOpenThread={onOpenRelatedThread} | 11552 | onOpenThread={onOpenRelatedThread} |
| 11505 | parentThreadLink={paintOnlyDisplayedTimeline ? null : parentThreadLink} | 11553 | parentThreadLink={paintOnlyDisplayedTimeline ? null : parentThreadLink} |
| 11506 | onForkFromRun={paintOnlyDisplayedTimeline ? async () => {} : onForkFromRun} | 11554 | onForkFromRun={paintOnlyDisplayedTimeline ? async () => {} : onForkFromRun} |
| 11507 | onRollbackCheckpoint={(input) => { | 11555 | onRollbackCheckpoint={onTimelineRollbackCheckpoint} |
| 11508 | if (!paintOnlyDisplayedTimeline) void onRollbackCheckpoint(input); | | |
| 11509 | }} | | |
| 11510 | supportsConversationRollback={ | 11556 | supportsConversationRollback={ |
| 11511 | !paintOnlyDisplayedTimeline && supportsConversationRollback | 11557 | !paintOnlyDisplayedTimeline && supportsConversationRollback |
| 11512 | } | 11558 | } |
| ... | @@ -11711,29 +11757,7 @@ export default function ChatView(props: ChatViewProps) { | ... | @@ -11711,29 +11757,7 @@ export default function ChatView(props: ChatViewProps) { |
| 11711 | : projectCloneSendBlockReason | 11757 | : projectCloneSendBlockReason |
| 11712 | } | 11758 | } |
| 11713 | isPreparingWorktree={isPreparingWorktree && !sendQueuesBehindSetup} | 11759 | isPreparingWorktree={isPreparingWorktree && !sendQueuesBehindSetup} |
| 11714 | queuedRunsControl={ | 11760 | queuedRunsControl={queuedRunsControl} |
| 11715 | isServerThread && activeThread ? ( | | |
| 11716 | <QueuedRunsControl | | |
| 11717 | ref={queuedRunsControlRef} | | |
| 11718 | steerShortcutLabel={shortcutLabelForCommand( | | |
| 11719 | keybindings, | | |
| 11720 | "thread.steerQueuedMessage", | | |
| 11721 | { context: { terminalFocus: false } }, | | |
| 11722 | )} | | |
| 11723 | editShortcutLabel={shortcutLabelForCommand( | | |
| 11724 | keybindings, | | |
| 11725 | "thread.editQueuedMessage", | | |
| 11726 | { context: { composerFocus: true } }, | | |
| 11727 | )} | | |
| 11728 | environmentId={activeThread.environmentId} | | |
| 11729 | threadId={activeThread.id} | | |
| 11730 | optimisticMessages={optimisticUserMessages} | | |
| 11731 | editingRunId={editingQueuedRun?.runId ?? null} | | |
| 11732 | onEditQueuedRun={beginEditingQueuedRun} | | |
| 11733 | onCancelEdit={cancelEditingQueuedRun} | | |
| 11734 | /> | | |
| 11735 | ) : null | | |
| 11736 | } | | |
| 11737 | bannerItems={composerBannerItems} | 11761 | bannerItems={composerBannerItems} |
| 11738 | resumeCompactionTokens={resumeCompactionTokens} | 11762 | resumeCompactionTokens={resumeCompactionTokens} |
| 11739 | keepFullHistory={keepFullHistory} | 11763 | keepFullHistory={keepFullHistory} |
| ... | @@ -11807,9 +11831,9 @@ export default function ChatView(props: ChatViewProps) { | ... | @@ -11807,9 +11831,9 @@ export default function ChatView(props: ChatViewProps) { |
| 11807 | onPageScrollKeyDown={onComposerPageScrollKeyDown} | 11831 | onPageScrollKeyDown={onComposerPageScrollKeyDown} |
| 11808 | onPageScrollKeyUp={onComposerPageScrollKeyUp} | 11832 | onPageScrollKeyUp={onComposerPageScrollKeyUp} |
| 11809 | onPageScrollRelease={onComposerPageScrollRelease} | 11833 | onPageScrollRelease={onComposerPageScrollRelease} |
| 11810 | onCompactContext={onCompactContext} | 11834 | onCompactContext={onComposerCompactContext} |
| 11811 | onSend={onSend} | 11835 | onSend={onComposerSend} |
| 11812 | onResume={onResume} | 11836 | onResume={onComposerResume} |
| 11813 | onInterrupt={onInterrupt} | 11837 | onInterrupt={onInterrupt} |
| 11814 | onImplementPlanInNewThread={onImplementPlanInNewThread} | 11838 | onImplementPlanInNewThread={onImplementPlanInNewThread} |
| 11815 | onRespondToApproval={onRespondToApproval} | 11839 | onRespondToApproval={onRespondToApproval} |