Skip to content

feat(cc): add statusline command for Claude Code integration#190

Merged
AnnatarHe merged 4 commits intomainfrom
feat/cc-statusline-command
Jan 4, 2026
Merged

feat(cc): add statusline command for Claude Code integration#190
AnnatarHe merged 4 commits intomainfrom
feat/cc-statusline-command

Conversation

@AnnatarHe
Copy link
Copy Markdown
Contributor

Summary

  • Add shelltime cc statusline command for Claude Code status bar integration
  • Display model name, session cost, daily cost from API, and context window usage
  • Cache daily cost with 5-minute TTL for performance
  • Add documentation at docs/CC_STATUSLINE.md

Usage

Configure in Claude Code settings (~/.claude/settings.json):

{
  "statusLine": {
    "type": "command",
    "command": "shelltime cc statusline"
  }
}

Output format:

🤖 Opus | 💰 $0.12 | 📊 $3.45 | 📈 45%

Test plan

  • Build passes: go build ./cmd/cli/main.go
  • Command appears in help: shelltime cc --help
  • Test with sample JSON input
  • Verify color coding works correctly

🤖 Generated with Claude Code

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>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @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 shelltime CLI tool by adding a new cc statusline command, specifically designed to integrate with Claude Code. This command provides users with real-time insights into their AI usage directly within Claude Code's status bar, displaying the active model, session cost, total daily cost, and context window utilization. The implementation includes robust caching for daily cost data and comprehensive documentation to guide users through setup and troubleshooting.

Highlights

  • New statusline command: Introduces shelltime cc statusline for Claude Code integration.
  • Real-time metrics display: Shows model name, current session cost, daily total cost, and context window usage percentage.
  • Daily cost caching: Implements a 5-minute TTL cache for daily cost to optimize performance.
  • Comprehensive documentation: Adds a new markdown file (docs/CC_STATUSLINE.md) detailing usage, output format, and troubleshooting.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 4, 2026

Codecov Report

❌ Patch coverage is 58.73494% with 137 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
commands/cc_statusline.go 48.80% 43 Missing ⚠️
model/cc_statusline_service.go 0.00% 41 Missing ⚠️
model/cc_statusline_cache.go 0.00% 39 Missing ⚠️
daemon/cc_info_timer.go 95.27% 4 Missing and 2 partials ⚠️
daemon/socket.go 72.72% 5 Missing and 1 partial ⚠️
daemon/client.go 89.47% 1 Missing and 1 partial ⚠️
Flag Coverage Δ
unittests 22.78% <58.73%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
commands/cc.go 0.00% <ø> (ø)
daemon/client.go 41.46% <89.47%> (+41.46%) ⬆️
daemon/cc_info_timer.go 95.27% <95.27%> (ø)
daemon/socket.go 16.21% <72.72%> (+16.21%) ⬆️
model/cc_statusline_cache.go 0.00% <0.00%> (ø)
model/cc_statusline_service.go 0.00% <0.00%> (ø)
commands/cc_statusline.go 48.80% <48.80%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

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.

Comment thread commands/cc_statusline.go
Comment on lines +98 to +100
currentTokens := cw.CurrentUsage.InputTokens +
cw.CurrentUsage.CacheCreationInputTokens +
cw.CurrentUsage.CacheReadInputTokens
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.

high

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

Comment thread commands/cc_statusline.go Outdated
var dailyCost float64
config, err := configService.ReadConfigFile(ctx)
if err == nil {
dailyCost = model.FetchDailyCostCached(ctx, config)
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

Following the removal of the unused ctx parameter from FetchDailyCostCached in model/cc_statusline_service.go, this call should be updated accordingly.

Suggested change
dailyCost = model.FetchDailyCostCached(ctx, config)
dailyCost = model.FetchDailyCostCached(config)

Comment thread commands/cc_statusline.go
Comment on lines +65 to +78
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
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 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

Comment on lines +75 to +80
statuslineCache.entry = &ccStatuslineCacheEntry{
Date: time.Now().Format("2006-01-02"),
CostUsd: costUsd,
FetchedAt: time.Now(),
TTL: statuslineCache.ttl,
}
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

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.

Suggested change
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 {
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 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.

Suggested change
func FetchDailyCostCached(ctx context.Context, config ShellTimeConfig) float64 {
func FetchDailyCostCached(config ShellTimeConfig) float64 {

AnnatarHe and others added 3 commits January 4, 2026 10:35
🤖 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>
@AnnatarHe AnnatarHe merged commit ed80256 into main Jan 4, 2026
3 checks passed
@AnnatarHe AnnatarHe deleted the feat/cc-statusline-command branch January 4, 2026 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant