commit a77213f933e916a734c146362bae2edb9b766660 Author: wehub-resource-sync Date: Mon Jul 13 12:49:29 2026 +0800 chore: import upstream snapshot with attribution diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..0bbeeeb --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +buy_me_a_coffee: sirmalloc diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6360c1f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,32 @@ +version: 2 +updates: + - package-ecosystem: bun + directory: / + schedule: + interval: weekly + day: monday + ignore: + - dependency-name: "ink" + open-pull-requests-limit: 10 + cooldown: + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + groups: + dev-dependencies: + dependency-type: development + update-types: + - minor + - patch + production-dependencies: + dependency-type: production + update-types: + - minor + - patch + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d94b2d2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + push: + pull_request: + branches: [main] + +jobs: + lint: + name: Lint & Type Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + - run: bun install + - run: bun run lint + + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + - run: bun install + - run: bun test + + build: + name: Build + runs-on: ubuntu-latest + needs: [lint, test] + steps: + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + - run: bun install + - run: bun run build + - run: test -f dist/ccstatusline.js diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..cf01504 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,36 @@ +name: Publish + +on: + push: + tags: + - "v*" + +permissions: + contents: write + id-token: write + +jobs: + publish: + if: github.repository == 'sirmalloc/ccstatusline' + name: Publish to npm + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + - uses: actions/setup-node@v6 + with: + node-version: 24 + registry-url: "https://registry.npmjs.org" + package-manager-cache: false + - run: bun install + - run: bun run lint + - run: bun test + - run: npm publish + - name: Create GitHub release + run: > + gh release create "$GITHUB_REF_NAME" + --title "$GITHUB_REF_NAME" + --generate-notes + --notes "Published to npm: https://www.npmjs.com/package/ccstatusline" + env: + GH_TOKEN: ${{ github.token }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ece75eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +typedoc +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..2f8df85 --- /dev/null +++ b/.npmignore @@ -0,0 +1,36 @@ +# Source files +src/ +scripts/ +*.ts +*.tsx + +# Development files +bun.lock +CLAUDE.md +.claude/ +test-settings.json + +# Build files +tsconfig.json + +# Test and example files +*.test.* +*.spec.* + +# Git files +.git/ +.gitignore + +# Editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Node modules (in case someone uses npm instead of bun) +node_modules/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6ffce5e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,28 @@ +{ + // Disable trimming trailing whitespace for markdown files to preserve ASCII art + "[markdown]": { + "files.trimTrailingWhitespace": false + }, + + // Keep trimming enabled for other file types + "[typescript]": { + "files.trimTrailingWhitespace": true + }, + "[typescriptreact]": { + "files.trimTrailingWhitespace": true + }, + "[json]": { + "files.trimTrailingWhitespace": true + }, + "[javascript]": { + "files.trimTrailingWhitespace": true + }, + "cSpell.words": [ + "ccstatusline", + "Powerline", + "statusline", + "sublabel", + "Worktree", + "worktrees" + ] +} \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..663d9c0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,151 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## 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 + +## Development Commands + +```bash +# 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:fix +``` + +## Architecture + +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, VoiceStatus - 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