11import type { SessionNotification } from "@agentclientprotocol/sdk" ;
22import type { SessionEvent } from "@features/sessions/stores/sessionStore" ;
33import { useAutoScroll } from "@hooks/useAutoScroll" ;
4- import {
5- Code as CodeIcon ,
6- Copy as CopyIcon ,
7- PaperPlaneRight as SendIcon ,
8- Stop as StopIcon ,
9- } from "@phosphor-icons/react" ;
4+ import { PaperPlaneRight as SendIcon } from "@phosphor-icons/react" ;
105import {
116 Box ,
127 Button ,
138 Code ,
9+ ContextMenu ,
1410 Flex ,
15- Heading ,
1611 IconButton ,
1712 Text ,
1813 TextArea ,
@@ -26,7 +21,6 @@ interface LogViewProps {
2621 isRunning : boolean ;
2722 isPromptPending ?: boolean ;
2823 onSendPrompt ?: ( text : string ) => Promise < void > ;
29- onCancelSession ?: ( ) => void ;
3024 onStartSession ?: ( ) => void ;
3125}
3226
@@ -62,7 +56,6 @@ export function LogView({
6256 isRunning,
6357 isPromptPending = false ,
6458 onSendPrompt,
65- onCancelSession,
6659 onStartSession,
6760} : LogViewProps ) {
6861 const [ inputValue , setInputValue ] = useState ( "" ) ;
@@ -97,21 +90,6 @@ export function LogView({
9790 [ handleSend ] ,
9891 ) ;
9992
100- const handleCopyLogs = ( ) => {
101- const logsText = events
102- . map ( ( event ) => {
103- if ( event . type === "session_update" ) {
104- return renderNotification ( event . notification ) ;
105- }
106- if ( event . type === "acp_message" ) {
107- return `[${ event . direction } ] ${ JSON . stringify ( event . message ) } ` ;
108- }
109- return JSON . stringify ( event ) ;
110- } )
111- . join ( "\n" ) ;
112- navigator . clipboard . writeText ( logsText ) ;
113- } ;
114-
11593 // Build rendered output from events (filter out raw acp_message unless showRawLogs is true)
11694 const renderedOutput : Array < {
11795 key : string ;
@@ -170,101 +148,46 @@ export function LogView({
170148
171149 return (
172150 < Flex direction = "column" height = "100%" >
173- { /* Header */ }
174- < Box p = "4" className = "border-gray-6 border-b" >
175- < Flex align = "center" justify = "between" >
176- < Heading size = "3" > Agent Chat</ Heading >
177- < Flex align = "center" gap = "3" >
178- < Tooltip
179- content = { showRawLogs ? "Show pretty view" : "Show raw ACP logs" }
180- >
181- < IconButton
182- size = "2"
183- variant = { showRawLogs ? "solid" : "ghost" }
184- color = "gray"
185- onClick = { ( ) => setShowRawLogs ( ! showRawLogs ) }
186- >
187- < CodeIcon size = { 16 } />
188- </ IconButton >
189- </ Tooltip >
190-
191- < Tooltip content = "Copy logs" >
192- < IconButton
193- size = "2"
194- variant = "ghost"
195- color = "gray"
196- onClick = { handleCopyLogs }
197- >
198- < CopyIcon size = { 16 } />
199- </ IconButton >
200- </ Tooltip >
201-
202- { isRunning && onCancelSession && (
203- < Tooltip content = "Cancel session" >
204- < Button size = "2" color = "red" onClick = { onCancelSession } >
205- < StopIcon size = { 16 } weight = "fill" />
206- Cancel
207- </ Button >
208- </ Tooltip >
209- ) }
210-
211- { isRunning ? (
212- < Flex align = "center" gap = "2" >
213- < Box
214- width = "8px"
215- height = "8px"
216- className = "animate-pulse rounded-full bg-green-9"
217- />
218- < Text size = "2" color = "gray" >
219- Running
220- </ Text >
221- </ Flex >
222- ) : (
223- events . length > 0 && (
224- < Flex align = "center" gap = "2" >
225- < Box
226- width = "8px"
227- height = "8px"
228- className = "rounded-full bg-accent-9"
229- />
230- < Text size = "2" color = "gray" >
231- Idle
232- </ Text >
233- </ Flex >
234- )
235- ) }
236- </ Flex >
237- </ Flex >
238- </ Box >
239-
240151 { /* Chat output */ }
241- < Box ref = { scrollRef } flexGrow = "1" overflowY = "auto" p = "4" >
242- < Box className = "space-y-1 font-mono text-sm" >
243- { renderedOutput . map ( ( item ) => (
244- < Code
245- key = { item . key }
246- size = "2"
247- variant = "ghost"
248- className = { `block whitespace-pre-wrap ${
249- item . rawDirection === "client"
250- ? "text-cyan-11"
251- : item . rawDirection === "agent"
252- ? "text-orange-11"
253- : item . isUserMessage
254- ? "text-blue-11"
255- : ""
256- } `}
257- >
258- { item . text }
259- </ Code >
260- ) ) }
261- { isPromptPending && (
262- < Code size = "2" variant = "ghost" className = "block text-gray-9" >
263- Thinking...
264- </ Code >
265- ) }
266- </ Box >
267- </ Box >
152+ < ContextMenu . Root >
153+ < ContextMenu . Trigger >
154+ < Box ref = { scrollRef } flexGrow = "1" overflowY = "auto" p = "4" >
155+ < Box className = "space-y-1 font-mono text-sm" >
156+ { renderedOutput . map ( ( item ) => (
157+ < Code
158+ key = { item . key }
159+ size = "2"
160+ variant = "ghost"
161+ className = { `block whitespace-pre-wrap ${
162+ item . rawDirection === "client"
163+ ? "text-cyan-11"
164+ : item . rawDirection === "agent"
165+ ? "text-orange-11"
166+ : item . isUserMessage
167+ ? "text-blue-11"
168+ : ""
169+ } `}
170+ >
171+ { item . text }
172+ </ Code >
173+ ) ) }
174+ { isPromptPending && (
175+ < Code size = "2" variant = "ghost" className = "block text-gray-9" >
176+ Thinking...
177+ </ Code >
178+ ) }
179+ </ Box >
180+ </ Box >
181+ </ ContextMenu . Trigger >
182+ < ContextMenu . Content >
183+ < ContextMenu . CheckboxItem
184+ checked = { showRawLogs }
185+ onCheckedChange = { setShowRawLogs }
186+ >
187+ Show raw ACP logs
188+ </ ContextMenu . CheckboxItem >
189+ </ ContextMenu . Content >
190+ </ ContextMenu . Root >
268191
269192 { /* Input area */ }
270193 { sessionId && (
0 commit comments