Przeglądaj źródła

wip: refactoring tui

adamdottv 8 miesięcy temu
rodzic
commit
cce2e4ad75
47 zmienionych plików z 1025 dodań i 3413 usunięć
  1. 3 1
      packages/tui/cmd/opencode/main.go
  2. 13 9
      packages/tui/go.mod
  3. 26 18
      packages/tui/go.sum
  4. 1 1
      packages/tui/internal/app/app.go
  5. 28 33
      packages/tui/internal/components/chat/editor.go
  6. 17 32
      packages/tui/internal/components/chat/message.go
  7. 24 92
      packages/tui/internal/components/chat/messages.go
  8. 15 114
      packages/tui/internal/components/core/status.go
  9. 24 17
      packages/tui/internal/components/dialog/arguments.go
  10. 11 11
      packages/tui/internal/components/dialog/commands.go
  11. 6 6
      packages/tui/internal/components/dialog/complete.go
  12. 1 1
      packages/tui/internal/components/dialog/custom_commands.go
  13. 25 24
      packages/tui/internal/components/dialog/filepicker.go
  14. 16 15
      packages/tui/internal/components/dialog/help.go
  15. 3 3
      packages/tui/internal/components/dialog/init.go
  16. 17 17
      packages/tui/internal/components/dialog/models.go
  17. 30 30
      packages/tui/internal/components/dialog/permission.go
  18. 10 10
      packages/tui/internal/components/dialog/quit.go
  19. 12 12
      packages/tui/internal/components/dialog/session.go
  20. 10 10
      packages/tui/internal/components/dialog/theme.go
  21. 20 20
      packages/tui/internal/components/dialog/tools.go
  22. 10 10
      packages/tui/internal/components/diff/diff.go
  23. 1 1
      packages/tui/internal/components/qr/qr.go
  24. 4 4
      packages/tui/internal/components/util/simple-list.go
  25. 9 8
      packages/tui/internal/image/images.go
  26. 12 7
      packages/tui/internal/layout/container.go
  27. 4 10
      packages/tui/internal/layout/flex.go
  28. 2 2
      packages/tui/internal/layout/layout.go
  29. 2 2
      packages/tui/internal/layout/overlay.go
  30. 4 4
      packages/tui/internal/page/chat.go
  31. 7 117
      packages/tui/internal/styles/background.go
  32. 106 69
      packages/tui/internal/styles/markdown.go
  33. 17 16
      packages/tui/internal/styles/styles.go
  34. 0 276
      packages/tui/internal/theme/ayu.go
  35. 0 244
      packages/tui/internal/theme/catppuccin.go
  36. 0 270
      packages/tui/internal/theme/dracula.go
  37. 0 278
      packages/tui/internal/theme/flexoki.go
  38. 0 298
      packages/tui/internal/theme/gruvbox.go
  39. 2 3
      packages/tui/internal/theme/manager.go
  40. 0 269
      packages/tui/internal/theme/monokai.go
  41. 0 270
      packages/tui/internal/theme/onedark.go
  42. 152 151
      packages/tui/internal/theme/opencode.go
  43. 180 179
      packages/tui/internal/theme/theme.go
  44. 152 151
      packages/tui/internal/theme/tokyonight.go
  45. 0 272
      packages/tui/internal/theme/tron.go
  46. 48 25
      packages/tui/internal/tui/tui.go
  47. 1 1
      packages/tui/internal/util/util.go

+ 3 - 1
packages/tui/cmd/opencode/main.go

@@ -9,7 +9,7 @@ import (
 	"sync"
 	"time"
 
-	tea "github.com/charmbracelet/bubbletea"
+	tea "github.com/charmbracelet/bubbletea/v2"
 	zone "github.com/lrstanley/bubblezone"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/pubsub"
@@ -65,6 +65,8 @@ func main() {
 	zone.NewGlobal()
 	program := tea.NewProgram(
 		tui.NewModel(app_),
+		// tea.WithMouseCellMotion(),
+		tea.WithKeyboardEnhancements(),
 		tea.WithAltScreen(),
 	)
 

+ 13 - 9
packages/tui/go.mod

@@ -4,13 +4,12 @@ go 1.24.0
 
 require (
 	github.com/BurntSushi/toml v1.5.0
-	github.com/alecthomas/chroma/v2 v2.15.0
+	github.com/alecthomas/chroma/v2 v2.18.0
 	github.com/bmatcuk/doublestar/v4 v4.8.1
-	github.com/catppuccin/go v0.3.0
-	github.com/charmbracelet/bubbles v0.21.0
-	github.com/charmbracelet/bubbletea v1.3.4
-	github.com/charmbracelet/glamour v0.9.1
-	github.com/charmbracelet/lipgloss v1.1.0
+	github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1
+	github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.3
+	github.com/charmbracelet/glamour v0.10.0
+	github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1
 	github.com/charmbracelet/x/ansi v0.8.0
 	github.com/lithammer/fuzzysearch v1.1.8
 	github.com/lrstanley/bubblezone v0.0.0-20250315020633-c249a3fe1231
@@ -28,6 +27,11 @@ require (
 	dario.cat/mergo v1.0.2 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
 	github.com/atombender/go-jsonschema v0.20.0 // indirect
+	github.com/charmbracelet/bubbletea v1.3.4 // indirect
+	github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect
+	github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect
+	github.com/charmbracelet/x/input v0.3.5-0.20250424101541-abb4d9a9b197 // indirect
+	github.com/charmbracelet/x/windows v0.2.1 // indirect
 	github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
 	github.com/fsnotify/fsnotify v1.8.0 // indirect
 	github.com/getkin/kin-openapi v0.127.0 // indirect
@@ -57,11 +61,11 @@ require (
 	github.com/atotto/clipboard v0.1.4
 	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
-	github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
-	github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
+	github.com/charmbracelet/colorprofile v0.3.1 // indirect
+	github.com/charmbracelet/x/cellbuf v0.0.14-0.20250501183327-ad3bc78c6a81 // indirect
 	github.com/charmbracelet/x/term v0.2.1 // indirect
 	github.com/disintegration/imaging v1.6.2
-	github.com/dlclark/regexp2 v1.11.4 // indirect
+	github.com/dlclark/regexp2 v1.11.5 // indirect
 	github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
 	github.com/google/go-cmp v0.7.0 // indirect
 	github.com/gorilla/css v1.0.1 // indirect

+ 26 - 18
packages/tui/go.sum

@@ -7,8 +7,8 @@ github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6
 github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
-github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
-github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
+github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4=
+github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
 github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
 github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
 github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
@@ -26,26 +26,34 @@ github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd3
 github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
 github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
 github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
-github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
-github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
-github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
-github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
+github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1 h1:swACzss0FjnyPz1enfX56GKkLiuKg5FlyVmOLIlU2kE=
+github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1/go.mod h1:6HamsBKWqEC/FVHuQMHgQL+knPyvHH55HwJDHl/adMw=
 github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
 github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
-github.com/charmbracelet/glamour v0.9.1 h1:11dEfiGP8q1BEqvGoIjivuc2rBk+5qEXdPtaQ2WoiCM=
-github.com/charmbracelet/glamour v0.9.1/go.mod h1:+SHvIS8qnwhgTpVMiXwn7OfGomSqff1cHBCI8jLOetk=
-github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
-github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
+github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.3 h1:5A2e3myxXMpCES+kjEWgGsaf9VgZXjZbLi5iMTH7j40=
+github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.3/go.mod h1:ZFDg5oPjyRYrPAa3iFrtP1DO8xy+LUQxd9JFHEcuwJY=
+github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40=
+github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0=
+github.com/charmbracelet/glamour v0.10.0 h1:MtZvfwsYCx8jEPFJm3rIBFIMZUfUJ765oX8V6kXldcY=
+github.com/charmbracelet/glamour v0.10.0/go.mod h1:f+uf+I/ChNmqo087elLnVdCiVgjSKWuXa/l6NU2ndYk=
+github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 h1:ZR7e0ro+SZZiIZD7msJyA+NjkCNNavuiPBLgerbOziE=
+github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA=
+github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1 h1:SOylT6+BQzPHEjn15TIzawBPVD0QmhKXbcb3jY0ZIKU=
+github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1/go.mod h1:tRlx/Hu0lo/j9viunCN2H+Ze6JrmdjQlXUQvvArgaOc=
 github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
 github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
-github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
-github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
+github.com/charmbracelet/x/cellbuf v0.0.14-0.20250501183327-ad3bc78c6a81 h1:iGrflaL5jQW6crML+pZx/ulWAVZQR3CQoRGvFsr2Tyg=
+github.com/charmbracelet/x/cellbuf v0.0.14-0.20250501183327-ad3bc78c6a81/go.mod h1:poPFOXFTsJsnLbkV3H2KxAAXT7pdjxxLujLocWjkyzM=
+github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw=
+github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
+github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf h1:rLG0Yb6MQSDKdB52aGX55JT1oi0P0Kuaj7wi1bLUpnI=
+github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf/go.mod h1:B3UgsnsBZS/eX42BlaNiJkD1pPOUa+oF1IYC6Yd2CEU=
+github.com/charmbracelet/x/input v0.3.5-0.20250424101541-abb4d9a9b197 h1:fsWj8NF5njyMVzELc7++HsvRDvgz3VcgGAUgWBDWWWM=
+github.com/charmbracelet/x/input v0.3.5-0.20250424101541-abb4d9a9b197/go.mod h1:xseGeVftoP9rVI+/8WKYrJFH6ior6iERGvklwwHz5+s=
 github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
 github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
+github.com/charmbracelet/x/windows v0.2.1 h1:3x7vnbpQrjpuq/4L+I4gNsG5htYoCiA5oe9hLjAij5I=
+github.com/charmbracelet/x/windows v0.2.1/go.mod h1:ptZp16h40gDYqs5TSawSVW+yiLB13j4kSMA0lSCHL0M=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -56,8 +64,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
 github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
-github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
-github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
+github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
 github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w=
 github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q=

+ 1 - 1
packages/tui/internal/app/app.go

@@ -8,7 +8,7 @@ import (
 
 	"log/slog"
 
-	tea "github.com/charmbracelet/bubbletea"
+	tea "github.com/charmbracelet/bubbletea/v2"
 	"github.com/sst/opencode/internal/config"
 	"github.com/sst/opencode/internal/fileutil"
 	"github.com/sst/opencode/internal/state"

+ 28 - 33
packages/tui/internal/components/chat/editor.go

@@ -5,15 +5,13 @@ import (
 	"log/slog"
 	"os"
 	"os/exec"
-	"slices"
 	"strings"
-	"unicode"
 
-	"github.com/charmbracelet/bubbles/key"
-	"github.com/charmbracelet/bubbles/spinner"
-	"github.com/charmbracelet/bubbles/textarea"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	"github.com/charmbracelet/bubbles/v2/spinner"
+	"github.com/charmbracelet/bubbles/v2/textarea"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/components/dialog"
 	"github.com/sst/opencode/internal/image"
@@ -129,18 +127,18 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			m.attachments = nil
 			return m, nil
 		}
-		if m.deleteMode && len(msg.Runes) > 0 && unicode.IsDigit(msg.Runes[0]) {
-			num := int(msg.Runes[0] - '0')
-			m.deleteMode = false
-			if num < 10 && len(m.attachments) > num {
-				if num == 0 {
-					m.attachments = m.attachments[num+1:]
-				} else {
-					m.attachments = slices.Delete(m.attachments, num, num+1)
-				}
-				return m, nil
-			}
-		}
+		// if m.deleteMode && len(msg.Runes) > 0 && unicode.IsDigit(msg.Runes[0]) {
+		// 	num := int(msg.Runes[0] - '0')
+		// 	m.deleteMode = false
+		// 	if num < 10 && len(m.attachments) > num {
+		// 		if num == 0 {
+		// 			m.attachments = m.attachments[num+1:]
+		// 		} else {
+		// 			m.attachments = slices.Delete(m.attachments, num, num+1)
+		// 		}
+		// 		return m, nil
+		// 	}
+		// }
 		if key.Matches(msg, messageKeys.PageUp) || key.Matches(msg, messageKeys.PageDown) ||
 			key.Matches(msg, messageKeys.HalfPageUp) || key.Matches(msg, messageKeys.HalfPageDown) {
 			return m, nil
@@ -258,7 +256,7 @@ func (m *editorComponent) View() string {
 		m.textarea.View(),
 	)
 	textarea = styles.BaseStyle().
-		Width(m.width-2).
+		Width(m.width). // -2).
 		Border(lipgloss.NormalBorder(), true, true).
 		BorderForeground(t.Border()).
 		Render(textarea)
@@ -286,10 +284,7 @@ func (m *editorComponent) View() string {
 		info,
 	)
 
-	return styles.ForceReplaceBackgroundWithLipgloss(
-		content,
-		t.Background(),
-	)
+	return content
 }
 
 func (m *editorComponent) SetSize(width, height int) tea.Cmd {
@@ -414,14 +409,14 @@ func createTextArea(existing *textarea.Model) textarea.Model {
 	ta := textarea.New()
 	ta.Placeholder = "It's prompting time..."
 
-	ta.BlurredStyle.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor)
-	ta.BlurredStyle.CursorLine = styles.BaseStyle().Background(bgColor)
-	ta.BlurredStyle.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor)
-	ta.BlurredStyle.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor)
-	ta.FocusedStyle.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor)
-	ta.FocusedStyle.CursorLine = styles.BaseStyle().Background(bgColor)
-	ta.FocusedStyle.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor)
-	ta.FocusedStyle.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor)
+	ta.Styles.Blurred.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor)
+	ta.Styles.Blurred.CursorLine = styles.BaseStyle().Background(bgColor)
+	ta.Styles.Blurred.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor)
+	ta.Styles.Blurred.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor)
+	ta.Styles.Focused.Base = styles.BaseStyle().Background(bgColor).Foreground(textColor)
+	ta.Styles.Focused.CursorLine = styles.BaseStyle().Background(bgColor)
+	ta.Styles.Focused.Placeholder = styles.BaseStyle().Background(bgColor).Foreground(textMutedColor)
+	ta.Styles.Focused.Text = styles.BaseStyle().Background(bgColor).Foreground(textColor)
 
 	ta.Prompt = " "
 	ta.ShowLineNumbers = false
@@ -437,7 +432,7 @@ func createTextArea(existing *textarea.Model) textarea.Model {
 	return ta
 }
 
-func NewEditorComponent(app *app.App) tea.Model {
+func NewEditorComponent(app *app.App) layout.ModelWithView {
 	s := spinner.New(spinner.WithSpinner(spinner.Ellipsis), spinner.WithStyle(styles.Muted().Width(3)))
 	ta := createTextArea(nil)
 

+ 17 - 32
packages/tui/internal/components/chat/message.go

@@ -9,7 +9,8 @@ import (
 	"time"
 	"unicode"
 
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
+	"github.com/charmbracelet/lipgloss/v2/compat"
 	"github.com/charmbracelet/x/ansi"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/components/diff"
@@ -21,8 +22,8 @@ import (
 	"golang.org/x/text/language"
 )
 
-func toMarkdown(content string, width int) string {
-	r := styles.GetMarkdownRenderer(width)
+func toMarkdown(content string, width int, backgroundColor compat.AdaptiveColor) string {
+	r := styles.GetMarkdownRenderer(width, backgroundColor)
 	content = strings.ReplaceAll(content, app.Info.Path.Root+"/", "")
 	rendered, _ := r.Render(content)
 	lines := strings.Split(rendered, "\n")
@@ -50,7 +51,7 @@ func toMarkdown(content string, width int) string {
 
 type blockRenderer struct {
 	align         *lipgloss.Position
-	borderColor   *lipgloss.AdaptiveColor
+	borderColor   *compat.AdaptiveColor
 	fullWidth     bool
 	paddingTop    int
 	paddingBottom int
@@ -70,7 +71,7 @@ func WithAlign(align lipgloss.Position) renderingOption {
 	}
 }
 
-func WithBorderColor(color lipgloss.AdaptiveColor) renderingOption {
+func WithBorderColor(color compat.AdaptiveColor) renderingOption {
 	return func(c *blockRenderer) {
 		c.borderColor = &color
 	}
@@ -137,9 +138,8 @@ func renderContentBlock(content string, options ...renderingOption) string {
 			BorderLeftBackground(t.Background())
 	}
 
-	content = styles.ForceReplaceBackgroundWithLipgloss(content, t.BackgroundSubtle())
 	if renderer.fullWidth {
-		style = style.Width(layout.Current.Container.Width - 2)
+		style = style.Width(layout.Current.Container.Width)
 	}
 	content = style.Render(content)
 	if renderer.paddingTop > 0 {
@@ -152,13 +152,11 @@ func renderContentBlock(content string, options ...renderingOption) string {
 		layout.Current.Container.Width,
 		align,
 		content,
-		lipgloss.WithWhitespaceBackground(t.Background()),
 	)
 	content = lipgloss.PlaceHorizontal(
 		layout.Current.Viewport.Width,
 		lipgloss.Center,
 		content,
-		lipgloss.WithWhitespaceBackground(t.Background()),
 	)
 	return content
 }
@@ -181,9 +179,7 @@ func renderText(message client.MessageInfo, text string, author string) string {
 		// don't show the date if it's today
 		timestamp = timestamp[12:]
 	}
-	info := styles.BaseStyle().
-		Foreground(t.TextMuted()).
-		Render(fmt.Sprintf("%s (%s)", author, timestamp))
+	info := fmt.Sprintf("%s (%s)", author, timestamp)
 
 	align := lipgloss.Left
 	switch message.Role {
@@ -195,7 +191,7 @@ func renderText(message client.MessageInfo, text string, author string) string {
 
 	textWidth := lipgloss.Width(text)
 	markdownWidth := min(textWidth, width-padding-4) // -4 for the border and padding
-	content := toMarkdown(text, markdownWidth)
+	content := toMarkdown(text, markdownWidth, t.BackgroundSubtle())
 	content = lipgloss.JoinVertical(align, content, info)
 
 	switch message.Role {
@@ -313,7 +309,7 @@ func renderToolInvocation(
 				lipgloss.Center,
 				lipgloss.Center,
 				body,
-				lipgloss.WithWhitespaceBackground(t.Background()),
+				lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Background(t.Background())),
 			)
 		}
 	case "opencode_write":
@@ -328,7 +324,7 @@ func renderToolInvocation(
 			command := toolArgsMap["command"].(string)
 			stdout := metadata["stdout"].(string)
 			body = fmt.Sprintf("```console\n> %s\n%s```", command, stdout)
-			body = toMarkdown(body, innerWidth)
+			body = toMarkdown(body, innerWidth, t.BackgroundSubtle())
 			body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
 		}
 	case "opencode_webfetch":
@@ -336,7 +332,7 @@ func renderToolInvocation(
 		format := toolArgsMap["format"].(string)
 		body = truncateHeight(body, 10)
 		if format == "html" || format == "markdown" {
-			body = toMarkdown(body, innerWidth)
+			body = toMarkdown(body, innerWidth, t.BackgroundSubtle())
 		}
 		body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
 	case "opencode_todowrite":
@@ -356,7 +352,7 @@ func renderToolInvocation(
 					body += fmt.Sprintf("- [ ] %s\n", content)
 				}
 			}
-			body = toMarkdown(body, innerWidth)
+			body = toMarkdown(body, innerWidth, t.BackgroundSubtle())
 			body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
 		}
 	default:
@@ -368,7 +364,7 @@ func renderToolInvocation(
 
 	content := style.Render(title)
 	content = lipgloss.PlaceHorizontal(layout.Current.Viewport.Width, lipgloss.Center, content)
-	content = styles.ForceReplaceBackgroundWithLipgloss(content, t.Background())
+	// content = styles.ForceReplaceBackgroundWithLipgloss(content, t.Background())
 	if showResult && body != "" {
 		content += "\n" + body
 	}
@@ -411,6 +407,7 @@ func WithTruncate(height int) fileRenderingOption {
 }
 
 func renderFile(filename string, content string, options ...fileRenderingOption) string {
+	t := theme.CurrentTheme()
 	renderer := &fileRenderer{
 		filename: filename,
 		content:  content,
@@ -419,7 +416,6 @@ func renderFile(filename string, content string, options ...fileRenderingOption)
 		option(renderer)
 	}
 
-	// TODO: is this even needed?
 	lines := []string{}
 	for line := range strings.SplitSeq(content, "\n") {
 		line = strings.TrimRightFunc(line, unicode.IsSpace)
@@ -428,23 +424,12 @@ func renderFile(filename string, content string, options ...fileRenderingOption)
 	}
 	content = strings.Join(lines, "\n")
 
-	width := layout.Current.Container.Width - 6
+	width := layout.Current.Container.Width - 8
 	if renderer.height > 0 {
 		content = truncateHeight(content, renderer.height)
 	}
 	content = fmt.Sprintf("```%s\n%s\n```", extension(renderer.filename), content)
-	content = toMarkdown(content, width)
-
-	// ensure no line is wider than the width
-	// truncated := []string{}
-	// for line := range strings.SplitSeq(content, "\n") {
-	// 	line = strings.TrimRightFunc(line, unicode.IsSpace)
-	// 	// if lipgloss.Width(line) > width-3 {
-	// 	line = ansi.Truncate(line, width-3, "")
-	// 	// }
-	// 	truncated = append(truncated, line)
-	// }
-	// content = strings.Join(truncated, "\n")
+	content = toMarkdown(content, width, t.BackgroundSubtle())
 
 	return renderContentBlock(content, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
 }

+ 24 - 92
packages/tui/internal/components/chat/messages.go

@@ -4,11 +4,11 @@ import (
 	"strings"
 	"time"
 
-	"github.com/charmbracelet/bubbles/key"
-	"github.com/charmbracelet/bubbles/spinner"
-	"github.com/charmbracelet/bubbles/viewport"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	"github.com/charmbracelet/bubbles/v2/spinner"
+	"github.com/charmbracelet/bubbles/v2/viewport"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/components/dialog"
 	"github.com/sst/opencode/internal/layout"
@@ -220,11 +220,11 @@ func (m *messagesComponent) renderView() {
 			m.width,
 			lipgloss.Center,
 			block,
-			lipgloss.WithWhitespaceBackground(t.Background()),
+			lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Background(t.Background())),
 		))
 	}
 
-	m.viewport.Height = m.height - lipgloss.Height(m.header())
+	m.viewport.SetHeight(m.height - lipgloss.Height(m.header()))
 	m.viewport.SetContent(strings.Join(centered, "\n"))
 }
 
@@ -238,7 +238,7 @@ func (m *messagesComponent) header() string {
 	base := styles.BaseStyle().Render
 	muted := styles.Muted().Render
 	headerLines := []string{}
-	headerLines = append(headerLines, toMarkdown("# "+m.app.Session.Title, width))
+	headerLines = append(headerLines, toMarkdown("# "+m.app.Session.Title, width, t.Background()))
 	if m.app.Session.Share != nil && m.app.Session.Share.Url != "" {
 		headerLines = append(headerLines, muted(m.app.Session.Share.Url))
 	} else {
@@ -255,7 +255,7 @@ func (m *messagesComponent) header() string {
 		Background(t.Background()).
 		Render(header)
 
-	return styles.ForceReplaceBackgroundWithLipgloss(header, t.Background())
+	return header
 }
 
 func (m *messagesComponent) View() string {
@@ -269,73 +269,8 @@ func (m *messagesComponent) View() string {
 	)
 }
 
-// func hasToolsWithoutResponse(messages []message.Message) bool {
-// 	toolCalls := make([]message.ToolCall, 0)
-// 	toolResults := make([]message.ToolResult, 0)
-// 	for _, m := range messages {
-// 		toolCalls = append(toolCalls, m.ToolCalls()...)
-// 		toolResults = append(toolResults, m.ToolResults()...)
-// 	}
-//
-// 	for _, v := range toolCalls {
-// 		found := false
-// 		for _, r := range toolResults {
-// 			if v.ID == r.ToolCallID {
-// 				found = true
-// 				break
-// 			}
-// 		}
-// 		if !found && v.Finished {
-// 			return true
-// 		}
-// 	}
-// 	return false
-// }
-
-// func hasUnfinishedToolCalls(messages []message.Message) bool {
-// 	toolCalls := make([]message.ToolCall, 0)
-// 	for _, m := range messages {
-// 		toolCalls = append(toolCalls, m.ToolCalls()...)
-// 	}
-// 	for _, v := range toolCalls {
-// 		if !v.Finished {
-// 			return true
-// 		}
-// 	}
-// 	return false
-// }
-
-func (m *messagesComponent) help() string {
-	t := theme.CurrentTheme()
-	baseStyle := styles.BaseStyle()
-
-	text := ""
-
-	if m.app.IsBusy() {
-		text += lipgloss.JoinHorizontal(
-			lipgloss.Left,
-			baseStyle.Foreground(t.TextMuted()).Bold(true).Render("press "),
-			baseStyle.Foreground(t.Text()).Bold(true).Render("esc"),
-			baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to interrupt"),
-		)
-	} else {
-		text += lipgloss.JoinHorizontal(
-			lipgloss.Left,
-			baseStyle.Foreground(t.Text()).Bold(true).Render("enter"),
-			baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to send,"),
-			baseStyle.Foreground(t.Text()).Bold(true).Render(" \\"),
-			baseStyle.Foreground(t.TextMuted()).Bold(true).Render("+"),
-			baseStyle.Foreground(t.Text()).Bold(true).Render("enter"),
-			baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" for newline"),
-		)
-	}
-	return baseStyle.
-		Width(m.width).
-		Render(text)
-}
-
 func (m *messagesComponent) home() string {
-	t := theme.CurrentTheme()
+	// t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	base := baseStyle.Render
 	muted := styles.Muted().Render
@@ -398,16 +333,13 @@ func (m *messagesComponent) home() string {
 		lines = append(lines, "")
 	}
 
-	return styles.ForceReplaceBackgroundWithLipgloss(
-		lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center,
-			baseStyle.Width(lipgloss.Width(logoAndVersion)).Render(
-				lipgloss.JoinVertical(
-					lipgloss.Top,
-					lines...,
-				),
-			)),
-		t.Background(),
-	)
+	return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center,
+		baseStyle.Width(lipgloss.Width(logoAndVersion)).Render(
+			lipgloss.JoinVertical(
+				lipgloss.Top,
+				lines...,
+			),
+		))
 }
 
 func (m *messagesComponent) SetSize(width, height int) tea.Cmd {
@@ -420,10 +352,10 @@ func (m *messagesComponent) SetSize(width, height int) tea.Cmd {
 	}
 	m.width = width
 	m.height = height
-	m.viewport.Width = width
-	m.viewport.Height = height - lipgloss.Height(m.header())
-	m.attachments.Width = width + 40
-	m.attachments.Height = 3
+	m.viewport.SetWidth(width)
+	m.viewport.SetHeight(height - lipgloss.Height(m.header()))
+	m.attachments.SetWidth(width + 40)
+	m.attachments.SetHeight(3)
 	m.renderView()
 	return nil
 }
@@ -449,15 +381,15 @@ func (m *messagesComponent) BindingKeys() []key.Binding {
 	}
 }
 
-func NewMessagesComponent(app *app.App) tea.Model {
+func NewMessagesComponent(app *app.App) layout.ModelWithView {
 	customSpinner := spinner.Spinner{
 		Frames: []string{" ", "┃", "┃"},
 		FPS:    time.Second / 3,
 	}
 	s := spinner.New(spinner.WithSpinner(customSpinner))
 
-	vp := viewport.New(0, 0)
-	attachments := viewport.New(0, 0)
+	vp := viewport.New()          //(0, 0)
+	attachments := viewport.New() //(0, 0)
 	vp.KeyMap.PageUp = messageKeys.PageUp
 	vp.KeyMap.PageDown = messageKeys.PageDown
 	vp.KeyMap.HalfPageUp = messageKeys.HalfPageUp

+ 15 - 114
packages/tui/internal/components/core/status.go

@@ -5,20 +5,21 @@ import (
 	"strings"
 	"time"
 
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/app"
+	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/pubsub"
 	"github.com/sst/opencode/internal/status"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
 )
 
-type StatusCmp interface {
-	tea.Model
+type StatusComponent interface {
+	layout.ModelWithView
 }
 
-type statusCmp struct {
+type statusComponent struct {
 	app         *app.App
 	queue       []status.StatusMessage
 	width       int
@@ -27,7 +28,7 @@ type statusCmp struct {
 }
 
 // clearMessageCmd is a command that clears status messages after a timeout
-func (m statusCmp) clearMessageCmd() tea.Cmd {
+func (m statusComponent) clearMessageCmd() tea.Cmd {
 	return tea.Tick(time.Second, func(t time.Time) tea.Msg {
 		return statusCleanupMsg{time: t}
 	})
@@ -38,11 +39,11 @@ type statusCleanupMsg struct {
 	time time.Time
 }
 
-func (m statusCmp) Init() tea.Cmd {
+func (m statusComponent) Init() tea.Cmd {
 	return m.clearMessageCmd()
 }
 
-func (m statusCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (m statusComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.WindowSizeMsg:
 		m.width = msg.Width
@@ -104,10 +105,9 @@ func logo() string {
 	open := styles.Muted().Render("open")
 	code := styles.BaseStyle().Bold(true).Render("code")
 	version := styles.Muted().Render(app.Info.Version)
-	return styles.ForceReplaceBackgroundWithLipgloss(
-		styles.Padded().Render(mark+open+code+" "+version),
-		t.BackgroundElement(),
-	)
+	return styles.Padded().
+		Background(t.BackgroundElement()).
+		Render(mark + open + code + " " + version)
 }
 
 func formatTokensAndCost(tokens float32, contextWindow float32, cost float32) string {
@@ -137,7 +137,7 @@ func formatTokensAndCost(tokens float32, contextWindow float32, cost float32) st
 	return fmt.Sprintf("Tokens: %s (%d%%), Cost: %s", formattedTokens, int(percentage), formattedCost)
 }
 
-func (m statusCmp) View() string {
+func (m statusComponent) View() string {
 	if m.app.Session.Id == "" {
 		return styles.BaseStyle().
 			Width(m.width).
@@ -250,107 +250,8 @@ func (m statusCmp) View() string {
 	// }
 }
 
-func (m *statusCmp) projectDiagnostics() string {
-	t := theme.CurrentTheme()
-
-	// Check if any LSP server is still initializing
-	initializing := false
-	// for _, client := range m.app.LSPClients {
-	// 	if client.GetServerState() == lsp.StateStarting {
-	// 		initializing = true
-	// 		break
-	// 	}
-	// }
-
-	// If any server is initializing, show that status
-	if initializing {
-		return lipgloss.NewStyle().
-			Foreground(t.Warning()).
-			Render(fmt.Sprintf("%s Initializing LSP...", styles.SpinnerIcon))
-	}
-
-	// errorDiagnostics := []protocol.Diagnostic{}
-	// warnDiagnostics := []protocol.Diagnostic{}
-	// hintDiagnostics := []protocol.Diagnostic{}
-	// infoDiagnostics := []protocol.Diagnostic{}
-	// for _, client := range m.app.LSPClients {
-	// 	for _, d := range client.GetDiagnostics() {
-	// 		for _, diag := range d {
-	// 			switch diag.Severity {
-	// 			case protocol.SeverityError:
-	// 				errorDiagnostics = append(errorDiagnostics, diag)
-	// 			case protocol.SeverityWarning:
-	// 				warnDiagnostics = append(warnDiagnostics, diag)
-	// 			case protocol.SeverityHint:
-	// 				hintDiagnostics = append(hintDiagnostics, diag)
-	// 			case protocol.SeverityInformation:
-	// 				infoDiagnostics = append(infoDiagnostics, diag)
-	// 			}
-	// 		}
-	// 	}
-	// }
-	return styles.ForceReplaceBackgroundWithLipgloss(
-		styles.Padded().Render("No diagnostics"),
-		t.BackgroundElement(),
-	)
-
-	// if len(errorDiagnostics) == 0 &&
-	// 	len(warnDiagnostics) == 0 &&
-	// 	len(infoDiagnostics) == 0 &&
-	// 	len(hintDiagnostics) == 0 {
-	// 	return styles.ForceReplaceBackgroundWithLipgloss(
-	// 		styles.Padded().Render("No diagnostics"),
-	// 		t.BackgroundDarker(),
-	// 	)
-	// }
-
-	// diagnostics := []string{}
-	//
-	// errStr := lipgloss.NewStyle().
-	// 	Background(t.BackgroundDarker()).
-	// 	Foreground(t.Error()).
-	// 	Render(fmt.Sprintf("%s %d", styles.ErrorIcon, len(errorDiagnostics)))
-	// diagnostics = append(diagnostics, errStr)
-	//
-	// warnStr := lipgloss.NewStyle().
-	// 	Background(t.BackgroundDarker()).
-	// 	Foreground(t.Warning()).
-	// 	Render(fmt.Sprintf("%s %d", styles.WarningIcon, len(warnDiagnostics)))
-	// diagnostics = append(diagnostics, warnStr)
-	//
-	// infoStr := lipgloss.NewStyle().
-	// 	Background(t.BackgroundDarker()).
-	// 	Foreground(t.Info()).
-	// 	Render(fmt.Sprintf("%s %d", styles.InfoIcon, len(infoDiagnostics)))
-	// diagnostics = append(diagnostics, infoStr)
-	//
-	// hintStr := lipgloss.NewStyle().
-	// 	Background(t.BackgroundDarker()).
-	// 	Foreground(t.Text()).
-	// 	Render(fmt.Sprintf("%s %d", styles.HintIcon, len(hintDiagnostics)))
-	// diagnostics = append(diagnostics, hintStr)
-	//
-	// return styles.ForceReplaceBackgroundWithLipgloss(
-	// 	styles.Padded().Render(strings.Join(diagnostics, " ")),
-	// 	t.BackgroundDarker(),
-	// )
-}
-
-func (m statusCmp) model() string {
-	t := theme.CurrentTheme()
-	model := "None"
-	if m.app.Model != nil {
-		model = *m.app.Model.Name
-	}
-
-	return styles.Padded().
-		Background(t.Secondary()).
-		Foreground(t.Background()).
-		Render(model)
-}
-
-func NewStatusCmp(app *app.App) StatusCmp {
-	statusComponent := &statusCmp{
+func NewStatusCmp(app *app.App) StatusComponent {
+	statusComponent := &statusComponent{
 		app:         app,
 		queue:       []status.StatusMessage{},
 		messageTTL:  4 * time.Second,

+ 24 - 17
packages/tui/internal/components/dialog/arguments.go

@@ -2,10 +2,10 @@ package dialog
 
 import (
 	"fmt"
-	"github.com/charmbracelet/bubbles/key"
-	"github.com/charmbracelet/bubbles/textinput"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	"github.com/charmbracelet/bubbles/v2/textinput"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
@@ -70,17 +70,24 @@ func NewMultiArgumentsDialogCmp(commandID, content string, argNames []string) Mu
 	for i, name := range argNames {
 		ti := textinput.New()
 		ti.Placeholder = fmt.Sprintf("Enter value for %s...", name)
-		ti.Width = 40
+		ti.SetWidth(40)
 		ti.Prompt = ""
-		ti.PlaceholderStyle = ti.PlaceholderStyle.Background(t.Background())
-		ti.PromptStyle = ti.PromptStyle.Background(t.Background())
-		ti.TextStyle = ti.TextStyle.Background(t.Background())
+		ti.Styles.Blurred.Placeholder = ti.Styles.Blurred.Placeholder.Background(t.Background())
+		ti.Styles.Blurred.Text = ti.Styles.Blurred.Text.Background(t.Background())
+		ti.Styles.Blurred.Prompt = ti.Styles.Blurred.Prompt.Foreground(t.Primary())
+
+		ti.Styles.Focused.Placeholder = ti.Styles.Focused.Placeholder.Background(t.Background())
+		ti.Styles.Focused.Text = ti.Styles.Focused.Text.Background(t.Background())
+		ti.Styles.Focused.Prompt = ti.Styles.Focused.Prompt.Foreground(t.Primary())
+
+		// ti.PromptStyle = ti.PromptStyle.Background(t.Background())
+		// ti.TextStyle = ti.TextStyle.Background(t.Background())
 
 		// Only focus the first input initially
 		if i == 0 {
 			ti.Focus()
-			ti.PromptStyle = ti.PromptStyle.Foreground(t.Primary())
-			ti.TextStyle = ti.TextStyle.Foreground(t.Primary())
+			// ti.PromptStyle = ti.PromptStyle.Foreground(t.Primary())
+			// ti.TextStyle = ti.TextStyle.Foreground(t.Primary())
 		} else {
 			ti.Blur()
 		}
@@ -115,7 +122,7 @@ func (m MultiArgumentsDialogCmp) Init() tea.Cmd {
 // Update implements tea.Model.
 func (m MultiArgumentsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	var cmds []tea.Cmd
-	t := theme.CurrentTheme()
+	// t := theme.CurrentTheme()
 
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
@@ -145,22 +152,22 @@ func (m MultiArgumentsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			m.inputs[m.focusIndex].Blur()
 			m.focusIndex++
 			m.inputs[m.focusIndex].Focus()
-			m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary())
-			m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary())
+			// m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary())
+			// m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary())
 		case key.Matches(msg, key.NewBinding(key.WithKeys("tab"))):
 			// Move to the next input
 			m.inputs[m.focusIndex].Blur()
 			m.focusIndex = (m.focusIndex + 1) % len(m.inputs)
 			m.inputs[m.focusIndex].Focus()
-			m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary())
-			m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary())
+			// m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary())
+			// m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary())
 		case key.Matches(msg, key.NewBinding(key.WithKeys("shift+tab"))):
 			// Move to the previous input
 			m.inputs[m.focusIndex].Blur()
 			m.focusIndex = (m.focusIndex - 1 + len(m.inputs)) % len(m.inputs)
 			m.inputs[m.focusIndex].Focus()
-			m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary())
-			m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary())
+			// m.inputs[m.focusIndex].PromptStyle = m.inputs[m.focusIndex].PromptStyle.Foreground(t.Primary())
+			// m.inputs[m.focusIndex].TextStyle = m.inputs[m.focusIndex].TextStyle.Foreground(t.Primary())
 		}
 	case tea.WindowSizeMsg:
 		m.width = msg.Width

+ 11 - 11
packages/tui/internal/components/dialog/commands.go

@@ -1,9 +1,9 @@
 package dialog
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	utilComponents "github.com/sst/opencode/internal/components/util"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
@@ -56,12 +56,12 @@ type CloseCommandDialogMsg struct{}
 
 // CommandDialog interface for the command selection dialog
 type CommandDialog interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 	SetCommands(commands []Command)
 }
 
-type commandDialogCmp struct {
+type commandDialogComponent struct {
 	listView utilComponents.SimpleList[Command]
 	width    int
 	height   int
@@ -83,11 +83,11 @@ var commandKeys = commandKeyMap{
 	),
 }
 
-func (c *commandDialogCmp) Init() tea.Cmd {
+func (c *commandDialogComponent) Init() tea.Cmd {
 	return c.listView.Init()
 }
 
-func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (c *commandDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	var cmds []tea.Cmd
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
@@ -114,7 +114,7 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return c, tea.Batch(cmds...)
 }
 
-func (c *commandDialogCmp) View() string {
+func (c *commandDialogComponent) View() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -158,11 +158,11 @@ func (c *commandDialogCmp) View() string {
 		Render(content)
 }
 
-func (c *commandDialogCmp) BindingKeys() []key.Binding {
+func (c *commandDialogComponent) BindingKeys() []key.Binding {
 	return layout.KeyMapToSlice(commandKeys)
 }
 
-func (c *commandDialogCmp) SetCommands(commands []Command) {
+func (c *commandDialogComponent) SetCommands(commands []Command) {
 	c.listView.SetItems(commands)
 }
 
@@ -174,7 +174,7 @@ func NewCommandDialogCmp() CommandDialog {
 		"No commands available",
 		true,
 	)
-	return &commandDialogCmp{
+	return &commandDialogComponent{
 		listView: listView,
 	}
 }

+ 6 - 6
packages/tui/internal/components/dialog/complete.go

@@ -1,13 +1,13 @@
 package dialog
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	"github.com/charmbracelet/bubbles/textarea"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
-	"github.com/sst/opencode/internal/status"
+	"github.com/charmbracelet/bubbles/v2/key"
+	"github.com/charmbracelet/bubbles/v2/textarea"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	utilComponents "github.com/sst/opencode/internal/components/util"
 	"github.com/sst/opencode/internal/layout"
+	"github.com/sst/opencode/internal/status"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
 	"github.com/sst/opencode/internal/util"
@@ -77,7 +77,7 @@ type CompletionDialogCompleteItemMsg struct {
 type CompletionDialogCloseMsg struct{}
 
 type CompletionDialog interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 	SetWidth(width int)
 }

+ 1 - 1
packages/tui/internal/components/dialog/custom_commands.go

@@ -7,7 +7,7 @@ import (
 	"regexp"
 	"strings"
 
-	tea "github.com/charmbracelet/bubbletea"
+	tea "github.com/charmbracelet/bubbletea/v2"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/util"
 )

+ 25 - 24
packages/tui/internal/components/dialog/filepicker.go

@@ -12,13 +12,14 @@ import (
 	"log/slog"
 
 	"github.com/atotto/clipboard"
-	"github.com/charmbracelet/bubbles/key"
-	"github.com/charmbracelet/bubbles/textinput"
-	"github.com/charmbracelet/bubbles/viewport"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	"github.com/charmbracelet/bubbles/v2/textinput"
+	"github.com/charmbracelet/bubbles/v2/viewport"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/image"
+	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/status"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
@@ -82,7 +83,7 @@ var filePickerKeyMap = FilePrickerKeyMap{
 	),
 }
 
-type filepickerCmp struct {
+type filepickerComponent struct {
 	basePath       string
 	width          int
 	height         int
@@ -118,18 +119,18 @@ type AttachmentAddedMsg struct {
 	Attachment app.Attachment
 }
 
-func (f *filepickerCmp) Init() tea.Cmd {
+func (f *filepickerComponent) Init() tea.Cmd {
 	return nil
 }
 
-func (f *filepickerCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (f *filepickerComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	var cmd tea.Cmd
 	switch msg := msg.(type) {
 	case tea.WindowSizeMsg:
 		f.width = 60
 		f.height = 20
-		f.viewport.Width = 80
-		f.viewport.Height = 22
+		f.viewport.SetWidth(80)
+		f.viewport.SetHeight(22)
 		f.cursor = 0
 		f.getCurrentFileBelowCursor()
 	case tea.KeyMsg:
@@ -236,7 +237,7 @@ func (f *filepickerCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return f, cmd
 }
 
-func (f *filepickerCmp) addAttachmentToMessage() (tea.Model, tea.Cmd) {
+func (f *filepickerComponent) addAttachmentToMessage() (tea.Model, tea.Cmd) {
 	// modeInfo := GetSelectedModel(config.Get())
 	// if !modeInfo.SupportsAttachments {
 	// 	status.Error(fmt.Sprintf("Model %s doesn't support attachments", modeInfo.Name))
@@ -273,7 +274,7 @@ func (f *filepickerCmp) addAttachmentToMessage() (tea.Model, tea.Cmd) {
 	return f, util.CmdHandler(AttachmentAddedMsg{attachment})
 }
 
-func (f *filepickerCmp) View() string {
+func (f *filepickerComponent) View() string {
 	t := theme.CurrentTheme()
 	const maxVisibleDirs = 20
 	const maxWidth = 80
@@ -333,7 +334,7 @@ func (f *filepickerCmp) View() string {
 		Render(f.cwd.View())
 
 	viewportstyle := lipgloss.NewStyle().
-		Width(f.viewport.Width).
+		Width(f.viewport.Width()).
 		Background(t.Background()).
 		Border(lipgloss.RoundedBorder()).
 		BorderForeground(t.TextMuted()).
@@ -366,21 +367,21 @@ func (f *filepickerCmp) View() string {
 	return lipgloss.JoinHorizontal(lipgloss.Center, contentStyle.Render(content), viewportstyle)
 }
 
-type FilepickerCmp interface {
-	tea.Model
+type FilepickerComponent interface {
+	layout.ModelWithView
 	ToggleFilepicker(showFilepicker bool)
 	IsCWDFocused() bool
 }
 
-func (f *filepickerCmp) ToggleFilepicker(showFilepicker bool) {
+func (f *filepickerComponent) ToggleFilepicker(showFilepicker bool) {
 	f.ShowFilePicker = showFilepicker
 }
 
-func (f *filepickerCmp) IsCWDFocused() bool {
+func (f *filepickerComponent) IsCWDFocused() bool {
 	return f.cwd.Focused()
 }
 
-func NewFilepickerCmp(app *app.App) FilepickerCmp {
+func NewFilepickerCmp(app *app.App) FilepickerComponent {
 	homepath, err := os.UserHomeDir()
 	if err != nil {
 		slog.Error("error loading user files")
@@ -388,16 +389,16 @@ func NewFilepickerCmp(app *app.App) FilepickerCmp {
 	}
 	baseDir := DirNode{parent: nil, directory: homepath}
 	dirs := readDir(homepath, false)
-	viewport := viewport.New(0, 0)
+	viewport := viewport.New() // viewport.New(0, 0)
 	currentDirectory := textinput.New()
 	currentDirectory.CharLimit = 200
-	currentDirectory.Width = 44
-	currentDirectory.Cursor.Blink = true
+	currentDirectory.SetWidth(44)
+	// currentDirectory.Cursor.Blink = true
 	currentDirectory.SetValue(baseDir.directory)
-	return &filepickerCmp{cwdDetails: &baseDir, dirs: dirs, cursorChain: make(stack, 0), viewport: viewport, cwd: currentDirectory, app: app}
+	return &filepickerComponent{cwdDetails: &baseDir, dirs: dirs, cursorChain: make(stack, 0), viewport: viewport, cwd: currentDirectory, app: app}
 }
 
-func (f *filepickerCmp) getCurrentFileBelowCursor() {
+func (f *filepickerComponent) getCurrentFileBelowCursor() {
 	if len(f.dirs) == 0 || f.cursor < 0 || f.cursor >= len(f.dirs) {
 		slog.Error(fmt.Sprintf("Invalid cursor position. Dirs length: %d, Cursor: %d", len(f.dirs), f.cursor))
 		f.viewport.SetContent("Preview unavailable")
@@ -410,7 +411,7 @@ func (f *filepickerCmp) getCurrentFileBelowCursor() {
 		fullPath := f.cwdDetails.directory + "/" + dir.Name()
 
 		go func() {
-			imageString, err := image.ImagePreview(f.viewport.Width-4, fullPath)
+			imageString, err := image.ImagePreview(f.viewport.Width()-4, fullPath)
 			if err != nil {
 				slog.Error(err.Error())
 				f.viewport.SetContent("Preview unavailable")

+ 16 - 15
packages/tui/internal/components/dialog/help.go

@@ -3,28 +3,29 @@ package dialog
 import (
 	"strings"
 
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
+	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
 )
 
-type helpCmp struct {
+type helpComponent struct {
 	width  int
 	height int
 	keys   []key.Binding
 }
 
-func (h *helpCmp) Init() tea.Cmd {
+func (h *helpComponent) Init() tea.Cmd {
 	return nil
 }
 
-func (h *helpCmp) SetBindings(k []key.Binding) {
+func (h *helpComponent) SetBindings(k []key.Binding) {
 	h.keys = k
 }
 
-func (h *helpCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (h *helpComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.WindowSizeMsg:
 		h.width = 90
@@ -53,7 +54,7 @@ func removeDuplicateBindings(bindings []key.Binding) []key.Binding {
 	return result
 }
 
-func (h *helpCmp) render() string {
+func (h *helpComponent) render() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -134,7 +135,7 @@ func (h *helpCmp) render() string {
 		pairs = append(pairs, pair)
 	}
 
-	// https://github.com/charmbracelet/lipgloss/issues/209
+	// https://github.com/charmbracelet/lipgloss/v2/issues/209
 	if len(pairs) > 1 {
 		prefix := pairs[:len(pairs)-1]
 		lastPair := pairs[len(pairs)-1]
@@ -144,7 +145,7 @@ func (h *helpCmp) render() string {
 			lipgloss.Left,              // x
 			lipgloss.Top,               // y
 			lastPair,                   // content
-			lipgloss.WithWhitespaceBackground(t.Background()),
+			// lipgloss.WithWhitespaceBackground(t.Background()),
 		))
 		content := baseStyle.Width(h.width).Render(
 			lipgloss.JoinHorizontal(
@@ -165,7 +166,7 @@ func (h *helpCmp) render() string {
 	return content
 }
 
-func (h *helpCmp) View() string {
+func (h *helpComponent) View() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -190,11 +191,11 @@ func (h *helpCmp) View() string {
 		)
 }
 
-type HelpCmp interface {
-	tea.Model
+type HelpComponent interface {
+	layout.ModelWithView
 	SetBindings([]key.Binding)
 }
 
-func NewHelpCmp() HelpCmp {
-	return &helpCmp{}
+func NewHelpCmp() HelpComponent {
+	return &helpComponent{}
 }

+ 3 - 3
packages/tui/internal/components/dialog/init.go

@@ -1,9 +1,9 @@
 package dialog
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"

+ 17 - 17
packages/tui/internal/components/dialog/models.go

@@ -7,9 +7,9 @@ import (
 	"slices"
 	"strings"
 
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
@@ -31,13 +31,13 @@ type CloseModelDialogMsg struct {
 
 // ModelDialog interface for the model selection dialog
 type ModelDialog interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 
 	SetProviders(providers []client.ProviderInfo)
 }
 
-type modelDialogCmp struct {
+type modelDialogComponent struct {
 	app                *app.App
 	availableProviders []client.ProviderInfo
 	provider           client.ProviderInfo
@@ -106,7 +106,7 @@ var modelKeys = modelKeyMap{
 	),
 }
 
-func (m *modelDialogCmp) Init() tea.Cmd {
+func (m *modelDialogComponent) Init() tea.Cmd {
 	// cfg := config.Get()
 	// modelInfo := GetSelectedModel(cfg)
 	// m.availableProviders = getEnabledProviders(cfg)
@@ -125,11 +125,11 @@ func (m *modelDialogCmp) Init() tea.Cmd {
 	return nil
 }
 
-func (m *modelDialogCmp) SetProviders(providers []client.ProviderInfo) {
+func (m *modelDialogComponent) SetProviders(providers []client.ProviderInfo) {
 	m.availableProviders = providers
 }
 
-func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (m *modelDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
 		switch {
@@ -159,7 +159,7 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return m, nil
 }
 
-func (m *modelDialogCmp) models() []client.ProviderModel {
+func (m *modelDialogComponent) models() []client.ProviderModel {
 	models := slices.SortedFunc(maps.Values(m.provider.Models), func(a, b client.ProviderModel) int {
 		return strings.Compare(*a.Name, *b.Name)
 	})
@@ -167,7 +167,7 @@ func (m *modelDialogCmp) models() []client.ProviderModel {
 }
 
 // moveSelectionUp moves the selection up or wraps to bottom
-func (m *modelDialogCmp) moveSelectionUp() {
+func (m *modelDialogComponent) moveSelectionUp() {
 	if m.selectedIdx > 0 {
 		m.selectedIdx--
 	} else {
@@ -182,7 +182,7 @@ func (m *modelDialogCmp) moveSelectionUp() {
 }
 
 // moveSelectionDown moves the selection down or wraps to top
-func (m *modelDialogCmp) moveSelectionDown() {
+func (m *modelDialogComponent) moveSelectionDown() {
 	if m.selectedIdx < len(m.provider.Models)-1 {
 		m.selectedIdx++
 	} else {
@@ -196,7 +196,7 @@ func (m *modelDialogCmp) moveSelectionDown() {
 	}
 }
 
-func (m *modelDialogCmp) switchProvider(offset int) {
+func (m *modelDialogComponent) switchProvider(offset int) {
 	newOffset := m.hScrollOffset + offset
 
 	// Ensure we stay within bounds
@@ -212,7 +212,7 @@ func (m *modelDialogCmp) switchProvider(offset int) {
 	m.setupModelsForProvider(m.provider.Id)
 }
 
-func (m *modelDialogCmp) View() string {
+func (m *modelDialogComponent) View() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -255,7 +255,7 @@ func (m *modelDialogCmp) View() string {
 		Render(content)
 }
 
-func (m *modelDialogCmp) getScrollIndicators(maxWidth int) string {
+func (m *modelDialogComponent) getScrollIndicators(maxWidth int) string {
 	var indicator string
 
 	if len(m.provider.Models) > numVisibleModels {
@@ -291,7 +291,7 @@ func (m *modelDialogCmp) getScrollIndicators(maxWidth int) string {
 		Render(indicator)
 }
 
-func (m *modelDialogCmp) BindingKeys() []key.Binding {
+func (m *modelDialogComponent) BindingKeys() []key.Binding {
 	return layout.KeyMapToSlice(modelKeys)
 }
 
@@ -305,7 +305,7 @@ func (m *modelDialogCmp) BindingKeys() []key.Binding {
 // 	return -1
 // }
 
-func (m *modelDialogCmp) setupModelsForProvider(_ string) {
+func (m *modelDialogComponent) setupModelsForProvider(_ string) {
 	m.selectedIdx = 0
 	m.scrollOffset = 0
 
@@ -332,7 +332,7 @@ func (m *modelDialogCmp) setupModelsForProvider(_ string) {
 }
 
 func NewModelDialogCmp(app *app.App) ModelDialog {
-	return &modelDialogCmp{
+	return &modelDialogComponent{
 		app: app,
 	}
 }

+ 30 - 30
packages/tui/internal/components/dialog/permission.go

@@ -2,10 +2,10 @@ package dialog
 
 import (
 	"fmt"
-	"github.com/charmbracelet/bubbles/key"
-	"github.com/charmbracelet/bubbles/viewport"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	"github.com/charmbracelet/bubbles/v2/viewport"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
@@ -28,9 +28,9 @@ type PermissionResponseMsg struct {
 	Action PermissionAction
 }
 
-// PermissionDialogCmp interface for permission dialog component
-type PermissionDialogCmp interface {
-	tea.Model
+// PermissionDialogComponent interface for permission dialog component
+type PermissionDialogComponent interface {
+	layout.ModelWithView
 	layout.Bindings
 	// SetPermissions(permission permission.PermissionRequest) tea.Cmd
 }
@@ -76,8 +76,8 @@ var permissionsKeys = permissionsMapping{
 	),
 }
 
-// permissionDialogCmp is the implementation of PermissionDialog
-type permissionDialogCmp struct {
+// permissionDialogComponent is the implementation of PermissionDialog
+type permissionDialogComponent struct {
 	width  int
 	height int
 	// permission      permission.PermissionRequest
@@ -89,11 +89,11 @@ type permissionDialogCmp struct {
 	markdownCache map[string]string
 }
 
-func (p *permissionDialogCmp) Init() tea.Cmd {
+func (p *permissionDialogComponent) Init() tea.Cmd {
 	return p.contentViewPort.Init()
 }
 
-func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (p *permissionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	var cmds []tea.Cmd
 
 	switch msg := msg.(type) {
@@ -129,7 +129,7 @@ func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return p, tea.Batch(cmds...)
 }
 
-func (p *permissionDialogCmp) selectCurrentOption() tea.Cmd {
+func (p *permissionDialogComponent) selectCurrentOption() tea.Cmd {
 	var action PermissionAction
 
 	switch p.selectedOption {
@@ -144,7 +144,7 @@ func (p *permissionDialogCmp) selectCurrentOption() tea.Cmd {
 	return util.CmdHandler(PermissionResponseMsg{Action: action}) // , Permission: p.permission})
 }
 
-func (p *permissionDialogCmp) renderButtons() string {
+func (p *permissionDialogComponent) renderButtons() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -190,7 +190,7 @@ func (p *permissionDialogCmp) renderButtons() string {
 	return content
 }
 
-func (p *permissionDialogCmp) renderHeader() string {
+func (p *permissionDialogComponent) renderHeader() string {
 	return "NOT IMPLEMENTED"
 	// t := theme.CurrentTheme()
 	// baseStyle := styles.BaseStyle()
@@ -246,7 +246,7 @@ func (p *permissionDialogCmp) renderHeader() string {
 	// return lipgloss.NewStyle().Background(t.Background()).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...))
 }
 
-func (p *permissionDialogCmp) renderBashContent() string {
+func (p *permissionDialogComponent) renderBashContent() string {
 	// t := theme.CurrentTheme()
 	// baseStyle := styles.BaseStyle()
 	//
@@ -269,7 +269,7 @@ func (p *permissionDialogCmp) renderBashContent() string {
 	return ""
 }
 
-func (p *permissionDialogCmp) renderEditContent() string {
+func (p *permissionDialogComponent) renderEditContent() string {
 	// if pr, ok := p.permission.Params.(tools.EditPermissionsParams); ok {
 	// 	diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) {
 	// 		return diff.FormatDiff(pr.Diff, diff.WithTotalWidth(p.contentViewPort.Width))
@@ -281,7 +281,7 @@ func (p *permissionDialogCmp) renderEditContent() string {
 	return ""
 }
 
-func (p *permissionDialogCmp) renderPatchContent() string {
+func (p *permissionDialogComponent) renderPatchContent() string {
 	// if pr, ok := p.permission.Params.(tools.EditPermissionsParams); ok {
 	// 	diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) {
 	// 		return diff.FormatDiff(pr.Diff, diff.WithTotalWidth(p.contentViewPort.Width))
@@ -293,7 +293,7 @@ func (p *permissionDialogCmp) renderPatchContent() string {
 	return ""
 }
 
-func (p *permissionDialogCmp) renderWriteContent() string {
+func (p *permissionDialogComponent) renderWriteContent() string {
 	// if pr, ok := p.permission.Params.(tools.WritePermissionsParams); ok {
 	// 	// Use the cache for diff rendering
 	// 	diff := p.GetOrSetDiff(p.permission.ID, func() (string, error) {
@@ -306,7 +306,7 @@ func (p *permissionDialogCmp) renderWriteContent() string {
 	return ""
 }
 
-func (p *permissionDialogCmp) renderFetchContent() string {
+func (p *permissionDialogComponent) renderFetchContent() string {
 	// 	t := theme.CurrentTheme()
 	// 	baseStyle := styles.BaseStyle()
 	//
@@ -329,7 +329,7 @@ func (p *permissionDialogCmp) renderFetchContent() string {
 	return ""
 }
 
-func (p *permissionDialogCmp) renderDefaultContent() string {
+func (p *permissionDialogComponent) renderDefaultContent() string {
 	// 	t := theme.CurrentTheme()
 	// 	baseStyle := styles.BaseStyle()
 	//
@@ -354,7 +354,7 @@ func (p *permissionDialogCmp) renderDefaultContent() string {
 	return p.styleViewport()
 }
 
-func (p *permissionDialogCmp) styleViewport() string {
+func (p *permissionDialogComponent) styleViewport() string {
 	t := theme.CurrentTheme()
 	contentStyle := lipgloss.NewStyle().
 		Background(t.Background())
@@ -362,7 +362,7 @@ func (p *permissionDialogCmp) styleViewport() string {
 	return contentStyle.Render(p.contentViewPort.View())
 }
 
-func (p *permissionDialogCmp) render() string {
+func (p *permissionDialogComponent) render() string {
 	return "NOT IMPLEMENTED"
 	// t := theme.CurrentTheme()
 	// baseStyle := styles.BaseStyle()
@@ -420,15 +420,15 @@ func (p *permissionDialogCmp) render() string {
 	// 	)
 }
 
-func (p *permissionDialogCmp) View() string {
+func (p *permissionDialogComponent) View() string {
 	return p.render()
 }
 
-func (p *permissionDialogCmp) BindingKeys() []key.Binding {
+func (p *permissionDialogComponent) BindingKeys() []key.Binding {
 	return layout.KeyMapToSlice(permissionsKeys)
 }
 
-func (p *permissionDialogCmp) SetSize() tea.Cmd {
+func (p *permissionDialogComponent) SetSize() tea.Cmd {
 	// if p.permission.ID == "" {
 	// 	return nil
 	// }
@@ -458,7 +458,7 @@ func (p *permissionDialogCmp) SetSize() tea.Cmd {
 // }
 
 // Helper to get or set cached diff content
-func (c *permissionDialogCmp) GetOrSetDiff(key string, generator func() (string, error)) string {
+func (c *permissionDialogComponent) GetOrSetDiff(key string, generator func() (string, error)) string {
 	if cached, ok := c.diffCache[key]; ok {
 		return cached
 	}
@@ -474,7 +474,7 @@ func (c *permissionDialogCmp) GetOrSetDiff(key string, generator func() (string,
 }
 
 // Helper to get or set cached markdown content
-func (c *permissionDialogCmp) GetOrSetMarkdown(key string, generator func() (string, error)) string {
+func (c *permissionDialogComponent) GetOrSetMarkdown(key string, generator func() (string, error)) string {
 	if cached, ok := c.markdownCache[key]; ok {
 		return cached
 	}
@@ -489,11 +489,11 @@ func (c *permissionDialogCmp) GetOrSetMarkdown(key string, generator func() (str
 	return content
 }
 
-func NewPermissionDialogCmp() PermissionDialogCmp {
+func NewPermissionDialogCmp() PermissionDialogComponent {
 	// Create viewport for content
-	contentViewport := viewport.New(0, 0)
+	contentViewport := viewport.New() // (0, 0)
 
-	return &permissionDialogCmp{
+	return &permissionDialogComponent{
 		contentViewPort: contentViewport,
 		selectedOption:  0, // Default to "Allow"
 		diffCache:       make(map[string]string),

+ 10 - 10
packages/tui/internal/components/dialog/quit.go

@@ -3,9 +3,9 @@ package dialog
 import (
 	"strings"
 
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
@@ -17,11 +17,11 @@ const question = "Are you sure you want to quit?"
 type CloseQuitMsg struct{}
 
 type QuitDialog interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 }
 
-type quitDialogCmp struct {
+type quitDialogComponent struct {
 	selectedNo bool
 }
 
@@ -56,11 +56,11 @@ var helpKeys = helpMapping{
 	),
 }
 
-func (q *quitDialogCmp) Init() tea.Cmd {
+func (q *quitDialogComponent) Init() tea.Cmd {
 	return nil
 }
 
-func (q *quitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (q *quitDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
 		switch {
@@ -81,7 +81,7 @@ func (q *quitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return q, nil
 }
 
-func (q *quitDialogCmp) View() string {
+func (q *quitDialogComponent) View() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -125,12 +125,12 @@ func (q *quitDialogCmp) View() string {
 		Render(content)
 }
 
-func (q *quitDialogCmp) BindingKeys() []key.Binding {
+func (q *quitDialogComponent) BindingKeys() []key.Binding {
 	return layout.KeyMapToSlice(helpKeys)
 }
 
 func NewQuitCmp() QuitDialog {
-	return &quitDialogCmp{
+	return &quitDialogComponent{
 		selectedNo: true,
 	}
 }

+ 12 - 12
packages/tui/internal/components/dialog/session.go

@@ -1,9 +1,9 @@
 package dialog
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
@@ -18,13 +18,13 @@ type CloseSessionDialogMsg struct {
 
 // SessionDialog interface for the session switching dialog
 type SessionDialog interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 	SetSessions(sessions []client.SessionInfo)
 	SetSelectedSession(sessionID string)
 }
 
-type sessionDialogCmp struct {
+type sessionDialogComponent struct {
 	sessions          []client.SessionInfo
 	selectedIdx       int
 	width             int
@@ -68,11 +68,11 @@ var sessionKeys = sessionKeyMap{
 	),
 }
 
-func (s *sessionDialogCmp) Init() tea.Cmd {
+func (s *sessionDialogComponent) Init() tea.Cmd {
 	return nil
 }
 
-func (s *sessionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (s *sessionDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.WindowSizeMsg:
 		s.width = msg.Width
@@ -105,7 +105,7 @@ func (s *sessionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return s, nil
 }
 
-func (s *sessionDialogCmp) View() string {
+func (s *sessionDialogComponent) View() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -185,11 +185,11 @@ func (s *sessionDialogCmp) View() string {
 		Render(content)
 }
 
-func (s *sessionDialogCmp) BindingKeys() []key.Binding {
+func (s *sessionDialogComponent) BindingKeys() []key.Binding {
 	return layout.KeyMapToSlice(sessionKeys)
 }
 
-func (s *sessionDialogCmp) SetSessions(sessions []client.SessionInfo) {
+func (s *sessionDialogComponent) SetSessions(sessions []client.SessionInfo) {
 	s.sessions = sessions
 
 	// If we have a selected session ID, find its index
@@ -206,7 +206,7 @@ func (s *sessionDialogCmp) SetSessions(sessions []client.SessionInfo) {
 	s.selectedIdx = 0
 }
 
-func (s *sessionDialogCmp) SetSelectedSession(sessionID string) {
+func (s *sessionDialogComponent) SetSelectedSession(sessionID string) {
 	s.selectedSessionID = sessionID
 
 	// Update the selected index if sessions are already loaded
@@ -222,7 +222,7 @@ func (s *sessionDialogCmp) SetSelectedSession(sessionID string) {
 
 // NewSessionDialogCmp creates a new session switching dialog
 func NewSessionDialogCmp() SessionDialog {
-	return &sessionDialogCmp{
+	return &sessionDialogComponent{
 		sessions:          []client.SessionInfo{},
 		selectedIdx:       0,
 		selectedSessionID: "",

+ 10 - 10
packages/tui/internal/components/dialog/theme.go

@@ -1,9 +1,9 @@
 package dialog
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/status"
 	"github.com/sst/opencode/internal/styles"
@@ -21,11 +21,11 @@ type CloseThemeDialogMsg struct{}
 
 // ThemeDialog interface for the theme switching dialog
 type ThemeDialog interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 }
 
-type themeDialogCmp struct {
+type themeDialogComponent struct {
 	themes       []string
 	selectedIdx  int
 	width        int
@@ -69,7 +69,7 @@ var themeKeys = themeKeyMap{
 	),
 }
 
-func (t *themeDialogCmp) Init() tea.Cmd {
+func (t *themeDialogComponent) Init() tea.Cmd {
 	// Load available themes and update selectedIdx based on current theme
 	t.themes = theme.AvailableThemes()
 	t.currentTheme = theme.CurrentThemeName()
@@ -85,7 +85,7 @@ func (t *themeDialogCmp) Init() tea.Cmd {
 	return nil
 }
 
-func (t *themeDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (t *themeDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
 		switch {
@@ -124,7 +124,7 @@ func (t *themeDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return t, nil
 }
 
-func (t *themeDialogCmp) View() string {
+func (t *themeDialogComponent) View() string {
 	currentTheme := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 
@@ -185,13 +185,13 @@ func (t *themeDialogCmp) View() string {
 		Render(content)
 }
 
-func (t *themeDialogCmp) BindingKeys() []key.Binding {
+func (t *themeDialogComponent) BindingKeys() []key.Binding {
 	return layout.KeyMapToSlice(themeKeys)
 }
 
 // NewThemeDialogCmp creates a new theme switching dialog
 func NewThemeDialogCmp() ThemeDialog {
-	return &themeDialogCmp{
+	return &themeDialogComponent{
 		themes:       []string{},
 		selectedIdx:  0,
 		currentTheme: "",

+ 20 - 20
packages/tui/internal/components/dialog/tools.go

@@ -1,9 +1,9 @@
 package dialog
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	utilComponents "github.com/sst/opencode/internal/components/util"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
@@ -17,7 +17,7 @@ const (
 
 // ToolsDialog interface for the tools list dialog
 type ToolsDialog interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 	SetTools(tools []string)
 }
@@ -39,7 +39,7 @@ func (t toolItem) Render(selected bool, width int) string {
 	baseStyle := styles.BaseStyle().
 		Width(width).
 		Background(th.Background())
-	
+
 	if selected {
 		baseStyle = baseStyle.
 			Background(th.Primary()).
@@ -49,15 +49,15 @@ func (t toolItem) Render(selected bool, width int) string {
 		baseStyle = baseStyle.
 			Foreground(th.Text())
 	}
-	
+
 	return baseStyle.Render(t.name)
 }
 
-type toolsDialogCmp struct {
-	tools       []toolItem
-	width       int
-	height      int
-	list        utilComponents.SimpleList[toolItem]
+type toolsDialogComponent struct {
+	tools  []toolItem
+	width  int
+	height int
+	list   utilComponents.SimpleList[toolItem]
 }
 
 type toolsKeyMap struct {
@@ -91,21 +91,21 @@ var toolsKeys = toolsKeyMap{
 	),
 }
 
-func (m *toolsDialogCmp) Init() tea.Cmd {
+func (m *toolsDialogComponent) Init() tea.Cmd {
 	return nil
 }
 
-func (m *toolsDialogCmp) SetTools(tools []string) {
+func (m *toolsDialogComponent) SetTools(tools []string) {
 	var toolItems []toolItem
 	for _, name := range tools {
 		toolItems = append(toolItems, toolItem{name: name})
 	}
-	
+
 	m.tools = toolItems
 	m.list.SetItems(toolItems)
 }
 
-func (m *toolsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (m *toolsDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
 		switch {
@@ -130,7 +130,7 @@ func (m *toolsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return m, cmd
 }
 
-func (m *toolsDialogCmp) View() string {
+func (m *toolsDialogComponent) View() string {
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle().Background(t.Background())
 
@@ -144,7 +144,7 @@ func (m *toolsDialogCmp) View() string {
 	// Calculate dialog width based on content
 	dialogWidth := min(maxToolsDialogWidth, m.width/2)
 	m.list.SetMaxWidth(dialogWidth)
-	
+
 	content := lipgloss.JoinVertical(
 		lipgloss.Left,
 		title,
@@ -160,7 +160,7 @@ func (m *toolsDialogCmp) View() string {
 		Render(content)
 }
 
-func (m *toolsDialogCmp) BindingKeys() []key.Binding {
+func (m *toolsDialogComponent) BindingKeys() []key.Binding {
 	return layout.KeyMapToSlice(toolsKeys)
 }
 
@@ -171,8 +171,8 @@ func NewToolsDialogCmp() ToolsDialog {
 		"No tools available",
 		true,
 	)
-	
-	return &toolsDialogCmp{
+
+	return &toolsDialogComponent{
 		list: list,
 	}
 }

+ 10 - 10
packages/tui/internal/components/diff/diff.go

@@ -3,6 +3,7 @@ package diff
 import (
 	"bytes"
 	"fmt"
+	"image/color"
 	"io"
 	"regexp"
 	"strconv"
@@ -12,9 +13,11 @@ import (
 	"github.com/alecthomas/chroma/v2/formatters"
 	"github.com/alecthomas/chroma/v2/lexers"
 	"github.com/alecthomas/chroma/v2/styles"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
+	"github.com/charmbracelet/lipgloss/v2/compat"
 	"github.com/charmbracelet/x/ansi"
 	"github.com/sergi/go-diff/diffmatchpatch"
+	stylesi "github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
 )
 
@@ -300,7 +303,7 @@ func pairLines(lines []DiffLine) []linePair {
 // -------------------------------------------------------------------------
 
 // SyntaxHighlight applies syntax highlighting to text based on file extension
-func SyntaxHighlight(w io.Writer, source, fileName, formatter string, bg lipgloss.TerminalColor) error {
+func SyntaxHighlight(w io.Writer, source, fileName, formatter string, bg color.Color) error {
 	t := theme.CurrentTheme()
 
 	// Determine the language lexer to use
@@ -509,15 +512,12 @@ func SyntaxHighlight(w io.Writer, source, fileName, formatter string, bg lipglos
 }
 
 // getColor returns the appropriate hex color string based on terminal background
-func getColor(adaptiveColor lipgloss.AdaptiveColor) string {
-	if lipgloss.HasDarkBackground() {
-		return adaptiveColor.Dark
-	}
-	return adaptiveColor.Light
+func getColor(adaptiveColor compat.AdaptiveColor) string {
+	return stylesi.AdaptiveColorToString(adaptiveColor)
 }
 
 // highlightLine applies syntax highlighting to a single line
-func highlightLine(fileName string, line string, bg lipgloss.TerminalColor) string {
+func highlightLine(fileName string, line string, bg color.Color) string {
 	var buf bytes.Buffer
 	err := SyntaxHighlight(&buf, line, fileName, "terminal16m", bg)
 	if err != nil {
@@ -540,7 +540,7 @@ func createStyles(t theme.Theme) (removedLineStyle, addedLineStyle, contextLineS
 // -------------------------------------------------------------------------
 
 // applyHighlighting applies intra-line highlighting to a piece of text
-func applyHighlighting(content string, segments []Segment, segmentType LineType, highlightBg lipgloss.AdaptiveColor) string {
+func applyHighlighting(content string, segments []Segment, segmentType LineType, highlightBg compat.AdaptiveColor) string {
 	// Find all ANSI sequences in the content
 	ansiRegex := regexp.MustCompile(`\x1b(?:[@-Z\\-_]|\[[0-9?]*(?:;[0-9?]*)*[@-~])`)
 	ansiMatches := ansiRegex.FindAllStringIndex(content, -1)
@@ -662,7 +662,7 @@ func renderDiffColumnLine(
 	var bgStyle lipgloss.Style
 	var lineNum string
 	var highlightType LineType
-	var highlightColor lipgloss.AdaptiveColor
+	var highlightColor compat.AdaptiveColor
 
 	if isLeftColumn {
 		// Left column logic

+ 1 - 1
packages/tui/internal/components/qr/qr.go

@@ -3,7 +3,7 @@ package qr
 import (
 	"strings"
 
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/theme"
 	"rsc.io/qr"
 )

+ 4 - 4
packages/tui/internal/components/util/simple-list.go

@@ -1,9 +1,9 @@
 package utilComponents
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/layout"
 	"github.com/sst/opencode/internal/styles"
 	"github.com/sst/opencode/internal/theme"
@@ -14,7 +14,7 @@ type SimpleListItem interface {
 }
 
 type SimpleList[T SimpleListItem] interface {
-	tea.Model
+	layout.ModelWithView
 	layout.Bindings
 	SetMaxWidth(maxWidth int)
 	GetSelectedItem() (item T, idx int)

+ 9 - 8
packages/tui/internal/image/images.go

@@ -4,11 +4,12 @@ import (
 	"bytes"
 	"fmt"
 	"image"
+	"image/color"
 	"image/png"
 	"os"
 	"strings"
 
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/disintegration/imaging"
 	"github.com/lucasb-eyer/go-colorful"
 	_ "golang.org/x/image/webp"
@@ -39,7 +40,7 @@ func ToString(width int, img image.Image) string {
 			c1, _ := colorful.MakeColor(img.At(x, heightCounter))
 			color1 := lipgloss.Color(c1.Hex())
 
-			var color2 lipgloss.Color
+			var color2 color.Color
 			if heightCounter+1 < h {
 				c2, _ := colorful.MakeColor(img.At(x, heightCounter+1))
 				color2 = lipgloss.Color(c2.Hex())
@@ -76,10 +77,10 @@ func ImagePreview(width int, filename string) (string, error) {
 
 func ImageToBytes(image image.Image) ([]byte, error) {
 	buf := new(bytes.Buffer)
-    err := png.Encode(buf, image)
-    if err != nil {
-        return nil, err
-    }
-    
-    return buf.Bytes(), nil
+	err := png.Encode(buf, image)
+	if err != nil {
+		return nil, err
+	}
+
+	return buf.Bytes(), nil
 }

+ 12 - 7
packages/tui/internal/layout/container.go

@@ -1,14 +1,19 @@
 package layout
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/theme"
 )
 
-type Container interface {
+type ModelWithView interface {
 	tea.Model
+	tea.ViewModel
+}
+
+type Container interface {
+	ModelWithView
 	Sizeable
 	Bindings
 	Focus()
@@ -21,7 +26,7 @@ type container struct {
 	width  int
 	height int
 
-	content tea.Model
+	content ModelWithView
 
 	paddingTop    int
 	paddingRight  int
@@ -46,7 +51,7 @@ func (c *container) Init() tea.Cmd {
 
 func (c *container) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	u, cmd := c.content.Update(msg)
-	c.content = u
+	c.content = u.(ModelWithView)
 	return c, cmd
 }
 
@@ -175,7 +180,7 @@ func (c *container) Blur() {
 
 type ContainerOption func(*container)
 
-func NewContainer(content tea.Model, options ...ContainerOption) Container {
+func NewContainer(content ModelWithView, options ...ContainerOption) Container {
 	c := &container{
 		content:     content,
 		borderStyle: lipgloss.NormalBorder(),

+ 4 - 10
packages/tui/internal/layout/flex.go

@@ -1,10 +1,9 @@
 package layout
 
 import (
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
-	"github.com/sst/opencode/internal/theme"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 )
 
 type FlexDirection int
@@ -26,7 +25,7 @@ func FlexPaneSizeFixed(size int) FlexPaneSize {
 }
 
 type FlexLayout interface {
-	tea.Model
+	ModelWithView
 	Sizeable
 	Bindings
 	SetPanes(panes []Container) tea.Cmd
@@ -75,8 +74,6 @@ func (f *flexLayout) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 }
 
 func (f *flexLayout) View() string {
-	t := theme.CurrentTheme()
-
 	if len(f.panes) == 0 {
 		return ""
 	}
@@ -94,7 +91,6 @@ func (f *flexLayout) View() string {
 				paneWidth,
 				pane.Alignment(),
 				pane.View(),
-				lipgloss.WithWhitespaceBackground(t.Background()),
 			)
 			views = append(views, view)
 		} else {
@@ -105,7 +101,6 @@ func (f *flexLayout) View() string {
 				lipgloss.Center,
 				pane.Alignment(),
 				pane.View(),
-				lipgloss.WithWhitespaceBackground(t.Background()),
 			)
 			views = append(views, view)
 		}
@@ -245,4 +240,3 @@ func WithPaneSizes(sizes ...FlexPaneSize) FlexLayoutOption {
 		f.sizes = sizes
 	}
 }
-

+ 2 - 2
packages/tui/internal/layout/layout.go

@@ -3,8 +3,8 @@ package layout
 import (
 	"reflect"
 
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
 )
 
 var Current *LayoutInfo

+ 2 - 2
packages/tui/internal/layout/overlay.go

@@ -3,7 +3,7 @@ package layout
 import (
 	"strings"
 
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
 	chAnsi "github.com/charmbracelet/x/ansi"
 	"github.com/muesli/ansi"
 	"github.com/muesli/reflow/truncate"
@@ -14,7 +14,7 @@ import (
 )
 
 // Most of this code is borrowed from
-// https://github.com/charmbracelet/lipgloss/pull/102
+// https://github.com/charmbracelet/lipgloss/v2/pull/102
 // as well as the lipgloss library, with some modification for what I needed.
 
 // Split a string into lines, additionally returning the size of the widest line.

+ 4 - 4
packages/tui/internal/page/chat.go

@@ -4,9 +4,9 @@ import (
 	"context"
 	"strings"
 
-	"github.com/charmbracelet/bubbles/key"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/key"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/completions"
 	"github.com/sst/opencode/internal/components/chat"
@@ -187,7 +187,7 @@ func (p *chatPage) BindingKeys() []key.Binding {
 	return bindings
 }
 
-func NewChatPage(app *app.App) tea.Model {
+func NewChatPage(app *app.App) layout.ModelWithView {
 	cg := completions.NewFileAndFolderContextGroup()
 	completionDialog := dialog.NewCompletionDialogCmp(cg)
 	messagesContainer := layout.NewContainer(

+ 7 - 117
packages/tui/internal/styles/background.go

@@ -1,123 +1,13 @@
 package styles
 
-import (
-	"fmt"
-	"regexp"
-	"strings"
-
-	"github.com/charmbracelet/lipgloss"
-)
-
-var ansiEscape = regexp.MustCompile("\x1b\\[[0-9;]*m")
-
-func getColorRGB(c lipgloss.TerminalColor) (uint8, uint8, uint8) {
-	r, g, b, a := c.RGBA()
-
-	// Un-premultiply alpha if needed
-	if a > 0 && a < 0xffff {
-		r = (r * 0xffff) / a
-		g = (g * 0xffff) / a
-		b = (b * 0xffff) / a
-	}
-
-	// Convert from 16-bit to 8-bit color
-	return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
+type TerminalInfo struct {
+	BackgroundIsDark bool
 }
 
-// ForceReplaceBackgroundWithLipgloss replaces any ANSI background color codes
-// in `input` with a single 24‑bit background (48;2;R;G;B).
-func ForceReplaceBackgroundWithLipgloss(input string, newBgColor lipgloss.TerminalColor) string {
-	// Precompute our new-bg sequence once
-	r, g, b := getColorRGB(newBgColor)
-	newBg := fmt.Sprintf("48;2;%d;%d;%d", r, g, b)
-
-	return ansiEscape.ReplaceAllStringFunc(input, func(seq string) string {
-		const (
-			escPrefixLen = 2 // "\x1b["
-			escSuffixLen = 1 // "m"
-		)
-
-		raw := seq
-		start := escPrefixLen
-		end := len(raw) - escSuffixLen
+var Terminal *TerminalInfo
 
-		var sb strings.Builder
-		// reserve enough space: original content minus bg codes + our newBg
-		sb.Grow((end - start) + len(newBg) + 2)
-
-		// scan from start..end, token by token
-		for i := start; i < end; {
-			// find the next ';' or end
-			j := i
-			for j < end && raw[j] != ';' {
-				j++
-			}
-			token := raw[i:j]
-
-			// fast‑path: skip "48;5;N" or "48;2;R;G;B"
-			if len(token) == 2 && token[0] == '4' && token[1] == '8' {
-				k := j + 1
-				if k < end {
-					// find next token
-					l := k
-					for l < end && raw[l] != ';' {
-						l++
-					}
-					next := raw[k:l]
-					if next == "5" {
-						// skip "48;5;N"
-						m := l + 1
-						for m < end && raw[m] != ';' {
-							m++
-						}
-						i = m + 1
-						continue
-					} else if next == "2" {
-						// skip "48;2;R;G;B"
-						m := l + 1
-						for count := 0; count < 3 && m < end; count++ {
-							for m < end && raw[m] != ';' {
-								m++
-							}
-							m++
-						}
-						i = m
-						continue
-					}
-				}
-			}
-
-			// decide whether to keep this token
-			// manually parse ASCII digits to int
-			isNum := true
-			val := 0
-			for p := i; p < j; p++ {
-				c := raw[p]
-				if c < '0' || c > '9' {
-					isNum = false
-					break
-				}
-				val = val*10 + int(c-'0')
-			}
-			keep := !isNum ||
-				((val < 40 || val > 47) && (val < 100 || val > 107) && val != 49)
-
-			if keep {
-				if sb.Len() > 0 {
-					sb.WriteByte(';')
-				}
-				sb.WriteString(token)
-			}
-			// advance past this token (and the semicolon)
-			i = j + 1
-		}
-
-		// append our new background
-		if sb.Len() > 0 {
-			sb.WriteByte(';')
-		}
-		sb.WriteString(newBg)
-
-		return "\x1b[" + sb.String() + "m"
-	})
+func init() {
+	Terminal = &TerminalInfo{
+		BackgroundIsDark: false,
+	}
 }

+ 106 - 69
packages/tui/internal/styles/markdown.go

@@ -3,7 +3,8 @@ package styles
 import (
 	"github.com/charmbracelet/glamour"
 	"github.com/charmbracelet/glamour/ansi"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2/compat"
+	"github.com/lucasb-eyer/go-colorful"
 	"github.com/sst/opencode/internal/theme"
 )
 
@@ -15,117 +16,120 @@ func stringPtr(s string) *string { return &s }
 func uintPtr(u uint) *uint       { return &u }
 
 // returns a glamour TermRenderer configured with the current theme
-func GetMarkdownRenderer(width int) *glamour.TermRenderer {
+func GetMarkdownRenderer(width int, backgroundColor compat.AdaptiveColor) *glamour.TermRenderer {
 	r, _ := glamour.NewTermRenderer(
-		glamour.WithStyles(generateMarkdownStyleConfig()),
+		glamour.WithStyles(generateMarkdownStyleConfig(backgroundColor)),
 		glamour.WithWordWrap(width),
+		glamour.WithChromaFormatter("terminal16m"),
 	)
 	return r
 }
 
 // creates an ansi.StyleConfig for markdown rendering
 // using adaptive colors from the provided theme.
-func generateMarkdownStyleConfig() ansi.StyleConfig {
+func generateMarkdownStyleConfig(backgroundColor compat.AdaptiveColor) ansi.StyleConfig {
 	t := theme.CurrentTheme()
+	background := stringPtr(AdaptiveColorToString(backgroundColor))
 
 	return ansi.StyleConfig{
 		Document: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
-				BlockPrefix: "",
-				BlockSuffix: "",
-				Color:       stringPtr(adaptiveColorToString(t.MarkdownText())),
+				BlockPrefix:     "",
+				BlockSuffix:     "",
+				BackgroundColor: background,
+				Color:           stringPtr(AdaptiveColorToString(t.MarkdownText())),
 			},
 		},
 		BlockQuote: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownBlockQuote())),
+				Color:  stringPtr(AdaptiveColorToString(t.MarkdownBlockQuote())),
 				Italic: boolPtr(true),
 				Prefix: "┃ ",
 			},
 			Indent:      uintPtr(1),
-			IndentToken: stringPtr(BaseStyle().Render(" ")),
+			IndentToken: stringPtr(" "),
 		},
 		List: ansi.StyleList{
 			LevelIndent: defaultMargin,
 			StyleBlock: ansi.StyleBlock{
-				IndentToken: stringPtr(BaseStyle().Render(" ")),
+				IndentToken: stringPtr(" "),
 				StylePrimitive: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.MarkdownText())),
+					Color: stringPtr(AdaptiveColorToString(t.MarkdownText())),
 				},
 			},
 		},
 		Heading: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
 				BlockSuffix: "\n",
-				Color:       stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+				Color:       stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				Bold:        boolPtr(true),
 			},
 		},
 		H1: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
 				Prefix: "# ",
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+				Color:  stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				Bold:   boolPtr(true),
 			},
 		},
 		H2: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
 				Prefix: "## ",
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+				Color:  stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				Bold:   boolPtr(true),
 			},
 		},
 		H3: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
 				Prefix: "### ",
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+				Color:  stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				Bold:   boolPtr(true),
 			},
 		},
 		H4: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
 				Prefix: "#### ",
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+				Color:  stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				Bold:   boolPtr(true),
 			},
 		},
 		H5: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
 				Prefix: "##### ",
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+				Color:  stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				Bold:   boolPtr(true),
 			},
 		},
 		H6: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
 				Prefix: "###### ",
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+				Color:  stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				Bold:   boolPtr(true),
 			},
 		},
 		Strikethrough: ansi.StylePrimitive{
 			CrossedOut: boolPtr(true),
-			Color:      stringPtr(adaptiveColorToString(t.TextMuted())),
+			Color:      stringPtr(AdaptiveColorToString(t.TextMuted())),
 		},
 		Emph: ansi.StylePrimitive{
-			Color:  stringPtr(adaptiveColorToString(t.MarkdownEmph())),
+			Color:  stringPtr(AdaptiveColorToString(t.MarkdownEmph())),
 			Italic: boolPtr(true),
 		},
 		Strong: ansi.StylePrimitive{
 			Bold:  boolPtr(true),
-			Color: stringPtr(adaptiveColorToString(t.MarkdownStrong())),
+			Color: stringPtr(AdaptiveColorToString(t.MarkdownStrong())),
 		},
 		HorizontalRule: ansi.StylePrimitive{
-			Color:  stringPtr(adaptiveColorToString(t.MarkdownHorizontalRule())),
+			Color:  stringPtr(AdaptiveColorToString(t.MarkdownHorizontalRule())),
 			Format: "\n─────────────────────────────────────────\n",
 		},
 		Item: ansi.StylePrimitive{
 			BlockPrefix: "• ",
-			Color:       stringPtr(adaptiveColorToString(t.MarkdownListItem())),
+			Color:       stringPtr(AdaptiveColorToString(t.MarkdownListItem())),
 		},
 		Enumeration: ansi.StylePrimitive{
 			BlockPrefix: ". ",
-			Color:       stringPtr(adaptiveColorToString(t.MarkdownListEnumeration())),
+			Color:       stringPtr(AdaptiveColorToString(t.MarkdownListEnumeration())),
 		},
 		Task: ansi.StyleTask{
 			StylePrimitive: ansi.StylePrimitive{},
@@ -133,116 +137,147 @@ func generateMarkdownStyleConfig() ansi.StyleConfig {
 			Unticked:       "[ ] ",
 		},
 		Link: ansi.StylePrimitive{
-			Color:     stringPtr(adaptiveColorToString(t.MarkdownLink())),
+			Color:     stringPtr(AdaptiveColorToString(t.MarkdownLink())),
 			Underline: boolPtr(true),
 		},
 		LinkText: ansi.StylePrimitive{
-			Color: stringPtr(adaptiveColorToString(t.MarkdownLinkText())),
+			Color: stringPtr(AdaptiveColorToString(t.MarkdownLinkText())),
 			Bold:  boolPtr(true),
 		},
 		Image: ansi.StylePrimitive{
-			Color:     stringPtr(adaptiveColorToString(t.MarkdownImage())),
+			Color:     stringPtr(AdaptiveColorToString(t.MarkdownImage())),
 			Underline: boolPtr(true),
 			Format:    "🖼 {{.text}}",
 		},
 		ImageText: ansi.StylePrimitive{
-			Color:  stringPtr(adaptiveColorToString(t.MarkdownImageText())),
+			Color:  stringPtr(AdaptiveColorToString(t.MarkdownImageText())),
 			Format: "{{.text}}",
 		},
 		Code: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
-				Color:  stringPtr(adaptiveColorToString(t.MarkdownCode())),
-				Prefix: "",
-				Suffix: "",
+				BackgroundColor: background,
+				Color:           stringPtr(AdaptiveColorToString(t.MarkdownCode())),
+				Prefix:          "",
+				Suffix:          "",
 			},
 		},
 		CodeBlock: ansi.StyleCodeBlock{
 			StyleBlock: ansi.StyleBlock{
 				StylePrimitive: ansi.StylePrimitive{
-					Prefix: " ",
-					Color:  stringPtr(adaptiveColorToString(t.MarkdownCodeBlock())),
+					BackgroundColor: background,
+					Prefix:          " ",
+					Color:           stringPtr(AdaptiveColorToString(t.MarkdownCodeBlock())),
 				},
 			},
 			Chroma: &ansi.Chroma{
+				Background: ansi.StylePrimitive{
+					BackgroundColor: background,
+				},
 				Text: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.MarkdownText())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.MarkdownText())),
 				},
 				Error: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.Error())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.Error())),
 				},
 				Comment: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxComment())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxComment())),
 				},
 				CommentPreproc: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxKeyword())),
 				},
 				Keyword: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxKeyword())),
 				},
 				KeywordReserved: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxKeyword())),
 				},
 				KeywordNamespace: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxKeyword())),
 				},
 				KeywordType: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxType())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxType())),
 				},
 				Operator: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxOperator())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxOperator())),
 				},
 				Punctuation: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxPunctuation())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxPunctuation())),
 				},
 				Name: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxVariable())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxVariable())),
 				},
 				NameBuiltin: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxVariable())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxVariable())),
 				},
 				NameTag: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxKeyword())),
 				},
 				NameAttribute: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxFunction())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxFunction())),
 				},
 				NameClass: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxType())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxType())),
 				},
 				NameConstant: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxVariable())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxVariable())),
 				},
 				NameDecorator: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxFunction())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxFunction())),
 				},
 				NameFunction: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxFunction())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxFunction())),
 				},
 				LiteralNumber: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxNumber())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxNumber())),
 				},
 				LiteralString: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxString())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxString())),
 				},
 				LiteralStringEscape: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.SyntaxKeyword())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.SyntaxKeyword())),
 				},
 				GenericDeleted: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.DiffRemoved())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.DiffRemoved())),
 				},
 				GenericEmph: ansi.StylePrimitive{
-					Color:  stringPtr(adaptiveColorToString(t.MarkdownEmph())),
-					Italic: boolPtr(true),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.MarkdownEmph())),
+					Italic:          boolPtr(true),
 				},
 				GenericInserted: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.DiffAdded())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.DiffAdded())),
 				},
 				GenericStrong: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.MarkdownStrong())),
-					Bold:  boolPtr(true),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.MarkdownStrong())),
+					Bold:            boolPtr(true),
 				},
 				GenericSubheading: ansi.StylePrimitive{
-					Color: stringPtr(adaptiveColorToString(t.MarkdownHeading())),
+					BackgroundColor: background,
+					Color:           stringPtr(AdaptiveColorToString(t.MarkdownHeading())),
 				},
 			},
 		},
@@ -259,24 +294,26 @@ func generateMarkdownStyleConfig() ansi.StyleConfig {
 		},
 		DefinitionDescription: ansi.StylePrimitive{
 			BlockPrefix: "\n ❯ ",
-			Color:       stringPtr(adaptiveColorToString(t.MarkdownLinkText())),
+			Color:       stringPtr(AdaptiveColorToString(t.MarkdownLinkText())),
 		},
 		Text: ansi.StylePrimitive{
-			Color: stringPtr(adaptiveColorToString(t.MarkdownText())),
+			Color: stringPtr(AdaptiveColorToString(t.MarkdownText())),
 		},
 		Paragraph: ansi.StyleBlock{
 			StylePrimitive: ansi.StylePrimitive{
-				Color: stringPtr(adaptiveColorToString(t.MarkdownText())),
+				Color: stringPtr(AdaptiveColorToString(t.MarkdownText())),
 			},
 		},
 	}
 }
 
-// adaptiveColorToString converts a lipgloss.AdaptiveColor to the appropriate
+// AdaptiveColorToString converts a compat.AdaptiveColor to the appropriate
 // hex color string based on the current terminal background
-func adaptiveColorToString(color lipgloss.AdaptiveColor) string {
-	if lipgloss.HasDarkBackground() {
-		return color.Dark
+func AdaptiveColorToString(color compat.AdaptiveColor) string {
+	if Terminal.BackgroundIsDark {
+		c1, _ := colorful.MakeColor(color.Dark)
+		return c1.Hex()
 	}
-	return color.Light
+	c1, _ := colorful.MakeColor(color.Light)
+	return c1.Hex()
 }

+ 17 - 16
packages/tui/internal/styles/styles.go

@@ -1,7 +1,8 @@
 package styles
 
 import (
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
+	"github.com/charmbracelet/lipgloss/v2/compat"
 	"github.com/sst/opencode/internal/theme"
 )
 
@@ -83,76 +84,76 @@ func DimBorder() lipgloss.Style {
 }
 
 // PrimaryColor returns the primary color from the current theme
-func PrimaryColor() lipgloss.AdaptiveColor {
+func PrimaryColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Primary()
 }
 
 // SecondaryColor returns the secondary color from the current theme
-func SecondaryColor() lipgloss.AdaptiveColor {
+func SecondaryColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Secondary()
 }
 
 // AccentColor returns the accent color from the current theme
-func AccentColor() lipgloss.AdaptiveColor {
+func AccentColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Accent()
 }
 
 // ErrorColor returns the error color from the current theme
-func ErrorColor() lipgloss.AdaptiveColor {
+func ErrorColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Error()
 }
 
 // WarningColor returns the warning color from the current theme
-func WarningColor() lipgloss.AdaptiveColor {
+func WarningColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Warning()
 }
 
 // SuccessColor returns the success color from the current theme
-func SuccessColor() lipgloss.AdaptiveColor {
+func SuccessColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Success()
 }
 
 // InfoColor returns the info color from the current theme
-func InfoColor() lipgloss.AdaptiveColor {
+func InfoColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Info()
 }
 
 // TextColor returns the text color from the current theme
-func TextColor() lipgloss.AdaptiveColor {
+func TextColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Text()
 }
 
 // TextMutedColor returns the muted text color from the current theme
-func TextMutedColor() lipgloss.AdaptiveColor {
+func TextMutedColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().TextMuted()
 }
 
 // BackgroundColor returns the background color from the current theme
-func BackgroundColor() lipgloss.AdaptiveColor {
+func BackgroundColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Background()
 }
 
 // BackgroundSubtleColor returns the subtle background color from the current theme
-func BackgroundSubtleColor() lipgloss.AdaptiveColor {
+func BackgroundSubtleColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().BackgroundSubtle()
 }
 
 // BackgroundElementColor returns the darker background color from the current theme
-func BackgroundElementColor() lipgloss.AdaptiveColor {
+func BackgroundElementColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().BackgroundElement()
 }
 
 // BorderColor returns the border color from the current theme
-func BorderColor() lipgloss.AdaptiveColor {
+func BorderColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().Border()
 }
 
 // BorderActiveColor returns the active border color from the current theme
-func BorderActiveColor() lipgloss.AdaptiveColor {
+func BorderActiveColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().BorderActive()
 }
 
 // BorderSubtleColor returns the subtle border color from the current theme
-func BorderSubtleColor() lipgloss.AdaptiveColor {
+func BorderSubtleColor() compat.AdaptiveColor {
 	return theme.CurrentTheme().BorderSubtle()
 }

+ 0 - 276
packages/tui/internal/theme/ayu.go

@@ -1,276 +0,0 @@
-package theme
-
-import (
-	"github.com/charmbracelet/lipgloss"
-)
-
-// AyuDarkTheme implements the Theme interface with Ayu Dark colors.
-type AyuDarkTheme struct {
-	BaseTheme
-}
-
-// AyuLightTheme implements the Theme interface with Ayu Light colors.
-type AyuLightTheme struct {
-	BaseTheme
-}
-
-// AyuMirageTheme implements the Theme interface with Ayu Mirage colors.
-type AyuMirageTheme struct {
-	BaseTheme
-}
-
-// NewAyuDarkTheme creates a new instance of the Ayu Dark theme.
-func NewAyuDarkTheme() *AyuDarkTheme {
-	// Ayu Dark color palette
-	darkBackground := "#0f1419"
-	darkCurrentLine := "#191f26"
-	darkSelection := "#253340"
-	darkForeground := "#b3b1ad"
-	darkComment := "#5c6773"
-	darkBlue := "#53bdfa"
-	darkCyan := "#90e1c6"
-	darkGreen := "#91b362"
-	darkOrange := "#f9af4f"
-	darkPurple := "#fae994"
-	darkRed := "#ea6c73"
-	darkBorder := "#253340"
-
-	// Light mode approximation for terminal compatibility
-	lightBackground := "#fafafa"
-	lightCurrentLine := "#f0f0f0"
-	lightSelection := "#d1d1d1"
-	lightForeground := "#5c6773"
-	lightComment := "#828c99"
-	lightBlue := "#3199e1"
-	lightCyan := "#46ba94"
-	lightGreen := "#7c9f32"
-	lightOrange := "#f29718"
-	lightPurple := "#9e75c7"
-	lightRed := "#f07171"
-	lightBorder := "#d1d1d1"
-
-	theme := &AyuDarkTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-
-	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkCurrentLine,
-		Light: lightCurrentLine,
-	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  "#0b0e14", // Darker than background
-		Light: "#ffffff", // Lighter than background
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  darkBorder,
-		Light: lightBorder,
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkSelection,
-		Light: lightSelection,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#91b362",
-		Light: "#a5d6a7",
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#ea6c73",
-		Light: "#ef9a9a",
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#1f2c1f",
-		Light: "#e8f5e9",
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#2c1f1f",
-		Light: "#ffebee",
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#1a261a",
-		Light: "#c8e6c9",
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#261a1a",
-		Light: "#ffcdd2",
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	return theme
-}
-
-func init() {
-	// Register all three Ayu theme variants with the theme manager
-	RegisterTheme("ayu", NewAyuDarkTheme())
-}

+ 0 - 244
packages/tui/internal/theme/catppuccin.go

@@ -1,244 +0,0 @@
-package theme
-
-import (
-	catppuccin "github.com/catppuccin/go"
-	"github.com/charmbracelet/lipgloss"
-)
-
-// CatppuccinTheme implements the Theme interface with Catppuccin colors.
-// It provides both dark (Mocha) and light (Latte) variants.
-type CatppuccinTheme struct {
-	BaseTheme
-}
-
-// NewCatppuccinTheme creates a new instance of the Catppuccin theme.
-func NewCatppuccinTheme() *CatppuccinTheme {
-	// Get the Catppuccin palettes
-	mocha := catppuccin.Mocha
-	latte := catppuccin.Latte
-
-	theme := &CatppuccinTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Blue().Hex,
-		Light: latte.Blue().Hex,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Mauve().Hex,
-		Light: latte.Mauve().Hex,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Peach().Hex,
-		Light: latte.Peach().Hex,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Red().Hex,
-		Light: latte.Red().Hex,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Peach().Hex,
-		Light: latte.Peach().Hex,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Green().Hex,
-		Light: latte.Green().Hex,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Blue().Hex,
-		Light: latte.Blue().Hex,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Text().Hex,
-		Light: latte.Text().Hex,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Subtext0().Hex,
-		Light: latte.Subtext0().Hex,
-	}
-
-	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  "#212121", // From existing styles
-		Light: "#EEEEEE", // Light equivalent
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  "#2c2c2c", // From existing styles
-		Light: "#E0E0E0", // Light equivalent
-	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  "#181818", // From existing styles
-		Light: "#F5F5F5", // Light equivalent
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  "#4b4c5c", // From existing styles
-		Light: "#BDBDBD", // Light equivalent
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Blue().Hex,
-		Light: latte.Blue().Hex,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Surface0().Hex,
-		Light: latte.Surface0().Hex,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#478247", // From existing diff.go
-		Light: "#2E7D32", // Light equivalent
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#7C4444", // From existing diff.go
-		Light: "#C62828", // Light equivalent
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0", // From existing diff.go
-		Light: "#757575", // Light equivalent
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0", // From existing diff.go
-		Light: "#757575", // Light equivalent
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#DAFADA", // From existing diff.go
-		Light: "#A5D6A7", // Light equivalent
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#FADADD", // From existing diff.go
-		Light: "#EF9A9A", // Light equivalent
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#303A30", // From existing diff.go
-		Light: "#E8F5E9", // Light equivalent
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3A3030", // From existing diff.go
-		Light: "#FFEBEE", // Light equivalent
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#212121", // From existing diff.go
-		Light: "#F5F5F5", // Light equivalent
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  "#888888", // From existing diff.go
-		Light: "#9E9E9E", // Light equivalent
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#293229", // From existing diff.go
-		Light: "#C8E6C9", // Light equivalent
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#332929", // From existing diff.go
-		Light: "#FFCDD2", // Light equivalent
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Text().Hex,
-		Light: latte.Text().Hex,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Mauve().Hex,
-		Light: latte.Mauve().Hex,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Sky().Hex,
-		Light: latte.Sky().Hex,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Pink().Hex,
-		Light: latte.Pink().Hex,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Green().Hex,
-		Light: latte.Green().Hex,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Yellow().Hex,
-		Light: latte.Yellow().Hex,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Yellow().Hex,
-		Light: latte.Yellow().Hex,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Peach().Hex,
-		Light: latte.Peach().Hex,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Overlay0().Hex,
-		Light: latte.Overlay0().Hex,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Blue().Hex,
-		Light: latte.Blue().Hex,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Sky().Hex,
-		Light: latte.Sky().Hex,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Sapphire().Hex,
-		Light: latte.Sapphire().Hex,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Pink().Hex,
-		Light: latte.Pink().Hex,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Text().Hex,
-		Light: latte.Text().Hex,
-	}
-
-	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Overlay1().Hex,
-		Light: latte.Overlay1().Hex,
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Pink().Hex,
-		Light: latte.Pink().Hex,
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Green().Hex,
-		Light: latte.Green().Hex,
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Sky().Hex,
-		Light: latte.Sky().Hex,
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Yellow().Hex,
-		Light: latte.Yellow().Hex,
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Teal().Hex,
-		Light: latte.Teal().Hex,
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Sky().Hex,
-		Light: latte.Sky().Hex,
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Pink().Hex,
-		Light: latte.Pink().Hex,
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  mocha.Text().Hex,
-		Light: latte.Text().Hex,
-	}
-
-	return theme
-}
-
-func init() {
-	// Register the Catppuccin theme with the theme manager
-	RegisterTheme("catppuccin", NewCatppuccinTheme())
-}

+ 0 - 270
packages/tui/internal/theme/dracula.go

@@ -1,270 +0,0 @@
-package theme
-
-import (
-	"github.com/charmbracelet/lipgloss"
-)
-
-// DraculaTheme implements the Theme interface with Dracula colors.
-// It provides both dark and light variants, though Dracula is primarily a dark theme.
-type DraculaTheme struct {
-	BaseTheme
-}
-
-// NewDraculaTheme creates a new instance of the Dracula theme.
-func NewDraculaTheme() *DraculaTheme {
-	// Dracula color palette
-	// Official colors from https://draculatheme.com/
-	darkBackground := "#282a36"
-	darkCurrentLine := "#44475a"
-	darkSelection := "#44475a"
-	darkForeground := "#f8f8f2"
-	darkComment := "#6272a4"
-	darkCyan := "#8be9fd"
-	darkGreen := "#50fa7b"
-	darkOrange := "#ffb86c"
-	darkPink := "#ff79c6"
-	darkPurple := "#bd93f9"
-	darkRed := "#ff5555"
-	darkYellow := "#f1fa8c"
-	darkBorder := "#44475a"
-
-	// Light mode approximation (Dracula is primarily a dark theme)
-	lightBackground := "#f8f8f2"
-	lightCurrentLine := "#e6e6e6"
-	lightSelection := "#d8d8d8"
-	lightForeground := "#282a36"
-	lightComment := "#6272a4"
-	lightCyan := "#0097a7"
-	lightGreen := "#388e3c"
-	lightOrange := "#f57c00"
-	lightPink := "#d81b60"
-	lightPurple := "#7e57c2"
-	lightRed := "#e53935"
-	lightYellow := "#fbc02d"
-	lightBorder := "#d8d8d8"
-
-	theme := &DraculaTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkPink,
-		Light: lightPink,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-
-	// Background colors
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkCurrentLine,
-		Light: lightCurrentLine,
-	}
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  "#21222c", // Slightly darker than background
-		Light: "#ffffff", // Slightly lighter than background
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  darkBorder,
-		Light: lightBorder,
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkSelection,
-		Light: lightSelection,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  darkCurrentLine,
-		Light: lightCurrentLine,
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#50fa7b",
-		Light: "#a5d6a7",
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#ff5555",
-		Light: "#ef9a9a",
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#2c3b2c",
-		Light: "#e8f5e9",
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3b2c2c",
-		Light: "#ffebee",
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#253025",
-		Light: "#c8e6c9",
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#302525",
-		Light: "#ffcdd2",
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  darkPink,
-		Light: lightPink,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  darkPink,
-		Light: lightPink,
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  darkPink,
-		Light: lightPink,
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	return theme
-}
-
-func init() {
-	// Register the Dracula theme with the theme manager
-	RegisterTheme("dracula", NewDraculaTheme())
-}

+ 0 - 278
packages/tui/internal/theme/flexoki.go

@@ -1,278 +0,0 @@
-package theme
-
-import (
-	"github.com/charmbracelet/lipgloss"
-)
-
-// Flexoki color palette constants
-const (
-	// Base colors
-	flexokiPaper   = "#FFFCF0" // Paper (lightest)
-	flexokiBase50  = "#F2F0E5" // bg-2 (light)
-	flexokiBase100 = "#E6E4D9" // ui (light)
-	flexokiBase150 = "#DAD8CE" // ui-2 (light)
-	flexokiBase200 = "#CECDC3" // ui-3 (light)
-	flexokiBase300 = "#B7B5AC" // tx-3 (light)
-	flexokiBase500 = "#878580" // tx-2 (light)
-	flexokiBase600 = "#6F6E69" // tx (light)
-	flexokiBase700 = "#575653" // tx-3 (dark)
-	flexokiBase800 = "#403E3C" // ui-3 (dark)
-	flexokiBase850 = "#343331" // ui-2 (dark)
-	flexokiBase900 = "#282726" // ui (dark)
-	flexokiBase950 = "#1C1B1A" // bg-2 (dark)
-	flexokiBlack   = "#100F0F" // bg (darkest)
-
-	// Accent colors - Light theme (600)
-	flexokiRed600     = "#AF3029"
-	flexokiOrange600  = "#BC5215"
-	flexokiYellow600  = "#AD8301"
-	flexokiGreen600   = "#66800B"
-	flexokiCyan600    = "#24837B"
-	flexokiBlue600    = "#205EA6"
-	flexokiPurple600  = "#5E409D"
-	flexokiMagenta600 = "#A02F6F"
-
-	// Accent colors - Dark theme (400)
-	flexokiRed400     = "#D14D41"
-	flexokiOrange400  = "#DA702C"
-	flexokiYellow400  = "#D0A215"
-	flexokiGreen400   = "#879A39"
-	flexokiCyan400    = "#3AA99F"
-	flexokiBlue400    = "#4385BE"
-	flexokiPurple400  = "#8B7EC8"
-	flexokiMagenta400 = "#CE5D97"
-)
-
-// FlexokiTheme implements the Theme interface with Flexoki colors.
-// It provides both dark and light variants.
-type FlexokiTheme struct {
-	BaseTheme
-}
-
-// NewFlexokiTheme creates a new instance of the Flexoki theme.
-func NewFlexokiTheme() *FlexokiTheme {
-	theme := &FlexokiTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBlue400,
-		Light: flexokiBlue600,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiPurple400,
-		Light: flexokiPurple600,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiOrange400,
-		Light: flexokiOrange600,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiRed400,
-		Light: flexokiRed600,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiYellow400,
-		Light: flexokiYellow600,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiGreen400,
-		Light: flexokiGreen600,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiCyan400,
-		Light: flexokiCyan600,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase300,
-		Light: flexokiBase600,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase700,
-		Light: flexokiBase500,
-	}
-
-	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBlack,
-		Light: flexokiPaper,
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase950,
-		Light: flexokiBase50,
-	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase900,
-		Light: flexokiBase100,
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase900,
-		Light: flexokiBase100,
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBlue400,
-		Light: flexokiBlue600,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase850,
-		Light: flexokiBase150,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiGreen400,
-		Light: flexokiGreen600,
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiRed400,
-		Light: flexokiRed600,
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase700,
-		Light: flexokiBase500,
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase700,
-		Light: flexokiBase500,
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiGreen400,
-		Light: flexokiGreen600,
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiRed400,
-		Light: flexokiRed600,
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#1D2419", // Darker green background
-		Light: "#EFF2E2", // Light green background
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#241919", // Darker red background
-		Light: "#F2E2E2", // Light red background
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBlack,
-		Light: flexokiPaper,
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase700,
-		Light: flexokiBase500,
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#1A2017", // Slightly darker green
-		Light: "#E5EBD9", // Light green
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#201717", // Slightly darker red
-		Light: "#EBD9D9", // Light red
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase300,
-		Light: flexokiBase600,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiYellow400,
-		Light: flexokiYellow600,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiCyan400,
-		Light: flexokiCyan600,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiMagenta400,
-		Light: flexokiMagenta600,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiGreen400,
-		Light: flexokiGreen600,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiCyan400,
-		Light: flexokiCyan600,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiYellow400,
-		Light: flexokiYellow600,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiOrange400,
-		Light: flexokiOrange600,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase800,
-		Light: flexokiBase200,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBlue400,
-		Light: flexokiBlue600,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBlue400,
-		Light: flexokiBlue600,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiPurple400,
-		Light: flexokiPurple600,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiMagenta400,
-		Light: flexokiMagenta600,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase300,
-		Light: flexokiBase600,
-	}
-
-	// Syntax highlighting colors (based on Flexoki's mappings)
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase700, // tx-3
-		Light: flexokiBase300, // tx-3
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiGreen400, // gr
-		Light: flexokiGreen600, // gr
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiOrange400, // or
-		Light: flexokiOrange600, // or
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBlue400, // bl
-		Light: flexokiBlue600, // bl
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiCyan400, // cy
-		Light: flexokiCyan600, // cy
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiPurple400, // pu
-		Light: flexokiPurple600, // pu
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiYellow400, // ye
-		Light: flexokiYellow600, // ye
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase500, // tx-2
-		Light: flexokiBase500, // tx-2
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  flexokiBase500, // tx-2
-		Light: flexokiBase500, // tx-2
-	}
-
-	return theme
-}
-
-func init() {
-	// Register the Flexoki theme with the theme manager
-	RegisterTheme("flexoki", NewFlexokiTheme())
-}

+ 0 - 298
packages/tui/internal/theme/gruvbox.go

@@ -1,298 +0,0 @@
-package theme
-
-import (
-	"github.com/charmbracelet/lipgloss"
-)
-
-// Gruvbox color palette constants
-const (
-	// Dark theme colors
-	gruvboxDarkBg0          = "#282828"
-	gruvboxDarkBg0Soft      = "#32302f"
-	gruvboxDarkBg1          = "#3c3836"
-	gruvboxDarkBg2          = "#504945"
-	gruvboxDarkBg3          = "#665c54"
-	gruvboxDarkBg4          = "#7c6f64"
-	gruvboxDarkFg0          = "#fbf1c7"
-	gruvboxDarkFg1          = "#ebdbb2"
-	gruvboxDarkFg2          = "#d5c4a1"
-	gruvboxDarkFg3          = "#bdae93"
-	gruvboxDarkFg4          = "#a89984"
-	gruvboxDarkGray         = "#928374"
-	gruvboxDarkRed          = "#cc241d"
-	gruvboxDarkRedBright    = "#fb4934"
-	gruvboxDarkGreen        = "#98971a"
-	gruvboxDarkGreenBright  = "#b8bb26"
-	gruvboxDarkYellow       = "#d79921"
-	gruvboxDarkYellowBright = "#fabd2f"
-	gruvboxDarkBlue         = "#458588"
-	gruvboxDarkBlueBright   = "#83a598"
-	gruvboxDarkPurple       = "#b16286"
-	gruvboxDarkPurpleBright = "#d3869b"
-	gruvboxDarkAqua         = "#689d6a"
-	gruvboxDarkAquaBright   = "#8ec07c"
-	gruvboxDarkOrange       = "#d65d0e"
-	gruvboxDarkOrangeBright = "#fe8019"
-
-	// Light theme colors
-	gruvboxLightBg0          = "#fbf1c7"
-	gruvboxLightBg0Soft      = "#f2e5bc"
-	gruvboxLightBg1          = "#ebdbb2"
-	gruvboxLightBg2          = "#d5c4a1"
-	gruvboxLightBg3          = "#bdae93"
-	gruvboxLightBg4          = "#a89984"
-	gruvboxLightFg0          = "#282828"
-	gruvboxLightFg1          = "#3c3836"
-	gruvboxLightFg2          = "#504945"
-	gruvboxLightFg3          = "#665c54"
-	gruvboxLightFg4          = "#7c6f64"
-	gruvboxLightGray         = "#928374"
-	gruvboxLightRed          = "#9d0006"
-	gruvboxLightRedBright    = "#cc241d"
-	gruvboxLightGreen        = "#79740e"
-	gruvboxLightGreenBright  = "#98971a"
-	gruvboxLightYellow       = "#b57614"
-	gruvboxLightYellowBright = "#d79921"
-	gruvboxLightBlue         = "#076678"
-	gruvboxLightBlueBright   = "#458588"
-	gruvboxLightPurple       = "#8f3f71"
-	gruvboxLightPurpleBright = "#b16286"
-	gruvboxLightAqua         = "#427b58"
-	gruvboxLightAquaBright   = "#689d6a"
-	gruvboxLightOrange       = "#af3a03"
-	gruvboxLightOrangeBright = "#d65d0e"
-)
-
-// GruvboxTheme implements the Theme interface with Gruvbox colors.
-// It provides both dark and light variants.
-type GruvboxTheme struct {
-	BaseTheme
-}
-
-// NewGruvboxTheme creates a new instance of the Gruvbox theme.
-func NewGruvboxTheme() *GruvboxTheme {
-	theme := &GruvboxTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBlueBright,
-		Light: gruvboxLightBlueBright,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkPurpleBright,
-		Light: gruvboxLightPurpleBright,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkOrangeBright,
-		Light: gruvboxLightOrangeBright,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkRedBright,
-		Light: gruvboxLightRedBright,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkYellowBright,
-		Light: gruvboxLightYellowBright,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkGreenBright,
-		Light: gruvboxLightGreenBright,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBlueBright,
-		Light: gruvboxLightBlueBright,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg1,
-		Light: gruvboxLightFg1,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg4,
-		Light: gruvboxLightFg4,
-	}
-
-	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBg0,
-		Light: gruvboxLightBg0,
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBg1,
-		Light: gruvboxLightBg1,
-	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBg0Soft,
-		Light: gruvboxLightBg0Soft,
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBg2,
-		Light: gruvboxLightBg2,
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBlueBright,
-		Light: gruvboxLightBlueBright,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBg1,
-		Light: gruvboxLightBg1,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkGreenBright,
-		Light: gruvboxLightGreenBright,
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkRedBright,
-		Light: gruvboxLightRedBright,
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg4,
-		Light: gruvboxLightFg4,
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg3,
-		Light: gruvboxLightFg3,
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkGreenBright,
-		Light: gruvboxLightGreenBright,
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkRedBright,
-		Light: gruvboxLightRedBright,
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3C4C3C", // Darker green background
-		Light: "#E8F5E9", // Light green background
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#4C3C3C", // Darker red background
-		Light: "#FFEBEE", // Light red background
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBg0,
-		Light: gruvboxLightBg0,
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg4,
-		Light: gruvboxLightFg4,
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#32432F", // Slightly darker green
-		Light: "#C8E6C9", // Light green
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#43322F", // Slightly darker red
-		Light: "#FFCDD2", // Light red
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg1,
-		Light: gruvboxLightFg1,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkYellowBright,
-		Light: gruvboxLightYellowBright,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBlueBright,
-		Light: gruvboxLightBlueBright,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkAquaBright,
-		Light: gruvboxLightAquaBright,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkGreenBright,
-		Light: gruvboxLightGreenBright,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkAquaBright,
-		Light: gruvboxLightAquaBright,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkYellowBright,
-		Light: gruvboxLightYellowBright,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkOrangeBright,
-		Light: gruvboxLightOrangeBright,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBg3,
-		Light: gruvboxLightBg3,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBlueBright,
-		Light: gruvboxLightBlueBright,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBlueBright,
-		Light: gruvboxLightBlueBright,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkPurpleBright,
-		Light: gruvboxLightPurpleBright,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkAquaBright,
-		Light: gruvboxLightAquaBright,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg1,
-		Light: gruvboxLightFg1,
-	}
-
-	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkGray,
-		Light: gruvboxLightGray,
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkRedBright,
-		Light: gruvboxLightRedBright,
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkGreenBright,
-		Light: gruvboxLightGreenBright,
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkBlueBright,
-		Light: gruvboxLightBlueBright,
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkYellowBright,
-		Light: gruvboxLightYellowBright,
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkPurpleBright,
-		Light: gruvboxLightPurpleBright,
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkYellow,
-		Light: gruvboxLightYellow,
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkAquaBright,
-		Light: gruvboxLightAquaBright,
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  gruvboxDarkFg1,
-		Light: gruvboxLightFg1,
-	}
-
-	return theme
-}
-
-func init() {
-	// Register the Gruvbox theme with the theme manager
-	RegisterTheme("gruvbox", NewGruvboxTheme())
-}

+ 2 - 3
packages/tui/internal/theme/manager.go

@@ -6,8 +6,7 @@ import (
 	"slices"
 	"strings"
 	"sync"
-
-	"github.com/alecthomas/chroma/v2/styles"
+	// "github.com/alecthomas/chroma/v2/styles"
 )
 
 // Manager handles theme registration, selection, and retrieval.
@@ -46,7 +45,7 @@ func RegisterTheme(name string, theme Theme) {
 func SetTheme(name string) error {
 	globalManager.mu.Lock()
 	defer globalManager.mu.Unlock()
-	delete(styles.Registry, "charm")
+	// delete(styles.Registry, "charm")
 
 	// Handle custom theme
 	// if name == "custom" {

+ 0 - 269
packages/tui/internal/theme/monokai.go

@@ -1,269 +0,0 @@
-package theme
-
-import (
-	"github.com/charmbracelet/lipgloss"
-)
-
-// MonokaiProTheme implements the Theme interface with Monokai Pro colors.
-// It provides both dark and light variants.
-type MonokaiProTheme struct {
-	BaseTheme
-}
-
-// NewMonokaiProTheme creates a new instance of the Monokai Pro theme.
-func NewMonokaiProTheme() *MonokaiProTheme {
-	// Monokai Pro color palette (dark mode)
-	darkBackground := "#2d2a2e"
-	darkCurrentLine := "#403e41"
-	darkSelection := "#5b595c"
-	darkForeground := "#fcfcfa"
-	darkComment := "#727072"
-	darkRed := "#ff6188"
-	darkOrange := "#fc9867"
-	darkYellow := "#ffd866"
-	darkGreen := "#a9dc76"
-	darkCyan := "#78dce8"
-	darkBlue := "#ab9df2"
-	darkPurple := "#ab9df2"
-	darkBorder := "#403e41"
-
-	// Light mode colors (adapted from dark)
-	lightBackground := "#fafafa"
-	lightCurrentLine := "#f0f0f0"
-	lightSelection := "#e5e5e6"
-	lightForeground := "#2d2a2e"
-	lightComment := "#939293"
-	lightRed := "#f92672"
-	lightOrange := "#fd971f"
-	lightYellow := "#e6db74"
-	lightGreen := "#9bca65"
-	lightCyan := "#66d9ef"
-	lightBlue := "#7e75db"
-	lightPurple := "#ae81ff"
-	lightBorder := "#d3d3d3"
-
-	theme := &MonokaiProTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-
-	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkCurrentLine,
-		Light: lightCurrentLine,
-	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  "#221f22", // Slightly darker than background
-		Light: "#ffffff", // Slightly lighter than background
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  darkBorder,
-		Light: lightBorder,
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkSelection,
-		Light: lightSelection,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#a9dc76",
-		Light: "#9bca65",
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#ff6188",
-		Light: "#f92672",
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0",
-		Light: "#757575",
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0",
-		Light: "#757575",
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#c2e7a9",
-		Light: "#c5e0b4",
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#ff8ca6",
-		Light: "#ffb3c8",
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3a4a35",
-		Light: "#e8f5e9",
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#4a3439",
-		Light: "#ffebee",
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  "#888888",
-		Light: "#9e9e9e",
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#2d3a28",
-		Light: "#c8e6c9",
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3d2a2e",
-		Light: "#ffcdd2",
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	return theme
-}
-
-func init() {
-	// Register the Monokai Pro theme with the theme manager
-	RegisterTheme("monokai", NewMonokaiProTheme())
-}

+ 0 - 270
packages/tui/internal/theme/onedark.go

@@ -1,270 +0,0 @@
-package theme
-
-import (
-	"github.com/charmbracelet/lipgloss"
-)
-
-// OneDarkTheme implements the Theme interface with Atom's One Dark colors.
-// It provides both dark and light variants.
-type OneDarkTheme struct {
-	BaseTheme
-}
-
-// NewOneDarkTheme creates a new instance of the One Dark theme.
-func NewOneDarkTheme() *OneDarkTheme {
-	// One Dark color palette
-	// Dark mode colors from Atom One Dark
-	darkBackground := "#282c34"
-	darkCurrentLine := "#2c313c"
-	darkSelection := "#3e4451"
-	darkForeground := "#abb2bf"
-	darkComment := "#5c6370"
-	darkRed := "#e06c75"
-	darkOrange := "#d19a66"
-	darkYellow := "#e5c07b"
-	darkGreen := "#98c379"
-	darkCyan := "#56b6c2"
-	darkBlue := "#61afef"
-	darkPurple := "#c678dd"
-	darkBorder := "#3b4048"
-
-	// Light mode colors from Atom One Light
-	lightBackground := "#fafafa"
-	lightCurrentLine := "#f0f0f0"
-	lightSelection := "#e5e5e6"
-	lightForeground := "#383a42"
-	lightComment := "#a0a1a7"
-	lightRed := "#e45649"
-	lightOrange := "#da8548"
-	lightYellow := "#c18401"
-	lightGreen := "#50a14f"
-	lightCyan := "#0184bc"
-	lightBlue := "#4078f2"
-	lightPurple := "#a626a4"
-	lightBorder := "#d3d3d3"
-
-	theme := &OneDarkTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-
-	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkCurrentLine,
-		Light: lightCurrentLine,
-	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  "#21252b", // Slightly darker than background
-		Light: "#ffffff", // Slightly lighter than background
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  darkBorder,
-		Light: lightBorder,
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkSelection,
-		Light: lightSelection,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#478247",
-		Light: "#2E7D32",
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#7C4444",
-		Light: "#C62828",
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0",
-		Light: "#757575",
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0",
-		Light: "#757575",
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#DAFADA",
-		Light: "#A5D6A7",
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#FADADD",
-		Light: "#EF9A9A",
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#303A30",
-		Light: "#E8F5E9",
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3A3030",
-		Light: "#FFEBEE",
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  "#888888",
-		Light: "#9E9E9E",
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#293229",
-		Light: "#C8E6C9",
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#332929",
-		Light: "#FFCDD2",
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	return theme
-}
-
-func init() {
-	// Register the One Dark theme with the theme manager
-	RegisterTheme("onedark", NewOneDarkTheme())
-}

+ 152 - 151
packages/tui/internal/theme/opencode.go

@@ -1,7 +1,8 @@
 package theme
 
 import (
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
+	"github.com/charmbracelet/lipgloss/v2/compat"
 )
 
 // OpenCodeTheme implements the Theme interface with OpenCode brand colors.
@@ -72,219 +73,219 @@ func NewOpenCodeTheme() *OpenCodeTheme {
 	theme := &OpenCodeTheme{}
 
 	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkPrimary,
-		Light: lightPrimary,
+	theme.PrimaryColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPrimary),
+		Light: lipgloss.Color(lightPrimary),
 	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkSecondary,
-		Light: lightSecondary,
+	theme.SecondaryColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkSecondary),
+		Light: lipgloss.Color(lightSecondary),
 	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  darkAccent,
-		Light: lightAccent,
+	theme.AccentColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkAccent),
+		Light: lipgloss.Color(lightAccent),
 	}
 
 	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
+	theme.ErrorColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkRed),
+		Light: lipgloss.Color(lightRed),
 	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
+	theme.WarningColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkOrange),
+		Light: lipgloss.Color(lightOrange),
 	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
+	theme.SuccessColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkGreen),
+		Light: lipgloss.Color(lightGreen),
 	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.InfoColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
 
 	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.TextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep11,
-		Light: lightStep11,
+	theme.TextMutedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep11),
+		Light: lipgloss.Color(lightStep11),
 	}
 
 	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep1,
-		Light: lightStep1,
+	theme.BackgroundColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep1),
+		Light: lipgloss.Color(lightStep1),
 	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep2,
-		Light: lightStep2,
+	theme.BackgroundSubtleColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep2),
+		Light: lipgloss.Color(lightStep2),
 	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep3,
-		Light: lightStep3,
+	theme.BackgroundElementColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep3),
+		Light: lipgloss.Color(lightStep3),
 	}
 
 	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep7,
-		Light: lightStep7,
+	theme.BorderColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep7),
+		Light: lipgloss.Color(lightStep7),
 	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep8,
-		Light: lightStep8,
+	theme.BorderActiveColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep8),
+		Light: lipgloss.Color(lightStep8),
 	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep6,
-		Light: lightStep6,
+	theme.BorderSubtleColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep6),
+		Light: lipgloss.Color(lightStep6),
 	}
 
 	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#478247",
-		Light: "#2E7D32",
+	theme.DiffAddedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#478247"),
+		Light: lipgloss.Color("#2E7D32"),
 	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#7C4444",
-		Light: "#C62828",
+	theme.DiffRemovedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#7C4444"),
+		Light: lipgloss.Color("#C62828"),
 	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0",
-		Light: "#757575",
+	theme.DiffContextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#a0a0a0"),
+		Light: lipgloss.Color("#757575"),
 	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  "#a0a0a0",
-		Light: "#757575",
+	theme.DiffHunkHeaderColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#a0a0a0"),
+		Light: lipgloss.Color("#757575"),
 	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#DAFADA",
-		Light: "#A5D6A7",
+	theme.DiffHighlightAddedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#DAFADA"),
+		Light: lipgloss.Color("#A5D6A7"),
 	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#FADADD",
-		Light: "#EF9A9A",
+	theme.DiffHighlightRemovedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#FADADD"),
+		Light: lipgloss.Color("#EF9A9A"),
 	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#303A30",
-		Light: "#E8F5E9",
+	theme.DiffAddedBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#303A30"),
+		Light: lipgloss.Color("#E8F5E9"),
 	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3A3030",
-		Light: "#FFEBEE",
+	theme.DiffRemovedBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#3A3030"),
+		Light: lipgloss.Color("#FFEBEE"),
 	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep2,
-		Light: lightStep2,
+	theme.DiffContextBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep2),
+		Light: lipgloss.Color(lightStep2),
 	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep3,
-		Light: lightStep3,
+	theme.DiffLineNumberColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep3),
+		Light: lipgloss.Color(lightStep3),
 	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#293229",
-		Light: "#C8E6C9",
+	theme.DiffAddedLineNumberBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#293229"),
+		Light: lipgloss.Color("#C8E6C9"),
 	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#332929",
-		Light: "#FFCDD2",
+	theme.DiffRemovedLineNumberBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#332929"),
+		Light: lipgloss.Color("#FFCDD2"),
 	}
 
 	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.MarkdownTextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  darkSecondary,
-		Light: lightSecondary,
+	theme.MarkdownHeadingColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkSecondary),
+		Light: lipgloss.Color(lightSecondary),
 	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  darkPrimary,
-		Light: lightPrimary,
+	theme.MarkdownLinkColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPrimary),
+		Light: lipgloss.Color(lightPrimary),
 	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.MarkdownLinkTextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
+	theme.MarkdownCodeColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkGreen),
+		Light: lipgloss.Color(lightGreen),
 	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
+	theme.MarkdownBlockQuoteColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkYellow),
+		Light: lipgloss.Color(lightYellow),
 	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
+	theme.MarkdownEmphColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkYellow),
+		Light: lipgloss.Color(lightYellow),
 	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  darkAccent,
-		Light: lightAccent,
+	theme.MarkdownStrongColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkAccent),
+		Light: lipgloss.Color(lightAccent),
 	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep11,
-		Light: lightStep11,
+	theme.MarkdownHorizontalRuleColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep11),
+		Light: lipgloss.Color(lightStep11),
 	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  darkPrimary,
-		Light: lightPrimary,
+	theme.MarkdownListItemColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPrimary),
+		Light: lipgloss.Color(lightPrimary),
 	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.MarkdownListEnumerationColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  darkPrimary,
-		Light: lightPrimary,
+	theme.MarkdownImageColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPrimary),
+		Light: lipgloss.Color(lightPrimary),
 	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.MarkdownImageTextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.MarkdownCodeBlockColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
 
 	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep11,
-		Light: lightStep11,
+	theme.SyntaxCommentColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep11),
+		Light: lipgloss.Color(lightStep11),
 	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  darkSecondary,
-		Light: lightSecondary,
+	theme.SyntaxKeywordColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPrimary),
+		Light: lipgloss.Color(lightPrimary),
 	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  darkPrimary,
-		Light: lightPrimary,
+	theme.SyntaxFunctionColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPrimary),
+		Light: lipgloss.Color(lightPrimary),
 	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
+	theme.SyntaxVariableColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkRed),
+		Light: lipgloss.Color(lightRed),
 	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
+	theme.SyntaxStringColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkGreen),
+		Light: lipgloss.Color(lightGreen),
 	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkAccent,
-		Light: lightAccent,
+	theme.SyntaxNumberColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkAccent),
+		Light: lipgloss.Color(lightAccent),
 	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
+	theme.SyntaxTypeColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkYellow),
+		Light: lipgloss.Color(lightYellow),
 	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.SyntaxOperatorColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.SyntaxPunctuationColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
 
 	return theme

+ 180 - 179
packages/tui/internal/theme/theme.go

@@ -4,231 +4,232 @@ import (
 	"fmt"
 	"regexp"
 
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
+	"github.com/charmbracelet/lipgloss/v2/compat"
 )
 
 // Theme defines the interface for all UI themes in the application.
-// All colors must be defined as lipgloss.AdaptiveColor to support
+// All colors must be defined as compat.AdaptiveColor to support
 // both light and dark terminal backgrounds.
 type Theme interface {
 	// Background colors
-	Background() lipgloss.AdaptiveColor        // Radix 1
-	BackgroundSubtle() lipgloss.AdaptiveColor  // Radix 2
-	BackgroundElement() lipgloss.AdaptiveColor // Radix 3
+	Background() compat.AdaptiveColor        // Radix 1
+	BackgroundSubtle() compat.AdaptiveColor  // Radix 2
+	BackgroundElement() compat.AdaptiveColor // Radix 3
 
 	// Border colors
-	BorderSubtle() lipgloss.AdaptiveColor // Radix 6
-	Border() lipgloss.AdaptiveColor       // Radix 7
-	BorderActive() lipgloss.AdaptiveColor // Radix 8
+	BorderSubtle() compat.AdaptiveColor // Radix 6
+	Border() compat.AdaptiveColor       // Radix 7
+	BorderActive() compat.AdaptiveColor // Radix 8
 
 	// Brand colors
-	Primary() lipgloss.AdaptiveColor // Radix 9
-	Secondary() lipgloss.AdaptiveColor
-	Accent() lipgloss.AdaptiveColor
+	Primary() compat.AdaptiveColor // Radix 9
+	Secondary() compat.AdaptiveColor
+	Accent() compat.AdaptiveColor
 
 	// Text colors
-	TextMuted() lipgloss.AdaptiveColor // Radix 11
-	Text() lipgloss.AdaptiveColor      // Radix 12
+	TextMuted() compat.AdaptiveColor // Radix 11
+	Text() compat.AdaptiveColor      // Radix 12
 
 	// Status colors
-	Error() lipgloss.AdaptiveColor
-	Warning() lipgloss.AdaptiveColor
-	Success() lipgloss.AdaptiveColor
-	Info() lipgloss.AdaptiveColor
+	Error() compat.AdaptiveColor
+	Warning() compat.AdaptiveColor
+	Success() compat.AdaptiveColor
+	Info() compat.AdaptiveColor
 
 	// Diff view colors
-	DiffAdded() lipgloss.AdaptiveColor
-	DiffRemoved() lipgloss.AdaptiveColor
-	DiffContext() lipgloss.AdaptiveColor
-	DiffHunkHeader() lipgloss.AdaptiveColor
-	DiffHighlightAdded() lipgloss.AdaptiveColor
-	DiffHighlightRemoved() lipgloss.AdaptiveColor
-	DiffAddedBg() lipgloss.AdaptiveColor
-	DiffRemovedBg() lipgloss.AdaptiveColor
-	DiffContextBg() lipgloss.AdaptiveColor
-	DiffLineNumber() lipgloss.AdaptiveColor
-	DiffAddedLineNumberBg() lipgloss.AdaptiveColor
-	DiffRemovedLineNumberBg() lipgloss.AdaptiveColor
+	DiffAdded() compat.AdaptiveColor
+	DiffRemoved() compat.AdaptiveColor
+	DiffContext() compat.AdaptiveColor
+	DiffHunkHeader() compat.AdaptiveColor
+	DiffHighlightAdded() compat.AdaptiveColor
+	DiffHighlightRemoved() compat.AdaptiveColor
+	DiffAddedBg() compat.AdaptiveColor
+	DiffRemovedBg() compat.AdaptiveColor
+	DiffContextBg() compat.AdaptiveColor
+	DiffLineNumber() compat.AdaptiveColor
+	DiffAddedLineNumberBg() compat.AdaptiveColor
+	DiffRemovedLineNumberBg() compat.AdaptiveColor
 
 	// Markdown colors
-	MarkdownText() lipgloss.AdaptiveColor
-	MarkdownHeading() lipgloss.AdaptiveColor
-	MarkdownLink() lipgloss.AdaptiveColor
-	MarkdownLinkText() lipgloss.AdaptiveColor
-	MarkdownCode() lipgloss.AdaptiveColor
-	MarkdownBlockQuote() lipgloss.AdaptiveColor
-	MarkdownEmph() lipgloss.AdaptiveColor
-	MarkdownStrong() lipgloss.AdaptiveColor
-	MarkdownHorizontalRule() lipgloss.AdaptiveColor
-	MarkdownListItem() lipgloss.AdaptiveColor
-	MarkdownListEnumeration() lipgloss.AdaptiveColor
-	MarkdownImage() lipgloss.AdaptiveColor
-	MarkdownImageText() lipgloss.AdaptiveColor
-	MarkdownCodeBlock() lipgloss.AdaptiveColor
+	MarkdownText() compat.AdaptiveColor
+	MarkdownHeading() compat.AdaptiveColor
+	MarkdownLink() compat.AdaptiveColor
+	MarkdownLinkText() compat.AdaptiveColor
+	MarkdownCode() compat.AdaptiveColor
+	MarkdownBlockQuote() compat.AdaptiveColor
+	MarkdownEmph() compat.AdaptiveColor
+	MarkdownStrong() compat.AdaptiveColor
+	MarkdownHorizontalRule() compat.AdaptiveColor
+	MarkdownListItem() compat.AdaptiveColor
+	MarkdownListEnumeration() compat.AdaptiveColor
+	MarkdownImage() compat.AdaptiveColor
+	MarkdownImageText() compat.AdaptiveColor
+	MarkdownCodeBlock() compat.AdaptiveColor
 
 	// Syntax highlighting colors
-	SyntaxComment() lipgloss.AdaptiveColor
-	SyntaxKeyword() lipgloss.AdaptiveColor
-	SyntaxFunction() lipgloss.AdaptiveColor
-	SyntaxVariable() lipgloss.AdaptiveColor
-	SyntaxString() lipgloss.AdaptiveColor
-	SyntaxNumber() lipgloss.AdaptiveColor
-	SyntaxType() lipgloss.AdaptiveColor
-	SyntaxOperator() lipgloss.AdaptiveColor
-	SyntaxPunctuation() lipgloss.AdaptiveColor
+	SyntaxComment() compat.AdaptiveColor
+	SyntaxKeyword() compat.AdaptiveColor
+	SyntaxFunction() compat.AdaptiveColor
+	SyntaxVariable() compat.AdaptiveColor
+	SyntaxString() compat.AdaptiveColor
+	SyntaxNumber() compat.AdaptiveColor
+	SyntaxType() compat.AdaptiveColor
+	SyntaxOperator() compat.AdaptiveColor
+	SyntaxPunctuation() compat.AdaptiveColor
 }
 
 // BaseTheme provides a default implementation of the Theme interface
 // that can be embedded in concrete theme implementations.
 type BaseTheme struct {
 	// Background colors
-	BackgroundColor        lipgloss.AdaptiveColor
-	BackgroundSubtleColor  lipgloss.AdaptiveColor
-	BackgroundElementColor lipgloss.AdaptiveColor
+	BackgroundColor        compat.AdaptiveColor
+	BackgroundSubtleColor  compat.AdaptiveColor
+	BackgroundElementColor compat.AdaptiveColor
 
 	// Border colors
-	BorderSubtleColor lipgloss.AdaptiveColor
-	BorderColor       lipgloss.AdaptiveColor
-	BorderActiveColor lipgloss.AdaptiveColor
+	BorderSubtleColor compat.AdaptiveColor
+	BorderColor       compat.AdaptiveColor
+	BorderActiveColor compat.AdaptiveColor
 
 	// Brand colors
-	PrimaryColor   lipgloss.AdaptiveColor
-	SecondaryColor lipgloss.AdaptiveColor
-	AccentColor    lipgloss.AdaptiveColor
+	PrimaryColor   compat.AdaptiveColor
+	SecondaryColor compat.AdaptiveColor
+	AccentColor    compat.AdaptiveColor
 
 	// Text colors
-	TextMutedColor lipgloss.AdaptiveColor
-	TextColor      lipgloss.AdaptiveColor
+	TextMutedColor compat.AdaptiveColor
+	TextColor      compat.AdaptiveColor
 
 	// Status colors
-	ErrorColor   lipgloss.AdaptiveColor
-	WarningColor lipgloss.AdaptiveColor
-	SuccessColor lipgloss.AdaptiveColor
-	InfoColor    lipgloss.AdaptiveColor
+	ErrorColor   compat.AdaptiveColor
+	WarningColor compat.AdaptiveColor
+	SuccessColor compat.AdaptiveColor
+	InfoColor    compat.AdaptiveColor
 
 	// Diff view colors
-	DiffAddedColor               lipgloss.AdaptiveColor
-	DiffRemovedColor             lipgloss.AdaptiveColor
-	DiffContextColor             lipgloss.AdaptiveColor
-	DiffHunkHeaderColor          lipgloss.AdaptiveColor
-	DiffHighlightAddedColor      lipgloss.AdaptiveColor
-	DiffHighlightRemovedColor    lipgloss.AdaptiveColor
-	DiffAddedBgColor             lipgloss.AdaptiveColor
-	DiffRemovedBgColor           lipgloss.AdaptiveColor
-	DiffContextBgColor           lipgloss.AdaptiveColor
-	DiffLineNumberColor          lipgloss.AdaptiveColor
-	DiffAddedLineNumberBgColor   lipgloss.AdaptiveColor
-	DiffRemovedLineNumberBgColor lipgloss.AdaptiveColor
+	DiffAddedColor               compat.AdaptiveColor
+	DiffRemovedColor             compat.AdaptiveColor
+	DiffContextColor             compat.AdaptiveColor
+	DiffHunkHeaderColor          compat.AdaptiveColor
+	DiffHighlightAddedColor      compat.AdaptiveColor
+	DiffHighlightRemovedColor    compat.AdaptiveColor
+	DiffAddedBgColor             compat.AdaptiveColor
+	DiffRemovedBgColor           compat.AdaptiveColor
+	DiffContextBgColor           compat.AdaptiveColor
+	DiffLineNumberColor          compat.AdaptiveColor
+	DiffAddedLineNumberBgColor   compat.AdaptiveColor
+	DiffRemovedLineNumberBgColor compat.AdaptiveColor
 
 	// Markdown colors
-	MarkdownTextColor            lipgloss.AdaptiveColor
-	MarkdownHeadingColor         lipgloss.AdaptiveColor
-	MarkdownLinkColor            lipgloss.AdaptiveColor
-	MarkdownLinkTextColor        lipgloss.AdaptiveColor
-	MarkdownCodeColor            lipgloss.AdaptiveColor
-	MarkdownBlockQuoteColor      lipgloss.AdaptiveColor
-	MarkdownEmphColor            lipgloss.AdaptiveColor
-	MarkdownStrongColor          lipgloss.AdaptiveColor
-	MarkdownHorizontalRuleColor  lipgloss.AdaptiveColor
-	MarkdownListItemColor        lipgloss.AdaptiveColor
-	MarkdownListEnumerationColor lipgloss.AdaptiveColor
-	MarkdownImageColor           lipgloss.AdaptiveColor
-	MarkdownImageTextColor       lipgloss.AdaptiveColor
-	MarkdownCodeBlockColor       lipgloss.AdaptiveColor
+	MarkdownTextColor            compat.AdaptiveColor
+	MarkdownHeadingColor         compat.AdaptiveColor
+	MarkdownLinkColor            compat.AdaptiveColor
+	MarkdownLinkTextColor        compat.AdaptiveColor
+	MarkdownCodeColor            compat.AdaptiveColor
+	MarkdownBlockQuoteColor      compat.AdaptiveColor
+	MarkdownEmphColor            compat.AdaptiveColor
+	MarkdownStrongColor          compat.AdaptiveColor
+	MarkdownHorizontalRuleColor  compat.AdaptiveColor
+	MarkdownListItemColor        compat.AdaptiveColor
+	MarkdownListEnumerationColor compat.AdaptiveColor
+	MarkdownImageColor           compat.AdaptiveColor
+	MarkdownImageTextColor       compat.AdaptiveColor
+	MarkdownCodeBlockColor       compat.AdaptiveColor
 
 	// Syntax highlighting colors
-	SyntaxCommentColor     lipgloss.AdaptiveColor
-	SyntaxKeywordColor     lipgloss.AdaptiveColor
-	SyntaxFunctionColor    lipgloss.AdaptiveColor
-	SyntaxVariableColor    lipgloss.AdaptiveColor
-	SyntaxStringColor      lipgloss.AdaptiveColor
-	SyntaxNumberColor      lipgloss.AdaptiveColor
-	SyntaxTypeColor        lipgloss.AdaptiveColor
-	SyntaxOperatorColor    lipgloss.AdaptiveColor
-	SyntaxPunctuationColor lipgloss.AdaptiveColor
+	SyntaxCommentColor     compat.AdaptiveColor
+	SyntaxKeywordColor     compat.AdaptiveColor
+	SyntaxFunctionColor    compat.AdaptiveColor
+	SyntaxVariableColor    compat.AdaptiveColor
+	SyntaxStringColor      compat.AdaptiveColor
+	SyntaxNumberColor      compat.AdaptiveColor
+	SyntaxTypeColor        compat.AdaptiveColor
+	SyntaxOperatorColor    compat.AdaptiveColor
+	SyntaxPunctuationColor compat.AdaptiveColor
 }
 
 // Implement the Theme interface for BaseTheme
-func (t *BaseTheme) Primary() lipgloss.AdaptiveColor   { return t.PrimaryColor }
-func (t *BaseTheme) Secondary() lipgloss.AdaptiveColor { return t.SecondaryColor }
-func (t *BaseTheme) Accent() lipgloss.AdaptiveColor    { return t.AccentColor }
-
-func (t *BaseTheme) Error() lipgloss.AdaptiveColor   { return t.ErrorColor }
-func (t *BaseTheme) Warning() lipgloss.AdaptiveColor { return t.WarningColor }
-func (t *BaseTheme) Success() lipgloss.AdaptiveColor { return t.SuccessColor }
-func (t *BaseTheme) Info() lipgloss.AdaptiveColor    { return t.InfoColor }
-
-func (t *BaseTheme) Text() lipgloss.AdaptiveColor      { return t.TextColor }
-func (t *BaseTheme) TextMuted() lipgloss.AdaptiveColor { return t.TextMutedColor }
-
-func (t *BaseTheme) Background() lipgloss.AdaptiveColor        { return t.BackgroundColor }
-func (t *BaseTheme) BackgroundSubtle() lipgloss.AdaptiveColor  { return t.BackgroundSubtleColor }
-func (t *BaseTheme) BackgroundElement() lipgloss.AdaptiveColor { return t.BackgroundElementColor }
-
-func (t *BaseTheme) Border() lipgloss.AdaptiveColor       { return t.BorderColor }
-func (t *BaseTheme) BorderActive() lipgloss.AdaptiveColor { return t.BorderActiveColor }
-func (t *BaseTheme) BorderSubtle() lipgloss.AdaptiveColor { return t.BorderSubtleColor }
-
-func (t *BaseTheme) DiffAdded() lipgloss.AdaptiveColor            { return t.DiffAddedColor }
-func (t *BaseTheme) DiffRemoved() lipgloss.AdaptiveColor          { return t.DiffRemovedColor }
-func (t *BaseTheme) DiffContext() lipgloss.AdaptiveColor          { return t.DiffContextColor }
-func (t *BaseTheme) DiffHunkHeader() lipgloss.AdaptiveColor       { return t.DiffHunkHeaderColor }
-func (t *BaseTheme) DiffHighlightAdded() lipgloss.AdaptiveColor   { return t.DiffHighlightAddedColor }
-func (t *BaseTheme) DiffHighlightRemoved() lipgloss.AdaptiveColor { return t.DiffHighlightRemovedColor }
-func (t *BaseTheme) DiffAddedBg() lipgloss.AdaptiveColor          { return t.DiffAddedBgColor }
-func (t *BaseTheme) DiffRemovedBg() lipgloss.AdaptiveColor        { return t.DiffRemovedBgColor }
-func (t *BaseTheme) DiffContextBg() lipgloss.AdaptiveColor        { return t.DiffContextBgColor }
-func (t *BaseTheme) DiffLineNumber() lipgloss.AdaptiveColor       { return t.DiffLineNumberColor }
-func (t *BaseTheme) DiffAddedLineNumberBg() lipgloss.AdaptiveColor {
+func (t *BaseTheme) Primary() compat.AdaptiveColor   { return t.PrimaryColor }
+func (t *BaseTheme) Secondary() compat.AdaptiveColor { return t.SecondaryColor }
+func (t *BaseTheme) Accent() compat.AdaptiveColor    { return t.AccentColor }
+
+func (t *BaseTheme) Error() compat.AdaptiveColor   { return t.ErrorColor }
+func (t *BaseTheme) Warning() compat.AdaptiveColor { return t.WarningColor }
+func (t *BaseTheme) Success() compat.AdaptiveColor { return t.SuccessColor }
+func (t *BaseTheme) Info() compat.AdaptiveColor    { return t.InfoColor }
+
+func (t *BaseTheme) Text() compat.AdaptiveColor      { return t.TextColor }
+func (t *BaseTheme) TextMuted() compat.AdaptiveColor { return t.TextMutedColor }
+
+func (t *BaseTheme) Background() compat.AdaptiveColor        { return t.BackgroundColor }
+func (t *BaseTheme) BackgroundSubtle() compat.AdaptiveColor  { return t.BackgroundSubtleColor }
+func (t *BaseTheme) BackgroundElement() compat.AdaptiveColor { return t.BackgroundElementColor }
+
+func (t *BaseTheme) Border() compat.AdaptiveColor       { return t.BorderColor }
+func (t *BaseTheme) BorderActive() compat.AdaptiveColor { return t.BorderActiveColor }
+func (t *BaseTheme) BorderSubtle() compat.AdaptiveColor { return t.BorderSubtleColor }
+
+func (t *BaseTheme) DiffAdded() compat.AdaptiveColor            { return t.DiffAddedColor }
+func (t *BaseTheme) DiffRemoved() compat.AdaptiveColor          { return t.DiffRemovedColor }
+func (t *BaseTheme) DiffContext() compat.AdaptiveColor          { return t.DiffContextColor }
+func (t *BaseTheme) DiffHunkHeader() compat.AdaptiveColor       { return t.DiffHunkHeaderColor }
+func (t *BaseTheme) DiffHighlightAdded() compat.AdaptiveColor   { return t.DiffHighlightAddedColor }
+func (t *BaseTheme) DiffHighlightRemoved() compat.AdaptiveColor { return t.DiffHighlightRemovedColor }
+func (t *BaseTheme) DiffAddedBg() compat.AdaptiveColor          { return t.DiffAddedBgColor }
+func (t *BaseTheme) DiffRemovedBg() compat.AdaptiveColor        { return t.DiffRemovedBgColor }
+func (t *BaseTheme) DiffContextBg() compat.AdaptiveColor        { return t.DiffContextBgColor }
+func (t *BaseTheme) DiffLineNumber() compat.AdaptiveColor       { return t.DiffLineNumberColor }
+func (t *BaseTheme) DiffAddedLineNumberBg() compat.AdaptiveColor {
 	return t.DiffAddedLineNumberBgColor
 }
-func (t *BaseTheme) DiffRemovedLineNumberBg() lipgloss.AdaptiveColor {
+func (t *BaseTheme) DiffRemovedLineNumberBg() compat.AdaptiveColor {
 	return t.DiffRemovedLineNumberBgColor
 }
 
-func (t *BaseTheme) MarkdownText() lipgloss.AdaptiveColor       { return t.MarkdownTextColor }
-func (t *BaseTheme) MarkdownHeading() lipgloss.AdaptiveColor    { return t.MarkdownHeadingColor }
-func (t *BaseTheme) MarkdownLink() lipgloss.AdaptiveColor       { return t.MarkdownLinkColor }
-func (t *BaseTheme) MarkdownLinkText() lipgloss.AdaptiveColor   { return t.MarkdownLinkTextColor }
-func (t *BaseTheme) MarkdownCode() lipgloss.AdaptiveColor       { return t.MarkdownCodeColor }
-func (t *BaseTheme) MarkdownBlockQuote() lipgloss.AdaptiveColor { return t.MarkdownBlockQuoteColor }
-func (t *BaseTheme) MarkdownEmph() lipgloss.AdaptiveColor       { return t.MarkdownEmphColor }
-func (t *BaseTheme) MarkdownStrong() lipgloss.AdaptiveColor     { return t.MarkdownStrongColor }
-func (t *BaseTheme) MarkdownHorizontalRule() lipgloss.AdaptiveColor {
+func (t *BaseTheme) MarkdownText() compat.AdaptiveColor       { return t.MarkdownTextColor }
+func (t *BaseTheme) MarkdownHeading() compat.AdaptiveColor    { return t.MarkdownHeadingColor }
+func (t *BaseTheme) MarkdownLink() compat.AdaptiveColor       { return t.MarkdownLinkColor }
+func (t *BaseTheme) MarkdownLinkText() compat.AdaptiveColor   { return t.MarkdownLinkTextColor }
+func (t *BaseTheme) MarkdownCode() compat.AdaptiveColor       { return t.MarkdownCodeColor }
+func (t *BaseTheme) MarkdownBlockQuote() compat.AdaptiveColor { return t.MarkdownBlockQuoteColor }
+func (t *BaseTheme) MarkdownEmph() compat.AdaptiveColor       { return t.MarkdownEmphColor }
+func (t *BaseTheme) MarkdownStrong() compat.AdaptiveColor     { return t.MarkdownStrongColor }
+func (t *BaseTheme) MarkdownHorizontalRule() compat.AdaptiveColor {
 	return t.MarkdownHorizontalRuleColor
 }
-func (t *BaseTheme) MarkdownListItem() lipgloss.AdaptiveColor { return t.MarkdownListItemColor }
-func (t *BaseTheme) MarkdownListEnumeration() lipgloss.AdaptiveColor {
+func (t *BaseTheme) MarkdownListItem() compat.AdaptiveColor { return t.MarkdownListItemColor }
+func (t *BaseTheme) MarkdownListEnumeration() compat.AdaptiveColor {
 	return t.MarkdownListEnumerationColor
 }
-func (t *BaseTheme) MarkdownImage() lipgloss.AdaptiveColor     { return t.MarkdownImageColor }
-func (t *BaseTheme) MarkdownImageText() lipgloss.AdaptiveColor { return t.MarkdownImageTextColor }
-func (t *BaseTheme) MarkdownCodeBlock() lipgloss.AdaptiveColor { return t.MarkdownCodeBlockColor }
-
-func (t *BaseTheme) SyntaxComment() lipgloss.AdaptiveColor     { return t.SyntaxCommentColor }
-func (t *BaseTheme) SyntaxKeyword() lipgloss.AdaptiveColor     { return t.SyntaxKeywordColor }
-func (t *BaseTheme) SyntaxFunction() lipgloss.AdaptiveColor    { return t.SyntaxFunctionColor }
-func (t *BaseTheme) SyntaxVariable() lipgloss.AdaptiveColor    { return t.SyntaxVariableColor }
-func (t *BaseTheme) SyntaxString() lipgloss.AdaptiveColor      { return t.SyntaxStringColor }
-func (t *BaseTheme) SyntaxNumber() lipgloss.AdaptiveColor      { return t.SyntaxNumberColor }
-func (t *BaseTheme) SyntaxType() lipgloss.AdaptiveColor        { return t.SyntaxTypeColor }
-func (t *BaseTheme) SyntaxOperator() lipgloss.AdaptiveColor    { return t.SyntaxOperatorColor }
-func (t *BaseTheme) SyntaxPunctuation() lipgloss.AdaptiveColor { return t.SyntaxPunctuationColor }
-
-// ParseAdaptiveColor parses a color value from the config file into a lipgloss.AdaptiveColor.
+func (t *BaseTheme) MarkdownImage() compat.AdaptiveColor     { return t.MarkdownImageColor }
+func (t *BaseTheme) MarkdownImageText() compat.AdaptiveColor { return t.MarkdownImageTextColor }
+func (t *BaseTheme) MarkdownCodeBlock() compat.AdaptiveColor { return t.MarkdownCodeBlockColor }
+
+func (t *BaseTheme) SyntaxComment() compat.AdaptiveColor     { return t.SyntaxCommentColor }
+func (t *BaseTheme) SyntaxKeyword() compat.AdaptiveColor     { return t.SyntaxKeywordColor }
+func (t *BaseTheme) SyntaxFunction() compat.AdaptiveColor    { return t.SyntaxFunctionColor }
+func (t *BaseTheme) SyntaxVariable() compat.AdaptiveColor    { return t.SyntaxVariableColor }
+func (t *BaseTheme) SyntaxString() compat.AdaptiveColor      { return t.SyntaxStringColor }
+func (t *BaseTheme) SyntaxNumber() compat.AdaptiveColor      { return t.SyntaxNumberColor }
+func (t *BaseTheme) SyntaxType() compat.AdaptiveColor        { return t.SyntaxTypeColor }
+func (t *BaseTheme) SyntaxOperator() compat.AdaptiveColor    { return t.SyntaxOperatorColor }
+func (t *BaseTheme) SyntaxPunctuation() compat.AdaptiveColor { return t.SyntaxPunctuationColor }
+
+// ParseAdaptiveColor parses a color value from the config file into a compat.AdaptiveColor.
 // It accepts either a string (hex color) or a map with "dark" and "light" keys.
-func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) {
+func ParseAdaptiveColor(value any) (compat.AdaptiveColor, error) {
 	// Regular expression to validate hex color format
 	hexColorRegex := regexp.MustCompile(`^#[0-9a-fA-F]{6}$`)
 
 	// Case 1: String value (same color for both dark and light modes)
 	if hexColor, ok := value.(string); ok {
 		if !hexColorRegex.MatchString(hexColor) {
-			return lipgloss.AdaptiveColor{}, fmt.Errorf("invalid hex color format: %s", hexColor)
+			return compat.AdaptiveColor{}, fmt.Errorf("invalid hex color format: %s", hexColor)
 		}
-		return lipgloss.AdaptiveColor{
-			Dark:  hexColor,
-			Light: hexColor,
+		return compat.AdaptiveColor{
+			Dark:  lipgloss.Color(hexColor),
+			Light: lipgloss.Color(hexColor),
 		}, nil
 	}
 
@@ -236,11 +237,11 @@ func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) {
 	if numericVal, ok := value.(float64); ok {
 		intVal := int(numericVal)
 		if intVal < 0 || intVal > 255 {
-			return lipgloss.AdaptiveColor{}, fmt.Errorf("invalid int color value (must be between 0 and 255): %d", intVal)
+			return compat.AdaptiveColor{}, fmt.Errorf("invalid int color value (must be between 0 and 255): %d", intVal)
 		}
-		return lipgloss.AdaptiveColor{
-			Dark:  fmt.Sprintf("%d", intVal),
-			Light: fmt.Sprintf("%d", intVal),
+		return compat.AdaptiveColor{
+			Dark:  lipgloss.Color(fmt.Sprintf("%d", intVal)),
+			Light: lipgloss.Color(fmt.Sprintf("%d", intVal)),
 		}, nil
 	}
 
@@ -250,7 +251,7 @@ func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) {
 		lightVal, lightOk := colorMap["light"]
 
 		if !darkOk || !lightOk {
-			return lipgloss.AdaptiveColor{}, fmt.Errorf("color map must contain both 'dark' and 'light' keys")
+			return compat.AdaptiveColor{}, fmt.Errorf("color map must contain both 'dark' and 'light' keys")
 		}
 
 		darkHex, darkIsString := darkVal.(string)
@@ -261,27 +262,27 @@ func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) {
 			lightVal, lightIsNumber := lightVal.(float64)
 
 			if !darkIsNumber || !lightIsNumber {
-				return lipgloss.AdaptiveColor{}, fmt.Errorf("color map values must be strings or ints")
+				return compat.AdaptiveColor{}, fmt.Errorf("color map values must be strings or ints")
 			}
 
 			darkInt := int(darkVal)
 			lightInt := int(lightVal)
 
-			return lipgloss.AdaptiveColor{
-				Dark:  fmt.Sprintf("%d", darkInt),
-				Light: fmt.Sprintf("%d", lightInt),
+			return compat.AdaptiveColor{
+				Dark:  lipgloss.Color(fmt.Sprintf("%d", darkInt)),
+				Light: lipgloss.Color(fmt.Sprintf("%d", lightInt)),
 			}, nil
 		}
 
 		if !hexColorRegex.MatchString(darkHex) || !hexColorRegex.MatchString(lightHex) {
-			return lipgloss.AdaptiveColor{}, fmt.Errorf("invalid hex color format")
+			return compat.AdaptiveColor{}, fmt.Errorf("invalid hex color format")
 		}
 
-		return lipgloss.AdaptiveColor{
-			Dark:  darkHex,
-			Light: lightHex,
+		return compat.AdaptiveColor{
+			Dark:  lipgloss.Color(darkHex),
+			Light: lipgloss.Color(lightHex),
 		}, nil
 	}
 
-	return lipgloss.AdaptiveColor{}, fmt.Errorf("color must be either a hex string or an object with dark/light keys")
+	return compat.AdaptiveColor{}, fmt.Errorf("color must be either a hex string or an object with dark/light keys")
 }

+ 152 - 151
packages/tui/internal/theme/tokyonight.go

@@ -1,7 +1,8 @@
 package theme
 
 import (
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/lipgloss/v2"
+	"github.com/charmbracelet/lipgloss/v2/compat"
 )
 
 // TokyoNightTheme implements the Theme interface with Tokyo Night colors.
@@ -70,219 +71,219 @@ func NewTokyoNightTheme() *TokyoNightTheme {
 	theme := &TokyoNightTheme{}
 
 	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
+	theme.PrimaryColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkBlue),
+		Light: lipgloss.Color(lightBlue),
 	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
+	theme.SecondaryColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPurple),
+		Light: lipgloss.Color(lightPurple),
 	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
+	theme.AccentColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkOrange),
+		Light: lipgloss.Color(lightOrange),
 	}
 
 	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
+	theme.ErrorColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkRed),
+		Light: lipgloss.Color(lightRed),
 	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
+	theme.WarningColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkOrange),
+		Light: lipgloss.Color(lightOrange),
 	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
+	theme.SuccessColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkGreen),
+		Light: lipgloss.Color(lightGreen),
 	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
+	theme.InfoColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkBlue),
+		Light: lipgloss.Color(lightBlue),
 	}
 
 	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.TextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep11,
-		Light: lightStep11,
+	theme.TextMutedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep11),
+		Light: lipgloss.Color(lightStep11),
 	}
 
 	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep1,
-		Light: lightStep1,
+	theme.BackgroundColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep1),
+		Light: lipgloss.Color(lightStep1),
 	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep2,
-		Light: lightStep2,
+	theme.BackgroundSubtleColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep2),
+		Light: lipgloss.Color(lightStep2),
 	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep3,
-		Light: lightStep3,
+	theme.BackgroundElementColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep3),
+		Light: lipgloss.Color(lightStep3),
 	}
 
 	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep7,
-		Light: lightStep7,
+	theme.BorderColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep7),
+		Light: lipgloss.Color(lightStep7),
 	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep8,
-		Light: lightStep8,
+	theme.BorderActiveColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep8),
+		Light: lipgloss.Color(lightStep8),
 	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep6,
-		Light: lightStep6,
+	theme.BorderSubtleColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep6),
+		Light: lipgloss.Color(lightStep6),
 	}
 
 	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#4fd6be", // teal from palette
-		Light: "#1e725c",
+	theme.DiffAddedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#4fd6be"), // teal from palette
+		Light: lipgloss.Color("#1e725c"),
 	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#c53b53", // red1 from palette
-		Light: "#c53b53",
+	theme.DiffRemovedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#c53b53"), // red1 from palette
+		Light: lipgloss.Color("#c53b53"),
 	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  "#828bb8", // fg_dark from palette
-		Light: "#7086b5",
+	theme.DiffContextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#828bb8"), // fg_dark from palette
+		Light: lipgloss.Color("#7086b5"),
 	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  "#828bb8", // fg_dark from palette
-		Light: "#7086b5",
+	theme.DiffHunkHeaderColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#828bb8"), // fg_dark from palette
+		Light: lipgloss.Color("#7086b5"),
 	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#b8db87", // git.add from palette
-		Light: "#4db380",
+	theme.DiffHighlightAddedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#b8db87"), // git.add from palette
+		Light: lipgloss.Color("#4db380"),
 	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#e26a75", // git.delete from palette
-		Light: "#f52a65",
+	theme.DiffHighlightRemovedColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#e26a75"), // git.delete from palette
+		Light: lipgloss.Color("#f52a65"),
 	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#20303b",
-		Light: "#d5e5d5",
+	theme.DiffAddedBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#20303b"),
+		Light: lipgloss.Color("#d5e5d5"),
 	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#37222c",
-		Light: "#f7d8db",
+	theme.DiffRemovedBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#37222c"),
+		Light: lipgloss.Color("#f7d8db"),
 	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep2,
-		Light: lightStep2,
+	theme.DiffContextBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep2),
+		Light: lipgloss.Color(lightStep2),
 	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep3, // dark3 from palette
-		Light: lightStep3,
+	theme.DiffLineNumberColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep3), // dark3 from palette
+		Light: lipgloss.Color(lightStep3),
 	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#1b2b34",
-		Light: "#c5d5c5",
+	theme.DiffAddedLineNumberBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#1b2b34"),
+		Light: lipgloss.Color("#c5d5c5"),
 	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#2d1f26",
-		Light: "#e7c8cb",
+	theme.DiffRemovedLineNumberBgColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color("#2d1f26"),
+		Light: lipgloss.Color("#e7c8cb"),
 	}
 
 	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.MarkdownTextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
+	theme.MarkdownHeadingColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPurple),
+		Light: lipgloss.Color(lightPurple),
 	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
+	theme.MarkdownLinkColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkBlue),
+		Light: lipgloss.Color(lightBlue),
 	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.MarkdownLinkTextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
+	theme.MarkdownCodeColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkGreen),
+		Light: lipgloss.Color(lightGreen),
 	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
+	theme.MarkdownBlockQuoteColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkYellow),
+		Light: lipgloss.Color(lightYellow),
 	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
+	theme.MarkdownEmphColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkYellow),
+		Light: lipgloss.Color(lightYellow),
 	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
+	theme.MarkdownStrongColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkOrange),
+		Light: lipgloss.Color(lightOrange),
 	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep11,
-		Light: lightStep11,
+	theme.MarkdownHorizontalRuleColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep11),
+		Light: lipgloss.Color(lightStep11),
 	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
+	theme.MarkdownListItemColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkBlue),
+		Light: lipgloss.Color(lightBlue),
 	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.MarkdownListEnumerationColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
+	theme.MarkdownImageColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkBlue),
+		Light: lipgloss.Color(lightBlue),
 	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.MarkdownImageTextColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.MarkdownCodeBlockColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
 
 	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep11,
-		Light: lightStep11,
+	theme.SyntaxCommentColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep11),
+		Light: lipgloss.Color(lightStep11),
 	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
+	theme.SyntaxKeywordColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkPurple),
+		Light: lipgloss.Color(lightPurple),
 	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
+	theme.SyntaxFunctionColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkBlue),
+		Light: lipgloss.Color(lightBlue),
 	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
+	theme.SyntaxVariableColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkRed),
+		Light: lipgloss.Color(lightRed),
 	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
+	theme.SyntaxStringColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkGreen),
+		Light: lipgloss.Color(lightGreen),
 	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
+	theme.SyntaxNumberColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkOrange),
+		Light: lipgloss.Color(lightOrange),
 	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
+	theme.SyntaxTypeColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkYellow),
+		Light: lipgloss.Color(lightYellow),
 	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
+	theme.SyntaxOperatorColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkCyan),
+		Light: lipgloss.Color(lightCyan),
 	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  darkStep12,
-		Light: lightStep12,
+	theme.SyntaxPunctuationColor = compat.AdaptiveColor{
+		Dark:  lipgloss.Color(darkStep12),
+		Light: lipgloss.Color(lightStep12),
 	}
 
 	return theme

+ 0 - 272
packages/tui/internal/theme/tron.go

@@ -1,272 +0,0 @@
-package theme
-
-import (
-	"github.com/charmbracelet/lipgloss"
-)
-
-// TronTheme implements the Theme interface with Tron-inspired colors.
-// It provides both dark and light variants, though Tron is primarily a dark theme.
-type TronTheme struct {
-	BaseTheme
-}
-
-// NewTronTheme creates a new instance of the Tron theme.
-func NewTronTheme() *TronTheme {
-	// Tron color palette
-	// Inspired by the Tron movie's neon aesthetic
-	darkBackground := "#0c141f"
-	darkCurrentLine := "#1a2633"
-	darkSelection := "#1a2633"
-	darkForeground := "#caf0ff"
-	darkComment := "#4d6b87"
-	darkCyan := "#00d9ff"
-	darkBlue := "#007fff"
-	darkOrange := "#ff9000"
-	darkPink := "#ff00a0"
-	darkPurple := "#b73fff"
-	darkRed := "#ff3333"
-	darkYellow := "#ffcc00"
-	darkGreen := "#00ff8f"
-	darkBorder := "#1a2633"
-
-	// Light mode approximation
-	lightBackground := "#f0f8ff"
-	lightCurrentLine := "#e0f0ff"
-	lightSelection := "#d0e8ff"
-	lightForeground := "#0c141f"
-	lightComment := "#4d6b87"
-	lightCyan := "#0097b3"
-	lightBlue := "#0066cc"
-	lightOrange := "#cc7300"
-	lightPink := "#cc0080"
-	lightPurple := "#9932cc"
-	lightRed := "#cc2929"
-	lightYellow := "#cc9900"
-	lightGreen := "#00cc72"
-	lightBorder := "#d0e8ff"
-
-	theme := &TronTheme{}
-
-	// Base colors
-	theme.PrimaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.SecondaryColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.AccentColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-
-	// Status colors
-	theme.ErrorColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.WarningColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SuccessColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.InfoColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-
-	// Text colors
-	theme.TextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.TextMutedColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-
-	// Background colors
-	theme.BackgroundColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.BackgroundSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkCurrentLine,
-		Light: lightCurrentLine,
-	}
-	theme.BackgroundElementColor = lipgloss.AdaptiveColor{
-		Dark:  "#070d14", // Slightly darker than background
-		Light: "#ffffff", // Slightly lighter than background
-	}
-
-	// Border colors
-	theme.BorderColor = lipgloss.AdaptiveColor{
-		Dark:  darkBorder,
-		Light: lightBorder,
-	}
-	theme.BorderActiveColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.BorderSubtleColor = lipgloss.AdaptiveColor{
-		Dark:  darkSelection,
-		Light: lightSelection,
-	}
-
-	// Diff view colors
-	theme.DiffAddedColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.DiffRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  darkRed,
-		Light: lightRed,
-	}
-	theme.DiffContextColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.DiffHunkHeaderColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.DiffHighlightAddedColor = lipgloss.AdaptiveColor{
-		Dark:  "#00ff8f",
-		Light: "#a5d6a7",
-	}
-	theme.DiffHighlightRemovedColor = lipgloss.AdaptiveColor{
-		Dark:  "#ff3333",
-		Light: "#ef9a9a",
-	}
-	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#0a2a1a",
-		Light: "#e8f5e9",
-	}
-	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#2a0a0a",
-		Light: "#ffebee",
-	}
-	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
-		Dark:  darkBackground,
-		Light: lightBackground,
-	}
-	theme.DiffLineNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#082015",
-		Light: "#c8e6c9",
-	}
-	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#200808",
-		Light: "#ffcdd2",
-	}
-
-	// Markdown colors
-	theme.MarkdownTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-	theme.MarkdownHeadingColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownLinkColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownLinkTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownCodeColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.MarkdownBlockQuoteColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownEmphColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.MarkdownStrongColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.MarkdownHorizontalRuleColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.MarkdownListItemColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownListEnumerationColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownImageColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.MarkdownImageTextColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.MarkdownCodeBlockColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	// Syntax highlighting colors
-	theme.SyntaxCommentColor = lipgloss.AdaptiveColor{
-		Dark:  darkComment,
-		Light: lightComment,
-	}
-	theme.SyntaxKeywordColor = lipgloss.AdaptiveColor{
-		Dark:  darkCyan,
-		Light: lightCyan,
-	}
-	theme.SyntaxFunctionColor = lipgloss.AdaptiveColor{
-		Dark:  darkGreen,
-		Light: lightGreen,
-	}
-	theme.SyntaxVariableColor = lipgloss.AdaptiveColor{
-		Dark:  darkOrange,
-		Light: lightOrange,
-	}
-	theme.SyntaxStringColor = lipgloss.AdaptiveColor{
-		Dark:  darkYellow,
-		Light: lightYellow,
-	}
-	theme.SyntaxNumberColor = lipgloss.AdaptiveColor{
-		Dark:  darkBlue,
-		Light: lightBlue,
-	}
-	theme.SyntaxTypeColor = lipgloss.AdaptiveColor{
-		Dark:  darkPurple,
-		Light: lightPurple,
-	}
-	theme.SyntaxOperatorColor = lipgloss.AdaptiveColor{
-		Dark:  darkPink,
-		Light: lightPink,
-	}
-	theme.SyntaxPunctuationColor = lipgloss.AdaptiveColor{
-		Dark:  darkForeground,
-		Light: lightForeground,
-	}
-
-	return theme
-}
-
-func init() {
-	// Register the Tron theme with the theme manager
-	RegisterTheme("tron", NewTronTheme())
-}

+ 48 - 25
packages/tui/internal/tui/tui.go

@@ -5,11 +5,11 @@ import (
 	"log/slog"
 	"strings"
 
-	"github.com/charmbracelet/bubbles/cursor"
-	"github.com/charmbracelet/bubbles/key"
-	"github.com/charmbracelet/bubbles/spinner"
-	tea "github.com/charmbracelet/bubbletea"
-	"github.com/charmbracelet/lipgloss"
+	"github.com/charmbracelet/bubbles/v2/cursor"
+	"github.com/charmbracelet/bubbles/v2/key"
+	"github.com/charmbracelet/bubbles/v2/spinner"
+	tea "github.com/charmbracelet/bubbletea/v2"
+	"github.com/charmbracelet/lipgloss/v2"
 
 	"github.com/sst/opencode/internal/app"
 	"github.com/sst/opencode/internal/components/core"
@@ -18,6 +18,8 @@ import (
 	"github.com/sst/opencode/internal/page"
 	"github.com/sst/opencode/internal/state"
 	"github.com/sst/opencode/internal/status"
+	"github.com/sst/opencode/internal/styles"
+	"github.com/sst/opencode/internal/theme"
 	"github.com/sst/opencode/internal/util"
 	"github.com/sst/opencode/pkg/client"
 )
@@ -90,16 +92,16 @@ type appModel struct {
 	width, height int
 	currentPage   page.PageID
 	previousPage  page.PageID
-	pages         map[page.PageID]tea.Model
+	pages         map[page.PageID]layout.ModelWithView
 	loadedPages   map[page.PageID]bool
-	status        core.StatusCmp
+	status        core.StatusComponent
 	app           *app.App
 
 	showPermissions bool
-	permissions     dialog.PermissionDialogCmp
+	permissions     dialog.PermissionDialogComponent
 
 	showHelp bool
-	help     dialog.HelpCmp
+	help     dialog.HelpComponent
 
 	showQuit bool
 	quit     dialog.QuitDialog
@@ -118,7 +120,7 @@ type appModel struct {
 	initDialog     dialog.InitDialogCmp
 
 	showFilepicker bool
-	filepicker     dialog.FilepickerCmp
+	filepicker     dialog.FilepickerComponent
 
 	showThemeDialog bool
 	themeDialog     dialog.ThemeDialog
@@ -131,7 +133,12 @@ type appModel struct {
 }
 
 func (a appModel) Init() tea.Cmd {
+	t := theme.CurrentTheme()
 	var cmds []tea.Cmd
+	cmds = append(cmds, tea.SetBackgroundColor(t.Background()))
+	// cmds = append(cmds, tea.SetForegroundColor(t.Background()))
+	cmds = append(cmds, tea.RequestBackgroundColor)
+
 	cmd := a.pages[a.currentPage].Init()
 	a.loadedPages[a.currentPage] = true
 	cmds = append(cmds, cmd)
@@ -170,13 +177,14 @@ func (a appModel) updateAllPages(msg tea.Msg) (tea.Model, tea.Cmd) {
 	var cmd tea.Cmd
 
 	for id := range a.pages {
-		a.pages[id], cmd = a.pages[id].Update(msg)
+		updated, cmd := a.pages[id].Update(msg)
+		a.pages[id] = updated.(layout.ModelWithView)
 		cmds = append(cmds, cmd)
 	}
 
 	s, cmd := a.status.Update(msg)
 	cmds = append(cmds, cmd)
-	a.status = s.(core.StatusCmp)
+	a.status = s.(core.StatusComponent)
 
 	return a, tea.Batch(cmds...)
 }
@@ -185,6 +193,10 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	var cmds []tea.Cmd
 	var cmd tea.Cmd
 	switch msg := msg.(type) {
+	case tea.BackgroundColorMsg:
+		styles.Terminal = &styles.TerminalInfo{
+			BackgroundIsDark: msg.IsDark(),
+		}
 	case cursor.BlinkMsg:
 		return a.updateAllPages(msg)
 	case spinner.TickMsg:
@@ -234,16 +246,17 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		}
 
 		s, _ := a.status.Update(msg)
-		a.status = s.(core.StatusCmp)
-		a.pages[a.currentPage], cmd = a.pages[a.currentPage].Update(msg)
+		a.status = s.(core.StatusComponent)
+		updated, cmd := a.pages[a.currentPage].Update(msg)
+		a.pages[a.currentPage] = updated.(layout.ModelWithView)
 		cmds = append(cmds, cmd)
 
 		prm, permCmd := a.permissions.Update(msg)
-		a.permissions = prm.(dialog.PermissionDialogCmp)
+		a.permissions = prm.(dialog.PermissionDialogComponent)
 		cmds = append(cmds, permCmd)
 
 		help, helpCmd := a.help.Update(msg)
-		a.help = help.(dialog.HelpCmp)
+		a.help = help.(dialog.HelpComponent)
 		cmds = append(cmds, helpCmd)
 
 		session, sessionCmd := a.sessionDialog.Update(msg)
@@ -255,7 +268,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		cmds = append(cmds, commandCmd)
 
 		filepicker, filepickerCmd := a.filepicker.Update(msg)
-		a.filepicker = filepicker.(dialog.FilepickerCmp)
+		a.filepicker = filepicker.(dialog.FilepickerComponent)
 		cmds = append(cmds, filepickerCmd)
 
 		a.initDialog.SetSize(msg.Width, msg.Height)
@@ -342,10 +355,19 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		a.app.Config.Theme = msg.ThemeName
 		a.app.SaveConfig()
 
-		a.pages[a.currentPage], cmd = a.pages[a.currentPage].Update(msg)
+		updated, cmd := a.pages[a.currentPage].Update(msg)
+		if cmd != nil {
+			cmds = append(cmds, cmd)
+		}
+
+		t := theme.CurrentTheme()
+		cmds = append(cmds, tea.SetBackgroundColor(t.Background()))
+		// cmds = append(cmds, tea.RequestBackgroundColor)
+
+		a.pages[a.currentPage] = updated.(layout.ModelWithView)
 		a.showThemeDialog = false
 		status.Info("Theme changed to: " + msg.ThemeName)
-		return a, cmd
+		return a, tea.Batch(cmds...)
 
 	case dialog.ShowInitDialogMsg:
 		a.showInitDialog = msg.Show
@@ -597,13 +619,13 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 
 	default:
 		f, filepickerCmd := a.filepicker.Update(msg)
-		a.filepicker = f.(dialog.FilepickerCmp)
+		a.filepicker = f.(dialog.FilepickerComponent)
 		cmds = append(cmds, filepickerCmd)
 	}
 
 	if a.showFilepicker {
 		f, filepickerCmd := a.filepicker.Update(msg)
-		a.filepicker = f.(dialog.FilepickerCmp)
+		a.filepicker = f.(dialog.FilepickerComponent)
 		cmds = append(cmds, filepickerCmd)
 		// Only block key messages send all other messages down
 		if _, ok := msg.(tea.KeyMsg); ok {
@@ -623,7 +645,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 
 	if a.showPermissions {
 		d, permissionsCmd := a.permissions.Update(msg)
-		a.permissions = d.(dialog.PermissionDialogCmp)
+		a.permissions = d.(dialog.PermissionDialogComponent)
 		cmds = append(cmds, permissionsCmd)
 		// Only block key messages send all other messages down
 		if _, ok := msg.(tea.KeyMsg); ok {
@@ -693,9 +715,10 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 
 	s, cmd := a.status.Update(msg)
 	cmds = append(cmds, cmd)
-	a.status = s.(core.StatusCmp)
+	a.status = s.(core.StatusComponent)
 
-	a.pages[a.currentPage], cmd = a.pages[a.currentPage].Update(msg)
+	updated, cmd := a.pages[a.currentPage].Update(msg)
+	a.pages[a.currentPage] = updated.(layout.ModelWithView)
 	cmds = append(cmds, cmd)
 	return a, tea.Batch(cmds...)
 }
@@ -930,7 +953,7 @@ func NewModel(app *app.App) tea.Model {
 		toolsDialog:   dialog.NewToolsDialogCmp(),
 		app:           app,
 		commands:      []dialog.Command{},
-		pages: map[page.PageID]tea.Model{
+		pages: map[page.PageID]layout.ModelWithView{
 			page.ChatPage: page.NewChatPage(app),
 		},
 		filepicker: dialog.NewFilepickerCmp(app),

+ 1 - 1
packages/tui/internal/util/util.go

@@ -1,7 +1,7 @@
 package util
 
 import (
-	tea "github.com/charmbracelet/bubbletea"
+	tea "github.com/charmbracelet/bubbletea/v2"
 )
 
 func CmdHandler(msg tea.Msg) tea.Cmd {