package tui import ( "fmt" "net/url" "os" "strings" "harness/internal/llm" ) // human renders a token count the way a status bar wants to read it. func human(n int) string { switch { case n >= 1_000_000: return fmt.Sprintf("%.1fM", float64(n)/1e6) case n >= 1_000: return fmt.Sprintf("%.1fk", float64(n)/1e3) } return fmt.Sprint(n) } // prettyModel names a model the way a person does. The transform itself lives // in llm, next to the ids it is about, so the wizard's list and the status bar // cannot disagree about what a model is called. func prettyModel(id string) string { return llm.PrettyModel(id) } // endpointLabel names where the prompts are going. The default endpoint gets // a short name; anything else shows its host, because "somewhere that is not // Anthropic" is the single most important thing the header can say. func endpointLabel(c *llm.Client) string { if c == nil { return "" } if c.IsDefaultEndpoint() { return "anthropic" } if u, err := url.Parse(c.BaseURL); err == nil && u.Host != "" { return u.Host } return c.BaseURL } // camel renders a snake_case tool name as the transcript shows it: read_file // becomes ReadFile. It is a display transform only — approvals and errors // still quote the real name. func camel(name string) string { parts := strings.Split(name, "_") for i, p := range parts { if p == "" { continue } parts[i] = strings.ToUpper(p[:1]) + p[1:] } return strings.Join(parts, "") } func maxInt(a, b int) int { if a > b { return a } return b } func minInt(a, b int) int { if a < b { return a } return b } // shortenHome writes a path the way a person says it. The working root is // shown in the welcome block, where "~/Work/thing" carries the same // information as the absolute path in a third of the columns. func shortenHome(path string) string { home, err := os.UserHomeDir() if err != nil || home == "" || path == home { return path } if strings.HasPrefix(path, home+string(os.PathSeparator)) { return "~" + path[len(home):] } return path }