diff --git a/AGENTS.md b/AGENTS.md index 5672b1c1..87311f19 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,148 +4,90 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -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: -1. A piped command processor for Claude Code status lines -2. An interactive TUI configuration tool when run without input +ccstatusline is a customizable status line formatter for Claude Code CLI. It operates in two modes: +1. **Piped mode**: Reads JSON from stdin (Claude Code session data), renders formatted status line to stdout +2. **Interactive TUI mode**: React/Ink configuration UI when run without piped input (TTY detected) + +Fork of [sirmalloc/ccstatusline](https://github.com/sirmalloc/ccstatusline). Published to npm as `ccstatusline` (v2.2.7). ## Development Commands ```bash -# Install dependencies -bun install - -# Run in interactive TUI mode -bun run start +bun install # Install dependencies +bun run start # Interactive TUI mode +bun run example # Pipe example payload through renderer +bun test # Run all tests (Vitest) +bun test --watch # Watch mode +bun test src/utils/__tests__/git.test.ts # Single test file +bun run lint # TypeScript type check + ESLint (no modifications) +bun run lint:fix # Apply ESLint auto-fixes +bun run build # Bundle to dist/ccstatusline.js (Node 14+) +``` -# Test with piped input (use [1m] suffix for 1M context models) +Test with piped input (use `[1m]` suffix for 1M context models): +```bash 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 +## Architecture -# Build for npm distribution -bun run build # Creates dist/ccstatusline.js with Node.js 14+ compatibility +### Data Flow (Piped Mode) -# Run tests -bun test +``` +stdin JSON → StatusJSONSchema.safeParse() → RenderContext enrichment → Widget rendering → ANSI stdout +``` -# Run tests in watch mode -bun test --watch +1. **Input**: `StatusJSON` (Zod-validated) — model info, transcript path, context window, cost, vim mode, rate_limits +2. **Enrichment**: Supplementary data fetched in parallel — token metrics from transcript JSONL, usage API quotas, session duration, speed metrics, skills tracking +3. **RenderContext**: Combined data object passed to all widgets — contains `data` (original JSON), `tokenMetrics`, `speedMetrics`, `usageData`, `sessionDuration`, `blockMetrics`, `skillsMetrics`, `terminalWidth` +4. **Rendering**: Pre-render all widgets once for width calculation, then assemble up to 3 lines with separators/powerline styling, truncate to terminal width -# Lint and type check -bun run lint # Runs TypeScript type checking and ESLint without modifying files +### Entry Point -# Apply ESLint auto-fixes intentionally -bun run lint:fix -``` +**src/ccstatusline.ts** — Checks `process.stdin.isTTY` to choose piped vs TUI mode. Cross-platform stdin reading (Bun vs Node.js). Windows UTF-8 code page setup. `--config` flag for custom settings path, `--hook` mode for Claude Code hook integration. -## Architecture +### Widget System + +Widgets implement the `Widget` interface (src/types/Widget.ts): `render(item, context, settings)` returns a string or null. Stateless — all state comes from config and render context. + +**Registry**: `src/utils/widget-manifest.ts` — Map-based registry mapping type strings to widget instances. `src/utils/widgets.ts` provides lookup, catalog, and search. + +**Widget categories**: Core metadata (model, version), Git (branch, changes, insertions, deletions, root-dir, worktree), Tokens (input, output, cached, total), Context (length, percentage, bar), Speed (input, output, total with configurable windows), Session (clock, cost, block-timer, reset-timer, weekly timers, usage), Environment (cwd, terminal-width, free-memory, vim-mode), Integration (session-id, session-name, skills, thinking-effort), User-defined (custom-text, custom-command, link), Layout (separator, flex-separator). + +**Widget config** (`WidgetItem`): Each widget instance has `id`, `type`, `color`, `backgroundColor`, `bold`, `rawValue`, `maxWidth`, `merge`, `metadata` (widget-specific flags like `hideNoGit`, `showRemaining`, speed window config). + +### Settings + +Stored at `~/.config/ccstatusline/settings.json`. Schema version 3 with automatic migrations from v1/v2. + +Key settings: `lines` (up to 3 arrays of WidgetItem), `flexMode` (full/full-minus-40/full-until-compact), `colorLevel` (0-3), `powerline` config (separators, themes, caps), global overrides (colors, bold). + +### Rendering Pipeline (src/utils/renderer.ts) + +- Terminal width detection with three flex modes +- Pre-rendering optimization: all widgets rendered once, reused across lines +- Standard mode: separator chars between widgets with padding +- Powerline mode: Unicode arrow/block characters, background color cycling, start/end caps +- ANSI stripping for width calculation, non-breaking space replacement (prevents VSCode trimming) + +### Key Utilities + +- **jsonl.ts / jsonl-metrics.ts / jsonl-blocks.ts**: Parse Claude Code transcript JSONL for token counts, speed, block usage. Results cached with hashed filenames +- **usage-fetch.ts / usage-prefetch.ts**: Anthropic usage API client with 180s caching, proxy support (`HTTPS_PROXY`), macOS keychain auth lookup. Only fetches if widgets need it +- **git.ts**: Cached git command execution (branch, status, remote URL, worktree detection) +- **hyperlink.ts**: OSC8 terminal hyperlink support for GitBranch and GitRootDir widgets +- **model-context.ts**: Model ID → context window size mapping. `[1m]` suffix = 1M tokens, otherwise 200k +- **claude-settings.ts**: Read/write Claude Code's settings.json, detect installation, respects `CLAUDE_CONFIG_DIR` +- **config.ts / migrations.ts**: Settings load/save with version migration and backup on corruption + +### TUI (src/tui/) -The project has dual runtime compatibility - works with both Bun and Node.js: - -### Core Structure -- **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 - -### TUI Components (src/tui/) -- **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 - -### Utilities (src/utils/) -- **config.ts**: Settings management - - Loads from `~/.config/ccstatusline/settings.json` - - Handles migration from old settings format - - Default configuration if no settings exist -- **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_DIR` environment 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 -- **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%) - -### Widgets (src/widgets/) -Custom widgets implementing the Widget interface defined in src/types/Widget.ts: - -**Widget Interface:** -All widgets must implement: -- `getDefaultColor()`: Default color for the widget -- `getDescription()`: Description shown in TUI -- `getDisplayName()`: Display name shown in TUI -- `getEditorDisplay()`: How the widget appears in the editor -- `render()`: Core rendering logic that produces the widget output -- `supportsRawValue()`: Whether widget supports raw value mode -- `supportsColors()`: 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 type -- `getAllWidgetTypes()`: Returns all available widget types -- `isKnownWidgetType()`: 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 - -## Key Implementation Details - -- **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 - -## Bun Usage Preferences - -Default to using Bun instead of Node.js: -- Use `bun ` instead of `node ` or `ts-node ` -- Use `bun install` instead of `npm install` -- Use `bun run