package tui import ( "context" "encoding/json" "fmt" "strings" tea "github.com/charmbracelet/bubbletea" ) // permissionRequest kommt vom Backend-Loop (E-11: "ask"-Modus) über // Model.permCh. resp erwartet genau eine Antwort; requestPermission blockiert // darauf im Loop-Goroutine, bis die TUI eine Taste verarbeitet hat. type permissionRequest struct { tool string input json.RawMessage resp chan bool } type permissionRequestMsg struct{ req permissionRequest } func listenPermissionRequests(ch <-chan permissionRequest) tea.Cmd { return func() tea.Msg { req, ok := <-ch if !ok { return nil } return permissionRequestMsg{req: req} } } // requestPermission ist der Hook, den loop.RequestPermission aufruft (siehe // New()). Läuft auf dem Goroutine des Backend-Loops, nicht dem der TUI — // deshalb reine Channel-Kommunikation statt direktem Feldzugriff auf m. func (m *Model) requestPermission(ctx context.Context, toolName string, input json.RawMessage) bool { resp := make(chan bool, 1) req := permissionRequest{tool: toolName, input: input, resp: resp} select { case m.permCh <- req: case <-ctx.Done(): return false } select { case decision := <-resp: return decision case <-ctx.Done(): return false } } func (m *Model) handlePermissionKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { req := m.permReq m.permReq = nil allow := msg.String() == "y" || msg.String() == "Y" req.resp <- allow verb := "denied" if allow { verb = "allowed" } m.pushCommand(fmt.Sprintf("permission %s: %s", verb, req.tool)) return m, nil } // renderPermissionRequest baut den Transkript-Block für eine offene // Rückfrage — bewusst kein Vollbild-Overlay (das hat vorher den Kontext // verdeckt, den man für die Entscheidung braucht), sondern ein eigener, // umrandeter Eintrag im normalen Nachrichtenfluss. Viewport, Eingabefeld und // Statuszeile bleiben sichtbar; die Statuszeile zeigt zusätzlich einen // Hinweis (siehe renderStatusLine). func renderPermissionRequest(toolName string, input json.RawMessage) string { in := strings.TrimSpace(prettyJSON(input)) if len(in) > 300 { in = in[:300] + "…" } body := fmt.Sprintf("⚠ Rückfrage: %s\n%s\n\n[y] erlauben [n / Esc / beliebige andere Taste] ablehnen", toolName, in) return stylePermissionBox.Render(body) }