@@ -4,6 +4,7 @@ import { useTheme } from '../hooks/use-theme'
44import { formatResetTime } from '../utils/time-format'
55
66import type { ClaudeQuotaData } from '../hooks/use-claude-quota-query'
7+ import type { SubscriptionRateLimit } from '../hooks/use-subscription-query'
78
89interface BottomStatusLineProps {
910 /** Whether Claude OAuth is connected */
@@ -12,70 +13,141 @@ interface BottomStatusLineProps {
1213 isClaudeActive : boolean
1314 /** Quota data from Anthropic API */
1415 claudeQuota ?: ClaudeQuotaData | null
16+ /** Whether the user has an active Codebuff Strong subscription */
17+ hasSubscription : boolean
18+ /** Rate limit data for the subscription */
19+ subscriptionRateLimit ?: SubscriptionRateLimit | null
1520}
1621
1722/**
1823 * Bottom status line component - shows below the input box
19- * Currently displays Claude subscription status when connected
24+ * Displays Claude subscription status and/or Codebuff Strong status
2025 */
2126export const BottomStatusLine : React . FC < BottomStatusLineProps > = ( {
2227 isClaudeConnected,
2328 isClaudeActive,
2429 claudeQuota,
30+ hasSubscription,
31+ subscriptionRateLimit,
2532} ) => {
2633 const theme = useTheme ( )
2734
28- // Don't render if there's nothing to show
29- if ( ! isClaudeConnected ) {
30- return null
31- }
32-
3335 // Use the more restrictive of the two quotas (5-hour window is usually the limiting factor)
34- const displayRemaining = claudeQuota
36+ const claudeDisplayRemaining = claudeQuota
3537 ? Math . min ( claudeQuota . fiveHourRemaining , claudeQuota . sevenDayRemaining )
3638 : null
3739
38- // Check if quota is exhausted (0%)
39- const isExhausted = displayRemaining !== null && displayRemaining <= 0
40+ // Check if Claude quota is exhausted (0%)
41+ const isClaudeExhausted = claudeDisplayRemaining !== null && claudeDisplayRemaining <= 0
4042
41- // Get the reset time for the limiting quota window
42- const resetTime = claudeQuota
43+ // Get the reset time for the limiting Claude quota window
44+ const claudeResetTime = claudeQuota
4345 ? claudeQuota . fiveHourRemaining <= claudeQuota . sevenDayRemaining
4446 ? claudeQuota . fiveHourResetsAt
4547 : claudeQuota . sevenDayResetsAt
4648 : null
4749
48- // Determine dot color: red if exhausted, green if active, muted otherwise
49- const dotColor = isExhausted
50+ // Show Claude when connected and not depleted (takes priority over Strong)
51+ const showClaude = isClaudeConnected && ! isClaudeExhausted
52+ // Show Strong when subscribed AND (no Claude connected OR Claude depleted)
53+ const showStrong = hasSubscription && ( ! isClaudeConnected || isClaudeExhausted )
54+
55+ // Don't render if there's nothing to show
56+ if ( ! showClaude && ! showStrong && ! ( isClaudeConnected && isClaudeExhausted ) ) {
57+ return null
58+ }
59+
60+ // Determine dot color for Claude: red if exhausted, green if active, muted otherwise
61+ const claudeDotColor = isClaudeExhausted
5062 ? theme . error
5163 : isClaudeActive
5264 ? theme . success
5365 : theme . muted
5466
67+ // Subscription remaining percentage (based on weekly)
68+ const subscriptionRemaining = subscriptionRateLimit
69+ ? 100 - subscriptionRateLimit . weeklyPercentUsed
70+ : null
71+ const isSubscriptionLimited = subscriptionRateLimit ?. limited === true
72+
73+ // Get subscription reset time
74+ const subscriptionResetTime = subscriptionRateLimit
75+ ? subscriptionRateLimit . reason === 'block_exhausted' && subscriptionRateLimit . blockResetsAt
76+ ? new Date ( subscriptionRateLimit . blockResetsAt )
77+ : subscriptionRateLimit . weeklyResetsAt
78+ ? new Date ( subscriptionRateLimit . weeklyResetsAt )
79+ : null
80+ : null
81+
82+ // Determine dot color for Strong: red if limited, green if has remaining credits, muted otherwise
83+ const strongDotColor = isSubscriptionLimited
84+ ? theme . error
85+ : subscriptionRemaining !== null && subscriptionRemaining > 0
86+ ? theme . success
87+ : theme . muted
88+
5589 return (
5690 < box
5791 style = { {
5892 width : '100%' ,
5993 flexDirection : 'row' ,
6094 justifyContent : 'flex-end' ,
6195 paddingRight : 1 ,
96+ gap : 2 ,
6297 } }
6398 >
64- < box
65- style = { {
66- flexDirection : 'row' ,
67- alignItems : 'center' ,
68- gap : 0 ,
69- } }
70- >
71- < text style = { { fg : dotColor } } > ●</ text >
72- < text style = { { fg : theme . muted } } > Claude subscription</ text >
73- { isExhausted && resetTime ? (
74- < text style = { { fg : theme . muted } } > { ` · resets in ${ formatResetTime ( resetTime ) } ` } </ text >
75- ) : displayRemaining !== null ? (
76- < BatteryIndicator value = { displayRemaining } theme = { theme } />
77- ) : null }
78- </ box >
99+ { /* Show Claude subscription when connected (even when depleted, to show reset time) */ }
100+ { isClaudeConnected && ! isClaudeExhausted && (
101+ < box
102+ style = { {
103+ flexDirection : 'row' ,
104+ alignItems : 'center' ,
105+ gap : 0 ,
106+ } }
107+ >
108+ < text style = { { fg : claudeDotColor } } > ●</ text >
109+ < text style = { { fg : theme . muted } } > Claude subscription</ text >
110+ { claudeDisplayRemaining !== null ? (
111+ < BatteryIndicator value = { claudeDisplayRemaining } theme = { theme } />
112+ ) : null }
113+ </ box >
114+ ) }
115+
116+ { /* Show Claude as depleted when exhausted */ }
117+ { isClaudeConnected && isClaudeExhausted && (
118+ < box
119+ style = { {
120+ flexDirection : 'row' ,
121+ alignItems : 'center' ,
122+ gap : 0 ,
123+ } }
124+ >
125+ < text style = { { fg : theme . error } } > ●</ text >
126+ < text style = { { fg : theme . muted } } > Claude</ text >
127+ { claudeResetTime && (
128+ < text style = { { fg : theme . muted } } > { ` · resets in ${ formatResetTime ( claudeResetTime ) } ` } </ text >
129+ ) }
130+ </ box >
131+ ) }
132+
133+ { /* Show Codebuff Strong when subscribed and Claude not healthy */ }
134+ { showStrong && (
135+ < box
136+ style = { {
137+ flexDirection : 'row' ,
138+ alignItems : 'center' ,
139+ gap : 0 ,
140+ } }
141+ >
142+ < text style = { { fg : strongDotColor } } > ●</ text >
143+ < text style = { { fg : theme . muted } } > Codebuff Strong</ text >
144+ { isSubscriptionLimited && subscriptionResetTime ? (
145+ < text style = { { fg : theme . muted } } > { ` · resets in ${ formatResetTime ( subscriptionResetTime ) } ` } </ text >
146+ ) : subscriptionRemaining !== null ? (
147+ < BatteryIndicator value = { subscriptionRemaining } theme = { theme } />
148+ ) : null }
149+ </ box >
150+ ) }
79151 </ box >
80152 )
81153}
0 commit comments