This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
ccstatusline is a customizable status line formatter for Claude Code CLI that displays model info, git branch, token usage, and other metrics. It functions as both:
- A piped command processor for Claude Code status lines
- An interactive TUI configuration tool when run without input
# Install dependencies
bun install
# Run in interactive TUI mode
bun run start
# Test with piped input (use [1m] suffix for 1M context models)
echo '{"model":{"id":"claude-sonnet-4-5-20250929[1m]"},"transcript_path":"test.jsonl"}' | bun run src/ccstatusline.ts
# Or use example payload
bun run example
# Build for npm distribution
bun run build # Creates dist/ccstatusline.js with Node.js 14+ compatibility
# Run tests
bun test
# Run tests in watch mode
bun test --watch
# Lint and type check
bun run lint # Runs TypeScript type checking and ESLint without modifying files
# Apply ESLint auto-fixes intentionally
bun run lint:fixThe project has dual runtime compatibility - works with both Bun and Node.js:
- src/ccstatusline.ts: Main entry point that detects piped vs interactive mode
- Piped mode: Parses JSON from stdin and renders formatted status line
- Interactive mode: Launches React/Ink TUI for configuration
- index.tsx: Main TUI entry point that handles React/Ink initialization
- App.tsx: Root component managing navigation and state
- components/: Modular UI components for different configuration screens
- MainMenu, LineSelector, ItemsEditor, ColorMenu, GlobalOverridesMenu
- PowerlineSetup, TerminalOptionsMenu, StatusLinePreview
- config.ts: Settings management
- Loads from
~/.config/ccstatusline/settings.json - Handles migration from old settings format
- Default configuration if no settings exist
- Loads from
- renderer.ts: Core rendering logic for status lines
- Handles terminal width detection and truncation
- Applies colors, padding, and separators
- Manages flex separator expansion
- powerline.ts: Powerline font detection and installation
- claude-settings.ts: Integration with Claude Code settings.json
- Respects
CLAUDE_CONFIG_DIRenvironment variable with fallback to~/.claude - Provides installation command constants (NPM, BUNX, self-managed)
- Detects installation status and manages settings.json updates
- Validates config directory paths with proper error handling
- Respects
- colors.ts: Color definitions and ANSI code mapping
- model-context.ts: Model-to-context-window mapping
- Maps model IDs to their context window sizes based on [1m] suffix
- Sonnet 4.5 WITH [1m] suffix: 1M tokens (800k usable at 80%) - requires long context beta access
- Sonnet 4.5 WITHOUT [1m] suffix: 200k tokens (160k usable at 80%)
- Legacy models: 200k tokens (160k usable at 80%)
Custom widgets implementing the Widget interface defined in src/types/Widget.ts:
Widget Interface: All widgets must implement:
getDefaultColor(): Default color for the widgetgetDescription(): Description shown in TUIgetDisplayName(): Display name shown in TUIgetEditorDisplay(): How the widget appears in the editorrender(): Core rendering logic that produces the widget outputsupportsRawValue(): Whether widget supports raw value modesupportsColors(): Whether widget supports color customization- Optional:
renderEditor(),getCustomKeybinds(),handleEditorAction()
Widget Registry Pattern:
- Located in src/utils/widgets.ts
- Uses a Map-based registry (
widgetRegistry) that maps widget type strings to widget instances getWidget(type): Retrieves widget instance by typegetAllWidgetTypes(): Returns all available widget typesisKnownWidgetType(): Validates if a type is registered
Available Widgets:
- Model, Version, OutputStyle - Claude Code metadata display
- GitBranch, GitChanges, GitInsertions, GitDeletions, GitWorktree - Git repository status
- TokensInput, TokensOutput, TokensCached, TokensTotal - Token usage metrics
- ContextLength, ContextPercentage, ContextPercentageUsable - Context window metrics (uses dynamic model-based context windows: 1M for Sonnet 4.5 with [1m] suffix, 200k for all other models)
- BlockTimer, SessionClock, SessionCost - Time and cost tracking
- CurrentWorkingDir, TerminalWidth - Environment info
- CustomText, CustomCommand - User-defined widgets
- Cross-platform stdin reading: Detects Bun vs Node.js environment and uses appropriate stdin API
- Token metrics: Parses Claude Code transcript files (JSONL format) to calculate token usage
- Git integration: Uses child_process.execSync to get current branch and changes
- Terminal width management: Three modes for handling width (full, full-minus-40, full-until-compact)
- Flex separators: Special separator type that expands to fill available space
- Powerline mode: Optional Powerline-style rendering with arrow separators
- Custom commands: Execute shell commands and display output in status line
- Mergeable items: Items can be merged together with or without padding
Default to using Bun instead of Node.js:
- Use
bun <file>instead ofnode <file>orts-node <file> - Use
bun installinstead ofnpm install - Use
bun run <script>instead ofnpm run <script> - Use
bun buildwith appropriate options for building - Bun automatically loads .env, so don't use dotenv
- ink@6.2.0 patch: The project uses a patch for ink@6.2.0 to fix backspace key handling on macOS
- Issue: ink treats
\x7f(backspace on macOS) as delete key instead of backspace - Fix: Patches
build/parse-keypress.jsto correctly map\x7fto backspace - Applied automatically during
bun installviapatchedDependenciesin package.json - Patch file:
patches/ink@6.2.0.patch
- Issue: ink treats
- Build process: Two-step build using
bun run buildbun build: Bundles src/ccstatusline.ts into dist/ccstatusline.js targeting Node.js 14+postbuild: Runs scripts/replace-version.ts to replace__PACKAGE_VERSION__placeholder with actual version from package.json
- ESLint configuration: Uses flat config format (eslint.config.js) with TypeScript and React plugins
- Dependencies: All runtime dependencies are bundled using
--packages=externalfor npm package - Type checking and linting: Run checks via
bun run lintand usebun run lint:fixonly when you intentionally want ESLint auto-fixes. Never usenpx eslint,eslint,tsx,bun tsc, or any other variation directly - Lint rules: Never disable a lint rule via a comment, no matter how benign the lint warning or error may seem
- Testing: Uses Vitest (via Bun) with 6 test files and ~40 test cases covering:
- Model context detection and token calculation (src/utils/tests/model-context.test.ts)
- Context percentage calculations (src/utils/tests/context-percentage.test.ts)
- JSONL transcript parsing (src/utils/tests/jsonl.test.ts)
- Widget rendering (src/widgets/tests/*.test.ts)
- Run tests with
bun testorbun test --watchfor watch mode - Test configuration: vitest.config.ts
- Manual testing also available via piped input and TUI interaction