[Sync] replace the flat layout with the unified stow tree
Supersedes the old flat .config/ layout (last published 2026-06-28) with the private repo's structure: one shared base plus per-host overlays. - packages: common/ gui/ lw/ fl/ wm/ plus install.sh and bin/ tooling (dotsync, reconcile-hyde.sh) - new README covering the layout, deploy order and the HyDE dependency - current HyDE waybar rig (layouts/, cava), pi agent extensions, claude/ config, tmux, presenterm, aichat roles - fish: kp (keepassxc-cli + fzf picker, db path from $KP_DB) and bind_M_n_history (alt+1..9 recalls the nth history entry) - drops cruft that should never have been tracked: the duplicate top-level .pi/ copy, btop.log, zellij config.kdl.bak, fish_variables - .pi/agent/auth.json is gitignored; auth.json.example ships instead Host-specific work sessions and the personal backlog stay in the private tree. Endpoint locators in the llamacpp/whisper guides are placeholders ($SERVER, <own-domain>) — the guides themselves stay, since they are the useful part.
@@ -1,41 +0,0 @@
|
|||||||
#
|
|
||||||
# ~/.bashrc
|
|
||||||
#
|
|
||||||
|
|
||||||
# If not running interactively, don't do anything
|
|
||||||
[[ $- != *i* ]] && return
|
|
||||||
|
|
||||||
|
|
||||||
alias grep='grep --color=auto'
|
|
||||||
alias fzf="fzf --preview color='always {}'"
|
|
||||||
alias pacs="sudo pacman -Syu"
|
|
||||||
alias nmaps="sudo nmap -sn 192.168.0.0/24"
|
|
||||||
alias mem="df -H --output=source,size,used,avail | grep 480G | sort -u"
|
|
||||||
alias kittyimg="kitten icat"
|
|
||||||
alias vpn="sudo wg-quick up wg0"
|
|
||||||
alias vpnoff="sudo wg-quick down wg0"
|
|
||||||
alias xremaps="sudo xremap ~/.config/xremap/config.yml"
|
|
||||||
alias llama="~/projects/llama.cpp/build/bin/llama-server -m /home/anon/projects/llama.cpp/models/Llama-3.2-3B-Instruct-F16.gguf"
|
|
||||||
alias dots="cd ~/.dotfiles/.config/ && nvim"
|
|
||||||
alias aliases="bat ~/.config/fish/config.fish"
|
|
||||||
|
|
||||||
# List Directory
|
|
||||||
alias ls="lsd"
|
|
||||||
alias l="ls -l"
|
|
||||||
alias la="ls -a"
|
|
||||||
alias lla="ls -la"
|
|
||||||
alias lt="ls --tree"
|
|
||||||
|
|
||||||
# Git
|
|
||||||
alias gs='git status'
|
|
||||||
alias gca='git add -p . && git commit'
|
|
||||||
alias gd="git diff --word-diff"
|
|
||||||
alias gl='git log --graph --show-signature'
|
|
||||||
alias gla="git log --all --decorate --oneline --graph"
|
|
||||||
alias gm='git merge'
|
|
||||||
alias gis='git status'
|
|
||||||
|
|
||||||
PS1='[\u@\h \W]\$'
|
|
||||||
set -o vi
|
|
||||||
|
|
||||||
eval "$(zoxide init --cmd cd bash)"
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
greet.txt
|
|
||||||
fish_variables
|
|
||||||
secrets.fish
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# see https://github.com/sigoden/aichat/blob/main/config.example.yaml
|
|
||||||
keybindings: vi
|
|
||||||
editor: nvim
|
|
||||||
model: duskadiy:Qwen3-Coder-30B-Instruct-IQ4_XS
|
|
||||||
clients:
|
|
||||||
- type: openai-compatible
|
|
||||||
name: local
|
|
||||||
api_base: http://192.168.0.204:11343/v1
|
|
||||||
models:
|
|
||||||
- name: Qwen3.5-27B-UD-Q3_K_XL
|
|
||||||
- name: Qwen3.5-9B-Q8_0
|
|
||||||
- name: Qwen3-Coder-30B-Instruct-IQ4_XS
|
|
||||||
- name: GLM-4.7-Flash-UD-Q3_K_XL
|
|
||||||
- name: DeepSeek-Coder-V2-Lite-Instruct-Q8_0
|
|
||||||
- name: gemma-4-E4B-it-UD-Q8_K_XL
|
|
||||||
- name: gemma-4-26B-A4B-it-UD-IQ4_XS
|
|
||||||
- type: openai-compatible
|
|
||||||
name: duskadiy
|
|
||||||
api_base: https://llm.duskadiy.com/api/v1
|
|
||||||
models:
|
|
||||||
- name: Qwen3.5-27B-UD-Q3_K_XL
|
|
||||||
- name: Qwen3.5-9B-Q8_0
|
|
||||||
- name: Qwen3-Coder-30B-Instruct-IQ4_XS
|
|
||||||
- name: GLM-4.7-Flash-UD-Q3_K_XL
|
|
||||||
- name: DeepSeek-Coder-V2-Lite-Instruct-Q8_0
|
|
||||||
- name: gemma-4-E4B-it-UD-Q8_K_XL
|
|
||||||
- name: gemma-4-26B-A4B-it-UD-IQ4_XS
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
|
|
||||||
2024/11/19 (20:36:51) | ===> btop++ v.1.4.0
|
|
||||||
2024/11/19 (20:36:51) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
2024/11/19 (20:37:28) | INFO: Logger set to INFO
|
|
||||||
|
|
||||||
2024/11/26 (00:47:27) | ===> btop++ v.1.4.0
|
|
||||||
2024/11/26 (00:47:27) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2024/11/26 (00:47:32) | ===> btop++ v.1.4.0
|
|
||||||
2024/11/26 (00:47:32) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2024/12/16 (20:32:28) | ===> btop++ v.1.4.0
|
|
||||||
2024/12/16 (20:32:28) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/01/06 (01:34:00) | ===> btop++ v.1.4.0
|
|
||||||
2025/01/06 (01:34:00) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/02/23 (01:19:32) | ===> btop++ v.1.4.0
|
|
||||||
2025/02/23 (01:19:32) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/03/12 (19:08:38) | ===> btop++ v.1.4.0
|
|
||||||
2025/03/12 (19:08:38) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/03/13 (00:34:24) | ===> btop++ v.1.4.0
|
|
||||||
2025/03/13 (00:34:24) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/03/19 (17:51:06) | ===> btop++ v.1.4.0
|
|
||||||
2025/03/19 (17:51:06) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/03/22 (05:43:25) | ===> btop++ v.1.4.0
|
|
||||||
2025/03/22 (05:43:25) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/03/22 (05:43:39) | ===> btop++ v.1.4.0
|
|
||||||
2025/03/22 (05:43:39) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/03/24 (02:13:29) | ===> btop++ v.1.4.0
|
|
||||||
2025/03/24 (02:13:29) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
|
|
||||||
2025/03/25 (22:21:48) | ===> btop++ v.1.4.0
|
|
||||||
2025/03/25 (22:21:48) | WARNING: Intel GPU: Failed to initialize PMU
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
[color]
|
|
||||||
|
|
||||||
gradient = 1
|
|
||||||
gradient_count = 8
|
|
||||||
gradient_color_1 = '#332952'
|
|
||||||
gradient_color_2 = '#463A6B'
|
|
||||||
gradient_color_3 = '#7D4B5F'
|
|
||||||
gradient_color_4 = '#8F576D'
|
|
||||||
gradient_color_5 = '#A36578'
|
|
||||||
gradient_color_6 = '#C27A90'
|
|
||||||
gradient_color_7 = '#E69A9D'
|
|
||||||
gradient_color_8 = '#F0AAAD'
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[color]
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#81c8be'
|
|
||||||
gradient_color_2 = '#99d1db'
|
|
||||||
gradient_color_3 = '#85c1dc'
|
|
||||||
gradient_color_4 = '#8caaee'
|
|
||||||
gradient_color_5 = '#ca9ee6'
|
|
||||||
gradient_color_6 = '#f4b8e4'
|
|
||||||
gradient_color_7 = '#ea999c'
|
|
||||||
gradient_color_8 = '#e78284'
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[color]
|
|
||||||
background = '#303446'
|
|
||||||
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#81c8be'
|
|
||||||
gradient_color_2 = '#99d1db'
|
|
||||||
gradient_color_3 = '#85c1dc'
|
|
||||||
gradient_color_4 = '#8caaee'
|
|
||||||
gradient_color_5 = '#ca9ee6'
|
|
||||||
gradient_color_6 = '#f4b8e4'
|
|
||||||
gradient_color_7 = '#ea999c'
|
|
||||||
gradient_color_8 = '#e78284'
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[color]
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#179299'
|
|
||||||
gradient_color_2 = '#04a5e5'
|
|
||||||
gradient_color_3 = '#209fb5'
|
|
||||||
gradient_color_4 = '#1e66f5'
|
|
||||||
gradient_color_5 = '#8839ef'
|
|
||||||
gradient_color_6 = '#ea76cb'
|
|
||||||
gradient_color_7 = '#e64553'
|
|
||||||
gradient_color_8 = '#d20f39'
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[color]
|
|
||||||
background = '#eff1f5'
|
|
||||||
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#179299'
|
|
||||||
gradient_color_2 = '#04a5e5'
|
|
||||||
gradient_color_3 = '#209fb5'
|
|
||||||
gradient_color_4 = '#1e66f5'
|
|
||||||
gradient_color_5 = '#8839ef'
|
|
||||||
gradient_color_6 = '#ea76cb'
|
|
||||||
gradient_color_7 = '#e64553'
|
|
||||||
gradient_color_8 = '#d20f39'
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[color]
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#8bd5ca'
|
|
||||||
gradient_color_2 = '#91d7e3'
|
|
||||||
gradient_color_3 = '#7dc4e4'
|
|
||||||
gradient_color_4 = '#8aadf4'
|
|
||||||
gradient_color_5 = '#c6a0f6'
|
|
||||||
gradient_color_6 = '#f5bde6'
|
|
||||||
gradient_color_7 = '#ee99a0'
|
|
||||||
gradient_color_8 = '#ed8796'
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[color]
|
|
||||||
background = '#24273a'
|
|
||||||
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#8bd5ca'
|
|
||||||
gradient_color_2 = '#91d7e3'
|
|
||||||
gradient_color_3 = '#7dc4e4'
|
|
||||||
gradient_color_4 = '#8aadf4'
|
|
||||||
gradient_color_5 = '#c6a0f6'
|
|
||||||
gradient_color_6 = '#f5bde6'
|
|
||||||
gradient_color_7 = '#ee99a0'
|
|
||||||
gradient_color_8 = '#ed8796'
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[color]
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#94e2d5'
|
|
||||||
gradient_color_2 = '#89dceb'
|
|
||||||
gradient_color_3 = '#74c7ec'
|
|
||||||
gradient_color_4 = '#89b4fa'
|
|
||||||
gradient_color_5 = '#cba6f7'
|
|
||||||
gradient_color_6 = '#f5c2e7'
|
|
||||||
gradient_color_7 = '#eba0ac'
|
|
||||||
gradient_color_8 = '#f38ba8'
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[color]
|
|
||||||
background = '#1e1e2e'
|
|
||||||
|
|
||||||
gradient = 1
|
|
||||||
|
|
||||||
gradient_color_1 = '#94e2d5'
|
|
||||||
gradient_color_2 = '#89dceb'
|
|
||||||
gradient_color_3 = '#74c7ec'
|
|
||||||
gradient_color_4 = '#89b4fa'
|
|
||||||
gradient_color_5 = '#cba6f7'
|
|
||||||
gradient_color_6 = '#f5c2e7'
|
|
||||||
gradient_color_7 = '#eba0ac'
|
|
||||||
gradient_color_8 = '#f38ba8'
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
fnm env --use-on-cd --shell fish | source
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
set -gx QT_FONT_DPI 96
|
|
||||||
set -gx EDITOR nvim
|
|
||||||
set -gx PAGER less
|
|
||||||
set -gx PATH "/run/user/1000/fnm_multishells/14287_1763490645306/bin" $PATH;
|
|
||||||
set -gx FNM_MULTISHELL_PATH "/run/user/1000/fnm_multishells/14287_1763490645306";
|
|
||||||
set -gx FNM_VERSION_FILE_STRATEGY "local";
|
|
||||||
set -gx FNM_DIR "/home/anon/.local/share/fnm";
|
|
||||||
set -gx FNM_LOGLEVEL "info";
|
|
||||||
set -gx FNM_NODE_DIST_MIRROR "https://nodejs.org/dist";
|
|
||||||
set -gx FNM_COREPACK_ENABLED "false";
|
|
||||||
set -gx FNM_RESOLVE_ENGINES "true";
|
|
||||||
set -gx FNM_ARCH "x64";
|
|
||||||
set -Ux MANPAGER "nvim +Man!"
|
|
||||||
# set -gx DUSKADIY_API_KEY "*****"
|
|
||||||
set -x NEWT_COLORS 'root=black,black;window=black,black;border=white,black;listbox=white,black;label=blue,black;checkbox=red,black;title=green,black;button=white,red;actsellistbox=white,red;actlistbox=white,gray;compactbutton=white,gray;actcheckbox=white,blue;entry=lightgray,black;textbox=blue,black' nmtui
|
|
||||||
# set -gx BAT_THEME "Catppuccin Mocha"
|
|
||||||
|
|
||||||
alias dmz="cat ~/.config/fish/dmz.txt"
|
|
||||||
alias matrix="~/projects/random-clones/matrix/matrix"
|
|
||||||
alias nmatrix="neo-matrix -DS 3"
|
|
||||||
|
|
||||||
# LLMs
|
|
||||||
alias llamasrv="~/projects/pkgs/llama.cpp/build/bin/llama-server"
|
|
||||||
abbr llamastart "llamasrv --host 0.0.0.0 --port 11343 --models-max 3 --models-preset ~/Documents/models/config.ini"
|
|
||||||
|
|
||||||
# Shorts
|
|
||||||
alias fzf="fzf --multi --preview 'bat --style=numbers --color=always {}' | xargs -n 1 nvim"
|
|
||||||
alias grep="grep --color=auto"
|
|
||||||
|
|
||||||
# Git
|
|
||||||
alias gs="git status --short"
|
|
||||||
alias gca="git add -p . && git commit"
|
|
||||||
alias gd="git diff --word-diff"
|
|
||||||
alias gl="git log --graph --show-signature"
|
|
||||||
alias gla="git log --all --decorate --oneline --graph"
|
|
||||||
alias gls="serie"
|
|
||||||
alias gm="git merge"
|
|
||||||
alias gm="git merge"
|
|
||||||
|
|
||||||
# List Directory
|
|
||||||
alias ls="lsd"
|
|
||||||
alias l="ls -l"
|
|
||||||
alias la="ls -a"
|
|
||||||
alias lla="ls -la"
|
|
||||||
alias lt="ls --tree"
|
|
||||||
|
|
||||||
alias cdots="cd ~/.dotfiles/.config/"
|
|
||||||
alias cpnotes="cd ~/sync/PersonalNotes/"
|
|
||||||
abbr dots "cdots && nvim"
|
|
||||||
abbr pnotes "cpnotes && nvim"
|
|
||||||
abbr todo "cpnotes && nvim ToDoNext.md"
|
|
||||||
|
|
||||||
abbr cat "bat -p"
|
|
||||||
abbr copy "wl-copy"
|
|
||||||
abbr img "kitten icat"
|
|
||||||
abbr fm "yazi" ## file manager
|
|
||||||
abbr lg "lazygit"
|
|
||||||
abbr mkdir "mkdir -p"
|
|
||||||
abbr faillock "sudo faillock --reset"
|
|
||||||
abbr ipadd "sudo ip route add 192.168.0.234 dev wg0"
|
|
||||||
abbr xremaps "sudo xremap --watch ~/.config/xremap/config.yml"
|
|
||||||
abbr pacs "sudo pacman -Syu --noconfirm"
|
|
||||||
abbr yays "yay --noconfirm --sudoloop"
|
|
||||||
abbr nmaps "sudo nmap -sn 192.168.0.0/24"
|
|
||||||
abbr scrcpyc 'scrcpy -wSK -m 1920 --window-borderless --always-on-top --power-off-on-close'
|
|
||||||
abbr scrcpys 'scrcpy -wS --power-off-on-close'
|
|
||||||
abbr aliases "bat ~/.config/fish/config.fish"
|
|
||||||
abbr tts "tt -notheme -bold -showwpm -json"
|
|
||||||
|
|
||||||
# Handy change dir shortcuts
|
|
||||||
abbr .. "cd .."
|
|
||||||
abbr ... "cd ../.."
|
|
||||||
abbr .3 "cd ../../.."
|
|
||||||
abbr .4 "cd ../../../.."
|
|
||||||
abbr .5 "cd ../../../../.."
|
|
||||||
|
|
||||||
|
|
||||||
zoxide init --cmd cd fish | source
|
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
|
||||||
thefuck --alias | source
|
|
||||||
|
|
||||||
# Created by `pipx` on 2025-05-31 20:14:06
|
|
||||||
set PATH $PATH /home/anon/.local/bin
|
|
||||||
|
|
||||||
# pnpm
|
|
||||||
set -gx PNPM_HOME "/home/anon/.local/share/pnpm"
|
|
||||||
if not string match -q -- $PNPM_HOME $PATH
|
|
||||||
set -gx PATH "$PNPM_HOME" $PATH
|
|
||||||
end
|
|
||||||
# pnpm end
|
|
||||||
|
|
||||||
|
|
||||||
fnm env --use-on-cd --shell fish | source
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# This file contains fish universal variable definitions.
|
|
||||||
# VERSION: 3.0
|
|
||||||
SETUVAR --export EDITOR:nvim
|
|
||||||
SETUVAR --export MANPAGER:nvim\x20\x2bMan\x21
|
|
||||||
SETUVAR --export MANROFFOPT:\x2dP\x20\x2dc
|
|
||||||
SETUVAR TMP:/tmp/tmp\x2eYYqSsNsses
|
|
||||||
SETUVAR __fish_initialized:4300
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
function askllama --description 'answer from llama'
|
|
||||||
~/projects/pkgs/llama.cpp/build/bin/llama-simple -m ~/Documents/models/Qwen3-4B-Instruct-2507.Q4_K_M.gguf $(string join '+' $argv[1..])
|
|
||||||
end
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
function clis --description 'fzf select cli'
|
|
||||||
eval (string split "\n" (cat $HOME/.config/misc/clis.txt) | bashs "fzf --multi")
|
|
||||||
end
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
function fish_greeting
|
|
||||||
#curl "wttr.in/Belgrade?format=%l:+%c+%t+|+%h+|+%w+|+(%%M+%m)\n"
|
|
||||||
cat ~/.config/fish/greet.txt ## populated by cronjob
|
|
||||||
date +"📅 %d. %b 🕗 %H:%M - %A"
|
|
||||||
end
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
function sshf --description 'fzf select for ssh hosts'
|
|
||||||
ssh $(grep Host -w ~/.ssh/config | awk '{print $2}' | bashs "fzf --multi")
|
|
||||||
end
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
function tuis --description 'fzf select tui'
|
|
||||||
eval (string split "\n" (cat $HOME/.config/misc/tuis.txt) | bashs "fzf --multi")
|
|
||||||
end
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Get the current battery percentage
|
|
||||||
battery_percentage=$(cat /sys/class/power_supply/BAT0/capacity)
|
|
||||||
|
|
||||||
# Get the battery status (Charging or Discharging)
|
|
||||||
battery_status=$(cat /sys/class/power_supply/BAT0/status)
|
|
||||||
|
|
||||||
# Define the battery icons for each 10% segment
|
|
||||||
battery_icons=("" "" "" "" "" "" "" "" "" "")
|
|
||||||
|
|
||||||
# Define the charging icon
|
|
||||||
charging_icon=""
|
|
||||||
|
|
||||||
# Calculate the index for the icon array
|
|
||||||
icon_index=$((battery_percentage / 10))
|
|
||||||
|
|
||||||
# Get the corresponding icon
|
|
||||||
battery_icon=${battery_icons[icon_index]}
|
|
||||||
|
|
||||||
# Check if the battery is charging
|
|
||||||
if [ "$battery_status" = "Charging" ]; then
|
|
||||||
battery_icon="$charging_icon"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Output the battery percentage and icon
|
|
||||||
echo "$battery_percentage% $battery_icon"
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#! ░▒▒▒░░░▓▓ ___________
|
|
||||||
#! ░░▒▒▒░░░░░▓▓ //___________/
|
|
||||||
#! ░░▒▒▒░░░░░▓▓ _ _ _ _ _____
|
|
||||||
#! ░░▒▒░░░░░▓▓▓▓▓▓ | | | | | | | __/
|
|
||||||
#! ░▒▒░░░░▓▓ ▓▓ | |_| | |_/ /| |___
|
|
||||||
#! ░▒▒░░▓▓ ▓▓ \__ |____/ |____/
|
|
||||||
#! ░▒▓▓ ▓▓ //____/
|
|
||||||
|
|
||||||
# $LOCKSCREEN = hyprlock # preferred LOCKSCREEN e.g swaylock
|
|
||||||
$LOCKSCREEN = lockscreen.sh # Calls $LOCKSCREEN set from hyprland
|
|
||||||
|
|
||||||
general {
|
|
||||||
lock_cmd = pidof hyprlock || hyprlock
|
|
||||||
on_unlock_cmd = bash -c 'notify-send "Welcome back!"'
|
|
||||||
before_sleep_cmd = loginctl lock-session
|
|
||||||
after_sleep_cmd = bash -c 'brightnessctl -r; brightnessctl -d tpacpi::kbd_backlight set 1; hyprctl dispatch dpms on'
|
|
||||||
}
|
|
||||||
|
|
||||||
listener {
|
|
||||||
timeout = 180
|
|
||||||
on-timeout = bash -c 'brightnessctl -s set 50'
|
|
||||||
on-resume = bash -c 'brightnessctl -r'
|
|
||||||
}
|
|
||||||
|
|
||||||
listener {
|
|
||||||
timeout = 250 # 5min
|
|
||||||
on-timeout = loginctl lock-session # lock screen when timeout has passed
|
|
||||||
}
|
|
||||||
|
|
||||||
listener {
|
|
||||||
timeout = 350 # 3.6 minutes
|
|
||||||
on-timeout = bash -c 'brightnessctl -r; brightnessctl -s set 10; brightnessctl -d tpacpi::kbd_backlight set 0; hyprctl dispatch dpms off'
|
|
||||||
on-resume = bash -c 'brightnessctl -r; brightnessctl -d tpacpi::kbd_backlight set 1; hyprctl dispatch dpms on'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
listener {
|
|
||||||
timeout = 550 # 5.5min
|
|
||||||
on-timeout = hyprctl dispatch dpms off # screen off when timeout has passed
|
|
||||||
on-resume = hyprctl dispatch dpms on # screen on when activity is detected after timeout has fired.
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
#! █░█ █▄█ █▀█ █▀█ █░░ █▀█ █▀▀ █▄▀
|
|
||||||
#! █▀█ ░█░ █▀▀ █▀▄ █▄▄ █▄█ █▄▄ █░█
|
|
||||||
|
|
||||||
#* Hyprlock Configuration File
|
|
||||||
|
|
||||||
$fontColor = rgba(255,255,255,0.5)
|
|
||||||
$fontFamily = SourceCodeVF ExtraBold
|
|
||||||
$timeFontFamily = Cantarell ExtraBold
|
|
||||||
|
|
||||||
general {
|
|
||||||
no_fade_in = true
|
|
||||||
grade = 1
|
|
||||||
ignore_empty_input = true
|
|
||||||
text_trim = true
|
|
||||||
fade_in_time = 0.8
|
|
||||||
disable_loading_bar = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
background {
|
|
||||||
monitor =
|
|
||||||
path = ~/sync/Drive/pics/foss-world-crop.png
|
|
||||||
blur_passes = 2
|
|
||||||
blur_size = 4
|
|
||||||
contrast = 0.7
|
|
||||||
brightness = 0.3
|
|
||||||
vibrancy = 0.15
|
|
||||||
vibrancy_darkness = 0.5
|
|
||||||
}
|
|
||||||
|
|
||||||
image {
|
|
||||||
monitor =
|
|
||||||
path = ~/sync/Drive/pics/matrixom-crop.png
|
|
||||||
position = 0, 80
|
|
||||||
reload_time = -1
|
|
||||||
reload_cmd =
|
|
||||||
}
|
|
||||||
|
|
||||||
input-field {
|
|
||||||
monitor =
|
|
||||||
size = 20%, 5%
|
|
||||||
position = 0, -60
|
|
||||||
outline_thickness = 3
|
|
||||||
dots_size = 0.08
|
|
||||||
dots_spacing = 0.2
|
|
||||||
dots_center = true
|
|
||||||
outer_color = rgba(0,0,0,0.1)
|
|
||||||
inner_color = $fontColor
|
|
||||||
fade_on_empty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:5000] echo "<span alpha='40%'>$(uptime -p)</span>"
|
|
||||||
color = $fontColor
|
|
||||||
font_family = $fontFamily
|
|
||||||
font_size = 15
|
|
||||||
position = 0, 350
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:300000] echo "<span alpha='50%'>$(cat ~/.config/fish/greet.txt)</span>"
|
|
||||||
color = $fontColor
|
|
||||||
font_family = $fontFamily
|
|
||||||
font_size = 14
|
|
||||||
position = 0, 310
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:1000] echo "<span alpha='50%'>$(date +"%H:%M")</span>"
|
|
||||||
color = $fontColor
|
|
||||||
font_family = $timeFontFamily
|
|
||||||
font_size = 120
|
|
||||||
position = 0, -180
|
|
||||||
animation = pulse 2s infinite
|
|
||||||
opacity = 0.5
|
|
||||||
shadow_passes = 1
|
|
||||||
shadow_size = 1
|
|
||||||
shadow_color = rgba(0, 0, 0, 0.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:1000] echo "<span alpha='50%'>$(LC_TIME=en_US.UF-8 date +'%A, %B %d')</span>"
|
|
||||||
color = $fontColor
|
|
||||||
font_family = $fontFamily
|
|
||||||
font_size = 25
|
|
||||||
position = 0, -300
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:1000] echo -e "<span alpha='50%'>$(~/.config/hypr/battery.sh)</span>"
|
|
||||||
color = $fontColor
|
|
||||||
font_family = $fontFamily
|
|
||||||
font_size = 14
|
|
||||||
position = -50, 30
|
|
||||||
halign = right
|
|
||||||
valign = bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
color = $fontColor
|
|
||||||
text = cmd[] echo "<span alpha='50%'>⏻ </span>"
|
|
||||||
font-size=24
|
|
||||||
onclick = systemctl poweroff
|
|
||||||
position = 50, 30
|
|
||||||
halign = left
|
|
||||||
valign = bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
# HyDE default layout
|
|
||||||
# Wallbash generated layout
|
|
||||||
|
|
||||||
# Local Variables
|
|
||||||
$fontFamily = JetBrainsMono Nerd Font
|
|
||||||
$fn_greet=echo "Good $(date +%H | awk '{if ($1 < 12) print "Morning"; else if ($1 < 18) print "Afternoon"; else print "Evening"}'), ${USER}"
|
|
||||||
|
|
||||||
# GENERAL
|
|
||||||
general {
|
|
||||||
no_fade_in = false
|
|
||||||
grace = 0
|
|
||||||
disable_loading_bar = true
|
|
||||||
}
|
|
||||||
|
|
||||||
# BACKGROUND
|
|
||||||
background {
|
|
||||||
monitor =
|
|
||||||
path = $BACKGROUND_PATH
|
|
||||||
blur_passes = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
# TIME
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = $TIME
|
|
||||||
color = $wallbash_txt1_rgba
|
|
||||||
font_size = 90
|
|
||||||
font_family = $fontFamily
|
|
||||||
position = -30, 0
|
|
||||||
halign = right
|
|
||||||
valign = top
|
|
||||||
}
|
|
||||||
|
|
||||||
# DATE
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:43200000] date +"%A, %d %B %Y"
|
|
||||||
color = $wallbash_txt2_rgba
|
|
||||||
font_size = 25
|
|
||||||
font_family = $fontFamily
|
|
||||||
position = -30, -150
|
|
||||||
halign = right
|
|
||||||
valign = top
|
|
||||||
}
|
|
||||||
|
|
||||||
# USER AVATAR
|
|
||||||
image {
|
|
||||||
monitor =
|
|
||||||
path = $MPRIS_IMAGE
|
|
||||||
size = 150 # lesser side if not 1:1 ratio
|
|
||||||
reload_time = 0 # seconds between reloading, 0 to reload with SIGUSR2
|
|
||||||
reload_cmd = # command to get new path. if empty, old path will be used. don't run "follow" commands like tail -F
|
|
||||||
position = 0, 0
|
|
||||||
halign = center
|
|
||||||
valign = center
|
|
||||||
}
|
|
||||||
|
|
||||||
# INPUT FIELD
|
|
||||||
input-field {
|
|
||||||
monitor =
|
|
||||||
size = 200, 50 #!
|
|
||||||
outline_thickness = 3
|
|
||||||
dots_size = 0.33 # Scale of input-field height, 0.2 - 0.8
|
|
||||||
dots_spacing = 0.15 # Scale of dots' absolute size, 0.0 - 1.0
|
|
||||||
dots_center = true
|
|
||||||
dots_rounding = -1 # -1 default circle, -2 follow input-field rounding
|
|
||||||
outer_color = $wallbash_pry4_rgba
|
|
||||||
inner_color = $wallbash_pry2_rgba
|
|
||||||
font_color = $wallbash_3xa9_rgba
|
|
||||||
fade_on_empty = true
|
|
||||||
fade_timeout = 1000 # Milliseconds before fade_on_empty is triggered.
|
|
||||||
placeholder_text = <i>Input Password...</i> # Text rendered in the input box when it's empty.
|
|
||||||
hide_input = false
|
|
||||||
rounding = -1 # -1 means complete rounding (circle/oval)
|
|
||||||
check_color = $wallbash_pry4_rgba
|
|
||||||
fail_color = rgba(FF0000FF) # if authentication failed, changes outer_color and fail message color
|
|
||||||
fail_text = <i>$FAIL <b>($ATTEMPTS)</b></i> # can be set to empty
|
|
||||||
fail_transition = 300 # transition time in ms between normal outer_color and fail_color
|
|
||||||
capslock_color = -1
|
|
||||||
numlock_color = -1
|
|
||||||
bothlock_color = -1 # when both locks are active. -1 means don't change outer color (same for above)
|
|
||||||
invert_numlock = false # change color if numlock is off
|
|
||||||
swap_font_color = true # see below
|
|
||||||
position = 0, 80
|
|
||||||
halign = center
|
|
||||||
valign = bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# USER Greeting
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:60000] $fn_greet
|
|
||||||
color = $text
|
|
||||||
font_size = 20
|
|
||||||
font_family = $fontFamily Bold
|
|
||||||
position = 0, -190
|
|
||||||
halign = center
|
|
||||||
valign = center
|
|
||||||
}
|
|
||||||
|
|
||||||
# Mpris and SPLASH
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:1000] $SPLASH_CMD # Outputs the song title when mpris is available, otherwise, it will output the splash command.
|
|
||||||
color = $wallbash_txt2_rgba
|
|
||||||
font_family = $fontFamily
|
|
||||||
font_size = 15
|
|
||||||
position = 0, 0
|
|
||||||
halign = center
|
|
||||||
valign = bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Battery Status if present
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:5000] $BATTERY_ICON
|
|
||||||
color = $wallbash_4xa9_rgba
|
|
||||||
font_size = 20
|
|
||||||
font_family = JetBrainsMono Nerd Font
|
|
||||||
position = -1%, 1%
|
|
||||||
halign = right
|
|
||||||
valign = bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
# Current Keyboard Layout
|
|
||||||
label {
|
|
||||||
monitor =
|
|
||||||
text = cmd[update:1000] $KEYBOARD_LAYOUT
|
|
||||||
color = $wallbash_4xa9_rgba
|
|
||||||
font_size = 20
|
|
||||||
font_family = $fontFamily
|
|
||||||
position = -2%, 1%
|
|
||||||
halign = right
|
|
||||||
valign = bottom
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
# █▀▀ █░█ █▀█ █▀ █▀█ █▀█
|
|
||||||
# █▄▄ █▄█ █▀▄ ▄█ █▄█ █▀▄
|
|
||||||
|
|
||||||
exec = hyprctl setcursor Bibata-Modern-Ice 20
|
|
||||||
exec = gsettings set org.gnome.desktop.interface cursor-theme 'Bibata-Modern-Ice'
|
|
||||||
exec = gsettings set org.gnome.desktop.interface cursor-size 20
|
|
||||||
|
|
||||||
|
|
||||||
# █▀▀ █▀█ █▄░█ ▀█▀
|
|
||||||
# █▀░ █▄█ █░▀█ ░█░
|
|
||||||
|
|
||||||
exec = gsettings set org.gnome.desktop.interface font-name 'Cantarell 10'
|
|
||||||
exec = gsettings set org.gnome.desktop.interface document-font-name 'Cantarell 10'
|
|
||||||
exec = gsettings set org.gnome.desktop.interface monospace-font-name 'CaskaydiaCove Nerd Font Mono 9'
|
|
||||||
exec = gsettings set org.gnome.desktop.interface font-antialiasing 'rgba'
|
|
||||||
exec = gsettings set org.gnome.desktop.interface font-hinting 'full'
|
|
||||||
|
|
||||||
|
|
||||||
# █▀ █▀█ █▀▀ █▀▀ █ ▄▀█ █░░
|
|
||||||
# ▄█ █▀▀ ██▄ █▄▄ █ █▀█ █▄▄
|
|
||||||
|
|
||||||
decoration {
|
|
||||||
dim_special = 0.3
|
|
||||||
blur {
|
|
||||||
special = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
exec = gsettings set org.gnome.desktop.interface icon-theme 'Tela-circle-dracula'
|
|
||||||
exec = gsettings set org.gnome.desktop.interface gtk-theme 'Catppuccin-Mocha'
|
|
||||||
exec = gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
|
|
||||||
|
|
||||||
general {
|
|
||||||
gaps_in = 2 #3
|
|
||||||
gaps_out = 4 #8
|
|
||||||
border_size = 1 #2
|
|
||||||
col.active_border = rgba(ca9ee6ff) rgba(f2d5cfff) 45deg
|
|
||||||
col.inactive_border = rgba(b4befecc) rgba(6c7086cc) 45deg
|
|
||||||
layout = dwindle
|
|
||||||
resize_on_border = true
|
|
||||||
}
|
|
||||||
|
|
||||||
group {
|
|
||||||
col.border_active = rgba(ca9ee6ff) rgba(f2d5cfff) 45deg
|
|
||||||
col.border_inactive = rgba(b4befecc) rgba(6c7086cc) 45deg
|
|
||||||
col.border_locked_active = rgba(ca9ee6ff) rgba(f2d5cfff) 45deg
|
|
||||||
col.border_locked_inactive = rgba(b4befecc) rgba(6c7086cc) 45deg
|
|
||||||
}
|
|
||||||
|
|
||||||
decoration {
|
|
||||||
rounding = 4 #10
|
|
||||||
# drop_shadow = true #false
|
|
||||||
blur {
|
|
||||||
enabled = yes
|
|
||||||
size = 6
|
|
||||||
passes = 3
|
|
||||||
new_optimizations = on
|
|
||||||
ignore_opacity = on
|
|
||||||
xray = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# layerrule = blur,waybar
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# Auto-generated by HyDE // Read-only
|
|
||||||
# // ----------------------------
|
|
||||||
# HyDE Theme: Catppuccin Mocha
|
|
||||||
# Configuration File: "/home/coja/.config/hyde/themes/Catppuccin Mocha/hypr.theme"
|
|
||||||
# Wallbash Mode : theme
|
|
||||||
# // ----------------------------
|
|
||||||
|
|
||||||
$HYDE_THEME=Catppuccin Mocha
|
|
||||||
$GTK_THEME=Catppuccin-Mocha
|
|
||||||
$COLOR-SCHEME=prefer-dark
|
|
||||||
$ICON_THEME=Tela-circle-dracula
|
|
||||||
|
|
||||||
$CURSOR_THEME=Bibata-Modern-Ice
|
|
||||||
$CURSOR_SIZE=24
|
|
||||||
|
|
||||||
$FONT=Cantarell
|
|
||||||
$FONT_SIZE=10
|
|
||||||
$DOCUMENT_FONT=Cantarell
|
|
||||||
$DOCUMENT_FONT_SIZE=10
|
|
||||||
$MONOSPACE_FONT=CaskaydiaCove Nerd Font Mono
|
|
||||||
$MONOSPACE_FONT_SIZE=9
|
|
||||||
|
|
||||||
|
|
||||||
$CODE_THEME=Wallbash
|
|
||||||
$SDDM_THEME=
|
|
||||||
|
|
||||||
# // ----------------------------
|
|
||||||
# README:
|
|
||||||
# Values above are derived and sanitized from the theme.conf file,
|
|
||||||
# This is to ensure themes won't have any 'exec' or 'source'
|
|
||||||
# commands that could potentially harm the system
|
|
||||||
# or undesired behavior.
|
|
||||||
#
|
|
||||||
# Dear Theme Owner:
|
|
||||||
# You can still add your own custom 'exec' or 'source' commands
|
|
||||||
# by adding it as variable, examples (you can name the variable anything):
|
|
||||||
# Note that you should indicate it in your README.md
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# -- ⌨️ theme.conf --
|
|
||||||
# $RUN_CMD="some_command"
|
|
||||||
# $SOURCE_FILE="/some/files"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# -- ⌨️ userprefs.conf --
|
|
||||||
# exec = ${RUN_CMD}"
|
|
||||||
# source = ${SOURCE_FILE}
|
|
||||||
# exec = hyde-shell walbash code $CODE_THEME # Setting the code theme
|
|
||||||
|
|
||||||
# // ----------------------------
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
|
|
||||||
# █░█░█ █ █▄░█ █▀▄ █▀█ █░█░█ █▀█ █░█ █░░ █▀▀ █▀
|
|
||||||
# ▀▄▀▄▀ █ █░▀█ █▄▀ █▄█ ▀▄▀▄▀ █▀▄ █▄█ █▄▄ ██▄ ▄█
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/
|
|
||||||
# hyprctl clients to get names
|
|
||||||
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(code-url-handler)$
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(code-insiders-url-handler)$
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(org.kde.dolphin)$
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(org.kde.ark)$
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(nwg-look)$
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(qt5ct)$
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(qt6ct)$
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(kvantummanager)$
|
|
||||||
windowrule = opacity 0.80 0.70, float on, match:class ^(org.pulseaudio.pavucontrol)$
|
|
||||||
windowrule = opacity 0.80 0.70, match:class ^(lagrange)$
|
|
||||||
windowrule = opacity 0.60 0.60, match:class ^(com.github.wwmm.easyeffects)$
|
|
||||||
windowrule = opacity 0.80 0.70, float on, match:class ^(blueman-manager)$
|
|
||||||
windowrule = opacity 0.80 0.70, float on, match:class ^(nm-applet)$
|
|
||||||
windowrule = opacity 0.80 0.70, float on, match:class ^(nm-connection-editor)$
|
|
||||||
windowrule = opacity 0.80 0.70, float on, match:class ^(org.kde.polkit-kde-authentication-agent-1)$
|
|
||||||
windowrule = opacity 0.80 0.70, match:class ^(polkit-gnome-authentication-agent-1)$
|
|
||||||
windowrule = opacity 0.80 0.70, match:class ^(org.freedesktop.impl.portal.desktop.gtk)$
|
|
||||||
windowrule = opacity 0.80 0.70, match:class ^(org.freedesktop.impl.portal.desktop.hyprland)$
|
|
||||||
windowrule = opacity 0.70 0.70, match:class ^([Ss]team)$
|
|
||||||
|
|
||||||
windowrule = opacity 0.90 0.90, float on, match:class ^(com.github.rafostar.Clapper)$ # Clapper-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(com.github.tchx84.Flatseal)$ # Flatseal-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(hu.kramo.Cartridges)$ # Cartridges-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(com.obsproject.Studio)$ # Obs-Qt
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(gnome-boxes)$ # Boxes-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(discord)$ # Discord-Electron
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(WebCord)$ # WebCord-Electron
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(ArmCord)$ # ArmCord-Electron
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(app.drey.Warp)$ # Warp-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(net.davidotek.pupgui2)$ # ProtonUp-Qt
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(yad)$ # Protontricks-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(Signal)$ # Signal-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(io.github.alainm23.planify)$ # planify-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(io.gitlab.theevilskeleton.Upscaler)$ # Upscaler-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(com.github.unrud.VideoDownloader)$ # VideoDownloader-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(io.gitlab.adhami3310.Impression)$ # Impression-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, float on, match:class ^(io.missioncenter.MissionCenter)$ # MissionCenter-Gtk
|
|
||||||
windowrule = opacity 0.80 0.80, match:class ^(io.github.flattool.Warehouse)$ # Warehouse-Gtk
|
|
||||||
|
|
||||||
windowrule = float on, match:class ^(org.kde.dolphin)$, match:title ^(Progress Dialog — Dolphin)$
|
|
||||||
windowrule = float on, match:class ^(org.kde.dolphin)$, match:title ^(Copying — Dolphin)$
|
|
||||||
windowrule = float on, match:title ^(About Mozilla Firefox)$
|
|
||||||
windowrule = float on, match:class ^(firefox)$, match:title ^(Picture-in-Picture)$
|
|
||||||
windowrule = float on, match:class ^(firefox)$, match:title ^(Library)$
|
|
||||||
windowrule = float on, match:class ^(kitty)$, match:title ^(top)$
|
|
||||||
windowrule = float on, match:class ^(kitty)$, match:title ^(btop)$
|
|
||||||
windowrule = float on, match:class ^(kitty)$, match:title ^(htop)$
|
|
||||||
windowrule = float on, match:class ^(vlc)$
|
|
||||||
|
|
||||||
windowrule = float on, match:class ^(eog)$ # Imageviewer-Gtk
|
|
||||||
windowrule = float on, match:class ^(com.github.unrud.VideoDownloader)$ # VideoDownloader-Gkk
|
|
||||||
|
|
||||||
|
|
||||||
# █░░ ▄▀█ █▄█ █▀▀ █▀█ █▀█ █░█ █░░ █▀▀ █▀
|
|
||||||
# █▄▄ █▀█ ░█░ ██▄ █▀▄ █▀▄ █▄█ █▄▄ ██▄ ▄█
|
|
||||||
|
|
||||||
# layerrule = blur,rofi
|
|
||||||
# layerrule = ignorezero,rofi
|
|
||||||
# layerrule = blur,notifications
|
|
||||||
# layerrule = ignorezero,notifications
|
|
||||||
# layerrule = blur,swaync-notification-window
|
|
||||||
# layerrule = ignorezero,swaync-notification-window
|
|
||||||
# layerrule = blur,swaync-control-center
|
|
||||||
# layerrule = ignorezero,swaync-control-center
|
|
||||||
# layerrule = blur,logout_dialog
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# run with `kitty --session ~/.config/kitty/c2.conf`
|
|
||||||
layout tall
|
|
||||||
|
|
||||||
# create a new tab
|
|
||||||
new_tab c2
|
|
||||||
|
|
||||||
cd ~/projects/wingman/c2/
|
|
||||||
launch --var window=first nvim
|
|
||||||
|
|
||||||
new_tab git
|
|
||||||
|
|
||||||
cd ~/projects/wingman/c2/
|
|
||||||
launch --var window=second lazygit
|
|
||||||
|
|
||||||
# focus neovim
|
|
||||||
# focus first
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# run with `kitty --session ~/.config/kitty/music.conf`
|
|
||||||
layout tall
|
|
||||||
|
|
||||||
# os_window_size 220c 64c
|
|
||||||
# create a new tab
|
|
||||||
new_tab music
|
|
||||||
|
|
||||||
# set the working directory for windows in the current tab
|
|
||||||
cd
|
|
||||||
|
|
||||||
launch --var window=first cava
|
|
||||||
# create additional terminals
|
|
||||||
launch --location=hsplit pyradio
|
|
||||||
resize_window taller 10
|
|
||||||
focus pyradio
|
|
||||||
launch --location=vsplit pipes-rs
|
|
||||||
resize_window wider 20
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# run with `kitty --session ~/.config/kitty/runners.conf`
|
|
||||||
layout stack
|
|
||||||
|
|
||||||
# create a new tab
|
|
||||||
new_tab runners
|
|
||||||
|
|
||||||
cd ~/projects/wingman/c2/
|
|
||||||
|
|
||||||
launch --var window=first pnpm dev
|
|
||||||
|
|
||||||
launch --location=hsplit react-devtools
|
|
||||||
resize_window narrower 20
|
|
||||||
|
|
||||||
launch --location=hsplit lazydocker
|
|
||||||
resize_window wider 120
|
|
||||||
|
|
||||||
# new_tab simulator
|
|
||||||
# cd ~/wmclient
|
|
||||||
# launch --var window=first wmsimulator.sh
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
cal
|
|
||||||
calc
|
|
||||||
speedtest
|
|
||||||
aichat -e
|
|
||||||
askllama
|
|
||||||
ask
|
|
||||||
tldr
|
|
||||||
man
|
|
||||||
info
|
|
||||||
rsync -avkP
|
|
||||||
lsd
|
|
||||||
zioxide
|
|
||||||
httpie
|
|
||||||
bat
|
|
||||||
xxd
|
|
||||||
mpv
|
|
||||||
nix
|
|
||||||
distrobox
|
|
||||||
scrcpy
|
|
||||||
adb
|
|
||||||
watch
|
|
||||||
unzip
|
|
||||||
open
|
|
||||||
nmcli
|
|
||||||
iwctl
|
|
||||||
lsusb
|
|
||||||
thefuck
|
|
||||||
fastfetch
|
|
||||||
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
browsh
|
|
||||||
wiki-tui
|
|
||||||
wikiman
|
|
||||||
yazi
|
|
||||||
tdf
|
|
||||||
dysk
|
|
||||||
dust
|
|
||||||
ncdu
|
|
||||||
systemctl-tui
|
|
||||||
btop
|
|
||||||
bandwhich
|
|
||||||
mtr
|
|
||||||
gping
|
|
||||||
bmon
|
|
||||||
profanity
|
|
||||||
nmtui
|
|
||||||
bluetui
|
|
||||||
drawterm
|
|
||||||
hunk
|
|
||||||
lazygit
|
|
||||||
lazydocker
|
|
||||||
lazyjorunal
|
|
||||||
pastel
|
|
||||||
hexyl
|
|
||||||
pyradio
|
|
||||||
kew
|
|
||||||
tt
|
|
||||||
gittype
|
|
||||||
matrix
|
|
||||||
cava
|
|
||||||
tetrigo
|
|
||||||
tui-mines
|
|
||||||
nyaa
|
|
||||||
stig
|
|
||||||
tmux
|
|
||||||
zellij
|
|
||||||
nvim
|
|
||||||
vim
|
|
||||||
tuios
|
|
||||||
llmfit
|
|
||||||
battop
|
|
||||||
subtui
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Volume
|
|
||||||
9 add volume -5
|
|
||||||
0 add volume 5
|
|
||||||
|
|
||||||
UP add volume 2
|
|
||||||
DOWN add volume -2
|
|
||||||
|
|
||||||
k add volume 2
|
|
||||||
j add volume -2
|
|
||||||
|
|
||||||
# Seek backward / forward
|
|
||||||
LEFT seek -5
|
|
||||||
RIGHT seek 5
|
|
||||||
|
|
||||||
l seek 5
|
|
||||||
h seek -5
|
|
||||||
|
|
||||||
# Bigger jumps
|
|
||||||
Shift+LEFT seek -30
|
|
||||||
Shift+RIGHT seek 30
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"LuaSnip": { "branch": "master", "commit": "a62e1083a3cfe8b6b206e7d3d33a51091df25357" },
|
|
||||||
"NvChad": { "branch": "v2.5", "commit": "d042cc975247c2aa55fcb228e5d146dc1dc6c648" },
|
|
||||||
"base46": { "branch": "v2.5", "commit": "fde7a2cd54599e148d376f82980407c2d24b0fa2" },
|
|
||||||
"cmp-async-path": { "branch": "main", "commit": "f8af3f726e07f2e9d37672eaa9102581aefce149" },
|
|
||||||
"cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" },
|
|
||||||
"cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" },
|
|
||||||
"cmp-nvim-lua": { "branch": "main", "commit": "e3a22cb071eb9d6508a156306b102c45cd2d573d" },
|
|
||||||
"cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" },
|
|
||||||
"codecompanion.nvim": { "branch": "main", "commit": "680c445eb357c72129d175ea5d481aa9e92ae6a5" },
|
|
||||||
"conform.nvim": { "branch": "master", "commit": "086a40dc7ed8242c03be9f47fbcee68699cc2395" },
|
|
||||||
"friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" },
|
|
||||||
"gitsigns.nvim": { "branch": "main", "commit": "6d808f99bd63303646794406e270bd553ad7792e" },
|
|
||||||
"indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" },
|
|
||||||
"lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
|
|
||||||
"mason.nvim": { "branch": "main", "commit": "12ddd182d9efbdc848b540f16484a583d52da0fb" },
|
|
||||||
"menu": { "branch": "main", "commit": "7a0a4a2896b715c066cfbe320bdc048091874cc6" },
|
|
||||||
"minty": { "branch": "main", "commit": "aafc9e8e0afe6bf57580858a2849578d8d8db9e0" },
|
|
||||||
"nvim-autopairs": { "branch": "master", "commit": "59bce2eef357189c3305e25bc6dd2d138c1683f5" },
|
|
||||||
"nvim-cmp": { "branch": "main", "commit": "a1d504892f2bc56c2e79b65c6faded2fd21f3eca" },
|
|
||||||
"nvim-lspconfig": { "branch": "master", "commit": "e146efacbafed3789ac568abcc5a981c5decaa58" },
|
|
||||||
"nvim-tree.lua": { "branch": "master", "commit": "d277467fc0d1d0e2bca88165a1de6b526f9f6fe8" },
|
|
||||||
"nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" },
|
|
||||||
"nvim-web-devicons": { "branch": "master", "commit": "c72328a5494b4502947a022fe69c0c47e53b6aa6" },
|
|
||||||
"plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" },
|
|
||||||
"render-markdown.nvim": { "branch": "main", "commit": "d67113f11384c0dad96fced2f7b91f1fc811e97f" },
|
|
||||||
"snacks.nvim": { "branch": "main", "commit": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e" },
|
|
||||||
"telescope.nvim": { "branch": "master", "commit": "028d9a0695a0cc4cfa893889f8c408ed7ccc8adc" },
|
|
||||||
"ui": { "branch": "v3.0", "commit": "cb75908a86720172594b30de147272c1b3a7f452" },
|
|
||||||
"volt": { "branch": "main", "commit": "620de1321f275ec9d80028c68d1b88b409c0c8b1" },
|
|
||||||
"which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
local model = "Qwen3-Coder-30B-Instruct-IQ4_XS"
|
|
||||||
|
|
||||||
return {
|
|
||||||
adapters = {
|
|
||||||
http = {
|
|
||||||
llama_cpp = function()
|
|
||||||
return require("codecompanion.adapters").extend("openai_compatible", {
|
|
||||||
env = {
|
|
||||||
url = "http://localhost:11343",
|
|
||||||
chat_url = "/v1/chat/completions",
|
|
||||||
models_endpoint = "/v1/models",
|
|
||||||
api_key = "dummy",
|
|
||||||
},
|
|
||||||
schema = {
|
|
||||||
model = {
|
|
||||||
default = model,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
interactions = {
|
|
||||||
chat = {
|
|
||||||
adapter = "llama_cpp",
|
|
||||||
},
|
|
||||||
inline = {
|
|
||||||
adapter = "llama_cpp",
|
|
||||||
},
|
|
||||||
cmd = {
|
|
||||||
adapter = "llama_cpp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
0|28|bottom|( cpu memory custom/cpuinfo custom/gpuinfo ) ( idle_inhibitor clock )|( hyprland/workspaces hyprland/window )|( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|28|top|( cpu memory custom/cpuinfo custom/gpuinfo ) ( idle_inhibitor clock )|( hyprland/workspaces hyprland/window )|( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|28|bottom|( cpu memory custom/cpuinfo custom/gpuinfo ) ( idle_inhibitor clock ) ( hyprland/workspaces )|( hyprland/window )|( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|28|top|( cpu memory custom/cpuinfo ) ( idle_inhibitor clock ) ( hyprland/workspaces )|( hyprland/window )|( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0||bottom|( hyprland/workspaces hyprland/window )|( idle_inhibitor clock )|( cpu memory custom/cpuinfo custom/gpuinfo ) ( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0||top|( hyprland/workspaces hyprland/window )|( idle_inhibitor clock )|( cpu memory custom/cpuinfo custom/gpuinfo ) ( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|31|bottom|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( wlr/taskbar custom/spotify ) |( idle_inhibitor clock )|( tray battery ) ( backlight network pulseaudio pulseaudio#microphone custom/notifications custom/keybindhint )
|
|
||||||
0|31|left|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( wlr/taskbar custom/spotify ) |( idle_inhibitor clock )|( tray battery ) ( backlight network pulseaudio pulseaudio#microphone custom/keybindhint )
|
|
||||||
0|31|top|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( wlr/taskbar custom/spotify ) |( idle_inhibitor clock )|( tray battery ) ( backlight network pulseaudio pulseaudio#microphone custom/keybindhint )
|
|
||||||
0|31|right|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( wlr/taskbar custom/spotify ) |( idle_inhibitor clock )|( tray battery ) ( backlight network pulseaudio pulseaudio#microphone custom/keybindhint )
|
|
||||||
0|32|bottom||( custom/power ) ( tray battery ) ( wlr/taskbar idle_inhibitor clock ) ( custom/cliphist ) ( custom/wbar ) ( custom/wallchange ) ( custom/theme )|
|
|
||||||
0|32|left||( custom/power ) ( tray battery ) ( wlr/taskbar idle_inhibitor clock ) ( custom/cliphist ) ( custom/wbar ) ( custom/wallchange ) ( custom/theme )|
|
|
||||||
1|32|top||( custom/power ) ( tray battery ) ( wlr/taskbar idle_inhibitor clock ) ( custom/cliphist ) ( custom/wbar ) ( custom/wallchange ) ( custom/theme )|
|
|
||||||
0|32|right||( custom/power ) ( tray battery ) ( wlr/taskbar idle_inhibitor clock ) ( custom/cliphist ) ( custom/wbar ) ( custom/wallchange ) ( custom/theme )|
|
|
||||||
0|31|bottom|( cpu memory custom/cpuinfo custom/gpuinfo ) ( idle_inhibitor clock ) ( hyprland/workspaces )|( wlr/taskbar )|( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|31|top|( cpu memory custom/cpuinfo custom/gpuinfo ) ( idle_inhibitor clock ) ( hyprland/workspaces )|( wlr/taskbar )|( backlight network pulseaudio pulseaudio#microphone custom/updates custom/keybindhint ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|29|bottom|( wlr/taskbar mpris )|( idle_inhibitor clock )|( backlight network pulseaudio pulseaudio#microphone custom/updates ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|29|left|( wlr/taskbar mpris )|( idle_inhibitor clock )|( backlight network pulseaudio pulseaudio#microphone custom/updates ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|29|top|( wlr/taskbar mpris )|( idle_inhibitor clock )|( backlight network pulseaudio pulseaudio#microphone custom/updates ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|29|right|( wlr/taskbar mpris )|( idle_inhibitor clock )|( backlight network pulseaudio pulseaudio#microphone custom/updates ) ( tray battery ) ( custom/wallchange custom/theme custom/wbar custom/cliphist custom/power )
|
|
||||||
0|28|bottom|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( idle_inhibitor clock custom/spotify )|( wlr/taskbar )|( tray ) ( backlight network pulseaudio pulseaudio#microphone )
|
|
||||||
0|28|left|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( idle_inhibitor clock custom/spotify )|( wlr/taskbar )|( tray ) ( backlight network pulseaudio pulseaudio#microphone )
|
|
||||||
0|28|top|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( idle_inhibitor clock custom/spotify )|( wlr/taskbar )|( tray ) ( backlight network pulseaudio pulseaudio#microphone )
|
|
||||||
0|28|right|( custom/power custom/cliphist custom/wbar custom/theme custom/wallchange ) ( idle_inhibitor clock custom/spotify )|( wlr/taskbar )|( tray ) ( backlight network pulseaudio pulseaudio#microphone )
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
"hyprland/window": {
|
|
||||||
"format": " {}",
|
|
||||||
"rotate": ${r_deg},
|
|
||||||
"separate-outputs": true,
|
|
||||||
"rewrite": {
|
|
||||||
"${USER}@${set_sysname}:(.*)": "$1 ",
|
|
||||||
"(.*) — Mozilla Firefox": "$1 ",
|
|
||||||
"(.*)Mozilla Firefox": "Firefox ",
|
|
||||||
"(.*) - Visual Studio Code": "$1 ",
|
|
||||||
"(.*)Visual Studio Code": "Code ",
|
|
||||||
"(.*) — Dolphin": "$1 ",
|
|
||||||
"(.*)Spotify": "Spotify ",
|
|
||||||
"(.*)Steam": "Steam "
|
|
||||||
},
|
|
||||||
"max-length": 1000
|
|
||||||
},
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
modmap:
|
|
||||||
- name: CapsLock to LeftCtrl/Esc
|
|
||||||
remap:
|
|
||||||
CapsLock:
|
|
||||||
held: leftctrl
|
|
||||||
alone: esc
|
|
||||||
alone_timeout_millis: 150
|
|
||||||
# keymap:
|
|
||||||
# - name: Alt+hjkl to Arrows
|
|
||||||
# remap:
|
|
||||||
# # Alt-H: Alt+left #back
|
|
||||||
# Alt-h: left
|
|
||||||
# Alt-l: right
|
|
||||||
# Alt-j: down
|
|
||||||
# Alt-k: up
|
|
||||||
# Alt-u: pageup
|
|
||||||
# Alt-d: pagedown
|
|
||||||
# keymap:
|
|
||||||
# - name: Freetube remap
|
|
||||||
# application:
|
|
||||||
# only: FreeTube
|
|
||||||
# remap:
|
|
||||||
# Alt-h: Left
|
|
||||||
# Alt-l: Right
|
|
||||||
# Alt-j: Down
|
|
||||||
# Alt-k: Up
|
|
||||||
@@ -1,452 +0,0 @@
|
|||||||
keybinds clear-defaults=true {
|
|
||||||
locked {
|
|
||||||
bind "Ctrl g" { SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
pane {
|
|
||||||
bind "left" { MoveFocus "left"; }
|
|
||||||
bind "down" { MoveFocus "down"; }
|
|
||||||
bind "up" { MoveFocus "up"; }
|
|
||||||
bind "right" { MoveFocus "right"; }
|
|
||||||
bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; }
|
|
||||||
bind "d" { NewPane "down"; SwitchToMode "normal"; }
|
|
||||||
bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; }
|
|
||||||
bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; }
|
|
||||||
bind "h" { MoveFocus "left"; }
|
|
||||||
bind "i" { TogglePanePinned; SwitchToMode "normal"; }
|
|
||||||
bind "j" { MoveFocus "down"; }
|
|
||||||
bind "k" { MoveFocus "up"; }
|
|
||||||
bind "l" { MoveFocus "right"; }
|
|
||||||
bind "n" { NewPane; SwitchToMode "normal"; }
|
|
||||||
bind "p" { SwitchFocus; }
|
|
||||||
bind "Ctrl p" { SwitchToMode "normal"; }
|
|
||||||
bind "r" { NewPane "right"; SwitchToMode "normal"; }
|
|
||||||
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
|
|
||||||
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
tab {
|
|
||||||
bind "left" { GoToPreviousTab; }
|
|
||||||
bind "down" { GoToNextTab; }
|
|
||||||
bind "up" { GoToPreviousTab; }
|
|
||||||
bind "right" { GoToNextTab; }
|
|
||||||
bind "1" { GoToTab 1; SwitchToMode "normal"; }
|
|
||||||
bind "2" { GoToTab 2; SwitchToMode "normal"; }
|
|
||||||
bind "3" { GoToTab 3; SwitchToMode "normal"; }
|
|
||||||
bind "4" { GoToTab 4; SwitchToMode "normal"; }
|
|
||||||
bind "5" { GoToTab 5; SwitchToMode "normal"; }
|
|
||||||
bind "6" { GoToTab 6; SwitchToMode "normal"; }
|
|
||||||
bind "7" { GoToTab 7; SwitchToMode "normal"; }
|
|
||||||
bind "8" { GoToTab 8; SwitchToMode "normal"; }
|
|
||||||
bind "9" { GoToTab 9; SwitchToMode "normal"; }
|
|
||||||
bind "[" { BreakPaneLeft; SwitchToMode "normal"; }
|
|
||||||
bind "]" { BreakPaneRight; SwitchToMode "normal"; }
|
|
||||||
bind "b" { BreakPane; SwitchToMode "normal"; }
|
|
||||||
bind "h" { GoToPreviousTab; }
|
|
||||||
bind "j" { GoToNextTab; }
|
|
||||||
bind "k" { GoToPreviousTab; }
|
|
||||||
bind "l" { GoToNextTab; }
|
|
||||||
bind "n" { NewTab; SwitchToMode "normal"; }
|
|
||||||
bind "r" { SwitchToMode "renametab"; TabNameInput 0; }
|
|
||||||
bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; }
|
|
||||||
bind "Ctrl t" { SwitchToMode "normal"; }
|
|
||||||
bind "x" { CloseTab; SwitchToMode "normal"; }
|
|
||||||
bind "tab" { ToggleTab; }
|
|
||||||
}
|
|
||||||
resize {
|
|
||||||
bind "left" { Resize "Increase left"; }
|
|
||||||
bind "down" { Resize "Increase down"; }
|
|
||||||
bind "up" { Resize "Increase up"; }
|
|
||||||
bind "right" { Resize "Increase right"; }
|
|
||||||
bind "+" { Resize "Increase"; }
|
|
||||||
bind "-" { Resize "Decrease"; }
|
|
||||||
bind "=" { Resize "Increase"; }
|
|
||||||
bind "H" { Resize "Decrease left"; }
|
|
||||||
bind "J" { Resize "Decrease down"; }
|
|
||||||
bind "K" { Resize "Decrease up"; }
|
|
||||||
bind "L" { Resize "Decrease right"; }
|
|
||||||
bind "h" { Resize "Increase left"; }
|
|
||||||
bind "j" { Resize "Increase down"; }
|
|
||||||
bind "k" { Resize "Increase up"; }
|
|
||||||
bind "l" { Resize "Increase right"; }
|
|
||||||
bind "Ctrl n" { SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
move {
|
|
||||||
bind "left" { MovePane "left"; }
|
|
||||||
bind "down" { MovePane "down"; }
|
|
||||||
bind "up" { MovePane "up"; }
|
|
||||||
bind "right" { MovePane "right"; }
|
|
||||||
bind "h" { MovePane "left"; }
|
|
||||||
bind "Ctrl h" { SwitchToMode "normal"; }
|
|
||||||
bind "j" { MovePane "down"; }
|
|
||||||
bind "k" { MovePane "up"; }
|
|
||||||
bind "l" { MovePane "right"; }
|
|
||||||
bind "n" { MovePane; }
|
|
||||||
bind "p" { MovePaneBackwards; }
|
|
||||||
bind "tab" { MovePane; }
|
|
||||||
}
|
|
||||||
scroll {
|
|
||||||
bind "e" { EditScrollback; SwitchToMode "normal"; }
|
|
||||||
bind "s" { SwitchToMode "entersearch"; SearchInput 0; }
|
|
||||||
}
|
|
||||||
search {
|
|
||||||
bind "c" { SearchToggleOption "CaseSensitivity"; }
|
|
||||||
bind "n" { Search "down"; }
|
|
||||||
bind "o" { SearchToggleOption "WholeWord"; }
|
|
||||||
bind "p" { Search "up"; }
|
|
||||||
bind "w" { SearchToggleOption "Wrap"; }
|
|
||||||
}
|
|
||||||
session {
|
|
||||||
bind "a" {
|
|
||||||
LaunchOrFocusPlugin "zellij:about" {
|
|
||||||
floating true
|
|
||||||
move_to_focused_tab true
|
|
||||||
}
|
|
||||||
SwitchToMode "normal"
|
|
||||||
}
|
|
||||||
bind "c" {
|
|
||||||
LaunchOrFocusPlugin "configuration" {
|
|
||||||
floating true
|
|
||||||
move_to_focused_tab true
|
|
||||||
}
|
|
||||||
SwitchToMode "normal"
|
|
||||||
}
|
|
||||||
bind "Ctrl o" { SwitchToMode "normal"; }
|
|
||||||
bind "p" {
|
|
||||||
LaunchOrFocusPlugin "plugin-manager" {
|
|
||||||
floating true
|
|
||||||
move_to_focused_tab true
|
|
||||||
}
|
|
||||||
SwitchToMode "normal"
|
|
||||||
}
|
|
||||||
bind "w" {
|
|
||||||
LaunchOrFocusPlugin "session-manager" {
|
|
||||||
floating true
|
|
||||||
move_to_focused_tab true
|
|
||||||
}
|
|
||||||
SwitchToMode "normal"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shared_except "locked" {
|
|
||||||
bind "Alt left" { MoveFocusOrTab "left"; }
|
|
||||||
bind "Alt down" { MoveFocus "down"; }
|
|
||||||
bind "Alt up" { MoveFocus "up"; }
|
|
||||||
bind "Alt right" { MoveFocusOrTab "right"; }
|
|
||||||
bind "Alt +" { Resize "Increase"; }
|
|
||||||
bind "Alt -" { Resize "Decrease"; }
|
|
||||||
bind "Alt =" { Resize "Increase"; }
|
|
||||||
bind "Alt [" { PreviousSwapLayout; }
|
|
||||||
bind "Alt ]" { NextSwapLayout; }
|
|
||||||
bind "Alt f" { ToggleFloatingPanes; }
|
|
||||||
bind "Ctrl g" { SwitchToMode "locked"; }
|
|
||||||
bind "Alt h" { MoveFocusOrTab "left"; }
|
|
||||||
bind "Alt i" { MoveTab "left"; }
|
|
||||||
bind "Alt j" { MoveFocus "down"; }
|
|
||||||
bind "Alt k" { MoveFocus "up"; }
|
|
||||||
bind "Alt l" { MoveFocusOrTab "right"; }
|
|
||||||
bind "Alt n" { NewPane; }
|
|
||||||
bind "Alt o" { MoveTab "right"; }
|
|
||||||
bind "Ctrl q" { Quit; }
|
|
||||||
}
|
|
||||||
shared_except "locked" "move" {
|
|
||||||
bind "Ctrl h" { SwitchToMode "move"; }
|
|
||||||
}
|
|
||||||
shared_except "locked" "session" {
|
|
||||||
bind "Ctrl o" { SwitchToMode "session"; }
|
|
||||||
}
|
|
||||||
shared_except "locked" "scroll" "search" "tmux" {
|
|
||||||
bind "Ctrl b" { SwitchToMode "tmux"; }
|
|
||||||
}
|
|
||||||
shared_except "locked" "scroll" "search" {
|
|
||||||
bind "Ctrl s" { SwitchToMode "scroll"; }
|
|
||||||
}
|
|
||||||
shared_except "locked" "tab" {
|
|
||||||
bind "Ctrl t" { SwitchToMode "tab"; }
|
|
||||||
}
|
|
||||||
shared_except "locked" "pane" {
|
|
||||||
bind "Ctrl p" { SwitchToMode "pane"; }
|
|
||||||
}
|
|
||||||
shared_except "locked" "resize" {
|
|
||||||
bind "Ctrl n" { SwitchToMode "resize"; }
|
|
||||||
}
|
|
||||||
shared_except "normal" "locked" "entersearch" {
|
|
||||||
bind "enter" { SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
shared_except "normal" "locked" "entersearch" "renametab" "renamepane" {
|
|
||||||
bind "esc" { SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
shared_among "pane" "tmux" {
|
|
||||||
bind "x" { CloseFocus; SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
shared_among "scroll" "search" {
|
|
||||||
bind "PageDown" { PageScrollDown; }
|
|
||||||
bind "PageUp" { PageScrollUp; }
|
|
||||||
bind "left" { PageScrollUp; }
|
|
||||||
bind "down" { ScrollDown; }
|
|
||||||
bind "up" { ScrollUp; }
|
|
||||||
bind "right" { PageScrollDown; }
|
|
||||||
bind "Ctrl b" { PageScrollUp; }
|
|
||||||
bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; }
|
|
||||||
bind "d" { HalfPageScrollDown; }
|
|
||||||
bind "Ctrl f" { PageScrollDown; }
|
|
||||||
bind "h" { PageScrollUp; }
|
|
||||||
bind "j" { ScrollDown; }
|
|
||||||
bind "k" { ScrollUp; }
|
|
||||||
bind "l" { PageScrollDown; }
|
|
||||||
bind "Ctrl s" { SwitchToMode "normal"; }
|
|
||||||
bind "u" { HalfPageScrollUp; }
|
|
||||||
}
|
|
||||||
entersearch {
|
|
||||||
bind "Ctrl c" { SwitchToMode "scroll"; }
|
|
||||||
bind "esc" { SwitchToMode "scroll"; }
|
|
||||||
bind "enter" { SwitchToMode "search"; }
|
|
||||||
}
|
|
||||||
renametab {
|
|
||||||
bind "esc" { UndoRenameTab; SwitchToMode "tab"; }
|
|
||||||
}
|
|
||||||
shared_among "renametab" "renamepane" {
|
|
||||||
bind "Ctrl c" { SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
renamepane {
|
|
||||||
bind "esc" { UndoRenamePane; SwitchToMode "pane"; }
|
|
||||||
}
|
|
||||||
shared_among "session" "tmux" {
|
|
||||||
bind "d" { Detach; }
|
|
||||||
}
|
|
||||||
tmux {
|
|
||||||
bind "left" { MoveFocus "left"; SwitchToMode "normal"; }
|
|
||||||
bind "down" { MoveFocus "down"; SwitchToMode "normal"; }
|
|
||||||
bind "up" { MoveFocus "up"; SwitchToMode "normal"; }
|
|
||||||
bind "right" { MoveFocus "right"; SwitchToMode "normal"; }
|
|
||||||
bind "space" { NextSwapLayout; }
|
|
||||||
bind "\"" { NewPane "down"; SwitchToMode "normal"; }
|
|
||||||
bind "%" { NewPane "right"; SwitchToMode "normal"; }
|
|
||||||
bind "," { SwitchToMode "renametab"; }
|
|
||||||
bind "[" { SwitchToMode "scroll"; }
|
|
||||||
bind "Ctrl b" { Write 2; SwitchToMode "normal"; }
|
|
||||||
bind "c" { NewTab; SwitchToMode "normal"; }
|
|
||||||
bind "h" { MoveFocus "left"; SwitchToMode "normal"; }
|
|
||||||
bind "j" { MoveFocus "down"; SwitchToMode "normal"; }
|
|
||||||
bind "k" { MoveFocus "up"; SwitchToMode "normal"; }
|
|
||||||
bind "l" { MoveFocus "right"; SwitchToMode "normal"; }
|
|
||||||
bind "n" { GoToNextTab; SwitchToMode "normal"; }
|
|
||||||
bind "o" { FocusNextPane; }
|
|
||||||
bind "p" { GoToPreviousTab; SwitchToMode "normal"; }
|
|
||||||
bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin aliases - can be used to change the implementation of Zellij
|
|
||||||
// changing these requires a restart to take effect
|
|
||||||
plugins {
|
|
||||||
about location="zellij:about"
|
|
||||||
compact-bar location="zellij:compact-bar"
|
|
||||||
configuration location="zellij:configuration"
|
|
||||||
filepicker location="zellij:strider" {
|
|
||||||
cwd "/"
|
|
||||||
}
|
|
||||||
plugin-manager location="zellij:plugin-manager"
|
|
||||||
session-manager location="zellij:session-manager"
|
|
||||||
status-bar location="zellij:status-bar"
|
|
||||||
strider location="zellij:strider"
|
|
||||||
tab-bar location="zellij:tab-bar"
|
|
||||||
welcome-screen location="zellij:session-manager" {
|
|
||||||
welcome_screen true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugins to load in the background when a new session starts
|
|
||||||
// eg. "file:/path/to/my-plugin.wasm"
|
|
||||||
// eg. "https://example.com/my-plugin.wasm"
|
|
||||||
load_plugins {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use a simplified UI without special fonts (arrow glyphs)
|
|
||||||
// Options:
|
|
||||||
// - true
|
|
||||||
// - false (Default)
|
|
||||||
//
|
|
||||||
// simplified_ui true
|
|
||||||
|
|
||||||
// Choose the theme that is specified in the themes section.
|
|
||||||
// Default: default
|
|
||||||
//
|
|
||||||
// theme "dracula"
|
|
||||||
|
|
||||||
// Choose the base input mode of zellij.
|
|
||||||
// Default: normal
|
|
||||||
//
|
|
||||||
// default_mode "locked"
|
|
||||||
|
|
||||||
// Choose the path to the default shell that zellij will use for opening new panes
|
|
||||||
// Default: $SHELL
|
|
||||||
//
|
|
||||||
// default_shell "fish"
|
|
||||||
|
|
||||||
// Choose the path to override cwd that zellij will use for opening new panes
|
|
||||||
//
|
|
||||||
// default_cwd "/tmp"
|
|
||||||
|
|
||||||
// The name of the default layout to load on startup
|
|
||||||
// Default: "default"
|
|
||||||
//
|
|
||||||
// default_layout "compact"
|
|
||||||
|
|
||||||
// The folder in which Zellij will look for layouts
|
|
||||||
// (Requires restart)
|
|
||||||
//
|
|
||||||
// layout_dir "/tmp"
|
|
||||||
|
|
||||||
// The folder in which Zellij will look for themes
|
|
||||||
// (Requires restart)
|
|
||||||
//
|
|
||||||
// theme_dir "/tmp"
|
|
||||||
|
|
||||||
// Toggle enabling the mouse mode.
|
|
||||||
// On certain configurations, or terminals this could
|
|
||||||
// potentially interfere with copying text.
|
|
||||||
// Options:
|
|
||||||
// - true (default)
|
|
||||||
// - false
|
|
||||||
//
|
|
||||||
// mouse_mode false
|
|
||||||
|
|
||||||
// Toggle having pane frames around the panes
|
|
||||||
// Options:
|
|
||||||
// - true (default, enabled)
|
|
||||||
// - false
|
|
||||||
//
|
|
||||||
// pane_frames false
|
|
||||||
|
|
||||||
// When attaching to an existing session with other users,
|
|
||||||
// should the session be mirrored (true)
|
|
||||||
// or should each user have their own cursor (false)
|
|
||||||
// (Requires restart)
|
|
||||||
// Default: false
|
|
||||||
//
|
|
||||||
// mirror_session true
|
|
||||||
|
|
||||||
// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP
|
|
||||||
// eg. when terminal window with an active zellij session is closed
|
|
||||||
// (Requires restart)
|
|
||||||
// Options:
|
|
||||||
// - detach (Default)
|
|
||||||
// - quit
|
|
||||||
//
|
|
||||||
// on_force_close "quit"
|
|
||||||
|
|
||||||
// Configure the scroll back buffer size
|
|
||||||
// This is the number of lines zellij stores for each pane in the scroll back
|
|
||||||
// buffer. Excess number of lines are discarded in a FIFO fashion.
|
|
||||||
// (Requires restart)
|
|
||||||
// Valid values: positive integers
|
|
||||||
// Default value: 10000
|
|
||||||
//
|
|
||||||
// scroll_buffer_size 10000
|
|
||||||
|
|
||||||
// Provide a command to execute when copying text. The text will be piped to
|
|
||||||
// the stdin of the program to perform the copy. This can be used with
|
|
||||||
// terminal emulators which do not support the OSC 52 ANSI control sequence
|
|
||||||
// that will be used by default if this option is not set.
|
|
||||||
// Examples:
|
|
||||||
//
|
|
||||||
// copy_command "xclip -selection clipboard" // x11
|
|
||||||
// copy_command "wl-copy" // wayland
|
|
||||||
// copy_command "pbcopy" // osx
|
|
||||||
//
|
|
||||||
// copy_command "pbcopy"
|
|
||||||
|
|
||||||
// Choose the destination for copied text
|
|
||||||
// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard.
|
|
||||||
// Does not apply when using copy_command.
|
|
||||||
// Options:
|
|
||||||
// - system (default)
|
|
||||||
// - primary
|
|
||||||
//
|
|
||||||
// copy_clipboard "primary"
|
|
||||||
|
|
||||||
// Enable automatic copying (and clearing) of selection when releasing mouse
|
|
||||||
// Default: true
|
|
||||||
//
|
|
||||||
// copy_on_select true
|
|
||||||
|
|
||||||
// Path to the default editor to use to edit pane scrollbuffer
|
|
||||||
// Default: $EDITOR or $VISUAL
|
|
||||||
// scrollback_editor "/usr/bin/vim"
|
|
||||||
|
|
||||||
// A fixed name to always give the Zellij session.
|
|
||||||
// Consider also setting `attach_to_session true,`
|
|
||||||
// otherwise this will error if such a session exists.
|
|
||||||
// Default: <RANDOM>
|
|
||||||
//
|
|
||||||
// session_name "My singleton session"
|
|
||||||
|
|
||||||
// When `session_name` is provided, attaches to that session
|
|
||||||
// if it is already running or creates it otherwise.
|
|
||||||
// Default: false
|
|
||||||
//
|
|
||||||
// attach_to_session true
|
|
||||||
|
|
||||||
// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible
|
|
||||||
// Options:
|
|
||||||
// - true (default)
|
|
||||||
// - false
|
|
||||||
//
|
|
||||||
// auto_layout false
|
|
||||||
|
|
||||||
// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected
|
|
||||||
// Options:
|
|
||||||
// - true (default)
|
|
||||||
// - false
|
|
||||||
//
|
|
||||||
// session_serialization false
|
|
||||||
|
|
||||||
// Whether pane viewports are serialized along with the session, default is false
|
|
||||||
// Options:
|
|
||||||
// - true
|
|
||||||
// - false (default)
|
|
||||||
//
|
|
||||||
// serialize_pane_viewport false
|
|
||||||
|
|
||||||
// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0
|
|
||||||
// defaults to the scrollback size. If this number is higher than the scrollback size, it will
|
|
||||||
// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true.
|
|
||||||
//
|
|
||||||
// scrollback_lines_to_serialize 10000
|
|
||||||
|
|
||||||
// Enable or disable the rendering of styled and colored underlines (undercurl).
|
|
||||||
// May need to be disabled for certain unsupported terminals
|
|
||||||
// (Requires restart)
|
|
||||||
// Default: true
|
|
||||||
//
|
|
||||||
// styled_underlines false
|
|
||||||
|
|
||||||
// How often in seconds sessions are serialized
|
|
||||||
//
|
|
||||||
// serialization_interval 10000
|
|
||||||
|
|
||||||
// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know
|
|
||||||
// metadata info on this session)
|
|
||||||
// (Requires restart)
|
|
||||||
// Default: false
|
|
||||||
//
|
|
||||||
// disable_session_metadata false
|
|
||||||
|
|
||||||
// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it)
|
|
||||||
// (Requires restart)
|
|
||||||
// Default: true (if the host terminal supports it)
|
|
||||||
//
|
|
||||||
// support_kitty_keyboard_protocol false
|
|
||||||
|
|
||||||
// Whether to stack panes when resizing beyond a certain size
|
|
||||||
// Default: true
|
|
||||||
//
|
|
||||||
// stacked_resize false
|
|
||||||
|
|
||||||
// Whether to show tips on startup
|
|
||||||
// Default: true
|
|
||||||
//
|
|
||||||
// show_startup_tips false
|
|
||||||
|
|
||||||
// Whether to show release notes on first version run
|
|
||||||
// Default: true
|
|
||||||
//
|
|
||||||
// show_release_notes false
|
|
||||||
@@ -1,3 +1,34 @@
|
|||||||
!.gitignore
|
# Secrets / local-only (matched at any depth)
|
||||||
.config/hyde/themes/
|
secrets.fish
|
||||||
.config/fish/greet.txt
|
fish_variables
|
||||||
|
greet.txt
|
||||||
|
settings.local.json
|
||||||
|
|
||||||
|
# pi agent runtime + machine-local auth/state
|
||||||
|
**/.pi/agent/auth.json
|
||||||
|
**/.pi/agent/sessions/
|
||||||
|
**/.pi/agent/bin/
|
||||||
|
**/.pi/agent/git/
|
||||||
|
**/.pi/agent/npm/
|
||||||
|
**/.pi/agent/trust.json
|
||||||
|
|
||||||
|
# tmux plugins (tpm-managed, not vendored)
|
||||||
|
**/tmux/plugins/
|
||||||
|
|
||||||
|
# HyDE generated theme + wallpaper assets (per-machine, huge — bloated the old repo to 255MB)
|
||||||
|
**/hyde/themes/
|
||||||
|
**/wallpapers/
|
||||||
|
|
||||||
|
# Claude Code project dir (worktrees, local settings, history) — never part of the dotfiles
|
||||||
|
.claude/
|
||||||
|
|
||||||
|
# backups / logs / package noise / os
|
||||||
|
*.bak
|
||||||
|
*.bak.*
|
||||||
|
*.log
|
||||||
|
package-lock.json
|
||||||
|
__pycache__/
|
||||||
|
**/hypr/themes/
|
||||||
|
# HyDE writes these at theme-apply time (sourced by animations/theme.conf & hyprlock/theme.conf)
|
||||||
|
**/hypr/animations/HyDE.conf
|
||||||
|
**/hypr/hyprlock/HyDE.conf
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Search config for THIS repo only (ripgrep / fd / telescope read .ignore).
|
||||||
|
#
|
||||||
|
# Everything this repo holds lives in dotfiles and dotdirs — common/.config, gui/.config,
|
||||||
|
# common/.pi, common/.bashrc — which rg and fd skip by default, so an unqualified search
|
||||||
|
# here returned nothing at all. Un-hide them, then put back the two dirs that would swamp
|
||||||
|
# every result: negating .* alone drags in the whole of .git, and .claude/worktrees holds
|
||||||
|
# entire checkouts of this same repo (background sessions create them), so every hit would
|
||||||
|
# appear several times over. Scoped to this directory tree; searches elsewhere on the
|
||||||
|
# machine are unaffected.
|
||||||
|
!.*
|
||||||
|
.git/
|
||||||
|
.claude/
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Vi mode
|
|
||||||
set editing-mode vi
|
|
||||||
set keymap vi
|
|
||||||
set show-mode-in-prompt on
|
|
||||||
set vi-ins-mode-string "\1\e[32m\2[I] \1\e[0m\2"
|
|
||||||
set vi-cmd-mode-string "\1\e[31m\2[N] \1\e[0m\2"
|
|
||||||
|
|
||||||
# exclude .dotfles
|
|
||||||
set match-hidden-files off
|
|
||||||
|
|
||||||
set show-all-if-ambiguous on
|
|
||||||
set show-all-if-unmodified on
|
|
||||||
set colored-stats on
|
|
||||||
set colored-completion-prefix on
|
|
||||||
set mark-symlinked-directories on
|
|
||||||
set completion-ignore-case on
|
|
||||||
|
|
||||||
# Ignore duplicates in history where supported
|
|
||||||
set skip-completed-text on
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
{
|
|
||||||
"providers": {
|
|
||||||
"duskadiy": {
|
|
||||||
"baseUrl": "https://llm.duskadiy.com/api/v1",
|
|
||||||
"api": "openai-completions",
|
|
||||||
"apiKey": "no-key-required",
|
|
||||||
"compat": {
|
|
||||||
"supportsDeveloperRole": false,
|
|
||||||
"supportsReasoningEffort": false,
|
|
||||||
"maxTokensField": "max_tokens"
|
|
||||||
},
|
|
||||||
"models": [
|
|
||||||
{
|
|
||||||
"id": "DeepSeek-Coder-V2-Lite-Instruct-Q8_0",
|
|
||||||
"name": "DeepSeek Coder V2",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-E4B-it-UD-Q8_K_XL",
|
|
||||||
"name": "Gemma 4 E4B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-26B-A4B-it-UD-IQ4_XS",
|
|
||||||
"name": "Gemma 4 26B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3-Coder-30B-Instruct-IQ4_XS",
|
|
||||||
"name": "Qwen3 Coder A3B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 8192,
|
|
||||||
"maxTokens": 4096,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-UD-IQ3_XXS",
|
|
||||||
"name": "Qwen3.6 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-27B-UD-Q3_K_XL",
|
|
||||||
"name": "Qwen3.5 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-9B-Q8_0",
|
|
||||||
"name": "Qwen3.5 9B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ3_M",
|
|
||||||
"name": "Qwen3.6 27B Uncensored",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "GLM-4.7-Flash-UD-Q3_K_XL",
|
|
||||||
"name": "GLM-4.7 Flash",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"localcpp": {
|
|
||||||
"baseUrl": "http://192.168.0.204:11343/v1",
|
|
||||||
"api": "openai-completions",
|
|
||||||
"apiKey": "no-key-required",
|
|
||||||
"compat": {
|
|
||||||
"supportsDeveloperRole": false,
|
|
||||||
"supportsReasoningEffort": false,
|
|
||||||
"maxTokensField": "max_tokens"
|
|
||||||
},
|
|
||||||
"models": [
|
|
||||||
{
|
|
||||||
"id": "DeepSeek-Coder-V2-Lite-Instruct-Q8_0",
|
|
||||||
"name": "DeepSeek Coder V2",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-E4B-it-UD-Q8_K_XL",
|
|
||||||
"name": "Gemma 4 E4B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-26B-A4B-it-UD-IQ4_XS",
|
|
||||||
"name": "Gemma 4 26B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3-Coder-30B-Instruct-IQ4_XS",
|
|
||||||
"name": "Qwen3 Coder A3B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 8192,
|
|
||||||
"maxTokens": 4096,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-UD-IQ3_XXS",
|
|
||||||
"name": "Qwen3.6 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-27B-UD-Q3_K_XL",
|
|
||||||
"name": "Qwen3.5 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-9B-Q8_0",
|
|
||||||
"name": "Qwen3.5 9B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ3_M",
|
|
||||||
"name": "Qwen3.6 27B Uncensored",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "GLM-4.7-Flash-UD-Q3_K_XL",
|
|
||||||
"name": "GLM-4.7 Flash",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
{
|
|
||||||
"providers": {
|
|
||||||
"duskadiy": {
|
|
||||||
"baseUrl": "https://llm.duskadiy.com/api/v1",
|
|
||||||
"api": "openai-completions",
|
|
||||||
"apiKey": "$DUSKADIY_API_KEY",
|
|
||||||
"compat": {
|
|
||||||
"supportsDeveloperRole": false,
|
|
||||||
"supportsReasoningEffort": false,
|
|
||||||
"maxTokensField": "max_tokens"
|
|
||||||
},
|
|
||||||
"models": [
|
|
||||||
{
|
|
||||||
"id": "DeepSeek-Coder-V2-Lite-Instruct-Q8_0",
|
|
||||||
"name": "DeepSeek Coder V2",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-E4B-it-UD-Q8_K_XL",
|
|
||||||
"name": "Gemma 4 E4B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-26B-A4B-it-UD-IQ4_XS",
|
|
||||||
"name": "Gemma 4 26B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3-Coder-30B-Instruct-IQ4_XS",
|
|
||||||
"name": "Qwen3 Coder A3B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 8192,
|
|
||||||
"maxTokens": 4096,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-UD-IQ3_XXS",
|
|
||||||
"name": "Qwen3.6 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-27B-UD-Q3_K_XL",
|
|
||||||
"name": "Qwen3.5 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-9B-Q8_0",
|
|
||||||
"name": "Qwen3.5 9B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ3_M",
|
|
||||||
"name": "Qwen3.6 27B Uncensored",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "GLM-4.7-Flash-UD-Q3_K_XL",
|
|
||||||
"name": "GLM-4.7 Flash",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"localcpp": {
|
|
||||||
"baseUrl": "http://192.168.0.204:11343/v1",
|
|
||||||
"api": "openai-completions",
|
|
||||||
"apiKey": "no-key-required",
|
|
||||||
"compat": {
|
|
||||||
"supportsDeveloperRole": false,
|
|
||||||
"supportsReasoningEffort": false,
|
|
||||||
"maxTokensField": "max_tokens"
|
|
||||||
},
|
|
||||||
"models": [
|
|
||||||
{
|
|
||||||
"id": "DeepSeek-Coder-V2-Lite-Instruct-Q8_0",
|
|
||||||
"name": "DeepSeek Coder V2",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-E4B-it-UD-Q8_K_XL",
|
|
||||||
"name": "Gemma 4 E4B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gemma-4-26B-A4B-it-UD-IQ4_XS",
|
|
||||||
"name": "Gemma 4 26B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3-Coder-30B-Instruct-IQ4_XS",
|
|
||||||
"name": "Qwen3 Coder A3B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 8192,
|
|
||||||
"maxTokens": 4096,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-UD-IQ3_XXS",
|
|
||||||
"name": "Qwen3.6 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-27B-UD-Q3_K_XL",
|
|
||||||
"name": "Qwen3.5 27B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.5-9B-Q8_0",
|
|
||||||
"name": "Qwen3.5 9B",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ3_M",
|
|
||||||
"name": "Qwen3.6 27B Uncensored",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "GLM-4.7-Flash-UD-Q3_K_XL",
|
|
||||||
"name": "GLM-4.7 Flash",
|
|
||||||
"reasoning": false,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 81920,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
---
|
|
||||||
description: Write a Conventional Commits message for the staged changes
|
|
||||||
argument-hint: "[extra context]"
|
|
||||||
---
|
|
||||||
Inspect the staged changes with `git diff --cached` (and `git status` for context). Then write a single Conventional Commits message:
|
|
||||||
|
|
||||||
- A `<type>(<scope>): <subject>` summary line, imperative mood, ≤72 chars (types: feat, fix, refactor, docs, chore, test, perf, build).
|
|
||||||
- An optional short body explaining the *why* only when it isn't obvious from the diff.
|
|
||||||
- Do NOT run `git commit`. Output only the message inside a code block so I can review it.
|
|
||||||
|
|
||||||
Extra context to incorporate: ${1:-none}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
description: Review the current diff for bugs and issues
|
|
||||||
argument-hint: "[focus area]"
|
|
||||||
---
|
|
||||||
Review the current changes. Check both `git diff` (unstaged) and `git diff --cached` (staged). Focus on:
|
|
||||||
|
|
||||||
- Correctness and logic bugs
|
|
||||||
- Error handling and missing edge cases
|
|
||||||
- Security issues (injection, secrets, unsafe input)
|
|
||||||
- Anything that doesn't match the surrounding code's conventions
|
|
||||||
|
|
||||||
List concrete findings as `file:line — issue — suggested fix`, ordered by severity. Be concise; skip praise. If nothing is wrong, say so.
|
|
||||||
|
|
||||||
Extra focus this round: ${1:-general correctness}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"defaultProvider": "duskadiy",
|
|
||||||
"defaultModel": "gemma-4-26B-A4B-it-UD-IQ4_XS",
|
|
||||||
"defaultThinkingLevel": "on",
|
|
||||||
"theme": "catppuccin-mocha",
|
|
||||||
"quietStartup": false,
|
|
||||||
"defaultProjectTrust": "ask",
|
|
||||||
"enableInstallTelemetry": false,
|
|
||||||
"enabledModels": [
|
|
||||||
"localcpp/*",
|
|
||||||
"duskadiy/*"
|
|
||||||
],
|
|
||||||
"compaction": {
|
|
||||||
"enabled": true,
|
|
||||||
"reserveTokens": 16384,
|
|
||||||
"keepRecentTokens": 20000
|
|
||||||
},
|
|
||||||
"retry": {
|
|
||||||
"enabled": true,
|
|
||||||
"maxRetries": 3,
|
|
||||||
"baseDelayMs": 2000,
|
|
||||||
"provider": {
|
|
||||||
"timeoutMs": 3600000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"httpIdleTimeoutMs": 600000,
|
|
||||||
"npmCommand": ["fnm", "exec", "--using=22", "--", "npm"],
|
|
||||||
"showHardwareCursor": true,
|
|
||||||
"lastChangelogVersion": "0.80.1"
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
||||||
"name": "catppuccin-mocha",
|
|
||||||
"vars": {
|
|
||||||
"rosewater": "#f5e0dc",
|
|
||||||
"flamingo": "#f2cdcd",
|
|
||||||
"pink": "#f5c2e7",
|
|
||||||
"mauve": "#cba6f7",
|
|
||||||
"red": "#f38ba8",
|
|
||||||
"maroon": "#eba0ac",
|
|
||||||
"peach": "#fab387",
|
|
||||||
"yellow": "#f9e2af",
|
|
||||||
"green": "#a6e3a1",
|
|
||||||
"teal": "#94e2d5",
|
|
||||||
"sky": "#89dceb",
|
|
||||||
"sapphire": "#74c7ec",
|
|
||||||
"blue": "#89b4fa",
|
|
||||||
"lavender": "#b4befe",
|
|
||||||
"fg": "#cdd6f4",
|
|
||||||
"subtext1": "#bac2de",
|
|
||||||
"subtext0": "#a6adc8",
|
|
||||||
"overlay2": "#9399b2",
|
|
||||||
"overlay1": "#7f849c",
|
|
||||||
"overlay0": "#6c7086",
|
|
||||||
"surface2": "#585b70",
|
|
||||||
"surface1": "#45475a",
|
|
||||||
"surface0": "#313244",
|
|
||||||
"base": "#1e1e2e",
|
|
||||||
"mantle": "#181825",
|
|
||||||
"crust": "#11111b"
|
|
||||||
},
|
|
||||||
"colors": {
|
|
||||||
"accent": "mauve",
|
|
||||||
"border": "surface1",
|
|
||||||
"borderAccent": "mauve",
|
|
||||||
"borderMuted": "surface0",
|
|
||||||
"success": "green",
|
|
||||||
"error": "red",
|
|
||||||
"warning": "yellow",
|
|
||||||
"muted": "subtext0",
|
|
||||||
"dim": "overlay0",
|
|
||||||
"text": "fg",
|
|
||||||
"thinkingText": "overlay1",
|
|
||||||
"selectedBg": "surface0",
|
|
||||||
"userMessageBg": "surface0",
|
|
||||||
"userMessageText": "fg",
|
|
||||||
"customMessageBg": "surface0",
|
|
||||||
"customMessageText": "fg",
|
|
||||||
"customMessageLabel": "mauve",
|
|
||||||
"toolPendingBg": "mantle",
|
|
||||||
"toolSuccessBg": "#1e2b22",
|
|
||||||
"toolErrorBg": "#2b1e22",
|
|
||||||
"toolTitle": "mauve",
|
|
||||||
"toolOutput": "fg",
|
|
||||||
"mdHeading": "mauve",
|
|
||||||
"mdLink": "blue",
|
|
||||||
"mdLinkUrl": "sapphire",
|
|
||||||
"mdCode": "green",
|
|
||||||
"mdCodeBlock": "fg",
|
|
||||||
"mdCodeBlockBorder": "surface1",
|
|
||||||
"mdQuote": "subtext0",
|
|
||||||
"mdQuoteBorder": "surface2",
|
|
||||||
"mdHr": "surface1",
|
|
||||||
"mdListBullet": "mauve",
|
|
||||||
"toolDiffAdded": "green",
|
|
||||||
"toolDiffRemoved": "red",
|
|
||||||
"toolDiffContext": "overlay0",
|
|
||||||
"syntaxComment": "overlay0",
|
|
||||||
"syntaxKeyword": "mauve",
|
|
||||||
"syntaxFunction": "blue",
|
|
||||||
"syntaxVariable": "fg",
|
|
||||||
"syntaxString": "green",
|
|
||||||
"syntaxNumber": "peach",
|
|
||||||
"syntaxType": "yellow",
|
|
||||||
"syntaxOperator": "sky",
|
|
||||||
"syntaxPunctuation": "overlay2",
|
|
||||||
"thinkingOff": "surface1",
|
|
||||||
"thinkingMinimal": "overlay0",
|
|
||||||
"thinkingLow": "blue",
|
|
||||||
"thinkingMedium": "teal",
|
|
||||||
"thinkingHigh": "peach",
|
|
||||||
"thinkingXhigh": "red",
|
|
||||||
"bashMode": "peach"
|
|
||||||
},
|
|
||||||
"export": {
|
|
||||||
"pageBg": "#11111b",
|
|
||||||
"cardBg": "#1e1e2e",
|
|
||||||
"infoBg": "#313244"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -209,7 +209,7 @@ If you develop a new program, and you want it to be of the greatest possible use
|
|||||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
|
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
dots
|
dots
|
||||||
Copyright (C) 2025 coja
|
Copyright (C) 2026 coja
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ Also add information on how to contact you by electronic and paper mail.
|
|||||||
|
|
||||||
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
|
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
dots Copyright (C) 2025 coja
|
dots Copyright (C) 2026 coja
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
|
This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,196 @@
|
|||||||
|
# dots
|
||||||
|
|
||||||
using `gnu stow`
|
Unified dotfiles for all machines: one shared base + per-host overlays, deployed with
|
||||||
|
[GNU Stow](https://www.gnu.org/software/stow/).
|
||||||
|
|
||||||
Customized [Hyde](https://github.com/HyDE-Project/HyDE)
|
## Layout
|
||||||
|
|
||||||
`hyde`, `waybar` and `fish` are from hyprdots with customizations
|
Every top-level directory is a Stow *package* (they all share one stow dir, which `--override`
|
||||||
|
requires). `bin/` holds repo tooling and is **not** a package (never stowed):
|
||||||
|
|
||||||
`nvim` is [nvchad](https://nvchad.com/) custom conf
|
```
|
||||||
|
common/ # shared everywhere (mirrors $HOME): fish, nvim, bat, btop, tmux, pi, claude, presenterm, ...
|
||||||
|
gui/ # GUI configs shared by graphical hosts: hypr, waybar, kitty, alacritty, mpv, zellij
|
||||||
|
wm/ # desktop: 4K monitors, NVIDIA, cloud LLM (duskadiy), work aliases
|
||||||
|
lw/ # laptop: no NVIDIA, roaming VPNs, network/LLM tools
|
||||||
|
fl/ # KDE Plasma box: a few Hyprland overrides + llamacpp, evremap
|
||||||
|
bin/ # tooling (not a stow package): install.sh companions
|
||||||
|
install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
A **headless** (terminal-only) machine has no overlay package — it runs `common` only. Mark any box
|
||||||
|
headless with `touch ~/.config/dots-headless` (a machine-local, hostname-independent marker); it then
|
||||||
|
skips `gui` too, so the same terminal-only setup replicates across any number of machines. In other
|
||||||
|
words `common` *is* the headless baseline; `gui` and the host packages layer graphical machines on top.
|
||||||
|
|
||||||
|
### How it deploys
|
||||||
|
|
||||||
|
Deploy order is `common → gui → <host>`; later layers win (the host package is stowed last with
|
||||||
|
`--override`, so a host file replaces the common/gui file at the same path). Stow runs with
|
||||||
|
`--no-folding`, so each *file* is symlinked individually (directories stay real) — this is what lets
|
||||||
|
a host override a single file in a shared dir without shadowing the rest.
|
||||||
|
|
||||||
|
**Editing a config edits the repo copy directly** (it's a symlink) — no deploy step. You only re-run
|
||||||
|
`install.sh` when files are **added or removed** (to create/prune symlinks). See **Syncing** below.
|
||||||
|
|
||||||
|
The repo must be cloned to **`~/.dots`** (the relative `../.dots` symlink convention). A host's
|
||||||
|
package name must match `hostname -s` (or pass the host explicitly, e.g. `./install.sh lw`).
|
||||||
|
|
||||||
|
## Install (new machine)
|
||||||
|
|
||||||
|
```fish
|
||||||
|
sudo pacman -S stow
|
||||||
|
git clone <remote> ~/.dots
|
||||||
|
cd ~/.dots
|
||||||
|
./install.sh # auto-detects host via `hostname -s`
|
||||||
|
```
|
||||||
|
|
||||||
|
`./install.sh -h` lists all options: `-n` dry-run, `-a` adopt (first run), `-D` unstow (revert),
|
||||||
|
`-h` help. GUI hosts also need **HyDE installed** first — see *HyDE dependency* below.
|
||||||
|
|
||||||
|
Once per machine afterwards: `bat cache --build` (registers the repo's custom bat themes —
|
||||||
|
without it every `bat` run warns `Unknown theme 'onedark'`), and `:Lazy restore` inside nvim
|
||||||
|
(`restore` obeys the shared `lazy-lock.json` pins; `sync`/`update` would rewrite them).
|
||||||
|
nvim's treesitter (`main` branch) builds parsers via the `tree-sitter` CLI — `pacman -S
|
||||||
|
tree-sitter-cli` first, or `:TSInstallAll` fails with `ENOENT ... 'tree-sitter'`.
|
||||||
|
|
||||||
|
### First run on a machine that still has real config files
|
||||||
|
|
||||||
|
Stow **aborts the whole package on the first conflict** (one real file blocks *everything* in
|
||||||
|
`common`), and refuses to clobber real files without `--adopt` — you'll see
|
||||||
|
`cannot stow … since neither a link nor a directory`. Adopt them, review, then keep the repo's
|
||||||
|
versions:
|
||||||
|
|
||||||
|
```fish
|
||||||
|
cd ~/.dots
|
||||||
|
git status # make sure the repo is clean first (see the restore caveat)
|
||||||
|
./install.sh -a <host> # --adopt: pull existing files into the repo, symlink them back
|
||||||
|
git diff --stat # what this machine had vs the repo (review the drift!)
|
||||||
|
git restore . # discard adopted content, keep the repo versions
|
||||||
|
```
|
||||||
|
|
||||||
|
`--adopt` overwrites the repo copies with the machine's files, so `git restore .` is what keeps the
|
||||||
|
repo versions. Cautions: adopted changes can land under `common/`/`gui/` even when host-specific, and
|
||||||
|
`git restore .` drops **all** uncommitted edits — so commit/stash anything you want first. To keep a
|
||||||
|
genuine machine change (e.g. custom pyradio `stations.csv`), hand-copy it into the right package
|
||||||
|
instead of restoring that path.
|
||||||
|
|
||||||
|
## Syncing (day-to-day)
|
||||||
|
|
||||||
|
Because configs are symlinks into the repo, **you almost never run `install.sh` to sync**:
|
||||||
|
|
||||||
|
- **Pull/propagate edits:** `cd ~/.dots && git pull` — changes are live in place instantly. No
|
||||||
|
re-stow, so **no symlink churn and no app reloads** (kitty etc. keep runtime state).
|
||||||
|
- **`bin/dotsync`** does this safely: `git pull`, then re-link via `install.sh` **only if** the pull
|
||||||
|
added/removed/renamed files (pure edits skip the re-stow). `dotsync -n` previews incoming changes.
|
||||||
|
- **`install.sh` is a (re)deploy tool, not a sync tool** — its `stow -R` deletes+recreates every
|
||||||
|
symlink, which is what makes apps reload. Only needed for the initial link or when files are
|
||||||
|
added/removed.
|
||||||
|
- **Never `stow` the repo root** (`stow .dots`, `stow */`) — it folds package dirs into `~` as stray
|
||||||
|
`~/common`, `~/gui`, … symlinks. `install.sh` only ever links package *contents*.
|
||||||
|
- **New host:** create a top-level `<name>/` package (at least a `host.fish`), commit, then
|
||||||
|
`./install.sh`. If it's terminal-only, skip the package and just `touch ~/.config/dots-headless`
|
||||||
|
(it runs `common` only).
|
||||||
|
|
||||||
|
## Tooling (`bin/`)
|
||||||
|
|
||||||
|
| Command | What it does |
|
||||||
|
|---|---|
|
||||||
|
| `./install.sh [host]` | Deploy `common → gui → <host>`. Flags: `-n` dry-run, `-a` adopt (first run), `-D`/`--unstow` revert (remove this host's symlinks; repo + real files kept), `-h` help. Self-heals: headless hosts get any stray `gui` unstowed; fails loudly (exit 1) if a package couldn't stow. |
|
||||||
|
| `./bin/dotsync [-n]` | Sync with least churn: `git pull`, re-stow only if files were added/removed. |
|
||||||
|
| `./bin/reconcile-hyde.sh [-i\|--relink] [host]` | After a HyDE update overwrote `~/.config/hypr`, reconcile HyDE's new files against your dots versions (report / `-i` keep·take·merge each / `--relink` re-symlink). |
|
||||||
|
|
||||||
|
## How per-host differences are expressed
|
||||||
|
|
||||||
|
| Difference | Mechanism |
|
||||||
|
|---|---|
|
||||||
|
| Monitors | `<h>/.config/hypr/monitors.conf` (sourced by the shared `hyprland.conf`) |
|
||||||
|
| NVIDIA | `wm/.config/hypr/nvidia.conf`, pulled in by wm's `host.conf` (fl/lw have no NVIDIA) |
|
||||||
|
| Shell aliases | shared `config.fish` sources `~/.config/fish/host.fish` (per host) |
|
||||||
|
| Bash extras | shared `.bashrc` sources `~/.bashrc.host` (optional, per host) |
|
||||||
|
| fl's Hyprland | overrides ~9 hypr files (`hyprland.conf`, keybinds, windowrules, theme colors, monitors); inherits the rest from `gui` |
|
||||||
|
| Unique apps | in the owning host overlay (fl: llamacpp/evremap; lw: xremap) |
|
||||||
|
|
||||||
|
`aichat`, `pi`, and `opencode` are **single shared configs** in `common` (LAN-first, with the cloud
|
||||||
|
provider also listed so any host can switch) — no per-host overrides.
|
||||||
|
|
||||||
|
## HyDE dependency (important for GUI hosts)
|
||||||
|
|
||||||
|
The Hyprland config is [HyDE](https://github.com/HyDE-Project/HyDE)-based. `gui/.config/hypr/*` is
|
||||||
|
your customization layer, but it **sources HyDE's framework**:
|
||||||
|
`source = ~/.local/share/hyde/hyprland.conf` — which defines `$mainMod` and other variables and is
|
||||||
|
**not tracked by dots** (HyDE generates it). So a GUI host must have **HyDE installed**, or Hyprland
|
||||||
|
fails to start (`source globbing error` + `invalid mod $mainMod`).
|
||||||
|
|
||||||
|
- Install/update HyDE with its own installer (`~/HyDE/Scripts/install.sh`); it also pulls the
|
||||||
|
required apps (`xdg-desktop-portal-hyprland`, `xdg-desktop-portal-gtk`, `hyprpolkitagent`).
|
||||||
|
- HyDE's `-r`/restore overwrites `~/.config/hypr` — use **`bin/reconcile-hyde.sh`** afterward to fold
|
||||||
|
its new defaults back against your dots configs.
|
||||||
|
- **Wallpapers and generated themes are HyDE-owned, never in dots** (`**/hyde/themes/` and
|
||||||
|
`**/wallpapers/` are gitignored — they once bloated a source repo to 255 MB). A fresh machine gets
|
||||||
|
them from HyDE, not from this repo.
|
||||||
|
|
||||||
|
## Waybar (two worlds: HyDE-generated vs the standalone rig)
|
||||||
|
|
||||||
|
**HyDE owns `~/.config/waybar/config.jsonc` AND `style.css`** — its `waybar.py` *writes* both on
|
||||||
|
any `--set`/`--update`, **through the stow symlinks, i.e. into this repo's checkout**. So dots
|
||||||
|
track neither. HyDE-managed customization goes via:
|
||||||
|
|
||||||
|
- `gui/.config/waybar/layouts/*.jsonc` — dots-tracked layouts; switch with `hyde-shell waybar --set <name>`.
|
||||||
|
- `gui/.config/waybar/modules/*.jsonc` — module defs, globbed into the generated config.
|
||||||
|
|
||||||
|
**The custom cava rig is NOT HyDE-managed**: `layouts/custom.jsonc` + `layouts/custom.css` form a
|
||||||
|
self-contained two-bar config launched raw (`waybar -c …custom.jsonc -s …custom.css` — exec-once,
|
||||||
|
the Ctrl+Alt+W / Super+Shift+R binds, and the `wbar` abbr). **Never route it through
|
||||||
|
`hyde-shell waybar --set`** — waybar.py would clobber the repo's files as above. HyDE only reads
|
||||||
|
from `layouts/`, which is what makes them safe to track. On a rig host, HyDE's own bar (systemd
|
||||||
|
user unit `hyde-<XDG_SESSION_DESKTOP>-bar.service`, auto-restarting) must be disabled once:
|
||||||
|
`systemctl --user stop <unit>; systemctl --user mask <unit>`.
|
||||||
|
|
||||||
|
Note: the Arch `waybar` build has **no native `cava`** module — the rig uses the script module
|
||||||
|
`custom/cava` running `cava-waybar.sh` (self-contained, no HyDE dependency).
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
|
||||||
|
Never committed. Put `DUSKADIY_API_KEY` etc. in `~/.config/fish/conf.d/secrets.fish` (gitignored).
|
||||||
|
`pi`'s `auth.json` is **not** tracked — it only ever holds `$VAR` references, but pi's `/login`
|
||||||
|
rewrites it with the literal key, so one stray `/login` would commit a real token. A new host
|
||||||
|
bootstraps it with `cp common/.pi/agent/auth.json.example common/.pi/agent/auth.json`, then
|
||||||
|
`./install.sh`. Also gitignored: `fish_variables`,
|
||||||
|
`greet.txt`, pi agent runtime/state, `tmux/plugins/`, `.claude/` (Claude Code project dir/worktrees),
|
||||||
|
`*.bak`/`*.log`.
|
||||||
|
|
||||||
|
## Merge notes (history — the one-time unification)
|
||||||
|
|
||||||
|
The four former per-machine repos had drifted; the merge made some judgment calls:
|
||||||
|
|
||||||
|
- **`config.fish` / `.bashrc`** were hand-reconciled into a neutral shared base + per-host
|
||||||
|
`host.fish` / `.bashrc.host` (removed a committed `fnm_multishells` runtime PATH, stray
|
||||||
|
absolute home-dir paths, duplicate git aliases).
|
||||||
|
- **`pi` lives at `~/.pi`** (repo `.pi/`); **`tmux` at `~/.config/tmux/`** (delete a legacy
|
||||||
|
`~/.tmux.conf` if present after migrating).
|
||||||
|
- **Appearance drift was unified to one canonical** (mostly wm): bat, btop, cava, fastfetch, lazygit,
|
||||||
|
mpv, pyradio, waybar, zellij, most of nvim.
|
||||||
|
- **nvim** is shared entirely (no host overrides); plugin set / `lazy-lock.json` are shared — run
|
||||||
|
`:Lazy restore` per machine once (obeys the lockfile pins — `:Lazy update` on one machine +
|
||||||
|
commit is how versions move forward; other machines converge with `restore`).
|
||||||
|
- **`zellij`** is one shared config with **vim keybinds** (h/j/k/l) + the `guvbox-dark` theme.
|
||||||
|
- **`misc/{clis,tuis}.txt`** launcher inventories use wm's lists in `common`; a machine needing its
|
||||||
|
own can override in its overlay.
|
||||||
|
|
||||||
|
## Third-party content and licensing
|
||||||
|
|
||||||
|
The repo is GPL-3.0 (`LICENSE`). What that does and doesn't cover:
|
||||||
|
|
||||||
|
- **`hypr/`, `waybar/` and the other desktop configs are derived from
|
||||||
|
[HyDE](https://github.com/HyDE-Project/HyDE)** (and, further back, legacy Hyprdots). HyDE is
|
||||||
|
itself GPL-3.0, so the derivation and this repo's licence agree — no conflict, and the
|
||||||
|
Hyprdots-era ASCII banners in those files are left in place as attribution.
|
||||||
|
- **`common/.config/aichat/dark.tmTheme`** is *One Half Dark* by Son A. Pham, **MIT**. The
|
||||||
|
licence header at the top of that file is the attribution — don't strip it.
|
||||||
|
- **`common/.config/fastfetch/pngs/`** holds project and distro marks (Arch, the Open Source
|
||||||
|
Initiative and Open Source Hardware logos, …). Trademarks aren't relicensable, so GPL-3 does
|
||||||
|
not extend to them; they are bundled as nominative use, the way most dotfiles repos do.
|
||||||
|
- **`gui/.config/hypr/hyprlock/assets/`** — the lock screen background and logo. EXIF is
|
||||||
|
stripped, so the files carry no provenance; confirm these are yours to redistribute before
|
||||||
|
publishing, or swap them for something you know the origin of.
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# dotsync — sync dotfiles with the least churn.
|
||||||
|
#
|
||||||
|
# Deployed configs are symlinks into this repo, so `git pull` makes edits LIVE instantly
|
||||||
|
# with no re-stow — meaning no symlink churn and no app reloads (kitty etc. keep their
|
||||||
|
# runtime state). Re-stowing (install.sh) is only needed when files are ADDED / REMOVED,
|
||||||
|
# to create or prune symlinks. dotsync does the minimum: pull, and re-link ONLY if the
|
||||||
|
# pull added/removed/renamed files.
|
||||||
|
#
|
||||||
|
# dotsync pull, then relink only if the file set changed
|
||||||
|
# dotsync -n preview incoming changes (fetch only; no pull, no relink)
|
||||||
|
set -uo pipefail
|
||||||
|
DOTS="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/.." && pwd)"
|
||||||
|
cd "$DOTS" || exit 1
|
||||||
|
|
||||||
|
if [ "${1:-}" = "-n" ] || [ "${1:-}" = "--dry-run" ]; then
|
||||||
|
git fetch -q 2>/dev/null || { echo "fetch failed (offline?)"; exit 1; }
|
||||||
|
up="$(git rev-parse --abbrev-ref '@{u}' 2>/dev/null)" || { echo "no upstream set"; exit 1; }
|
||||||
|
# rev-list, not diff: a plain diff also fires when the LOCAL side is ahead, mislabelling
|
||||||
|
# your own unpushed commits as incoming. Count commits that exist only on the upstream.
|
||||||
|
n="$(git rev-list --count "HEAD..$up")"
|
||||||
|
if [ "$n" -eq 0 ]; then echo "already up to date with $up."; else
|
||||||
|
echo "incoming from $up ($n commit(s)):"; git --no-pager diff --stat "HEAD...$up"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
before="$(git rev-parse HEAD)"
|
||||||
|
if ! git pull --ff-only; then
|
||||||
|
echo "pull not fast-forward (local commits or conflicts) — commit/stash, then retry." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
after="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
if [ "$before" = "$after" ]; then
|
||||||
|
echo "already up to date — nothing to sync."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Services that read config ONCE at startup don't pick up pulled edits — nudge loudly.
|
||||||
|
# (Symlinked edits are live for everything else; these are the exceptions that bit us.)
|
||||||
|
if git diff --name-only "$before" "$after" | grep -q '\.config/llamacpp/' \
|
||||||
|
&& systemctl cat llama.service &>/dev/null; then
|
||||||
|
echo ""
|
||||||
|
echo "⚠⚠ llamacpp presets changed — the router reads them only at startup. Apply with:"
|
||||||
|
echo " sudo systemctl restart llama.service"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A unit file is read from /etc, not through the stow symlink — needs daemon-reload as well.
|
||||||
|
if git diff --name-only "$before" "$after" | grep -q '\.config/whisper/' \
|
||||||
|
&& systemctl cat whisper.service &>/dev/null; then
|
||||||
|
echo ""
|
||||||
|
echo "⚠⚠ whisper unit changed — apply with:"
|
||||||
|
echo " sudo systemctl daemon-reload && sudo systemctl restart whisper.service"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Modified files (M) are already live through the symlinks. Only Added/Deleted/Renamed
|
||||||
|
# need (un)linking, which is the only case that justifies the churny re-stow.
|
||||||
|
if git diff --name-status "$before" "$after" | grep -qE '^(A|D|R)'; then
|
||||||
|
echo "files added/removed/renamed — re-linking via install.sh (this may reload some apps)…"
|
||||||
|
exec "$DOTS/install.sh"
|
||||||
|
else
|
||||||
|
echo "edits only — already live through the symlinks; no re-stow, no reload needed."
|
||||||
|
fi
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# reconcile-hyde.sh — reconcile a HyDE update with your dots-tracked configs.
|
||||||
|
#
|
||||||
|
# HyDE's updater (`Scripts/install.sh -r`) overwrites every config listed in
|
||||||
|
# Scripts/restore_cfg.psv — including ~/.config/hypr/*. It backs the old ones up to
|
||||||
|
# ~/.config/cfg_backups and REPLACES your stow symlinks with real files (HyDE's new
|
||||||
|
# defaults). This tool, run ON THE GUI MACHINE right after that update, shows per file:
|
||||||
|
# your dots version vs HyDE's new one
|
||||||
|
# lets you keep / take / merge each, then removes the severed real files and re-runs
|
||||||
|
# install.sh so everything is symlinked back to the repo.
|
||||||
|
#
|
||||||
|
# ./bin/reconcile-hyde.sh [host] report only — safe, changes nothing (default)
|
||||||
|
# ./bin/reconcile-hyde.sh -i [host] interactive: decide each conflicting file
|
||||||
|
# ./bin/reconcile-hyde.sh --relink [host] skip decisions: back up severed files,
|
||||||
|
# then re-stow (repo versions win)
|
||||||
|
#
|
||||||
|
# host defaults to `hostname -s`. Commit your repo first so choices are reviewable/revertable.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
# Config subtrees where HyDE and your dots overlap. Add/remove as your setup needs.
|
||||||
|
SUBTREES=(.config/hypr .config/waybar)
|
||||||
|
|
||||||
|
# --- args ---
|
||||||
|
MODE=report
|
||||||
|
HOST=""
|
||||||
|
for a in "$@"; do
|
||||||
|
case "$a" in
|
||||||
|
-i|--interactive) MODE=interactive ;;
|
||||||
|
--relink) MODE=relink ;;
|
||||||
|
-h|--help) awk 'NR > 1 && !/^#/ { exit } NR > 1' "$0"; exit 0 ;;
|
||||||
|
-*) echo "unknown option: $a" >&2; exit 2 ;;
|
||||||
|
*) HOST="$a" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[ -z "$HOST" ] && HOST="$(hostname -s)"
|
||||||
|
skip_relink=() # files the user chose to skip during interactive reconcile
|
||||||
|
|
||||||
|
DOTS="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/.." && pwd)" # repo root (script in bin/)
|
||||||
|
[ -x "$DOTS/install.sh" ] || { echo "error: $DOTS/install.sh not found — run from inside the dots repo" >&2; exit 1; }
|
||||||
|
|
||||||
|
# repo package search order: host overlay wins, then gui, then common
|
||||||
|
PKGS=("$HOST" gui common)
|
||||||
|
repo_src() { # repo_src <rel-path> -> print the repo file stow would link, or nothing
|
||||||
|
local rel="$1" p
|
||||||
|
for p in "${PKGS[@]}"; do
|
||||||
|
[ -f "$DOTS/$p/$rel" ] && { printf '%s\n' "$DOTS/$p/$rel"; return 0; }
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "host=$HOST dots=$DOTS mode=$MODE"
|
||||||
|
if [ -n "$(git -C "$DOTS" status --porcelain 2>/dev/null)" ]; then
|
||||||
|
echo "note: $DOTS has uncommitted changes — commit first so reconcile choices are reviewable." >&2
|
||||||
|
fi
|
||||||
|
[ -d "$HOME/.config/cfg_backups" ] && echo "HyDE's pre-update backups are in ~/.config/cfg_backups"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --- classify every live file under the managed subtrees ---
|
||||||
|
linked=0; foreign=0
|
||||||
|
same=(); conflicts=(); new_files=()
|
||||||
|
for st in "${SUBTREES[@]}"; do
|
||||||
|
[ -d "$HOME/$st" ] || continue
|
||||||
|
while IFS= read -r -d '' live; do
|
||||||
|
rel="${live#"$HOME"/}"
|
||||||
|
if [ -L "$live" ]; then # still a symlink
|
||||||
|
tgt="$(readlink -f "$live" 2>/dev/null || true)"
|
||||||
|
case "$tgt" in
|
||||||
|
"$DOTS"/*) linked=$((linked+1)) ;; # intact -> HyDE didn't sever it
|
||||||
|
*) foreign=$((foreign+1)); echo " ? $rel -> symlink outside repo: $tgt" ;;
|
||||||
|
esac
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# real file: HyDE overwrote (severed) it, or it is brand new
|
||||||
|
src="$(repo_src "$rel" || true)"
|
||||||
|
if [ -z "$src" ]; then
|
||||||
|
new_files+=("$rel")
|
||||||
|
elif diff -q "$src" "$live" >/dev/null 2>&1; then
|
||||||
|
same+=("$rel") # content == repo; just relink
|
||||||
|
else
|
||||||
|
conflicts+=("$rel") # HyDE's new content differs from yours
|
||||||
|
fi
|
||||||
|
done < <(find "$HOME/$st" \( -type f -o -type l \) -print0)
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== summary =="
|
||||||
|
echo " intact symlinks (untouched): $linked"
|
||||||
|
echo " severed but identical (relink): ${#same[@]}"
|
||||||
|
echo " severed & CHANGED (need decision): ${#conflicts[@]}"
|
||||||
|
echo " new HyDE files not tracked by dots: ${#new_files[@]}"
|
||||||
|
[ "$foreign" -gt 0 ] && echo " foreign symlinks flagged above: $foreign"
|
||||||
|
echo
|
||||||
|
if [ "$linked" -gt 0 ]; then
|
||||||
|
echo "For intact symlinks, check whether HyDE wrote THROUGH them into the repo:"
|
||||||
|
echo " git -C $DOTS diff -- '*/.config/hypr/*' '*/.config/waybar/*'"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
if [ "${#new_files[@]}" -gt 0 ]; then
|
||||||
|
echo "New HyDE files (left as-is; add to a package + re-stow if you want them tracked):"
|
||||||
|
printf ' %s\n' "${new_files[@]}"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
if [ "${#conflicts[@]}" -gt 0 ]; then
|
||||||
|
echo "Changed files (your dots version vs HyDE's new default):"
|
||||||
|
for rel in "${conflicts[@]}"; do
|
||||||
|
src="$(repo_src "$rel")"
|
||||||
|
printf ' %-45s %s changed lines\n' "$rel" "$(diff "$src" "$HOME/$rel" | grep -cE '^[<>]')"
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# report-only ends here
|
||||||
|
if [ "$MODE" = report ]; then
|
||||||
|
if [ "${#conflicts[@]}" -gt 0 ]; then
|
||||||
|
echo "Re-run with -i to decide each changed file, or --relink to keep your repo versions wholesale."
|
||||||
|
elif [ "${#same[@]}" -gt 0 ]; then
|
||||||
|
echo "No content conflicts. Re-run with --relink to drop the severed files and re-symlink."
|
||||||
|
else
|
||||||
|
echo "Nothing to reconcile."
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- interactive: decide each changed file, writing the choice into the repo copy ---
|
||||||
|
if [ "$MODE" = interactive ] && [ "${#conflicts[@]}" -gt 0 ]; then
|
||||||
|
for rel in "${conflicts[@]}"; do
|
||||||
|
src="$(repo_src "$rel")"; live="$HOME/$rel"
|
||||||
|
echo "──────── $rel ────────"
|
||||||
|
echo " repo (yours): ${src#"$DOTS"/}"
|
||||||
|
diff "$src" "$live" | sed 's/^/ /' | head -60
|
||||||
|
echo " [k]eep yours (default) [t]ake HyDE's [m]erge in \$EDITOR -d [s]kip"
|
||||||
|
read -r -p " choice> " ans </dev/tty || ans=k
|
||||||
|
case "$ans" in
|
||||||
|
t|take) cp "$live" "$src"; echo " -> took HyDE's version into $src" ;;
|
||||||
|
m|merge) "${EDITOR:-nvim}" -d "$src" "$live" </dev/tty >/dev/tty 2>&1; echo " -> merged (saved $src)" ;;
|
||||||
|
s|skip) echo " -> skipped (left severed; not relinked)"; skip_relink+=("$rel") ;;
|
||||||
|
*) echo " -> kept your repo version" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- relink: back up severed files that the repo owns, remove them, re-stow ---
|
||||||
|
BK="$HOME/.config/hyde-reconcile-backup-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
to_relink=()
|
||||||
|
for st in "${SUBTREES[@]}"; do
|
||||||
|
[ -d "$HOME/$st" ] || continue
|
||||||
|
while IFS= read -r -d '' live; do
|
||||||
|
[ -L "$live" ] && continue # only real (severed) files
|
||||||
|
rel="${live#"$HOME"/}"
|
||||||
|
repo_src "$rel" >/dev/null || continue # only files the repo can provide
|
||||||
|
for s in "${skip_relink[@]}"; do [ "$s" = "$rel" ] && continue 2; done
|
||||||
|
to_relink+=("$rel")
|
||||||
|
done < <(find "$HOME/$st" -type f -print0)
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${#to_relink[@]}" -eq 0 ]; then
|
||||||
|
echo "nothing to relink."; exit 0
|
||||||
|
fi
|
||||||
|
echo "will back up + remove ${#to_relink[@]} severed file(s), then re-stow so they link to the repo:"
|
||||||
|
printf ' %s\n' "${to_relink[@]}"
|
||||||
|
read -r -p "proceed? [y/N] " go </dev/tty || go=n
|
||||||
|
case "$go" in y|Y|yes) ;; *) echo "aborted — nothing changed."; exit 0 ;; esac
|
||||||
|
|
||||||
|
for rel in "${to_relink[@]}"; do
|
||||||
|
mkdir -p "$BK/$(dirname "$rel")"
|
||||||
|
cp -a "$HOME/$rel" "$BK/$rel"
|
||||||
|
rm -f "$HOME/$rel"
|
||||||
|
done
|
||||||
|
echo "backed up to $BK; removed severed files. re-stowing…"
|
||||||
|
"$DOTS/install.sh" "$HOST"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "done. verify a couple of links resolve into the repo, e.g.:"
|
||||||
|
echo " readlink ~/.config/hypr/keybindings.conf"
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#
|
||||||
|
# ~/.bashrc (shared; host-specific bits in ~/.bashrc.host)
|
||||||
|
#
|
||||||
|
|
||||||
|
# If not running interactively, don't do anything
|
||||||
|
[[ $- != *i* ]] && return
|
||||||
|
|
||||||
|
# fzf's built-in walker ignores .ignore files; fd honours them. Mirrors config.fish.
|
||||||
|
export FZF_DEFAULT_COMMAND='fd --type f --strip-cwd-prefix'
|
||||||
|
|
||||||
|
alias grep='grep --color=auto'
|
||||||
|
alias fzf="fzf --preview 'bat --color=always {}'"
|
||||||
|
alias copy="wl-copy"
|
||||||
|
alias img="kitten icat"
|
||||||
|
alias fm="yazi"
|
||||||
|
alias lg="lazygit"
|
||||||
|
alias mkdir="mkdir -p"
|
||||||
|
alias pacs="sudo pacman -Syu --noconfirm"
|
||||||
|
alias yays="yay --noconfirm --sudoloop"
|
||||||
|
alias nmaps="sudo nmap -sn 192.168.0.0/24"
|
||||||
|
alias faillock="sudo faillock --reset"
|
||||||
|
alias xremaps="sudo xremap ~/.config/xremap/config.yml"
|
||||||
|
alias dots="cd ~/.dots/ && nvim"
|
||||||
|
alias aliases="bat ~/.config/fish/config.fish"
|
||||||
|
alias ipadd="sudo ip route add 192.168.0.234 dev wg0"
|
||||||
|
|
||||||
|
# List directory
|
||||||
|
alias l="ls -l"
|
||||||
|
alias la="ls -a"
|
||||||
|
alias lla="ls -la"
|
||||||
|
alias lt="ls --tree"
|
||||||
|
|
||||||
|
# Git
|
||||||
|
alias gs='git status'
|
||||||
|
alias gca='git add -p . && git commit'
|
||||||
|
alias gd="git diff --word-diff"
|
||||||
|
alias gl='git log --graph --show-signature'
|
||||||
|
alias gla="git log --all --decorate --oneline --graph"
|
||||||
|
alias gm='git merge'
|
||||||
|
|
||||||
|
# Powerline prompt, synthwave palette (needs a Nerd Font for the glyphs)
|
||||||
|
PROMPT_DIRTRIM=3
|
||||||
|
__pl_sep=$'\ue0b0' # powerline triangle
|
||||||
|
__pl_branch=$'\ue0a0' # branch glyph
|
||||||
|
__pl_seg() { # $1=bg $2=fg $3=text (colors as "R;G;B")
|
||||||
|
[[ -n $__pl_bg ]] && PS1+="\[\e[38;2;${__pl_bg};48;2;${1}m\]${__pl_sep}\[\e[0m\]"
|
||||||
|
PS1+="\[\e[48;2;${1};38;2;${2}m\] ${3} \[\e[0m\]"
|
||||||
|
__pl_bg=$1
|
||||||
|
}
|
||||||
|
__pl_end() {
|
||||||
|
PS1+="\[\e[38;2;${__pl_bg}m\]${__pl_sep}\[\e[0m\] "
|
||||||
|
__pl_bg=''
|
||||||
|
}
|
||||||
|
__prompt() {
|
||||||
|
local s=$?
|
||||||
|
# muted synthwave: segment colors pre-blended ~40% onto the terminal bg
|
||||||
|
# (#262335) so they read as semi-transparent overlays
|
||||||
|
local fg='205;200;220'
|
||||||
|
local purple='67;56;93' green='65;107;99' yellow='114;100;67'
|
||||||
|
local red='124;39;52' pink='122;71;77'
|
||||||
|
PS1="\[\e]0;\w\a\]"
|
||||||
|
__pl_bg=''
|
||||||
|
[[ -n $SSH_TTY ]] && __pl_seg "$pink" "$fg" '\u@\h'
|
||||||
|
__pl_seg "$purple" "$fg" '\w'
|
||||||
|
local b
|
||||||
|
if b=$(git symbolic-ref --short HEAD 2>/dev/null || git describe --contains --all HEAD 2>/dev/null); then
|
||||||
|
if [[ -n $(git status --porcelain 2>/dev/null | head -n1) ]]; then
|
||||||
|
__pl_seg "$yellow" "$fg" "${__pl_branch} ${b} ✱"
|
||||||
|
else
|
||||||
|
__pl_seg "$green" "$fg" "${__pl_branch} ${b}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
((s != 0)) && __pl_seg "$red" "$fg" "✘ ${s}"
|
||||||
|
[[ $EUID == 0 ]] && __pl_seg "$red" "$fg" '#'
|
||||||
|
__pl_end
|
||||||
|
}
|
||||||
|
PROMPT_COMMAND=__prompt
|
||||||
|
|
||||||
|
set -o vi
|
||||||
|
# eval "$(zoxide init --cmd cd bash)"
|
||||||
|
|
||||||
|
# colorized --help
|
||||||
|
h() { "$@" --help 2>&1 | bat --plain --language=help; }
|
||||||
|
|
||||||
|
# Record lookup against the local dmz db (adjust the db path to this machine)
|
||||||
|
lk(){
|
||||||
|
local DB="$HOME/projects/dmz/soft/lk/db.rec"
|
||||||
|
passes=0 count=0; until [ "$count" -eq "1" ] || [ "$passes" -gt 2 ] ; do \
|
||||||
|
query="$(recsel "$DB" -p aim,tag | recsel -iq "$query" -CP aim,tag | sort -u | fzf --preview="recsel \"$DB\" -e \"aim~{}\"")" \
|
||||||
|
&& count="$(recsel "$DB" -q "$query" -c )" ;\
|
||||||
|
passes=$(( passes + 1 )) ;\
|
||||||
|
done \
|
||||||
|
&& recsel "$DB" -q "$query" | recfmt -f "$HOME/projects/dmz/soft/lk/lists.fmt" | less
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keepassxc search
|
||||||
|
kp() {
|
||||||
|
local DB="${KP_DB:?Error: KP_DB environment variable is not set. Check .bash_profile.}"
|
||||||
|
read -sp "Enter db password: " pass; echo ""; printf '%s\n' "$pass" | keepassxc-cli ls -q -R "$DB" | fzf | (read -r entry; printf '%s\n' "$pass" | keepassxc-cli clip -q "$DB" "$entry" 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Per-host extras
|
||||||
|
[ -f ~/.bashrc.host ] && . ~/.bashrc.host
|
||||||
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# see https://github.com/sigoden/aichat/blob/main/config.example.yaml
|
||||||
|
keybindings: vi
|
||||||
|
editor: nvim
|
||||||
|
model: local:Qwen3-Coder-30B-Instruct-UD-Q3_K_XL
|
||||||
|
|
||||||
|
# Sessions: persist REPL sessions and keep more history before summarizing.
|
||||||
|
# The default compress_threshold (4000) summarizes far too early for 24k+ windows.
|
||||||
|
save_session: true
|
||||||
|
compress_threshold: 16000
|
||||||
|
|
||||||
|
# REPL prompts show live context usage (needs max_input_tokens, set per model below)
|
||||||
|
left_prompt: '{color.green}{?session {session}{?role /}}{role}{color.cyan}{?rag @{rag}}{color.reset}> '
|
||||||
|
right_prompt: '{color.purple}{?session {consume_tokens}/{max_input_tokens} }{color.reset}'
|
||||||
|
|
||||||
|
# NOTE: temperature/top_p are intentionally unset — the LAN server applies tuned
|
||||||
|
# per-model sampling via --jinja (e.g. GLM 0.6/0.95); a global value would clobber it.
|
||||||
|
|
||||||
|
# max_input_tokens = real ctx-size (from the router) minus output headroom.
|
||||||
|
clients:
|
||||||
|
# LAN access (fast; only reachable on the home network)
|
||||||
|
- type: openai-compatible
|
||||||
|
name: local
|
||||||
|
api_base: http://192.168.0.204:11343/v1
|
||||||
|
models: &lan_models
|
||||||
|
- name: Qwen3-Coder-30B-Instruct-UD-Q3_K_XL
|
||||||
|
max_input_tokens: 30000 # ctx 32768
|
||||||
|
- name: Qwen3-Coder-Next-UD-IQ3_XXS
|
||||||
|
max_input_tokens: 128000 # ctx 131072
|
||||||
|
- name: Qwen3.6-35B-A3B-MTP-UD-IQ3_XXS
|
||||||
|
max_input_tokens: 22000 # ctx 24576
|
||||||
|
supports_vision: true
|
||||||
|
- name: Qwen3.6-35B-A3B-Thinking
|
||||||
|
max_input_tokens: 22000 # ctx 24576
|
||||||
|
supports_vision: true
|
||||||
|
- name: Qwen3.5-9B-UD-Q6_K_XL
|
||||||
|
max_input_tokens: 30000 # ctx 32768
|
||||||
|
supports_vision: true
|
||||||
|
- name: gemma-4-26B-A4B-it-UD-IQ4_XS
|
||||||
|
max_input_tokens: 22000 # ctx 24576
|
||||||
|
supports_vision: true
|
||||||
|
- name: gemma-4-E4B-it-UD-Q8_K_XL
|
||||||
|
max_input_tokens: 62000 # ctx 65536
|
||||||
|
supports_vision: true
|
||||||
|
- name: GLM-4.7-Flash-UD-Q4_K_XL
|
||||||
|
max_input_tokens: 22000 # ctx 24576
|
||||||
|
- name: gpt-oss-20b
|
||||||
|
max_input_tokens: 62000 # ctx 65536
|
||||||
|
- name: gpt-oss-20b-low
|
||||||
|
max_input_tokens: 62000 # ctx 65536
|
||||||
|
# Remote access via duskadiy.com (reachable from anywhere; requires an API key —
|
||||||
|
# $DUSKADIY_API_KEY, from the gitignored conf.d/secrets.fish). The LAN endpoint above is keyless.
|
||||||
|
# Same server, same model ids — reuse the list above via a YAML anchor.
|
||||||
|
- type: openai-compatible
|
||||||
|
name: duskadiy
|
||||||
|
api_base: https://llm.duskadiy.com/api/v1
|
||||||
|
models: *lan_models
|
||||||
@@ -0,0 +1,663 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
Name: One Half Dark
|
||||||
|
Author: Son A. Pham <sp@sonpham.me>
|
||||||
|
Url: https://github.com/sonph/onehalf
|
||||||
|
License: The MIT License (MIT)
|
||||||
|
|
||||||
|
A dark Sublime Text color scheme based on Atom's One. See
|
||||||
|
github.com/sonph/onehalf for installation instructions, a light color
|
||||||
|
scheme, and versions for other editors/terminals such as Vim or iTerm.
|
||||||
|
|
||||||
|
Red: #e06c75
|
||||||
|
Green: #98c379
|
||||||
|
Yellow: #e5c07b
|
||||||
|
Blue: #61afef
|
||||||
|
Purple: #c678dd
|
||||||
|
Cyan: #56b6c2
|
||||||
|
White: #dcdfe4
|
||||||
|
Black: #282c34
|
||||||
|
Fg: #dcdfe4
|
||||||
|
Bg: #282c34
|
||||||
|
Comment: #5c6370
|
||||||
|
Gutter foreground: #919baa
|
||||||
|
Gutter background: #282c34
|
||||||
|
Selection: #474e5d
|
||||||
|
-->
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>OneHalfLight</string>
|
||||||
|
<key>semanticClass</key>
|
||||||
|
<string>theme.dark.one_half_dark</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string></string>
|
||||||
|
<key>colorSpaceName</key>
|
||||||
|
<string>sRGB</string>
|
||||||
|
<key>author</key>
|
||||||
|
<string>Son A. Pham <sp@sonpham.me></string>
|
||||||
|
<key>comment</key>
|
||||||
|
<string>A dark iTerm color scheme based on Atom's One. See github.com/sonph/onehalf for installation instructions, a light color scheme, and versions for other editors/terminals such as (Neo)Vim and Sublime Text.</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#282c34</string>
|
||||||
|
<key>bracketsOptions</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>caret</key>
|
||||||
|
<string>#a3b3cc</string>
|
||||||
|
<key>gutter</key>
|
||||||
|
<string>#282c34</string>
|
||||||
|
<key>gutterForeground</key>
|
||||||
|
<string>#919baa</string>
|
||||||
|
<key>invisibles</key>
|
||||||
|
<string>#5c6370</string>
|
||||||
|
<key>lineHighlight</key>
|
||||||
|
<string>#313640</string>
|
||||||
|
<key>selection</key>
|
||||||
|
<string>#474e5d</string>
|
||||||
|
<key>selectionBorder</key>
|
||||||
|
<string>#474e5d</string>
|
||||||
|
<key>tagsForeground</key>
|
||||||
|
<string></string>
|
||||||
|
<key>tagsOptions</key>
|
||||||
|
<string>stippled_underline</string>
|
||||||
|
<key>bracketContentsOptions</key>
|
||||||
|
<string>underline</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Comments</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>comment</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#5c6370</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Text</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.parameter.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Delimiters</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>none</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Operators</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword.operator</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Keywords</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#c678dd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variables</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Functions</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.function, meta.require, support.function.any-method</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#61afef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Classes</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.class, entity.name.class, entity.name.type.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Classes</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Methods</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword.other.special-method</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#61afef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#c678dd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Support</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#61afef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Strings, Inherited Class</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Integers</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.numeric</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Floats</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>none</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Boolean</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>none</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Constants</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>HTML: Tags</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>HTML: Tag attributes</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.attribute-name</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Attribute IDs</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.attribute-name.id, punctuation.definition.entity</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Selector</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.selector</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#c678dd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Headings</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.heading punctuation.definition.heading, entity.name.section</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#61afef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Bold</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.bold, punctuation.definition.bold</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#c678dd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Italic</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.italic, punctuation.definition.italic</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#c678dd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Code</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.raw.inline</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Link Text</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string.other.link, punctuation.definition.string.end.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Link Url</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.link</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Lists</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.list</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Quotes</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.quote</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Java Source</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.java meta.class.java meta.method.java</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Java Class Body</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.java meta.class.java meta.class.body.java</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Function Arguments</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js meta.function.js variable.parameter.function.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: New Variables</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js variable.other.readwrite.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Variables</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js variable.other.object.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Variables in Function Calls</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js meta.function-call.method.js variable.other.readwrite.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: New Block Variables</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js meta.block.js variable.other.readwrite.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Block Variables</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js meta.block.js variable.other.object.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Block Variables in Function Calls</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js meta.block.js meta.function-call.method.js variable.other.readwrite.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Function Calls</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js meta.function-call.method.js variable.function.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Properties</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js meta.property.object.js entity.name.function.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#61afef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Javascript: Prototypes</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.js support.constant.prototype.js</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Separator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.separator</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Inserted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.inserted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Deleted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.deleted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Changed</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.changed</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Regular Expressions</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string.regexp</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Escape Characters</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.character.escape</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#56b6c2</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Embedded</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.embedded, variable.interpolation</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Illegal</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid.illegal</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Broken</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid.broken</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Deprecated</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid.deprecated</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#e5c07b</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Unimplemented</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid.unimplemented</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#c678dd</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#dcdfe4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
temperature: 0.2
|
||||||
|
---
|
||||||
|
You are a terse coding assistant.
|
||||||
|
|
||||||
|
- Lead with the code, as a single fenced block.
|
||||||
|
- Add at most 1–2 short sentences of explanation, and only if genuinely needed. No preamble, no "here is", no closing summary.
|
||||||
|
- Match the language and style implied by the question; if unspecified, infer the most likely one.
|
||||||
|
- If the request is ambiguous, make the most reasonable assumption and state it in one line above the code.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
temperature: 0.2
|
||||||
|
---
|
||||||
|
You write a git commit message from a diff. Output ONLY the message — no preamble, no code fences, no explanation.
|
||||||
|
|
||||||
|
- Subject: `[Scope] imperative summary`, where Scope is a short tag inferred from the changed paths, matching the style of recent `git log` (e.g. [Waybar], [Fish], [LLM]). Keep it under 70 characters.
|
||||||
|
- Imperative mood ("add", "fix", "rename"), never past tense.
|
||||||
|
- For a non-trivial change, leave a blank line then add 1–4 terse bullets ("- ...") covering what changed and why. Omit the body for small, self-explanatory changes.
|
||||||
|
- Describe only what the diff actually shows; do not invent rationale or files.
|
||||||
|
|
||||||
|
The user's input is the diff (typically `git diff --cached`).
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
temperature: 0.1
|
||||||
|
---
|
||||||
|
You translate a request into a single shell command for the fish shell on Arch Linux. Output ONLY the command on one line — no code fence, no explanation.
|
||||||
|
|
||||||
|
- Use fish syntax, not bash. Notably: `set -x VAR value` (not `export`), `$status` (not `$?`), the `test` / `string` / `math` builtins, and `(cmd)` for command substitution (not `$(cmd)`). `&&` / `||` work in modern fish.
|
||||||
|
- Package management is pacman / yay (`yay -S`, `pacman -Qi`, `pacman -Qo`). Clipboard is Wayland: `wl-copy` / `wl-paste`.
|
||||||
|
- Prefer one pipeline. If several steps are unavoidable, chain them with `; and`.
|
||||||
|
- If it can't be done safely in one command, output a single `# ...` comment saying why instead.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
temperature: 0.2
|
||||||
|
---
|
||||||
|
You review a code diff for defects. Be concise and specific.
|
||||||
|
|
||||||
|
- Focus on correctness bugs, edge cases, error handling, security issues, and clear regressions. Skip style and formatting nits unless they cause a bug.
|
||||||
|
- Format each finding as `file:line — issue — why it matters`, most severe first.
|
||||||
|
- Reference exact identifiers and lines from the diff; do not speculate about code you cannot see.
|
||||||
|
- If nothing substantive is wrong, say so in one line rather than inventing issues.
|
||||||
|
|
||||||
|
The user's input is the diff (typically `git diff`).
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
model: local:gemma-4-E4B-it-UD-Q8_K_XL
|
||||||
|
temperature: 0.1
|
||||||
|
---
|
||||||
|
You translate a request into a single shell command for the fish shell on Arch Linux. Output ONLY the command on one line — no code fence, no explanation.
|
||||||
|
|
||||||
|
- Use fish syntax, not bash. Notably: `set -x VAR value` (not `export`), `$status` (not `$?`), the `test` / `string` / `math` builtins, and `(cmd)` for command substitution (not `$(cmd)`). `&&` / `||` work in modern fish.
|
||||||
|
- Package management is pacman / yay (`yay -S`, `pacman -Qi`, `pacman -Qo`). Clipboard is Wayland: `wl-copy` / `wl-paste`.
|
||||||
|
- Prefer one pipeline. If several steps are unavoidable, chain them with `; and`.
|
||||||
|
- If it can't be done safely in one command, output a single `# ...` comment saying why instead.
|
||||||
@@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
# Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes`
|
# Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes`
|
||||||
# for a list of all available themes
|
# for a list of all available themes
|
||||||
--theme="Catppuccin Mocha"
|
# Custom theme lives in ./themes/ — run `bat cache --build` after changing it
|
||||||
--style="numbers,changes,header"
|
--theme="OneHalfDark"
|
||||||
|
--style="numbers,changes,header,snip"
|
||||||
|
|
||||||
# Enable this to use italic text on the terminal. This is not supported on all
|
# Enable this to use italic text on the terminal. This is not supported on all
|
||||||
# terminal emulators (like tmux, by default):
|
# terminal emulators (like tmux, by default):
|
||||||
#--italic-text=always
|
--italic-text=always
|
||||||
|
|
||||||
# Uncomment the following line to disable automatic paging:
|
# Uncomment the following line to disable automatic paging:
|
||||||
#--paging=never
|
#--paging=never
|
||||||
@@ -17,10 +18,17 @@
|
|||||||
# Uncomment the following line if you are using less version >= 551 and want to
|
# Uncomment the following line if you are using less version >= 551 and want to
|
||||||
# enable mouse scrolling support in `bat` when running inside tmux. This might
|
# enable mouse scrolling support in `bat` when running inside tmux. This might
|
||||||
# disable text selection, unless you press shift.
|
# disable text selection, unless you press shift.
|
||||||
--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse"
|
--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse --ignore-case"
|
||||||
|
|
||||||
# Syntax mappings: map a certain filename pattern to a language.
|
# Syntax mappings: map a certain filename pattern to a language.
|
||||||
# Example 1: use the C++ syntax for Arduino .ino files
|
# Example 1: use the C++ syntax for Arduino .ino files
|
||||||
# Example 2: Use ".gitignore"-style highlighting for ".ignore" files
|
# Example 2: Use ".gitignore"-style highlighting for ".ignore" files
|
||||||
--map-syntax "*.ino:C++"
|
--map-syntax "*.ino:C++"
|
||||||
--map-syntax ".ignore:Git Ignore"
|
--map-syntax ".ignore:Git Ignore"
|
||||||
|
--map-syntax "**/hypr/**/*.conf:INI"
|
||||||
|
--map-syntax "**/kitty/*.conf:INI"
|
||||||
|
--map-syntax "*.ctl:INI"
|
||||||
|
--map-syntax ".inputrc:bash"
|
||||||
|
--map-syntax "**/cava/config:INI"
|
||||||
|
--map-syntax "**/mpv/*.conf:INI"
|
||||||
|
--map-syntax "**/btop/btop.conf:INI"
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>One Dark (NvChad base46)</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>3c1e2b84-9d5f-4a7c-8b2e-6f4a1d9c7e5b</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#1e222a</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#abb2bf</string>
|
||||||
|
<key>caret</key>
|
||||||
|
<string>#abb2bf</string>
|
||||||
|
<key>selection</key>
|
||||||
|
<string>#3e4451</string>
|
||||||
|
<key>lineHighlight</key>
|
||||||
|
<string>#252931</string>
|
||||||
|
<key>gutterForeground</key>
|
||||||
|
<string>#545862</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Comment</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>comment, punctuation.definition.comment</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6f737b</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Number, constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.numeric, constant.language, constant.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#d19a66</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Escape character</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.character.escape</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#a3b8ef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Keyword, storage</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword, storage</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#c882e7</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Operator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword.operator</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#abb2bf</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.function, support.function, meta.function-call.generic</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#61afef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Class, type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.class, entity.name.type, entity.name.struct, entity.name.enum, support.type, support.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e7c787</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable, variable.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function parameter</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.parameter</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Attribute</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.attribute-name</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#d19a66</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.tag, meta.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup heading</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.heading, entity.name.section</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>bold</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup bold</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.bold</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>bold</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup italic</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.italic</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup link</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.underline.link, string.other.link</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#61afef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup quote</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.quote</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6f737b</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Diff inserted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.inserted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#98c379</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Diff deleted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.deleted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#e06c75</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid, invalid.illegal</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#be5046</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,262 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Synthwave 84</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>7b2c3a10-4b6e-4d8f-9c1a-2e5f8d7a9b3c</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#262335</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
<key>caret</key>
|
||||||
|
<string>#f97e72</string>
|
||||||
|
<key>selection</key>
|
||||||
|
<string>#463465</string>
|
||||||
|
<key>lineHighlight</key>
|
||||||
|
<string>#2a2139</string>
|
||||||
|
<key>gutterForeground</key>
|
||||||
|
<string>#848bbd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Comment</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>comment, punctuation.definition.comment</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#848bbd</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff8b39</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Number, constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.numeric, constant.language, constant.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#f97e72</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Escape character</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.character.escape</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#36f9f6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Keyword, storage</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword, storage, keyword.operator</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#fede5d</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type, storage.modifier</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#fede5d</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.function, support.function, meta.function-call.generic</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#36f9f6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Class, type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.class, entity.name.type, entity.name.struct, entity.name.enum, support.type, support.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#fe4450</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable, variable.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff7edb</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function parameter</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.parameter</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff7edb</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Attribute</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.attribute-name</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#fede5d</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.tag, meta.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#72f1b8</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup heading</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.heading, entity.name.section</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#fe4450</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>bold</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup bold</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.bold</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>bold</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup italic</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.italic</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup link</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.underline.link, string.other.link</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#36f9f6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup quote</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.quote</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#848bbd</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Diff inserted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.inserted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#72f1b8</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Diff deleted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.deleted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#fe4450</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid, invalid.illegal</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#fe4450</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -253,7 +253,7 @@ show_battery_watts = true
|
|||||||
log_level = "WARNING"
|
log_level = "WARNING"
|
||||||
|
|
||||||
#* Automatically save current settings to config file on exit.
|
#* Automatically save current settings to config file on exit.
|
||||||
save_config_on_exit = true
|
save_config_on_exit = false
|
||||||
|
|
||||||
#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards.
|
#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards.
|
||||||
nvml_measure_pcie_speeds = true
|
nvml_measure_pcie_speeds = true
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
[general]
|
[general]
|
||||||
|
|
||||||
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
|
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
|
||||||
mode = scientific
|
# mode = scientific # deprecated since cava 0.6.0, ignored
|
||||||
|
|
||||||
# Accepts only non-negative values.
|
# Accepts only non-negative values.
|
||||||
framerate = 60
|
framerate = 60
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Global user preferences (applies to every project)
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
- Arch Linux, Wayland, fish shell, kitty terminal. Prefer fish-compatible syntax in shell snippets (not bash-isms) when writing things the user will run interactively. Clipboard is `wl-copy`.
|
||||||
|
- Package manager: pacman / yay. Common abbrs: `pacs`, `yays`.
|
||||||
|
|
||||||
|
## Local-first LLMs
|
||||||
|
- The user self-hosts models on the LAN at `192.168.0.204`:
|
||||||
|
- llama.cpp server — `http://192.168.0.204:11343/v1` (OpenAI-compatible).
|
||||||
|
- Ollama — `192.168.0.204:11434`.
|
||||||
|
- Recurring models: Qwen3-Coder-30B, gemma-4-26B, DeepSeek-Coder-V2-Lite, GLM-4.7-Flash. When configuring any AI/agent tool, default to these endpoints rather than a cloud API unless asked otherwise.
|
||||||
|
|
||||||
|
## Git
|
||||||
|
- **Do not run `git commit` or `git push`, and never offer or ask to do the committing/pushing yourself** — the user reviews and commits entirely manually (these are also denied in settings.json). Stage/prepare changes and stop there. You may suggest a commit message for the user to use, but nothing more.
|
||||||
|
- To hand off a suggested commit message, write it to the per-worktree file `$(git rev-parse --git-path CLAUDE_COMMIT_MSG)` — **not** `COMMIT_EDITMSG` (git overwrites that on `git commit`). A `prepare-commit-msg` hook prefills the editor from it (one-shot) on the next `git commit` / lazygit `C`. Just the raw message, no `#` comments.
|
||||||
|
|
||||||
|
## Formatting
|
||||||
|
- Lua: format with `stylua` (2-space indent, 120 col, no call parentheses — see any `.stylua.toml`).
|
||||||
|
|
||||||
|
## Dotfiles
|
||||||
|
- Configs live in the dots repo under `.config/` and are surfaced via per-directory symlinks into `~/.config/` (and `~/.claude/`). Editing a file under the repo's `.config/` is editing the live config — no deploy step.
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# Claude Code config
|
||||||
|
|
||||||
|
Portable [Claude Code](https://claude.com/claude-code) customizations, synced via these
|
||||||
|
dots. Claude Code still uses its default `~/.claude/` directory; we surface the tracked
|
||||||
|
files below into it via per-file/dir symlinks, so edits made through Claude write straight
|
||||||
|
back into this repo.
|
||||||
|
|
||||||
|
## What's tracked here
|
||||||
|
|
||||||
|
- `settings.json` — global settings: permissions (deny git commit/push + read of secret
|
||||||
|
files), default `model`, `enabledPlugins`, vim mode, dark theme, `effortLevel`, fullscreen
|
||||||
|
TUI, `statusLine`, `hooks`, `worktree` defaults, …
|
||||||
|
- `statusline.py` — rich status line (dir, git, model, context %, cost, disk — system metrics live in the tmux bar).
|
||||||
|
See [StatusBar.md](StatusBar.md) for what each segment and colour means.
|
||||||
|
- `keybindings.json` — custom keybindings (vim-style scroll/navigation).
|
||||||
|
- `CLAUDE.md` — global user preferences applied to every project.
|
||||||
|
- `hooks/format.py` — PostToolUse hook: formats edited files by extension (stylua / ruff /
|
||||||
|
prettier / gofmt / rustfmt / fish_indent / shfmt / taplo). Opinionated formatters (stylua, ruff,
|
||||||
|
prettier, taplo) only run where the project opts in via a config file found walking up; gofmt and
|
||||||
|
rustfmt gate on a project marker (`go.mod` / `Cargo.toml`); fish_indent and shfmt run on sight.
|
||||||
|
No-ops if the formatter isn't installed, and always exits 0.
|
||||||
|
- `skills/` — custom [Agent Skills](https://code.claude.com/docs/en/skills). See **Skills** below.
|
||||||
|
- `link.sh` — idempotent bootstrap that creates the `~/.claude` symlinks below.
|
||||||
|
|
||||||
|
Paths inside `settings.json` reference `~/.claude/...` via `$HOME`/`PATH` (`/usr/bin/env
|
||||||
|
python3 ~/.claude/...`), so they work regardless of the username, python location, or where the
|
||||||
|
dots repo is cloned (`~/.dots`, …).
|
||||||
|
|
||||||
|
## What is **not** tracked (stays local, per device)
|
||||||
|
|
||||||
|
Everything else under `~/.claude/` is machine-specific or secret and must never be committed:
|
||||||
|
credentials (`.credentials.json`), session history, `projects/` (transcripts + memory),
|
||||||
|
caches, and the `plugins/` cache/binaries.
|
||||||
|
|
||||||
|
## Setup on a new device
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Deploy the dotfiles repo — install.sh stows ~/.config/claude AND runs link.sh for you
|
||||||
|
cd ~/.dots && ./install.sh
|
||||||
|
|
||||||
|
# 2. Launch Claude and log in once (credentials are NOT synced)
|
||||||
|
claude
|
||||||
|
|
||||||
|
# 3. Reinstall the plugins from settings.json -> enabledPlugins
|
||||||
|
# (typescript-lsp, frontend-design — anthropics/claude-plugins-official) via /plugin.
|
||||||
|
# Optional: install any formatters you want the hook to use (stylua, ruff, prettier, …).
|
||||||
|
```
|
||||||
|
|
||||||
|
`install.sh` deploys `~/.config/claude` (via stow) and then runs `link.sh` automatically. You only
|
||||||
|
need to run `link.sh` by hand (`bash ~/.config/claude/link.sh`) if a link later gets clobbered
|
||||||
|
(e.g. Claude's `/config` replaces one with a plain file) — it's idempotent and self-healing.
|
||||||
|
|
||||||
|
A **new skill/hook** added to the repo shows up after a re-stow — `./install.sh` (or `dotsync`) links
|
||||||
|
the new file into `~/.config/claude`, which `link.sh` then surfaces into `~/.claude`.
|
||||||
|
|
||||||
|
## Skills
|
||||||
|
|
||||||
|
Custom skills live in `skills/<name>/SKILL.md` (the directory name is the `/command`) and are
|
||||||
|
linked in as `~/.claude/skills`. All are `disable-model-invocation: true` — explicit `/` only,
|
||||||
|
so Claude never auto-triggers them. Run them inside the repo whose branch you're working on.
|
||||||
|
|
||||||
|
- **`/review-branch [base]`** — reviews the current branch's diff (vs its merge-base with the
|
||||||
|
base branch) for 🐞 bugs / 🔒 security / ⚡ optimizations / 📖 readability, reports grouped
|
||||||
|
findings with `file:line`, then applies the readability + safe fixes *after you approve*. Never
|
||||||
|
commits.
|
||||||
|
Borrows `/code-review`'s discipline: CLAUDE.md-aware, changed-lines-only, verified bugs with a
|
||||||
|
false-positive filter (skips what linters/CI catch and pre-existing issues). Ends by pointing
|
||||||
|
you at the relevant built-in follow-ups (`/security-review`, `/code-review`, `/verify`, …).
|
||||||
|
- **`/pr-description [base]`** — auto-detects this repo's GitHub PR template
|
||||||
|
(`.github/pull_request_template.md`, …), fills it from the branch diff + commits, prints a
|
||||||
|
copy-paste markdown block, and copies it to the clipboard with `wl-copy`. Leaves verification
|
||||||
|
checkboxes for you; never creates/pushes the PR.
|
||||||
|
- **`/commit-msg [hint]`** — reads the **staged** diff, infers the repo's commit style from recent
|
||||||
|
`git log` (e.g. this repo's `[Scope] summary`), drafts a matching message, prints it, and copies
|
||||||
|
it to the clipboard with `wl-copy`. Never stages or commits — draft only.
|
||||||
|
- **`/pr-loop [pr]`** — babysits the current branch's PR in a self-paced loop: fixes review
|
||||||
|
comments that don't need your input — from **any** reviewer (Codex, Claude, humans) plus any
|
||||||
|
`@claude` request — `git add`s them, drafts the commit message (`/commit-msg` style) and marks
|
||||||
|
each thread with a reaction instead of an "Addressed — …" reply: **👍** fixed, **👀** parked for
|
||||||
|
your decision, **👎** a bot false positive (bots only, always with a one-line why). Then pings you
|
||||||
|
to commit & push and re-checks every ~10 min (via `ScheduleWakeup`). Resolves threads once their
|
||||||
|
fix is pushed — dismissals right away, since there's nothing to land. Stops when no unresolved comments
|
||||||
|
remain or the automated reviewers (Codex/Claude) hit their limit. Prep-only — never
|
||||||
|
commits/pushes/merges; needs `gh` authed and the session left open. Each cycle it prints when it
|
||||||
|
will re-check and that `Esc` (between cycles) stops it; on the last cycle it prints a clear
|
||||||
|
**"Finished — no more active issues"** and does not reschedule.
|
||||||
|
|
||||||
|
## Adding more config later
|
||||||
|
|
||||||
|
Drop the file/dir under `.config/claude/` here, add its name to the `items` list in `link.sh`,
|
||||||
|
and re-run `bash ~/.config/claude/link.sh`. For example `commands/` or `agents/`.
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
# Status line (`statusline.py`)
|
||||||
|
|
||||||
|
The custom Claude Code status line, ordered **work info (left) → system info (right)**,
|
||||||
|
segments joined by a light-gray `│`. It's **responsive**: always a single line — if the
|
||||||
|
rendered width would exceed the terminal (`$COLUMNS`, which Claude Code re-exports on
|
||||||
|
resize), trailing (lowest-priority) segments are dropped from the right until it fits.
|
||||||
|
|
||||||
|
Wide — everything:
|
||||||
|
|
||||||
|
```
|
||||||
|
📁 ~/.dots │ 🌿 .dots main* │ 🤖 Opus 4.8 (1M) · xhigh │ 📝 84% (843k) │ 📊 34% 2h54m │ 💰 $0.40 $12.00/h │ 💾 81%
|
||||||
|
```
|
||||||
|
|
||||||
|
Narrow — trailing segments trimmed:
|
||||||
|
|
||||||
|
```
|
||||||
|
📁 ~/.dots │ 🌿 .dots main* │ 🤖 Opus 4.8 (1M) · xhigh │ 📝 84% (843k) │ 📊 34% 2h54m │ 💰 $0.40 $12.00/h
|
||||||
|
```
|
||||||
|
|
||||||
|
Every segment is defensive: if its data is missing or a command fails, the segment is
|
||||||
|
simply omitted (the bar never crashes the UI). Secondary detail (the parts in light gray)
|
||||||
|
is supplementary to the main colored value.
|
||||||
|
|
||||||
|
## Live segments
|
||||||
|
|
||||||
|
| | Segment | Shows | Notes |
|
||||||
|
|---|---|---|---|
|
||||||
|
| | **Vim mode** | `[I]`/`[N]`/`[V]` editor mode | only with `editorMode: vim`; pair with `hideVimModeIndicator: true` so the built-in one doesn't duplicate it |
|
||||||
|
| 📁 | **Directory** | Current working dir, with `~` for home | cyan |
|
||||||
|
| 🌿 | **Git** | `repo branch` + `*` if dirty + `↑N`/`↓N` ahead/behind upstream | repo = magenta; branch = green when clean, yellow + red `*` when dirty; `↑` cyan, `↓` yellow. Omitted outside a repo |
|
||||||
|
| 🤖 | **Model** | Active model display name + `· effort` level (`low`/`medium`/`high`/`xhigh`) | name = blue, effort = light gray; effort omitted for models without the param |
|
||||||
|
| 📝 | **Context** | `% of context window used` + `(Nk)` tokens | window = 1M for `[1m]` models, else 200k. Adds a red **⚠compact** at ≥80% |
|
||||||
|
| 📊 | **5h usage** | `% of the 5-hour rolling limit used` + time until it resets | from `rate_limits.five_hour`; Pro/Max only, and absent until the first API response of a session |
|
||||||
|
| 💰 | **Cost** | `$` session cost so far + `$/h` burn rate | burn rate shown once the session exceeds ~30s |
|
||||||
|
| 💾 | **Disk** | `% used` of the filesystem at the cwd | from `statvfs` |
|
||||||
|
|
||||||
|
## Colour legend
|
||||||
|
|
||||||
|
Most numbers are **green / yellow / red** by threshold — green = healthy, red = needs
|
||||||
|
attention. Light gray = secondary detail. Thresholds (`green < … < yellow < … ≤ red`):
|
||||||
|
|
||||||
|
| Segment | green | yellow | red |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Context | `< 50%` | `50–80%` | `≥ 80%` (⚠compact) |
|
||||||
|
| 5h usage | `< 50%` | `50–80%` | `≥ 80%` |
|
||||||
|
| Disk | `< 75%` | `75–90%` | `≥ 90%` |
|
||||||
|
|
||||||
|
> Light gray is `\033[37m`; dimming (`\033[2m`) is disabled because it blended the gray
|
||||||
|
> detail text into dark terminal backgrounds. To go brighter, set `"gray"` to `\033[97m`
|
||||||
|
> (bright white) in the `C` table near the top of `statusline.py`.
|
||||||
|
|
||||||
|
## Optional segments (defined but not shown)
|
||||||
|
|
||||||
|
These functions exist in `statusline.py` but aren't in the output. Enable one by adding it
|
||||||
|
to the `work` or `system` list in `main()`:
|
||||||
|
|
||||||
|
RAM/CPU/temp were **retired 2026-07-26**: the status line only refreshes on message
|
||||||
|
events, so system metrics sat visibly stale between turns — the tmux status bar
|
||||||
|
(`tmux/scripts/`) owns live system metrics now.
|
||||||
|
|
||||||
|
| | Function | Shows |
|
||||||
|
|---|---|---|
|
||||||
|
| 🧠 | `ram_segment` | `% used` + `used/totalG` from `/proc/meminfo` (green `<70%` / yellow / red `≥85%`) |
|
||||||
|
| 🖥️ | `cpu_segment` | `% busy` (diffed `/proc/stat` snapshot) + loadavg + cores (green `<60%` / red `≥85%`) |
|
||||||
|
| 🌡️ | `temp_segment` | hottest CPU thermal zone °C (green `<60` / red `≥80`) |
|
||||||
|
| ✏️ | `velocity_segment` | `+added/-removed` lines this session + lines/min |
|
||||||
|
| ♻️ | `cache_segment` | prompt-cache hit % (higher is better) |
|
||||||
|
| ⚙️ | `api_segment` | share of wall-clock time spent in API/inference |
|
||||||
|
| | `version_segment` | Claude Code version (`vX.Y.Z`) |
|
||||||
|
| 🎨 | `style_segment` | active output-style name |
|
||||||
|
|
||||||
|
## Where it lives
|
||||||
|
|
||||||
|
`statusline.py` is tracked in this repo and symlinked to `~/.claude/statusline.py`;
|
||||||
|
`settings.json` runs it via `statusLine` (`/usr/bin/env python3 ~/.claude/statusline.py`).
|
||||||
|
Edits take effect on the next status refresh.
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""PostToolUse hook: format an edited file with the right formatter.
|
||||||
|
|
||||||
|
Reads the hook JSON from stdin, extracts the edited file path, and runs a
|
||||||
|
language-appropriate formatter -- but, to avoid imposing a style on a project
|
||||||
|
that never asked for it, opinionated formatters (stylua, ruff, prettier, taplo)
|
||||||
|
only run when the project opts in via a config file discoverable by walking up
|
||||||
|
from the edited file. Canonical single-style toolchains run on sight: gofmt and
|
||||||
|
rustfmt on their go.mod / Cargo.toml marker; fish_indent and shfmt whenever the
|
||||||
|
tool itself is installed (shell and fish have one de-facto style, no config).
|
||||||
|
|
||||||
|
Best-effort: always exits 0 so a format hiccup never blocks an edit. jq is not
|
||||||
|
guaranteed on the host, hence python for the stdin JSON parse.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def find_up(start, names):
|
||||||
|
"""Nearest ancestor dir (incl. the file's own) containing any of `names`."""
|
||||||
|
d = os.path.dirname(os.path.abspath(start))
|
||||||
|
while True:
|
||||||
|
if any(os.path.exists(os.path.join(d, n)) for n in names):
|
||||||
|
return d
|
||||||
|
parent = os.path.dirname(d)
|
||||||
|
if parent == d:
|
||||||
|
return None
|
||||||
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def has_toml_section(start, filename, section):
|
||||||
|
"""True if the nearest ancestor `filename` contains `section`."""
|
||||||
|
d = find_up(start, [filename])
|
||||||
|
if not d:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
with open(os.path.join(d, filename), errors="ignore") as fh:
|
||||||
|
return section in fh.read()
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def stylua_cmd(path):
|
||||||
|
exe = os.path.expanduser("~/.local/share/nvim/mason/bin/stylua")
|
||||||
|
if not os.access(exe, os.X_OK):
|
||||||
|
exe = shutil.which("stylua")
|
||||||
|
if exe and find_up(path, [".stylua.toml", "stylua.toml"]):
|
||||||
|
return [exe, path]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def ruff_cmd(path):
|
||||||
|
exe = shutil.which("ruff")
|
||||||
|
if exe and (find_up(path, ["ruff.toml", ".ruff.toml"])
|
||||||
|
or has_toml_section(path, "pyproject.toml", "[tool.ruff")):
|
||||||
|
return [exe, "format", path]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
_PRETTIER_CFGS = [
|
||||||
|
".prettierrc", ".prettierrc.json", ".prettierrc.yaml", ".prettierrc.yml",
|
||||||
|
".prettierrc.json5", ".prettierrc.js", ".prettierrc.cjs", ".prettierrc.mjs",
|
||||||
|
".prettierrc.toml", "prettier.config.js", "prettier.config.cjs",
|
||||||
|
"prettier.config.mjs",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def prettier_cmd(path):
|
||||||
|
exe = shutil.which("prettier")
|
||||||
|
if exe and find_up(path, _PRETTIER_CFGS):
|
||||||
|
return [exe, "--write", path]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def gofmt_cmd(path):
|
||||||
|
exe = shutil.which("gofmt")
|
||||||
|
if exe and find_up(path, ["go.mod"]): # one canonical style
|
||||||
|
return [exe, "-w", path]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def rustfmt_cmd(path):
|
||||||
|
exe = shutil.which("rustfmt")
|
||||||
|
if exe and find_up(path, ["Cargo.toml", "rustfmt.toml", ".rustfmt.toml"]):
|
||||||
|
return [exe, path]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def fish_cmd(path):
|
||||||
|
exe = shutil.which("fish_indent") # ships with fish, one canonical style
|
||||||
|
return [exe, "-w", path] if exe else None
|
||||||
|
|
||||||
|
|
||||||
|
def shfmt_cmd(path):
|
||||||
|
exe = shutil.which("shfmt") # de-facto shell formatter, sane defaults
|
||||||
|
return [exe, "-w", path] if exe else None
|
||||||
|
|
||||||
|
|
||||||
|
def taplo_cmd(path):
|
||||||
|
exe = shutil.which("taplo")
|
||||||
|
# opt-in: TOML reflow/align is intrusive, so only where the project asked.
|
||||||
|
if exe and find_up(path, ["taplo.toml", ".taplo.toml"]):
|
||||||
|
return [exe, "format", path]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
HANDLERS = {
|
||||||
|
".lua": stylua_cmd,
|
||||||
|
".py": ruff_cmd,
|
||||||
|
".js": prettier_cmd, ".jsx": prettier_cmd, ".mjs": prettier_cmd,
|
||||||
|
".cjs": prettier_cmd, ".ts": prettier_cmd, ".tsx": prettier_cmd,
|
||||||
|
".css": prettier_cmd, ".scss": prettier_cmd, ".less": prettier_cmd,
|
||||||
|
".html": prettier_cmd, ".vue": prettier_cmd, ".json": prettier_cmd,
|
||||||
|
".md": prettier_cmd, ".yaml": prettier_cmd, ".yml": prettier_cmd,
|
||||||
|
".go": gofmt_cmd,
|
||||||
|
".rs": rustfmt_cmd,
|
||||||
|
".fish": fish_cmd,
|
||||||
|
".sh": shfmt_cmd, ".bash": shfmt_cmd,
|
||||||
|
".toml": taplo_cmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
ti = data.get("tool_input") or {}
|
||||||
|
tr = data.get("tool_response") or {}
|
||||||
|
path = ti.get("file_path") or tr.get("filePath") or ""
|
||||||
|
if not path or not os.path.isfile(path):
|
||||||
|
return
|
||||||
|
handler = HANDLERS.get(os.path.splitext(path)[1].lower())
|
||||||
|
if not handler:
|
||||||
|
return
|
||||||
|
cmd = handler(path)
|
||||||
|
if not cmd:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
subprocess.run(cmd, timeout=15, capture_output=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://www.schemastore.org/claude-code-keybindings.json",
|
||||||
|
"$docs": "https://code.claude.com/docs/en/keybindings",
|
||||||
|
"bindings": [
|
||||||
|
{
|
||||||
|
"context": "Global",
|
||||||
|
"bindings": {
|
||||||
|
"alt+j": "scroll:lineDown",
|
||||||
|
"alt+k": "scroll:lineUp",
|
||||||
|
"ctrl+shift+j": "scroll:lineDown",
|
||||||
|
"ctrl+shift+k": "scroll:lineUp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "MessageSelector",
|
||||||
|
"bindings": {
|
||||||
|
"g": "messageSelector:top",
|
||||||
|
"shift+g": "messageSelector:bottom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "Select",
|
||||||
|
"bindings": {
|
||||||
|
"g": "select:first",
|
||||||
|
"shift+g": "select:last"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "Footer",
|
||||||
|
"bindings": {
|
||||||
|
"j": "footer:down",
|
||||||
|
"k": "footer:up"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Surface this repo's Claude Code config into ~/.claude via symlinks.
|
||||||
|
#
|
||||||
|
# `stow` deploys the repo to ~/.config/claude; Claude itself reads from ~/.claude,
|
||||||
|
# so we link the individual files/dirs across. Idempotent and self-healing: re-run
|
||||||
|
# any time. It also flags any file that has broken out of stow into a plain file —
|
||||||
|
# which silently stops Claude's edits from reaching the repo.
|
||||||
|
# (New skills/hooks added to the repo appear after a re-stow: `./install.sh` or `dotsync`.)
|
||||||
|
#
|
||||||
|
# bash ~/.config/claude/link.sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SRC="$HOME/.config/claude"
|
||||||
|
DST="$HOME/.claude"
|
||||||
|
|
||||||
|
if [ ! -e "$SRC" ]; then
|
||||||
|
echo "error: $SRC not found — run 'cd ~/.dots && ./install.sh' first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$DST"
|
||||||
|
|
||||||
|
# This repo's claude dir, resolved via link.sh's own symlink (location-independent).
|
||||||
|
repo=$(dirname "$(readlink -f "$SRC/link.sh")")
|
||||||
|
|
||||||
|
# If link.sh itself has broken out of stow into a plain file, $repo resolves to $SRC and
|
||||||
|
# the drift heal below would relink each drifted file onto ITSELF — destroying the only
|
||||||
|
# copy of its content. Refuse to continue.
|
||||||
|
if [ "$repo" = "$SRC" ]; then
|
||||||
|
echo "error: link.sh itself is a plain file (broken out of stow) — re-stow first:" >&2
|
||||||
|
echo " cd ~/.dots && ./install.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Tracked items to expose in ~/.claude. Add new ones (e.g. commands agents) here.
|
||||||
|
items="settings.json statusline.py keybindings.json CLAUDE.md hooks skills"
|
||||||
|
|
||||||
|
# Expose each item in ~/.claude (where Claude actually reads).
|
||||||
|
for item in $items; do
|
||||||
|
[ -e "$SRC/$item" ] || continue
|
||||||
|
if [ -d "$DST/$item" ] && [ ! -L "$DST/$item" ]; then
|
||||||
|
echo "skip ~/.claude/$item (real directory in the way — move it aside first)" >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# A plain FILE here means an atomic write replaced the link (Claude writes e.g.
|
||||||
|
# ~/.claude/settings.json) — it may hold newer edits, so never clobber it silently:
|
||||||
|
# heal only when provably lossless, warn otherwise (mirrors the SRC drift guard below).
|
||||||
|
if [ -f "$DST/$item" ] && [ ! -L "$DST/$item" ]; then
|
||||||
|
same=0
|
||||||
|
case "$item" in
|
||||||
|
*.json)
|
||||||
|
python3 -c 'import json,sys; sys.exit(0 if json.load(open(sys.argv[1]))==json.load(open(sys.argv[2])) else 1)' \
|
||||||
|
"$DST/$item" "$SRC/$item" 2>/dev/null && same=1 ;;
|
||||||
|
*)
|
||||||
|
cmp -s "$DST/$item" "$SRC/$item" && same=1 ;;
|
||||||
|
esac
|
||||||
|
if [ "$same" != 1 ]; then
|
||||||
|
echo "DRIFT ~/.claude/$item is a real file that differs from the repo copy —" >&2
|
||||||
|
echo " it may hold newer edits. Review, then re-link:" >&2
|
||||||
|
echo " diff '$DST/$item' '$SRC/$item' # compare; keep whichever is right" >&2
|
||||||
|
echo " ln -sfn '$SRC/$item' '$DST/$item' # re-link" >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "healed ~/.claude/$item (plain copy identical to repo — re-linking)"
|
||||||
|
fi
|
||||||
|
ln -sfn "$SRC/$item" "$DST/$item"
|
||||||
|
echo "linked ~/.claude/$item -> ~/.config/claude/$item"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Stow-layer drift guard: each SRC *file* should be a symlink into the repo, so edits
|
||||||
|
# Claude writes (e.g. via /config) flow back and stay tracked. If an atomic write
|
||||||
|
# replaced one with a plain file, it has silently broken out of stow. Auto-heal only
|
||||||
|
# when provably lossless — the plain file is identical to the repo copy (JSON compared
|
||||||
|
# ignoring key order, since /config often just reorders keys). Otherwise warn and stop:
|
||||||
|
# the file may hold newer edits worth diffing in before re-linking.
|
||||||
|
for item in $items; do
|
||||||
|
[ -f "$SRC/$item" ] && [ ! -L "$SRC/$item" ] || continue # a real file where a link belongs
|
||||||
|
same=0
|
||||||
|
if [ -f "$repo/$item" ]; then
|
||||||
|
case "$item" in
|
||||||
|
*.json)
|
||||||
|
python3 -c 'import json,sys; sys.exit(0 if json.load(open(sys.argv[1]))==json.load(open(sys.argv[2])) else 1)' \
|
||||||
|
"$SRC/$item" "$repo/$item" 2>/dev/null && same=1 ;;
|
||||||
|
*)
|
||||||
|
cmp -s "$SRC/$item" "$repo/$item" && same=1 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
if [ "$same" = 1 ]; then
|
||||||
|
ln -sfrn "$repo/$item" "$SRC/$item" # -r: relative link, so stow keeps owning it
|
||||||
|
echo "healed ~/.config/claude/$item (plain copy identical to repo — re-linked)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "DRIFT ~/.config/claude/$item is a real file that differs from the repo copy —" >&2
|
||||||
|
echo " it may hold edits not yet tracked. Review, then re-link:" >&2
|
||||||
|
echo " diff '$SRC/$item' '$repo/$item' # compare; keep whichever is right" >&2
|
||||||
|
echo " ln -sfrn '$repo/$item' '$SRC/$item' # re-link (relative, stow-owned)" >&2
|
||||||
|
done
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"attribution": {
|
||||||
|
"commit": "",
|
||||||
|
"pr": ""
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"deny": [
|
||||||
|
"Bash(git push)",
|
||||||
|
"Bash(git push:*)",
|
||||||
|
"Bash(git commit)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(git reset --hard)",
|
||||||
|
"Bash(git reset --hard:*)",
|
||||||
|
"Bash(git clean)",
|
||||||
|
"Bash(git clean:*)",
|
||||||
|
"Read(**/.env)",
|
||||||
|
"Read(**/.env.*)",
|
||||||
|
"Read(**/*.env)",
|
||||||
|
"Read(**/*.pem)",
|
||||||
|
"Read(**/*.key)",
|
||||||
|
"Read(**/*.p12)",
|
||||||
|
"Read(**/*.pfx)",
|
||||||
|
"Read(**/*.keystore)",
|
||||||
|
"Read(**/id_rsa*)",
|
||||||
|
"Read(**/.ssh/**)",
|
||||||
|
"Read(**/.aws/**)",
|
||||||
|
"Read(**/.npmrc)",
|
||||||
|
"Read(**/.netrc)",
|
||||||
|
"Read(**/.git-credentials)",
|
||||||
|
"Read(**/.claude/.credentials.json)",
|
||||||
|
"Read(**/secrets.fish)",
|
||||||
|
"Read(**/*.token)",
|
||||||
|
"Read(**/.envrc)"
|
||||||
|
],
|
||||||
|
"defaultMode": "auto"
|
||||||
|
},
|
||||||
|
"model": "opus[1m]",
|
||||||
|
"enableWorkflows": false,
|
||||||
|
"skipWorkflowUsageWarning": true,
|
||||||
|
"enabledPlugins": {
|
||||||
|
"typescript-lsp@claude-plugins-official": true,
|
||||||
|
"frontend-design@claude-plugins-official": true
|
||||||
|
},
|
||||||
|
"statusLine": {
|
||||||
|
"type": "command",
|
||||||
|
"command": "/usr/bin/env python3 ~/.claude/statusline.py",
|
||||||
|
"padding": 0,
|
||||||
|
"hideVimModeIndicator": true
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Edit|Write|MultiEdit",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "/usr/bin/env python3 ~/.claude/hooks/format.py",
|
||||||
|
"timeout": 20,
|
||||||
|
"statusMessage": "format"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"worktree": {
|
||||||
|
"baseRef": "fresh"
|
||||||
|
},
|
||||||
|
"effortLevel": "xhigh",
|
||||||
|
"advisorModel": "fable",
|
||||||
|
"tui": "fullscreen",
|
||||||
|
"theme": "dark",
|
||||||
|
"editorMode": "vim",
|
||||||
|
"verbose": true,
|
||||||
|
"autoCompactEnabled": true,
|
||||||
|
"remoteControlAtStartup": false,
|
||||||
|
"inputNeededNotifEnabled": false,
|
||||||
|
"agentPushNotifEnabled": false,
|
||||||
|
"skipAutoPermissionPrompt": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
description: Draft a commit message for the staged changes, matching this repo's commit style, then print it in the reply, save it to the repo's CLAUDE_COMMIT_MSG file, and copy it to the clipboard. Never stages or commits. Use once you've staged what you want to commit.
|
||||||
|
argument-hint: [optional focus/scope hint]
|
||||||
|
disable-model-invocation: true
|
||||||
|
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git status:*), Bash(git rev-parse:*), Bash(wl-copy:*), Read, Glob, Write
|
||||||
|
---
|
||||||
|
|
||||||
|
# Draft a commit message for the staged changes
|
||||||
|
|
||||||
|
Context for the current commit — what's staged, plus this repo's recent style:
|
||||||
|
|
||||||
|
!`echo "=== Staged (git diff --cached --stat) ==="; git --no-pager diff --cached --stat 2>/dev/null; echo; echo "=== Working tree (git status --short) ==="; git --no-pager status --short 2>/dev/null; echo; echo "=== Recent subjects — match this convention ==="; git --no-pager log -20 --pretty=format:'%s' 2>/dev/null`
|
||||||
|
|
||||||
|
## What to do
|
||||||
|
|
||||||
|
1. **See exactly what's being committed.** Read the full staged diff with
|
||||||
|
`git --no-pager diff --cached`. If nothing is staged (the stat above is empty), tell me and
|
||||||
|
**stop** — I stage changes myself; never run `git add`.
|
||||||
|
2. **Learn the repo's commit style** from the recent subjects above — prefix convention (this repo
|
||||||
|
uses `[Scope] summary`), imperative vs. past tense, subject length, whether bodies are used.
|
||||||
|
Match what's already there; don't impose Conventional Commits / gitmoji if the repo doesn't use
|
||||||
|
them.
|
||||||
|
3. **Write the message from the *actual* staged diff** (not a guess):
|
||||||
|
- A concise subject in the repo's style (~50 chars, imperative). Fold in my hint if given:
|
||||||
|
**$ARGUMENTS**.
|
||||||
|
- Add a short body (wrapped ~72 cols) only when the change needs the *why*; otherwise
|
||||||
|
subject-only. Don't invent motivation that isn't evident from the diff.
|
||||||
|
4. **Print the message in your reply first** — as a single fenced ` ```text ` block, copy-paste
|
||||||
|
ready. This in-reply copy is the durable one: it lives in the transcript, so it survives even if
|
||||||
|
the clipboard gets overwritten later (by me copying something else, or another Claude session
|
||||||
|
running `wl-copy`). Always print it; don't rely on the clipboard alone.
|
||||||
|
5. **Save it to a file in the repo** so I can recover it any time: resolve the path with
|
||||||
|
`git rev-parse --git-path CLAUDE_COMMIT_MSG` (per-worktree correct), then use the Write tool to
|
||||||
|
write the raw message there — **not** `COMMIT_EDITMSG`, which git overwrites on every
|
||||||
|
`git commit` before the editor opens. My `prepare-commit-msg` hook prefills the commit editor
|
||||||
|
from `CLAUDE_COMMIT_MSG` (one-shot) on the next `git commit` / lazygit `C`. The file lives
|
||||||
|
inside the git dir so it never shows up in `git status`.
|
||||||
|
6. **Also copy it to the clipboard** as a convenience: `wl-copy < <path from step 5>`. Then
|
||||||
|
tell me all three places it is: **printed above**, **saved to `CLAUDE_COMMIT_MSG`** (hook
|
||||||
|
prefills the next commit), and **on the clipboard** — so I never lose it to a stray copy.
|
||||||
|
7. **Never** run `git add`, `git commit`, or `git push`, and never offer to — I stage and commit
|
||||||
|
manually. Draft only.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
description: Draft a ready-to-paste PR description by filling this repo's GitHub PR template from the branch diff and commits, then copy it to the clipboard. Use after finishing a feature.
|
||||||
|
argument-hint: [base-branch]
|
||||||
|
disable-model-invocation: true
|
||||||
|
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git merge-base:*), Bash(git symbolic-ref:*), Bash(git rev-parse:*), Bash(git show-ref:*), Bash(ls:*), Bash(cat:*), Bash(wl-copy:*), Bash(mktemp:*), Bash(rm:*), Read, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Draft this branch's PR description
|
||||||
|
|
||||||
|
This repo's PR template (first match), plus the branch's changes:
|
||||||
|
|
||||||
|
!`for f in .github/pull_request_template.md .github/PULL_REQUEST_TEMPLATE.md docs/pull_request_template.md docs/PULL_REQUEST_TEMPLATE.md PULL_REQUEST_TEMPLATE.md pull_request_template.md; do if [ -f "$f" ]; then echo "=== PR template: $f ==="; cat "$f"; found=1; break; fi; done; if [ -z "$found" ]; then if [ -d .github/PULL_REQUEST_TEMPLATE ]; then echo "=== template dir .github/PULL_REQUEST_TEMPLATE/ (pick one) ==="; ls .github/PULL_REQUEST_TEMPLATE/; else echo "(no PR template found — use the fallback structure)"; fi; fi`
|
||||||
|
|
||||||
|
!`b=$(git symbolic-ref --short -q refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@'); [ -z "$b" ] && { git show-ref -q --verify refs/heads/main && b=main || b=master; }; m=$(git merge-base "$b" HEAD 2>/dev/null); echo "Branch: $(git rev-parse --abbrev-ref HEAD 2>/dev/null) Base: $b Range: ${m:-?}..HEAD"; echo; echo "Commits:"; git --no-pager log --oneline "${m}..HEAD" 2>/dev/null; echo; echo "Files changed:"; git --no-pager diff --stat "${m}...HEAD" 2>/dev/null`
|
||||||
|
|
||||||
|
## What to do
|
||||||
|
|
||||||
|
1. **Resolve the base branch** (use the invocation argument if given — **$ARGUMENTS** — else the
|
||||||
|
detected base) and read the full diff + commit messages for `merge-base..HEAD`.
|
||||||
|
2. **Fill the PR template shown above** from the *actual* changes:
|
||||||
|
- Write the Summary / motivation and any "Implementation Notes" from the diff and commits.
|
||||||
|
- Fill the **Type of Change** field or boxes with the kinds that genuinely match (feature /
|
||||||
|
fix / refactor / perf / tests / docs / chore).
|
||||||
|
- Tick `Self-reviewed` and `LLM-assisted` if those boxes exist.
|
||||||
|
- **Leave verification boxes unchecked** — e.g. "tests passed", "`validate:full` passes",
|
||||||
|
"pre-commit hooks passed". I confirm those myself; never tick them for me.
|
||||||
|
- Fill **Related Issues** from issue numbers in the branch name or commit trailers; delete any
|
||||||
|
placeholder lines you can't fill (never leave a dangling `Closes #`), and drop the whole
|
||||||
|
section if there are no issues to reference.
|
||||||
|
- If a multi-template dir was listed (no single file), pick the most fitting one and say which.
|
||||||
|
- **If no template exists**, use this fallback: `## Summary` / `## Changes` / `## Testing` /
|
||||||
|
`## Notes`.
|
||||||
|
3. **Output** the filled description as a single fenced ```markdown code block, copy-paste ready.
|
||||||
|
4. **Copy it to the clipboard**: write the same markdown to a temp file (`mktemp`) and run
|
||||||
|
`wl-copy < "$tmpfile"`, then remove the temp file. Tell me it's on the clipboard.
|
||||||
|
5. **Do not** create, push, or edit the PR (`gh pr ...`) — I add the text to the PR myself.
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
---
|
||||||
|
description: Babysit the current branch's PR — address review comments that don't need my input, re-check every ~10 min, and stop when there are no open comments left or the automated reviewers (Codex, Claude) hit their limit. Prep-only — stages fixes and drafts the commit message; never commits, pushes, or merges.
|
||||||
|
argument-hint: [pr number or url — optional; defaults to the current branch's PR]
|
||||||
|
disable-model-invocation: true
|
||||||
|
allowed-tools: Bash(gh:*), Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git rev-parse:*), Bash(git fetch:*), Bash(git add:*), Bash(wl-copy:*), Read, Edit, Write, Grep, Glob, ScheduleWakeup
|
||||||
|
---
|
||||||
|
|
||||||
|
# Watch this PR and resolve review comments (prep-only)
|
||||||
|
|
||||||
|
A self-paced loop over one PR's review feedback: fix the comments that don't need my judgement,
|
||||||
|
stage them, draft a commit message, then wait ~10 min and re-check — until there are no unresolved
|
||||||
|
comments left or the automated reviewers (Codex/Claude) hit a usage limit.
|
||||||
|
|
||||||
|
**The contract — read this first:**
|
||||||
|
- **I never commit, push, or merge.** Each cycle you *prepare*: edit + `git add` + draft a commit
|
||||||
|
message + reply on the threads you handled. Then you **ping me to commit & push**, and the loop
|
||||||
|
resumes after I do. This honours the global no-commit/no-push rule; nothing in `settings.json`
|
||||||
|
changes.
|
||||||
|
- **React, don't reply — then resolve.** A handled thread gets a 👍 **reaction** on the reviewer's
|
||||||
|
comment while unpushed — never an "Addressed — …" reply, those are just noise. Once I've pushed
|
||||||
|
and its fix is live, you **resolve the thread on GitHub** (or minimize the bot comment as
|
||||||
|
RESOLVED) rather than leaving it open — see step 6. Never resolve unpushed work or a needs-input
|
||||||
|
thread. The **only** comments you ever post are the one-line decision questions for needs-input
|
||||||
|
items (step 7) and the one-line reason on a dismissal.
|
||||||
|
- **The marker vocabulary — exactly these three, never others.** Every item you triage gets exactly
|
||||||
|
one reaction, so I can read the PR's state at a glance without opening threads:
|
||||||
|
- 👍 `+1` — **addressed**: fix staged; the thread gets resolved once I push.
|
||||||
|
- 👀 `eyes` — **parked**: needs a decision from me, paired with the one-line question (step 7).
|
||||||
|
- 👎 `-1` — **dismissed**: a *bot* finding that's wrong, paired with a one-line why, then
|
||||||
|
resolved/minimized straight away (step 8).
|
||||||
|
|
||||||
|
**Never 👎 a human's comment.** If I'm the one who's wrong, write the reasoning as a reply and
|
||||||
|
park it as 👀 — I decide, not you. And don't invent other reactions (🎉/❤️/🚀/😄/😕): an
|
||||||
|
unexplained emoji is worse than no emoji.
|
||||||
|
- The 10-minute cadence uses `ScheduleWakeup`, so the loop only advances **while this Claude
|
||||||
|
session stays open**. **To stop it: press `Esc` while I'm idle between cycles** (that clears the
|
||||||
|
queued wake-up); closing the session also stops it. A plain message does **not** cancel a pending
|
||||||
|
wake-up — use `Esc`.
|
||||||
|
- **Every token counts.** Each wake-up re-reads the whole conversation with a cold prompt cache
|
||||||
|
(the 10-min cadence outlives the 5-min cache TTL), so cost compounds with every cycle and every
|
||||||
|
extra line in context. Therefore: fetch **filtered** data only (use the `--jq` filters below —
|
||||||
|
never let raw unfiltered JSON into the conversation), summarize deltas rather than restating
|
||||||
|
unchanged state, and keep idle cycles to **one cheap API call and ≤2 lines of output**.
|
||||||
|
|
||||||
|
Current state (auth + the current branch's PR):
|
||||||
|
|
||||||
|
!`echo "=== gh auth ==="; gh auth status 2>&1 | head -3; echo; echo "=== PR (current branch) ==="; gh pr view --json number,url,state,headRefName,baseRefName,headRefOid 2>/dev/null || echo "(no open PR for current branch — or gh not authed)"; echo; echo "=== repo ==="; gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null`
|
||||||
|
|
||||||
|
## Each cycle (one invocation / wake-up)
|
||||||
|
|
||||||
|
1. **Preflight.** If `gh auth status` failed above → **stop** and tell me to run `! gh auth login`,
|
||||||
|
then re-run `/pr-loop`. Do nothing else. Capture `owner`/`repo` from `nameWithOwner`.
|
||||||
|
|
||||||
|
2. **Load state & resolve the PR.** Read `<git-dir>/pr-loop-state.json` (find `<git-dir>` with
|
||||||
|
`git rev-parse --absolute-git-dir`). It's inside `.git/`, so it never shows in `git status` and
|
||||||
|
survives wake-ups. Shape:
|
||||||
|
```json
|
||||||
|
{ "number": 0, "lastHeadOid": "", "lastSeenUpdatedAt": "", "handledThreadIds": [],
|
||||||
|
"handledCommentIds": [], "needsInputThreadIds": [], "needsInputCommentIds": [],
|
||||||
|
"dismissedIds": [], "awaitingPush": false, "idleCount": 0, "cycleCount": 0 }
|
||||||
|
```
|
||||||
|
Resolve the target PR **in this order**: my argument if given (**$ARGUMENTS**) → the `number`
|
||||||
|
in the state file (wake-ups re-invoke `/pr-loop` *without* arguments — the state file is the
|
||||||
|
durable copy) → the current branch's PR from the context block. If none → **stop** and say so.
|
||||||
|
If the state file is missing or for a different `number`, start fresh. Increment `cycleCount`.
|
||||||
|
|
||||||
|
**Then print one status line before any network call** — so I always see the loop is alive:
|
||||||
|
> 🔄 pr-loop cycle <N> — PR #<num>: checking…
|
||||||
|
|
||||||
|
3. **Cheap activity check — one API call, before any heavy fetch.**
|
||||||
|
`gh pr view NUM --json headRefOid,updatedAt`
|
||||||
|
- If `updatedAt == lastSeenUpdatedAt` **and** `headRefOid == lastHeadOid` → nothing happened at
|
||||||
|
all (no comment, review, or push). This is an **idle cycle**: `idleCount += 1`; if a safety
|
||||||
|
cap (step 5) is now exceeded, STOP per step 5. Otherwise save state and jump straight to
|
||||||
|
step 10's reschedule. Total output ≤2 lines — if `awaitingPush`, one line is a brief
|
||||||
|
commit-&-push reminder (remind at most twice across idle cycles, then just the status line).
|
||||||
|
- Otherwise: remember the fetched `headRefOid` for step 6 and continue. (Don't update
|
||||||
|
`lastSeenUpdatedAt` yet — step 10 refreshes it *after* you've posted replies, so your own
|
||||||
|
replies don't defeat the next cycle's cheap check.)
|
||||||
|
|
||||||
|
4. **Fetch review state — filtered at the source, both calls in parallel** (one message, two
|
||||||
|
tool calls). Never fetch unfiltered `reviews,comments`.
|
||||||
|
|
||||||
|
Unresolved review threads (resolved/unresolved is GraphQL-only):
|
||||||
|
```bash
|
||||||
|
gh api graphql --paginate -F owner=OWNER -F repo=REPO -F number=NUM -f query='
|
||||||
|
query($owner:String!,$repo:String!,$number:Int!,$cursor:String){
|
||||||
|
repository(owner:$owner,name:$repo){ pullRequest(number:$number){
|
||||||
|
reviewThreads(first:100,after:$cursor){ pageInfo{hasNextPage endCursor}
|
||||||
|
nodes{ id isResolved isOutdated
|
||||||
|
comments(first:100){ nodes{ id databaseId author{login} path line body } } } } } } }' \
|
||||||
|
--jq '.data.repository.pullRequest.reviewThreads.nodes[]
|
||||||
|
| select(.isResolved | not)
|
||||||
|
| {id, isOutdated,
|
||||||
|
comments: [.comments.nodes[] | {id, databaseId, author: .author.login, path, line, body}]}'
|
||||||
|
```
|
||||||
|
Mind the two id kinds: the thread's own `id` (`PRRT_…`) is what you resolve; a
|
||||||
|
`comments[].id` (`PRRC_…`) is what you react to.
|
||||||
|
|
||||||
|
Automated-reviewer activity + `@claude` requests from the PR conversation — latest review per
|
||||||
|
bot (for the limit check in step 5) and only the relevant comments, not the whole history:
|
||||||
|
```bash
|
||||||
|
gh pr view NUM --json reviews,comments --jq '{
|
||||||
|
latestBotReviews: ([.reviews[] | select(.author.login | test("codex|claude"; "i"))]
|
||||||
|
| group_by(.author.login) | map(max_by(.submittedAt))
|
||||||
|
| map({author: .author.login, state, submittedAt, body})),
|
||||||
|
relevantComments: ([.comments[] | select((.isMinimized | not)
|
||||||
|
and ((.body | test("@claude")) or (.author.login | test("codex|claude"; "i"))))
|
||||||
|
| {id, author: .author.login, body}] | .[-10:])
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
Act on feedback from **any** reviewer — especially the automated ones, **Codex and Claude**
|
||||||
|
(`author.login` matching `codex`/`claude`, or a Bot account). Treat any comment — inline review
|
||||||
|
**or** PR conversation — whose body **mentions `@claude`** as an explicit request to act on,
|
||||||
|
same as a review comment.
|
||||||
|
|
||||||
|
Some bots post **findings as a plain PR-conversation comment** rather than inline review threads
|
||||||
|
(e.g. Claude when its tooling can't post inline). Triage those findings like thread findings;
|
||||||
|
since they have no thread, you "resolve" them by **minimizing** the comment once fixed (step 8).
|
||||||
|
`relevantComments[].id` is the comment's GraphQL node id (`IC_…`) used for that, and the
|
||||||
|
`isMinimized` filter above already drops ones you've resolved. A bot's pure **summary / status /
|
||||||
|
usage-limit** comment carries no finding — triage/minimize only comments with concrete asks.
|
||||||
|
|
||||||
|
5. **Check stop conditions — before doing any work:**
|
||||||
|
- **Nothing left to address** → no unresolved review threads, no un-minimized bot **findings**
|
||||||
|
comments, and no open `@claude` requests. Anything in `dismissedIds` doesn't count as
|
||||||
|
outstanding (if a resolve/minimize failed, the 👎 + reason still stands). The PR is clean:
|
||||||
|
report done, save state, and **do not** schedule another wake-up. STOP.
|
||||||
|
- **The automated reviewers are spent** → an automated reviewer's most recent review/comment
|
||||||
|
body matches a limit signal (case-insensitive: `rate/usage/quota/credit … limit`,
|
||||||
|
`limit reached`, `exceeded … quota`, `out of … credits`). Automated reviewers = authors whose
|
||||||
|
`login` matches `codex` or `claude` (or a `[bot]` that leaves review comments; confirm with
|
||||||
|
`gh api users/<login> --jq .type` → `Bot`). STOP and report which reviewer hit the limit
|
||||||
|
**only** when no unresolved threads (incl. `@claude` requests) remain that you can still act
|
||||||
|
on. If one reviewer is limited but other threads still need work, handle those first, then
|
||||||
|
re-check.
|
||||||
|
- **Safety caps** (these apply on idle cycles too) → if `cycleCount > 20`, or `idleCount > 4`,
|
||||||
|
or `gh api rate_limit --jq .resources.core.remaining` is `< 100` → STOP and hand back to me
|
||||||
|
with a summary.
|
||||||
|
|
||||||
|
**When any stop fires:** save state, do **not** call `ScheduleWakeup`, and end with a clear
|
||||||
|
final line so I know the loop is over and won't run again — e.g.:
|
||||||
|
> ✅ **Finished — no more active issues.** I won't re-check again.
|
||||||
|
|
||||||
|
Adapt it to the reason: `✅ Finished — <reviewer> hit its usage limit; nothing left to address,
|
||||||
|
I won't re-check again.` or `⏹ Stopped — hit safety cap (<which>); re-run \`/pr-loop\` to resume.`
|
||||||
|
|
||||||
|
6. **Did I push since last cycle?** Compare the `headRefOid` from step 3 to `lastHeadOid` (no
|
||||||
|
extra API call).
|
||||||
|
- If **unchanged and `awaitingPush` is true** → I haven't pushed yet. Don't re-fix anything for
|
||||||
|
threads already handled: `idleCount += 1`, then continue with step 7 **only for genuinely new
|
||||||
|
threads/comments** (something new must exist, or step 3 would have short-circuited).
|
||||||
|
- If **changed** → I pushed. Set `awaitingPush=false`, `idleCount=0`, update `lastHeadOid`. Then,
|
||||||
|
**before handling anything new, resolve on GitHub every already-handled item whose fix is now
|
||||||
|
live** — don't leave them lingering as open, 👍-only threads. For each id in `handledThreadIds`
|
||||||
|
that is still unresolved and not re-flagged, run `resolveReviewThread`; for each id in
|
||||||
|
`handledCommentIds` not re-flagged, `minimizeComment` as RESOLVED (mutations in step 8).
|
||||||
|
Resolved threads drop out of the step-4 fetch, so each fix is resolved exactly once. Then
|
||||||
|
continue to any genuinely new threads.
|
||||||
|
|
||||||
|
7. **Triage** each unresolved review thread, every bot **findings** comment on the PR conversation,
|
||||||
|
and every `@claude` request **not already handled**:
|
||||||
|
- **Auto-handle (no input needed):** typos, lint/format, naming, missing null/error checks,
|
||||||
|
applying the reviewer's concrete suggested diff, docs/comments, and localized bugs with one
|
||||||
|
correct fix — **including fixes that touch a shared type/contract or span multiple layers,
|
||||||
|
when the repo's existing conventions determine the shape.** Blast radius (multi-file,
|
||||||
|
contract-touching, "I'd have to pick among a few representations") is **not** a reason to
|
||||||
|
defer: pick the minimal idiomatic shape that matches existing patterns, implement it, and let
|
||||||
|
me veto. A reviewer finding that names the concrete fix is almost always auto-handleable.
|
||||||
|
- **Leave for me (needs input) — 👀:** defer **only** for genuine ambiguity — two or more
|
||||||
|
*materially different* correct behaviours, a real security/performance trade-off, or missing
|
||||||
|
product/domain knowledge that existing code can't settle. Never guess these. Post the
|
||||||
|
`path:line` + a **one-line decision I can answer in a word**, and record the id in
|
||||||
|
`needsInputThreadIds` (or `needsInputCommentIds` for a plain conversation comment) so step 3
|
||||||
|
re-surfaces it every idle cycle instead of letting it fall silent.
|
||||||
|
- **Not an issue (dismiss) — 👎:** a **bot** finding that is simply wrong — it misread the code,
|
||||||
|
the behaviour is intentional and the surrounding code proves it, or the concern is already
|
||||||
|
handled elsewhere. Don't "fix" it to make it go away, and don't park it as needs-input either:
|
||||||
|
that leaves a false positive propping the loop open until a safety cap fires. Reply with the
|
||||||
|
one-line reason (facts, not opinion: the line/behaviour that disproves it), 👎 it, then resolve
|
||||||
|
the thread / minimize the comment **immediately** — no push required, since there's no fix to
|
||||||
|
land. Record the id in `dismissedIds` so a re-fetch can't re-litigate it.
|
||||||
|
**Only bots get dismissed.** A *human* comment you think is wrong is a needs-input item: state
|
||||||
|
your reasoning in a reply, mark it 👀, and let me settle it. If you'd be dismissing more than
|
||||||
|
one or two findings in a cycle, you're probably the one who's wrong — park them for me instead.
|
||||||
|
|
||||||
|
Apply the same split to Codex's and Claude's review suggestions and to every `@claude` request:
|
||||||
|
a concrete ask is auto-handled; a genuine judgement call is left for me. Skip anything whose id
|
||||||
|
is already in `handledThreadIds` / `handledCommentIds` / `dismissedIds`. When I answer a needs-input item (or you
|
||||||
|
push a fix for it), drop its id from the needs-input arrays and handle/resolve it normally.
|
||||||
|
|
||||||
|
8. **Prepare the auto-handled set (no commit, no push):**
|
||||||
|
- Apply the edits (the PostToolUse format hook auto-formats). `git add` the changed files.
|
||||||
|
- **Mark every triaged item with its reaction — never an "Addressed — …" reply.** The reaction
|
||||||
|
goes on the reviewer's comment (for a thread, its *first* comment — the finding itself):
|
||||||
|
👍 what you fixed this cycle, 👀 what you parked for me, 👎 a dismissed bot finding.
|
||||||
|
|
||||||
|
One mutation covers both surfaces. Pass the **comment** node id — `comments[].id` (`PRRC_…`)
|
||||||
|
from the thread query, or `relevantComments[].id` (`IC_…`) for a conversation comment; *not*
|
||||||
|
the thread's own `PRRT_…` id. `content` is `THUMBS_UP` / `EYES` / `THUMBS_DOWN`:
|
||||||
|
```bash
|
||||||
|
gh api graphql -f query='mutation($id:ID!,$c:ReactionContent!){
|
||||||
|
addReaction(input:{subjectId:$id,content:$c}){ reaction{ content } } }' \
|
||||||
|
-F id=COMMENT_NODE_ID -F c=THUMBS_UP
|
||||||
|
```
|
||||||
|
Re-adding the same reaction is a harmless no-op, so a repeat cycle can't double-post. When an
|
||||||
|
item **changes class** — I answer a 👀, or a reviewer re-flags something you'd 👍'd — clear the
|
||||||
|
stale marker first, same call shape, so nothing ever carries two contradictory markers:
|
||||||
|
```bash
|
||||||
|
gh api graphql -f query='mutation($id:ID!,$c:ReactionContent!){
|
||||||
|
removeReaction(input:{subjectId:$id,content:$c}){ reaction{ content } } }' \
|
||||||
|
-F id=COMMENT_NODE_ID -F c=EYES
|
||||||
|
```
|
||||||
|
- Add handled review-thread ids to `handledThreadIds` and handled conversation/`@claude`
|
||||||
|
comment ids to `handledCommentIds`; set `awaitingPush=true`.
|
||||||
|
- **Resolve** a thread — `gh api graphql -f query='mutation($id:ID!){
|
||||||
|
resolveReviewThread(input:{threadId:$id}){ thread{ id isResolved } } }' -F id=THREAD_ID` —
|
||||||
|
**only** once its fix is live (a cycle where `headRefOid` advanced, per step 6) and the
|
||||||
|
reviewer hasn't re-flagged it. Never resolve unpushed work or a "needs input" thread. This
|
||||||
|
resolves the review *conversation*, not any linked GitHub Issue.
|
||||||
|
**The one exception is a 👎 dismissal:** there's no fix to land, so resolve/minimize it in the
|
||||||
|
same cycle you post the reason — otherwise the false positive keeps the loop alive forever.
|
||||||
|
- **Resolve a plain PR-conversation findings comment** (a bot finding with no inline thread —
|
||||||
|
e.g. Claude's) by **minimizing it as resolved** — the issue-comment equivalent, under the same
|
||||||
|
rules (only once its fix is live and not re-flagged):
|
||||||
|
```bash
|
||||||
|
gh api graphql -f query='mutation($id:ID!){ minimizeComment(input:{subjectId:$id,
|
||||||
|
classifier:RESOLVED}){ minimizedComment{ isMinimized } } }' -F id=COMMENT_NODE_ID
|
||||||
|
```
|
||||||
|
`COMMENT_NODE_ID` is the `relevantComments[].id` (`IC_…`). Never minimize unpushed work, a
|
||||||
|
"needs input" comment, or a summary/status/usage-limit comment.
|
||||||
|
|
||||||
|
9. **Draft the commit message — exactly like `/commit-msg`:** from the staged diff and the repo's
|
||||||
|
recent `git log` style (this repo uses `[Scope] summary`), write a message that matches. Then:
|
||||||
|
- **(a) Print it** in your reply as a fenced ` ```text ` block — the durable copy.
|
||||||
|
- **(b) Write it** with the Write tool to the path from `git rev-parse --git-path CLAUDE_COMMIT_MSG`
|
||||||
|
(**not** `COMMIT_EDITMSG` — git overwrites that on `git commit`; the `prepare-commit-msg` hook
|
||||||
|
prefills the editor from `CLAUDE_COMMIT_MSG`).
|
||||||
|
- **(c) Copy it:** `wl-copy < <that path>`.
|
||||||
|
- Tell me all three locations. **Never** run `git commit`.
|
||||||
|
(Skip this step when nothing new was staged this cycle.)
|
||||||
|
|
||||||
|
10. **Ping + schedule.** Give me a tight summary — deltas only, don't restate unchanged threads:
|
||||||
|
- 👍 fixed & staged this cycle: threads (with `path:line`);
|
||||||
|
- 👀 left for you: threads + one-line reason each;
|
||||||
|
- 👎 dismissed as not-an-issue: thread + the one-line why (call these out explicitly — a
|
||||||
|
dismissal is me trusting your judgement, so I should see every one);
|
||||||
|
- resolved on GitHub this cycle (if any);
|
||||||
|
- the commit message (printed above), then "commit & push when ready".
|
||||||
|
|
||||||
|
Refresh `lastSeenUpdatedAt` with one `gh pr view NUM --json updatedAt` call **after** any
|
||||||
|
needs-input questions are posted (reactions don't bump `updatedAt`, comments do — so your own
|
||||||
|
activity doesn't defeat the next cheap check), then save state
|
||||||
|
to `<git-dir>/pr-loop-state.json`. Then schedule:
|
||||||
|
- **normal cycle:** `ScheduleWakeup(delaySeconds=600, prompt="/pr-loop", reason="recheck PR
|
||||||
|
#<num> review comments")`;
|
||||||
|
- **idle cycle** (step 3 short-circuited): back off — `delaySeconds=1200`, I'm clearly away;
|
||||||
|
re-running `/pr-loop` checks immediately.
|
||||||
|
|
||||||
|
End the turn with a sign-off that states when you'll run again and how to stop, e.g.:
|
||||||
|
> ⏳ **Next check in ~10 min** (~20 when idle). To stop, press `Esc` while I'm idle between
|
||||||
|
> cycles (or close the session).
|
||||||
|
|
||||||
|
(When a stop condition in step 5 fired, skip both the wake-up and this sign-off — use the
|
||||||
|
**Finished** line from step 5 instead.)
|
||||||
|
|
||||||
|
## Guardrails
|
||||||
|
|
||||||
|
- **Never** `git commit`, `git push`, `gh pr merge`, `gh pr create`, `gh pr close`, or `gh pr edit`
|
||||||
|
— I do all of those. You stage, react, resolve, and draft; nothing more. The only comment you may
|
||||||
|
post is a needs-input decision question.
|
||||||
|
- Act only on the target PR. Don't touch unrelated files or other PRs.
|
||||||
|
- **Keep context lean:** no raw JSON dumps in replies, no re-listing threads that haven't changed,
|
||||||
|
idle cycles ≤2 lines. Every line you emit is re-read (uncached) on every later cycle.
|
||||||
|
- If anything is unclear or risky, leave it for me rather than guessing.
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
description: Review all changes on the current branch (diff vs its base) for bugs, security issues, optimizations, and readability/scannability, then apply the readability + safe improvements after you approve. Use right before opening a PR.
|
||||||
|
argument-hint: [base-branch]
|
||||||
|
disable-model-invocation: true
|
||||||
|
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git status:*), Bash(git merge-base:*), Bash(git symbolic-ref:*), Bash(git rev-parse:*), Bash(git show-ref:*), Bash(git branch:*), Read, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Review this branch
|
||||||
|
|
||||||
|
Context auto-collected for the current branch vs. its base:
|
||||||
|
|
||||||
|
!`b=$(git symbolic-ref --short -q refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@'); [ -z "$b" ] && { git show-ref -q --verify refs/heads/main && b=main || b=master; }; m=$(git merge-base "$b" HEAD 2>/dev/null); echo "Current branch: $(git rev-parse --abbrev-ref HEAD 2>/dev/null)"; echo "Base branch: $b"; echo "Diff range: ${m:-?}..HEAD"; echo; echo "Commits:"; git --no-pager log --oneline "${m}..HEAD" 2>/dev/null; echo; echo "Files changed:"; git --no-pager diff --stat "${m}...HEAD" 2>/dev/null`
|
||||||
|
|
||||||
|
## What to do
|
||||||
|
|
||||||
|
1. **Resolve the base branch.** If a base branch was passed when invoking (it appears here:
|
||||||
|
**$ARGUMENTS** — empty if none), use that. Otherwise use the base detected above. The changes
|
||||||
|
to review are the diff `git merge-base <base> HEAD`..`HEAD`.
|
||||||
|
2. **Gather context.** Read the full diff for that range (`git diff <merge-base>...HEAD`) and
|
||||||
|
review **only the lines this branch changed** — not pre-existing code. Read surrounding code
|
||||||
|
with the Read tool when you need it to judge a finding. Also read the repo's `CLAUDE.md` (root,
|
||||||
|
and any in the directories the branch touched) and treat its guidance as a review lens.
|
||||||
|
3. **Find issues** across four lenses:
|
||||||
|
- 🐞 **Correctness / bugs** — logic errors, unhandled edge cases, swallowed/ignored errors,
|
||||||
|
race conditions, wrong/loose types, off-by-ones, and anything that violates the repo's
|
||||||
|
`CLAUDE.md`.
|
||||||
|
- 🔒 **Security** — injection (SQL / command / path traversal), missing input validation or
|
||||||
|
output encoding, authn/authz gaps, secrets or credentials committed / logged / echoed,
|
||||||
|
unsafe deserialization, SSRF, weak crypto or randomness, unsafe defaults, and sensitive data
|
||||||
|
leaked in logs or error messages.
|
||||||
|
- ⚡ **Optimizations** — redundant work, needless allocations/copies, N+1 patterns, a simpler
|
||||||
|
or standard-library equivalent.
|
||||||
|
- 📖 **Readability & scannability** — naming, structure, dead code, stale/misleading comments,
|
||||||
|
formatting, over-long functions, unclear control flow.
|
||||||
|
4. **Verify the bugs and security findings before reporting.** Double-check each 🐞 and 🔒
|
||||||
|
finding against the real code and keep only the ones you're confident are real and exploitable
|
||||||
|
/ will bite in practice. **Do not flag:**
|
||||||
|
- issues on lines the branch didn't change (pre-existing);
|
||||||
|
- theoretical vulnerabilities with no reachable exploit path in the changed code, or anything a
|
||||||
|
SAST / dependency scanner would own;
|
||||||
|
- anything a linter / type-checker / compiler / CI catches (imports, type errors, formatting) —
|
||||||
|
assume those run separately;
|
||||||
|
- pedantic nitpicks a senior engineer wouldn't raise, or "needs more tests/docs" unless the
|
||||||
|
repo's `CLAUDE.md` requires it;
|
||||||
|
- changes that are clearly intentional and part of the feature.
|
||||||
|
|
||||||
|
(This filter is for 🐞 bugs and 🔒 security. ⚡ optimizations and 📖 readability are the
|
||||||
|
deliberate polish pass — minor suggestions there are welcome, since the goal is PR-readiness.)
|
||||||
|
5. **Report**, grouped by the four lenses, most-severe-first, each finding one or two lines with
|
||||||
|
a `path:line` reference so it's scannable. If a category is clean, say so in one line. No walls
|
||||||
|
of text.
|
||||||
|
6. **Then stop and ask** whether to apply the fixes. On approval, apply **only** the readability
|
||||||
|
improvements and behavior-preserving optimizations. Anything that changes behavior, public API,
|
||||||
|
or semantics: list it separately and let me decide — do **not** apply it silently. Treat 🔒
|
||||||
|
security fixes the same way: propose them, but never apply them silently. After editing, re-run
|
||||||
|
the repo's formatter/linter if it has one.
|
||||||
|
7. **Point me at the relevant built-in follow-ups.** After reporting, list the Claude Code
|
||||||
|
commands worth running next as separate, deeper passes — tailored to what this review
|
||||||
|
surfaced, not a blanket dump. Only include the ones that actually fit:
|
||||||
|
- `/security-review` — a deeper, whole-branch security pass; suggest whenever the 🔒 lens
|
||||||
|
flagged something or the diff touches auth, crypto, input handling, secrets, or network I/O.
|
||||||
|
- `/code-review` (add `--fix` to apply, `--comment` for inline PR comments) — a second review
|
||||||
|
of the working-tree diff at a chosen effort level.
|
||||||
|
- `/simplify` — apply reuse / simplification / efficiency cleanups beyond the safe ones applied
|
||||||
|
here.
|
||||||
|
- `/verify` — run the app to confirm the change behaves, if this branch changed behavior.
|
||||||
|
- `/pr-description` — draft the PR text from this branch once the review is clean.
|
||||||
|
- `/review` — review the PR on GitHub after it's open.
|
||||||
|
8. **Never** run `git commit` or `git push` — I do that manually.
|
||||||
@@ -0,0 +1,517 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Claude Code status line.
|
||||||
|
|
||||||
|
One line: vim mode | dir (repo-relative, hidden at the root) |
|
||||||
|
git(repo/branch +dirty +ahead/behind) | model (+effort) |
|
||||||
|
context% (+compact warn) | 5h usage (+reset eta) | cost (+burn rate) | disk. If the
|
||||||
|
rendered line would overflow the terminal, trailing (lowest-priority) segments are
|
||||||
|
dropped until it fits.
|
||||||
|
(Dormant, re-addable in main(): ram, cpu%, temp -- retired 2026-07-26 because the
|
||||||
|
status line only refreshes on message events, so system metrics sat visibly stale;
|
||||||
|
tmux's status bar owns those now -- plus velocity, cache hit %, api ratio, version,
|
||||||
|
style.)
|
||||||
|
|
||||||
|
Reads the status JSON from stdin (Claude Code statusLine command). Every segment
|
||||||
|
is wrapped defensively so the status line can never crash the UI -- on any error
|
||||||
|
a segment is simply omitted.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
|
# --- ANSI helpers -----------------------------------------------------------
|
||||||
|
RESET = "\033[0m"
|
||||||
|
DIM = "" # disabled: "\033[2m" blended the gray detail text into dark backgrounds
|
||||||
|
BOLD = "\033[1m"
|
||||||
|
C = {
|
||||||
|
"cyan": "\033[36m",
|
||||||
|
"green": "\033[32m",
|
||||||
|
"yellow": "\033[33m",
|
||||||
|
"red": "\033[31m",
|
||||||
|
"magenta": "\033[35m",
|
||||||
|
"blue": "\033[34m",
|
||||||
|
"gray": "\033[37m", # light gray (was "\033[90m" bright-black, too dark to read)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def color(text, name="", dim=False, bold=False):
|
||||||
|
pre = ""
|
||||||
|
if dim:
|
||||||
|
pre += DIM
|
||||||
|
if bold:
|
||||||
|
pre += BOLD
|
||||||
|
pre += C.get(name, "")
|
||||||
|
return f"{pre}{text}{RESET}" if pre else str(text)
|
||||||
|
|
||||||
|
|
||||||
|
def bucket(value, lo, hi, invert=False):
|
||||||
|
"""green/yellow/red by threshold. invert=True -> high is good."""
|
||||||
|
if invert:
|
||||||
|
return "green" if value >= hi else ("yellow" if value >= lo else "red")
|
||||||
|
return "green" if value < lo else ("yellow" if value < hi else "red")
|
||||||
|
|
||||||
|
|
||||||
|
DIV = color(" │ ", "gray", dim=True)
|
||||||
|
|
||||||
|
|
||||||
|
def join_line(segs):
|
||||||
|
return DIV.join(s for s in segs if s)
|
||||||
|
|
||||||
|
|
||||||
|
_ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
|
||||||
|
|
||||||
|
|
||||||
|
def vlen(text):
|
||||||
|
"""Visible width of a rendered string: ANSI stripped, emoji counted as 2."""
|
||||||
|
text = _ANSI_RE.sub("", text)
|
||||||
|
w = 0
|
||||||
|
for ch in text:
|
||||||
|
if ch in ("\u200d", "\ufe0f", "\ufe0e") or unicodedata.combining(ch):
|
||||||
|
continue # ZWJ / variation selectors / combining marks: zero width
|
||||||
|
o = ord(ch)
|
||||||
|
if o >= 0x1F000 or 0x2600 <= o <= 0x27BF or unicodedata.east_asian_width(ch) in ("W", "F"):
|
||||||
|
w += 2
|
||||||
|
else:
|
||||||
|
w += 1
|
||||||
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def term_cols():
|
||||||
|
"""Terminal width. Claude Code exports COLUMNS; 0 if unknown -> stay one line."""
|
||||||
|
try:
|
||||||
|
return shutil.get_terminal_size(fallback=(0, 0)).columns
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# --- shared transcript usage ------------------------------------------------
|
||||||
|
def last_usage(data):
|
||||||
|
"""Most recent `message.usage` block from the transcript, or {}."""
|
||||||
|
try:
|
||||||
|
path = data.get("transcript_path")
|
||||||
|
if not path or not os.path.exists(path):
|
||||||
|
return {}
|
||||||
|
usage = {}
|
||||||
|
with open(path, "r", errors="ignore") as fh:
|
||||||
|
for line in fh:
|
||||||
|
line = line.strip()
|
||||||
|
if not line or '"usage"' not in line:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
obj = json.loads(line)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
msg = obj.get("message")
|
||||||
|
if isinstance(msg, dict) and isinstance(msg.get("usage"), dict):
|
||||||
|
usage = msg["usage"]
|
||||||
|
return usage
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
# --- row 1: work ------------------------------------------------------------
|
||||||
|
def vim_segment(data):
|
||||||
|
"""Vim editor mode as a compact [I]/[N]/[V] (only present with editorMode: vim).
|
||||||
|
|
||||||
|
Pair with `"hideVimModeIndicator": true` in the statusLine settings block so
|
||||||
|
Claude's own built-in indicator doesn't duplicate this one.
|
||||||
|
"""
|
||||||
|
mode = (data.get("vim") or {}).get("mode")
|
||||||
|
if not mode:
|
||||||
|
return ""
|
||||||
|
m = mode.upper()
|
||||||
|
if m.startswith("INSERT"):
|
||||||
|
return color("[I]", "green", bold=True)
|
||||||
|
if m.startswith("VISUAL"):
|
||||||
|
return color("[V]", "magenta", bold=True)
|
||||||
|
if m.startswith("NORMAL"):
|
||||||
|
return color("[N]", "blue", bold=True)
|
||||||
|
return color(f"[{m[:1]}]", "gray")
|
||||||
|
|
||||||
|
|
||||||
|
def abbrev(path):
|
||||||
|
"""fish-style prompt_pwd: shrink every component but the last to one char,
|
||||||
|
keeping a leading dot (`.config` -> `.c`)."""
|
||||||
|
parts = path.split(os.sep)
|
||||||
|
out = []
|
||||||
|
for i, p in enumerate(parts):
|
||||||
|
if i == len(parts) - 1 or p in ("", "~"):
|
||||||
|
out.append(p)
|
||||||
|
elif p.startswith("."):
|
||||||
|
out.append(p[:2])
|
||||||
|
else:
|
||||||
|
out.append(p[:1])
|
||||||
|
return os.sep.join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def dir_segment(cwd, top=None):
|
||||||
|
"""Path *inside* the repo -- git_segment already names the repo itself, so
|
||||||
|
repeating the full ~-path here was pure duplication. Empty at the repo root;
|
||||||
|
a fish-shortened ~-path when we're not in a repo at all."""
|
||||||
|
try:
|
||||||
|
rel = os.path.relpath(cwd, top) if top else None
|
||||||
|
if rel and not rel.startswith(os.pardir): # `..` -> cwd is outside `top` (symlinked in); use the ~-path
|
||||||
|
if rel == os.curdir:
|
||||||
|
return ""
|
||||||
|
shown = rel if len(rel) <= 28 else abbrev(rel)
|
||||||
|
else:
|
||||||
|
home = os.path.expanduser("~")
|
||||||
|
shown = cwd
|
||||||
|
if cwd == home:
|
||||||
|
shown = "~"
|
||||||
|
elif cwd.startswith(home + os.sep):
|
||||||
|
shown = "~" + cwd[len(home):]
|
||||||
|
shown = abbrev(shown)
|
||||||
|
return "📁 " + color(shown, "cyan")
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def _git(cwd, *args):
|
||||||
|
return subprocess.run(
|
||||||
|
["git", "-C", cwd, *args], capture_output=True, text=True, timeout=1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def git_top(cwd):
|
||||||
|
"""Absolute path of the enclosing work tree, or None."""
|
||||||
|
try:
|
||||||
|
r = _git(cwd, "rev-parse", "--show-toplevel")
|
||||||
|
return r.stdout.strip() or None if r.returncode == 0 else None
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def git_segment(cwd, top):
|
||||||
|
try:
|
||||||
|
if not top:
|
||||||
|
return ""
|
||||||
|
repo = os.path.basename(top) or "repo"
|
||||||
|
branch = _git(cwd, "rev-parse", "--abbrev-ref", "HEAD").stdout.strip() or "?"
|
||||||
|
dirty = bool(_git(cwd, "status", "--porcelain").stdout.strip())
|
||||||
|
|
||||||
|
# ahead/behind vs upstream (omitted when no upstream is configured)
|
||||||
|
ab = ""
|
||||||
|
rl = _git(cwd, "rev-list", "--left-right", "--count", "@{upstream}...HEAD")
|
||||||
|
if rl.returncode == 0 and rl.stdout.strip():
|
||||||
|
try:
|
||||||
|
behind, ahead = (int(x) for x in rl.stdout.split())
|
||||||
|
bits = []
|
||||||
|
if ahead:
|
||||||
|
bits.append(color(f"↑{ahead}", "cyan"))
|
||||||
|
if behind:
|
||||||
|
bits.append(color(f"↓{behind}", "yellow"))
|
||||||
|
if bits:
|
||||||
|
ab = " " + "".join(bits)
|
||||||
|
except Exception:
|
||||||
|
ab = ""
|
||||||
|
|
||||||
|
mark = color("*", "red") if dirty else ""
|
||||||
|
label = color(repo, "magenta", bold=True)
|
||||||
|
br = color(branch, "yellow" if dirty else "green")
|
||||||
|
return f"🌿 {label} {br}{mark}{ab}"
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def model_segment(data):
|
||||||
|
name = (data.get("model") or {}).get("display_name")
|
||||||
|
if not name:
|
||||||
|
return ""
|
||||||
|
name = name.replace(" context)", ")") # "Opus 4.8 (1M context)" -> "Opus 4.8 (1M)"
|
||||||
|
out = "🤖 " + color(name, "blue")
|
||||||
|
level = (data.get("effort") or {}).get("level")
|
||||||
|
if level:
|
||||||
|
out += color(f" · {level}", "gray")
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def context_segment(data, usage):
|
||||||
|
try:
|
||||||
|
if not usage:
|
||||||
|
return ""
|
||||||
|
used = (
|
||||||
|
usage.get("input_tokens", 0)
|
||||||
|
+ usage.get("cache_creation_input_tokens", 0)
|
||||||
|
+ usage.get("cache_read_input_tokens", 0)
|
||||||
|
)
|
||||||
|
model_id = (data.get("model") or {}).get("id", "")
|
||||||
|
window = 1_000_000 if "1m" in model_id.lower() else 200_000
|
||||||
|
pct = used / window * 100 if window else 0
|
||||||
|
col = bucket(pct, 50, 80)
|
||||||
|
out = "📝 " + color(f"{pct:.0f}%", col) + color(f" ({used / 1000:.0f}k)", "gray", dim=True)
|
||||||
|
if pct >= 80:
|
||||||
|
out += color(" ⚠compact", "red", bold=True)
|
||||||
|
return out
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def usage_segment(data):
|
||||||
|
"""5-hour rolling usage window: used % (+ time until it resets)."""
|
||||||
|
try:
|
||||||
|
five = (data.get("rate_limits") or {}).get("five_hour") or {}
|
||||||
|
pct = five.get("used_percentage")
|
||||||
|
if pct is None:
|
||||||
|
return ""
|
||||||
|
out = "📊 " + color(f"{pct:.0f}%", bucket(pct, 50, 80))
|
||||||
|
resets = five.get("resets_at")
|
||||||
|
if resets:
|
||||||
|
secs = int(resets) - int(time.time())
|
||||||
|
if secs > 0:
|
||||||
|
h, m = divmod(secs // 60, 60)
|
||||||
|
out += color(f" {h}h{m:02d}m" if h else f" {m}m", "gray")
|
||||||
|
return out
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def cost_segment(data):
|
||||||
|
try:
|
||||||
|
cost = data.get("cost") or {}
|
||||||
|
usd = cost.get("total_cost_usd")
|
||||||
|
if usd is None:
|
||||||
|
return ""
|
||||||
|
out = "💰 " + color(f"${usd:.2f}", "yellow")
|
||||||
|
dur_ms = cost.get("total_duration_ms") or 0
|
||||||
|
if dur_ms > 30_000: # need a meaningful window before extrapolating
|
||||||
|
per_hr = usd / (dur_ms / 3_600_000)
|
||||||
|
out += color(f" ${per_hr:.2f}/h", "gray", dim=True)
|
||||||
|
return out
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def velocity_segment(data):
|
||||||
|
try:
|
||||||
|
cost = data.get("cost") or {}
|
||||||
|
added = cost.get("total_lines_added", 0)
|
||||||
|
removed = cost.get("total_lines_removed", 0)
|
||||||
|
if not (added or removed):
|
||||||
|
return ""
|
||||||
|
out = "✏️ " + color(f"+{added}", "green") + color("/", "gray", dim=True) + color(f"-{removed}", "red")
|
||||||
|
dur_ms = cost.get("total_duration_ms") or 0
|
||||||
|
if dur_ms > 30_000:
|
||||||
|
per_min = added / (dur_ms / 60_000)
|
||||||
|
out += color(f" {per_min:.0f}/m", "gray", dim=True)
|
||||||
|
return out
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def cache_segment(usage):
|
||||||
|
try:
|
||||||
|
if not usage:
|
||||||
|
return ""
|
||||||
|
read = usage.get("cache_read_input_tokens", 0)
|
||||||
|
total = (
|
||||||
|
usage.get("input_tokens", 0)
|
||||||
|
+ usage.get("cache_creation_input_tokens", 0)
|
||||||
|
+ read
|
||||||
|
)
|
||||||
|
if total <= 0:
|
||||||
|
return ""
|
||||||
|
pct = read / total * 100
|
||||||
|
return "♻️ " + color(f"{pct:.0f}%", bucket(pct, 50, 80, invert=True))
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def api_segment(data):
|
||||||
|
"""Share of wall-clock time spent in API/inference (rough 'busy' ratio)."""
|
||||||
|
try:
|
||||||
|
cost = data.get("cost") or {}
|
||||||
|
wall = cost.get("total_duration_ms") or 0
|
||||||
|
api = cost.get("total_api_duration_ms") or 0
|
||||||
|
if wall <= 0 or api <= 0:
|
||||||
|
return ""
|
||||||
|
pct = min(api / wall * 100, 100)
|
||||||
|
return "⚙️ " + color(f"{pct:.0f}%", "blue")
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
# --- row 2: system ----------------------------------------------------------
|
||||||
|
def ram_segment():
|
||||||
|
try:
|
||||||
|
info = {}
|
||||||
|
with open("/proc/meminfo") as fh:
|
||||||
|
for line in fh:
|
||||||
|
k, _, v = line.partition(":")
|
||||||
|
info[k.strip()] = int(v.split()[0]) # kB
|
||||||
|
total = info.get("MemTotal", 0)
|
||||||
|
avail = info.get("MemAvailable", info.get("MemFree", 0))
|
||||||
|
if total <= 0:
|
||||||
|
return ""
|
||||||
|
used = total - avail
|
||||||
|
pct = used / total * 100
|
||||||
|
g = 1024 * 1024
|
||||||
|
return (
|
||||||
|
"🧠 " + color(f"{pct:.0f}%", bucket(pct, 70, 85))
|
||||||
|
+ color(f" {used / g:.1f}/{total / g:.0f}G", "gray", dim=True)
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def disk_segment(cwd):
|
||||||
|
try:
|
||||||
|
st = os.statvfs(cwd)
|
||||||
|
total = st.f_blocks
|
||||||
|
if total <= 0:
|
||||||
|
return ""
|
||||||
|
used = total - st.f_bfree
|
||||||
|
pct = used / total * 100
|
||||||
|
return "💾 " + color(f"{pct:.0f}%", bucket(pct, 75, 90))
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def _cpu_pct():
|
||||||
|
"""Live CPU% diffed against a cached /proc/stat snapshot (no sleeping)."""
|
||||||
|
try:
|
||||||
|
with open("/proc/stat") as fh:
|
||||||
|
parts = fh.readline().split()
|
||||||
|
if not parts or parts[0] != "cpu":
|
||||||
|
return None
|
||||||
|
vals = [int(x) for x in parts[1:]]
|
||||||
|
idle = vals[3] + (vals[4] if len(vals) > 4 else 0) # idle + iowait
|
||||||
|
total = sum(vals)
|
||||||
|
|
||||||
|
state = os.path.expanduser("~/.claude/cache/statusline.cpu")
|
||||||
|
prev = None
|
||||||
|
try:
|
||||||
|
with open(state) as fh:
|
||||||
|
pt, pi = fh.read().split()
|
||||||
|
prev = (int(pt), int(pi))
|
||||||
|
except Exception:
|
||||||
|
prev = None
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.dirname(state), exist_ok=True)
|
||||||
|
with open(state, "w") as fh:
|
||||||
|
fh.write(f"{total} {idle}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not prev:
|
||||||
|
return None
|
||||||
|
dt = total - prev[0]
|
||||||
|
di = idle - prev[1]
|
||||||
|
if dt <= 0 or di < 0:
|
||||||
|
return None
|
||||||
|
return max(0.0, min(100.0, (1 - di / dt) * 100))
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def cpu_segment():
|
||||||
|
try:
|
||||||
|
load1 = os.getloadavg()[0]
|
||||||
|
cores = os.cpu_count() or 1
|
||||||
|
pct = _cpu_pct()
|
||||||
|
if pct is not None:
|
||||||
|
head = color(f"{pct:.0f}%", bucket(pct, 60, 85))
|
||||||
|
tail = color(f" {load1:.1f} {cores}c", "gray", dim=True)
|
||||||
|
else:
|
||||||
|
head = color(f"{load1:.2f}", bucket(load1 / cores, 0.7, 1.0))
|
||||||
|
tail = color(f" {cores}c", "gray", dim=True)
|
||||||
|
return "🖥️ " + head + tail
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def temp_segment():
|
||||||
|
"""Hottest CPU-ish thermal zone in °C, falling back to the max zone."""
|
||||||
|
try:
|
||||||
|
base = "/sys/class/thermal"
|
||||||
|
if not os.path.isdir(base):
|
||||||
|
return ""
|
||||||
|
prefer = ("x86_pkg_temp", "coretemp", "cpu", "k10temp", "tctl")
|
||||||
|
chosen = None
|
||||||
|
fallback = None
|
||||||
|
for name in os.listdir(base):
|
||||||
|
if not name.startswith("thermal_zone"):
|
||||||
|
continue
|
||||||
|
d = os.path.join(base, name)
|
||||||
|
try:
|
||||||
|
with open(os.path.join(d, "temp")) as fh:
|
||||||
|
milli = int(fh.read().strip())
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
ztype = ""
|
||||||
|
try:
|
||||||
|
with open(os.path.join(d, "type")) as fh:
|
||||||
|
ztype = fh.read().strip().lower()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if fallback is None or milli > fallback:
|
||||||
|
fallback = milli
|
||||||
|
if any(p in ztype for p in prefer) and (chosen is None or milli > chosen):
|
||||||
|
chosen = milli
|
||||||
|
milli = chosen if chosen is not None else fallback
|
||||||
|
if milli is None:
|
||||||
|
return ""
|
||||||
|
c = milli / 1000.0
|
||||||
|
return "🌡️ " + color(f"{c:.0f}°C", bucket(c, 60, 80))
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def version_segment(data):
|
||||||
|
v = data.get("version")
|
||||||
|
return color(f"v{v}", "gray", dim=True) if v else ""
|
||||||
|
|
||||||
|
|
||||||
|
def style_segment(data):
|
||||||
|
name = (data.get("output_style") or {}).get("name")
|
||||||
|
return color(f"🎨{name}", "gray", dim=True) if name else ""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
except Exception:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
cwd = (
|
||||||
|
(data.get("workspace") or {}).get("current_dir")
|
||||||
|
or data.get("cwd")
|
||||||
|
or os.getcwd()
|
||||||
|
)
|
||||||
|
usage = last_usage(data)
|
||||||
|
top = git_top(cwd)
|
||||||
|
|
||||||
|
# One row: work (left) then system (right), joined. If it would overflow the
|
||||||
|
# terminal, trailing (lowest-priority) segments are dropped so it stays one line.
|
||||||
|
# Dormant helpers kept above for easy re-add: ram_segment, cpu_segment,
|
||||||
|
# temp_segment (retired -- they only refresh on message events, so they sat
|
||||||
|
# stale; the tmux status bar owns system metrics now), velocity_segment,
|
||||||
|
# cache_segment, api_segment, version_segment, style_segment.
|
||||||
|
work = [s for s in (
|
||||||
|
vim_segment(data),
|
||||||
|
dir_segment(cwd, top),
|
||||||
|
git_segment(cwd, top),
|
||||||
|
model_segment(data),
|
||||||
|
context_segment(data, usage),
|
||||||
|
usage_segment(data),
|
||||||
|
cost_segment(data),
|
||||||
|
) if s]
|
||||||
|
system = [s for s in (
|
||||||
|
disk_segment(cwd),
|
||||||
|
) if s]
|
||||||
|
|
||||||
|
segs = work + system
|
||||||
|
cols = term_cols()
|
||||||
|
if cols: # trim from the right until it fits one line (cols=0 -> width unknown, keep all)
|
||||||
|
while len(segs) > 1 and vlen(join_line(segs)) > cols:
|
||||||
|
segs.pop()
|
||||||
|
sys.stdout.write(join_line(segs))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |