@@ -113,9 +113,10 @@ type openEditorMsg struct {
113113}
114114
115115type shellResultMsg struct {
116− Command string
117− Output string
118− ExitCode int
116+ PendingID string // ID of the pending ShellItem to update.
117+ Command string
118+ Output string
119+ ExitCode int
119120}
120121
121122type (
@@ -200,8 +201,9 @@ type UI struct {
200201 isCanceling bool
201202
202203 // bangMode tracks whether the editor is in bang (!) shell mode.
203− bangMode bool
204− bangWasEmpty bool // true when bang prompt became empty on last keystroke
204+ bangMode bool
205+ bangWasEmpty bool // true when bang prompt became empty on last keystroke
206+ pendingShellItem *chat.ShellItem
205207
206208 header *header
207209
@@ -607,6 +609,17 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
607609 if cmd := m.autoExpandPillsIfReasonable(); cmd != nil {
608610 cmds = append(cmds, cmd)
609611 }
612+ // Re-append pending shell item if session load wiped it.
613+ if m.pendingShellItem != nil {
614+ m.chat.AppendMessages(m.pendingShellItem)
615+ if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
616+ cmds = append(cmds, cmd)
617+ }
618+ if cmd := m.pendingShellItem.StartAnimation(); cmd != nil {
619+ cmds = append(cmds, cmd)
620+ }
621+ m.pendingShellItem = nil
622+ }
610623 if hasInProgressTodo(m.session.Todos) {
611624 // only start spinner if there is an in-progress todo
612625 if m.isAgentBusy() {
@@ -941,6 +954,18 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
941954 m.textarea.MoveToEnd()
942955 cmds = append(cmds, m.updateTextareaWithPrevHeight(msg, prevHeight))
943956 case shellResultMsg:
957+ // Complete the pending shell item if it exists, otherwise create a new one.
958+ if msg.PendingID != "" {
959+ if item := m.chat.MessageItem(msg.PendingID); item != nil {
960+ if shellItem, ok := item.(*chat.ShellItem); ok {
961+ shellItem.Complete(msg.Output, msg.ExitCode)
962+ if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
963+ cmds = append(cmds, cmd)
964+ }
965+ break
966+ }
967+ }
968+ }
944969 item := chat.NewShellItem(m.com.Styles, msg.Command, msg.Output, msg.ExitCode)
945970 m.chat.AppendMessages(item)
946971 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
@@ -3387,7 +3412,8 @@ func (m *UI) sendMessage(content string, attachments ...message.Attachment) tea.
33873412// the LLM. The result is displayed as a tool-style item in the chat.
33883413func (m *UI) runShellCommand(command string) tea.Cmd {
33893414 var cmds []tea.Cmd
3390− if !m.hasSession() {
3415+ creatingSession := !m.hasSession()
3416+ if creatingSession {
33913417 newSession, err := m.com.Workspace.CreateSession(context.Background(), "New Session")
33923418 if err != nil {
33933419 return util.ReportError(err)
@@ -3404,6 +3430,23 @@ func (m *UI) runShellCommand(command string) tea.Cmd {
34043430
34053431 sessionID := m.session.ID
34063432 contentWidth := min(m.layout.main.Dx()-2, 120)
3433+
3434+ // Append a pending shell item immediately so the user sees feedback.
3435+ pendingItem := chat.NewPendingShellItem(m.com.Styles, command)
3436+ if creatingSession {
3437+ // loadSession will wipe the chat list via SetMessages.
3438+ // Stash the item and re-append after messages load.
3439+ m.pendingShellItem = pendingItem
3440+ } else {
3441+ m.chat.AppendMessages(pendingItem)
3442+ if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
3443+ cmds = append(cmds, cmd)
3444+ }
3445+ if cmd := pendingItem.StartAnimation(); cmd != nil {
3446+ cmds = append(cmds, cmd)
3447+ }
3448+ }
3449+
34073450 cmds = append(cmds, func() tea.Msg {
34083451 resp, err := m.com.Workspace.AgentRunShellCommand(context.Background(), sessionID, command, contentWidth)
34093452 if err != nil {
@@ -3413,9 +3456,10 @@ func (m *UI) runShellCommand(command string) tea.Cmd {
34133456 }
34143457 }
34153458 return shellResultMsg{
3416− Command: command,
3417− Output: resp.Output,
3418− ExitCode: resp.ExitCode,
3459+ PendingID: pendingItem.ID(),
3460+ Command: command,
3461+ Output: resp.Output,
3462+ ExitCode: resp.ExitCode,
34193463 }
34203464 })
34213465 return tea.Batch(cmds...)