Merge branch 'onboarding' of github.com:charmbracelet/opencode-internal into onboarding

Kujtim Hoxha created

Change summary

go.mod                                                       |   6 
go.sum                                                       |  10 
vendor/github.com/charmbracelet/bubbletea/v2/tea.go          |  19 
vendor/github.com/charmbracelet/lipgloss/v2/get.go           |  33 +
vendor/github.com/charmbracelet/lipgloss/v2/set.go           |  27 +
vendor/github.com/charmbracelet/lipgloss/v2/style.go         |  26 
vendor/github.com/charmbracelet/lipgloss/v2/unset.go         |   7 
vendor/github.com/charmbracelet/ultraviolet/screen/screen.go | 109 ------
vendor/modules.txt                                           |  11 
9 files changed, 112 insertions(+), 136 deletions(-)

Detailed changes

go.mod 🔗

@@ -2,9 +2,9 @@ module github.com/charmbracelet/crush
 
 go 1.24.3
 
-replace github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891
+replace github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595
 
-replace github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093
+replace github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb
 
 require (
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
@@ -75,7 +75,7 @@ require (
 	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/charmbracelet/colorprofile v0.3.1 // indirect
-	github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9
+	github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 // indirect
 	github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa // indirect
 	github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef
 	github.com/charmbracelet/x/term v0.2.1

go.sum 🔗

@@ -70,16 +70,16 @@ github.com/charlievieth/fastwalk v1.0.11 h1:5sLT/q9+d9xMdpKExawLppqvXFZCVKf6JHnr
 github.com/charlievieth/fastwalk v1.0.11/go.mod h1:yGy1zbxog41ZVMcKA/i8ojXLFsuayX5VvwhQVoj9PBI=
 github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250607113720-eb5e1cf3b09e h1:99Ugtt633rqauFsXjZobZmtkNpeaWialfj8dl6COC6A=
 github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250607113720-eb5e1cf3b09e/go.mod h1:6HamsBKWqEC/FVHuQMHgQL+knPyvHH55HwJDHl/adMw=
-github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891 h1:wh6N1dR4XkDh6XsiZh1/tImJAZvYB0yVLmaUKvJXvK0=
-github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891/go.mod h1:SwBB+WoaQVMMOM9hknbN/7FNT86kgKG0LSHGTmLphX8=
+github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595 h1:wLMjzOqrwoM7Em9UR9sGbn4375G8WuxcwFB3kjZiqHo=
+github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595/go.mod h1:+Tl7rePElw6OKt382t04zXwtPFoPXxAaJzNrYmtsLds=
 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/fang v0.1.0 h1:SlZS2crf3/zQh7Mr4+W+7QR1k+L08rrPX5rm5z3d7Wg=
 github.com/charmbracelet/fang v0.1.0/go.mod h1:Zl/zeUQ8EtQuGyiV0ZKZlZPDowKRTzu8s/367EpN/fc=
 github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe h1:i6ce4CcAlPpTj2ER69m1DBeLZ3RRcHnKExuwhKa3GfY=
 github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe/go.mod h1:p3Q+aN4eQKeM5jhrmXPMgPrlKbmc59rWSnMsSA3udhk=
-github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093 h1:c9vOmNJQUwy/lp/pNOB5ZDMhOuXJ3Y2LL9uZMYGgJxQ=
-github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093/go.mod h1:XmxjFJcMEfYIHa4Mw4ra+uMjploDkTlkKIs7wLt9v4Q=
+github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb h1:lswj7CYZVYbLn2OhYJsXOMRQQGdRIfyuSnh5FdVSMr0=
+github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb/go.mod h1:wEc/TRrTAIDJYjVCg3+y8WeKaN+F88gpYfGbUuP6W3A=
 github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706 h1:WkwO6Ks3mSIGnGuSdKl9qDSyfbYK50z2wc2gGMggegE=
 github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706/go.mod h1:mjJGp00cxcfvD5xdCa+bso251Jt4owrQvuimJtVmEmM=
 github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 h1:+LLFCLxtb/sHegwY3zYdFAbaOgI/I9pv/pxdUlI1Q9s=
@@ -88,8 +88,6 @@ github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh
 github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
 github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa h1:lphz0Z3rsiOtMYiz8axkT24i9yFiueDhJbzyNUADmME=
 github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa/go.mod h1:xBlh2Yi3DL3zy/2n15kITpg0YZardf/aa/hgUaIM6Rk=
-github.com/charmbracelet/x/exp/charmtone v0.0.0-20250627134340-c144409e381c h1:2GELBLPgfSbHU53bsQhR9XIgNuVZ6w+Rz8RWV5Lq+A4=
-github.com/charmbracelet/x/exp/charmtone v0.0.0-20250627134340-c144409e381c/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0=
 github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 h1:1xwHZg6eMZ9Wv5TE1UGub6ARubyOd1Lo5kPUI/6VL50=
 github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0=
 github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw=

vendor/github.com/charmbracelet/bubbletea/v2/tea.go 🔗

@@ -624,6 +624,10 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
 				switch msg.Mode {
 				case ansi.AltScreenSaveCursorMode:
 					p.renderer.enterAltScreen()
+					// Main and alternate screen have their own Kitty keyboard
+					// stack. We need to request keyboard enhancements again
+					// when entering/exiting the alternate screen.
+					p.requestKeyboardEnhancements()
 				case ansi.TextCursorEnableMode:
 					p.renderer.showCursor()
 				case ansi.GraphemeClusteringMode:
@@ -645,6 +649,10 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
 				switch msg.Mode {
 				case ansi.AltScreenSaveCursorMode:
 					p.renderer.exitAltScreen()
+					// Main and alternate screen have their own Kitty keyboard
+					// stack. We need to request keyboard enhancements again
+					// when entering/exiting the alternate screen.
+					p.requestKeyboardEnhancements()
 				case ansi.TextCursorEnableMode:
 					p.renderer.hideCursor()
 				default:
@@ -1410,13 +1418,16 @@ func (p *Program) stopRenderer(kill bool) {
 // requestKeyboardEnhancements tries to enable keyboard enhancements and read
 // the active keyboard enhancements from the terminal.
 func (p *Program) requestKeyboardEnhancements() {
+	// XXX: We write to the renderer directly so that we synchronize with the
+	// alt-screen state of the renderer. This is because the main screen and
+	// alternate screen have their own Kitty keyboard state stack.
 	if p.requestedEnhancements.modifyOtherKeys > 0 {
-		p.execute(ansi.KeyModifierOptions(4, p.requestedEnhancements.modifyOtherKeys)) //nolint:mnd
-		p.execute(ansi.QueryModifyOtherKeys)
+		_, _ = p.renderer.writeString(ansi.KeyModifierOptions(4, p.requestedEnhancements.modifyOtherKeys)) //nolint:mnd
+		_, _ = p.renderer.writeString(ansi.QueryModifyOtherKeys)
 	}
 	if p.requestedEnhancements.kittyFlags > 0 {
-		p.execute(ansi.PushKittyKeyboard(p.requestedEnhancements.kittyFlags))
-		p.execute(ansi.RequestKittyKeyboard)
+		_, _ = p.renderer.writeString(ansi.PushKittyKeyboard(p.requestedEnhancements.kittyFlags))
+		_, _ = p.renderer.writeString(ansi.RequestKittyKeyboard)
 	}
 }
 

vendor/github.com/charmbracelet/lipgloss/v2/get.go 🔗

@@ -135,6 +135,16 @@ func (s Style) GetPaddingLeft() int {
 	return s.getAsInt(paddingLeftKey)
 }
 
+// GetPaddingChar returns the style's padding character. If no value is set a
+// space (`\u0020`) is returned.
+func (s Style) GetPaddingChar() rune {
+	char := s.getAsRune(paddingCharKey)
+	if char == 0 {
+		return ' '
+	}
+	return char
+}
+
 // GetHorizontalPadding returns the style's left and right padding. Unset
 // values are measured as 0.
 func (s Style) GetHorizontalPadding() int {
@@ -186,6 +196,16 @@ func (s Style) GetMarginLeft() int {
 	return s.getAsInt(marginLeftKey)
 }
 
+// GetMarginChar returns the style's padding character. If no value is set a
+// space (`\u0020`) is returned.
+func (s Style) GetMarginChar() rune {
+	char := s.getAsRune(marginCharKey)
+	if char == 0 {
+		return ' '
+	}
+	return char
+}
+
 // GetHorizontalMargins returns the style's left and right margins. Unset
 // values are measured as 0.
 func (s Style) GetHorizontalMargins() int {
@@ -432,6 +452,19 @@ func (s Style) isSet(k propKey) bool {
 	return s.props.has(k)
 }
 
+func (s Style) getAsRune(k propKey) rune {
+	if !s.isSet(k) {
+		return 0
+	}
+	switch k { //nolint:exhaustive
+	case paddingCharKey:
+		return s.paddingChar
+	case marginCharKey:
+		return s.marginChar
+	}
+	return 0
+}
+
 func (s Style) getAsBool(k propKey, defaultVal bool) bool {
 	if !s.isSet(k) {
 		return defaultVal

vendor/github.com/charmbracelet/lipgloss/v2/set.go 🔗

@@ -29,6 +29,8 @@ func (s *Style) set(key propKey, value any) {
 		s.paddingBottom = max(0, value.(int))
 	case paddingLeftKey:
 		s.paddingLeft = max(0, value.(int))
+	case paddingCharKey:
+		s.paddingChar = value.(rune)
 	case marginTopKey:
 		s.marginTop = max(0, value.(int))
 	case marginRightKey:
@@ -39,6 +41,8 @@ func (s *Style) set(key propKey, value any) {
 		s.marginLeft = max(0, value.(int))
 	case marginBackgroundKey:
 		s.marginBgColor = colorOrNil(value)
+	case marginCharKey:
+		s.marginChar = value.(rune)
 	case borderStyleKey:
 		s.borderStyle = value.(Border)
 	case borderTopForegroundKey:
@@ -111,6 +115,8 @@ func (s *Style) setFrom(key propKey, i Style) {
 		s.set(paddingBottomKey, i.paddingBottom)
 	case paddingLeftKey:
 		s.set(paddingLeftKey, i.paddingLeft)
+	case paddingCharKey:
+		s.set(paddingCharKey, i.paddingChar)
 	case marginTopKey:
 		s.set(marginTopKey, i.marginTop)
 	case marginRightKey:
@@ -121,6 +127,8 @@ func (s *Style) setFrom(key propKey, i Style) {
 		s.set(marginLeftKey, i.marginLeft)
 	case marginBackgroundKey:
 		s.set(marginBackgroundKey, i.marginBgColor)
+	case marginCharKey:
+		s.set(marginCharKey, i.marginChar)
 	case borderStyleKey:
 		s.set(borderStyleKey, i.borderStyle)
 	case borderTopForegroundKey:
@@ -320,6 +328,18 @@ func (s Style) PaddingBottom(i int) Style {
 	return s
 }
 
+// PaddingChar sets the character used for padding. This is useful for
+// rendering blocks with a specific character, such as a space or a dot.
+// Example of using [NBSP] as padding to prevent line breaks:
+//
+//	```go
+//	s := lipgloss.NewStyle().PaddingChar(lipgloss.NBSP)
+//	```
+func (s Style) PaddingChar(r rune) Style {
+	s.set(paddingCharKey, r)
+	return s
+}
+
 // ColorWhitespace determines whether or not the background color should be
 // applied to the padding. This is true by default as it's more than likely the
 // desired and expected behavior, but it can be disabled for certain graphic
@@ -390,6 +410,13 @@ func (s Style) MarginBackground(c color.Color) Style {
 	return s
 }
 
+// MarginChar sets the character used for the margin. This is useful for
+// rendering blocks with a specific character, such as a space or a dot.
+func (s Style) MarginChar(r rune) Style {
+	s.set(marginCharKey, r)
+	return s
+}
+
 // Border is shorthand for setting the border style and which sides should
 // have a border at once. The variadic argument sides works as follows:
 //

vendor/github.com/charmbracelet/lipgloss/v2/style.go 🔗

@@ -10,7 +10,8 @@ import (
 )
 
 const (
-	nbsp            = '\u00A0'
+	// NBSP is the non-breaking space rune.
+	NBSP            = '\u00A0'
 	tabWidthDefault = 4
 )
 
@@ -44,6 +45,7 @@ const (
 	paddingRightKey
 	paddingBottomKey
 	paddingLeftKey
+	paddingCharKey
 
 	// Margins.
 	marginTopKey
@@ -51,6 +53,7 @@ const (
 	marginBottomKey
 	marginLeftKey
 	marginBackgroundKey
+	marginCharKey
 
 	// Border runes.
 	borderStyleKey
@@ -128,12 +131,14 @@ type Style struct {
 	paddingRight  int
 	paddingBottom int
 	paddingLeft   int
+	paddingChar   rune
 
 	marginTop     int
 	marginRight   int
 	marginBottom  int
 	marginLeft    int
 	marginBgColor color.Color
+	marginChar    rune
 
 	borderStyle         Border
 	borderTopFgColor    color.Color
@@ -387,23 +392,24 @@ func (s Style) Render(strs ...string) string {
 
 	// Padding
 	if !inline { //nolint:nestif
+		padChar := s.paddingChar
+		if padChar == 0 {
+			padChar = ' '
+		}
 		if leftPadding > 0 {
 			var st *ansi.Style
 			if colorWhitespace || styleWhitespace {
 				st = &teWhitespace
 			}
-			str = padLeft(str, leftPadding, st, nbsp)
+			str = padLeft(str, leftPadding, st, padChar)
 		}
 
-		// XXX: We use a non-breaking space to pad so that the padding is
-		// preserved when the string is copied and pasted.
-
 		if rightPadding > 0 {
 			var st *ansi.Style
 			if colorWhitespace || styleWhitespace {
 				st = &teWhitespace
 			}
-			str = padRight(str, rightPadding, st, nbsp)
+			str = padRight(str, rightPadding, st, padChar)
 		}
 
 		if topPadding > 0 {
@@ -494,8 +500,12 @@ func (s Style) applyMargins(str string, inline bool) string {
 	}
 
 	// Add left and right margin
-	str = padLeft(str, leftMargin, &style, ' ')
-	str = padRight(str, rightMargin, &style, ' ')
+	marginChar := s.marginChar
+	if marginChar == 0 {
+		marginChar = ' '
+	}
+	str = padLeft(str, leftMargin, &style, marginChar)
+	str = padRight(str, rightMargin, &style, marginChar)
 
 	// Top/bottom margin
 	if !inline {

vendor/github.com/charmbracelet/lipgloss/v2/unset.go 🔗

@@ -96,6 +96,13 @@ func (s Style) UnsetPadding() Style {
 	s.unset(paddingRightKey)
 	s.unset(paddingTopKey)
 	s.unset(paddingBottomKey)
+	s.unset(paddingCharKey)
+	return s
+}
+
+// UnsetPaddingChar removes the padding character style rule, if set.
+func (s Style) UnsetPaddingChar() Style {
+	s.unset(paddingCharKey)
 	return s
 }
 

vendor/github.com/charmbracelet/ultraviolet/screen/screen.go 🔗

@@ -1,109 +0,0 @@
-// Package screen provides functions and helpers to manipulate a [uv.Screen].
-package screen
-
-import uv "github.com/charmbracelet/ultraviolet"
-
-// Clear clears the screen with empty cells. This is equivalent to filling the
-// screen with empty cells.
-//
-// If the screen implements a [Clear] method, it will be called instead of
-// filling the screen with empty cells.
-func Clear(scr uv.Screen) {
-	if c, ok := scr.(interface {
-		Clear()
-	}); ok {
-		c.Clear()
-		return
-	}
-	Fill(scr, nil)
-}
-
-// ClearArea clears the given area of the screen with empty cells. This is
-// equivalent to filling the area with empty cells.
-//
-// If the screen implements a [ClearArea] method, it will be called instead of
-// filling the area with empty cells.
-func ClearArea(scr uv.Screen, area uv.Rectangle) {
-	if c, ok := scr.(interface {
-		ClearArea(area uv.Rectangle)
-	}); ok {
-		c.ClearArea(area)
-		return
-	}
-	FillArea(scr, nil, area)
-}
-
-// Fill fills the screen with the given cell. If the cell is nil, it fills the
-// screen with empty cells.
-//
-// If the screen implements a [Fill] method, it will be called instead of
-// filling the screen with empty cells.
-func Fill(scr uv.Screen, cell *uv.Cell) {
-	if f, ok := scr.(interface {
-		Fill(cell *uv.Cell)
-	}); ok {
-		f.Fill(cell)
-		return
-	}
-	FillArea(scr, cell, scr.Bounds())
-}
-
-// FillArea fills the given area of the screen with the given cell. If the cell
-// is nil, it fills the area with empty cells.
-//
-// If the screen implements a [FillArea] method, it will be called instead of
-// filling the area with empty cells.
-func FillArea(scr uv.Screen, cell *uv.Cell, area uv.Rectangle) {
-	if f, ok := scr.(interface {
-		FillArea(cell *uv.Cell, area uv.Rectangle)
-	}); ok {
-		f.FillArea(cell, area)
-		return
-	}
-	for y := area.Min.Y; y < area.Max.Y; y++ {
-		for x := area.Min.X; x < area.Max.X; x++ {
-			scr.SetCell(x, y, cell)
-		}
-	}
-}
-
-// CloneArea clones the given area of the screen and returns a new buffer
-// with the same size as the area. The new buffer will contain the same cells
-// as the area in the screen.
-// Use [uv.Buffer.Draw] to draw the cloned buffer to a screen again.
-//
-// If the screen implements a [CloneArea] method, it will be called instead of
-// cloning the area manually.
-func CloneArea(scr uv.Screen, area uv.Rectangle) *uv.Buffer {
-	if c, ok := scr.(interface {
-		CloneArea(area uv.Rectangle) *uv.Buffer
-	}); ok {
-		return c.CloneArea(area)
-	}
-	buf := uv.NewBuffer(area.Dx(), area.Dy())
-	for y := area.Min.Y; y < area.Max.Y; y++ {
-		for x := area.Min.X; x < area.Max.X; x++ {
-			cell := scr.CellAt(x, y)
-			if cell == nil || cell.IsZero() {
-				continue
-			}
-			buf.SetCell(x-area.Min.X, y-area.Min.Y, cell.Clone())
-		}
-	}
-	return buf
-}
-
-// Clone creates a new [uv.Buffer] clone of the given screen. The new buffer will
-// have the same size as the screen and will contain the same cells.
-// Use [uv.Buffer.Draw] to draw the cloned buffer to a screen again.
-//
-// If the screen implements a [Clone] method, it will be called instead of
-// cloning the entire screen manually.
-func Clone(scr uv.Screen) *uv.Buffer {
-	if c, ok := scr.(interface {
-		Clone() *uv.Buffer
-	}); ok {
-		return c.Clone()
-	}
-	return CloneArea(scr, scr.Bounds())
-}

vendor/modules.txt 🔗

@@ -254,8 +254,8 @@ github.com/charmbracelet/bubbles/v2/spinner
 github.com/charmbracelet/bubbles/v2/textarea
 github.com/charmbracelet/bubbles/v2/textinput
 github.com/charmbracelet/bubbles/v2/viewport
-# github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.1 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891
-## explicit; go 1.24.3
+# github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.1 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595
+## explicit; go 1.24.0
 github.com/charmbracelet/bubbletea/v2
 # github.com/charmbracelet/colorprofile v0.3.1
 ## explicit; go 1.23.0
@@ -269,7 +269,7 @@ github.com/charmbracelet/glamour/v2
 github.com/charmbracelet/glamour/v2/ansi
 github.com/charmbracelet/glamour/v2/internal/autolink
 github.com/charmbracelet/glamour/v2/styles
-# github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.2.0.20250703152125-8e1c474f8a71 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093
+# github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.2.0.20250703152125-8e1c474f8a71 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb
 ## explicit; go 1.24.2
 github.com/charmbracelet/lipgloss/v2
 github.com/charmbracelet/lipgloss/v2/table
@@ -280,7 +280,6 @@ github.com/charmbracelet/log/v2
 # github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9
 ## explicit; go 1.24.0
 github.com/charmbracelet/ultraviolet
-github.com/charmbracelet/ultraviolet/screen
 # github.com/charmbracelet/x/ansi v0.9.3
 ## explicit; go 1.23.0
 github.com/charmbracelet/x/ansi
@@ -839,5 +838,5 @@ mvdan.cc/sh/v3/fileutil
 mvdan.cc/sh/v3/interp
 mvdan.cc/sh/v3/pattern
 mvdan.cc/sh/v3/syntax
-# github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891
-# github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093
+# github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595
+# github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb