Skip to content

Commit 1828e12

Browse files
committed
Add /clear command to reset current tab with a new session
Introduces a /clear slash command that resets the current tab and starts a fresh session in the same working directory. Unlike /new which opens a new tab, /clear reuses the current tab by creating a new session in-place, rebuilding UI components, and updating persisted state. Assisted-By: docker-agent
1 parent a099feb commit 1828e12

4 files changed

Lines changed: 67 additions & 0 deletions

File tree

pkg/tui/commands/commands.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ type Item struct {
3636

3737
func builtInSessionCommands() []Item {
3838
cmds := []Item{
39+
{
40+
ID: "session.clear",
41+
Label: "Clear",
42+
SlashCommand: "/clear",
43+
Description: "Clear the current tab and start a new session",
44+
Category: "Session",
45+
Execute: func(string) tea.Cmd {
46+
return core.CmdHandler(messages.ClearSessionMsg{})
47+
},
48+
},
3949
{
4050
ID: "session.attach",
4151
Label: "Attach",

pkg/tui/commands/commands_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ func TestParseSlashCommand_OtherCommands(t *testing.T) {
7171
assert.True(t, ok)
7272
})
7373

74+
t.Run("clear command", func(t *testing.T) {
75+
t.Parallel()
76+
cmd := ParseSlashCommand("/clear")
77+
require.NotNil(t, cmd)
78+
msg := cmd()
79+
_, ok := msg.(messages.ClearSessionMsg)
80+
assert.True(t, ok)
81+
})
82+
7483
t.Run("star command", func(t *testing.T) {
7584
t.Parallel()
7685
cmd := ParseSlashCommand("/star")

pkg/tui/messages/session.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ type (
2525
// NewSessionMsg requests creation of a new session.
2626
NewSessionMsg struct{}
2727

28+
// ClearSessionMsg resets the current tab and starts a new session
29+
// in the same working directory.
30+
ClearSessionMsg struct{}
31+
2832
// ExitSessionMsg requests exiting the current session.
2933
ExitSessionMsg struct{}
3034

pkg/tui/tui.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,10 @@ func (m *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
702702
// /new spawns a new tab when a session spawner is configured.
703703
return m.handleSpawnSession("")
704704

705+
case messages.ClearSessionMsg:
706+
// /clear resets the current tab with a fresh session in the same working dir.
707+
return m.handleClearSession()
708+
705709
// --- Exit ---
706710

707711
case messages.ExitSessionMsg:
@@ -1116,6 +1120,46 @@ func (m *appModel) replaceActiveSession(ctx context.Context, sess *session.Sessi
11161120
return m, cmd
11171121
}
11181122

1123+
// handleClearSession resets the current tab by creating a fresh session
1124+
// in the same working directory.
1125+
func (m *appModel) handleClearSession() (tea.Model, tea.Cmd) {
1126+
activeID := m.supervisor.ActiveID()
1127+
1128+
// Cleanup old editor for the active session.
1129+
if ed, ok := m.editors[activeID]; ok {
1130+
ed.Cleanup()
1131+
}
1132+
1133+
// Create a fresh session in the same app, preserving the working dir.
1134+
m.application.NewSession()
1135+
newSess := m.application.Session()
1136+
1137+
// Rebuild all per-session UI components.
1138+
m.initSessionComponents(activeID, m.application, newSess)
1139+
m.dialogMgr = dialog.New()
1140+
m.supervisor.SetRunnerTitle(activeID, "")
1141+
m.sessionState.SetSessionTitle("")
1142+
m.sessionState.SetPreviousMessage(nil)
1143+
1144+
// Update persisted tab to point to the new session.
1145+
if m.tuiStore != nil {
1146+
ctx := context.Background()
1147+
oldPersistedID := m.persistedSessionID(activeID)
1148+
if err := m.tuiStore.UpdateTabSessionID(ctx, oldPersistedID, newSess.ID); err != nil {
1149+
slog.Warn("Failed to update tab session ID after clear", "error", err)
1150+
}
1151+
}
1152+
m.persistActiveTab(newSess.ID)
1153+
1154+
m.reapplyKeyboardEnhancements()
1155+
1156+
return m, tea.Sequence(
1157+
m.chatPage.Init(),
1158+
m.resizeAll(),
1159+
m.editor.Focus(),
1160+
)
1161+
}
1162+
11191163
// handleSpawnSession spawns a new session.
11201164
func (m *appModel) handleSpawnSession(workingDir string) (tea.Model, tea.Cmd) {
11211165
// If no working dir specified, open the picker

0 commit comments

Comments
 (0)