mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-13 19:20:06 +00:00
feat: upgrade charmbracelet libs to v2 (bubbletea, lipgloss, bubbles)
Migrate from github.com/charmbracelet/* v1 to charm.land/* v2 vanity imports. Key changes: - bubbletea: View() returns tea.View, KeyMsg -> KeyPressMsg, msg.String() matching - lipgloss: AdaptiveColor replaced with cached dark-bg detection helper - bubbles/textarea: Styles()/SetStyles() pattern, KeyMap.InsertNewline override - bubbles/progress: SetWidth(), WithDefaultBlend(), typed Update return - Input: enter always submits, ctrl+j/alt+enter insert newlines - User message newlines preserved through glamour via \n -> \n\n conversion - glamour stays at v1 (no v2 exists)
This commit is contained in:
+16
-17
@@ -10,7 +10,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/mark3labs/mcphost/internal/agent"
|
||||
"github.com/mark3labs/mcphost/internal/config"
|
||||
@@ -251,22 +250,22 @@ func LoadConfigWithEnvSubstitution(configPath string) error {
|
||||
|
||||
func configToUiTheme(theme config.Theme) ui.Theme {
|
||||
return ui.Theme{
|
||||
Primary: lipgloss.AdaptiveColor(theme.Primary),
|
||||
Secondary: lipgloss.AdaptiveColor(theme.Secondary),
|
||||
Success: lipgloss.AdaptiveColor(theme.Success),
|
||||
Warning: lipgloss.AdaptiveColor(theme.Warning),
|
||||
Error: lipgloss.AdaptiveColor(theme.Error),
|
||||
Info: lipgloss.AdaptiveColor(theme.Info),
|
||||
Text: lipgloss.AdaptiveColor(theme.Text),
|
||||
Muted: lipgloss.AdaptiveColor(theme.Muted),
|
||||
VeryMuted: lipgloss.AdaptiveColor(theme.VeryMuted),
|
||||
Background: lipgloss.AdaptiveColor(theme.Background),
|
||||
Border: lipgloss.AdaptiveColor(theme.Border),
|
||||
MutedBorder: lipgloss.AdaptiveColor(theme.MutedBorder),
|
||||
System: lipgloss.AdaptiveColor(theme.System),
|
||||
Tool: lipgloss.AdaptiveColor(theme.Tool),
|
||||
Accent: lipgloss.AdaptiveColor(theme.Accent),
|
||||
Highlight: lipgloss.AdaptiveColor(theme.Highlight),
|
||||
Primary: ui.AdaptiveColor(theme.Primary.Light, theme.Primary.Dark),
|
||||
Secondary: ui.AdaptiveColor(theme.Secondary.Light, theme.Secondary.Dark),
|
||||
Success: ui.AdaptiveColor(theme.Success.Light, theme.Success.Dark),
|
||||
Warning: ui.AdaptiveColor(theme.Warning.Light, theme.Warning.Dark),
|
||||
Error: ui.AdaptiveColor(theme.Error.Light, theme.Error.Dark),
|
||||
Info: ui.AdaptiveColor(theme.Info.Light, theme.Info.Dark),
|
||||
Text: ui.AdaptiveColor(theme.Text.Light, theme.Text.Dark),
|
||||
Muted: ui.AdaptiveColor(theme.Muted.Light, theme.Muted.Dark),
|
||||
VeryMuted: ui.AdaptiveColor(theme.VeryMuted.Light, theme.VeryMuted.Dark),
|
||||
Background: ui.AdaptiveColor(theme.Background.Light, theme.Background.Dark),
|
||||
Border: ui.AdaptiveColor(theme.Border.Light, theme.Border.Dark),
|
||||
MutedBorder: ui.AdaptiveColor(theme.MutedBorder.Light, theme.MutedBorder.Dark),
|
||||
System: ui.AdaptiveColor(theme.System.Light, theme.System.Dark),
|
||||
Tool: ui.AdaptiveColor(theme.Tool.Light, theme.Tool.Dark),
|
||||
Accent: ui.AdaptiveColor(theme.Accent.Light, theme.Accent.Dark),
|
||||
Highlight: ui.AdaptiveColor(theme.Highlight.Light, theme.Highlight.Dark),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
module github.com/mark3labs/mcphost
|
||||
|
||||
go 1.24.0
|
||||
go 1.24.2
|
||||
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
charm.land/bubbles/v2 v2.0.0
|
||||
charm.land/bubbletea/v2 v2.0.0
|
||||
charm.land/lipgloss/v2 v2.0.0
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.6.0
|
||||
github.com/PuerkitoBio/goquery v1.10.3
|
||||
github.com/bytedance/sonic v1.15.0
|
||||
github.com/charmbracelet/fang v0.4.0
|
||||
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
|
||||
github.com/charmbracelet/fang v0.4.4
|
||||
github.com/cloudwego/eino v0.7.13
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.12
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.8
|
||||
@@ -54,13 +56,18 @@ require (
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.3.2 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.4.2 // indirect
|
||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta1 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20250902204034-1cdc10c66d5b // indirect
|
||||
github.com/charmbracelet/x/exp/color v0.0.0-20250902204034-1cdc10c66d5b // indirect
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250902204034-1cdc10c66d5b // indirect
|
||||
github.com/charmbracelet/x/termios v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.2.2 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250826113018-8c6f6358d4bb // indirect
|
||||
github.com/djherbis/times v1.6.0 // indirect
|
||||
@@ -142,24 +149,19 @@ require (
|
||||
|
||||
require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/charmbracelet/bubbles v0.21.0
|
||||
github.com/charmbracelet/bubbletea v1.3.10
|
||||
github.com/charmbracelet/glamour v0.10.0
|
||||
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/charmbracelet/x/ansi v0.11.6 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.2 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.20 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s=
|
||||
charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI=
|
||||
charm.land/bubbletea/v2 v2.0.0 h1:p0d6CtWyJXJ9GfzMpUUqbP/XUUhhlk06+vCKWmox1wQ=
|
||||
charm.land/bubbletea/v2 v2.0.0/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=
|
||||
charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo=
|
||||
charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14=
|
||||
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
|
||||
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
|
||||
@@ -57,8 +63,8 @@ github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE=
|
||||
github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM=
|
||||
github.com/aymanbagabas/go-udiff v0.4.0/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
@@ -78,36 +84,40 @@ github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9V
|
||||
github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
|
||||
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||
github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
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/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
||||
github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI=
|
||||
github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI=
|
||||
github.com/charmbracelet/fang v0.4.0 h1:boBxmdcFghTeotqkD2itXi7SMBozdIlcslRqjboSJDg=
|
||||
github.com/charmbracelet/fang v0.4.0/go.mod h1:9gCUAHmVx5BwSafeyNr3GI0GgvlB1WYjL21SkPp1jyU=
|
||||
github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY=
|
||||
github.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8=
|
||||
github.com/charmbracelet/fang v0.4.4 h1:G4qKxF6or/eTPgmAolwPuRNyuci3hTUGGX1rj1YkHJY=
|
||||
github.com/charmbracelet/fang v0.4.4/go.mod h1:P5/DNb9DddQ0Z0dbc0P3ol4/ix5Po7Ofr2KMBfAqoCo=
|
||||
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/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
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.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
|
||||
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98=
|
||||
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
|
||||
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20250902204034-1cdc10c66d5b h1:U9SnQTnrxy8y3gEpxhpBS3ztHAR7IvL0CjvFHOR4sbE=
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20250902204034-1cdc10c66d5b/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0=
|
||||
github.com/charmbracelet/x/exp/color v0.0.0-20250902204034-1cdc10c66d5b h1:x4wRlDV7e7qM6yYS06W6wMKh6z1NeD1+DTjvOm2grzo=
|
||||
github.com/charmbracelet/x/exp/color v0.0.0-20250902204034-1cdc10c66d5b/go.mod h1:hk/GyTELmEgX54pBAOHcFvH8Xed53JWo/g8kJXFo/PI=
|
||||
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/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250902204034-1cdc10c66d5b h1:DZ2Li1O0j+wWw6AgEUDrODB7PAIKpmOy65yu1UBPYc4=
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250902204034-1cdc10c66d5b/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms=
|
||||
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/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
|
||||
github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
|
||||
github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM=
|
||||
github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=
|
||||
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/cloudwego/eino v0.7.13 h1:Ku7hY+83gGJJjf4On3UgqjC57UcA+DXe0tqAZiNDDew=
|
||||
@@ -134,8 +144,6 @@ github.com/eino-contrib/jsonschema v1.0.3 h1:2Kfsm1xlMV0ssY2nuxshS4AwbLFuqmPmzIj
|
||||
github.com/eino-contrib/jsonschema v1.0.3/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4=
|
||||
github.com/eino-contrib/ollama v0.1.0 h1:z1NaMdKW6X1ftP8g5xGGR5zDRPUtuTKFq35vBQgxsN4=
|
||||
github.com/eino-contrib/ollama v0.1.0/go.mod h1:mYsQ7b3DeqY8bHPuD3MZJYTqkgyL6LoemxoP/B7ZNhA=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
|
||||
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
@@ -216,8 +224,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mark3labs/mcp-filesystem-server v0.11.1 h1:7uKIZRMaKWfgvtDj/uLAvo0+7Mwb8gxo5DJywhqFW88=
|
||||
@@ -228,11 +236,9 @@ github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=
|
||||
github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/meguminnnnnnnnn/go-openai v0.0.0-20250821095446-07791bea23a0 h1:nIohpHs1ViKR0SVgW/cbBstHjmnqFZDM9RqgX9m9Xu8=
|
||||
github.com/meguminnnnnnnnn/go-openai v0.0.0-20250821095446-07791bea23a0/go.mod h1:qs96ysDmxhE4BZoU45I43zcyfnaYxU3X+aRzLko/htY=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
@@ -246,8 +252,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/mango v0.2.0 h1:iNNc0c5VLQ6fsMgAqGQofByNUBH2Q2nEbD6TaI+5yyQ=
|
||||
@@ -426,14 +430,13 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -447,8 +450,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
@@ -463,8 +463,8 @@ func (m escListenerModel) Init() tea.Cmd {
|
||||
|
||||
func (m escListenerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
if msg.Type == tea.KeyEsc {
|
||||
case tea.KeyPressMsg:
|
||||
if msg.String() == "esc" {
|
||||
// Signal ESC was pressed
|
||||
select {
|
||||
case m.escPressed <- true:
|
||||
@@ -476,8 +476,8 @@ func (m escListenerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m escListenerModel) View() string {
|
||||
return "" // No visual output needed
|
||||
func (m escListenerModel) View() tea.View {
|
||||
return tea.NewView("") // No visual output needed
|
||||
}
|
||||
|
||||
// listenForESC listens for ESC key press using Bubble Tea and returns true if detected
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"image/color"
|
||||
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
// blockRenderer handles rendering of content blocks with configurable options
|
||||
type blockRenderer struct {
|
||||
align *lipgloss.Position
|
||||
borderColor *lipgloss.AdaptiveColor
|
||||
borderColor *color.Color
|
||||
fullWidth bool
|
||||
paddingTop int
|
||||
paddingBottom int
|
||||
@@ -42,9 +44,9 @@ func WithAlign(align lipgloss.Position) renderingOption {
|
||||
// WithBorderColor returns a renderingOption that sets the border color
|
||||
// for the block. The color parameter uses lipgloss.AdaptiveColor to support
|
||||
// both light and dark terminal themes automatically.
|
||||
func WithBorderColor(color lipgloss.AdaptiveColor) renderingOption {
|
||||
return func(c *blockRenderer) {
|
||||
c.borderColor = &color
|
||||
func WithBorderColor(c color.Color) renderingOption {
|
||||
return func(br *blockRenderer) {
|
||||
br.borderColor = &c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,16 +143,13 @@ func renderContentBlock(content string, containerWidth int, options ...rendering
|
||||
}
|
||||
|
||||
// Default to transparent/no border color
|
||||
borderColor := lipgloss.AdaptiveColor{Light: "", Dark: ""}
|
||||
var borderColor color.Color = lipgloss.NoColor{}
|
||||
if renderer.borderColor != nil {
|
||||
borderColor = *renderer.borderColor
|
||||
}
|
||||
|
||||
// Very muted color for the opposite border
|
||||
mutedOppositeBorder := lipgloss.AdaptiveColor{
|
||||
Light: "#F3F4F6", // Very light gray, barely visible
|
||||
Dark: "#1F2937", // Very dark gray, barely visible
|
||||
}
|
||||
mutedOppositeBorder := AdaptiveColor("#F3F4F6", "#1F2937")
|
||||
|
||||
switch align {
|
||||
case lipgloss.Left:
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
// CompactRenderer handles rendering messages in a space-efficient compact format,
|
||||
@@ -41,6 +41,10 @@ func (r *CompactRenderer) RenderUserMessage(content string, timestamp time.Time)
|
||||
symbol := lipgloss.NewStyle().Foreground(theme.Secondary).Render(">")
|
||||
label := lipgloss.NewStyle().Foreground(theme.Secondary).Bold(true).Render("User")
|
||||
|
||||
// Convert single newlines to paragraph breaks so they survive glamour's
|
||||
// markdown rendering (glamour treats single \n as a soft break).
|
||||
content = strings.ReplaceAll(content, "\n", "\n\n")
|
||||
|
||||
// Format content for user messages (preserve formatting, no truncation)
|
||||
compactContent := r.formatUserAssistantContent(content)
|
||||
|
||||
|
||||
@@ -2,12 +2,27 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"os"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
// Enhanced styling utilities and theme definitions
|
||||
|
||||
// isDarkBg caches the terminal background detection result at package init.
|
||||
var isDarkBg = lipgloss.HasDarkBackground(os.Stdin, os.Stdout)
|
||||
|
||||
// AdaptiveColor picks between a light-mode and dark-mode hex color string
|
||||
// based on the detected terminal background. This replaces the old
|
||||
// lipgloss.AdaptiveColor{Light: ..., Dark: ...} pattern from v1.
|
||||
func AdaptiveColor(light, dark string) color.Color {
|
||||
if isDarkBg {
|
||||
return lipgloss.Color(dark)
|
||||
}
|
||||
return lipgloss.Color(light)
|
||||
}
|
||||
|
||||
// Global theme instance
|
||||
var currentTheme = DefaultTheme()
|
||||
|
||||
@@ -27,22 +42,22 @@ func SetTheme(theme Theme) {
|
||||
// both light and dark terminal modes through adaptive colors. It includes semantic
|
||||
// colors for different message types and UI elements, based on the Catppuccin color palette.
|
||||
type Theme struct {
|
||||
Primary lipgloss.AdaptiveColor
|
||||
Secondary lipgloss.AdaptiveColor
|
||||
Success lipgloss.AdaptiveColor
|
||||
Warning lipgloss.AdaptiveColor
|
||||
Error lipgloss.AdaptiveColor
|
||||
Info lipgloss.AdaptiveColor
|
||||
Text lipgloss.AdaptiveColor
|
||||
Muted lipgloss.AdaptiveColor
|
||||
VeryMuted lipgloss.AdaptiveColor
|
||||
Background lipgloss.AdaptiveColor
|
||||
Border lipgloss.AdaptiveColor
|
||||
MutedBorder lipgloss.AdaptiveColor
|
||||
System lipgloss.AdaptiveColor
|
||||
Tool lipgloss.AdaptiveColor
|
||||
Accent lipgloss.AdaptiveColor
|
||||
Highlight lipgloss.AdaptiveColor
|
||||
Primary color.Color
|
||||
Secondary color.Color
|
||||
Success color.Color
|
||||
Warning color.Color
|
||||
Error color.Color
|
||||
Info color.Color
|
||||
Text color.Color
|
||||
Muted color.Color
|
||||
VeryMuted color.Color
|
||||
Background color.Color
|
||||
Border color.Color
|
||||
MutedBorder color.Color
|
||||
System color.Color
|
||||
Tool color.Color
|
||||
Accent color.Color
|
||||
Highlight color.Color
|
||||
}
|
||||
|
||||
// DefaultTheme creates and returns the default MCPHost theme based on the Catppuccin
|
||||
@@ -50,70 +65,22 @@ type Theme struct {
|
||||
// pleasant visual experience with carefully selected colors for different UI elements.
|
||||
func DefaultTheme() Theme {
|
||||
return Theme{
|
||||
Primary: lipgloss.AdaptiveColor{
|
||||
Light: "#8839ef", // Latte Mauve
|
||||
Dark: "#cba6f7", // Mocha Mauve
|
||||
},
|
||||
Secondary: lipgloss.AdaptiveColor{
|
||||
Light: "#04a5e5", // Latte Sky
|
||||
Dark: "#89dceb", // Mocha Sky
|
||||
},
|
||||
Success: lipgloss.AdaptiveColor{
|
||||
Light: "#40a02b", // Latte Green
|
||||
Dark: "#a6e3a1", // Mocha Green
|
||||
},
|
||||
Warning: lipgloss.AdaptiveColor{
|
||||
Light: "#df8e1d", // Latte Yellow
|
||||
Dark: "#f9e2af", // Mocha Yellow
|
||||
},
|
||||
Error: lipgloss.AdaptiveColor{
|
||||
Light: "#d20f39", // Latte Red
|
||||
Dark: "#f38ba8", // Mocha Red
|
||||
},
|
||||
Info: lipgloss.AdaptiveColor{
|
||||
Light: "#1e66f5", // Latte Blue
|
||||
Dark: "#89b4fa", // Mocha Blue
|
||||
},
|
||||
Text: lipgloss.AdaptiveColor{
|
||||
Light: "#4c4f69", // Latte Text
|
||||
Dark: "#cdd6f4", // Mocha Text
|
||||
},
|
||||
Muted: lipgloss.AdaptiveColor{
|
||||
Light: "#6c6f85", // Latte Subtext 0
|
||||
Dark: "#a6adc8", // Mocha Subtext 0
|
||||
},
|
||||
VeryMuted: lipgloss.AdaptiveColor{
|
||||
Light: "#9ca0b0", // Latte Overlay 0
|
||||
Dark: "#6c7086", // Mocha Overlay 0
|
||||
},
|
||||
Background: lipgloss.AdaptiveColor{
|
||||
Light: "#eff1f5", // Latte Base
|
||||
Dark: "#1e1e2e", // Mocha Base
|
||||
},
|
||||
Border: lipgloss.AdaptiveColor{
|
||||
Light: "#acb0be", // Latte Surface 2
|
||||
Dark: "#585b70", // Mocha Surface 2
|
||||
},
|
||||
MutedBorder: lipgloss.AdaptiveColor{
|
||||
Light: "#ccd0da", // Latte Surface 0
|
||||
Dark: "#313244", // Mocha Surface 0
|
||||
},
|
||||
System: lipgloss.AdaptiveColor{
|
||||
Light: "#179299", // Latte Teal
|
||||
Dark: "#94e2d5", // Mocha Teal
|
||||
},
|
||||
Tool: lipgloss.AdaptiveColor{
|
||||
Light: "#fe640b", // Latte Peach
|
||||
Dark: "#fab387", // Mocha Peach
|
||||
},
|
||||
Accent: lipgloss.AdaptiveColor{
|
||||
Light: "#ea76cb", // Latte Pink
|
||||
Dark: "#f5c2e7", // Mocha Pink
|
||||
},
|
||||
Highlight: lipgloss.AdaptiveColor{
|
||||
Light: "#df8e1d", // Latte Yellow (for highlights)
|
||||
Dark: "#45475a", // Mocha Surface 1 (subtle highlight)
|
||||
},
|
||||
Primary: AdaptiveColor("#8839ef", "#cba6f7"), // Latte/Mocha Mauve
|
||||
Secondary: AdaptiveColor("#04a5e5", "#89dceb"), // Latte/Mocha Sky
|
||||
Success: AdaptiveColor("#40a02b", "#a6e3a1"), // Latte/Mocha Green
|
||||
Warning: AdaptiveColor("#df8e1d", "#f9e2af"), // Latte/Mocha Yellow
|
||||
Error: AdaptiveColor("#d20f39", "#f38ba8"), // Latte/Mocha Red
|
||||
Info: AdaptiveColor("#1e66f5", "#89b4fa"), // Latte/Mocha Blue
|
||||
Text: AdaptiveColor("#4c4f69", "#cdd6f4"), // Latte/Mocha Text
|
||||
Muted: AdaptiveColor("#6c6f85", "#a6adc8"), // Latte/Mocha Subtext 0
|
||||
VeryMuted: AdaptiveColor("#9ca0b0", "#6c7086"), // Latte/Mocha Overlay 0
|
||||
Background: AdaptiveColor("#eff1f5", "#1e1e2e"), // Latte/Mocha Base
|
||||
Border: AdaptiveColor("#acb0be", "#585b70"), // Latte/Mocha Surface 2
|
||||
MutedBorder: AdaptiveColor("#ccd0da", "#313244"), // Latte/Mocha Surface 0
|
||||
System: AdaptiveColor("#179299", "#94e2d5"), // Latte/Mocha Teal
|
||||
Tool: AdaptiveColor("#fe640b", "#fab387"), // Latte/Mocha Peach
|
||||
Accent: AdaptiveColor("#ea76cb", "#f5c2e7"), // Latte/Mocha Pink
|
||||
Highlight: AdaptiveColor("#df8e1d", "#45475a"), // Latte Yellow / Mocha Surface 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +96,11 @@ func StyleCard(width int, theme Theme) lipgloss.Style {
|
||||
MarginBottom(1)
|
||||
}
|
||||
|
||||
// IsDarkBackground returns the cached terminal background detection result.
|
||||
func IsDarkBackground() bool {
|
||||
return isDarkBg
|
||||
}
|
||||
|
||||
// StyleHeader creates a lipgloss style for primary headers using the theme's
|
||||
// primary color with bold text for emphasis and hierarchy.
|
||||
func StyleHeader(theme Theme) lipgloss.Style {
|
||||
@@ -187,9 +159,9 @@ func StyleInfo(theme Theme) lipgloss.Style {
|
||||
|
||||
// CreateSeparator generates a horizontal separator line with the specified width,
|
||||
// character, and color. Useful for visually dividing sections of content in the UI.
|
||||
func CreateSeparator(width int, char string, color lipgloss.AdaptiveColor) string {
|
||||
func CreateSeparator(width int, char string, c color.Color) string {
|
||||
return lipgloss.NewStyle().
|
||||
Foreground(color).
|
||||
Foreground(c).
|
||||
Width(width).
|
||||
Render(lipgloss.PlaceHorizontal(width, lipgloss.Center, char))
|
||||
}
|
||||
@@ -214,10 +186,10 @@ func CreateProgressBar(width int, percentage float64, theme Theme) string {
|
||||
|
||||
// CreateBadge generates a styled badge or label with inverted colors (text on
|
||||
// colored background) for highlighting important tags, statuses, or categories.
|
||||
func CreateBadge(text string, color lipgloss.AdaptiveColor) string {
|
||||
func CreateBadge(text string, c color.Color) string {
|
||||
return lipgloss.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#FFFFFF", Dark: "#000000"}).
|
||||
Background(color).
|
||||
Foreground(AdaptiveColor("#FFFFFF", "#000000")).
|
||||
Background(c).
|
||||
Padding(0, 1).
|
||||
Bold(true).
|
||||
Render(text)
|
||||
@@ -226,7 +198,7 @@ func CreateBadge(text string, color lipgloss.AdaptiveColor) string {
|
||||
// CreateGradientText creates styled text with a gradient-like effect. Currently
|
||||
// implements a simplified version using the start color only, as true gradients
|
||||
// require more complex terminal capabilities.
|
||||
func CreateGradientText(text string, startColor, endColor lipgloss.AdaptiveColor) string {
|
||||
func CreateGradientText(text string, startColor, endColor color.Color) string {
|
||||
// For now, just use the start color - true gradients would require more complex implementation
|
||||
return lipgloss.NewStyle().
|
||||
Foreground(startColor).
|
||||
@@ -238,32 +210,32 @@ func CreateGradientText(text string, startColor, endColor lipgloss.AdaptiveColor
|
||||
|
||||
// StyleCompactSymbol creates a lipgloss style for message type indicators in
|
||||
// compact mode, using bold colored text to distinguish different message categories.
|
||||
func StyleCompactSymbol(symbol string, color lipgloss.AdaptiveColor) lipgloss.Style {
|
||||
func StyleCompactSymbol(symbol string, c color.Color) lipgloss.Style {
|
||||
return lipgloss.NewStyle().
|
||||
Foreground(color).
|
||||
Foreground(c).
|
||||
Bold(true)
|
||||
}
|
||||
|
||||
// StyleCompactLabel creates a lipgloss style for message labels in compact mode
|
||||
// with fixed width for alignment and bold colored text for readability.
|
||||
func StyleCompactLabel(color lipgloss.AdaptiveColor) lipgloss.Style {
|
||||
func StyleCompactLabel(c color.Color) lipgloss.Style {
|
||||
return lipgloss.NewStyle().
|
||||
Foreground(color).
|
||||
Foreground(c).
|
||||
Bold(true).
|
||||
Width(8)
|
||||
}
|
||||
|
||||
// StyleCompactContent creates a simple lipgloss style for message content in
|
||||
// compact mode, applying only color without additional formatting.
|
||||
func StyleCompactContent(color lipgloss.AdaptiveColor) lipgloss.Style {
|
||||
func StyleCompactContent(c color.Color) lipgloss.Style {
|
||||
return lipgloss.NewStyle().
|
||||
Foreground(color)
|
||||
Foreground(c)
|
||||
}
|
||||
|
||||
// FormatCompactLine assembles a complete compact mode message line with consistent
|
||||
// spacing and styling. Combines a symbol, fixed-width label, and content with their
|
||||
// respective colors to create a uniform appearance across all message types.
|
||||
func FormatCompactLine(symbol, label, content string, symbolColor, labelColor, contentColor lipgloss.AdaptiveColor) string {
|
||||
func FormatCompactLine(symbol, label, content string, symbolColor, labelColor, contentColor color.Color) string {
|
||||
styledSymbol := StyleCompactSymbol(symbol, symbolColor).Render(symbol)
|
||||
styledLabel := StyleCompactLabel(labelColor).Render(label)
|
||||
styledContent := StyleCompactContent(contentColor).Render(content)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
// MessageType represents different categories of messages displayed in the UI,
|
||||
@@ -88,6 +88,10 @@ func (r *MessageRenderer) RenderUserMessage(content string, timestamp time.Time)
|
||||
timeStr := timestamp.Local().Format("15:04")
|
||||
username := getSystemUsername()
|
||||
|
||||
// Convert single newlines to paragraph breaks so they survive glamour's
|
||||
// markdown rendering (glamour treats single \n as a soft break).
|
||||
content = strings.ReplaceAll(content, "\n", "\n\n")
|
||||
|
||||
// Render the message content
|
||||
messageContent := r.renderMarkdown(content, r.width-8) // Account for padding and borders
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/bubbles/progress"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/bubbles/v2/progress"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
var helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#626262")).Render
|
||||
@@ -57,7 +57,7 @@ type ProgressModel struct {
|
||||
// progress bar and initial "Initializing..." status message.
|
||||
func NewProgressModel() ProgressModel {
|
||||
return ProgressModel{
|
||||
progress: progress.New(progress.WithDefaultGradient()),
|
||||
progress: progress.New(progress.WithDefaultBlend()),
|
||||
status: "Initializing...",
|
||||
}
|
||||
}
|
||||
@@ -73,17 +73,18 @@ func (m ProgressModel) Init() tea.Cmd {
|
||||
// triggers program exit on completion or cancellation.
|
||||
func (m ProgressModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
case tea.KeyPressMsg:
|
||||
if msg.String() == "q" || msg.String() == "ctrl+c" {
|
||||
return m, tea.Quit
|
||||
}
|
||||
return m, nil
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.progress.Width = msg.Width - padding*2 - 4
|
||||
if m.progress.Width > maxWidth {
|
||||
m.progress.Width = maxWidth
|
||||
newWidth := msg.Width - padding*2 - 4
|
||||
if newWidth > maxWidth {
|
||||
newWidth = maxWidth
|
||||
}
|
||||
m.progress.SetWidth(newWidth)
|
||||
return m, nil
|
||||
|
||||
case progressErrMsg:
|
||||
@@ -107,8 +108,8 @@ func (m ProgressModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, tea.Batch(cmds...)
|
||||
|
||||
case progress.FrameMsg:
|
||||
progressModel, cmd := m.progress.Update(msg)
|
||||
m.progress = progressModel.(progress.Model)
|
||||
var cmd tea.Cmd
|
||||
m.progress, cmd = m.progress.Update(msg)
|
||||
return m, cmd
|
||||
|
||||
default:
|
||||
@@ -119,23 +120,23 @@ func (m ProgressModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
// View implements the tea.Model interface, rendering the progress bar with
|
||||
// status information and help text. Displays error messages if present or
|
||||
// a completion message when the download finishes.
|
||||
func (m ProgressModel) View() string {
|
||||
func (m ProgressModel) View() tea.View {
|
||||
if m.err != nil {
|
||||
return fmt.Sprintf("Error: %s\n", m.err.Error())
|
||||
return tea.NewView(fmt.Sprintf("Error: %s\n", m.err.Error()))
|
||||
}
|
||||
|
||||
if m.complete {
|
||||
return fmt.Sprintf("\n%s%s\n\n%sComplete!\n",
|
||||
return tea.NewView(fmt.Sprintf("\n%s%s\n\n%sComplete!\n",
|
||||
strings.Repeat(" ", padding),
|
||||
m.progress.View(),
|
||||
strings.Repeat(" ", padding))
|
||||
strings.Repeat(" ", padding)))
|
||||
}
|
||||
|
||||
pad := strings.Repeat(" ", padding)
|
||||
return fmt.Sprintf("\n%s%s\n%s%s\n\n%s",
|
||||
return tea.NewView(fmt.Sprintf("\n%s%s\n%s%s\n\n%s",
|
||||
pad, m.progress.View(),
|
||||
pad, m.status,
|
||||
pad+helpStyle("Press 'q' or Ctrl+C to cancel"))
|
||||
pad+helpStyle("Press 'q' or Ctrl+C to cancel")))
|
||||
}
|
||||
|
||||
// ProgressReader wraps an io.Reader to intercept and parse Ollama pull operation
|
||||
|
||||
@@ -3,10 +3,10 @@ package ui
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/charmbracelet/bubbles/textarea"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/bubbles/v2/key"
|
||||
"charm.land/bubbles/v2/textarea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
// SlashCommandInput provides an interactive text input field with intelligent
|
||||
@@ -41,13 +41,21 @@ func NewSlashCommandInput(width int, title string) *SlashCommandInput {
|
||||
ta.SetHeight(3) // Default to 3 lines like huh
|
||||
ta.Focus()
|
||||
|
||||
// Override InsertNewline so only ctrl+j and alt+enter insert newlines.
|
||||
// Enter always submits the input.
|
||||
ta.KeyMap.InsertNewline = key.NewBinding(
|
||||
key.WithKeys("ctrl+j", "alt+enter"),
|
||||
key.WithHelp("ctrl+j", "insert newline"),
|
||||
)
|
||||
|
||||
// Style the textarea to match huh theme
|
||||
ta.FocusedStyle.Base = lipgloss.NewStyle()
|
||||
ta.FocusedStyle.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
|
||||
ta.FocusedStyle.Text = lipgloss.NewStyle().Foreground(lipgloss.Color("252"))
|
||||
ta.FocusedStyle.Prompt = lipgloss.NewStyle()
|
||||
ta.FocusedStyle.CursorLine = lipgloss.NewStyle()
|
||||
ta.Cursor.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("39"))
|
||||
styles := ta.Styles()
|
||||
styles.Focused.Base = lipgloss.NewStyle()
|
||||
styles.Focused.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
|
||||
styles.Focused.Text = lipgloss.NewStyle().Foreground(lipgloss.Color("252"))
|
||||
styles.Focused.Prompt = lipgloss.NewStyle()
|
||||
styles.Focused.CursorLine = lipgloss.NewStyle()
|
||||
ta.SetStyles(styles)
|
||||
|
||||
return &SlashCommandInput{
|
||||
textarea: ta,
|
||||
@@ -78,25 +86,13 @@ func (s *SlashCommandInput) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg: // Check for quit keys first (when popup is not shown)
|
||||
case tea.KeyPressMsg: // Check for quit keys first (when popup is not shown)
|
||||
if !s.showPopup {
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "esc":
|
||||
s.quitting = true
|
||||
return s, tea.Quit
|
||||
case "ctrl+d": // Submit on Ctrl+D like huh
|
||||
s.value = s.textarea.Value()
|
||||
s.quitting = true
|
||||
return s, tea.Quit
|
||||
}
|
||||
|
||||
// Check for newline keys first
|
||||
if msg.String() == "ctrl+j" || msg.String() == "alt+enter" {
|
||||
// Insert newline at cursor position
|
||||
s.textarea, cmd = s.textarea.Update(tea.KeyMsg{Type: tea.KeyEnter, Alt: true})
|
||||
return s, cmd
|
||||
} else if msg.String() == "enter" && !strings.Contains(s.textarea.Value(), "\n") {
|
||||
// Submit on Enter only if it's single line
|
||||
case "ctrl+d", "enter": // Enter always submits
|
||||
s.value = s.textarea.Value()
|
||||
s.quitting = true
|
||||
return s, tea.Quit
|
||||
@@ -178,7 +174,7 @@ func (s *SlashCommandInput) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
// View implements the tea.Model interface, rendering the complete input field
|
||||
// including the title, text area, autocomplete popup (when active), and help text.
|
||||
// The view adapts based on whether single or multi-line input is detected.
|
||||
func (s *SlashCommandInput) View() string {
|
||||
func (s *SlashCommandInput) View() tea.View {
|
||||
// Add left padding to entire component (2 spaces like other UI elements)
|
||||
containerStyle := lipgloss.NewStyle().PaddingLeft(2)
|
||||
|
||||
@@ -228,20 +224,14 @@ func (s *SlashCommandInput) View() string {
|
||||
Foreground(lipgloss.Color("240")).
|
||||
MarginTop(1)
|
||||
|
||||
// Show different help based on whether we have multiline content
|
||||
helpText := "enter submit"
|
||||
if strings.Contains(s.textarea.Value(), "\n") {
|
||||
helpText = "ctrl+d submit • enter new line"
|
||||
} else {
|
||||
helpText = "enter submit • ctrl+j / alt+enter new line"
|
||||
}
|
||||
helpText := "enter submit • ctrl+j / alt+enter new line"
|
||||
|
||||
view.WriteString("\n")
|
||||
view.WriteString(helpStyle.Render(helpText))
|
||||
s.renderedLines += 2 // newline + help text
|
||||
|
||||
// Apply container padding to entire view
|
||||
return containerStyle.Render(view.String())
|
||||
return tea.NewView(containerStyle.Render(view.String()))
|
||||
}
|
||||
|
||||
// renderPopup renders the autocomplete popup
|
||||
|
||||
+10
-9
@@ -3,11 +3,12 @@ package ui
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"os"
|
||||
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/bubbles/v2/spinner"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
// Spinner provides an animated loading indicator that displays while long-running
|
||||
@@ -34,7 +35,7 @@ func (m spinnerModel) Init() tea.Cmd {
|
||||
|
||||
func (m spinnerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
case tea.KeyPressMsg:
|
||||
m.quitting = true
|
||||
return m, tea.Quit
|
||||
case spinner.TickMsg:
|
||||
@@ -49,9 +50,9 @@ func (m spinnerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m spinnerModel) View() string {
|
||||
func (m spinnerModel) View() tea.View {
|
||||
if m.quitting {
|
||||
return ""
|
||||
return tea.NewView("")
|
||||
}
|
||||
|
||||
// Enhanced spinner display with better styling
|
||||
@@ -66,9 +67,9 @@ func (m spinnerModel) View() string {
|
||||
Foreground(theme.Text).
|
||||
Italic(true)
|
||||
|
||||
return fmt.Sprintf(" %s %s",
|
||||
return tea.NewView(fmt.Sprintf(" %s %s",
|
||||
spinnerStyle.Render(m.spinner.View()),
|
||||
messageStyle.Render(m.message))
|
||||
messageStyle.Render(m.message)))
|
||||
}
|
||||
|
||||
// quitMsg is sent when we want to quit the spinner
|
||||
@@ -104,7 +105,7 @@ func NewSpinner(message string) *Spinner {
|
||||
// NewThemedSpinner creates a new animated spinner with custom color styling.
|
||||
// This allows for different spinner colors based on the operation type or status.
|
||||
// The spinner runs independently in its own tea.Program.
|
||||
func NewThemedSpinner(message string, color lipgloss.AdaptiveColor) *Spinner {
|
||||
func NewThemedSpinner(message string, color color.Color) *Spinner {
|
||||
s := spinner.New()
|
||||
s.Spinner = spinner.Dot
|
||||
s.Style = s.Style.Foreground(color)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"charm.land/lipgloss/v2"
|
||||
"github.com/charmbracelet/glamour"
|
||||
"github.com/charmbracelet/glamour/ansi"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/mark3labs/mcphost/internal/config"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
@@ -42,7 +42,7 @@ func generateMarkdownStyleConfig() ansi.StyleConfig {
|
||||
|
||||
err := config.FilepathOr("markdown-theme", &mdTheme)
|
||||
fromConfig := err == nil && viper.InConfig("markdown-theme")
|
||||
if fromConfig && lipgloss.HasDarkBackground() {
|
||||
if fromConfig && IsDarkBackground() {
|
||||
textColor = mdTheme.Text.Light
|
||||
mutedColor = mdTheme.Muted.Light
|
||||
headingColor = mdTheme.Heading.Light
|
||||
@@ -68,7 +68,7 @@ func generateMarkdownStyleConfig() ansi.StyleConfig {
|
||||
stringColor = mdTheme.String.Dark
|
||||
numberColor = mdTheme.Number.Dark
|
||||
commentColor = mdTheme.Comment.Dark
|
||||
} else if lipgloss.HasDarkBackground() {
|
||||
} else if IsDarkBackground() {
|
||||
textColor = "#F9FAFB" // Light text for dark backgrounds
|
||||
mutedColor = "#9CA3AF" // Light muted for dark backgrounds
|
||||
// Dark background colors
|
||||
@@ -117,12 +117,12 @@ func generateMarkdownStyleConfig() ansi.StyleConfig {
|
||||
Prefix: "┃ ",
|
||||
},
|
||||
Indent: uintPtr(1),
|
||||
IndentToken: stringPtr(lipgloss.NewStyle().Background(lipgloss.AdaptiveColor{Light: bgColor, Dark: bgColor}).Render(" ")),
|
||||
IndentToken: stringPtr(lipgloss.NewStyle().Background(lipgloss.Color(bgColor)).Render(" ")),
|
||||
},
|
||||
List: ansi.StyleList{
|
||||
LevelIndent: 0, // Remove list indentation
|
||||
StyleBlock: ansi.StyleBlock{
|
||||
IndentToken: stringPtr(lipgloss.NewStyle().Background(lipgloss.AdaptiveColor{Light: bgColor, Dark: bgColor}).Render(" ")),
|
||||
IndentToken: stringPtr(lipgloss.NewStyle().Background(lipgloss.Color(bgColor)).Render(" ")),
|
||||
StylePrimitive: ansi.StylePrimitive{
|
||||
Color: stringPtr(textColor),
|
||||
},
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/textarea"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/bubbles/v2/textarea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
type ToolApprovalInput struct {
|
||||
@@ -29,12 +29,13 @@ func NewToolApprovalInput(toolName, toolArgs string, width int) *ToolApprovalInp
|
||||
ta.Focus()
|
||||
|
||||
// Style the textarea to match huh theme
|
||||
ta.FocusedStyle.Base = lipgloss.NewStyle()
|
||||
ta.FocusedStyle.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
|
||||
ta.FocusedStyle.Text = lipgloss.NewStyle().Foreground(lipgloss.Color("252"))
|
||||
ta.FocusedStyle.Prompt = lipgloss.NewStyle()
|
||||
ta.FocusedStyle.CursorLine = lipgloss.NewStyle()
|
||||
ta.Cursor.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("39"))
|
||||
styles := ta.Styles()
|
||||
styles.Focused.Base = lipgloss.NewStyle()
|
||||
styles.Focused.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
|
||||
styles.Focused.Text = lipgloss.NewStyle().Foreground(lipgloss.Color("252"))
|
||||
styles.Focused.Prompt = lipgloss.NewStyle()
|
||||
styles.Focused.CursorLine = lipgloss.NewStyle()
|
||||
ta.SetStyles(styles)
|
||||
|
||||
return &ToolApprovalInput{
|
||||
textarea: ta,
|
||||
@@ -51,7 +52,7 @@ func (t *ToolApprovalInput) Init() tea.Cmd {
|
||||
|
||||
func (t *ToolApprovalInput) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
case tea.KeyPressMsg:
|
||||
switch msg.String() {
|
||||
case "y", "Y":
|
||||
t.approved = true
|
||||
@@ -80,9 +81,9 @@ func (t *ToolApprovalInput) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *ToolApprovalInput) View() string {
|
||||
func (t *ToolApprovalInput) View() tea.View {
|
||||
if t.done {
|
||||
return "we are done"
|
||||
return tea.NewView("we are done")
|
||||
}
|
||||
// Add left padding to entire component (2 spaces like other UI elements)
|
||||
containerStyle := lipgloss.NewStyle().PaddingLeft(2)
|
||||
@@ -131,5 +132,5 @@ func (t *ToolApprovalInput) View() string {
|
||||
}
|
||||
view.WriteString(yesText + "/" + noText + "\n")
|
||||
|
||||
return containerStyle.Render(inputBoxStyle.Render(view.String()))
|
||||
return tea.NewView(containerStyle.Render(inputBoxStyle.Render(view.String())))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/lipgloss/v2"
|
||||
"image/color"
|
||||
|
||||
"github.com/mark3labs/mcphost/internal/models"
|
||||
"github.com/mark3labs/mcphost/internal/tokens"
|
||||
)
|
||||
@@ -167,7 +169,7 @@ func (ut *UsageTracker) RenderUsageInfo() string {
|
||||
|
||||
// Calculate percentage based on context limit with color coding
|
||||
var percentageStr string
|
||||
var percentageColor lipgloss.AdaptiveColor
|
||||
var percentageColor color.Color
|
||||
if ut.modelInfo.Limit.Context > 0 {
|
||||
percentage := float64(totalTokens) / float64(ut.modelInfo.Limit.Context) * 100
|
||||
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mark3labs/mcphost/internal/models"
|
||||
)
|
||||
|
||||
// stripAnsi removes ANSI escape codes from a string for test comparisons.
|
||||
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`)
|
||||
|
||||
func stripAnsi(s string) string {
|
||||
return ansiRegex.ReplaceAllString(s, "")
|
||||
}
|
||||
|
||||
func TestUsageTracker_RenderUsageInfo_OAuth(t *testing.T) {
|
||||
// Create a mock model info with costs and context limit
|
||||
modelInfo := &models.ModelInfo{
|
||||
@@ -26,7 +34,7 @@ func TestUsageTracker_RenderUsageInfo_OAuth(t *testing.T) {
|
||||
oauthTracker := NewUsageTracker(modelInfo, "anthropic", 80, true)
|
||||
oauthTracker.UpdateUsage(1500, 500, 0, 0) // 2000 total tokens
|
||||
|
||||
rendered := oauthTracker.RenderUsageInfo()
|
||||
rendered := stripAnsi(oauthTracker.RenderUsageInfo())
|
||||
|
||||
// Should show tokens and percentage, but cost should show "$0.00"
|
||||
if !strings.Contains(rendered, "Tokens: 2.0K") {
|
||||
@@ -43,7 +51,7 @@ func TestUsageTracker_RenderUsageInfo_OAuth(t *testing.T) {
|
||||
regularTracker := NewUsageTracker(modelInfo, "anthropic", 80, false)
|
||||
regularTracker.UpdateUsage(1500, 500, 0, 0) // Same token usage
|
||||
|
||||
regularRendered := regularTracker.RenderUsageInfo()
|
||||
regularRendered := stripAnsi(regularTracker.RenderUsageInfo())
|
||||
|
||||
// Should show tokens and actual cost
|
||||
if !strings.Contains(regularRendered, "Tokens: 2.0K") {
|
||||
|
||||
Reference in New Issue
Block a user