feat(cc): add statusline command for Claude Code integration#190
feat(cc): add statusline command for Claude Code integration#190
Conversation
Add `shelltime cc statusline` command that outputs a formatted status line for Claude Code, displaying model name, session cost, daily cost from API, and context window usage percentage. Features: - Reads JSON from stdin (passed by Claude Code) - Fetches daily cost from GraphQL API with 5-minute cache - Color-coded context percentage (green/yellow/red) - 100ms hard timeout for fast statusline updates - Graceful error handling with fallback output 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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
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 1 file with indirect coverage changes 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request introduces a shelltime cc statusline command for integration with Claude Code, displaying real-time session and cost information. The implementation includes a non-blocking, cached fetch for daily costs and graceful fallbacks. The changes are well-structured and include comprehensive documentation. My review includes a few suggestions for improvement: a correction to the context window calculation, simplification of the stdin reading logic, removal of an unused context parameter, and a minor refinement to the caching logic to prevent potential race conditions.
| currentTokens := cw.CurrentUsage.InputTokens + | ||
| cw.CurrentUsage.CacheCreationInputTokens + | ||
| cw.CurrentUsage.CacheReadInputTokens |
There was a problem hiding this comment.
The calculation for currentTokens appears to be missing cw.CurrentUsage.OutputTokens. The context window is typically consumed by both input and output tokens. The fallback logic on line 105 correctly includes both total input and output tokens, suggesting that OutputTokens from current_usage should also be included here for an accurate percentage.
currentTokens := cw.CurrentUsage.InputTokens +
cw.CurrentUsage.OutputTokens +
cw.CurrentUsage.CacheCreationInputTokens + cw.CurrentUsage.CacheReadInputTokens| var dailyCost float64 | ||
| config, err := configService.ReadConfigFile(ctx) | ||
| if err == nil { | ||
| dailyCost = model.FetchDailyCostCached(ctx, config) |
There was a problem hiding this comment.
| reader := bufio.NewReader(os.Stdin) | ||
| var data []byte | ||
| for { | ||
| line, err := reader.ReadBytes('\n') | ||
| data = append(data, line...) | ||
| if err != nil { | ||
| if err == io.EOF { | ||
| break | ||
| } | ||
| errCh <- err | ||
| return | ||
| } | ||
| } | ||
| resultCh <- data |
There was a problem hiding this comment.
The current implementation for reading from stdin is more complex than necessary. You can simplify this by using io.ReadAll(os.Stdin), which reads from the reader until an error or EOF and returns all the data. This makes the code more concise and easier to understand.
data, err := io.ReadAll(os.Stdin)
if err != nil {
errCh <- err
return
}
resultCh <- data| statuslineCache.entry = &ccStatuslineCacheEntry{ | ||
| Date: time.Now().Format("2006-01-02"), | ||
| CostUsd: costUsd, | ||
| FetchedAt: time.Now(), | ||
| TTL: statuslineCache.ttl, | ||
| } |
There was a problem hiding this comment.
time.Now() is called twice here, once to get the date string and once to get the FetchedAt timestamp. This could theoretically lead to inconsistencies if the execution is paused between the two calls and a day boundary is crossed. It's safer and cleaner to call time.Now() once and reuse the result.
| statuslineCache.entry = &ccStatuslineCacheEntry{ | |
| Date: time.Now().Format("2006-01-02"), | |
| CostUsd: costUsd, | |
| FetchedAt: time.Now(), | |
| TTL: statuslineCache.ttl, | |
| } | |
| now := time.Now() | |
| statuslineCache.entry = &ccStatuslineCacheEntry{ | |
| Date: now.Format("2006-01-02"), | |
| CostUsd: costUsd, | |
| FetchedAt: now, | |
| TTL: statuslineCache.ttl, | |
| } |
| // FetchDailyCostCached returns today's cost from cache or fetches from API | ||
| // This function is non-blocking - if cache is invalid, it returns cached/zero value | ||
| // and triggers a background fetch | ||
| func FetchDailyCostCached(ctx context.Context, config ShellTimeConfig) float64 { |
There was a problem hiding this comment.
The ctx parameter is unused in this function and can be removed to improve code clarity. The background fetch initiated by this function correctly uses context.Background() to ensure it's not cancelled prematurely. Note that this change will require updating the call site in commands/cc_statusline.go.
| func FetchDailyCostCached(ctx context.Context, config ShellTimeConfig) float64 { | |
| func FetchDailyCostCached(config ShellTimeConfig) float64 { |
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cc_info socket message type with time range parameter (today/week/month) - Create CCInfoTimerService with lazy timer pattern: - 3-second fetch interval when active - 3-minute inactivity timeout to stop timer - Cache per requested time range - CLI now requests daily cost from daemon first with 50ms timeout - Falls back to direct API call if daemon unavailable 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CCInfoTimerTestSuite with 21 tests for timer service - Constructor, cache, lifecycle, inactivity, fetch, concurrency tests - Add CCInfoHandlerTestSuite with 4 tests for socket handler - Add CCInfoClientTestSuite with 5 tests for RequestCCInfo client - Add CCStatuslineTestSuite with 11 tests for CLI command - getDailyCostWithDaemonFallback, formatStatuslineOutput, calculateContextPercent - Change CCInfoFetchInterval/CCInfoInactivityTimeout from const to var for testability 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
shelltime cc statuslinecommand for Claude Code status bar integrationdocs/CC_STATUSLINE.mdUsage
Configure in Claude Code settings (
~/.claude/settings.json):{ "statusLine": { "type": "command", "command": "shelltime cc statusline" } }Output format:
Test plan
go build ./cmd/cli/main.goshelltime cc --help🤖 Generated with Claude Code