Last active
July 17, 2026 19:56
-
-
Save enimiste/b4b33bd45e2d8e5463386524e3d8bd8f to your computer and use it in GitHub Desktop.
Claude code status line shell script (to be put inside .claude folder + configure it in the .claude/settings.json file)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| input=$(cat) | |
| # --------------------------------------------------------------------------- | |
| # Options CLI (défauts : deux lignes, organisation affichée) | |
| # --------------------------------------------------------------------------- | |
| layout="two" # two | one | |
| show_org="yes" # yes | no | |
| path_mode="full" # full | short | |
| for arg in "$@"; do | |
| case "$arg" in | |
| --one-line|--single-line) layout="one" ;; | |
| --two-lines|--two-line) layout="two" ;; | |
| --no-org|--hide-org) show_org="no" ;; | |
| --org|--show-org) show_org="yes" ;; | |
| --full-path|--long-path) path_mode="full" ;; | |
| --short-path|--basename) path_mode="short" ;; | |
| esac | |
| done | |
| # --------------------------------------------------------------------------- | |
| # Colors (ANSI) — use $'...' so \033 is interpreted by the shell | |
| # --------------------------------------------------------------------------- | |
| RESET=$'\033[0m' | |
| BOLD=$'\033[1m' | |
| CYAN=$'\033[36m' | |
| YELLOW=$'\033[33m' | |
| GREEN=$'\033[32m' | |
| BLUE=$'\033[34m' | |
| MAGENTA=$'\033[35m' | |
| RED=$'\033[31m' | |
| GRAY=$'\033[90m' | |
| WHITE=$'\033[97m' | |
| # --------------------------------------------------------------------------- | |
| # 1. Model name | |
| # --------------------------------------------------------------------------- | |
| model=$(echo "$input" | jq -r '.model.display_name // empty') | |
| # --------------------------------------------------------------------------- | |
| # 2. Effort level — from JSON first, fall back to settings.json | |
| # --------------------------------------------------------------------------- | |
| effort=$(echo "$input" | jq -r '.effort.level // empty') | |
| if [ -z "$effort" ]; then | |
| script_dir="$(cd "$(dirname "$0")" 2>/dev/null && pwd)" | |
| settings_file="" | |
| if [ -f "$script_dir/settings.json" ]; then | |
| settings_file="$script_dir/settings.json" | |
| elif [ -f "$HOME/.claude/settings.json" ]; then | |
| settings_file="$HOME/.claude/settings.json" | |
| fi | |
| if [ -n "$settings_file" ]; then | |
| effort=$(jq -r '.effortLevel // empty' "$settings_file" 2>/dev/null) | |
| fi | |
| fi | |
| case "$effort" in | |
| low) effort_label="low" ; effort_color="$GRAY" ;; | |
| medium) effort_label="medium" ; effort_color="$YELLOW" ;; | |
| high) effort_label="high" ; effort_color="$GREEN" ;; | |
| xhigh) effort_label="xhigh" ; effort_color="$CYAN" ;; | |
| max) effort_label="max" ; effort_color="$MAGENTA" ;; | |
| *) effort_label="" ; effort_color="$GRAY" ;; | |
| esac | |
| # --------------------------------------------------------------------------- | |
| # 3. Git branch — run in the cwd reported by Claude Code | |
| # --------------------------------------------------------------------------- | |
| cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty' | grep -v '^$') | |
| [ -z "$cwd" ] && cwd="$(pwd)" | |
| git_branch="" | |
| if command -v git >/dev/null 2>&1; then | |
| git_branch=$(git -C "$cwd" --no-optional-locks branch --show-current 2>/dev/null) | |
| if [ -z "$git_branch" ]; then | |
| git_branch=$(git -C "$cwd" --no-optional-locks rev-parse --short HEAD 2>/dev/null) | |
| [ -n "$git_branch" ] && git_branch="(${git_branch})" | |
| fi | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # 4. Current directory (path complet + basename ; l'affichage dépend du layout) | |
| # --------------------------------------------------------------------------- | |
| current_dir_path=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty' | grep -v '^$') | |
| [ -z "$current_dir_path" ] && current_dir_path="$(pwd)" | |
| current_dir_name=$(basename "$current_dir_path") | |
| # --------------------------------------------------------------------------- | |
| # 4b. Nombre d'échanges (prompts utilisateur) dans la session | |
| # --------------------------------------------------------------------------- | |
| transcript=$(echo "$input" | jq -r '.transcript_path // empty') | |
| msg_count="" | |
| if [ -n "$transcript" ] && [ -f "$transcript" ]; then | |
| msg_count=$(jq -rc 'select(.type=="user" and (.isMeta != true) and ((.message.content|type)=="string" or (.message.content[0].type != "tool_result")))' "$transcript" 2>/dev/null | wc -l | tr -d ' ') | |
| resp_count=$(jq -rc 'select(.type=="assistant") | .message.id // empty' "$transcript" 2>/dev/null | sort -u | grep -c .) | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # 5. Context usage (pourcentage coloré + token counts) | |
| # --------------------------------------------------------------------------- | |
| used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty' | grep -v '^null$') | |
| bar="" | |
| pct_str="" | |
| token_str="" | |
| bar_color="$GRAY" | |
| if [ -n "$used_pct" ]; then | |
| # 2 decimal places for the percentage | |
| pct_str=$(awk "BEGIN {printf \"%.2f%%\", $used_pct}") | |
| pct_int=$(printf "%.0f" "$used_pct") | |
| # (plus de barre ████░░░░ — le code couleur est reporté sur le pourcentage) | |
| if [ "$pct_int" -ge 80 ]; then | |
| bar_color="$RED" | |
| elif [ "$pct_int" -ge 50 ]; then | |
| bar_color="$YELLOW" | |
| else | |
| bar_color="$GREEN" | |
| fi | |
| # Taille max de la fenêtre de contexte (sans le détail des tokens utilisés) | |
| win_size=$(echo "$input" | jq -r '.context_window.context_window_size // empty' | grep -v '^null$') | |
| if [ -n "$win_size" ] && [ "$win_size" -gt 0 ] 2>/dev/null; then | |
| total_k=$(awk "BEGIN {printf \"%.1fk\", $win_size/1000}") | |
| token_str="(${total_k})" | |
| fi | |
| else | |
| # Avant le premier échange : aucun token réel n'est encore compté côté API. | |
| # On laisse bar / pct_str / token_str vides pour masquer le segment "context". | |
| : | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # 5a. Rate limits Claude.ai (session 5h + hebdo 7j) — depuis le stdin only, | |
| # aucun appel réseau. Champs absents (ancienne version / juste après | |
| # /clear) => segments masqués silencieusement. | |
| # --------------------------------------------------------------------------- | |
| now_epoch=$(date +%s) | |
| # Formate un delta de secondes en "Xj YhZZm" (jours omis si 0, heures omises si 0, "0m" si passé) | |
| fmt_countdown() { | |
| d="$1" | |
| if [ -z "$d" ] || [ "$d" -le 0 ] 2>/dev/null; then | |
| printf '0m' | |
| return | |
| fi | |
| days=$((d / 86400)) | |
| h=$(((d % 86400) / 3600)) | |
| m=$(((d % 3600) / 60)) | |
| if [ "$days" -gt 0 ]; then | |
| printf '%dj%dh%02dm' "$days" "$h" "$m" | |
| elif [ "$h" -gt 0 ]; then | |
| printf '%dh%02dm' "$h" "$m" | |
| else | |
| printf '%dm' "$m" | |
| fi | |
| } | |
| # Formate un timestamp epoch en "jour heure:min" lisible (macOS + Linux) | |
| fmt_datetime() { | |
| ts="$1" | |
| # GNU date (Linux) | |
| out=$(date -d "@$ts" '+%a %H:%M' 2>/dev/null) | |
| if [ -z "$out" ]; then | |
| # BSD date (macOS) | |
| out=$(date -r "$ts" '+%a %H:%M' 2>/dev/null) | |
| fi | |
| printf '%s' "$out" | |
| } | |
| pct_color_for() { | |
| p="$1" | |
| pi=$(printf '%.0f' "$p") | |
| if [ "$pi" -ge 80 ]; then | |
| printf '%s' "$RED" | |
| elif [ "$pi" -ge 50 ]; then | |
| printf '%s' "$YELLOW" | |
| else | |
| printf '%s' "$GREEN" | |
| fi | |
| } | |
| # -- Session 5h -------------------------------------------------------------- | |
| five_hour_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty' | grep -v '^null$') | |
| five_hour_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty' | grep -v '^null$') | |
| five_hour_str="" | |
| if [ -n "$five_hour_pct" ]; then | |
| five_hour_color=$(pct_color_for "$five_hour_pct") | |
| five_hour_pct_str=$(printf '%.0f' "$five_hour_pct") | |
| five_hour_str="⏳ ${five_hour_color}${five_hour_pct_str}%${RESET}" | |
| if [ -n "$five_hour_reset" ]; then | |
| five_hour_left=$(fmt_countdown $((five_hour_reset - now_epoch))) | |
| five_hour_str="${five_hour_str} ${GRAY}(${five_hour_left})${RESET}" | |
| fi | |
| fi | |
| # -- Hebdo 7j ----------------------------------------------------------------- | |
| seven_day_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty' | grep -v '^null$') | |
| seven_day_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty' | grep -v '^null$') | |
| seven_day_str="" | |
| if [ -n "$seven_day_pct" ]; then | |
| seven_day_color=$(pct_color_for "$seven_day_pct") | |
| seven_day_pct_str=$(printf '%.0f' "$seven_day_pct") | |
| seven_day_str="📅 ${seven_day_color}${seven_day_pct_str}%${RESET}" | |
| if [ -n "$seven_day_reset" ]; then | |
| seven_day_left=$(fmt_countdown $((seven_day_reset - now_epoch))) | |
| seven_day_str="${seven_day_str} ${GRAY}(${seven_day_left})${RESET}" | |
| fi | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # 6. Organisation + méthode de login (dépendent de la session, pas du stdin) | |
| # --------------------------------------------------------------------------- | |
| # Résolution du .claude.json de la session (respecte CLAUDE_CONFIG_DIR ; | |
| # attention : sans la variable le fichier est $HOME/.claude.json, PAS | |
| # $HOME/.claude/.claude.json). | |
| claude_json="" | |
| if [ -n "$CLAUDE_CONFIG_DIR" ] && [ -f "$CLAUDE_CONFIG_DIR/.claude.json" ]; then | |
| claude_json="$CLAUDE_CONFIG_DIR/.claude.json" | |
| elif [ -f "$HOME/.claude.json" ]; then | |
| claude_json="$HOME/.claude.json" | |
| fi | |
| org_name="" | |
| org_type="" | |
| if [ -n "$claude_json" ]; then | |
| org_name=$(jq -r '.oauthAccount.organizationName // empty' "$claude_json" 2>/dev/null) | |
| org_type=$(jq -r '.oauthAccount.organizationType // empty' "$claude_json" 2>/dev/null) | |
| fi | |
| # Méthode de login (ordre de précédence officiel Claude Code) | |
| if [ -n "$CLAUDE_CODE_USE_BEDROCK" ]; then login_label="bedrock" | |
| elif [ -n "$CLAUDE_CODE_USE_VERTEX" ]; then login_label="vertex" | |
| elif [ -n "$CLAUDE_CODE_USE_FOUNDRY" ]; then login_label="foundry" | |
| elif [ -n "$ANTHROPIC_AUTH_TOKEN" ]; then login_label="gateway" | |
| elif [ -n "$ANTHROPIC_API_KEY" ]; then login_label="api-key" | |
| elif [ -n "$CLAUDE_CODE_OAUTH_TOKEN" ]; then login_label="oauth-token" | |
| elif [ -n "$org_name" ]; then login_label="oauth" | |
| else login_label="?" | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Assemble the status line (layout: two|one) | |
| # Ligne 1: 🤖 model | 💪 effort | 💬 counter | 🪟 context | ⏳ 5h | 📅 7j | |
| # Ligne 2: 🌿 branch | 📁 dir | 🏢 org | 🔑 login | |
| # (en mode --one-line, les deux groupes sont concaténés sur une seule ligne) | |
| # --------------------------------------------------------------------------- | |
| SEP="${GRAY} | ${RESET}" | |
| out="${BOLD}${BLUE}🤖 ${model}${RESET}" | |
| [ -n "$effort_label" ] && out="${out}${SEP}💪 ${effort_color}${effort_label}${RESET}" | |
| # Compteur directionnel (↑ prompts / ↓ réponses) — masqué avant le 1er prompt | |
| if [ -n "$msg_count" ] && [ "$msg_count" -gt 0 ] 2>/dev/null; then | |
| out="${out}${SEP}${CYAN}💬 ${msg_count}↑ ${resp_count:-0}↓${RESET}" | |
| fi | |
| # Context — masqué tant qu'aucune donnée réelle n'est disponible (avant 1er échange) | |
| if [ -n "$used_pct" ]; then | |
| out="${out}${SEP}🪟 ${bar_color}${pct_str}${RESET}" | |
| [ -n "$token_str" ] && out="${out} ${GRAY}${token_str}${RESET}" | |
| fi | |
| # Rate limits Claude.ai (session 5h + hebdo 7j) — juste après le context, | |
| # masqués si absents du stdin | |
| [ -n "$five_hour_str" ] && out="${out}${SEP}${five_hour_str}" | |
| [ -n "$seven_day_str" ] && out="${out}${SEP}${seven_day_str}" | |
| # --- Ligne 2 : branche | dossier | organisation | login --------------------- | |
| # Helper : ajoute un segment à line2, sans séparateur en tête du 1er segment. | |
| line2="" | |
| add2() { | |
| if [ -z "$line2" ]; then | |
| line2="$1" | |
| else | |
| line2="${line2}${SEP}$1" | |
| fi | |
| } | |
| # Git branch en tête de la 2e ligne | |
| [ -n "$git_branch" ] && add2 "${GREEN}🌿 ${git_branch}${RESET}" | |
| # Dossier courant : path absolu complet (--full-path, défaut) ou basename | |
| # (--short-path) — indépendant du layout | |
| if [ "$path_mode" = "short" ]; then | |
| dir_display="$current_dir_name" | |
| else | |
| dir_display="$current_dir_path" | |
| fi | |
| [ -n "$dir_display" ] && add2 "${CYAN}📁 ${dir_display}${RESET}" | |
| # Organisation (nom + type) juste après le dossier — masquée si --no-org | |
| if [ "$show_org" = "yes" ] && [ -n "$org_name" ]; then | |
| org_disp="$org_name" | |
| [ -n "$org_type" ] && org_disp="${org_disp} (${org_type})" | |
| add2 "${MAGENTA}🏢 ${org_disp}${RESET}" | |
| fi | |
| # Méthode de login juste après l'organisation | |
| add2 "${CYAN}🔑 ${login_label}${RESET}" | |
| # Affichage selon le layout | |
| if [ "$layout" = "one" ]; then | |
| # Tout sur une seule ligne : ligne 1 + ligne 2 concaténées | |
| full="$out" | |
| [ -n "$line2" ] && full="${full}${SEP}${line2}" | |
| printf '%s\n' "$full" | |
| else | |
| # Deux lignes : ligne 1 puis ligne 2 (seulement si non vide) | |
| if [ -n "$line2" ]; then | |
| printf '%s\n%s\n' "$out" "$line2" | |
| else | |
| printf '%s\n' "$out" | |
| fi | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| 'use strict'; | |
| // --------------------------------------------------------------------------- | |
| // Claude Code status line (Windows / cross-platform Node.js port) | |
| // Faithful port of statusline-command.sh — no jq / coreutils dependency. | |
| // Order: model | 💪 effort | 💬 counter | 🪟 context | ⏳ 5h | 📅 7j | 🌿 branch | 📁 dir | 🏢 org | 🔑 login | |
| // --------------------------------------------------------------------------- | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const os = require('os'); | |
| const { execFileSync } = require('child_process'); | |
| // --- Colors (ANSI) --------------------------------------------------------- | |
| const RESET = '\x1b[0m'; | |
| const BOLD = '\x1b[1m'; | |
| const CYAN = '\x1b[36m'; | |
| const YELLOW = '\x1b[33m'; | |
| const GREEN = '\x1b[32m'; | |
| const BLUE = '\x1b[34m'; | |
| const MAGENTA = '\x1b[35m'; | |
| const RED = '\x1b[31m'; | |
| const GRAY = '\x1b[90m'; | |
| // --- Read + parse stdin JSON ----------------------------------------------- | |
| let input = {}; | |
| try { | |
| const raw = fs.readFileSync(0, 'utf8'); | |
| input = raw.trim() ? JSON.parse(raw) : {}; | |
| } catch (_) { | |
| input = {}; | |
| } | |
| const get = (obj, pathStr) => { | |
| return pathStr.split('.').reduce((o, k) => (o == null ? undefined : o[k]), obj); | |
| }; | |
| const readJson = (file) => { | |
| try { | |
| return JSON.parse(fs.readFileSync(file, 'utf8')); | |
| } catch (_) { | |
| return null; | |
| } | |
| }; | |
| // --- 1. Model name ---------------------------------------------------------- | |
| const model = get(input, 'model.display_name') || ''; | |
| // --- 2. Effort level (JSON first, then settings.json) ----------------------- | |
| let effort = get(input, 'effort.level') || ''; | |
| if (!effort) { | |
| const candidates = [ | |
| path.join(__dirname, 'settings.json'), | |
| path.join(os.homedir(), '.claude', 'settings.json'), | |
| ]; | |
| for (const f of candidates) { | |
| if (fs.existsSync(f)) { | |
| const s = readJson(f); | |
| if (s && s.effortLevel) { effort = s.effortLevel; break; } | |
| } | |
| } | |
| } | |
| let effortLabel = ''; | |
| let effortColor = GRAY; | |
| switch (effort) { | |
| case 'low': effortLabel = 'low'; effortColor = GRAY; break; | |
| case 'medium': effortLabel = 'medium'; effortColor = YELLOW; break; | |
| case 'high': effortLabel = 'high'; effortColor = GREEN; break; | |
| case 'xhigh': effortLabel = 'xhigh'; effortColor = CYAN; break; | |
| case 'max': effortLabel = 'max'; effortColor = MAGENTA; break; | |
| } | |
| // --- 3. Directory + git branch --------------------------------------------- | |
| const cwd = get(input, 'workspace.current_dir') || get(input, 'cwd') || process.cwd(); | |
| let gitBranch = ''; | |
| try { | |
| gitBranch = execFileSync( | |
| 'git', ['-C', cwd, '--no-optional-locks', 'branch', '--show-current'], | |
| { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] } | |
| ).trim(); | |
| if (!gitBranch) { | |
| const short = execFileSync( | |
| 'git', ['-C', cwd, '--no-optional-locks', 'rev-parse', '--short', 'HEAD'], | |
| { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] } | |
| ).trim(); | |
| if (short) gitBranch = `(${short})`; | |
| } | |
| } catch (_) { /* not a repo / no git */ } | |
| const currentDirName = path.basename(cwd); | |
| // --- 4b. Session exchange counts (↑ prompts / ↓ responses) ------------------ | |
| let msgCount = 0; | |
| let respCount = 0; | |
| const transcript = get(input, 'transcript_path') || ''; | |
| if (transcript && fs.existsSync(transcript)) { | |
| try { | |
| const lines = fs.readFileSync(transcript, 'utf8').split('\n'); | |
| const respIds = new Set(); | |
| for (const line of lines) { | |
| if (!line.trim()) continue; | |
| let e; | |
| try { e = JSON.parse(line); } catch (_) { continue; } | |
| if (e.type === 'user' && e.isMeta !== true) { | |
| const content = e.message && e.message.content; | |
| const isToolResult = | |
| Array.isArray(content) && content[0] && content[0].type === 'tool_result'; | |
| if (typeof content === 'string' || !isToolResult) msgCount++; | |
| } else if (e.type === 'assistant' && e.message && e.message.id) { | |
| respIds.add(e.message.id); | |
| } | |
| } | |
| respCount = respIds.size; | |
| } catch (_) { /* ignore */ } | |
| } | |
| // --- 5. Context usage ------------------------------------------------------- | |
| const usedPct = get(input, 'context_window.used_percentage'); | |
| let pctStr = ''; | |
| let tokenStr = ''; | |
| let barColor = GRAY; | |
| const hasPct = usedPct !== undefined && usedPct !== null; | |
| if (hasPct) { | |
| pctStr = `${Number(usedPct).toFixed(2)}%`; | |
| const pctInt = Math.round(Number(usedPct)); | |
| if (pctInt >= 80) barColor = RED; | |
| else if (pctInt >= 50) barColor = YELLOW; | |
| else barColor = GREEN; | |
| // Taille max de la fenêtre de contexte (sans le détail des tokens utilisés) | |
| const winSize = get(input, 'context_window.context_window_size'); | |
| if (winSize != null && Number(winSize) > 0) { | |
| const totalK = `${(Number(winSize) / 1000).toFixed(1)}k`; | |
| tokenStr = `(${totalK})`; | |
| } | |
| } | |
| // --- 5a. Rate limits Claude.ai (session 5h + hebdo 7j) ---------------------- | |
| // Depuis le stdin uniquement, aucun appel réseau. Champs absents (ancienne | |
| // version / juste après /clear) => segments masqués silencieusement. | |
| const nowEpoch = Math.floor(Date.now() / 1000); | |
| // Formate un delta de secondes en "XhYYm" (ou "YYm" si < 1h, "0m" si passé) | |
| function fmtCountdown(d) { | |
| if (!Number.isFinite(d) || d <= 0) return '0m'; | |
| const h = Math.floor(d / 3600); | |
| const m = Math.floor((d % 3600) / 60); | |
| return h > 0 ? `${h}h${String(m).padStart(2, '0')}m` : `${m}m`; | |
| } | |
| // Formate un timestamp epoch en "jour heure:min" (heure locale, comme date -r) | |
| function fmtDatetime(ts) { | |
| const d = new Date(Number(ts) * 1000); | |
| if (isNaN(d.getTime())) return ''; | |
| const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; | |
| const hh = String(d.getHours()).padStart(2, '0'); | |
| const mm = String(d.getMinutes()).padStart(2, '0'); | |
| return `${days[d.getDay()]} ${hh}:${mm}`; | |
| } | |
| function pctColorFor(p) { | |
| const pi = Math.round(Number(p)); | |
| if (pi >= 80) return RED; | |
| if (pi >= 50) return YELLOW; | |
| return GREEN; | |
| } | |
| // -- Session 5h -- | |
| const fiveHourPct = get(input, 'rate_limits.five_hour.used_percentage'); | |
| const fiveHourReset = get(input, 'rate_limits.five_hour.resets_at'); | |
| let fiveHourStr = ''; | |
| if (fiveHourPct != null) { | |
| fiveHourStr = `⏳ ${pctColorFor(fiveHourPct)}${Math.round(Number(fiveHourPct))}%${RESET}`; | |
| if (fiveHourReset != null) { | |
| const left = fmtCountdown(Number(fiveHourReset) - nowEpoch); | |
| fiveHourStr += ` ${GRAY}(${left})${RESET}`; | |
| } | |
| } | |
| // -- Hebdo 7j -- | |
| const sevenDayPct = get(input, 'rate_limits.seven_day.used_percentage'); | |
| const sevenDayReset = get(input, 'rate_limits.seven_day.resets_at'); | |
| let sevenDayStr = ''; | |
| if (sevenDayPct != null) { | |
| sevenDayStr = `📅 ${pctColorFor(sevenDayPct)}${Math.round(Number(sevenDayPct))}%${RESET}`; | |
| if (sevenDayReset != null) { | |
| const when = fmtDatetime(sevenDayReset); | |
| if (when) sevenDayStr += ` ${GRAY}(${when})${RESET}`; | |
| } | |
| } | |
| // --- 6. Organisation + login method ---------------------------------------- | |
| let claudeJson = ''; | |
| const cfgDir = process.env.CLAUDE_CONFIG_DIR; | |
| if (cfgDir && fs.existsSync(path.join(cfgDir, '.claude.json'))) { | |
| claudeJson = path.join(cfgDir, '.claude.json'); | |
| } else if (fs.existsSync(path.join(os.homedir(), '.claude.json'))) { | |
| claudeJson = path.join(os.homedir(), '.claude.json'); | |
| } | |
| let orgName = ''; | |
| let orgType = ''; | |
| if (claudeJson) { | |
| const cj = readJson(claudeJson); | |
| if (cj && cj.oauthAccount) { | |
| orgName = cj.oauthAccount.organizationName || ''; | |
| orgType = cj.oauthAccount.organizationType || ''; | |
| } | |
| } | |
| let loginLabel; | |
| if (process.env.CLAUDE_CODE_USE_BEDROCK) loginLabel = 'bedrock'; | |
| else if (process.env.CLAUDE_CODE_USE_VERTEX) loginLabel = 'vertex'; | |
| else if (process.env.CLAUDE_CODE_USE_FOUNDRY) loginLabel = 'foundry'; | |
| else if (process.env.ANTHROPIC_AUTH_TOKEN) loginLabel = 'gateway'; | |
| else if (process.env.ANTHROPIC_API_KEY) loginLabel = 'api-key'; | |
| else if (process.env.CLAUDE_CODE_OAUTH_TOKEN) loginLabel = 'oauth-token'; | |
| else if (orgName) loginLabel = 'oauth'; | |
| else loginLabel = '?'; | |
| // --- Assemble --------------------------------------------------------------- | |
| const SEP = `${GRAY} | ${RESET}`; | |
| let out = `${BOLD}${BLUE}${model}${RESET}`; | |
| if (effortLabel) out += `${SEP}💪 ${effortColor}${effortLabel}${RESET}`; | |
| if (msgCount > 0) out += `${SEP}${CYAN}💬 ${msgCount}↑ ${respCount}↓${RESET}`; | |
| if (hasPct) { | |
| out += `${SEP}🪟 ${barColor}${pctStr}${RESET}`; | |
| if (tokenStr) out += ` ${GRAY}${tokenStr}${RESET}`; | |
| } | |
| // Rate limits Claude.ai (session 5h + hebdo 7j) — masqués si absents du stdin | |
| if (fiveHourStr) out += `${SEP}${fiveHourStr}`; | |
| if (sevenDayStr) out += `${SEP}${sevenDayStr}`; | |
| // Git branch juste après les rate limits (avant le dossier) | |
| if (gitBranch) out += `${SEP}${GREEN}🌿 ${gitBranch}${RESET}`; | |
| if (currentDirName) out += `${SEP}${CYAN}📁 ${currentDirName}${RESET}`; | |
| // Organisation puis méthode de login, en fin de barre | |
| if (orgName) { | |
| let orgDisp = orgName; | |
| if (orgType) orgDisp += ` (${orgType})`; | |
| out += `${SEP}${MAGENTA}🏢 ${orgDisp}${RESET}`; | |
| } | |
| out += `${SEP}${CYAN}🔑 ${loginLabel}${RESET}`; | |
| process.stdout.write(out + '\n'); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Two files :