import * as React from 'react' import { Markdown } from '../../components/Markdown.js' import { Box, Text } from '../../ink.js' import { jsonParse } from '../../utils/slowOperations.js' import { type IdleNotificationMessage, isIdleNotification, isPlanApprovalRequest, isPlanApprovalResponse, type PlanApprovalRequestMessage, type PlanApprovalResponseMessage, } from '../../utils/teammateMailbox.js' import { getShutdownMessageSummary } from './ShutdownMessage.js' import { getTaskAssignmentSummary } from './TaskAssignmentMessage.js' type PlanApprovalRequestProps = { request: PlanApprovalRequestMessage } /** * Renders a plan approval request with a planMode-colored border, * showing the plan content and instructions for approving/rejecting. */ export function PlanApprovalRequestDisplay({ request, }: PlanApprovalRequestProps): React.ReactNode { return ( Plan Approval Request from {request.from} {request.planContent} Plan file: {request.planFilePath} ) } type PlanApprovalResponseProps = { response: PlanApprovalResponseMessage senderName: string } /** * Renders a plan approval response with a success (green) or error (red) border. */ export function PlanApprovalResponseDisplay({ response, senderName, }: PlanApprovalResponseProps): React.ReactNode { if (response.approved) { return ( ✓ Plan Approved by {senderName} You can now proceed with implementation. Your plan mode restrictions have been lifted. ) } return ( ✗ Plan Rejected by {senderName} {response.feedback && ( Feedback: {response.feedback} )} Please revise your plan based on the feedback and call ExitPlanMode again. ) } /** * Try to parse and render a plan approval message from raw content. * Returns the rendered component if it's a plan approval message, null otherwise. */ export function tryRenderPlanApprovalMessage( content: string, senderName: string, ): React.ReactNode | null { const request = isPlanApprovalRequest(content) if (request) { return } const response = isPlanApprovalResponse(content) if (response) { return ( ) } return null } /** * Get a brief summary text for a plan approval message. * Used in places like the inbox queue where we want a short description. * Returns null if the content is not a plan approval message. */ function getPlanApprovalSummary(content: string): string | null { const request = isPlanApprovalRequest(content) if (request) { return `[Plan Approval Request from ${request.from}]` } const response = isPlanApprovalResponse(content) if (response) { if (response.approved) { return '[Plan Approved] You can now proceed with implementation' } else { return `[Plan Rejected] ${response.feedback || 'Please revise your plan'}` } } return null } /** * Get a brief summary text for an idle notification. */ function getIdleNotificationSummary(msg: IdleNotificationMessage): string { const parts: string[] = ['Agent idle'] if (msg.completedTaskId) { const status = msg.completedStatus || 'completed' parts.push(`Task ${msg.completedTaskId} ${status}`) } if (msg.summary) { parts.push(`Last DM: ${msg.summary}`) } return parts.join(' · ') } /** * Format teammate message content for display. * If it's a structured message (plan approval, shutdown, or idle), returns a formatted summary. * Otherwise returns the original content. */ export function formatTeammateMessageContent(content: string): string { const planSummary = getPlanApprovalSummary(content) if (planSummary) { return planSummary } const shutdownSummary = getShutdownMessageSummary(content) if (shutdownSummary) { return shutdownSummary } const idleMsg = isIdleNotification(content) if (idleMsg) { return getIdleNotificationSummary(idleMsg) } const taskAssignmentSummary = getTaskAssignmentSummary(content) if (taskAssignmentSummary) { return taskAssignmentSummary } // Check for teammate_terminated message try { const parsed = jsonParse(content) as { type?: string; message?: string } if (parsed?.type === 'teammate_terminated' && parsed.message) { return parsed.message } } catch { // Not JSON } return content }