Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion commands/cc_statusline.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,13 @@ func formatStatuslineOutput(modelName string, sessionCost, dailyCost float64, se
// Quota utilization
parts = append(parts, formatQuotaPart(fiveHourUtil, sevenDayUtil))

// AI agent time (magenta)
// 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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential issues with double slashes in the generated URL if webEndpoint has a trailing slash, it's safer to normalize it before formatting the string. Using strings.TrimSuffix will ensure the URL is always correctly formed.

This would be a good improvement for the other URL constructions in this function as well for consistency.

Suggested change
url := fmt.Sprintf("%s/users/%s", webEndpoint, userLogin)
url := fmt.Sprintf("%s/users/%s", strings.TrimSuffix(webEndpoint, "/"), userLogin)

timeStr = wrapOSC8Link(url, timeStr)
}
parts = append(parts, timeStr)
} else {
parts = append(parts, color.Gray.Sprint("⏱️ -"))
Expand Down
21 changes: 21 additions & 0 deletions commands/cc_statusline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,27 @@ func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_SessionCostWithoutLin
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")

// Should contain OSC8 link wrapping time section to user profile
assert.Contains(s.T(), output, "shelltime.xyz/users/testuser")
assert.Contains(s.T(), output, "1h1m")
}

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")
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//")
Comment on lines +369 to +371
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The comment on line 370 is misleading because when userLogin is empty, no user-specific links (including for session and daily cost) should be generated at all. Additionally, the assertion on line 371 is weak as it only checks for a double slash. A more robust test would be to assert that no /users/ path is present in the output, confirming that no user-specific link was created.

Suggested change
// 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//")
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")
assert.Contains(s.T(), output, "1h1m")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test case for an empty webEndpoint is missing an assertion to verify that no link is actually generated. To make the test more complete, you should add an assertion to check that the user profile link is not present in the output.

assert.Contains(s.T(), output, "1h1m")
	assert.NotContains(s.T(), output, "/users/testuser")

}

func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_WithQuota() {
fh := 45.0
sd := 23.0
Expand Down
Loading