@@ -15,6 +15,7 @@ import (
1515	"strings" 
1616	"time" 
1717
18+ 	"github.com/atotto/clipboard" 
1819	tea "github.com/charmbracelet/bubbletea/v2" 
1920	"github.com/fatih/color" 
2021	"github.com/spf13/cobra" 
@@ -641,12 +642,86 @@ func runUserCommand(userInput string, sess *session.Session, rt runtime.Runtime,
641642			fmt .Printf ("%s\n " , yellow ("No summary generated" ))
642643		}
643644
645+ 		return  true , nil 
646+ 	case  "/copy" :
647+ 		// Copy the conversation to clipboard 
648+ 		transcript  :=  generatePlainTextTranscript (sess )
649+ 		if  transcript  ==  ""  {
650+ 			fmt .Printf ("%s\n " , yellow ("Conversation is empty; nothing copied." ))
651+ 			return  true , nil 
652+ 		}
653+ 
654+ 		if  err  :=  clipboard .WriteAll (transcript ); err  !=  nil  {
655+ 			fmt .Printf ("%s\n " , yellow ("Failed to copy conversation: %s" , err .Error ()))
656+ 			return  true , err 
657+ 		}
658+ 
659+ 		fmt .Printf ("%s\n " , yellow ("Conversation copied to clipboard." ))
644660		return  true , nil 
645661	}
646662
647663	return  false , nil 
648664}
649665
666+ // generatePlainTextTranscript generates a plain text transcript from the session 
667+ func  generatePlainTextTranscript (sess  * session.Session ) string  {
668+ 	var  builder  strings.Builder 
669+ 
670+ 	for  _ , item  :=  range  sess .Messages  {
671+ 		if  item .IsMessage () {
672+ 			msg  :=  item .Message 
673+ 			// Skip implicit messages 
674+ 			if  msg .Implicit  {
675+ 				continue 
676+ 			}
677+ 
678+ 			switch  msg .Message .Role  {
679+ 			case  chat .MessageRoleUser :
680+ 				writeTranscriptSection (& builder , "User" , msg .Message .Content )
681+ 			case  chat .MessageRoleAssistant :
682+ 				agentLabel  :=  msg .AgentName 
683+ 				if  agentLabel  ==  ""  ||  agentLabel  ==  "root"  {
684+ 					agentLabel  =  "Assistant" 
685+ 				}
686+ 				writeTranscriptSection (& builder , agentLabel , msg .Message .Content )
687+ 			case  chat .MessageRoleTool :
688+ 				// Format tool results 
689+ 				msgContent  :=  msg .Message .Content 
690+ 				if  msg .Message .Name  !=  ""  {
691+ 					writeTranscriptSection (& builder , fmt .Sprintf ("Tool Result (%s)" , msg .Message .Name ), msgContent )
692+ 				} else  {
693+ 					writeTranscriptSection (& builder , "Tool Result" , msgContent )
694+ 				}
695+ 			}
696+ 		} else  if  item .IsSubSession () {
697+ 			// Recursively process sub-sessions 
698+ 			subTranscript  :=  generatePlainTextTranscript (item .SubSession )
699+ 			if  subTranscript  !=  ""  {
700+ 				if  builder .Len () >  0  {
701+ 					builder .WriteString ("\n \n " )
702+ 				}
703+ 				builder .WriteString (subTranscript )
704+ 			}
705+ 		}
706+ 	}
707+ 
708+ 	return  strings .TrimSpace (builder .String ())
709+ }
710+ 
711+ // writeTranscriptSection writes a section to the transcript builder 
712+ func  writeTranscriptSection (builder  * strings.Builder , title , text  string ) {
713+ 	trimmed  :=  strings .TrimSpace (text )
714+ 	if  trimmed  ==  ""  {
715+ 		return 
716+ 	}
717+ 	if  builder .Len () >  0  {
718+ 		builder .WriteString ("\n \n " )
719+ 	}
720+ 	builder .WriteString (title )
721+ 	builder .WriteString (":\n " )
722+ 	builder .WriteString (trimmed )
723+ }
724+ 
650725// parseAttachCommand parses user input for /attach commands 
651726// Returns the message text (with /attach commands removed) and the attachment path 
652727func  parseAttachCommand (input  string ) (messageText , attachPath  string ) {
0 commit comments