feat(tui): navigate child sessions (subagents)
This commit is contained in:
@@ -391,11 +391,41 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return a, toast.NewErrorToast(msg.Error())
|
||||
case app.SendPrompt:
|
||||
a.showCompletionDialog = false
|
||||
a.app, cmd = a.app.SendPrompt(context.Background(), msg)
|
||||
cmds = append(cmds, cmd)
|
||||
// If we're in a child session, switch back to parent before sending prompt
|
||||
if a.app.Session.ParentID != "" {
|
||||
parentSession, err := a.app.Client.Session.Get(context.Background(), a.app.Session.ParentID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get parent session", "error", err)
|
||||
return a, toast.NewErrorToast("Failed to get parent session")
|
||||
}
|
||||
a.app.Session = parentSession
|
||||
a.app, cmd = a.app.SendPrompt(context.Background(), msg)
|
||||
cmds = append(cmds, tea.Sequence(
|
||||
util.CmdHandler(app.SessionSelectedMsg(parentSession)),
|
||||
cmd,
|
||||
))
|
||||
} else {
|
||||
a.app, cmd = a.app.SendPrompt(context.Background(), msg)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
case app.SendShell:
|
||||
a.app, cmd = a.app.SendShell(context.Background(), msg.Command)
|
||||
cmds = append(cmds, cmd)
|
||||
// If we're in a child session, switch back to parent before sending prompt
|
||||
if a.app.Session.ParentID != "" {
|
||||
parentSession, err := a.app.Client.Session.Get(context.Background(), a.app.Session.ParentID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get parent session", "error", err)
|
||||
return a, toast.NewErrorToast("Failed to get parent session")
|
||||
}
|
||||
a.app.Session = parentSession
|
||||
a.app, cmd = a.app.SendShell(context.Background(), msg.Command)
|
||||
cmds = append(cmds, tea.Sequence(
|
||||
util.CmdHandler(app.SessionSelectedMsg(parentSession)),
|
||||
cmd,
|
||||
))
|
||||
} else {
|
||||
a.app, cmd = a.app.SendShell(context.Background(), msg.Command)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
case app.SetEditorContentMsg:
|
||||
// Set the editor content without sending
|
||||
a.editor.SetValueWithAttachments(msg.Text)
|
||||
@@ -1111,6 +1141,122 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
// TODO: block until compaction is complete
|
||||
a.app.CompactSession(context.Background())
|
||||
case commands.SessionChildCycleCommand:
|
||||
if a.app.Session.ID == "" {
|
||||
return a, nil
|
||||
}
|
||||
cmds = append(cmds, func() tea.Msg {
|
||||
parentSessionID := a.app.Session.ID
|
||||
var parentSession *opencode.Session
|
||||
if a.app.Session.ParentID != "" {
|
||||
parentSessionID = a.app.Session.ParentID
|
||||
session, err := a.app.Client.Session.Get(context.Background(), parentSessionID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get parent session", "error", err)
|
||||
return toast.NewErrorToast("Failed to get parent session")
|
||||
}
|
||||
parentSession = session
|
||||
} else {
|
||||
parentSession = a.app.Session
|
||||
}
|
||||
|
||||
children, err := a.app.Client.Session.Children(context.Background(), parentSessionID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get session children", "error", err)
|
||||
return toast.NewErrorToast("Failed to get session children")
|
||||
}
|
||||
|
||||
// Reverse sort the children (newest first)
|
||||
slices.Reverse(*children)
|
||||
|
||||
// Create combined array: [parent, child1, child2, ...]
|
||||
sessions := []*opencode.Session{parentSession}
|
||||
for i := range *children {
|
||||
sessions = append(sessions, &(*children)[i])
|
||||
}
|
||||
|
||||
if len(sessions) == 1 {
|
||||
return toast.NewInfoToast("No child sessions available")
|
||||
}
|
||||
|
||||
// Find current session index in combined array
|
||||
currentIndex := -1
|
||||
for i, session := range sessions {
|
||||
if session.ID == a.app.Session.ID {
|
||||
currentIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If session not found, default to parent (shouldn't happen)
|
||||
if currentIndex == -1 {
|
||||
currentIndex = 0
|
||||
}
|
||||
|
||||
// Cycle to next session (parent or child)
|
||||
nextIndex := (currentIndex + 1) % len(sessions)
|
||||
nextSession := sessions[nextIndex]
|
||||
|
||||
return app.SessionSelectedMsg(nextSession)
|
||||
})
|
||||
case commands.SessionChildCycleReverseCommand:
|
||||
if a.app.Session.ID == "" {
|
||||
return a, nil
|
||||
}
|
||||
cmds = append(cmds, func() tea.Msg {
|
||||
parentSessionID := a.app.Session.ID
|
||||
var parentSession *opencode.Session
|
||||
if a.app.Session.ParentID != "" {
|
||||
parentSessionID = a.app.Session.ParentID
|
||||
session, err := a.app.Client.Session.Get(context.Background(), parentSessionID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get parent session", "error", err)
|
||||
return toast.NewErrorToast("Failed to get parent session")
|
||||
}
|
||||
parentSession = session
|
||||
} else {
|
||||
parentSession = a.app.Session
|
||||
}
|
||||
|
||||
children, err := a.app.Client.Session.Children(context.Background(), parentSessionID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get session children", "error", err)
|
||||
return toast.NewErrorToast("Failed to get session children")
|
||||
}
|
||||
|
||||
// Reverse sort the children (newest first)
|
||||
slices.Reverse(*children)
|
||||
|
||||
// Create combined array: [parent, child1, child2, ...]
|
||||
sessions := []*opencode.Session{parentSession}
|
||||
for i := range *children {
|
||||
sessions = append(sessions, &(*children)[i])
|
||||
}
|
||||
|
||||
if len(sessions) == 1 {
|
||||
return toast.NewInfoToast("No child sessions available")
|
||||
}
|
||||
|
||||
// Find current session index in combined array
|
||||
currentIndex := -1
|
||||
for i, session := range sessions {
|
||||
if session.ID == a.app.Session.ID {
|
||||
currentIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If session not found, default to parent (shouldn't happen)
|
||||
if currentIndex == -1 {
|
||||
currentIndex = 0
|
||||
}
|
||||
|
||||
// Cycle to previous session (parent or child)
|
||||
nextIndex := (currentIndex - 1 + len(sessions)) % len(sessions)
|
||||
nextSession := sessions[nextIndex]
|
||||
|
||||
return app.SessionSelectedMsg(nextSession)
|
||||
})
|
||||
case commands.SessionExportCommand:
|
||||
if a.app.Session.ID == "" {
|
||||
return a, toast.NewErrorToast("No active session to export.")
|
||||
|
||||
Reference in New Issue
Block a user