Compare commits

...

8 Commits

Author SHA1 Message Date
rootiest eb1b780a80 docs(logging): add C5 logging toggle to Minimal Mode in README 2026-06-10 21:49:47 -04:00
rootiest 2ce41d0c55 docs(logging): fix 'four' → 'five' category count in fish-config.md prose 2026-06-10 21:46:14 -04:00
rootiest e30ccbc633 docs(logging): document C5 logging guard in fish-config.md
Add __fish_config_op_logging (C5 — Logging & Capture) to the opinionated
components variable table and update the master-disable example comment
from "four categories" to "five categories".

AGENTS.md and opinionated_catalog.md are git-ignored per project policy;
those files were updated on disk but cannot be tracked in this repo.
2026-06-10 21:43:46 -04:00
rootiest 7e266cb61a feat(logging): gate paru/yay wrapper generation under C5 guard (Tasks 5-6)
Add C5 (Logging & Capture) guard to wrapper generation in both
conf.d/paru-wrapper.fish and conf.d/yay-wrapper.fish. When C5 logging
is disabled, the guard removes any generated wrapper and returns early,
allowing the system to fall back to the bare binary.

Also replaces stale Task #4 comment references with C5 classification.
2026-06-10 21:33:54 -04:00
rootiest be3dd7494e feat(logging): gate scrollback capture in smart_exit under C5 guard 2026-06-10 21:29:52 -04:00
rootiest 0382d6ab9c feat(logging): add C5 --on-variable event handlers for real-time sync 2026-06-10 21:28:13 -04:00
rootiest f17229d0b8 feat(logging): add __fish_config_sync_logging shared C5 state sync 2026-06-10 21:26:40 -04:00
rootiest 621d67e89e chore(logging): add .logging_disabled sentinel to .gitignore 2026-06-10 21:20:54 -04:00
9 changed files with 215 additions and 39 deletions
+5
View File
@@ -62,6 +62,11 @@
opinionated_catalog.md opinionated_catalog.md
docs/superpowers docs/superpowers
# ──────────────────── Runtime State Files ───────────────────
# Sentinel file written/removed at runtime to coordinate logging state
# across the fish config and the Kitty Python watcher. Never committed.
.logging_disabled
# ──────────────── Fisher-Managed Plugin Files ─────────────── # ──────────────── Fisher-Managed Plugin Files ───────────────
# Fisher writes these into the repo directory on install/update. # Fisher writes these into the repo directory on install/update.
# They are owned by Fisher — do not commit them. # They are owned by Fisher — do not commit them.
+3 -2
View File
@@ -166,7 +166,7 @@ end
## Minimal Mode ## Minimal Mode
Everything opinionated in this config — command shadows, startup side-effects, key and environment overrides, and terminal integrations — is active by default but can be switched off with universal variables. Four category toggles and one master switch are available: Everything opinionated in this config — command shadows, startup side-effects, key and environment overrides, terminal integrations, and logging — is active by default but can be switched off with universal variables. Five category toggles and one master switch are available:
| Variable | Disables | | Variable | Disables |
|---|---| |---|---|
@@ -174,7 +174,8 @@ Everything opinionated in this config — command shadows, startup side-effects,
| `__fish_config_op_autoexec` | Startup side-effects: Fisher bootstrap, theme apply, `paru`/`yay` wrapper generation, auto venv activation, WakaTime hook | | `__fish_config_op_autoexec` | Startup side-effects: Fisher bootstrap, theme apply, `paru`/`yay` wrapper generation, auto venv activation, WakaTime hook |
| `__fish_config_op_overrides` | Vi mode, `exit``smart_exit`, `$PAGER`/`$MANPAGER`/`$CDPATH`, bang-bang history expansion, autopair, puffer, Starship prompt, theme colors | | `__fish_config_op_overrides` | Vi mode, `exit``smart_exit`, `$PAGER`/`$MANPAGER`/`$CDPATH`, bang-bang history expansion, autopair, puffer, Starship prompt, theme colors |
| `__fish_config_op_integrations` | Kitty/WezTerm window abbreviations, `done` notifications, `spwin`/`tab`/`split`, `hist`, `logs`, `upgrade`, WakaTime | | `__fish_config_op_integrations` | Kitty/WezTerm window abbreviations, `done` notifications, `spwin`/`tab`/`split`, `hist`, `logs`, `upgrade`, WakaTime |
| `__fish_config_opinionated` | Master switch — all four categories at once | | `__fish_config_op_logging` | Scrollback capture on exit, `paru`/`yay` AUR log wrappers, Kitty watcher capture (sentinel-file coordinated) |
| `__fish_config_opinionated` | Master switch — all five categories at once |
Set any of them to a falsy value (`0`, `false`, `no`, `off`, `n`) to disable; erase the variable to re-enable: Set any of them to a falsy value (`0`, `false`, `no`, `off`, `n`) to disable; erase the variable to re-enable:
+10 -1
View File
@@ -6,9 +6,18 @@
# timestamped log file and prunes old logs, mirroring smart_exit behavior. # timestamped log file and prunes old logs, mirroring smart_exit behavior.
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec). # Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
# Task #4's __fish_config_enable_logging will additionally gate this wrapper. # Wrapper generation is also gated by C5 (Logging & Capture).
__fish_config_op_enabled __fish_config_op_autoexec; or return __fish_config_op_enabled __fish_config_op_autoexec; or return
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
if not __fish_config_op_enabled __fish_config_op_logging
if test -f "$HOME/.local/bin/paru"
and grep -q "# paru-wrapper-version:" "$HOME/.local/bin/paru" 2>/dev/null
rm -f "$HOME/.local/bin/paru"
end
return
end
set -l _paru_real /usr/bin/paru set -l _paru_real /usr/bin/paru
set -l _paru_wrapper "$HOME/.local/bin/paru" set -l _paru_wrapper "$HOME/.local/bin/paru"
set -l _paru_wrapper_version 1 set -l _paru_wrapper_version 1
+10 -1
View File
@@ -6,9 +6,18 @@
# timestamped log file and prunes old logs, mirroring smart_exit behavior. # timestamped log file and prunes old logs, mirroring smart_exit behavior.
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec). # Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
# Task #4's __fish_config_enable_logging will additionally gate this wrapper. # Wrapper generation is also gated by C5 (Logging & Capture).
__fish_config_op_enabled __fish_config_op_autoexec; or return __fish_config_op_enabled __fish_config_op_autoexec; or return
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
if not __fish_config_op_enabled __fish_config_op_logging
if test -f "$HOME/.local/bin/yay"
and grep -q "# yay-wrapper-version:" "$HOME/.local/bin/yay" 2>/dev/null
rm -f "$HOME/.local/bin/yay"
end
return
end
set -l _yay_real /usr/bin/yay set -l _yay_real /usr/bin/yay
set -l _yay_wrapper "$HOME/.local/bin/yay" set -l _yay_wrapper "$HOME/.local/bin/yay"
set -l _yay_wrapper_version 1 set -l _yay_wrapper_version 1
+7 -2
View File
@@ -1382,7 +1382,7 @@ fish_variables.
## Opinionated Components (Minimal Mode) ## Opinionated Components (Minimal Mode)
Every opinionated piece of this config is active by default but can be Every opinionated piece of this config is active by default but can be
switched off through four category opt-out variables, each evaluated via switched off through five category opt-out variables, each evaluated via
__fish_variable_check. Set a variable to any falsy value (0, false, no, __fish_variable_check. Set a variable to any falsy value (0, false, no,
off, n) to disable its category; erase it or set a truthy value (1, true, off, n) to disable its category; erase it or set a truthy value (1, true,
yes, on, y) to re-enable. Unset means enabled. yes, on, y) to re-enable. Unset means enabled.
@@ -1410,13 +1410,18 @@ yes, on, y) to re-enable. Unset means enabled.
WezTerm window abbreviations, done WezTerm window abbreviations, done
notifications, spwin/tab/split, notifications, spwin/tab/split,
hist, logs, upgrade, WakaTime hist, logs, upgrade, WakaTime
__fish_config_op_logging Logging & capture: scrollback
capture on exit, paru/yay AUR log
wrappers, Kitty watcher capture;
sentinel file coordinates
cross-process state
Examples: Examples:
# Disable command shadows only (rm becomes plain rm again): # Disable command shadows only (rm becomes plain rm again):
set -U __fish_config_op_aliases off set -U __fish_config_op_aliases off
# Full minimal mode — disable all four categories at once: # Full minimal mode — disable all five categories at once:
set -U __fish_config_opinionated 0 set -U __fish_config_opinionated 0
# Re-enable everything: # Re-enable everything:
@@ -0,0 +1,21 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# __fish_config_logging_changed
#
# DESCRIPTION
# Event handler that fires in every running shell when
# __fish_config_op_logging is set or erased. Delegates to
# __fish_config_sync_logging to update the Kitty sentinel file and
# paru/yay wrappers immediately without requiring a shell restart.
#
# RETURNS
# 0 Always
#
# EXAMPLE
# set -U __fish_config_op_logging 0 # triggers this automatically
function __fish_config_logging_changed --on-variable __fish_config_op_logging \
--description 'C5 event handler: sync logging state when __fish_config_op_logging changes'
__fish_config_sync_logging
end
@@ -0,0 +1,24 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# __fish_config_opinionated_changed
#
# DESCRIPTION
# Event handler that fires in every running shell when
# __fish_config_opinionated (the master opinionated switch) is set or
# erased. Delegates to __fish_config_sync_logging to keep C5 logging
# state in sync. Logging is the only category with external on-disk
# state (sentinel file, wrapper scripts) that requires real-time
# synchronisation when the master variable changes; C1-C4 guards
# evaluate at call-time and need no event handler.
#
# RETURNS
# 0 Always
#
# EXAMPLE
# set -U __fish_config_opinionated 0 # triggers this automatically
function __fish_config_opinionated_changed --on-variable __fish_config_opinionated \
--description 'C5 event handler: sync logging state when master opinionated switch changes'
__fish_config_sync_logging
end
+99
View File
@@ -0,0 +1,99 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# __fish_config_sync_logging
#
# DESCRIPTION
# Synchronises C5 logging state: creates or removes the Kitty sentinel
# file ($XDG_CONFIG_HOME/fish/.logging_disabled) and generates or removes
# the paru/yay AUR-helper log wrappers based on the combined value of
# __fish_config_opinionated (master) and __fish_config_op_logging (C5).
# Called by --on-variable event handlers whenever either variable changes.
# Safe to call at any time; wrapper removal only affects files bearing
# the generated version-marker comment.
#
# RETURNS
# 0 Always
#
# EXAMPLE
# __fish_config_sync_logging
function __fish_config_sync_logging --description 'Sync C5 logging state: sentinel file and paru/yay wrappers'
set -l config_home $XDG_CONFIG_HOME
if test -z "$config_home"
set config_home "$HOME/.config"
end
set -l sentinel "$config_home/fish/.logging_disabled"
set -l paru_wrapper "$HOME/.local/bin/paru"
set -l yay_wrapper "$HOME/.local/bin/yay"
set -l wrapper_version 1
if __fish_config_op_enabled __fish_config_op_logging
# Logging enabled: remove sentinel and regenerate wrappers if binaries exist
rm -f $sentinel
if test -x /usr/bin/paru
mkdir -p (dirname $paru_wrapper)
printf '%s\n' \
'#!/usr/bin/env bash' \
"# paru-wrapper-version: $wrapper_version" \
'# Auto-generated by conf.d/paru-wrapper.fish — do not edit by hand.' \
'# Tees paru output to a timestamped log file and prunes old ones.' \
'set -o pipefail' \
'' \
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
'mkdir -p "$log_dir"' \
'log_file="$log_dir/paru_$(date +%Y-%m-%d_%H-%M-%S).log"' \
'' \
'/usr/bin/paru "$@" 2>&1 | tee "$log_file"' \
'' \
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
'mapfile -t logs < <(ls -1t "$log_dir"/paru_*.log 2>/dev/null)' \
'excess=$(( ${#logs[@]} - max_files ))' \
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
' rm -f "${logs[$i]}"' \
'done' \
>$paru_wrapper
chmod +x $paru_wrapper
end
if test -x /usr/bin/yay
mkdir -p (dirname $yay_wrapper)
printf '%s\n' \
'#!/usr/bin/env bash' \
"# yay-wrapper-version: $wrapper_version" \
'# Auto-generated by conf.d/yay-wrapper.fish — do not edit by hand.' \
'# Tees yay output to a timestamped log file and prunes old ones.' \
'set -o pipefail' \
'' \
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
'mkdir -p "$log_dir"' \
'log_file="$log_dir/yay_$(date +%Y-%m-%d_%H-%M-%S).log"' \
'' \
'/usr/bin/yay "$@" 2>&1 | tee "$log_file"' \
'' \
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
'mapfile -t logs < <(ls -1t "$log_dir"/yay_*.log 2>/dev/null)' \
'excess=$(( ${#logs[@]} - max_files ))' \
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
' rm -f "${logs[$i]}"' \
'done' \
>$yay_wrapper
chmod +x $yay_wrapper
end
else
# Logging disabled: create sentinel and remove any generated wrappers
mkdir -p (dirname $sentinel)
touch $sentinel
if test -f $paru_wrapper
and grep -q "# paru-wrapper-version:" $paru_wrapper 2>/dev/null
rm -f $paru_wrapper
end
if test -f $yay_wrapper
and grep -q "# yay-wrapper-version:" $yay_wrapper 2>/dev/null
rm -f $yay_wrapper
end
end
end
+36 -33
View File
@@ -48,49 +48,52 @@ function smart_exit --description 'Capture colorized scrollback before exiting,
return 0 return 0
end end
set -l snapshot_dir (set -q SCROLLBACK_HISTORY_DIR; and echo $SCROLLBACK_HISTORY_DIR; or echo "$HOME/.terminal_history") # C5 — Logging & Capture: skip all capture when logging is disabled
set -l max_files (set -q SCROLLBACK_HISTORY_MAX_FILES; and echo $SCROLLBACK_HISTORY_MAX_FILES; or echo 100) if __fish_config_op_enabled __fish_config_op_logging
set -l snapshot_dir (set -q SCROLLBACK_HISTORY_DIR; and echo $SCROLLBACK_HISTORY_DIR; or echo "$HOME/.terminal_history")
set -l max_files (set -q SCROLLBACK_HISTORY_MAX_FILES; and echo $SCROLLBACK_HISTORY_MAX_FILES; or echo 100)
# Handle Scrollback Capture (Skipped if -n/--no-log is used) # Handle Scrollback Capture (Skipped if -n/--no-log is used)
if not set -q _flag_no_log if not set -q _flag_no_log
mkdir -p $snapshot_dir mkdir -p $snapshot_dir
set -l timestamp (date "+%Y-%m-%d_%H-%M-%S") set -l timestamp (date "+%Y-%m-%d_%H-%M-%S")
set -l filename "$snapshot_dir/scrollback_$timestamp.log" set -l filename "$snapshot_dir/scrollback_$timestamp.log"
# Safe child process detection # Safe child process detection
set -l active_tui (ps -o comm= --ppid $fish_pid 2>/dev/null) set -l active_tui (ps -o comm= --ppid $fish_pid 2>/dev/null)
if test -n "$KITTY_WINDOW_ID" if test -n "$KITTY_WINDOW_ID"
# LIVE BUFFER CHECK: Check the active token variable $_ # LIVE BUFFER CHECK: Check the active token variable $_
# If the user typed exit, $_ will match "exit". If flags were passed, # If the user typed exit, $_ will match "exit". If flags were passed,
# we check if it contains the phrase "exit" to match 'exit -n' or 'exit --help'. # we check if it contains the phrase "exit" to match 'exit -n' or 'exit --help'.
if string match -qr exit "$_" if string match -qr exit "$_"
if not string match -qr '^(nvim|vim|vi|nano|emacs|tmux)$' "$active_tui" if not string match -qr '^(nvim|vim|vi|nano|emacs|tmux)$' "$active_tui"
# Capture the log via the shell # Capture the log via the shell
kitty @ get-text --match id:$KITTY_WINDOW_ID --extent all --ansi | sed 's/^\[38;2;[0-9;]*m//g' >$filename 2>/dev/null kitty @ get-text --match id:$KITTY_WINDOW_ID --extent all --ansi | sed 's/^\[38;2;[0-9;]*m//g' >$filename 2>/dev/null
# Broadcast a window variable flag telling Kitty the log is handled # Broadcast a window variable flag telling Kitty the log is handled
kitty @ set-user-vars "logged_by_shell=true" 2>/dev/null kitty @ set-user-vars "logged_by_shell=true" 2>/dev/null
end
end end
end end
end
# 4. Prune junk logs before counting toward the max # 4. Prune junk logs before counting toward the max
_scrollback_prune_junk $snapshot_dir _scrollback_prune_junk $snapshot_dir
# 5. Automatic Pruning Logic # 5. Automatic Pruning Logic
set -l current_logs $snapshot_dir/scrollback_*.log set -l current_logs $snapshot_dir/scrollback_*.log
if test -f "$current_logs[1]" if test -f "$current_logs[1]"
set -l total_files (count $current_logs) set -l total_files (count $current_logs)
if test $total_files -gt $max_files if test $total_files -gt $max_files
set -l num_to_delete (math $total_files - $max_files) set -l num_to_delete (math $total_files - $max_files)
for i in (seq 1 $num_to_delete) for i in (seq 1 $num_to_delete)
rm -f $current_logs[$i] rm -f $current_logs[$i]
end
end end
end end
else
echo -e "$c_warn""➔""$c_reset Exiting discreetly; $c_bold""no history logs saved.""$c_reset"
sleep 0.4
end end
else
echo -e "$c_warn""➔""$c_reset Exiting discreetly; $c_bold""no history logs saved.""$c_reset"
sleep 0.4
end end
# Call the true system exit directly # Call the true system exit directly