[Sync] adopt unified stow layout from the private repo
Mirrors the private dots tree at 900bdda: one shared base plus per-host overlays, replacing the old flat .config/ layout (last synced 2026-06-28). - packages: common/ gui/ wm/ lw/ fl/ + install.sh and bin/ tooling (dotsync, reconcile-hyde.sh) - new README (layout, deploy order, HyDE dependency), plus ToDo.md and HYDE-UPDATE.md - current HyDE waybar rig (layouts/, cava), pi agent extensions, claude/ config, tmux, presenterm, aichat roles - drops stale duplicates and generated cruft that should never have been tracked: the second top-level .pi/ copy, btop.log, zellij config.kdl.bak, fish_variables, nvim codecompanion.lua - .pi/agent/auth.json is gitignored now; auth.json.example ships instead - fl/ and wm/ hypr themes/ stay untracked (HyDE-generated per machine, per the root .gitignore)
This commit is contained in:
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# CPU utilisation (%) averaged over the interval since the PREVIOUS status refresh:
|
||||
# /proc/stat totals persist in a state file between runs (same pattern as net.sh),
|
||||
# so the value covers the whole status-interval. (The old version slept 0.3s and
|
||||
# sampled just that window — a 6% duty cycle that aliased bursty loads.) No sleep,
|
||||
# ~5ms. First run (no state yet) shows the since-boot average. Glyph = Waybar's
|
||||
# cpu module icon (U+F035B).
|
||||
printf '\U000f035b '
|
||||
rt="${XDG_RUNTIME_DIR:-/tmp}"
|
||||
st="$rt/tmux_cpu_stat" # previous totals: tot idle
|
||||
|
||||
read -r _ u n s i w rest < /proc/stat
|
||||
idle=$((i + w)); tot=$((u + n + s + i + w)); for v in $rest; do tot=$((tot + v)); done
|
||||
|
||||
p_tot=0; p_idle=0
|
||||
[ -r "$st" ] && read -r p_tot p_idle < "$st"
|
||||
[ "$p_tot" -gt "$tot" ] && { p_tot=0; p_idle=0; } # stale state from a previous boot
|
||||
printf '%s %s\n' "$tot" "$idle" > "$st"
|
||||
|
||||
dt=$((tot - p_tot)); di=$((idle - p_idle))
|
||||
if [ "$dt" -le 0 ]; then printf -- '--%%'; else printf '%d%%' $(((100 * (dt - di) + dt / 2) / dt)); fi
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# RAM utilisation (%) — used = MemTotal - MemAvailable, from /proc/meminfo.
|
||||
# Called from tmux status-right via #(); cached per status-interval.
|
||||
printf '\U000f0f86 ' # Waybar's memory glyph (U+F0F86), then the percentage
|
||||
awk '/^MemTotal:/{t=$2} /^MemAvailable:/{a=$2} END{if(t>0)printf "%d%%",(t-a)*100/t; else printf "--%%"}' /proc/meminfo
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# Network throughput from /proc/net/dev (sum of all non-lo interfaces), averaged
|
||||
# over the interval between status refreshes — no blocking sleep.
|
||||
#
|
||||
# Usage: net.sh dl -> " 1.2M" (download icon U+F019 + rate)
|
||||
# net.sh ul -> " 45K" (upload icon U+F093 + rate)
|
||||
#
|
||||
# tmux calls both from status-right. A short (<3s) cache lets the two calls of a
|
||||
# single refresh share one computation, so the up/down figures are consistent and
|
||||
# only one of them re-samples the counters per refresh.
|
||||
which=${1:-dl}
|
||||
rt="${XDG_RUNTIME_DIR:-/tmp}"
|
||||
ctr="$rt/tmux_net_ctr" # previous counters: rx tx epoch.ns
|
||||
cache="$rt/tmux_net_cache" # computed rates: dl_rate ul_rate epoch_s
|
||||
|
||||
emit() { # emit <icon-printf-escape> <rate>
|
||||
printf "$1 %s" "$2"
|
||||
}
|
||||
|
||||
# Reuse a fresh cache so dl and ul agree and we only sample once per refresh.
|
||||
fresh_emit() { # print from the cache and exit — if the cache is fresh enough
|
||||
[ -r "$cache" ] || return 1
|
||||
read -r cdl cul cts < "$cache"
|
||||
{ [ -n "$cts" ] && [ "$(( $(date +%s) - cts ))" -lt 3 ]; } || return 1
|
||||
if [ "$which" = ul ]; then emit '\U0000f093' "$cul"; else emit '\U0000f019' "$cdl"; fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
fresh_emit
|
||||
|
||||
# tmux launches the dl and ul jobs CONCURRENTLY each refresh, so without a lock
|
||||
# both miss the stale cache and compute independently — worst case the loser reads
|
||||
# the counters milliseconds after the winner rewrote them and shows a ~0 rate.
|
||||
# Serialize: the loser waits ~30ms on the lock, then hits the winner's fresh cache.
|
||||
exec 9>"$rt/tmux_net_lock"
|
||||
flock 9
|
||||
fresh_emit
|
||||
|
||||
now=$(date +%s.%N)
|
||||
read -r rx tx < <(awk 'NR>2{gsub(/:/," "); if($1!="lo"){r+=$2; t+=$10}} END{print r+0, t+0}' /proc/net/dev)
|
||||
|
||||
drx=0; dtx=0; dt=1
|
||||
if [ -r "$ctr" ]; then
|
||||
read -r prx ptx pnow < "$ctr"
|
||||
dt=$(awk -v a="$now" -v b="$pnow" 'BEGIN{d=a-b; print (d>0.05)?d:1}')
|
||||
drx=$(( rx - prx )); dtx=$(( tx - ptx ))
|
||||
[ "$drx" -lt 0 ] && drx=0
|
||||
[ "$dtx" -lt 0 ] && dtx=0
|
||||
fi
|
||||
printf '%s %s %s\n' "$rx" "$tx" "$now" > "$ctr"
|
||||
|
||||
human() { awk -v b="$1" 'BEGIN{ split("B K M G T", u, " "); i=1;
|
||||
while (b >= 1024 && i < 5) { b /= 1024; i++ }
|
||||
if (i == 1) printf "%d%s", b, u[i]; else printf "%.1f%s", b, u[i] }'; }
|
||||
|
||||
dl=$(human "$(awk -v x="$drx" -v d="$dt" 'BEGIN{printf "%d", x/d}')")
|
||||
ul=$(human "$(awk -v x="$dtx" -v d="$dt" 'BEGIN{printf "%d", x/d}')")
|
||||
printf '%s %s %s\n' "$dl" "$ul" "$(date +%s)" > "$cache"
|
||||
|
||||
if [ "$which" = ul ]; then emit '\U0000f093' "$ul"; else emit '\U0000f019' "$dl"; fi
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# CPU temperature (°C) for the tmux status bar (thermometer glyph U+F050F).
|
||||
# Sensor hunt, most→least specific: a CPU-ish thermal zone (x86_pkg_temp/…),
|
||||
# else a CPU hwmon chip (coretemp/k10temp/…), else the hottest remaining zone
|
||||
# (acpitz can be a bogus constant on desktops, hence last). Prints NOTHING when
|
||||
# no sensor exists (VMs/containers) so the segment simply disappears — which is
|
||||
# also why the trailing spacing lives in here, not in status-right.
|
||||
cpu_zone=""; any_zone=""; hw=""
|
||||
|
||||
for d in /sys/class/thermal/thermal_zone*/; do
|
||||
[ -r "${d}temp" ] && [ -r "${d}type" ] || continue
|
||||
t=$(<"${d}temp")
|
||||
case $t in ''|*[!0-9]*) continue ;; esac
|
||||
ty=$(<"${d}type"); ty=${ty,,}
|
||||
case $ty in *x86_pkg_temp*|*coretemp*|*k10temp*|*tctl*|*cpu*)
|
||||
if [ -z "$cpu_zone" ] || [ "$t" -gt "$cpu_zone" ]; then cpu_zone=$t; fi ;;
|
||||
esac
|
||||
if [ -z "$any_zone" ] || [ "$t" -gt "$any_zone" ]; then any_zone=$t; fi
|
||||
done
|
||||
|
||||
if [ -z "$cpu_zone" ]; then
|
||||
for d in /sys/class/hwmon/hwmon*/; do
|
||||
[ -r "${d}name" ] || continue
|
||||
case $(<"${d}name") in coretemp|k10temp|zenpower|cpu_thermal)
|
||||
for f in "${d}"temp*_input; do
|
||||
[ -r "$f" ] || continue
|
||||
t=$(<"$f")
|
||||
case $t in ''|*[!0-9]*) continue ;; esac
|
||||
if [ -z "$hw" ] || [ "$t" -gt "$hw" ]; then hw=$t; fi
|
||||
done ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
t=${cpu_zone:-${hw:-$any_zone}}
|
||||
[ -n "$t" ] || exit 0
|
||||
printf '\U000f050f %d° ' $(( (t + 500) / 1000 ))
|
||||
@@ -0,0 +1,78 @@
|
||||
# Forward modified keys (Shift/Ctrl/Alt+Enter) to apps like pi-coding-agent.
|
||||
# Without this, tmux collapses them to a plain Enter. Requires tmux 3.5+ for csi-u.
|
||||
set -g extended-keys on
|
||||
set -g extended-keys-format csi-u
|
||||
|
||||
# Number windows (and panes) from 1 instead of 0 — easier to reach on the
|
||||
# keyboard. renumber-windows keeps them gap-free when a window is closed.
|
||||
set -g base-index 1
|
||||
setw -g pane-base-index 1
|
||||
set -g renumber-windows on
|
||||
|
||||
# --- Session persistence (survives reboot) ---------------------------------
|
||||
# resurrect: save/restore sessions, windows, panes, layout and working dirs
|
||||
# (prefix + Ctrl-s to save, prefix + Ctrl-r to restore).
|
||||
# continuum: auto-saves every 15 min and auto-restores when the tmux server
|
||||
# starts, so sessions come back after a reboot. Both via tpm.
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
set -g @plugin 'tmux-plugins/tmux-resurrect'
|
||||
set -g @plugin 'tmux-plugins/tmux-continuum'
|
||||
|
||||
# Also capture pane scrollback and restore running programs (nvim, …).
|
||||
# nvim 'session' strategy restores via Session.vim when present, else plain nvim.
|
||||
set -g @resurrect-capture-pane-contents 'on'
|
||||
set -g @resurrect-strategy-nvim 'session'
|
||||
|
||||
# Auto-restore the last saved environment on tmux server start.
|
||||
set -g @continuum-restore 'on'
|
||||
|
||||
# Auto-start a detached tmux server at login: continuum writes and enables a
|
||||
# systemd --user unit (~/.config/systemd/user/tmux.service). With the restore
|
||||
# option above, sessions are already back and waiting after a reboot+login.
|
||||
set -g @continuum-boot 'on'
|
||||
|
||||
# --- Status bar (Catppuccin Mocha, flat) -----------------------------------
|
||||
# Palette: bg #1e1e2e · surface #313244 · divider #45475a · muted #6c7086/#7f849c
|
||||
# text #cdd6f4 · subtext #a6adc8 · accent(mauve) #cba6f7
|
||||
set -g status on
|
||||
set -g status-position bottom # (also tmux's default)
|
||||
set -g status-interval 5 # refresh clock + CPU every 5s
|
||||
set -g status-justify left
|
||||
set -g status-style "bg=default,fg=#cdd6f4" # transparent: no bar background
|
||||
set -g status-left-length 40
|
||||
set -g status-right-length 100
|
||||
|
||||
# Left: session name (mauve/bold) + thin divider.
|
||||
set -g status-left " #[fg=#cba6f7,bold]#S #[fg=#45475a]│ "
|
||||
|
||||
# Middle: flat window list — inactive muted, active mauve/bold, 2-space gaps.
|
||||
set -g window-status-separator " "
|
||||
setw -g window-status-format "#[fg=#7f849c]#I #[fg=#6c7086]#W"
|
||||
setw -g window-status-current-format "#[fg=#cba6f7,bold]#I #[fg=#cdd6f4,bold]#W"
|
||||
setw -g window-status-activity-style "fg=#f9e2af"
|
||||
|
||||
# Right: net dl/ul · cpu · mem │ date │ clock. continuum prepends its invisible
|
||||
# save hook here (this block sits above the tpm `run` line, so the hook survives
|
||||
# every reload). Metrics are scripts/*.sh, symlinked into ~/.config/tmux/scripts/.
|
||||
set -g status-right "#[fg=#a6e3a1]#(~/.config/tmux/scripts/net.sh dl) #[fg=#f9e2af]#(~/.config/tmux/scripts/net.sh ul) #[fg=#89b4fa]#(~/.config/tmux/scripts/cpu.sh) #[fg=#94e2d5]#(~/.config/tmux/scripts/mem.sh) #[fg=#fab387]#(~/.config/tmux/scripts/temp.sh)#[fg=#45475a]│ #[fg=#a6adc8]%a %b %-d #[fg=#45475a]│ #[fg=#cba6f7,bold]%H:%M "
|
||||
|
||||
# Two rows: [0] drawn top-border rule · [1] the bar content. The rule doubles as
|
||||
# the separator from the pane content above; tmux status height is whole rows, so
|
||||
# one row above the content is the smallest gap that still shows a border.
|
||||
# Full-width run of ─ (yes|head|paste avoids %, backslashes and nested parens so
|
||||
# tmux's strftime/quote/#() parsing leave it alone); tmux truncates it to width.
|
||||
# status-format[1] is tmux 3.7's default content template (status-left/windows/right).
|
||||
set -g status 2
|
||||
set -g status-format[0] "#[fg=#6c7086,bg=default]#(yes ─ | head -n 400 | paste -sd '')"
|
||||
set -g status-format[1] "#[align=left range=left #{E:status-left-style}]#[push-default]#{T;=/#{status-left-length}:status-left}#[pop-default]#[norange default]#[list=on align=#{status-justify}]#[list=left-marker]<#[list=right-marker]>#[list=on]#{W:#[range=window|#{window_index} #{E:window-status-style}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-format}#[pop-default]#[norange default]#{?loop_last_flag,,#{E:window-status-separator}},#[range=window|#{window_index} list=focus #{?#{!=:#{E:window-status-current-style},default},#{E:window-status-current-style},#{E:window-status-style}}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-current-format}#[pop-default]#[norange list=on default]#{?loop_last_flag,,#{E:window-status-separator}}}#[nolist align=right range=right #{E:status-right-style}]#[push-default]#{T;=/#{status-right-length}:status-right}#[pop-default]#[norange default]"
|
||||
|
||||
# Round out the theme so no default green leaks into borders/messages/modes.
|
||||
set -g pane-border-style "fg=#313244"
|
||||
set -g pane-active-border-style "fg=#cba6f7"
|
||||
set -g message-style "bg=#313244,fg=#cdd6f4"
|
||||
set -g message-command-style "bg=#313244,fg=#cdd6f4"
|
||||
set -g mode-style "bg=#45475a,fg=#cdd6f4"
|
||||
set -g clock-mode-colour "#cba6f7"
|
||||
|
||||
# Initialize tpm — KEEP THIS LINE AT THE VERY BOTTOM of tmux.conf.
|
||||
run '~/.config/tmux/plugins/tpm/tpm'
|
||||
Reference in New Issue
Block a user