mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
78570d4188
Removes ~600 lines of unreferenced code surfaced by deadcode + manual
audit (none of it reachable from production code paths or test setup):
- internal/models/pool.go: ProviderPool was never wired into kitsetup
or the agent; the global pool singleton had zero callers.
- internal/ui/debug_logger.go: CLIDebugLogger was unreachable; debug
routing goes through internal/tools/buffered_logger.go instead.
- internal/ui/tool_approval_input.go: tea.Model never instantiated;
approvals are handled inline in model.go.
- internal/ui/cli.go: DisplayAssistantMessage / DisplayCancellation /
GetDebugLogger had zero callers (the *WithModel variant is what
event_handler.go uses).
- internal/ui/style/enhanced.go: Style{Card,Header,Subheader,Muted,
Success,Error,Warning,Info} + Create{Separator,ProgressBar} — none
used. CreateBadge stays (used by model.go).
- internal/ui/style/themes.go: RefreshThemeRegistry — never called.
- internal/ui/block_renderer.go: With{FullWidth,MarginTop,Padding{Left,
Right},Background,Foreground,Width} — option helpers nobody calls.
- internal/ui/render/blocks.go: UserBlock, ToolBlock — replaced by
inline rendering elsewhere; the test for UserBlock was rewritten to
directly exercise HighlightFileTokens (which is what the test really
cared about).
- internal/ui/commands/commands.go: GetAllCommandNames — no callers.
- internal/ui/message_items.go: NewTextMessageItem,
NewSystemMessageItem + the entire SystemMessageItem type — model.go
uses NewStyledMessageItem instead.
- internal/prompts/loader.go: Deduplicate — the loader does dedup
internally; standalone helper was unused.
- internal/models/cache_options.go: mergeProviderOptions + its
test-only consumer.
- internal/extensions/installer.go: Installer.GetInstalledPackages —
intended for a 'kit ext list' command that was never built.
- internal/extensions/manifest.go: saveManifestToScope,
saveManifestToPath, GetGlobalManifest, GetProjectManifest,
addEntryToManifest, removeEntryFromManifest — package-level
duplicates of *Installer methods. Tests rewritten to exercise the
live Installer methods instead, which fixes a latent path-resolution
inconsistency between manifestPathForScope and Installer.manifestPath
(the former hard-coded paths, the latter respects projectGitRoot).
- internal/extensions/subagent.go: SpawnSubagent + helpers
(generateSubagentID, findKitBinary, subagentJSONOutput). The
subprocess-spawn implementation is unreachable; production code
routes through kit.Kit.Subagent (in-process). Types
(SubagentConfig/Result/Handle/etc.) and the SubagentHandle methods
remain because they are exposed to extensions via Yaegi symbols and
the Context.SpawnSubagent field.
- cmd/root.go: LoadConfigWithEnvSubstitution — one-line wrapper around
kit.LoadConfigWithEnvSubstitution with zero callers.
go test -race ./... passes.
146 lines
4.8 KiB
Go
146 lines
4.8 KiB
Go
// Package render provides pure rendering functions for message blocks.
|
|
// These functions are stateless and can be used by both streaming and
|
|
// historical message rendering paths, eliminating code duplication.
|
|
package render
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"charm.land/lipgloss/v2"
|
|
"github.com/indaco/herald"
|
|
|
|
"github.com/mark3labs/kit/internal/ui/style"
|
|
)
|
|
|
|
// fileTokenPattern matches @file references in user text. Supports:
|
|
// - @"path with spaces.txt" (quoted)
|
|
// - @path/to/file.txt (unquoted, no spaces)
|
|
var fileTokenPattern = regexp.MustCompile(`@"[^"]+"|@[^\s]+`)
|
|
|
|
// UserBlock-related rendering helpers and herald typography.
|
|
|
|
// HighlightFileTokens wraps @file tokens in the given text with the theme
|
|
// accent color so they stand out visually in rendered user messages.
|
|
func HighlightFileTokens(text string, theme style.Theme) string {
|
|
accentStyle := style.GetCachedStyles().FileTokenAccent
|
|
return fileTokenPattern.ReplaceAllStringFunc(text, func(token string) string {
|
|
return accentStyle.Render(token)
|
|
})
|
|
}
|
|
|
|
// AssistantBlock renders an assistant message with markdown styling.
|
|
func AssistantBlock(content string, width int, theme style.Theme) string {
|
|
if strings.TrimSpace(content) == "" {
|
|
return ""
|
|
}
|
|
|
|
rendered := style.ToMarkdown(content, width-4)
|
|
return styleMarginBottom(theme, rendered)
|
|
}
|
|
|
|
// ReasoningBlock renders a reasoning/thinking block with muted italic text.
|
|
// If duration > 0, shows "Thought for Xs" label. Otherwise shows just "Thought".
|
|
// The width parameter controls soft-wrapping so long reasoning lines don't get cut off.
|
|
func ReasoningBlock(content string, duration int64, width int, ty *herald.Typography, theme style.Theme) string {
|
|
if strings.TrimSpace(content) == "" {
|
|
return ""
|
|
}
|
|
|
|
// Match live streaming styling: muted italic text.
|
|
lines := strings.Split(strings.TrimRight(content, "\n"), "\n")
|
|
contentStr := strings.TrimLeft(strings.Join(lines, "\n"), " \t\n")
|
|
if width > 4 {
|
|
contentStr = wrapText(contentStr, width-4)
|
|
}
|
|
cs := style.GetCachedStyles()
|
|
contentRendered := cs.Muted.Render(ty.Italic(contentStr))
|
|
|
|
// Build label based on duration
|
|
if duration > 0 {
|
|
var durationStr string
|
|
if duration < 1000 {
|
|
durationStr = fmt.Sprintf("%dms", duration)
|
|
} else {
|
|
durationStr = fmt.Sprintf("%.1fs", float64(duration)/1000)
|
|
}
|
|
labelPart := cs.VeryMuted.Render("Thought for ")
|
|
durationPart := cs.Accent.Render(durationStr)
|
|
label := labelPart + durationPart
|
|
rendered := contentRendered + "\n" + label
|
|
return styleMarginBottom(theme, rendered)
|
|
}
|
|
|
|
label := cs.VeryMuted.Render("Thought")
|
|
rendered := contentRendered + "\n" + label
|
|
|
|
return styleMarginBottom(theme, rendered)
|
|
}
|
|
|
|
// SystemBlock renders a system message with herald Note styling.
|
|
func SystemBlock(content string, ty *herald.Typography, theme style.Theme) string {
|
|
if strings.TrimSpace(content) == "" {
|
|
content = "No content available"
|
|
}
|
|
|
|
rendered := ty.Note(content)
|
|
return styleMarginBottom(theme, rendered)
|
|
}
|
|
|
|
// CustomBlock renders a message with herald Note styling and a custom label.
|
|
// Content is rendered as markdown before being wrapped in the alert. This
|
|
// creates a one-off Typography instance with the given label so callers
|
|
// can use any title (e.g. "Help", "Warning") without changing the shared
|
|
// typography's default "Info" label.
|
|
func CustomBlock(content, label string, width int, theme style.Theme) string {
|
|
if strings.TrimSpace(content) == "" {
|
|
content = "No content available"
|
|
}
|
|
|
|
// Render markdown first — subtract 4 for the alert bar prefix ("│ ").
|
|
mdWidth := max(width-4, 10)
|
|
rendered := style.ToMarkdown(content, mdWidth)
|
|
|
|
ty := herald.New(
|
|
herald.WithPalette(herald.ColorPalette{
|
|
Primary: theme.Primary,
|
|
Secondary: theme.Secondary,
|
|
Tertiary: theme.Info,
|
|
Accent: theme.Accent,
|
|
Highlight: theme.Highlight,
|
|
Muted: theme.Muted,
|
|
Text: theme.Text,
|
|
Surface: theme.Background,
|
|
Base: theme.CodeBg,
|
|
}),
|
|
herald.WithAlertPalette(herald.AlertPalette{
|
|
Note: theme.Info,
|
|
Tip: theme.Success,
|
|
Important: theme.Accent,
|
|
Warning: theme.Warning,
|
|
Caution: theme.Error,
|
|
}),
|
|
herald.WithAlertLabel(herald.AlertNote, label),
|
|
)
|
|
alertRendered := ty.Note(rendered)
|
|
return styleMarginBottom(theme, alertRendered)
|
|
}
|
|
|
|
// ErrorBlock renders an error message with herald Caution styling.
|
|
func ErrorBlock(errorMsg string, ty *herald.Typography, theme style.Theme) string {
|
|
rendered := ty.Caution(errorMsg)
|
|
return styleMarginBottom(theme, rendered)
|
|
}
|
|
|
|
// styleMarginBottom applies a 1-line margin bottom using the theme.
|
|
func styleMarginBottom(theme style.Theme, content string) string {
|
|
return style.GetCachedStyles().MarginBottom1.Render(content)
|
|
}
|
|
|
|
// wrapText soft-wraps a string to the given width using lipgloss, which is
|
|
// ANSI-aware and preserves escape sequences across line breaks.
|
|
func wrapText(s string, width int) string {
|
|
return lipgloss.NewStyle().Width(width).Render(s)
|
|
}
|