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