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
}