diff --git a/internal/backend/agent/prompt/replay.go b/internal/backend/agent/prompt/replay.go
index baf86f6..68560b7 100644
--- a/internal/backend/agent/prompt/replay.go
+++ b/internal/backend/agent/prompt/replay.go
@@ -26,10 +26,13 @@ func BuildUserMessageReplayMessage(userMessage *agentv1.UserMessage) (Message, b
func buildUserReplayMessage(text string, selectedContext *agentv1.SelectedContext) (Message, bool) {
images := buildSelectedImageContentParts(selectedContext)
- sections := make([]string, 0, 4)
+ sections := make([]string, 0, 5)
if text != "" {
sections = append(sections, formatMessageText(fmt.Sprintf("\n%s\n", text)))
}
+ if cursorCommands := buildSelectedCursorCommandsPromptSection(selectedContext); cursorCommands != "" {
+ sections = append(sections, cursorCommands)
+ }
if ideState := buildSelectedIDEStatePromptSection(selectedContext); ideState != "" {
sections = append(sections, ideState)
}
@@ -62,6 +65,32 @@ func buildUserReplayMessage(text string, selectedContext *agentv1.SelectedContex
}, true
}
+func buildSelectedCursorCommandsPromptSection(selectedContext *agentv1.SelectedContext) string {
+ if selectedContext == nil || len(selectedContext.GetCursorCommands()) == 0 {
+ return ""
+ }
+ entries := make([]string, 0, len(selectedContext.GetCursorCommands()))
+ for _, command := range selectedContext.GetCursorCommands() {
+ if command == nil {
+ continue
+ }
+ content := strings.TrimSpace(command.GetContent())
+ if content == "" {
+ continue
+ }
+ name := strings.TrimSpace(command.GetName())
+ if name == "" {
+ entries = append(entries, "\n"+content+"\n")
+ continue
+ }
+ entries = append(entries, fmt.Sprintf("\n%s\n", escapePromptXML(name), content))
+ }
+ if len(entries) == 0 {
+ return ""
+ }
+ return "\n" + strings.Join(entries, "\n\n") + "\n"
+}
+
func buildSelectedIDEStatePromptSection(selectedContext *agentv1.SelectedContext) string {
if selectedContext == nil || selectedContext.GetInvocationContext() == nil {
return ""
diff --git a/internal/backend/agent/prompt/replay_test.go b/internal/backend/agent/prompt/replay_test.go
index 04abd85..fc91b90 100644
--- a/internal/backend/agent/prompt/replay_test.go
+++ b/internal/backend/agent/prompt/replay_test.go
@@ -2,9 +2,67 @@ package promptengine
import (
"reflect"
+ "strings"
"testing"
+
+ "cursor/gen/agentv1"
)
+func TestBuildUserMessageReplayMessageIncludesSelectedCursorCommands(t *testing.T) {
+ message, ok := BuildUserMessageReplayMessage(&agentv1.UserMessage{
+ Text: "/init",
+ SelectedContext: &agentv1.SelectedContext{
+ CursorCommands: []*agentv1.SelectedCursorCommand{
+ {Name: "init", Content: "Analyze the repository and create AGENTS.md."},
+ {Name: `review"<&`, Content: "Review the implementation."},
+ },
+ },
+ })
+ if !ok {
+ t.Fatal("BuildUserMessageReplayMessage() returned ok=false")
+ }
+
+ want := strings.Join([]string{
+ "\n/init\n",
+ "\n" +
+ "\nAnalyze the repository and create AGENTS.md.\n\n\n" +
+ "\nReview the implementation.\n\n" +
+ "",
+ }, "\n\n")
+ if message.Role != "user" || message.Content != want {
+ t.Fatalf("message = %#v, want content %q", message, want)
+ }
+}
+
+func TestBuildUserMessageReplayMessageSkipsEmptyCursorCommandsAndKeepsOrder(t *testing.T) {
+ message, ok := BuildUserMessageReplayMessage(&agentv1.UserMessage{
+ Text: "run commands",
+ SelectedContext: &agentv1.SelectedContext{
+ CursorCommands: []*agentv1.SelectedCursorCommand{
+ nil,
+ {Name: "empty", Content: " "},
+ {Content: "First command."},
+ {Name: "second", Content: "Second command."},
+ },
+ },
+ })
+ if !ok {
+ t.Fatal("BuildUserMessageReplayMessage() returned ok=false")
+ }
+
+ first := strings.Index(message.Content, "First command.")
+ second := strings.Index(message.Content, "Second command.")
+ if first < 0 || second < 0 || first >= second {
+ t.Fatalf("cursor command order was not preserved: %q", message.Content)
+ }
+ if strings.Contains(message.Content, "empty") {
+ t.Fatalf("empty cursor command was not skipped: %q", message.Content)
+ }
+ if !strings.Contains(message.Content, "\nFirst command.\n") {
+ t.Fatalf("unnamed cursor command was not rendered safely: %q", message.Content)
+ }
+}
+
func TestBuildReplayMessagesFromPendingAssistantOutputsKeepsTextAndToolCallInOneAssistantTurn(t *testing.T) {
raw := `{
"id":"1",