theniceboy/agent-tracker/cmd/agent/tmux_status.go
2026-07-15 14:26:56 +08:00

1230 lines
33 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bufio"
"encoding/json"
"flag"
"fmt"
"math"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"unicode/utf8"
)
const (
statusRightModuleCPU = "cpu"
statusRightModuleNetwork = "network"
statusRightModuleMemory = "memory"
statusRightModuleWindowMemory = "window_memory"
statusRightModuleSessionMemory = "session_memory"
statusRightModuleTotalMemory = "total_memory"
statusRightModuleScratch = "scratch"
statusRightModuleFlashMoe = "flash_moe"
statusRightModuleHost = "host"
)
const (
statusIconCPU = ""
statusIconNetwork = "󰖩"
statusIconMemory = ""
statusIconWindow = "󰖲"
statusIconSession = ""
statusIconTotal = "󰍛"
statusIconAgent = "󰚩"
statusIconScratch = "✏️"
statusIconTodos = "󰎚"
statusIconFlashMoe = "󱙺"
statusIconGoal = "⌖"
statusIconNext = "󰁔"
statusIconLastMsg = "󰅻"
)
func statusRightModules() []string {
return []string{
statusRightModuleCPU,
statusRightModuleNetwork,
statusRightModuleMemory,
statusRightModuleWindowMemory,
statusRightModuleSessionMemory,
statusRightModuleTotalMemory,
statusRightModuleScratch,
statusRightModuleFlashMoe,
statusRightModuleHost,
}
}
var cpuUsagePattern = regexp.MustCompile(`CPU usage:\s*([0-9.]+)% user,\s*([0-9.]+)% sys,`)
var statusCommandOutput = func(name string, args ...string) ([]byte, error) {
cmd := exec.Command(name, args...)
return cmd.Output()
}
var statusCommandStart = func(name string, args ...string) error {
cmd := exec.Command(name, args...)
if err := cmd.Start(); err != nil {
return err
}
if cmd.Process != nil {
_ = cmd.Process.Release()
}
return nil
}
var statusNow = time.Now
var statusHostname = os.Hostname
var statusDetectCurrentAgentFromTmux = detectCurrentAgentFromTmux
var statusLoadRegistry = loadRegistry
var statusMemoryCachePath = func() string { return "/tmp/tmux-mem-usage.json" }
var statusMemoryCacheRefreshScript = func() string {
return filepath.Join(os.Getenv("HOME"), ".config", "tmux", "tmux-status", "mem_usage_cache.py")
}
var statusTodoFilePath = func() string {
return filepath.Join(os.Getenv("HOME"), ".cache", "agent", "todos.json")
}
var statusFlashMoeMetricsPath = func() string {
return filepath.Join(os.Getenv("HOME"), ".flash-moe", "tmux_metrics")
}
var statusNetworkRateCachePath = func() string {
return "/tmp/agent-tmux-network-rate.json"
}
type tmuxRightStatusArgs struct {
Width int
StatusBG string
SessionName string
WindowIndex string
WindowName string
PaneID string
WindowID string
}
type statusSegment struct {
FG string
BG string
Text string
Bold bool
NoRightPadding bool
}
type statusMemoryCache struct {
Pane map[string]string `json:"pane"`
Window map[string]string `json:"window"`
Session map[string]string `json:"session"`
Total string `json:"total"`
}
type statusTodoCache struct {
Global []statusTodoItem `json:"global"`
Sessions map[string][]statusTodoItem `json:"sessions"`
Windows map[string][]statusTodoItem `json:"windows"`
}
type windowSnapshotEntry struct {
SessionName string `json:"session_name"`
WindowIndex string `json:"window_index"`
WindowName string `json:"window_name"`
}
func windowSnapshotPath() string {
stateDir := os.Getenv("XDG_STATE_HOME")
if stateDir == "" {
home, _ := os.UserHomeDir()
stateDir = filepath.Join(home, ".local", "state")
}
return filepath.Join(stateDir, "agent-tracker", "window-snapshot.json")
}
func saveWindowSnapshot(args tmuxRightStatusArgs) {
if args.WindowID == "" {
return
}
path := windowSnapshotPath()
data, err := os.ReadFile(path)
var snapshot map[string]windowSnapshotEntry
if err == nil {
_ = json.Unmarshal(data, &snapshot)
}
if snapshot == nil {
snapshot = make(map[string]windowSnapshotEntry)
}
out, err := runTmuxOutput("list-windows", "-a", "-F", "#{window_id}\t#{session_name}\t#{window_index}\t#{window_name}")
if err != nil {
entry := windowSnapshotEntry{
SessionName: args.SessionName,
WindowIndex: args.WindowIndex,
WindowName: args.WindowName,
}
if existing, ok := snapshot[args.WindowID]; ok && existing == entry {
return
}
snapshot[args.WindowID] = entry
} else {
for _, line := range strings.Split(out, "\n") {
fields := strings.SplitN(line, "\t", 4)
if len(fields) != 4 {
continue
}
wid := strings.TrimSpace(fields[0])
if wid == "" {
continue
}
snapshot[wid] = windowSnapshotEntry{
SessionName: strings.TrimSpace(fields[1]),
WindowIndex: strings.TrimSpace(fields[2]),
WindowName: strings.TrimSpace(fields[3]),
}
}
}
updated, _ := json.Marshal(snapshot)
_ = os.MkdirAll(filepath.Dir(path), 0755)
tmp := path + ".tmp"
_ = os.WriteFile(tmp, updated, 0644)
_ = os.Rename(tmp, path)
}
type statusTodoItem struct {
Title string `json:"title"`
Done bool `json:"done"`
}
type statusNetworkCounter struct {
InBytes uint64
OutBytes uint64
}
type statusNetworkRateCache struct {
Interface string `json:"interface"`
InBytes uint64 `json:"in_bytes"`
OutBytes uint64 `json:"out_bytes"`
SampledAt int64 `json:"sampled_at_unix_ms"`
}
func runTmuxRightStatus(args []string) error {
fs := flag.NewFlagSet("agent tmux right-status", flag.ContinueOnError)
fs.SetOutput(os.Stderr)
if err := fs.Parse(args); err != nil {
return err
}
values := fs.Args()
parsed := tmuxRightStatusArgs{}
if len(values) > 0 {
parsed.Width, _ = strconv.Atoi(strings.TrimSpace(values[0]))
}
if len(values) > 1 {
parsed.StatusBG = strings.TrimSpace(values[1])
}
if len(values) > 2 {
parsed.SessionName = strings.TrimSpace(values[2])
}
if len(values) > 3 {
parsed.WindowIndex = strings.TrimSpace(values[3])
}
if len(values) > 4 {
parsed.PaneID = strings.TrimSpace(values[4])
}
if len(values) > 5 {
parsed.WindowID = strings.TrimSpace(values[5])
}
if parsed.StatusBG == "" || parsed.StatusBG == "default" {
parsed.StatusBG = "black"
}
if parsed.Width > 0 && parsed.Width < statusRightMinimumWidth() {
return nil
}
fmt.Print(renderTmuxRightStatus(parsed))
return nil
}
func runTmuxWorkStatus(args []string) error {
fs := flag.NewFlagSet("agent tmux work-status", flag.ContinueOnError)
fs.SetOutput(os.Stderr)
if err := fs.Parse(args); err != nil {
return err
}
values := fs.Args()
parsed := tmuxRightStatusArgs{}
if len(values) > 0 {
parsed.Width, _ = strconv.Atoi(strings.TrimSpace(values[0]))
}
if len(values) > 1 {
parsed.WindowID = strings.TrimSpace(values[1])
}
if len(values) > 2 {
parsed.SessionName = strings.TrimSpace(values[2])
}
if len(values) > 3 {
parsed.WindowIndex = strings.TrimSpace(values[3])
}
if len(values) > 4 {
parsed.WindowName = strings.TrimSpace(values[4])
}
saveWindowSnapshot(parsed)
fmt.Print(renderTmuxWorkStatus(parsed))
return nil
}
func renderTmuxRightStatus(args tmuxRightStatusArgs) string {
segments := make([]statusSegment, 0, 6)
if statusRightModuleEnabled(statusRightModuleCPU) {
if label := loadCPUStatusLabel(); label != "" {
segments = append(segments, statusSegment{FG: "#1d1f21", BG: "#d08770", Text: label, Bold: true})
}
}
if statusRightModuleEnabled(statusRightModuleNetwork) {
if label := loadNetworkStatusLabel(); label != "" {
segments = append(segments, statusSegment{FG: "#1d1f21", BG: "#8fbcbb", Text: label, Bold: true})
}
}
if statusRightModuleEnabled(statusRightModuleMemory) {
if label := loadMemoryStatusLabel(args.PaneID); label != "" {
segments = append(segments, statusSegment{FG: "#eceff4", BG: "#5e81ac", Text: label})
}
}
segments = append(segments, loadSplitMemoryStatusSegments(args)...)
if statusRightModuleEnabled(statusRightModuleFlashMoe) {
if segment, ok := loadFlashMoeStatusSegment(); ok {
segments = append(segments, segment)
}
}
if statusRightModuleEnabled(statusRightModuleHost) {
if label := loadHostStatusLabel(); label != "" {
segments = append(segments, statusSegment{FG: "#1d1f21", BG: statusThemeColor(), Text: label})
}
}
if statusRightModuleEnabled(statusRightModuleScratch) {
if label := loadScratchStatusLabel(args.SessionName); label != "" {
segments = append(segments, statusSegment{FG: "#1d1f21", BG: "#d75f5f", Text: label, Bold: true, NoRightPadding: true})
}
}
return formatRightStatusSegments(args.StatusBG, segments)
}
func renderTmuxWorkStatus(args tmuxRightStatusArgs) string {
baseBG := "#232530"
leftBG := "#272535"
available := args.Width
if available <= 0 {
available = 120
}
leftParts := make([]string, 0, 3)
if label := loadGoalWorkStatusLabel(args.WindowID); label != "" {
leftParts = append(leftParts, fmt.Sprintf("#[fg=#f8f8f2,bg=#343746] %s %s #[fg=#343746,bg=%s]", statusIconGoal, label, leftBG))
}
if label := loadTodoCountWorkStatusLabel(args.WindowID); label != "" {
leftParts = append(leftParts, fmt.Sprintf("#[fg=#ff79c6,bg=%s] %s %s ", leftBG, statusIconTodos, label))
}
if label := loadTodoPreviewWorkStatusLabel(args.WindowID); label != "" {
leftParts = append(leftParts, fmt.Sprintf("#[fg=#ff79c6,bg=%s]%s #[fg=#ff79c6,bg=%s]%s", leftBG, statusIconNext, leftBG, label))
}
hasLeft := len(leftParts) > 0
msgLabel := loadLastUserMessageLabel(args.WindowID)
var agentPart string
if label := loadAgentWorkStatusLabel(args.WindowID); label != "" {
agentPart = fmt.Sprintf("#[fg=#8be9fd,bg=#233a45] %s %s ", statusIconAgent, label)
}
if len(leftParts) == 0 && msgLabel == "" && agentPart == "" {
return ""
}
left := ""
if hasLeft {
left = strings.Join(leftParts, fmt.Sprintf("#[fg=#c5c8c6,bg=%s] ", leftBG))
}
leftPlain := stripTmuxStyles(left)
agentPlain := stripTmuxStyles(agentPart)
leftMaxWidth := maxInt(1, available*60/100)
if len([]rune(leftPlain)) > leftMaxWidth {
left = truncateStyledWorkStatus(left, leftMaxWidth)
leftPlain = stripTmuxStyles(left)
}
var msgPart string
if msgLabel != "" {
msgSpace := available - len([]rune(leftPlain)) - len([]rune(agentPlain)) - 1
msgPrefixWidth := len([]rune(statusIconLastMsg)) + 1
if hasLeft {
msgPrefixWidth += len([]rune(" │ "))
}
msgMaxWidth := msgSpace - msgPrefixWidth
if msgMaxWidth > 0 {
msg := truncate(msgLabel, msgMaxWidth)
if hasLeft {
msgPart = fmt.Sprintf("#[fg=#3d4050,bg=%s] │ #[fg=#6c7086,bg=%s]%s #[fg=#c5c8c6,bg=%s]%s", baseBG, baseBG, statusIconLastMsg, baseBG, msg)
} else {
msgPart = fmt.Sprintf("#[fg=#6c7086,bg=%s]%s #[fg=#c5c8c6,bg=%s]%s", baseBG, statusIconLastMsg, baseBG, msg)
}
}
}
msgPlain := stripTmuxStyles(msgPart)
middle := left + msgPart
middlePlain := leftPlain + msgPlain
gapWidth := available - len([]rune(middlePlain)) - len([]rune(agentPlain))
if gapWidth < 1 {
gapWidth = 1
}
return fmt.Sprintf("#[fg=#c5c8c6,bg=%s,fill=%s]%s%s%s#[default]", baseBG, baseBG, middle, strings.Repeat(" ", gapWidth), agentPart)
}
var tmuxStylePattern = regexp.MustCompile(`#\[[^]]*\]`)
func stripTmuxStyles(text string) string {
return tmuxStylePattern.ReplaceAllString(text, "")
}
func truncateStyledWorkStatus(text string, width int) string {
plain := stripTmuxStyles(text)
if len([]rune(plain)) <= width {
return text
}
if width <= 0 {
return ""
}
limit := maxInt(0, width-1)
visible := 0
var b strings.Builder
for i := 0; i < len(text); {
if strings.HasPrefix(text[i:], "#[") {
end := strings.IndexByte(text[i:], ']')
if end >= 0 {
end += i
b.WriteString(text[i : end+1])
i = end + 1
continue
}
}
r, size := utf8.DecodeRuneInString(text[i:])
if r == utf8.RuneError && size == 0 {
break
}
if visible >= limit {
break
}
b.WriteRune(r)
visible++
i += size
}
b.WriteRune('…')
return b.String()
}
func loadLastUserMessageLabel(windowID string) string {
windowID = strings.TrimSpace(windowID)
if windowID == "" {
return ""
}
sanitized := sanitizeStateKey(windowID)
stateDir := os.Getenv("XDG_STATE_HOME")
if stateDir == "" {
home, _ := os.UserHomeDir()
stateDir = filepath.Join(home, ".local", "state")
}
path := filepath.Join(stateDir, "op", "lastmsg_"+sanitized)
data, err := os.ReadFile(path)
if err != nil {
return ""
}
text := strings.TrimSpace(string(data))
text = strings.Join(strings.Fields(text), " ")
return text
}
func sanitizeStateKey(s string) string {
var b strings.Builder
for _, r := range s {
if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '_' {
b.WriteRune(r)
} else {
b.WriteByte('_')
}
}
return b.String()
}
func loadAgentWorkStatusLabel(windowID string) string {
windowID = strings.TrimSpace(windowID)
if windowID == "" {
return ""
}
ref, err := statusDetectCurrentAgentFromTmux(windowID)
if err != nil || strings.TrimSpace(ref.ID) == "" {
return ""
}
reg, err := statusLoadRegistry()
if err != nil || reg == nil {
return ""
}
record := reg.Agents[strings.TrimSpace(ref.ID)]
if record == nil {
return ""
}
device := strings.TrimSpace(record.Device)
if device == "" {
device = "no device"
}
return device
}
func loadGoalWorkStatusLabel(windowID string) string {
windowID = strings.TrimSpace(windowID)
if windowID == "" {
return ""
}
store, err := loadGoalStore()
if err != nil || store == nil {
return ""
}
thread := findThreadByWindow(store, windowID)
if thread == nil {
return ""
}
path := goalPathTitles(store, thread.GoalID)
if len(path) == 0 {
return ""
}
return strings.Join(path, " ")
}
func loadTodoCountWorkStatusLabel(windowID string) string {
items, ok := statusTodoItemsForWindow(windowID)
if !ok {
return ""
}
count := 0
for _, item := range items {
if !item.Done {
count++
}
}
if count == 0 {
return ""
}
return fmt.Sprintf("%d", count)
}
func loadTodoPreviewWorkStatusLabel(windowID string) string {
items, ok := statusTodoItemsForWindow(windowID)
if !ok {
return ""
}
title := firstOpenStatusTodoTitle(items)
if title == "" {
return ""
}
return title
}
func loadScratchStatusLabel(currentSessionName string) string {
if scratchSessionName(currentSessionName) {
return ""
}
if scratchTrackerWaiting() {
return fmt.Sprintf(" %s 🔔", statusIconScratch)
}
out, err := statusCommandOutput("tmux", "list-windows", "-t", "Scratch", "-F", "#{window_bell_flag} #{window_activity_flag} #{@unread} #{@watch_failed}")
if err != nil {
out, err = statusCommandOutput("tmux", "list-windows", "-t", "scratch", "-F", "#{window_bell_flag} #{window_activity_flag} #{@unread} #{@watch_failed}")
if err != nil {
return ""
}
}
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
for _, field := range strings.Fields(line) {
if field == "1" {
return fmt.Sprintf(" %s 🔔", statusIconScratch)
}
}
}
return ""
}
func scratchTrackerWaiting() bool {
data, err := os.ReadFile("/tmp/tmux-tracker-cache.json")
if err != nil {
return false
}
var state struct {
Tasks []struct {
SessionID string `json:"session_id"`
Session string `json:"session"`
Status string `json:"status"`
Acknowledged bool `json:"acknowledged"`
} `json:"tasks"`
}
if err := json.Unmarshal(data, &state); err != nil {
return false
}
for _, task := range state.Tasks {
if task.Status == "completed" && !task.Acknowledged && scratchTrackerTaskSession(task.Session, task.SessionID) {
return true
}
}
return false
}
func scratchTrackerTaskSession(sessionName, sessionID string) bool {
if scratchSessionName(sessionName) {
return true
}
for _, target := range []string{"Scratch", "scratch"} {
out, err := statusCommandOutput("tmux", "display-message", "-p", "-t", target, "#{session_id}")
if err == nil && strings.TrimSpace(string(out)) == strings.TrimSpace(sessionID) {
return true
}
}
return false
}
func scratchSessionName(name string) bool {
name = strings.TrimSpace(name)
if match := regexp.MustCompile(`^\d+-(.*)$`).FindStringSubmatch(name); len(match) == 2 {
name = match[1]
}
return strings.EqualFold(name, "scratch")
}
func formatRightStatusSegments(statusBG string, segments []statusSegment) string {
if len(segments) == 0 {
return ""
}
separator := ""
rightCap := "█"
prevBG := statusBG
var builder strings.Builder
for _, segment := range segments {
builder.WriteString(fmt.Sprintf("#[fg=%s,bg=%s]%s#[fg=%s,bg=%s", segment.BG, prevBG, separator, segment.FG, segment.BG))
if segment.Bold {
builder.WriteString(",bold")
}
builder.WriteString("]")
builder.WriteString(segment.Text)
prevBG = segment.BG
}
last := segments[len(segments)-1]
if last.NoRightPadding {
builder.WriteString(fmt.Sprintf("#[bg=%s]", statusBG))
return builder.String()
}
builder.WriteString(fmt.Sprintf(" #[fg=%s,bg=%s]%s", prevBG, statusBG, rightCap))
return builder.String()
}
func statusRightMinimumWidth() int {
value := strings.TrimSpace(os.Getenv("TMUX_RIGHT_MIN_WIDTH"))
if value == "" {
return 90
}
parsed, err := strconv.Atoi(value)
if err != nil || parsed < 1 {
return 90
}
return parsed
}
func statusThemeColor() string {
value := strings.TrimSpace(os.Getenv("TMUX_THEME_COLOR"))
if value == "" {
return "#b294bb"
}
return value
}
func loadCPUStatusLabel() string {
output, err := statusCommandOutput("top", "-l", "1", "-n", "0")
if err != nil {
return ""
}
total, ok := parseCPUUsageTotal(string(output))
if !ok {
return ""
}
return fmt.Sprintf(" %s %s ", statusIconCPU, formatUsagePercent(total))
}
func parseCPUUsageTotal(output string) (float64, bool) {
matches := cpuUsagePattern.FindStringSubmatch(output)
if len(matches) != 3 {
return 0, false
}
user, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
return 0, false
}
system, err := strconv.ParseFloat(matches[2], 64)
if err != nil {
return 0, false
}
total := math.Max(0, user+system)
if total > 100 {
total = 100
}
return total, true
}
func formatUsagePercent(value float64) string {
if value < 10 && math.Abs(value-math.Round(value)) > 0.05 {
return fmt.Sprintf("%.1f%%", value)
}
return fmt.Sprintf("%.0f%%", value)
}
func loadNetworkStatusLabel() string {
preferred := loadPrimaryNetworkInterface()
output, err := statusCommandOutput("netstat", "-ibn")
if err != nil {
return ""
}
counters := parseNetworkCounters(string(output))
iface, current, ok := pickNetworkCounter(counters, preferred)
if !ok {
return ""
}
now := statusNow().UnixMilli()
previous, _ := loadNetworkRateCache()
rate := " ↓-- ↑-- "
if previous.Interface == iface && previous.SampledAt > 0 && now > previous.SampledAt && current.InBytes >= previous.InBytes && current.OutBytes >= previous.OutBytes {
seconds := float64(now-previous.SampledAt) / 1000
if seconds >= 0.25 {
down := float64(current.InBytes-previous.InBytes) / seconds
up := float64(current.OutBytes-previous.OutBytes) / seconds
rate = fmt.Sprintf(" %s ↓%s ↑%s ", statusIconNetwork, formatByteRate(down), formatByteRate(up))
}
}
_ = saveNetworkRateCache(statusNetworkRateCache{
Interface: iface,
InBytes: current.InBytes,
OutBytes: current.OutBytes,
SampledAt: now,
})
if rate == " ↓-- ↑-- " {
return fmt.Sprintf(" %s ↓-- ↑-- ", statusIconNetwork)
}
return rate
}
func loadPrimaryNetworkInterface() string {
output, err := statusCommandOutput("route", "-n", "get", "default")
if err != nil {
return ""
}
scanner := bufio.NewScanner(strings.NewReader(string(output)))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if !strings.HasPrefix(line, "interface:") {
continue
}
return strings.TrimSpace(strings.TrimPrefix(line, "interface:"))
}
return ""
}
func parseNetworkCounters(output string) map[string]statusNetworkCounter {
counters := make(map[string]statusNetworkCounter)
scanner := bufio.NewScanner(strings.NewReader(output))
for scanner.Scan() {
fields := strings.Fields(scanner.Text())
if len(fields) < 10 {
continue
}
name := strings.TrimSuffix(strings.TrimSpace(fields[0]), "*")
if name == "" || strings.EqualFold(name, "Name") {
continue
}
if _, exists := counters[name]; exists {
continue
}
inBytes, err := strconv.ParseUint(fields[6], 10, 64)
if err != nil {
continue
}
outBytes, err := strconv.ParseUint(fields[9], 10, 64)
if err != nil {
continue
}
counters[name] = statusNetworkCounter{InBytes: inBytes, OutBytes: outBytes}
}
return counters
}
func pickNetworkCounter(counters map[string]statusNetworkCounter, preferred string) (string, statusNetworkCounter, bool) {
preferred = strings.TrimSpace(preferred)
if preferred != "" {
if counter, ok := counters[preferred]; ok {
return preferred, counter, true
}
}
var bestName string
var bestCounter statusNetworkCounter
var bestTotal uint64
for name, counter := range counters {
if ignoreNetworkInterface(name) {
continue
}
total := counter.InBytes + counter.OutBytes
if total <= bestTotal {
continue
}
bestName = name
bestCounter = counter
bestTotal = total
}
if bestName == "" {
return "", statusNetworkCounter{}, false
}
return bestName, bestCounter, true
}
func ignoreNetworkInterface(name string) bool {
for _, prefix := range []string{"lo", "awdl", "llw", "gif", "stf", "anpi", "ap", "bridge", "pktap"} {
if strings.HasPrefix(name, prefix) {
return true
}
}
return false
}
func formatByteRate(bytesPerSecond float64) string {
if bytesPerSecond < 0 {
bytesPerSecond = 0
}
units := []string{"B", "K", "M", "G"}
value := bytesPerSecond
unit := units[0]
for _, candidate := range units[1:] {
if value < 1024 {
break
}
value /= 1024
unit = candidate
}
if value < 10 && unit != "B" {
return fmt.Sprintf("%.1f%s", value, unit)
}
return fmt.Sprintf("%.0f%s", value, unit)
}
func loadNetworkRateCache() (statusNetworkRateCache, error) {
data, err := os.ReadFile(statusNetworkRateCachePath())
if err != nil {
return statusNetworkRateCache{}, err
}
var cache statusNetworkRateCache
if err := json.Unmarshal(data, &cache); err != nil {
return statusNetworkRateCache{}, err
}
return cache, nil
}
func saveNetworkRateCache(cache statusNetworkRateCache) error {
data, err := json.Marshal(cache)
if err != nil {
return err
}
path := statusNetworkRateCachePath()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return err
}
tmpPath := path + ".tmp"
if err := os.WriteFile(tmpPath, data, 0o644); err != nil {
return err
}
return os.Rename(tmpPath, path)
}
func loadMemoryStatusLabel(paneID string) string {
paneID = strings.TrimSpace(paneID)
if paneID == "" {
return ""
}
cache, ok := loadMemoryStatusCache()
if !ok {
return ""
}
value := strings.TrimSpace(cache.Pane[paneID])
if value == "" {
return ""
}
return fmt.Sprintf(" %s %s ", statusIconMemory, value)
}
func loadSplitMemoryStatusSegments(args tmuxRightStatusArgs) []statusSegment {
cache, ok := loadMemoryStatusCache()
if !ok {
return nil
}
segments := make([]statusSegment, 0, 3)
windowKey := strings.TrimSpace(args.SessionName)
if windowKey != "" && strings.TrimSpace(args.WindowIndex) != "" {
windowKey = windowKey + ":" + strings.TrimSpace(args.WindowIndex)
}
if statusRightModuleEnabled(statusRightModuleWindowMemory) {
if value := strings.TrimSpace(cache.Window[windowKey]); value != "" {
segments = append(segments, statusSegment{FG: "#eceff4", BG: "#4c566a", Text: fmt.Sprintf(" %s %s ", statusIconWindow, value)})
}
}
if statusRightModuleEnabled(statusRightModuleSessionMemory) {
if value := strings.TrimSpace(cache.Session[strings.TrimSpace(args.SessionName)]); value != "" {
segments = append(segments, statusSegment{FG: "#eceff4", BG: "#434c5e", Text: fmt.Sprintf(" %s %s ", statusIconSession, value)})
}
}
if statusRightModuleEnabled(statusRightModuleTotalMemory) {
if value := strings.TrimSpace(cache.Total); value != "" {
segments = append(segments, statusSegment{FG: "#eceff4", BG: "#3b4252", Text: fmt.Sprintf(" %s %s ", statusIconTotal, value)})
}
}
return segments
}
func loadMemoryStatusCache() (statusMemoryCache, bool) {
refreshMemoryUsageCache()
data, err := os.ReadFile(statusMemoryCachePath())
if err != nil {
return statusMemoryCache{}, false
}
var cache statusMemoryCache
if err := json.Unmarshal(data, &cache); err != nil {
return statusMemoryCache{}, false
}
return cache, true
}
func loadAgentStatusLabel(windowID string) string {
windowID = strings.TrimSpace(windowID)
if windowID == "" {
return ""
}
ref, err := statusDetectCurrentAgentFromTmux(windowID)
if err != nil || strings.TrimSpace(ref.ID) == "" {
return ""
}
reg, err := statusLoadRegistry()
if err != nil || reg == nil {
return ""
}
record := reg.Agents[strings.TrimSpace(ref.ID)]
if record == nil {
return ""
}
device := strings.TrimSpace(record.Device)
if device == "" {
device = "no device"
}
return fmt.Sprintf(" %s %s ", statusIconAgent, device)
}
// loadGoalStatusLabel renders the focused window's goal path + thread name.
func loadGoalStatusLabel(windowID string) string {
windowID = strings.TrimSpace(windowID)
if windowID == "" {
return ""
}
store, err := loadGoalStore()
if err != nil || store == nil {
return ""
}
thread := findThreadByWindow(store, windowID)
if thread == nil {
return ""
}
path := goalPathTitles(store, thread.GoalID)
if len(path) == 0 {
return ""
}
label := strings.Join(path, " ")
return fmt.Sprintf(" %s %s ", statusIconGoal, truncate(label, 40))
}
// goalPathTitles returns ancestor goal titles from root to the given goal.
func goalPathTitles(store *GoalStore, goalID string) []string {
goalID = strings.TrimSpace(goalID)
if goalID == "" || store == nil {
return nil
}
var titles []string
seen := map[string]bool{}
for goalID != "" && !seen[goalID] {
g, ok := store.Goals[goalID]
if !ok {
break
}
seen[goalID] = true
titles = append([]string{strings.TrimSpace(g.Title)}, titles...)
goalID = strings.TrimSpace(g.ParentID)
}
return titles
}
func refreshMemoryUsageCache() {
script := statusMemoryCacheRefreshScript()
if strings.TrimSpace(script) == "" || !fileExists(script) {
return
}
_ = statusCommandStart("python3", script)
}
func loadTodosStatusLabel(windowID string) string {
items, ok := statusTodoItemsForWindow(windowID)
if !ok {
return ""
}
count := 0
for _, item := range items {
if !item.Done {
count++
}
}
if count == 0 {
return ""
}
return fmt.Sprintf(" %s %d ", statusIconTodos, count)
}
func loadStatusTodoCache() (statusTodoCache, bool) {
data, err := os.ReadFile(statusTodoFilePath())
if err != nil {
return statusTodoCache{}, false
}
var cache statusTodoCache
if err := json.Unmarshal(data, &cache); err != nil {
return statusTodoCache{}, false
}
if cache.Global == nil {
cache.Global = []statusTodoItem{}
}
if cache.Sessions == nil {
cache.Sessions = map[string][]statusTodoItem{}
}
if cache.Windows == nil {
cache.Windows = map[string][]statusTodoItem{}
}
return cache, true
}
func statusTodoItemsForWindow(windowID string) ([]statusTodoItem, bool) {
windowID = strings.TrimSpace(windowID)
if windowID == "" {
return nil, false
}
cache, ok := loadStatusTodoCache()
if !ok {
return nil, false
}
return cache.Windows[windowID], true
}
func firstOpenStatusTodoTitle(items []statusTodoItem) string {
for _, item := range items {
if item.Done {
continue
}
title := strings.Join(strings.Fields(strings.TrimSpace(item.Title)), " ")
if title != "" {
return title
}
}
return ""
}
func statusTodoMaxChars() int {
value := strings.TrimSpace(os.Getenv("TMUX_TODO_MAX_CHARS"))
if value == "" {
return 32
}
parsed, err := strconv.Atoi(value)
if err != nil || parsed < 8 {
return 32
}
return parsed
}
func loadFlashMoeStatusSegment() (statusSegment, bool) {
metricsPath := statusFlashMoeMetricsPath()
if strings.TrimSpace(metricsPath) == "" {
return statusSegment{}, false
}
data, err := os.ReadFile(metricsPath)
if err != nil {
return statusSegment{}, false
}
values := map[string]string{}
scanner := bufio.NewScanner(strings.NewReader(string(data)))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" {
continue
}
key, value, ok := strings.Cut(line, "=")
if !ok {
continue
}
values[strings.TrimSpace(key)] = strings.TrimSpace(value)
}
phase := values["phase"]
if updated := strings.TrimSpace(values["updated_ms"]); updated != "" {
if updatedMS, err := strconv.ParseInt(updated, 10, 64); err == nil {
ageMS := statusNow().UnixMilli() - updatedMS
if ageMS > 10000 && (phase == "gen" || phase == "prefill") {
phase = "idle"
}
}
}
switch phase {
case "prefill":
promptTokens := strings.TrimSpace(values["prompt_tokens"])
label := fmt.Sprintf(" %s prefill ", statusIconFlashMoe)
if promptTokens != "" && promptTokens != "0" {
label = fmt.Sprintf(" %s prefill:%s ", statusIconFlashMoe, promptTokens)
}
return statusSegment{FG: "#1d1f21", BG: "#ebcb8b", Text: label, Bold: true}, true
case "gen":
tokS := strings.TrimSpace(values["tok_s"])
label := fmt.Sprintf(" %s gen ", statusIconFlashMoe)
if tokS != "" && tokS != "0.00" {
label = fmt.Sprintf(" %s %s tok/s ", statusIconFlashMoe, tokS)
}
return statusSegment{FG: "#1d1f21", BG: "#a3be8c", Text: label, Bold: true}, true
default:
return statusSegment{}, false
}
}
func loadHostStatusLabel() string {
host, err := statusHostname()
if err != nil {
return ""
}
host = strings.TrimSpace(host)
if host == "" {
return ""
}
if short, _, ok := strings.Cut(host, "."); ok {
host = short
}
return fmt.Sprintf(" %s", host)
}
func defaultStatusRightModuleEnabled(module string) bool {
switch module {
case statusRightModuleCPU, statusRightModuleNetwork, statusRightModuleMemory, statusRightModuleWindowMemory, statusRightModuleSessionMemory, statusRightModuleTotalMemory, statusRightModuleScratch, statusRightModuleFlashMoe, statusRightModuleHost:
return true
default:
return false
}
}
func isValidStatusRightModule(module string) bool {
switch module {
case statusRightModuleCPU, statusRightModuleNetwork, statusRightModuleMemory, statusRightModuleWindowMemory, statusRightModuleSessionMemory, statusRightModuleTotalMemory, statusRightModuleScratch, statusRightModuleFlashMoe, statusRightModuleHost:
return true
default:
return false
}
}
func statusRightModuleEnabled(module string) bool {
if !isValidStatusRightModule(module) {
return false
}
cfg := loadAppConfig()
if cfg.StatusRight == nil {
return defaultStatusRightModuleEnabled(module)
}
return cfg.StatusRight.moduleEnabled(module)
}
func (cfg statusRightConfig) moduleEnabled(module string) bool {
switch module {
case statusRightModuleCPU:
return derefBool(cfg.CPU, defaultStatusRightModuleEnabled(module))
case statusRightModuleNetwork:
return derefBool(cfg.Network, defaultStatusRightModuleEnabled(module))
case statusRightModuleMemory:
return derefBool(cfg.Memory, defaultStatusRightModuleEnabled(module))
case statusRightModuleWindowMemory:
return derefBool(cfg.WindowMemory, derefBool(cfg.MemoryTotals, defaultStatusRightModuleEnabled(module)))
case statusRightModuleSessionMemory:
return derefBool(cfg.SessionMemory, derefBool(cfg.MemoryTotals, defaultStatusRightModuleEnabled(module)))
case statusRightModuleTotalMemory:
return derefBool(cfg.TotalMemory, derefBool(cfg.MemoryTotals, defaultStatusRightModuleEnabled(module)))
case statusRightModuleScratch:
return derefBool(cfg.Scratch, defaultStatusRightModuleEnabled(module))
case statusRightModuleFlashMoe:
return derefBool(cfg.FlashMoe, defaultStatusRightModuleEnabled(module))
case statusRightModuleHost:
return derefBool(cfg.Host, defaultStatusRightModuleEnabled(module))
default:
return false
}
}
func toggleStatusRightModule(module string) error {
if !isValidStatusRightModule(module) {
return fmt.Errorf("unknown status-right module: %s", module)
}
enabled := !statusRightModuleEnabled(module)
return updateAppConfig(func(cfg *appConfig) {
if cfg.StatusRight == nil {
cfg.StatusRight = &statusRightConfig{}
}
cfg.StatusRight.setModuleEnabled(module, enabled)
if cfg.StatusRight.isDefault() {
cfg.StatusRight = nil
}
})
}
func (cfg *statusRightConfig) setModuleEnabled(module string, enabled bool) {
value := boolPtr(enabled)
if enabled == defaultStatusRightModuleEnabled(module) {
value = nil
}
switch module {
case statusRightModuleCPU:
cfg.CPU = value
case statusRightModuleNetwork:
cfg.Network = value
case statusRightModuleMemory:
cfg.Memory = value
case statusRightModuleWindowMemory:
cfg.WindowMemory = value
case statusRightModuleSessionMemory:
cfg.SessionMemory = value
case statusRightModuleTotalMemory:
cfg.TotalMemory = value
case statusRightModuleScratch:
cfg.Scratch = value
case statusRightModuleFlashMoe:
cfg.FlashMoe = value
case statusRightModuleHost:
cfg.Host = value
}
}
func (cfg *statusRightConfig) isDefault() bool {
if cfg == nil {
return true
}
return cfg.CPU == nil && cfg.Network == nil && cfg.Memory == nil && cfg.MemoryTotals == nil && cfg.WindowMemory == nil && cfg.SessionMemory == nil && cfg.TotalMemory == nil && cfg.Scratch == nil && cfg.FlashMoe == nil && cfg.Host == nil
}
func derefBool(value *bool, fallback bool) bool {
if value == nil {
return fallback
}
return *value
}
func boolPtr(value bool) *bool {
ptr := new(bool)
*ptr = value
return ptr
}