41 lines
1.3 KiB
Go
41 lines
1.3 KiB
Go
package tui
|
|
|
|
import (
|
|
"context"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
"nub/internal/agent"
|
|
"nub/internal/config"
|
|
"nub/internal/mcpc"
|
|
"nub/internal/session"
|
|
"nub/internal/skill"
|
|
"nub/internal/tool"
|
|
)
|
|
|
|
// Run startet die TUI und blockiert, bis der Nutzer beendet oder der
|
|
// Kontext abbricht. loop.Run wird intern gestartet (auch erneut bei einem
|
|
// Session-Wechsel über /sessions); die TUI ist ein reiner Consumer des
|
|
// jeweils aktuellen UIEvent-Channels (E-04).
|
|
func Run(ctx context.Context, loop *agent.Loop, store *session.Store, cfg config.Config, skills []skill.Skill, mcpServers []*mcpc.Server) error {
|
|
runCtx, cancel := context.WithCancel(ctx)
|
|
defer cancel()
|
|
|
|
m := New(runCtx, loop, store, cfg, skills, mcpServers)
|
|
|
|
p := tea.NewProgram(m, tea.WithAltScreen(), tea.WithContext(runCtx), tea.WithMouseCellMotion())
|
|
finalModel, err := p.Run()
|
|
|
|
// `in` bewusst nicht schließen: ein noch laufender sendInput-Cmd könnte
|
|
// gerade darauf senden; Close+Send racet in einen "send on closed
|
|
// channel"-Panic. ctx.Done() reicht, damit loop.Run() sauber zurückkehrt.
|
|
cancel()
|
|
if fm, ok := finalModel.(*Model); ok && fm.out != nil {
|
|
for range fm.out {
|
|
// Drainen, damit loop.Run() nicht an einem blockierenden Send hängen bleibt.
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
var _ tool.UIEvent // Import-Anker: tool wird über model.go/render.go transitiv gebraucht
|