func AddComment(n *github.Notification, issue *github.Issue, comment string) tea.Cmd {
	return func(ctx context.Context) tea.Msg {
		gh := MustClientFromContext(ctx)
		ctx, cancel := context.WithTimeout(ctx, time.Second*10)
		defer cancel()
		owner, repo := ownerRepo(n)
		_, _, err := gh.Issues.CreateComment(ctx, owner, repo, issue.GetNumber(), &github.IssueComment{
			Body: &comment,
		})
		if err != nil {
			return fmt.Errorf("creating comment: %w", err)
		}
		return CommentAdded{}
	}
}
AddComment adds a comment to an issue.
package triage
import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
	"github.com/AstromechZA/terminfo"
	"github.com/google/go-github/v28/github"
	"github.com/pkg/browser"
	"github.com/tj/go-tea"
)
func GetDimensions(ctx context.Context) tea.Msg {
	w, h, err := terminfo.GetStdoutDimensions()
	if err != nil {
		return err
	}
	if w == 0 && h == 0 {
		ch := make(chan os.Signal, 1)
		signal.Notify(ch, syscall.SIGWINCH)
		<-ch
		return GetDimensions(ctx)
	}
	return GotDimensions{w, h}
}
func LoadNotifications(ctx context.Context) tea.Msg {
	gh := MustClientFromContext(ctx)
	ctx, cancel := context.WithTimeout(ctx, time.Second*5)
	defer cancel()
	options := &github.NotificationListOptions{
		ListOptions: github.ListOptions{
			PerPage: 100,
		},
	}
	var filtered []*github.Notification
	notifications, _, err := gh.Activity.ListNotifications(ctx, options)
	if err != nil {
		return fmt.Errorf("fetching notifications: %w", err)
	}
	for _, n := range notifications {
		if n.GetSubject().GetType() == "Release" {
			continue
		}
		filtered = append(filtered, n)
	}
	return NotificationsLoaded{filtered}
}
func LoadNotification(n *github.Notification) tea.Cmd {
	return LoadNotificationIssue(n)
}
func LoadNotificationIssue(n *github.Notification) tea.Cmd {
	return func(ctx context.Context) tea.Msg {
		ctx, cancel := context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		issue, err := getIssue(ctx, n)
		if err != nil {
			return fmt.Errorf("fetching issue: %w", err)
		}
		return NotificationIssueLoaded{issue}
	}
}
func LoadNotificationLabels(n *github.Notification, issue *github.Issue) tea.Cmd {
	return func(ctx context.Context) tea.Msg {
		ctx, cancel := context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		labels, err := getIssueLabels(ctx, n, issue.GetNumber())
		if err != nil {
			return fmt.Errorf("fetching issue labels: %w", err)
		}
		return NotificationLabelsLoaded{labels}
	}
}
func LoadNotificationComments(issue *github.Issue) tea.Cmd {
	return func(ctx context.Context) tea.Msg {
		ctx, cancel := context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		comments, err := getIssueComments(ctx, issue)
		if err != nil {
			return fmt.Errorf("fetching issue comments: %w", err)
		}
		return NotificationCommentsLoaded{comments}
	}
}
func LoadRepoLabels(n *github.Notification) tea.Cmd {
	return func(ctx context.Context) tea.Msg {
		gh := MustClientFromContext(ctx)
		ctx, cancel := context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		owner, repo := ownerRepo(n)
		labels, _, err := gh.Issues.ListLabels(ctx, owner, repo, nil)
		if err != nil {
			return fmt.Errorf("fetching repo labels: %w", err)
		}
		return LabelsLoaded{labels}
	}
}
func UpdateNotificationLabels(n *github.Notification, issue *github.Issue, labels []string) tea.Cmd {
	return func(ctx context.Context) tea.Msg {
		gh := MustClientFromContext(ctx)
		ctx, cancel := context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		owner, repo := ownerRepo(n)
		if len(labels) == 0 {
			_, err := gh.Issues.RemoveLabelsForIssue(ctx, owner, repo, issue.GetNumber())
			if err != nil {
				return fmt.Errorf("removing labels: %w", err)
			}
		} else {
			_, _, err := gh.Issues.ReplaceLabelsForIssue(ctx, owner, repo, issue.GetNumber(), labels)
			if err != nil {
				return fmt.Errorf("replacing labels: %w", err)
			}
		}
		return NotificationLabelsUpdated{}
	}
}
func UpdateNotificationPriority(n *github.Notification, issue *github.Issue, name string) tea.Cmd {
	return func(ctx context.Context) tea.Msg {
		gh := MustClientFromContext(ctx)
		config := MustConfigFromContext(ctx)
		ctx, cancel := context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		owner, repo := ownerRepo(n)
		var priority Priority
		for _, p := range config.Priorities {
			if p.Name == name {
				priority = p
				break
			}
		}
		color := strings.Replace(priority.Color, "#", "", 1)
		desc := fmt.Sprintf("%s priority issue.", priority.Name)
		_, _, err := gh.Issues.CreateLabel(ctx, owner, repo, &github.Label{
			Name:        &priority.Label,
			Color:       &color,
			Description: &desc,
		})
		if err != nil && !isAlreadyExists(err) {
			return fmt.Errorf("creating priority label: %w", err)
		}
		for _, p := range config.Priorities {
			_, err := gh.Issues.RemoveLabelForIssue(ctx, owner, repo, issue.GetNumber(), p.Label)
			if err != nil && !isNotFound(err) {
				return fmt.Errorf("error removing label %q: %w", p.Label, err)
			}
		}
		_, _, err = gh.Issues.AddLabelsToIssue(ctx, owner, repo, issue.GetNumber(), []string{priority.Label})
		if err != nil {
			return fmt.Errorf("assigning priority label: %w", err)
		}
		return NotificationPriorityUpdated{}
	}
}