feat(commands): make daily cost clickable in cc statusline#215
feat(commands): make daily cost clickable in cc statusline#215
Conversation
Add user profile GraphQL service to fetch current user's login, cache it
in the daemon timer (once per lifetime), and use it to wrap the daily
cost section with an OSC8 clickable link pointing to the coding agent
page at {webEndpoint}/users/{login}/coding-agent/claude-code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Summary of ChangesHello @AnnatarHe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 2 files with indirect coverage changes 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request successfully adds a clickable link to the daily cost in the cc statusline, which improves user experience by providing a quick link to the coding agent page. The implementation is well-structured, involving changes in the daemon to fetch and cache user data, and in the CLI to construct and display the link.
My review includes a couple of suggestions:
- In
daemon/cc_info_timer.go, I've identified a potential race condition in how the user profile is fetched and suggested a more robust implementation usingsync.Once. - In
commands/cc_statusline_test.go, I've noted that while existing tests were updated, new tests covering the link generation logic would improve coverage for this new feature.
| func (s *CCInfoTimerService) fetchUserProfile(ctx context.Context) { | ||
| if s.config.Token == "" { | ||
| return | ||
| } | ||
|
|
||
| s.mu.RLock() | ||
| fetched := s.userLoginFetched | ||
| s.mu.RUnlock() | ||
|
|
||
| if fetched { | ||
| return | ||
| } | ||
|
|
||
| profile, err := model.FetchCurrentUserProfile(ctx, *s.config) | ||
| if err != nil { | ||
| slog.Warn("Failed to fetch user profile", slog.Any("err", err)) | ||
| return | ||
| } | ||
|
|
||
| s.mu.Lock() | ||
| s.userLogin = profile.FetchUser.Login | ||
| s.userLoginFetched = true | ||
| s.mu.Unlock() | ||
|
|
||
| slog.Debug("User profile fetched", slog.String("login", profile.FetchUser.Login)) | ||
| } |
There was a problem hiding this comment.
The current implementation of fetchUserProfile has a potential race condition. If it were ever called concurrently, multiple goroutines could pass the if fetched check and perform the network request, which is inefficient. Using sync.Once is the idiomatic Go way to ensure a piece of code is executed exactly once.
To apply this suggestion, you'll also need to modify the CCInfoTimerService struct by replacing userLoginFetched bool with userProfileOnce sync.Once.
func (s *CCInfoTimerService) fetchUserProfile(ctx context.Context) {
s.userProfileOnce.Do(func() {
if s.config.Token == "" {
return
}
profile, err := model.FetchCurrentUserProfile(ctx, *s.config)
if err != nil {
slog.Warn("Failed to fetch user profile", slog.Any("err", err))
return
}
s.mu.Lock()
s.userLogin = profile.FetchUser.Login
s.mu.Unlock()
slog.Debug("User profile fetched", slog.String("login", profile.FetchUser.Login))
})
}|
|
||
| func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_AllValues() { | ||
| output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil) | ||
| output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "", "") |
There was a problem hiding this comment.
While the existing tests for formatStatuslineOutput have been updated to compile, they don't yet cover the new clickable link functionality. Adding a dedicated test case would ensure the OSC8 link is generated correctly when userLogin and webEndpoint are provided.
For example, you could add a new test like this:
func (s *CCStatuslineTestSuite) TestFormatStatuslineOutput_WithClickableLink() {
output := formatStatuslineOutput("claude-opus-4", 1.23, 4.56, 3661, 75.0, "main", false, nil, nil, "testuser", "https://example.com")
expectedURL := "https://example.com/users/testuser/coding-agent/claude-code"
dailyStr := color.Yellow.Sprintf("📊 $%.2f", 4.56)
expectedLink := wrapOSC8Link(expectedURL, dailyStr)
assert.Contains(s.T(), output, expectedLink)
}Since a code suggestion can't add a new function, you could also adapt an existing test to include these assertions.
| if dailyCost > 0 { | ||
| dailyStr := color.Yellow.Sprintf("📊 $%.2f", dailyCost) | ||
| if userLogin != "" && webEndpoint != "" { | ||
| url := fmt.Sprintf("%s/users/%s/coding-agent/claude-code", webEndpoint, userLogin) |
There was a problem hiding this comment.
🟡 User login not URL-encoded when constructing clickable link URL
The userLogin string is directly interpolated into the URL path without URL encoding. If a user's login contains special characters (spaces, @, #, %, or non-ASCII characters), the generated URL would be malformed.
Root Cause
At commands/cc_statusline.go:155, the URL is constructed as:
url := fmt.Sprintf("%s/users/%s/coding-agent/claude-code", webEndpoint, userLogin)The userLogin value comes directly from the GraphQL API response (model/user_profile_service.go:21) and is used without sanitization. While most login systems restrict usernames to safe characters, this is not guaranteed, and URL path segments should be properly encoded using url.PathEscape() to handle edge cases.
Impact: Users with special characters in their login would see broken clickable links in their terminal statusline, leading to 404 errors or incorrect navigation when clicked.
| url := fmt.Sprintf("%s/users/%s/coding-agent/claude-code", webEndpoint, userLogin) | |
| url := fmt.Sprintf("%s/users/%s/coding-agent/claude-code", webEndpoint, url.PathEscape(userLogin)) |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
model/user_profile_service.gowith GraphQL query to fetch current user'sloginUserLoginthroughCCInfoResponsefrom daemon to CLI{webEndpoint}/users/{login}/coding-agent/claude-codeTest plan
go build ./...compiles successfullygo test ./daemon/... ./model/...passgo test -run TestCCStatuslineTestSuite ./commands/pass🤖 Generated with Claude Code