import React, { useMemo } from 'react' import type { DeepImmutable } from 'src/types/utils.js' import { useElapsedTime } from '../../hooks/useElapsedTime.js' import type { KeyboardEvent } from '../../ink/events/keyboard-event.js' import { Box, Text, useTheme } from '../../ink.js' import { useKeybindings } from '../../keybindings/useKeybinding.js' import { getEmptyToolPermissionContext } from '../../Tool.js' import type { InProcessTeammateTaskState } from '../../tasks/InProcessTeammateTask/types.js' import { getTools } from '../../tools.js' import { formatNumber, truncateToWidth } from '../../utils/format.js' import { toInkColor } from '../../utils/ink.js' import { Byline } from '../design-system/Byline.js' import { Dialog } from '../design-system/Dialog.js' import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js' import { renderToolActivity } from './renderToolActivity.js' import { describeTeammateActivity } from './taskStatusUtils.js' type Props = { teammate: DeepImmutable onDone: () => void onKill?: () => void onBack?: () => void onForeground?: () => void } export function InProcessTeammateDetailDialog({ teammate, onDone, onKill, onBack, onForeground, }: Props): React.ReactNode { const [theme] = useTheme() const tools = useMemo(() => getTools(getEmptyToolPermissionContext()), []) const elapsedTime = useElapsedTime( teammate.startTime, teammate.status === 'running', 1000, teammate.totalPausedMs ?? 0, ) // Restore confirm:yes (Enter/y) dismissal — Dialog handles confirm:no (Esc) useKeybindings( { 'confirm:yes': onDone, }, { context: 'Confirmation' }, ) const handleKeyDown = (e: KeyboardEvent) => { if (e.key === ' ') { e.preventDefault() onDone() } else if (e.key === 'left' && onBack) { e.preventDefault() onBack() } else if (e.key === 'x' && teammate.status === 'running' && onKill) { e.preventDefault() onKill() } else if (e.key === 'f' && teammate.status === 'running' && onForeground) { e.preventDefault() onForeground() } } const activity = describeTeammateActivity(teammate) const tokenCount = teammate.result?.totalTokens ?? teammate.progress?.tokenCount const toolUseCount = teammate.result?.totalToolUseCount ?? teammate.progress?.toolUseCount const displayPrompt = truncateToWidth(teammate.prompt, 300) const title = ( @{teammate.identity.agentName} {activity && ({activity})} ) const subtitle = ( {teammate.status !== 'running' && ( {teammate.status === 'completed' ? 'Completed' : teammate.status === 'failed' ? 'Failed' : 'Stopped'} {' · '} )} {elapsedTime} {tokenCount !== undefined && tokenCount > 0 && ( <> · {formatNumber(tokenCount)} tokens )} {toolUseCount !== undefined && toolUseCount > 0 && ( <> {' '} · {toolUseCount} {toolUseCount === 1 ? 'tool' : 'tools'} )} ) return ( exitState.pending ? ( Press {exitState.keyName} again to exit ) : ( {onBack && } {teammate.status === 'running' && onKill && ( )} {teammate.status === 'running' && onForeground && ( )} ) } > {/* Recent activities for running teammates */} {teammate.status === 'running' && teammate.progress?.recentActivities && teammate.progress.recentActivities.length > 0 && ( Progress {teammate.progress.recentActivities.map((activity, i) => ( {i === teammate.progress!.recentActivities!.length - 1 ? '› ' : ' '} {renderToolActivity(activity, tools, theme)} ))} )} {/* Prompt section */} Prompt {displayPrompt} {/* Error details if failed */} {teammate.status === 'failed' && teammate.error && ( Error {teammate.error} )} ) }