From 5cc3857d9eb43035afe56714a8ad7cac1acd7395 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Wed, 18 Mar 2026 09:23:15 +0100 Subject: [PATCH 1/2] feat: support "exit" as a keyword to quit the session Typing "exit" in the TUI now terminates the session immediately, equivalent to the /exit slash command. The check is case-insensitive and whitespace-trimmed, and runs before slash command parsing so it works even when the agent is busy. --- pkg/tui/page/chat/chat.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/tui/page/chat/chat.go b/pkg/tui/page/chat/chat.go index 357e297db..c0d9c09dc 100644 --- a/pkg/tui/page/chat/chat.go +++ b/pkg/tui/page/chat/chat.go @@ -624,6 +624,12 @@ func (p *chatPage) cancelStream(showCancelMessage bool) tea.Cmd { // handleSendMsg handles incoming messages from the editor, either processing // them immediately or queuing them if the agent is busy. func (p *chatPage) handleSendMsg(msg msgtypes.SendMsg) (layout.Model, tea.Cmd) { + // Handle "exit" as a special keyword to quit the session immediately, + // equivalent to the /exit slash command. + if strings.TrimSpace(strings.ToLower(msg.Content)) == "exit" { + return p, core.CmdHandler(msgtypes.ExitSessionMsg{}) + } + // Predefined slash commands (e.g., /yolo, /exit, /compact) execute immediately // even while the agent is working - they're UI commands that don't interrupt the stream. // Custom agent commands (defined in config) should still be queued. From 5813e3b517665bec383104fc4d3f8143dddc47f8 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Wed, 18 Mar 2026 09:31:48 +0100 Subject: [PATCH 2/2] feat: add "quit" and ":q" as exit aliases, matching opencode behavior Add "quit" and ":q" as bare keywords (alongside "exit") that quit the session immediately. Also register /quit and /q as slash command aliases for /exit. The bare keyword check is now case-sensitive, matching opencode's implementation. --- pkg/tui/commands/commands.go | 20 ++++++++++++++++++++ pkg/tui/page/chat/chat.go | 7 ++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/pkg/tui/commands/commands.go b/pkg/tui/commands/commands.go index f3eeed72f..1deacef21 100644 --- a/pkg/tui/commands/commands.go +++ b/pkg/tui/commands/commands.go @@ -107,6 +107,26 @@ func builtInSessionCommands() []Item { return core.CmdHandler(messages.ExitSessionMsg{}) }, }, + { + ID: "session.quit", + Label: "Quit", + SlashCommand: "/quit", + Description: "Quit the application (alias for /exit)", + Category: "Session", + Execute: func(string) tea.Cmd { + return core.CmdHandler(messages.ExitSessionMsg{}) + }, + }, + { + ID: "session.q", + Label: "Quit (short)", + SlashCommand: "/q", + Description: "Quit the application (alias for /exit)", + Category: "Session", + Execute: func(string) tea.Cmd { + return core.CmdHandler(messages.ExitSessionMsg{}) + }, + }, { ID: "session.export", Label: "Export", diff --git a/pkg/tui/page/chat/chat.go b/pkg/tui/page/chat/chat.go index c0d9c09dc..7eb86530f 100644 --- a/pkg/tui/page/chat/chat.go +++ b/pkg/tui/page/chat/chat.go @@ -624,9 +624,10 @@ func (p *chatPage) cancelStream(showCancelMessage bool) tea.Cmd { // handleSendMsg handles incoming messages from the editor, either processing // them immediately or queuing them if the agent is busy. func (p *chatPage) handleSendMsg(msg msgtypes.SendMsg) (layout.Model, tea.Cmd) { - // Handle "exit" as a special keyword to quit the session immediately, - // equivalent to the /exit slash command. - if strings.TrimSpace(strings.ToLower(msg.Content)) == "exit" { + // Handle "exit", "quit", and ":q" as special keywords to quit the session + // immediately, equivalent to the /exit slash command. + switch strings.TrimSpace(msg.Content) { + case "exit", "quit", ":q": return p, core.CmdHandler(msgtypes.ExitSessionMsg{}) }