diff --git a/src/renderer/src/components/native-chat/use-native-chat-context-menu.targets.test.tsx b/src/renderer/src/components/native-chat/use-native-chat-context-menu.targets.test.tsx index 37d578b207e..e18426f98e4 100644 --- a/src/renderer/src/components/native-chat/use-native-chat-context-menu.targets.test.tsx +++ b/src/renderer/src/components/native-chat/use-native-chat-context-menu.targets.test.tsx @@ -45,12 +45,14 @@ function Chat({ acceptsText = true, rewind, onFind, - actions + actions, + standalone = false }: { acceptsText?: boolean rewind?: NativeChatRewindSurface onFind?: () => void actions?: Partial + standalone?: boolean }): React.JSX.Element { const rootRef = useRef(null) const composerRef = useRef({ @@ -68,6 +70,20 @@ function Chat({ composerRef, actions: { ...emptyNativeChatContextMenuActions, ...actions, onPaste: vi.fn() }, showTerminalPaneActions: actions !== undefined, + chatPane: standalone + ? { tabId: 'chat-tab', worktreeId: 'wt-1', groupId: 'group-1', sessionId: 'session-1' } + : undefined, + chatSession: standalone + ? { + target: { kind: 'local' }, + sessionId: 'session-1', + worktreeId: 'wt-1', + epoch: 'epoch-1', + agent: 'claude', + messages: [], + focusSource: vi.fn() + } + : undefined, fileLinkContext: linkContext, rewind, onFind @@ -108,6 +124,23 @@ afterEach(() => { vi.resetAllMocks() }) +it.each(['terminal-backed', 'standalone'] as const)( + 'omits the whole-session fork action from the %s chat menu', + async (surface) => { + render( + + ) + + await rightClick('Empty area') + + expect(screen.getByRole('menuitem', { name: 'Copy Context' })).toBeInTheDocument() + expect(screen.queryByRole('menuitem', { name: 'Fork Agent Session…' })).not.toBeInTheDocument() + } +) + it.each([ { firstText: 'docs link', diff --git a/src/renderer/src/components/native-chat/use-native-chat-context-menu.tsx b/src/renderer/src/components/native-chat/use-native-chat-context-menu.tsx index f3b12bb3807..33061ecd15c 100644 --- a/src/renderer/src/components/native-chat/use-native-chat-context-menu.tsx +++ b/src/renderer/src/components/native-chat/use-native-chat-context-menu.tsx @@ -9,7 +9,7 @@ import { } from 'react' import { flushSync } from 'react-dom' import { chatMathSelectionText } from '../sidebar/chat-markdown-math-selection' -import { Clipboard, Copy, GitFork, Image as ImageIcon, SquareTerminal } from 'lucide-react' +import { Clipboard, Copy, Image as ImageIcon, SquareTerminal } from 'lucide-react' import { DropdownMenu, DropdownMenuContent, @@ -101,7 +101,6 @@ export type NativeChatContextMenuActions = { onToggleExpand: () => void canContinueAgentSessionInNewSession: boolean onContinueAgentSessionInNewSession: () => void - onForkAgentSession: () => void onCopyAgentSessionContext: () => void onSetTitle: () => void canClearPaneTitle: boolean @@ -124,7 +123,6 @@ export const emptyNativeChatContextMenuActions: Omit {}, canContinueAgentSessionInNewSession: false, onContinueAgentSessionInNewSession: () => {}, - onForkAgentSession: () => {}, onCopyAgentSessionContext: () => {}, onSetTitle: () => {}, canClearPaneTitle: false, @@ -337,13 +335,6 @@ export function useNativeChatContextMenu({ onSelect={actions.onContinueAgentSessionInNewSession} /> ) : null} - - - {translate( - 'auto.components.terminal.pane.TerminalContextMenu.8a7ddb8b8a', - 'Fork Agent Session…' - )} - ) : null} diff --git a/src/renderer/src/components/native-chat/use-native-chat-session-context-actions.tsx b/src/renderer/src/components/native-chat/use-native-chat-session-context-actions.tsx index fdd7c87ffbe..cfe88876b8b 100644 --- a/src/renderer/src/components/native-chat/use-native-chat-session-context-actions.tsx +++ b/src/renderer/src/components/native-chat/use-native-chat-session-context-actions.tsx @@ -1,13 +1,8 @@ import { useCallback, useLayoutEffect, useRef, useState } from 'react' -import { toast } from 'sonner' import { executionHostIdForStructuredTarget } from '@/runtime/structured-agent-session-owner' import { translate } from '@/i18n/i18n' -import { buildAgentSessionForkPrompt } from '@/lib/agent-session-fork-context' -import { isTuiAgent } from '../../../../shared/agent-launch/catalog/tui-agent-config' import type { AgentType } from '../../../../shared/agent-status/contracts/agent-status-types' -import type { PreparedAgentSessionFork } from '../terminal-pane/terminal-agent-session-fork' import { copyAgentSessionContext } from '@/lib/copy-agent-session-context' -import { TerminalAgentSessionForkDialog } from '../terminal-pane/TerminalAgentSessionForkDialog' import { resolveNativeChatSessionContext, type NativeChatSessionContextSource @@ -22,7 +17,6 @@ export type NativeChatSessionMenuSource = Omit(null) const [pending, setPending] = useState(false) const operation = useRef(0) const busy = useRef(false) @@ -34,11 +28,10 @@ export function useNativeChatSessionContextActions( retire() busy.current = false setPending(false) - setFork(null) return retire }, [source?.sessionId, hostId, source?.epoch, source?.worktreeId, retire]) - const prepare = async (action: 'fork' | 'copy'): Promise => { + const copy = async (): Promise => { if (!source?.epoch || busy.current) { return } @@ -54,26 +47,7 @@ export function useNativeChatSessionContextActions( 'components.native-chat.contextMenu.noSessionContext', 'No chat context is available.' ) - if (action === 'copy') { - await copyAgentSessionContext(context.capturedText, source.focusSource, noContext) - return - } - const prompt = buildAgentSessionForkPrompt({ - capturedText: context.capturedText, - sourceLabel: source.sessionId, - agentLabel: source.agent - }) - if (!prompt) { - toast.error(noContext) - source.focusSource() - return - } - setFork({ - prompt, - agent: isTuiAgent(source.agent) ? source.agent : null, - worktreeId: source.worktreeId, - focusSource: source.focusSource - }) + await copyAgentSessionContext(context.capturedText, source.focusSource, noContext) } finally { if (operation.current === current) { busy.current = false @@ -84,14 +58,6 @@ export function useNativeChatSessionContextActions( return { available: Boolean(source?.epoch), pending, - onFork: () => void prepare('fork'), - onCopy: () => void prepare('copy'), - dialog: fork ? ( - !open && setFork(null)} - /> - ) : null + onCopy: () => void copy() } } diff --git a/src/renderer/src/components/native-chat/use-native-chat-standalone-menu.tsx b/src/renderer/src/components/native-chat/use-native-chat-standalone-menu.tsx index 534a5780853..6605aa98a9f 100644 --- a/src/renderer/src/components/native-chat/use-native-chat-standalone-menu.tsx +++ b/src/renderer/src/components/native-chat/use-native-chat-standalone-menu.tsx @@ -1,6 +1,3 @@ -import { GitFork } from 'lucide-react' -import { DropdownMenuItem } from '@/components/ui/dropdown-menu' -import { translate } from '@/i18n/i18n' import { NativeChatCliForkMenuItems } from '../tab-bar/NativeChatCliForkMenuItems' import { AgentSessionContextCopyMenuItem } from '../terminal-pane/AgentSessionContextCopyMenuItem' import { useNativeChatQuickCommandsMenu } from './use-native-chat-quick-commands-menu' @@ -26,19 +23,7 @@ export function useNativeChatStandaloneMenu({ pane && source ? ( <> {context.available ? ( - <> - - - {translate( - 'auto.components.terminal.pane.TerminalContextMenu.8a7ddb8b8a', - 'Fork Agent Session…' - )} - - - + ) : null} ) : null, - dialogs: ( - <> - {quickCommands.dialog} - {context.dialog} - - ) + dialogs: quickCommands.dialog } } diff --git a/src/renderer/src/components/terminal-pane/TerminalPaneNativeChatPortal.tsx b/src/renderer/src/components/terminal-pane/TerminalPaneNativeChatPortal.tsx index 410e60bc8cb..7897806ce75 100644 --- a/src/renderer/src/components/terminal-pane/TerminalPaneNativeChatPortal.tsx +++ b/src/renderer/src/components/terminal-pane/TerminalPaneNativeChatPortal.tsx @@ -54,8 +54,6 @@ export function TerminalPaneNativeChatPortal({ ), onContinueAgentSessionInNewSession: () => contextMenu.runForPane(chatPane.id, contextMenu.onContinueAgentSessionInNewSession), - onForkAgentSession: () => - void contextMenu.runForPane(chatPane.id, contextMenu.onForkAgentSession), onCopyAgentSessionContext: () => void contextMenu.runForPane(chatPane.id, contextMenu.onCopyAgentSessionContext), onSetTitle: () => contextMenu.runForPane(chatPane.id, contextMenu.onSetTitle),