From c06172c0d4198e6b58b8eeb2379c95d79a6b4ce8 Mon Sep 17 00:00:00 2001 From: AnnatarHe Date: Sun, 15 Feb 2026 12:28:11 +0800 Subject: [PATCH] refactor(commands): replace 12 positional params with statuslineParams struct formatStatuslineOutput had 12 positional parameters making call sites hard to read and error-prone. Introduce a statuslineParams struct with named fields for clarity and easier future extension. Co-Authored-By: Claude Opus 4.6 --- commands/cc_statusline.go | 74 ++++++++++----- commands/cc_statusline_test.go | 160 +++++++++++++++++++++++++++++---- 2 files changed, 195 insertions(+), 39 deletions(-) diff --git a/commands/cc_statusline.go b/commands/cc_statusline.go index a14d847..12dd721 100644 --- a/commands/cc_statusline.go +++ b/commands/cc_statusline.go @@ -89,7 +89,20 @@ func commandCCStatusline(c *cli.Context) error { } // Format and output - output := formatStatuslineOutput(data.Model.DisplayName, data.Cost.TotalCostUSD, result.Cost, result.SessionSeconds, contextPercent, result.GitBranch, result.GitDirty, result.FiveHourUtilization, result.SevenDayUtilization, result.UserLogin, result.WebEndpoint, data.SessionID) + output := formatStatuslineOutput(statuslineParams{ + ModelName: data.Model.DisplayName, + SessionCost: data.Cost.TotalCostUSD, + DailyCost: result.Cost, + SessionSeconds: result.SessionSeconds, + ContextPercent: contextPercent, + GitBranch: result.GitBranch, + GitDirty: result.GitDirty, + FiveHourUtil: result.FiveHourUtilization, + SevenDayUtil: result.SevenDayUtilization, + UserLogin: result.UserLogin, + WebEndpoint: result.WebEndpoint, + SessionID: data.SessionID, + }) fmt.Println(output) return nil @@ -145,13 +158,28 @@ func calculateContextPercent(cw model.CCStatuslineContextWindow) float64 { return float64(currentTokens) / float64(cw.ContextWindowSize) * 100 } -func formatStatuslineOutput(modelName string, sessionCost, dailyCost float64, sessionSeconds int, contextPercent float64, gitBranch string, gitDirty bool, fiveHourUtil, sevenDayUtil *float64, userLogin, webEndpoint, sessionID string) string { +type statuslineParams struct { + ModelName string + SessionCost float64 + DailyCost float64 + SessionSeconds int + ContextPercent float64 + GitBranch string + GitDirty bool + FiveHourUtil *float64 + SevenDayUtil *float64 + UserLogin string + WebEndpoint string + SessionID string +} + +func formatStatuslineOutput(p statuslineParams) string { var parts []string // Git info FIRST (green) - if gitBranch != "" { - gitStr := gitBranch - if gitDirty { + if p.GitBranch != "" { + gitStr := p.GitBranch + if p.GitDirty { gitStr += "*" } parts = append(parts, color.Green.Sprintf("🌿 %s", gitStr)) @@ -160,22 +188,22 @@ func formatStatuslineOutput(modelName string, sessionCost, dailyCost float64, se } // Model name - modelStr := fmt.Sprintf("🤖 %s", modelName) + modelStr := fmt.Sprintf("🤖 %s", p.ModelName) parts = append(parts, modelStr) // Session cost (cyan) - clickable link to session page when user login and session ID are available - sessionStr := color.Cyan.Sprintf("💰 $%.2f", sessionCost) - if userLogin != "" && webEndpoint != "" && sessionID != "" { - url := fmt.Sprintf("%s/users/%s/coding-agent/session/%s", webEndpoint, userLogin, sessionID) + sessionStr := color.Cyan.Sprintf("💰 $%.2f", p.SessionCost) + if p.UserLogin != "" && p.WebEndpoint != "" && p.SessionID != "" { + url := fmt.Sprintf("%s/users/%s/coding-agent/session/%s", p.WebEndpoint, p.UserLogin, p.SessionID) sessionStr = wrapOSC8Link(url, sessionStr) } parts = append(parts, sessionStr) // Daily cost (yellow) - clickable link to coding agent page when user login is available - if dailyCost > 0 { - dailyStr := color.Yellow.Sprintf("📊 $%.2f", dailyCost) - if userLogin != "" && webEndpoint != "" { - url := fmt.Sprintf("%s/users/%s/coding-agent/claude-code", webEndpoint, userLogin) + if p.DailyCost > 0 { + dailyStr := color.Yellow.Sprintf("📊 $%.2f", p.DailyCost) + if p.UserLogin != "" && p.WebEndpoint != "" { + url := fmt.Sprintf("%s/users/%s/coding-agent/claude-code", p.WebEndpoint, p.UserLogin) dailyStr = wrapOSC8Link(url, dailyStr) } parts = append(parts, dailyStr) @@ -185,14 +213,14 @@ func formatStatuslineOutput(modelName string, sessionCost, dailyCost float64, se // Quota utilization (macOS only - requires Keychain for OAuth token) if runtime.GOOS == "darwin" { - parts = append(parts, formatQuotaPart(fiveHourUtil, sevenDayUtil)) + parts = append(parts, formatQuotaPart(p.FiveHourUtil, p.SevenDayUtil)) } // AI agent time (magenta) - clickable link to user profile - if sessionSeconds > 0 { - timeStr := color.Magenta.Sprintf("⏱️ %s", formatSessionDuration(sessionSeconds)) - if userLogin != "" && webEndpoint != "" { - url := fmt.Sprintf("%s/users/%s", webEndpoint, userLogin) + if p.SessionSeconds > 0 { + timeStr := color.Magenta.Sprintf("⏱️ %s", formatSessionDuration(p.SessionSeconds)) + if p.UserLogin != "" && p.WebEndpoint != "" { + url := fmt.Sprintf("%s/users/%s", p.WebEndpoint, p.UserLogin) timeStr = wrapOSC8Link(url, timeStr) } parts = append(parts, timeStr) @@ -203,12 +231,12 @@ func formatStatuslineOutput(modelName string, sessionCost, dailyCost float64, se // Context percentage with color coding var contextStr string switch { - case contextPercent >= 80: - contextStr = color.Red.Sprintf("📈 %.0f%%", contextPercent) - case contextPercent >= 50: - contextStr = color.Yellow.Sprintf("📈 %.0f%%", contextPercent) + case p.ContextPercent >= 80: + contextStr = color.Red.Sprintf("📈 %.0f%%", p.ContextPercent) + case p.ContextPercent >= 50: + contextStr = color.Yellow.Sprintf("📈 %.0f%%", p.ContextPercent) default: - contextStr = color.Green.Sprintf("📈 %.0f%%", contextPercent) + contextStr = color.Green.Sprintf("📈 %.0f%%", p.ContextPercent) } parts = append(parts, contextStr) diff --git a/commands/cc_statusline_test.go b/commands/cc_statusline_test.go index de1c6a0..5758ed1 100644 --- a/commands/cc_statusline_test.go +++ b/commands/cc_statusline_test.go @@ -151,7 +151,14 @@ func (s *CCStatuslineTestSuite) TestGetDaemonInfo_UsesDefaultSocketPath() { // formatStatuslineOutput Tests func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_AllValues() { - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + }) // Should contain all components assert.Contains(s.T(), output, "🌿 main") @@ -163,7 +170,15 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_AllValues() { } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_WithDirtyBranch() { - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "feature/test", true, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "feature/test", + GitDirty: true, + }) // Should contain branch with asterisk for dirty assert.Contains(s.T(), output, "🌿 feature/test*") @@ -171,7 +186,13 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_WithDirtyBranch() { } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_NoBranch() { - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "", false, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + }) // Should show "-" for no branch assert.Contains(s.T(), output, "🌿 -") @@ -179,7 +200,13 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_NoBranch() { } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_ZeroDailyCost() { - output := formatStatuslineOutput("claude-sonnet", 0.50, 0, 300, 50.0, "main", false, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-sonnet", + SessionCost: 0.50, + SessionSeconds: 300, + ContextPercent: 50.0, + GitBranch: "main", + }) // Should show "-" for zero daily cost assert.Contains(s.T(), output, "📊 -") @@ -187,14 +214,27 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_ZeroDailyCost() { } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_ZeroSessionSeconds() { - output := formatStatuslineOutput("claude-sonnet", 0.50, 1.0, 0, 50.0, "main", false, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-sonnet", + SessionCost: 0.50, + DailyCost: 1.0, + ContextPercent: 50.0, + GitBranch: "main", + }) // Should show "-" for zero session seconds assert.Contains(s.T(), output, "⏱️ -") } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_HighContextPercentage() { - output := formatStatuslineOutput("test-model", 1.0, 1.0, 60, 85.0, "main", false, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "test-model", + SessionCost: 1.0, + DailyCost: 1.0, + SessionSeconds: 60, + ContextPercent: 85.0, + GitBranch: "main", + }) // Should contain the percentage (color codes may vary) assert.Contains(s.T(), output, "85%") @@ -202,7 +242,14 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_HighContextPercentage } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_LowContextPercentage() { - output := formatStatuslineOutput("test-model", 1.0, 1.0, 45, 25.0, "main", false, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "test-model", + SessionCost: 1.0, + DailyCost: 1.0, + SessionSeconds: 45, + ContextPercent: 25.0, + GitBranch: "main", + }) // Should contain the percentage assert.Contains(s.T(), output, "25%") @@ -330,7 +377,17 @@ func (s *CCStatuslineTestSuite) TestFormatQuotaPart_ContainsLink() { } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_SessionCostWithLink() { - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "testuser", "https://shelltime.xyz", "session-abc123") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + UserLogin: "testuser", + WebEndpoint: "https://shelltime.xyz", + SessionID: "session-abc123", + }) // Should contain OSC8 link wrapping session cost assert.Contains(s.T(), output, "shelltime.xyz/users/testuser/coding-agent/session/session-abc123") @@ -340,23 +397,60 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_SessionCostWithLink() func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_SessionCostWithoutLink() { // No userLogin - should not have link - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "", "https://shelltime.xyz", "session-abc123") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + WebEndpoint: "https://shelltime.xyz", + SessionID: "session-abc123", + }) assert.Contains(s.T(), output, "$1.23") assert.NotContains(s.T(), output, "coding-agent/session/") // No sessionID - should not have link - output = formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "testuser", "https://shelltime.xyz", "") + output = formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + UserLogin: "testuser", + WebEndpoint: "https://shelltime.xyz", + }) assert.Contains(s.T(), output, "$1.23") assert.NotContains(s.T(), output, "coding-agent/session/") // No webEndpoint - should not have link - output = formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "testuser", "", "session-abc123") + output = formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + UserLogin: "testuser", + SessionID: "session-abc123", + }) assert.Contains(s.T(), output, "$1.23") assert.NotContains(s.T(), output, "coding-agent/session/") } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_TimeWithProfileLink() { - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "testuser", "https://shelltime.xyz", "session-abc123") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + UserLogin: "testuser", + WebEndpoint: "https://shelltime.xyz", + SessionID: "session-abc123", + }) // Should contain OSC8 link wrapping time section to user profile assert.Contains(s.T(), output, "shelltime.xyz/users/testuser") @@ -365,21 +459,48 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_TimeWithProfileLink() func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_TimeWithoutProfileLink() { // No userLogin - should not have profile link on time - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "", "https://shelltime.xyz", "session-abc123") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + WebEndpoint: "https://shelltime.xyz", + SessionID: "session-abc123", + }) assert.Contains(s.T(), output, "1h1m") // The time section should not contain a link to users/ profile // Count occurrences of "shelltime.xyz/users/" - should only be in session cost and daily cost links assert.NotContains(s.T(), output, "shelltime.xyz/users//") // No webEndpoint - should not have profile link on time - output = formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "testuser", "", "session-abc123") + output = formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + UserLogin: "testuser", + SessionID: "session-abc123", + }) assert.Contains(s.T(), output, "1h1m") } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_WithQuota() { fh := 45.0 sd := 23.0 - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, &fh, &sd, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + FiveHourUtil: &fh, + SevenDayUtil: &sd, + }) if runtime.GOOS == "darwin" { assert.Contains(s.T(), output, "5h:45%") @@ -391,7 +512,14 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_WithQuota() { } func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_WithoutQuota() { - output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "", "", "") + output := formatStatuslineOutput(statuslineParams{ + ModelName: "claude-opus-4", + SessionCost: 1.23, + DailyCost: 4.56, + SessionSeconds: 3661, + ContextPercent: 75.0, + GitBranch: "main", + }) if runtime.GOOS == "darwin" { assert.Contains(s.T(), output, "🚦 -")