Skip to content

feat: built-in status line with usage quota display#51

Closed
amDosion wants to merge 2 commits intoclaude-code-best:mainfrom
amDosion:feat/status-line-clean
Closed

feat: built-in status line with usage quota display#51
amDosion wants to merge 2 commits intoclaude-code-best:mainfrom
amDosion:feat/status-line-clean

Conversation

@amDosion
Copy link
Copy Markdown
Contributor

@amDosion amDosion commented Apr 2, 2026

Summary

  • Add BuiltinStatusLine component with token counts, cost tracking, and usage quota display
  • Refactor StatusLine to use the built-in implementation

Files changed (2 only)

  • src/components/BuiltinStatusLine.tsx — new component
  • src/components/StatusLine.tsx — refactored to use built-in

Replaces #44 (cleaned up unrelated files).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Compact status line shows model name, context usage %, optional token counts, 5‑hour “Session” and 7‑day “Weekly” rate‑limit percentages with progress bars on wide terminals, reset countdowns (auto‑refresh every 60s), and total cost in USD; layout adapts to terminal width.
  • Changes

    • Status line now displays consistently (except in the special active mode) and updates synchronously for simpler, more immediate feedback.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a memoized synchronous BuiltinStatusLine component that displays model, context usage, optional token counts, rate-limit utilization bars, reset countdowns (refreshed every 60s), and cost. Refactors StatusLine to compute and render this data synchronously, removing the previous async command pipeline.

Changes

Cohort / File(s) Summary
New Status Line Component
src/components/BuiltinStatusLine.tsx
Adds BuiltinStatusLine (memoized) and exported formatCountdown(epochSeconds); renders compact terminal status with model name, context usage %, optional token counts, optional 5‑hour & 7‑day rate-limit utilizations (rounded %), progress bars on wide terminals, reset countdowns updated every 60s, and optional USD cost.
Status Line Refactor
src/components/StatusLine.tsx
Removes async/debounced status-line command execution, AbortController cancellation, trust-dialog/notification/telemetry gating, and statusLineText state. StatusLineInner now derives display values synchronously from runtime inputs and messagesRef.current and renders BuiltinStatusLine directly. statusLineShouldDisplay() now returns false only when KAIROS mode is active; vimMode prop typed as unknown.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I nibble keys and count the hops,
A tiny line that neatly pops.
Bars and tokens, time that ticks,
Costs and models, all the mix —
Hooray for tidy status crops!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: introducing a new built-in status line component with usage quota and token/cost display functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/components/BuiltinStatusLine.tsx (1)

1-6: Use src/ 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 unused vimMode prop.

The vimMode prop is declared but never used in StatusLineInner (line 32 doesn't destructure it). If it's no longer needed, remove it from the Props type 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 of src/ alias and relative paths.

Line 4 uses the src/ path alias while the remaining imports use relative paths. Standardize on the src/ 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

📥 Commits

Reviewing files that changed from the base of the PR and between d04e00f and 28bd4a0.

📒 Files selected for processing (2)
  • src/components/BuiltinStatusLine.tsx
  • src/components/StatusLine.tsx

amDosion pushed a commit to amDosion/claude-code-bast that referenced this pull request Apr 3, 2026
messagesRef.current is typed as Message[] | null per React's RefObject.
doesMostRecentAssistantMessageExceed200k() and getCurrentUsage() expect
Message[], not null. Add ?? [] fallback to prevent runtime error.

Addresses CodeRabbit finding on PR claude-code-best#51.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/StatusLine.tsx (1)

5-6: Use the src/ alias for the touched imports.

This diff adds more relative imports into a TSX file that should resolve through the tsconfig alias. Please switch the modified imports in this block so it stays consistent with the repo standard.

♻️ Suggested import cleanup
-import { getSdkBetas, getKairosActive } from '../bootstrap/state.js';
+import { getSdkBetas, getKairosActive } from 'src/bootstrap/state.js';
-import { getTotalCost, getTotalInputTokens, getTotalOutputTokens } from '../cost-tracker.js';
+import { getTotalCost, getTotalInputTokens, getTotalOutputTokens } from 'src/cost-tracker.js';
-import { type ReadonlySettings } from '../hooks/useSettings.js';
+import { type ReadonlySettings } from 'src/hooks/useSettings.js';
-import { getRuntimeMainLoopModel, renderModelName } from '../utils/model/model.js';
+import { getRuntimeMainLoopModel, renderModelName } from 'src/utils/model/model.js';
-import { BuiltinStatusLine } from './BuiltinStatusLine.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.

Also applies to: 8-8, 13-15

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/StatusLine.tsx` around lines 5 - 6, Update the imports in
StatusLine.tsx to use the tsconfig "src/" path alias instead of relative paths:
replace the import of getSdkBetas and getKairosActive from
'../bootstrap/state.js' with 'src/bootstrap/state' and replace getTotalCost,
getTotalInputTokens, getTotalOutputTokens from '../cost-tracker.js' with
'src/cost-tracker'; keep the same named symbols (getSdkBetas, getKairosActive,
getTotalCost, getTotalInputTokens, getTotalOutputTokens) and ensure file
extensions follow the repo convention (omit .js if the project maps TS/TSX
sources).
🤖 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-47: The StatusLine is reading messagesRef.current (messagesRef)
inside the memoized component which prevents rerenders during token streaming;
change StatusLine to accept messages (or precomputed display metadata) as a prop
and use that prop instead of messagesRef.current when computing
exceeds200kTokens (doesMostRecentAssistantMessageExceed200k), currentUsage
(getCurrentUsage), usedTokens/getTotalInputTokens/getTotalOutputTokens,
runtimeModel (getRuntimeMainLoopModel) and related values; update the parent to
pass the reactive messages array so React can detect changes and remove direct
reads of messagesRef.current from StatusLine to ensure proper rerendering.

---

Nitpick comments:
In `@src/components/StatusLine.tsx`:
- Around line 5-6: Update the imports in StatusLine.tsx to use the tsconfig
"src/" path alias instead of relative paths: replace the import of getSdkBetas
and getKairosActive from '../bootstrap/state.js' with 'src/bootstrap/state' and
replace getTotalCost, getTotalInputTokens, getTotalOutputTokens from
'../cost-tracker.js' with 'src/cost-tracker'; keep the same named symbols
(getSdkBetas, getKairosActive, getTotalCost, getTotalInputTokens,
getTotalOutputTokens) and ensure file extensions follow the repo convention
(omit .js if the project maps TS/TSX sources).
🪄 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: 70ccf894-1dd6-42b3-a6be-315a2edbfcb6

📥 Commits

Reviewing files that changed from the base of the PR and between 28bd4a0 and b6558de.

📒 Files selected for processing (1)
  • src/components/StatusLine.tsx

Comment on lines +36 to +47
const messages = messagesRef.current ?? [];

// Get padding from settings or default to 0
const paddingX = settings?.statusLine?.padding ?? 0;
const exceeds200kTokens = lastAssistantMessageId ? doesMostRecentAssistantMessageExceed200k(messages) : 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(messages);
const contextWindowSize = getContextWindowForModel(runtimeModel, getSdkBetas());
const contextPercentages = calculateContextPercentages(currentUsage, contextWindowSize);
const rawUtil = getRawUtilization();
const totalCost = getTotalCost();
const usedTokens = getTotalInputTokens() + getTotalOutputTokens();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine StatusLine.tsx to see if it's memoized and how it uses messagesRef
cat -n src/components/StatusLine.tsx | head -80

Repository: claude-code-best/claude-code

Length of output: 3088


🏁 Script executed:

# Also check PromptInputFooter.tsx around lines 102-104
cat -n src/components/PromptInput/PromptInputFooter.tsx | sed -n '95,115p'

Repository: claude-code-best/claude-code

Length of output: 1190


🏁 Script executed:

# Check the full StatusLine component signature and exports
grep -A 20 "export" src/components/StatusLine.tsx | head -40

Repository: claude-code-best/claude-code

Length of output: 1441


🏁 Script executed:

# Search for all usages of messagesRef in the codebase
rg "messagesRef" --type ts --type tsx -B 2 -A 2

Repository: claude-code-best/claude-code

Length of output: 99


🏁 Script executed:

# Check if StatusLine is wrapped in memo
rg "memo.*StatusLine\|StatusLine.*memo" --type ts --type tsx

Repository: claude-code-best/claude-code

Length of output: 99


🏁 Script executed:

# Let me search for how messages are updated during streaming to understand if the array reference changes
rg "messages\s*=" --type ts -A 2 -B 2 | head -100

Repository: claude-code-best/claude-code

Length of output: 6337


🏁 Script executed:

# Check how messages are stored in state and whether they're immutably updated
rg "setMessages\|updateMessages" --type ts -A 3 -B 1 | head -80

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Look for streaming-related code to understand message mutations
rg "stream\|token" -i --type ts -l | head -15

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check the AppState to see how messages are managed
find src -name "*AppState*" -o -name "*state*" | head -10

Repository: claude-code-best/claude-code

Length of output: 471


🏁 Script executed:

# Verify what triggers re-renders of StatusLine by checking all props passed to it
rg "StatusLine\s*" --type ts -A 3 -B 1 | grep -A 3 "lastAssistantMessageId\|messagesRef"

Repository: claude-code-best/claude-code

Length of output: 1385


🏁 Script executed:

# Check how the messages array is updated in AppState to understand if it's mutated in place or immutably
cat -n src/components/PromptInput/src/state/AppState.ts | head -100

Repository: claude-code-best/claude-code

Length of output: 298


🏁 Script executed:

# Look for how messages are added/updated in the main state
rg "addMessage\|updateMessage\|pushMessage" -A 5 --type ts | head -60

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check if the streaming process mutates messages in place or creates new arrays
rg "stream" -i -A 3 --type ts | grep -A 3 "message" | head -40

Repository: claude-code-best/claude-code

Length of output: 2322


🏁 Script executed:

# Search for the actual AppState implementation in the main source
find src -name "*.ts" -type f | xargs grep -l "class AppState\|export.*AppState" | grep -v node_modules

Repository: claude-code-best/claude-code

Length of output: 1524


🏁 Script executed:

# Look at how messages state is actually managed - check the main state files
cat -n src/cli/src/state/AppStateStore.ts | head -150

Repository: claude-code-best/claude-code

Length of output: 176


🏁 Script executed:

# Check if messages are immutably updated or mutated in place
rg "messages\s*\[\s*\d+\s*\]|\[\s*\.\.\.messages" --type ts -B 2 -A 2 | head -80

Repository: claude-code-best/claude-code

Length of output: 4976


🏁 Script executed:

# Look for streaming-related state updates to understand if messages array reference changes
rg "streamEvent\|onStreamEvent" -A 5 --type ts | head -80

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check what triggers useMainLoopModel and useAppState rerenders
rg "useMainLoopModel|useAppState" --type ts -B 3 -A 8 | head -100

Repository: claude-code-best/claude-code

Length of output: 6083


🏁 Script executed:

# Look at the actual rendering of StatusLine to understand dependency chain
cat -n src/components/PromptInput/PromptInputFooter.tsx | sed -n '95,140p'

Repository: claude-code-best/claude-code

Length of output: 2732


🏁 Script executed:

# Check if messages prop in PromptInputFooter actually changes on new messages
rg "PromptInputFooter" --type ts -B 5 | grep "messages" | head -20

Repository: claude-code-best/claude-code

Length of output: 1566


🏁 Script executed:

# Verify whether messages is a new array reference each time or same reference
rg "const messages|messages =" --type ts -B 2 -A 2 | grep -A 2 "const messages" | head -40

Repository: claude-code-best/claude-code

Length of output: 2450


🏁 Script executed:

# Check how assistant messages are created and if UUID is immutable
rg "uuid.*assistant\|createAssistantMessage" --type ts -B 3 -A 3 | head -80

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Look at how messages array is updated in state - is it a new array or mutation?
cat -n src/state/AppStateStore.ts | head -200

Repository: claude-code-best/claude-code

Length of output: 10318


🏁 Script executed:

# Check if messages prop actually changes on streaming
rg "transcript\|messages" src/cli/src/state/AppStateStore.ts -A 2 -B 2 | head -60

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Look for where transcript or messages state is updated
rg "transcript\|messages" src/state -A 3 -B 1 --type ts | head -100

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Find where assistant messages are created with UUID
rg "createAssistantMessage\|new.*Message" --type ts -A 5 | head -80

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check if the messages prop passed to PromptInputFooter is a new array reference on each change
rg "PromptInput.*messages=" --type ts -B 5 -A 3 | head -80

Repository: claude-code-best/claude-code

Length of output: 4675


🏁 Script executed:

# Look at the main loop or state management to understand message flow
find src -name "main.tsx" -o -name "index.tsx" -o -name "App.tsx" | xargs ls -la 2>/dev/null | head -10

Repository: claude-code-best/claude-code

Length of output: 368


🏁 Script executed:

# Search more broadly for how messages are updated in state
rg "setAppState\|setState.*message" --type ts -B 2 -A 5 | head -100

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check if messages array is passed as-is or recreated in state management
cat -n src/screens/REPL.tsx | grep -A 5 -B 5 "messages="

Repository: claude-code-best/claude-code

Length of output: 6782


🏁 Script executed:

# Verify if assistant message UUID is immutable once created
rg "uuid.*=\|createAssistantMessage" --type ts | grep -v test | head -20

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check how streaming updates the transcript - mutate in place or create new array?
rg "addStreamEvent\|pushEvent\|transcript\[" --type ts -A 4 -B 2 | head -80

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check if messages array is a new reference each render or same reference
rg "const \[.*messages\|messages.*state\|getState.*messages" --type ts -B 2 -A 2 | head -80

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Look for where messages prop originates in REPL to see if it's a new array each render
cat -n src/screens/REPL.tsx | sed -n '1,100p'

Repository: claude-code-best/claude-code

Length of output: 8829


🏁 Script executed:

# Check how transcript/messages are managed in the store
rg "transcript" src/state --type ts -B 2 -A 3 | head -100

Repository: claude-code-best/claude-code

Length of output: 2302


🏁 Script executed:

# Check if messagesRef itself is recreated or stays stable
rg "StatusLine\s+messagesRef" --type ts -B 10 -A 2 | head -60

Repository: claude-code-best/claude-code

Length of output: 1991


🏁 Script executed:

# Verify how messages array updates during streaming - is it immutably updated?
rg "streaming.*message\|stream.*update" --type ts -i -A 3 -B 1 | head -80

Repository: claude-code-best/claude-code

Length of output: 54


🏁 Script executed:

# Check if messages prop actually changes on each new message or token
cat -n src/screens/REPL.tsx | sed -n '3400,3450p'

Repository: claude-code-best/claude-code

Length of output: 2588


🏁 Script executed:

# Let's trace how messages flow through the component tree to understand if it's a new array each render
cat -n src/components/PromptInput/PromptInput.tsx | sed -n '1,60p'

Repository: claude-code-best/claude-code

Length of output: 1870


🏁 Script executed:

# Check if there's any dependency on messages array reference changes
rg "useEffect.*messages\|useMemo.*messages" --type ts -A 3 | head -60

Repository: claude-code-best/claude-code

Length of output: 1870


🏁 Script executed:

# Verify the exact memoization comparison - does React.memo compare messagesRef by reference?
cat -n src/components/StatusLine.tsx | sed -n '59,62p'

Repository: claude-code-best/claude-code

Length of output: 1870


Pass reactive message state to StatusLine instead of using a ref snapshot.

This memoized component reads messagesRef.current to compute exceeds200kTokens, context usage, and token/cost figures, but the memo optimization prevents rerenders when the ref object stays stable—which happens when the most recent assistant message UUID hasn't changed. This leaves the display frozen during token streaming and after subsequent user messages until an unrelated state change forces a rerender.

Instead, pass messages as a prop (or precomputed display metadata) so React can track actual message changes and rerender accordingly.

🤖 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 - 47, The StatusLine is
reading messagesRef.current (messagesRef) inside the memoized component which
prevents rerenders during token streaming; change StatusLine to accept messages
(or precomputed display metadata) as a prop and use that prop instead of
messagesRef.current when computing exceeds200kTokens
(doesMostRecentAssistantMessageExceed200k), currentUsage (getCurrentUsage),
usedTokens/getTotalInputTokens/getTotalOutputTokens, runtimeModel
(getRuntimeMainLoopModel) and related values; update the parent to pass the
reactive messages array so React can detect changes and remove direct reads of
messagesRef.current from StatusLine to ensure proper rerendering.

@amDosion
Copy link
Copy Markdown
Contributor Author

amDosion commented Apr 3, 2026

这个为什么失败了?之前都是好好的啊,不合进去啊?我这边要改/schedule Create, update, list, or run scheduled remote agents (triggers) that execute on a cron schedule. (bundled) 这个啊. ,账户授权是获取api显示的,key显示也支持
image

amDosion pushed a commit to amDosion/claude-code-bast that referenced this pull request Apr 3, 2026
Cherry-picked from feat/status-line-clean (28bd4a0 + b6558de).
PR claude-code-best#51 not yet merged upstream — apply locally to keep feature working.

Includes null guard fix for messagesRef.current (CodeRabbit finding).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@amDosion
Copy link
Copy Markdown
Contributor Author

amDosion commented Apr 3, 2026

Status line 已通过 #1 合并到 main,此 PR 不再需要。

@amDosion amDosion closed this Apr 3, 2026
@amDosion amDosion reopened this Apr 3, 2026
unraid and others added 2 commits April 3, 2026 19:47
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>
messagesRef.current is typed as Message[] | null per React's RefObject.
doesMostRecentAssistantMessageExceed200k() and getCurrentUsage() expect
Message[], not null. Add ?? [] fallback to prevent runtime error.

Addresses CodeRabbit finding on PR claude-code-best#51.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@amDosion amDosion force-pushed the feat/status-line-clean branch from b6558de to 2bede6c Compare April 3, 2026 11:47
@amDosion
Copy link
Copy Markdown
Contributor Author

amDosion commented Apr 3, 2026

分支已 rebase 到最新 main,将以新 PR 重新提交。

@amDosion amDosion closed this Apr 3, 2026
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