Merge branch 'worktree-statusline'
- Зачем:
- statusLine Claude Code ссылался на скрипт, который install.sh не создавал.
- Что:
- новый statusline-command.sh (округление процентов, порог длины пути,
работа в Git Bash без jq) и его установка в ~/.claude через install.sh.
- Проверка:
- printf '%s' "$json" | bash claude/.claude/statusline-command.sh на тестовых JSON.
This commit is contained in:
commit
962012204a
3 files changed
+107
-70
No files matched your search
@@ -75,7 +75,7 @@ Chezmoi использует отдельный source dir `chezmoi/` внутр
|
||||
| Инструмент | Что настраивается |
|
||||
|------------|-------------------|
|
||||
| **Agents** | Каноничное хранилище скиллов: `~/.agents/skills/<name>/SKILL.md` |
|
||||
| **Claude** | `~/.claude/skills` → симлинк на agents; `settings.local.json` → симлинк на репозиторий (базовые permissions + statusLine); `settings.json` — управляется Claude Code |
|
||||
| **Claude** | `~/.claude/skills` → симлинк на agents; `settings.local.json` → симлинк на репозиторий (базовые permissions + statusLine); `statusline-command.sh` → копия из репозитория; `settings.json` — управляется Claude Code |
|
||||
| **[Opencode](https://github.com/anomalyco/opencode)** | MCP-серверы (context7, web-reader, playwright и др.), `~/.config/opencode/skills` → симлинк на agents |
|
||||
| **Codex** | `~/.codex/skills/` → симлинки на agents |
|
||||
| **Gemini** | Политики для CLI: pre-approved readonly команды |
|
||||
|
||||
Regular → Executable
+98
-69
@@ -1,87 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
# Статусная строка Claude Code. JSON приходит на stdin.
|
||||
#
|
||||
# user@host:.../dir (branch) | Model Name (NM context) ctx:N% | 5h:N% 7d:N%
|
||||
#
|
||||
# Работает в Linux и в Git Bash на Windows: без `hostname -s`, jq не обязателен.
|
||||
|
||||
# Читаем и парсим JSON одним вызовом jq
|
||||
IFS=$'\t' read -r cwd display_name ctx_pct rate5h rate7d < <(jq -r '[
|
||||
(.workspace.current_dir // ""),
|
||||
(.model.display_name // ""),
|
||||
(.context_window.used_percentage // ""),
|
||||
(.rate_limits.five_hour.used_percentage // ""),
|
||||
(.rate_limits.seven_day.used_percentage // "")
|
||||
] | @tsv')
|
||||
# Порог, после которого путь сокращается до .../<последний каталог>
|
||||
MAX_PATH_LEN="${STATUSLINE_MAX_PATH_LEN:-28}"
|
||||
|
||||
# Путь: $HOME → ~, длинные пути → .../<last_dir>
|
||||
path="$cwd"
|
||||
home="$HOME"
|
||||
if [[ "$path" == "$home" ]]; then
|
||||
path="~"
|
||||
elif [[ "$path" == "$home"/* ]]; then
|
||||
path="~${path#$home}"
|
||||
input="$(cat)"
|
||||
|
||||
# ── Разбор JSON ───────────────────────────────────────────────────────
|
||||
|
||||
# Числовое поле $2 внутри объекта $1 (резервный разбор, без jq).
|
||||
json_num() {
|
||||
printf '%s' "$input" \
|
||||
| tr -d ' \t\n\r' \
|
||||
| grep -o "\"$1\":{[^}]*}" \
|
||||
| grep -o "\"$2\":[0-9.eE+-]*" \
|
||||
| head -1 \
|
||||
| cut -d: -f2
|
||||
}
|
||||
|
||||
# Строковое поле $2 внутри объекта $1 (резервный разбор, без jq).
|
||||
json_str() {
|
||||
printf '%s' "$input" \
|
||||
| tr -d '\n\r' \
|
||||
| grep -o "\"$1\"[[:space:]]*:[[:space:]]*{[^}]*}" \
|
||||
| grep -o "\"$2\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" \
|
||||
| head -1 \
|
||||
| sed 's/.*"[[:space:]]*:[[:space:]]*"//; s/"$//'
|
||||
}
|
||||
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
IFS=$'\t' read -r cwd display_name ctx_pct rate5h rate7d <<EOF
|
||||
$(printf '%s' "$input" | jq -r '
|
||||
def num: if type == "number" then tostring else "" end;
|
||||
[ (.workspace.current_dir // ""),
|
||||
(.model.display_name // ""),
|
||||
(.context_window.used_percentage | num),
|
||||
(.rate_limits.five_hour.used_percentage | num),
|
||||
(.rate_limits.seven_day.used_percentage | num)
|
||||
] | @tsv' 2>/dev/null)
|
||||
EOF
|
||||
else
|
||||
cwd="$(json_str workspace current_dir)"
|
||||
display_name="$(json_str model display_name)"
|
||||
ctx_pct="$(json_num context_window used_percentage)"
|
||||
rate5h="$(json_num five_hour used_percentage)"
|
||||
rate7d="$(json_num seven_day used_percentage)"
|
||||
fi
|
||||
|
||||
# Считаем сегменты (кроме ведущего ~)
|
||||
IFS='/' read -ra segs <<< "${path#\~}"
|
||||
segs=("${segs[@]/#/}") # убираем пустые
|
||||
real_segs=()
|
||||
for s in "${segs[@]}"; do [[ -n "$s" ]] && real_segs+=("$s"); done
|
||||
# Проценты в JSON дробные — округляем до целых.
|
||||
round_pct() {
|
||||
case "$1" in
|
||||
''|null) return 0 ;;
|
||||
esac
|
||||
awk -v v="$1" 'BEGIN { printf "%d", (v < 0 ? -int(-v + 0.5) : int(v + 0.5)) }' 2>/dev/null
|
||||
}
|
||||
|
||||
if (( ${#real_segs[@]} > 2 )); then
|
||||
last="${real_segs[-1]}"
|
||||
if [[ "$path" == ~* ]]; then
|
||||
path="~/.../$last"
|
||||
else
|
||||
path=".../$last"
|
||||
fi
|
||||
ctx_pct="$(round_pct "$ctx_pct")"
|
||||
rate5h="$(round_pct "$rate5h")"
|
||||
rate7d="$(round_pct "$rate7d")"
|
||||
|
||||
# ── Путь ──────────────────────────────────────────────────────────────
|
||||
|
||||
# В Git Bash current_dir может прийти с обратными слэшами.
|
||||
path="${cwd//\\//}"
|
||||
home="${HOME//\\//}"
|
||||
|
||||
if [ -n "$home" ]; then
|
||||
if [ "$path" = "$home" ]; then
|
||||
path="~"
|
||||
else
|
||||
case "$path" in
|
||||
"$home"/*) path="~${path#"$home"}" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
# Git branch
|
||||
if [ "${#path}" -gt "$MAX_PATH_LEN" ]; then
|
||||
path=".../${path##*/}"
|
||||
fi
|
||||
|
||||
# ── Остальные секции ──────────────────────────────────────────────────
|
||||
|
||||
branch=""
|
||||
if [[ -n "$cwd" ]]; then
|
||||
branch=$(git -C "$cwd" rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
if [ -n "$cwd" ]; then
|
||||
branch="$(git -C "$cwd" rev-parse --abbrev-ref HEAD 2>/dev/null)"
|
||||
fi
|
||||
|
||||
# Модель: убрать префикс "Claude "
|
||||
# Размер контекста уже внутри display_name, убираем только префикс «Claude ».
|
||||
model="${display_name#Claude }"
|
||||
|
||||
# ANSI цвета
|
||||
GREEN='\033[32m'
|
||||
YELLOW='\033[33m'
|
||||
PURPLE='\033[35m'
|
||||
CYAN='\033[36m'
|
||||
RESET='\033[0m'
|
||||
user="${USER:-${USERNAME:-$(id -un 2>/dev/null)}}"
|
||||
host="${HOSTNAME:-$(hostname 2>/dev/null)}"
|
||||
host="${host%%.*}"
|
||||
|
||||
# user@hostname
|
||||
user_host="${GREEN}${USER}@$(hostname -s)${RESET}"
|
||||
GREEN=$'\033[32m'
|
||||
YELLOW=$'\033[33m'
|
||||
PURPLE=$'\033[35m'
|
||||
CYAN=$'\033[36m'
|
||||
RESET=$'\033[0m'
|
||||
|
||||
# путь
|
||||
colored_path="${YELLOW}${path}${RESET}"
|
||||
out="${GREEN}${user}@${host}${RESET}:${YELLOW}${path}${RESET}"
|
||||
[ -n "$branch" ] && out="${out} ${PURPLE}(${branch})${RESET}"
|
||||
out="${out} | ${CYAN}${model}${RESET}"
|
||||
[ -n "$ctx_pct" ] && out="${out} ctx:${ctx_pct}%"
|
||||
|
||||
# ветка
|
||||
colored_branch=""
|
||||
if [[ -n "$branch" ]]; then
|
||||
colored_branch=" ${PURPLE}(${branch})${RESET}"
|
||||
fi
|
||||
|
||||
# модель
|
||||
colored_model="${CYAN}${model}${RESET}"
|
||||
|
||||
# Собираем секции
|
||||
out="${user_host}:${colored_path}${colored_branch} | ${colored_model}"
|
||||
|
||||
# ctx: только если не пустое и не null
|
||||
if [[ -n "$ctx_pct" && "$ctx_pct" != "null" ]]; then
|
||||
out+=" ctx:${ctx_pct}%"
|
||||
fi
|
||||
|
||||
# rate limits: только если не пустые и не null
|
||||
rates=""
|
||||
if [[ -n "$rate5h" && "$rate5h" != "null" ]]; then
|
||||
rates+=" 5h:${rate5h}%"
|
||||
fi
|
||||
if [[ -n "$rate7d" && "$rate7d" != "null" ]]; then
|
||||
rates+=" 7d:${rate7d}%"
|
||||
fi
|
||||
if [[ -n "$rates" ]]; then
|
||||
out+=" |${rates}"
|
||||
fi
|
||||
[ -n "$rate5h" ] && rates="${rates} 5h:${rate5h}%"
|
||||
[ -n "$rate7d" ] && rates="${rates} 7d:${rate7d}%"
|
||||
[ -n "$rates" ] && out="${out} |${rates}"
|
||||
|
||||
printf '%b\n' "$out"
|
||||
printf '%s\n' "$out"
|
||||
@@ -393,6 +393,14 @@ if [ -f "$CLAUDE_LOCAL_SRC" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# statusline-command.sh — копия из репозитория (на Windows симлинки ненадёжны)
|
||||
CLAUDE_STATUSLINE_SRC="$DOTFILES_DIR/claude/.claude/statusline-command.sh"
|
||||
CLAUDE_STATUSLINE_DST="$HOME/.claude/statusline-command.sh"
|
||||
if [ -f "$CLAUDE_STATUSLINE_SRC" ]; then
|
||||
install -m 755 "$CLAUDE_STATUSLINE_SRC" "$CLAUDE_STATUSLINE_DST"
|
||||
info "statusline-command.sh скопирован в ~/.claude/"
|
||||
fi
|
||||
|
||||
# ── Bash: .bashrc ────────────────────────────────────────────────────
|
||||
|
||||
BASHRC="$HOME/.bashrc"
|
||||
|
||||
Reference in new issue
Block a user