feat: built-in status line with usage quota display#51
feat: built-in status line with usage quota display#51amDosion wants to merge 1 commit intoclaude-code-best:mainfrom
Conversation
Add BuiltinStatusLine component with token counts, cost tracking, and usage quota display. Refactor StatusLine to use the built-in implementation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughA new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/components/BuiltinStatusLine.tsx (1)
1-6: Usesrc/path alias instead of relative imports.The coding guidelines require using
src/path alias via tsconfig mapping instead of relative paths. These imports should be updated for consistency.♻️ Suggested refactor
import React, { useEffect, useState } from 'react'; -import { formatCost } from '../cost-tracker.js'; -import { Box, Text } from '../ink.js'; -import { formatTokens } from '../utils/format.js'; -import { ProgressBar } from './design-system/ProgressBar.js'; -import { useTerminalSize } from '../hooks/useTerminalSize.js'; +import { formatCost } from 'src/cost-tracker.js'; +import { Box, Text } from 'src/ink.js'; +import { formatTokens } from 'src/utils/format.js'; +import { ProgressBar } from 'src/components/design-system/ProgressBar.js'; +import { useTerminalSize } from 'src/hooks/useTerminalSize.js';As per coding guidelines: "Import
src/path alias via tsconfig mapping instead of relative paths in imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/BuiltinStatusLine.tsx` around lines 1 - 6, Replace the relative import paths in BuiltinStatusLine.tsx with the project tsconfig path alias (src/...) for consistency; update imports for formatCost, Box, Text, formatTokens, ProgressBar, and useTerminalSize to use the src/ path alias (e.g., import { formatCost } from 'src/…') while preserving the same exported symbols and filenames so function/component references (formatCost, Box, Text, formatTokens, ProgressBar, useTerminalSize) continue to resolve correctly.src/components/StatusLine.tsx (2)
22-26: Remove unusedvimModeprop.The
vimModeprop is declared but never used inStatusLineInner(line 32 doesn't destructure it). If it's no longer needed, remove it from thePropstype to avoid confusion.♻️ Suggested refactor
type Props = { messagesRef: React.RefObject<Message[]>; lastAssistantMessageId: string | null; - vimMode?: unknown; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/StatusLine.tsx` around lines 22 - 26, The Props type declares an unused vimMode property; remove vimMode from the Props definition and any related optional typing to keep the shape consistent with StatusLineInner (which does not destructure vimMode). Update the Props type in the file (and any local uses of Props) so it only includes messagesRef and lastAssistantMessageId, and run a quick search for any external references to Props or a vimMode prop usage to remove or adjust them accordingly.
3-15: Inconsistent import style: mix ofsrc/alias and relative paths.Line 4 uses the
src/path alias while the remaining imports use relative paths. Standardize on thesrc/alias per coding guidelines.♻️ Suggested refactor
import { feature } from 'bun:bundle'; import * as React from 'react'; import { memo } from 'react'; import { useAppState } from 'src/state/AppState.js'; -import { getSdkBetas, getKairosActive } from '../bootstrap/state.js'; -import { getTotalCost, getTotalInputTokens, getTotalOutputTokens } from '../cost-tracker.js'; -import { useMainLoopModel } from '../hooks/useMainLoopModel.js'; -import { type ReadonlySettings } from '../hooks/useSettings.js'; -import { getRawUtilization } from '../services/claudeAiLimits.js'; -import type { Message } from '../types/message.js'; -import { calculateContextPercentages, getContextWindowForModel } from '../utils/context.js'; -import { getLastAssistantMessage } from '../utils/messages.js'; -import { getRuntimeMainLoopModel, renderModelName } from '../utils/model/model.js'; -import { doesMostRecentAssistantMessageExceed200k, getCurrentUsage } from '../utils/tokens.js'; -import { BuiltinStatusLine } from './BuiltinStatusLine.js'; +import { getSdkBetas, getKairosActive } from 'src/bootstrap/state.js'; +import { getTotalCost, getTotalInputTokens, getTotalOutputTokens } from 'src/cost-tracker.js'; +import { useMainLoopModel } from 'src/hooks/useMainLoopModel.js'; +import { type ReadonlySettings } from 'src/hooks/useSettings.js'; +import { getRawUtilization } from 'src/services/claudeAiLimits.js'; +import type { Message } from 'src/types/message.js'; +import { calculateContextPercentages, getContextWindowForModel } from 'src/utils/context.js'; +import { getLastAssistantMessage } from 'src/utils/messages.js'; +import { getRuntimeMainLoopModel, renderModelName } from 'src/utils/model/model.js'; +import { doesMostRecentAssistantMessageExceed200k, getCurrentUsage } from 'src/utils/tokens.js'; +import { BuiltinStatusLine } from 'src/components/BuiltinStatusLine.js';As per coding guidelines: "Import
src/path alias via tsconfig mapping instead of relative paths in imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/StatusLine.tsx` around lines 3 - 15, The import list in StatusLine.tsx mixes the src/ alias with relative paths; update all relative imports to use the src/ path alias to match project guidelines. Specifically replace imports for useAppState, getSdkBetas, getKairosActive, getTotalCost, getTotalInputTokens, getTotalOutputTokens, useMainLoopModel, ReadonlySettings, getRawUtilization, Message type, calculateContextPercentages, getContextWindowForModel, getLastAssistantMessage, getRuntimeMainLoopModel, renderModelName, doesMostRecentAssistantMessageExceed200k, getCurrentUsage, and BuiltinStatusLine so they import from 'src/...' (e.g. 'src/bootstrap/state', 'src/cost-tracker', 'src/hooks/useMainLoopModel', 'src/hooks/useSettings', 'src/services/claudeAiLimits', 'src/types/message', 'src/utils/context', 'src/utils/messages', 'src/utils/model/model', 'src/utils/tokens', 'src/components/BuiltinStatusLine') while keeping the existing named symbols unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/StatusLine.tsx`:
- Around line 36-42: Guard against messagesRef.current being null before passing
it to functions that require Message[]: update the logic around
doesMostRecentAssistantMessageExceed200k and getCurrentUsage so they receive a
non-null array (e.g., use messagesRef.current ?? [] or short-circuit when null).
Specifically, ensure the call to doesMostRecentAssistantMessageExceed200k (used
to set exceeds200kTokens) and the call to getCurrentUsage both never get a null
input by checking messagesRef.current and falling back to an empty array before
invoking those functions.
---
Nitpick comments:
In `@src/components/BuiltinStatusLine.tsx`:
- Around line 1-6: Replace the relative import paths in BuiltinStatusLine.tsx
with the project tsconfig path alias (src/...) for consistency; update imports
for formatCost, Box, Text, formatTokens, ProgressBar, and useTerminalSize to use
the src/ path alias (e.g., import { formatCost } from 'src/…') while preserving
the same exported symbols and filenames so function/component references
(formatCost, Box, Text, formatTokens, ProgressBar, useTerminalSize) continue to
resolve correctly.
In `@src/components/StatusLine.tsx`:
- Around line 22-26: The Props type declares an unused vimMode property; remove
vimMode from the Props definition and any related optional typing to keep the
shape consistent with StatusLineInner (which does not destructure vimMode).
Update the Props type in the file (and any local uses of Props) so it only
includes messagesRef and lastAssistantMessageId, and run a quick search for any
external references to Props or a vimMode prop usage to remove or adjust them
accordingly.
- Around line 3-15: The import list in StatusLine.tsx mixes the src/ alias with
relative paths; update all relative imports to use the src/ path alias to match
project guidelines. Specifically replace imports for useAppState, getSdkBetas,
getKairosActive, getTotalCost, getTotalInputTokens, getTotalOutputTokens,
useMainLoopModel, ReadonlySettings, getRawUtilization, Message type,
calculateContextPercentages, getContextWindowForModel, getLastAssistantMessage,
getRuntimeMainLoopModel, renderModelName,
doesMostRecentAssistantMessageExceed200k, getCurrentUsage, and BuiltinStatusLine
so they import from 'src/...' (e.g. 'src/bootstrap/state', 'src/cost-tracker',
'src/hooks/useMainLoopModel', 'src/hooks/useSettings',
'src/services/claudeAiLimits', 'src/types/message', 'src/utils/context',
'src/utils/messages', 'src/utils/model/model', 'src/utils/tokens',
'src/components/BuiltinStatusLine') while keeping the existing named symbols
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b7a7f74a-0f25-4195-82c6-3b8eba7f9d0c
📒 Files selected for processing (2)
src/components/BuiltinStatusLine.tsxsrc/components/StatusLine.tsx
| const exceeds200kTokens = lastAssistantMessageId | ||
| ? doesMostRecentAssistantMessageExceed200k(messagesRef.current) | ||
| : false; | ||
|
|
||
| // StatusLine must have stable height in fullscreen — the footer is | ||
| // flexShrink:0 so a 0→1 row change when the command finishes steals | ||
| // a row from ScrollBox and shifts content. Reserve the row while loading | ||
| // (same trick as PromptInputFooterLeftSide). | ||
| return <Box paddingX={paddingX} gap={2}> | ||
| {statusLineText ? <Text dimColor wrap="truncate"> | ||
| <Ansi>{statusLineText}</Ansi> | ||
| </Text> : isFullscreenEnvEnabled() ? <Text> </Text> : null} | ||
| </Box>; | ||
| const runtimeModel = getRuntimeMainLoopModel({ permissionMode, mainLoopModel, exceeds200kTokens }); | ||
| const modelDisplay = renderModelName(runtimeModel); | ||
| const currentUsage = getCurrentUsage(messagesRef.current); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if these functions handle null/undefined arrays gracefully
ast-grep --pattern 'function doesMostRecentAssistantMessageExceed200k($_) {
$$$
}'
ast-grep --pattern 'function getCurrentUsage($_) {
$$$
}'Repository: claude-code-best/claude-code
Length of output: 54
🏁 Script executed:
#!/bin/bash
# Search for the function definitions with broader patterns
rg "doesMostRecentAssistantMessageExceed200k" -A 5
rg "getCurrentUsage" -A 5Repository: claude-code-best/claude-code
Length of output: 9213
🏁 Script executed:
#!/bin/bash
# Read the StatusLine.tsx file to understand the context
head -50 src/components/StatusLine.tsxRepository: claude-code-best/claude-code
Length of output: 2370
🏁 Script executed:
#!/bin/bash
# Check for messagesRef definition and its type
rg "messagesRef" src/components/StatusLine.tsx -B 2 -A 2Repository: claude-code-best/claude-code
Length of output: 932
🏁 Script executed:
#!/bin/bash
# Find where StatusLineInner or StatusLine component is called
rg "StatusLineInner|<StatusLine" -B 3 -A 3Repository: claude-code-best/claude-code
Length of output: 2710
🏁 Script executed:
#!/bin/bash
# Search for messagesRef creation patterns
rg "messagesRef.*useRef|useRef.*Message" -B 2 -A 2Repository: claude-code-best/claude-code
Length of output: 5260
🏁 Script executed:
#!/bin/bash
# Check the full implementation of both functions to understand null handling
sed -n '1,30p' src/utils/tokens.tsRepository: claude-code-best/claude-code
Length of output: 1384
Guard messagesRef.current before passing to functions expecting non-null arrays.
dossMostRecentAssistantMessageExceed200k and getCurrentUsage are typed to accept Message[], but messagesRef.current has type Message[] | null per React's RefObject typing. The second call at line 42 is unconditional with no guard. While the functions handle empty arrays, they cannot handle null input.
🛡️ Proposed defensive guard
+ const messages = messagesRef.current ?? [];
+
const exceeds200kTokens = lastAssistantMessageId
- ? doesMostRecentAssistantMessageExceed200k(messagesRef.current)
+ ? doesMostRecentAssistantMessageExceed200k(messages)
: false;
const runtimeModel = getRuntimeMainLoopModel({ permissionMode, mainLoopModel, exceeds200kTokens });
const modelDisplay = renderModelName(runtimeModel);
- const currentUsage = getCurrentUsage(messagesRef.current);
+ const currentUsage = getCurrentUsage(messages);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const exceeds200kTokens = lastAssistantMessageId | |
| ? doesMostRecentAssistantMessageExceed200k(messagesRef.current) | |
| : false; | |
| // StatusLine must have stable height in fullscreen — the footer is | |
| // flexShrink:0 so a 0→1 row change when the command finishes steals | |
| // a row from ScrollBox and shifts content. Reserve the row while loading | |
| // (same trick as PromptInputFooterLeftSide). | |
| return <Box paddingX={paddingX} gap={2}> | |
| {statusLineText ? <Text dimColor wrap="truncate"> | |
| <Ansi>{statusLineText}</Ansi> | |
| </Text> : isFullscreenEnvEnabled() ? <Text> </Text> : null} | |
| </Box>; | |
| const runtimeModel = getRuntimeMainLoopModel({ permissionMode, mainLoopModel, exceeds200kTokens }); | |
| const modelDisplay = renderModelName(runtimeModel); | |
| const currentUsage = getCurrentUsage(messagesRef.current); | |
| const messages = messagesRef.current ?? []; | |
| const exceeds200kTokens = lastAssistantMessageId | |
| ? doesMostRecentAssistantMessageExceed200k(messages) | |
| : false; | |
| const runtimeModel = getRuntimeMainLoopModel({ permissionMode, mainLoopModel, exceeds200kTokens }); | |
| const modelDisplay = renderModelName(runtimeModel); | |
| const currentUsage = getCurrentUsage(messages); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/StatusLine.tsx` around lines 36 - 42, Guard against
messagesRef.current being null before passing it to functions that require
Message[]: update the logic around doesMostRecentAssistantMessageExceed200k and
getCurrentUsage so they receive a non-null array (e.g., use messagesRef.current
?? [] or short-circuit when null). Specifically, ensure the call to
doesMostRecentAssistantMessageExceed200k (used to set exceeds200kTokens) and the
call to getCurrentUsage both never get a null input by checking
messagesRef.current and falling back to an empty array before invoking those
functions.
Summary
BuiltinStatusLinecomponent with token counts, cost tracking, and usage quota displayStatusLineto use the built-in implementationFiles changed (2 only)
src/components/BuiltinStatusLine.tsx— new componentsrc/components/StatusLine.tsx— refactored to use built-inReplaces #44 (cleaned up unrelated files).
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes