Squash al branch-ului de lucru plan13-s2. Clase: ofacturare (nucleul formularului unificat), ofacturare_comun, ferestre_cere_date, ocomenzi, caut_ora (lista de preturi in combo-urile de cautare), omodificari. Programe: ofacturare impartit - ofacturare_antet, ofacturare_rutare_scriere si ogrid_latimi sunt fisiere noi; oproceduri_facturare primeste discountul pe linie si cota standard de TVA cand articolul nu are cota pe politica. Documentatie: capcana SQLExec no_data_found, conventia de encoding, depanarea testelor VFP si regulile de lucru - conflictele cu modificarile venite din alte proiecte sunt rezolvate pastrand ambele parti. Loguri de rulare a testelor scoase din versionare; testele raman. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
10 KiB
Prompt pentru alta sesiune: recreeaza statusline-ul Claude Code
Copiaza tot ce urmeaza si trimite-l ca prompt intr-o sesiune Claude Code noua (pe alta masina/user), ca sa recreeze exact statusline-ul curent (Windows / Git Bash).
Vreau sa configurezi un statusline custom pentru Claude Code, pe Windows cu Git Bash.
-
Verifica ca exista
jq.exein~/.claude/bin/jq.exe. Daca nu exista, descarca binarul oficial jq pentru Windows (jq-win64.exe de pe github.com/jqlang/jq/releases) si salveaza-l acolo cajq.exe. -
Creeaza fisierul
~/.claude/statusline.sh(bash, LF, executabil) cu continutul de mai jos. -
In
~/.claude/settings.json, adauga/actualizeaza cheia de nivel radacina:"statusLine": { "type": "command", "command": "C:/Users/<USER>/.claude/statusline.sh" }(inlocuieste
<USER>cu userul curent; foloseste slash-uri, nu backslash).
Ce face scriptul:
- Linia 1: model | ctx folosit/total si % din fereastra | proiect (branch git, cu
*daca e dirty) - Linia 2: trei bare de puncte (10 puncte fiecare) pentru consum curent (5h), saptamanal (7 zile)
si sonnet (7 zile) — procent + timp pana la reset, in format
●●●○○○○○○○ 30% ↺ 2hr 15min - Cele trei procente vin din
/api/oauth/usage(acelasi endpoint ca ecranul/usage), cu cache de 10 minute in~/.claude/.statusline-usage.jsonsi backoff la 429/eroare (20 min, respectiv 5 min), ca sa nu loveasca rate-limit-ul la fiecare prompt. - Pana la primul fetch reusit, current/weekly cad back pe
rate_limitsdin JSON-ul primit pe stdin. - Token-ul OAuth se ia din
~/.claude/.credentials.json(claudeAiOauth.accessToken). - La inceput reface PATH-ul (
$HOME/.claude/bin:/usr/bin:/bin:$PATH), pentru ca Claude Code lanseaza scriptul ca shell non-login/non-interactiv, deci profilul Git Bash nu se incarca si PATH-ul nu are coreutils.
Continutul complet al ~/.claude/statusline.sh:
#!/bin/bash
# Claude Code Statusline (Windows / Git Bash)
# Line 1: Model | ctx 33K/1M 3% | project (branch*)
# Line 2: current <bar> 24% ↺ 3hr │ weekly <bar> 4% ↺ Thu 7pm │ sonnet <bar> 2% ↺ Thu 7pm
#
# All three usage figures come from /api/oauth/usage -- the same source as the
# `/usage` screen -- so the numbers match it exactly. That endpoint is rate-
# limited, so the result is cached for 10 min; on failure the last good values
# are kept. Until the first successful fetch, current/weekly fall back to the
# `rate_limits` object on stdin (slightly different snapshot, but never blank).
set -o pipefail
# Claude Code spawns this as a non-login, non-interactive shell, so Git Bash's
# profile is never sourced and PATH has no coreutils. Restore them explicitly,
# plus the bundled jq.exe in ~/.claude/bin.
export PATH="$HOME/.claude/bin:/usr/bin:/bin:$PATH"
input=$(cat)
# Validate JSON
if ! echo "$input" | jq -e . >/dev/null 2>&1; then
printf '\033[90mLoading...\033[0m'
exit 0
fi
# --- Context / project (line 1) ---
model=$(echo "$input" | jq -r '.model.display_name // "?"')
workdir=$(echo "$input" | jq -r '.workspace.current_dir // ""')
project=$(basename "$workdir" 2>/dev/null) || project="?"
ctx_pct=$(echo "$input" | jq -r '(.context_window.used_percentage // 0) | floor')
[[ "$ctx_pct" =~ ^[0-9]+$ ]] || ctx_pct=0
ctx_size=$(echo "$input" | jq -r '.context_window.context_window_size // 0')
ctx_input=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // 0')
ctx_output=$(echo "$input" | jq -r '.context_window.current_usage.output_tokens // 0')
ctx_cache_create=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0')
ctx_cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0')
ctx_used=$(( ctx_input + ctx_output + ctx_cache_create + ctx_cache_read ))
fmt_tokens() {
local n=$1
if [ "$n" -ge 1000000 ]; then printf "%dM" $(( n / 1000000 ))
elif [ "$n" -ge 1000 ]; then printf "%dK" $(( n / 1000 ))
else printf "%d" "$n"; fi
}
ctx_used_fmt=$(fmt_tokens "$ctx_used")
ctx_size_fmt=$(fmt_tokens "$ctx_size")
# Git branch with dirty marker
git_branch=""
if [ -n "$workdir" ] && [ -d "$workdir" ]; then
git_branch=$(cd "$workdir" 2>/dev/null && git -c gc.auto=0 rev-parse --abbrev-ref HEAD 2>/dev/null) || git_branch=""
if [ -n "$git_branch" ]; then
git_dirty=$(cd "$workdir" 2>/dev/null && git -c gc.auto=0 status --porcelain 2>/dev/null | head -1)
[ -n "$git_dirty" ] && git_branch="${git_branch}*"
fi
fi
# --- Usage: all three figures from /api/oauth/usage, cached ---
USAGE_CACHE="$HOME/.claude/.statusline-usage.json"
USAGE_REFRESH=600 # refresh at most every 10 min
USAGE_BACKOFF_429=1200 # after a rate-limit, wait 20 min before retrying
USAGE_BACKOFF_ERR=300 # after any other error, wait 5 min
now=$(date +%s)
c5p=""; c5r=""; c7p=""; c7r=""; csp=""; csr=""; fetched=0; retry=0
read_usage_cache() {
[ -f "$USAGE_CACHE" ] || return
c5p=$(jq -r '.five_hour_pct // ""' "$USAGE_CACHE" 2>/dev/null)
c5r=$(jq -r '.five_hour_reset // ""' "$USAGE_CACHE" 2>/dev/null)
c7p=$(jq -r '.seven_day_pct // ""' "$USAGE_CACHE" 2>/dev/null)
c7r=$(jq -r '.seven_day_reset // ""' "$USAGE_CACHE" 2>/dev/null)
csp=$(jq -r '.sonnet_pct // ""' "$USAGE_CACHE" 2>/dev/null)
csr=$(jq -r '.sonnet_reset // ""' "$USAGE_CACHE" 2>/dev/null)
fetched=$(jq -r '(.fetched_at // 0) | floor' "$USAGE_CACHE" 2>/dev/null || echo 0)
retry=$(jq -r '(.retry_until // 0) | floor' "$USAGE_CACHE" 2>/dev/null || echo 0)
}
read_usage_cache
[[ "$fetched" =~ ^[0-9]+$ ]] || fetched=0
[[ "$retry" =~ ^[0-9]+$ ]] || retry=0
write_usage_cache() { # 5p 5r 7p 7r sp sr fetched_at retry_until
printf '{"five_hour_pct":"%s","five_hour_reset":"%s","seven_day_pct":"%s","seven_day_reset":"%s","sonnet_pct":"%s","sonnet_reset":"%s","fetched_at":%s,"retry_until":%s}\n' \
"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" > "$USAGE_CACHE"
}
refresh_usage() {
local creds="$HOME/.claude/.credentials.json" token tmp http
[ -f "$creds" ] || return
token=$(jq -r '.claudeAiOauth.accessToken // empty' "$creds" 2>/dev/null)
[ -n "$token" ] || return
tmp="$HOME/.claude/.statusline-usage.tmp.$$"
http=$(curl -s -o "$tmp" -w '%{http_code}' --max-time 3 \
-H "Authorization: Bearer $token" \
-H "anthropic-beta: oauth-2025-04-20" \
-H "Content-Type: application/json" \
"https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
if [ "$http" = "200" ]; then
local p5 r5 p7 r7 ps rs
p5=$(jq -r 'if .five_hour.utilization!=null then (.five_hour.utilization|floor) else "" end' "$tmp" 2>/dev/null)
r5=$(jq -r '.five_hour.resets_at // ""' "$tmp" 2>/dev/null)
p7=$(jq -r 'if .seven_day.utilization!=null then (.seven_day.utilization|floor) else "" end' "$tmp" 2>/dev/null)
r7=$(jq -r '.seven_day.resets_at // ""' "$tmp" 2>/dev/null)
ps=$(jq -r 'if .seven_day_sonnet.utilization!=null then (.seven_day_sonnet.utilization|floor) else "" end' "$tmp" 2>/dev/null)
rs=$(jq -r '.seven_day_sonnet.resets_at // ""' "$tmp" 2>/dev/null)
write_usage_cache "$p5" "$r5" "$p7" "$r7" "$ps" "$rs" "$now" 0
elif [ "$http" = "429" ]; then
write_usage_cache "$c5p" "$c5r" "$c7p" "$c7r" "$csp" "$csr" "$fetched" "$(( now + USAGE_BACKOFF_429 ))"
else
write_usage_cache "$c5p" "$c5r" "$c7p" "$c7r" "$csp" "$csr" "$fetched" "$(( now + USAGE_BACKOFF_ERR ))"
fi
rm -f "$tmp"
}
if [ "$(( now - fetched ))" -gt "$USAGE_REFRESH" ] && [ "$now" -gt "$retry" ]; then
refresh_usage
read_usage_cache
fi
# current / weekly: use API cache; fall back to stdin rate_limits if not yet fetched
if [ -n "$c5p" ]; then
five_hr_pct=$c5p; five_hr_reset=$c5r
else
five_hr_pct=$(echo "$input" | jq -r '(.rate_limits.five_hour.used_percentage // 0) | floor')
five_hr_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // ""')
fi
if [ -n "$c7p" ]; then
weekly_pct=$c7p; weekly_reset=$c7r
else
weekly_pct=$(echo "$input" | jq -r '(.rate_limits.seven_day.used_percentage // 0) | floor')
weekly_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // ""')
fi
# sonnet: only available from the API
sonnet_pct=${csp:-0}; sonnet_reset=$csr
[[ "$five_hr_pct" =~ ^[0-9]+$ ]] || five_hr_pct=0
[[ "$weekly_pct" =~ ^[0-9]+$ ]] || weekly_pct=0
[[ "$sonnet_pct" =~ ^[0-9]+$ ]] || sonnet_pct=0
# --- reset-time formatting (accepts epoch seconds or ISO string) ---
to_epoch() {
local v="${1%%.*}"
if [ -z "$v" ] || [ "$v" = "null" ]; then return 1; fi
if [[ "$v" =~ ^[0-9]+$ ]]; then printf '%s' "$v"
else date -d "$1" +%s 2>/dev/null || return 1; fi
}
fmt_reset() {
# No TZ= : Git Bash's date has no zoneinfo DB, but with TZ unset it uses the
# Windows system timezone correctly. Setting TZ=Europe/... falls back to UTC.
local e
e=$(to_epoch "$1") || { printf '%s' "--"; return; }
date -d "@$e" "+%a %-I:%M%P" 2>/dev/null || printf '%s' "--"
}
fmt_remaining() {
local e now_ts rem rh rm rd
e=$(to_epoch "$1") || { printf '%s' "--"; return; }
now_ts=$(date +%s)
if [ "$e" -gt "$now_ts" ]; then
rem=$(( e - now_ts )); rh=$(( rem / 3600 )); rm=$(( (rem % 3600) / 60 ))
if [ "$rh" -gt 24 ]; then
rd=$(( rh / 24 )); rh=$(( rh % 24 )); printf "%dd %dh" "$rd" "$rh"
elif [ "$rh" -gt 0 ]; then printf "%dhr %dmin" "$rh" "$rm"
else printf "%dmin" "$rm"; fi
else printf "resetting"; fi
}
five_hr_remain=$(fmt_remaining "$five_hr_reset")
weekly_reset_str=$(fmt_reset "$weekly_reset")
sonnet_reset_str=$(fmt_reset "$sonnet_reset")
# --- dot bar ---
DOT_TOTAL=10
make_dots() {
local pct=$1 filled i dots=""
filled=$(( pct * DOT_TOTAL / 100 ))
[ "$filled" -gt "$DOT_TOTAL" ] && filled=$DOT_TOTAL
[ "$filled" -lt 0 ] && filled=0
for (( i=0; i<DOT_TOTAL; i++ )); do
if [ "$i" -lt "$filled" ]; then dots="${dots}●"; else dots="${dots}○"; fi
done
printf "%s" "$dots"
}
# --- build & output ---
if [ -n "$git_branch" ]; then
proj_display="${project} (${git_branch})"
else
proj_display="${project}"
fi
line1=$(printf "%s │ ctx %s/%s %d%% │ %s" "$model" "$ctx_used_fmt" "$ctx_size_fmt" "$ctx_pct" "$proj_display")
line2=$(printf "current %s %d%% ↺ %s │ weekly %s %d%% ↺ %s │ sonnet %s %d%% ↺ %s" \
"$(make_dots "$five_hr_pct")" "$five_hr_pct" "$five_hr_remain" \
"$(make_dots "$weekly_pct")" "$weekly_pct" "$weekly_reset_str" \
"$(make_dots "$sonnet_pct")" "$sonnet_pct" "$sonnet_reset_str")
printf "%s\n%s" "$line1" "$line2"
Dupa ce salvezi fisierul si actualizezi settings.json, deschide o sesiune noua Claude
Code (sau /statusline refresh) ca sa vezi statusline-ul aplicat.