Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/charmbracelet/bubbletea v1.3.4
github.com/charmbracelet/glamour v0.9.1
github.com/charmbracelet/lipgloss v1.1.0
github.com/charmbracelet/log v0.4.2
github.com/charmbracelet/x/ansi v0.8.0
github.com/fsnotify/fsnotify v1.8.0
github.com/go-logfmt/logfmt v0.6.0
Expand All @@ -34,10 +35,7 @@ require (
github.com/stretchr/testify v1.10.0
)

require (
github.com/charmbracelet/log v0.4.2 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
)
require golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect

require (
cloud.google.com/go v0.116.0 // indirect
Expand Down Expand Up @@ -74,7 +72,7 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/s2a-go v0.1.8 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
Expand Down
15 changes: 15 additions & 0 deletions internal/llm/models/anthropic.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
Claude35Haiku ModelID = "claude-3.5-haiku"
Claude3Opus ModelID = "claude-3-opus"
Claude4Sonnet ModelID = "claude-4-sonnet"
Claude4Opus ModelID = "claude-4-opus"
)

// https://docs.anthropic.com/en/docs/about-claude/models/all-models
Expand Down Expand Up @@ -68,6 +69,20 @@ var AnthropicModels = map[ModelID]Model{
CanReason: true,
SupportsAttachments: true,
},
Claude4Opus: {
ID: Claude4Opus,
Name: "Claude 4 Opus",
Provider: ProviderAnthropic,
APIModel: "claude-opus-4-20250514",
CostPer1MIn: 15.0,
CostPer1MInCached: 18.75,
CostPer1MOutCached: 1.50,
CostPer1MOut: 75.0,
ContextWindow: 200000,
DefaultMaxTokens: 32000,
CanReason: true,
SupportsAttachments: true,
},
Claude35Haiku: {
ID: Claude35Haiku,
Name: "Claude 3.5 Haiku",
Expand Down
30 changes: 30 additions & 0 deletions internal/llm/models/bedrock.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const (

// Models
BedrockClaude37Sonnet ModelID = "bedrock.claude-3.7-sonnet"
BedrockClaude4Sonnet ModelID = "bedrock.claude-4.0-sonnet"
BedrockClaude4Opus ModelID = "bedrock.claude-4.0-opus"
)

var BedrockModels = map[ModelID]Model{
Expand All @@ -22,4 +24,32 @@ var BedrockModels = map[ModelID]Model{
CanReason: true,
SupportsAttachments: true,
},
BedrockClaude4Sonnet: {
ID: BedrockClaude4Sonnet,
Name: "Bedrock: Claude 4 Sonnet",
Provider: ProviderBedrock,
APIModel: "anthropic.claude-sonnet-4-20250514-v1:0",
CostPer1MIn: 3.0,
CostPer1MInCached: 3.75,
CostPer1MOutCached: 0.30,
CostPer1MOut: 15.0,
ContextWindow: 200_000,
DefaultMaxTokens: 50_000,
CanReason: true,
SupportsAttachments: true,
},
BedrockClaude4Opus: {
ID: BedrockClaude4Opus,
Name: "Bedrock: Claude 4 Opus",
Provider: ProviderBedrock,
APIModel: "anthropic.claude-opus-4-20250514-v1:0",
CostPer1MIn: 15.0,
CostPer1MInCached: 18.75,
CostPer1MOutCached: 1.50,
CostPer1MOut: 75.0,
ContextWindow: 200_000,
DefaultMaxTokens: 50_000,
CanReason: true,
SupportsAttachments: true,
},
}
107 changes: 107 additions & 0 deletions internal/tui/theme/nord.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package theme

import (
"github.com/charmbracelet/lipgloss"
)

// NordTheme implements the Theme interface with Nord colors.
// It provides both list and dark variants based on the Nord palette.
type NordTheme struct {
BaseTheme
}

// NewNordTheme creates a new instance of the Nord theme.
func NewNordTheme() *NordTheme {
// Nord color palette from https://www.nordtheme.com/docs/colors-and-palettes
polarNight0 := "#2E3440"
polarNight1 := "#3B4252"
polarNight2 := "#434C5E"
polarNight3 := "#4C566A"
snowStorm0 := "#D8DEE9"
snowStorm1 := "#E5E9F0"
snowStorm2 := "#ECEFF4"
frost0 := "#8FBCBB"
frost1 := "#88C0D0"
frost2 := "#81A1C1"
frost3 := "#5E81AC"
aurora0 := "#BF616A"
// aurora1 := "#D08770"
aurora2 := "#EBCB8B"
aurora3 := "#A3BE8C"
aurora4 := "#B48EAD"

theme := &NordTheme{}

// Base colors
theme.PrimaryColor = lipgloss.AdaptiveColor{Dark: frost1, Light: frost1}
theme.SecondaryColor = lipgloss.AdaptiveColor{Dark: frost2, Light: frost2}
theme.AccentColor = lipgloss.AdaptiveColor{Dark: frost0, Light: frost0}

// Status colors
theme.ErrorColor = lipgloss.AdaptiveColor{Dark: aurora0, Light: aurora0}
theme.WarningColor = lipgloss.AdaptiveColor{Dark: aurora2, Light: aurora2}
theme.SuccessColor = lipgloss.AdaptiveColor{Dark: aurora3, Light: aurora3}
theme.InfoColor = lipgloss.AdaptiveColor{Dark: frost0, Light: frost0}

// Text colors
theme.TextColor = lipgloss.AdaptiveColor{Dark: snowStorm2, Light: polarNight0}
theme.TextMutedColor = lipgloss.AdaptiveColor{Dark: snowStorm0, Light: polarNight3}
theme.TextEmphasizedColor = lipgloss.AdaptiveColor{Dark: aurora2, Light: aurora2}

// Background colors
theme.BackgroundColor = lipgloss.AdaptiveColor{Dark: polarNight0, Light: snowStorm2}
theme.BackgroundSecondaryColor = lipgloss.AdaptiveColor{Dark: polarNight1, Light: snowStorm1}
theme.BackgroundDarkerColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm0}

// Border colors
theme.BorderNormalColor = lipgloss.AdaptiveColor{Dark: polarNight3, Light: snowStorm1}
theme.BorderFocusedColor = lipgloss.AdaptiveColor{Dark: frost3, Light: frost3}
theme.BorderDimColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm0}

// Diff view colors
theme.DiffAddedColor = lipgloss.AdaptiveColor{Dark: aurora3, Light: aurora3}
theme.DiffRemovedColor = lipgloss.AdaptiveColor{Dark: aurora0, Light: aurora0}
theme.DiffContextColor = lipgloss.AdaptiveColor{Dark: polarNight3, Light: snowStorm0}
theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{Dark: frost3, Light: frost3}
theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{Dark: frost3, Light: frost3}
theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{Dark: aurora0, Light: aurora0}
theme.DiffAddedBgColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm0}
theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm0}
theme.DiffContextBgColor = lipgloss.AdaptiveColor{Dark: polarNight1, Light: snowStorm1}
theme.DiffLineNumberColor = lipgloss.AdaptiveColor{Dark: polarNight3, Light: snowStorm1}
theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm0}
theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm0}

// Markdown colors
theme.MarkdownTextColor = lipgloss.AdaptiveColor{Dark: snowStorm2, Light: polarNight0}
theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{Dark: frost3, Light: frost3}
theme.MarkdownLinkColor = lipgloss.AdaptiveColor{Dark: frost0, Light: frost0}
theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{Dark: frost1, Light: frost1}
theme.MarkdownCodeColor = lipgloss.AdaptiveColor{Dark: aurora3, Light: aurora3}
theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{Dark: aurora2, Light: aurora2}
theme.MarkdownEmphColor = lipgloss.AdaptiveColor{Dark: aurora2, Light: aurora2}
theme.MarkdownStrongColor = lipgloss.AdaptiveColor{Dark: aurora0, Light: aurora0}
theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{Dark: polarNight3, Light: snowStorm1}
theme.MarkdownListItemColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm1}
theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm1}
theme.MarkdownImageColor = lipgloss.AdaptiveColor{Dark: frost1, Light: frost1}
theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{Dark: frost1, Light: frost1}
theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm0}

// Syntax highsnowStorming colors
theme.SyntaxCommentColor = lipgloss.AdaptiveColor{Dark: polarNight3, Light: snowStorm2}
theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{Dark: aurora4, Light: aurora4}
theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{Dark: frost1, Light: frost1}
theme.SyntaxVariableColor = lipgloss.AdaptiveColor{Dark: frost0, Light: frost0}
theme.SyntaxStringColor = lipgloss.AdaptiveColor{Dark: aurora2, Light: aurora2}
theme.SyntaxNumberColor = lipgloss.AdaptiveColor{Dark: aurora2, Light: aurora2}
theme.SyntaxTypeColor = lipgloss.AdaptiveColor{Dark: aurora3, Light: aurora3}
theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{Dark: aurora4, Light: aurora4}
theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{Dark: polarNight2, Light: snowStorm2}

return theme
}

func init() {
RegisterTheme("nord", NewNordTheme())
}
12 changes: 12 additions & 0 deletions internal/tui/theme/theme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ func TestThemeRegistration(t *testing.T) {
t.Errorf("Monokai theme is not registered")
}

// Check if "nord" theme is registered
nordFound := false
for _, themeName := range availableThemes {
if themeName == "nord" {
nordFound = true
break
}
}
if !nordFound {
t.Errorf("Nord theme is not registered")
}

// Try to get the themes and make sure they're not nil
catppuccin := GetTheme("catppuccin")
if catppuccin == nil {
Expand Down
1 change: 1 addition & 0 deletions www/src/content/docs/docs/themes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The following predefined themes are available:
- `flexoki`
- `gruvbox`
- `monokai`
- `nord`
- `onedark`
- `tokyonight`
- `tron`
Expand Down