Commit Graph
1321 Commits
Author SHA1 Message Date
dissimulo eacdbe6350 tmux: status-*-length must exceed the RAW format string, not the rendered width
tmux applies these limits as #{T;=/N:status-right}, truncating the format
string BEFORE #[...] style directives are stripped. status-right renders 45
columns but is 129 characters of source; status-left renders 12 and is ~118.
Capping either below its raw length severs the string mid-way, which presents
as "the right side of the status bar vanished".

Restores 451 (the long-standing value). An earlier commit today cut it to 60
believing a large value starved the bar -- that reasoning was backwards and
introduced a hard truncation.

Window formats stay plain: the circled numbers are U+2776, absent from
DejaVu Sans Mono, and fontconfig substitutes a CJK double-width face that
breaks monospace cell alignment. Only FreeMono carries them.
2026-08-24 18:35:51 -07:00
dissimulo e782c2565b tmux: mouse back on -- it was never the cause either
Measuring display columns instead of string length shows the status bar uses
74 of 158 available columns with the circled-number formats in place. The
"92 chars" that justified both the format change and turning the mouse off
was counting #[fg=...] style directives, which take no screen width at all.

So nothing here starves anything, and the bar still blanks in every mouse
state. Keeping mouse off bought nothing and cost scrolling.

The blanking is handled by tmux-statusline-keepalive.service instead: a full
refresh-client every 2s across each socket, 0.1% of a core. That is a
mitigation, not a fix -- the cause is still unknown.
2026-08-24 17:54:46 -07:00
dissimulo c7bb97bf52 tmux: circled-number window formats back; mouse stays off
Testing mouse off together with the nested formats -- the combination never
tried -- the status bar holds. So mouse mode is the trigger and the window
formats were innocent; the earlier commit blaming them changed two things
at once and credited the wrong one.

Restores the circled numbers. mouse off stays, since turning it back on
reproduced the fault immediately with plain formats already in place.

Marked tentative: observed steady over a short window, not yet across a
long session.
2026-08-24 17:48:01 -07:00
dissimulo 22f7fd419c tmux: mouse off again -- it is genuinely part of the cause
Turning mouse mode back on brought the vanishing status bar straight back,
with the plain window formats already in place. So both matter: the nested
window formats starve status-right of width, and mouse mode reintroduces
the symptom on its own.

Reverting to the combination that is actually observed to work: mouse off
plus plain window formats. Scrolling inside tmux is Ctrl-b [.

Keeping this honest rather than tidy -- the earlier commit claiming mouse
mode "was never the cause" was wrong, and this reverts it.
2026-08-24 17:46:14 -07:00
dissimulo 6713b033a9 tmux: mouse back on
Mouse mode was turned off while hunting the vanishing status bar. It was
never the cause -- the nested window formats were starving status-right of
width -- so this restores click-to-select, drag-to-resize and wheel scroll.
2026-08-24 17:43:18 -07:00
dissimulo cb4936f336 tmux: plain window formats -- the nested ones ate the status line
The circled-number window formats expand to 92 characters through ten
levels of nested conditionals, one per window index. tmux lays out the left
segment, then the window list, then hands the remainder to the right -- and
that list was wide enough that the right segment got no room, so the host,
IP and clock vanished while the left side stayed put.

Restoring the pretty format after shrinking status-right-length brought the
problem straight back, so the width of the list is the cause rather than
the right segment's declared length.

Plain #I:#W renders to twelve characters and the right side stays.
2026-08-24 17:40:39 -07:00
dissimulo 79c485ea6f tmux: shrink status-right-length from 451 to 60
status-right-length was 451 on a 158-column terminal. tmux lays out the
left segment, then the window list, then gives what is left to the right
segment -- and with the right declared three times wider than the screen
there is no stable allocation. Anything that changes the window list's
rendered width pushes the right segment off entirely, which is why the IP
and clock kept vanishing while the left side stayed put.

The window formats render to 92 characters because of the nested
conditionals that pick a circled number per index, so the list is wide
enough to matter.

This is what the "seizure" was. Not X, not NVIDIA, not picom, not hotplug
events, not the monitors, not mosh, not tmux's version, and not the shell
substitution in status-right -- it reproduced on a bare framebuffer console
with none of those present, and it was intermittent because it depended on
what the window list happened to render at that moment.
2026-08-24 17:40:02 -07:00
dissimulo 3391b4cd2a tmux: turn mouse mode off
Mouse mode routed wheel events into the pane, where Claude Code's
full-screen TUI repaints the whole screen in response. That repaint took
the status bar with it, which is the flicker that has been chased for two
weeks through X, NVIDIA, picom and hotplug settings -- none of which were
involved. It reproduces on a bare framebuffer console with no X running at
all.

Disabling mouse mode keeps those events out of the pane entirely. Scrolling
inside tmux is Ctrl-b [ as usual. Paired with CLAUDE_CODE_DISABLE_MOUSE and
CLAUDE_CODE_DISABLE_VIRTUAL_SCROLL exported in the shell, since the env
block in Claude Code's settings.json does not reach the process.
2026-08-24 17:35:53 -07:00
dissimulo 48814c5d42 tmux-net: trailing space after the ✕ offline glyph for status-bar padding 2026-06-30 16:57:22 -07:00
dissimulo 0eb605a835 tmux statusline: directly-held WAN/LAN IP, offline ✕, native window-status
- tmux-ip: show the first directly-held public/WAN IP on a non-tunnel interface,
  else the LAN/private IP. No external 'what's my IP' lookup and no DigitalOcean
  special-case (a droplet's eth0 public IP is found by the same interface scan);
  RFC1918/link-local/CGNAT classed as not-WAN, so a NAT'd box shows its LAN IP.
- tmux-net: show ✕ when there's no local IP and no VPN tunnel (offline). VPN ⇡
  overlay unchanged.
- .tmux.conf: window-status icon + path now native tmux formats (no per-redraw
  #() forks); tmux-window-icon kept as fallback.
2026-06-30 16:39:52 -07:00
dissimulo c32dbb92ac claude: fullscreen tui 2026-06-30 16:32:46 -07:00
dissimulo 8c3dcacafc claude: dark-daltonized theme 2026-06-30 15:23:32 -07:00
dissimulo c680be4817 lolcat: revert to busyloop (Debian) active; jaseg removed from PATH (too coarse) 2026-06-24 09:40:27 -07:00
dissimulo 13f43c3c5f lolcat: jaseg C build now active at /usr/local/bin (ahead of busyloop) 2026-06-24 09:35:35 -07:00
dissimulo aafdc3a119 lolcat: correct attribution to busyloop Ruby build (Debian pkg upstream) 2026-06-24 09:29:33 -07:00
dissimulo 4053acbbc0 Add zsh/lolcat.zsh rainbow helpers + document in README 2026-06-24 09:12:17 -07:00
dissimulo 2906352220 tmux: lowercase am/pm in statusline clock 2026-06-16 17:12:10 -07:00
dissimulo 1d2a823750 tmux: drop space between time and AM/PM in statusline 2026-06-16 17:11:44 -07:00
dissimulo 8400ddf6a8 tmux: 12-hour clock in statusline (%-I:%M %p) 2026-06-16 17:08:27 -07:00
dissimulo 11bf7ecaa4 zsh: eagerly define diff() to avoid prezto autoload-stub error
Pretzo's modules/utility/functions/diff registers an autoload stub that
emits '(eval):1: diff: function definition file not found' in non-
interactive eval contexts where $fpath doesn't include the utility
module's functions directory. Define diff as a real function up front so
the stub never has to look itself up.
2026-05-17 04:02:13 -07:00
dissimulo 3d6f13b2bc tmux-net: always prefix local IP with home symbol
Show ⌂ before the local IP whether or not a VPN is up. The VPN branch
already prefixes ⌂; the non-VPN branch was emitting the bare IP.
2026-05-17 03:58:11 -07:00
dissimulo e2a1e3b784 tmux status: use short hostname (#h) instead of FQDN (#H) 2026-05-17 03:23:55 -07:00
dissimulo e38a6b3166 tmux status: show VPN IP when tunnel is active
Add tmux-vpn-ip helper (parses ifconfig for utun* on macOS, falls back
to tun/wg/ppp on Linux) and a tmux-net wrapper that conditionally
emits "⌂ <local> / ⇡ <vpn>" when a VPN tunnel is up, or just "<local>"
when it's not. status-right now calls tmux-net.
2026-05-17 03:19:26 -07:00
dissimulo 467b967ced tmux-ip: portable local-IP fallback for macOS
`hostname -I` is GNU-only and errors on BSD/macOS, so when the public-IP
curl couldn't reach api.ipify.org the script printed nothing and the
tmux status bar showed an empty IP. Try `ipconfig getifaddr` for common
interfaces first, fall back to `hostname -I` on Linux, then `ifconfig`
as a last resort. Also guard against empty-but-zero-exit curl output.
2026-05-17 03:12:11 -07:00
dissimulo 474fdd028c Rakefile: handle non-interactive stdin in ask()
STDIN.gets returns nil when stdin is closed/EOF (e.g. after vim/vundle
runs during install), causing `nil.chomp` to abort rake install during
install_term_theme. Return nil from ask() on EOF and have callers bail
out of the iTerm theme prompts gracefully.
2026-05-17 02:14:29 -07:00
dissimulo a45f89b187 .claude/settings.json: prune server-specific entries; consolidate redundant ones
The previous snapshot of settings.json was a verbatim dump from one
Mastodon-server install — it carried allowlist entries that won't
match anywhere else and a lot of narrow rules already subsumed by
broader wildcards.

Removed (server-specific, dead weight on other hosts):
- /home/mastodon/* paths and Mastodon .env.production sed/chmod/chown
- signers.online and auto.signers.online curl/openssl probes
- mastodon-web / mastodon-streaming / mastodon-sidekiq journalctl
- n8n journalctl, windmill journalctl + binary
- /usr/local/bin/fail2ban-ignoreip and the hardcoded IP 76.95.82.63
- nslookup signers.live, nginx site-availables grep with literal paths
- /var/log/nginx/access.log* zcat probes (path-specific)
- StatusReactions / status_quoted grep over Mastodon's frontend tree

Removed (redundant, covered by broader wildcard already in the list):
- All narrow Bash(systemctl <verb>:*) entries — Bash(systemctl:*) covers
- All narrow Bash(git ...) entries — Bash(git:*) covers
- All narrow Bash(curl ...) probes — Bash(curl:*) covers
- Bash(rkhunter --update), Bash(rkhunter --propupd) — Bash(rkhunter:*) covers
- Bash(sysctl -a) — Bash(sysctl:*) covers

Kept: tmux/git/curl/sudo/find/ls/cat plus generic system-admin verbs
(systemctl, sysctl, crontab, iptables, ufw, firewall-cmd, fail2ban-client,
apt/apt-get/dpkg, mount, netstat, openssl, lsmod, last, nginx, redis-cli,
rkhunter, aideinit, getent, sqlite3, dig, ulimit, getenforce, aa-status)
plus Read(//home/**), Read(//opt/**), Read(//etc/nginx/sites-{enabled,available}/**).

Net: 5004 -> 1434 bytes (57 lines), still valid JSON, behavior on a
fresh host is identical for the kept verbs and tighter for the dropped
ones (host-specific allows just won't match anything anyway).

If you re-run install.sh on this host, the slim version replaces the
fat one; the fat one survives in ~/.drunkendotfiles.bak.<ts>/ for
recovery.
2026-05-06 10:10:21 +00:00
dissimulo 1b60a9364d Add portable Claude Code config
Saves ~/.claude/settings.json (user-level prefs + Bash/Read permissions
allowlist) so the same Claude Code config can be replicated on other
hosts via install.sh.

What gets deployed:
- .claude/settings.json — theme, verbose, defaultMode, skipAutoPermissionPrompt
  and the cumulative "approve once" allowlist for common ops (systemctl,
  iptables, journalctl, git, curl, etc.). Server-specific allow entries
  (e.g. /home/mastodon/* paths) are dead weight elsewhere but harmless.
- .claude/.gitignore — explicit deny-list so a future `git add .claude`
  doesn't accidentally pull in credentials, session logs, project
  memories, file-history, telemetry, caches, or settings.local.json.

What is NOT tracked (by design):
- .credentials.json (auth)
- history.jsonl, sessions/, projects/ (chat data, project memories)
- settings.local.json (per-machine overrides — by Claude Code convention)
- file-history/, plans/, paste-cache/, shell-snapshots/, session-env/,
  telemetry/, downloads/, cache/, backups/, mcp-needs-auth-cache.json
- plugins/ (marketplace install paths are absolute and host-specific)

deploy_dir's merge semantics mean: on a host that already has
~/.claude/.credentials.json or ~/.claude/projects/, those stay untouched
because the repo doesn't track them. Only the files we explicitly
include get installed.

Existing settings.json on the target host is moved aside to
~/.drunkendotfiles.bak.<timestamp>/ before being replaced.
2026-05-06 10:06:36 +00:00
dissimulo 5208e9a5bb install.sh: repoint dangling claude symlink to latest installed version
The committed ~/.local/bin/claude symlink targets a specific Claude Code
version path (whatever was current when this snapshot was taken). On any
host that has Claude Code installed at a different version, that symlink
arrives dangling.

Old behavior: just delete the dangling link and rely on the Claude
installer to recreate it. That doesn't help when the host has Claude
installed but at a version other than the one in the snapshot, and we
also support skipping the installer via DRUNKENDOTFILES_SKIP_CLAUDE=1
(used when the binary is already on disk but at a different version).

New behavior: when the deployed symlink is dangling, scan
~/.local/share/claude/versions/ and repoint the symlink to the highest
installed version (semver sort). Only fall back to deleting the link if
no version is installed at all.
2026-05-06 09:45:52 +00:00
dissimulo 6188583ee9 tmux: enable truecolor + focus-events for TUI apps
- Switch default-terminal from screen-256color to tmux-256color
  (better italics/undercurl/SGR support for nvim, Claude Code, etc.)
- Add terminal-features RGB for the common outer terminals so
  truecolor escape sequences pass through cleanly
- Enable focus-events so inner programs can redraw when the pane
  regains focus
2026-05-06 09:37:20 +00:00
dissimulo f27ba2710e Pin git identity to dissimulo / connect+gitea@dustin-williams.com
Identity was previously deferred to ~/.gitconfig.user via the include
at the bottom of this file. Per the dotfiles owner, identity should
travel with the dotfiles regardless of host or local user — every
machine where this repo is deployed commits as dissimulo.

Per-machine bits (safe.directory, etc.) still belong in
~/.gitconfig.user, which the existing [include] at the bottom picks
up after this block.
2026-05-06 02:26:08 -07:00
dissimulo c0e4a88d70 Add ~/.local/bin to PATH from prezto-override zshrc
The Claude Code installer drops the binary at ~/.local/bin/claude.
Without this PATH entry, freshly-installed Claude Code is invisible to
new shells until the user adds it manually. Other ~/.local/bin scripts
in this dotfiles repo (tmux-ip, tmux-window-icon, twitterbot, etc.)
benefit from the same.
2026-05-06 02:24:33 -07:00
dissimulo 700da3aa0b Make tmux/tmux.conf a relative symlink to ../.tmux.conf
YADR's Rakefile maps tmux/tmux.conf -> $HOME/.tmux.conf, but the
canonical, customized tmux config has lived at the repo root since
3d2508a (when the relationship was inverted). Re-running rake install
on its own (without the bash installer's subsequent personal-deploy
overlay) was therefore replacing the deployed real .tmux.conf with a
symlink to the older 3987-byte tmux/tmux.conf, dropping the IP/host
status-right and the bumped history limit.

Pointing tmux/tmux.conf at ../.tmux.conf via a relative symlink fixes
this on any machine, regardless of where ~/.yadr lives or which user
owns it: rake install's symlink chain now resolves to the customized
config no matter the install order.
2026-05-06 02:24:32 -07:00
dissimuloandClaude Opus 4.7 fb80b6dfb2 gitconfig: use absolute include path for .gitconfig.user
The previous `[include] path = .gitconfig.user` was resolved relative to
the config file being read, which — because `~/.gitconfig` is a symlink
to `~/.yadr/git/gitconfig` — meant git looked for the user-identity
override at `~/.yadr/git/.gitconfig.user` instead of the conventional
`~/.gitconfig.user`. Switch to an absolute path so the include picks up
the homedir file regardless of symlink layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 07:41:12 -07:00
dissimuloandClaude Opus 4.7 1d7df94a1d install.sh: merge PERSONAL_DIRS contents instead of wholesale replace
The previous deploy_one() did `mv $HOME/<dir> $BACKUP_DIR/<dir>` then
`cp -a $YADR_DIR/<dir> $HOME/<dir>` for every entry in PERSONAL_DIRS.
For dirs the repo only partially populates (notably .local — repo only
tracks .local/bin/), this swept away unrelated user data: the most
recent re-bootstrap moved ~/.local/share/fonts/ (Intel One Mono, Open
Gorton, Roboto Mono, GALLAUDET, code128) into the timestamped backup,
making them appear missing.

Rework deploy logic:
- deploy_file: copies one file/symlink, backing up only the conflicting
  destination (if any). Idempotent via paths_equivalent() so re-runs
  with no changes produce no output and no spurious backups.
- deploy_dir: walks the repo's tree for that dir and deploys each leaf
  via deploy_file. Files in $HOME the repo doesn't know about are left
  untouched. Subdirs are mkdir'd as needed.

Also: track the personal fonts at .local/share/fonts/ so they redeploy
on every install, and run fc-cache -f at the end so apps see them
without a logout/login.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 07:28:40 -07:00
dissimulo 065686f341 spam-ascii: "*" dumps entire ~/ascii; alias quotes $0 to preserve it
Close stale issues / stale (push) Has been cancelled
2026-04-22 07:00:52 -07:00
dissimulo 079bee5774 spam-ascii: pass -L to find so it dereferences ~/ascii when symlinked
Close stale issues / stale (push) Has been cancelled
~/ascii is a symlink to ~/.yadr/ascii. Without -L, 'find <symlink>'
treats the link itself as the starting point, -type f rules it out,
and fuzzy matches return nothing.
2026-04-21 10:01:08 -07:00
dissimulo 4813512731 spam-ascii: fuzzy-match helper for /spam alias
New .local/bin/spam-ascii POSIX shell script: resolves a pattern to
a file in ~/ascii with this order:

  1. exact filename match
  2. exact name + common ASCII-art extension (.txt/.ans/.asc)
  3. first case-insensitive substring match (sorted alphabetically)

Non-zero exit + stderr-ish error if nothing matches, so /spam
prints 'no match in ~/ascii for: <pattern>' instead of spewing
a missing-file error.

Rewire the irssi /spam alias to call the script instead of
hardcoding 'cat ~/ascii/$0'. Now:

  /spam mario     -> matches ~/ascii/mario.txt or ~/ascii/Mario_art.ans
  /spam MARIO     -> case-insensitive
  /spam nothere   -> 'no match in ~/ascii for: nothere'
2026-04-21 09:48:40 -07:00
dissimulo 7b47e38f53 Add ascii art collection 2026-04-21 09:41:46 -07:00
dissimulo a6c2b5de40 irssi/config: add /spam alias — cat file from ~/ascii to channel
/spam <name> runs 'cat ~/ascii/<name>' via EXEC -out, which sends
each line of output as a message to the current channel/query. Good
for posting ASCII art.

Usage: /spam <filename>  (file lives at ~/ascii/<filename>)
2026-04-21 09:32:48 -07:00
dissimulo 4ca7f9714d rainbow-dark: drop rainbow dashes, add rainbow-timestamp.pl
- rainbow-dark.theme: revert line_start back to the stock '-!-' pattern.
- .irssi/scripts/autorun/rainbow-timestamp.pl: new autorun script that
  hooks 'print text', matches a leading HH:MM[:SS], and reruns it
  through rainbow.pl's make_colors (same palette [4,8,9,11,12,13],
  same 2-char stride, same phase-advance on each line). The result
  is that every successive timestamp is a 5-character rainbow
  gradient that also shifts starting colour line-to-line.
2026-04-21 09:27:03 -07:00
dissimulo 2dbc05bc0b irssi/config: revert active theme to rainbow-dark 2026-04-21 09:21:24 -07:00
dissimulo dcde950329 Add claude.theme (ports Claude Code's default dark palette)
claude.theme: a dark irssi theme whose colours map 1:1 to the roles
Claude Code uses in its default dark UI:

  #8c8c8c  dim        timestamps, brackets, connective text
  #f85149  red        errors, netsplits, parts, private msg frames
  #56d364  green      joins, ctcp, dcc, netjoins, quiet activity
  #e3b341  yellow     messages-to-me, /me, statusbar chatter
  #4a9eff  blue       channel names, pubnicks, diff-style accents
  #c9a3ff  magenta    own nick / prompt / notices / hilights
  #4ec9b0  cyan       whois field names, info lines

Uses 24-bit true-colour escapes (%z<rrggbb>) so the shades land
exactly regardless of terminal palette. Requires irssi 1.2+ and a
truecolour-capable terminal (modern xterm/tmux both are).

irssi/config: switch the active theme from rainbow-dark to claude.
2026-04-21 09:15:42 -07:00
dissimulo 92b9e0ec99 irssi: dynamic-nick.pl — set default nick to `|<hostname> at startup
Autorun script so the same drunkendotfiles deploy gives each host a
distinctive nick without per-host config hand-edits. Trims FQDNs to
the short hostname before composing. Static 'nick = "`"' in
config stays as a fallback if the script ever fails to load.
2026-04-21 09:07:09 -07:00
dissimulo 6f86285f71 irssi/config: set nick to backtick 2026-04-21 09:05:54 -07:00
dissimulo eac005ad3c irssi/config: activate rainbow-dark as the default theme 2026-04-21 09:05:18 -07:00
dissimulo c5ccf351de rainbow-dark: line_start uses ROYGBIV (7 colours)
R-Y-G-C-B-M was only six. Full spectrum now: red, orange (%y dark
yellow, renders brown-orange on most terminals), yellow, green,
blue, indigo (%b dark blue as the closest ANSI indigo), violet
(%M bright magenta). Stays ANSI-only so it renders reliably
regardless of 24-bit truecolor support.
2026-04-21 09:01:20 -07:00
dissimulo 1d4d454434 rainbow-dark: reset to default.theme + minimal rainbow
Scrap the over-engineered version. Start from irssi's default theme
(already dark-safe) and apply rainbow only where it actually earns
its keep:

- line_start: the leading '-!-' on non-message lines gets a full
  R-Y-G-C-B-M dash sequence instead of blue-blue.
- sb_act_msg: drop the %W (white) on statusbar activity — on a dark
  terminal this was the one stark-white glyph. Re-colour the whole
  activity band as a rainbow escalation: %G (quiet) -> %Y (chatter)
  -> %R (hilight), so urgency tracks the colour.
- sb_act_sep: comma separator drops to %K (dark grey) so the rainbow
  entries stand apart.

Everything else stays untouched from default.theme. No invented
24-bit escapes, no format overrides.
2026-04-21 08:59:13 -07:00
dissimulo 99049754f9 rainbow-dark: swap teal accent for diff-style blue (#4a90e2)
Teal wasn't landing; try diff-header blue instead. Same %z<rgb>
24-bit foreground mechanism, just a different colour value.
2026-04-21 08:54:54 -07:00
dissimulo 415ee5028c rainbow-dark: %z not %Z (lowercase is fg, uppercase is bg)
Previous commit used %Z005f5f, which irssi 1.4 interprets as a
24-bit *background* colour. That rendered as 'teal background
behind each affected character' — easy to miss on short glyphs,
invisible on whitespace. Foreground is %z (lowercase).
2026-04-21 08:52:06 -07:00
dissimulo 92c4f0bdc1 rainbow-dark: use 24-bit true-colour #005f5f for the teal accent
Earlier pass tried %X17 (256-palette idx 23), but %X isn't the
256-colour code in modern irssi — 1.4+ treats %X as a no-op for
unknown sequences, so every intended teal element was silently
falling through to the terminal default (= bright white).

irssi 1.4.5 supports %Z<rrggbb> for 24-bit foreground colour, so
use it directly: %Z005f5f renders as exactly #005f5f (dark teal),
no palette guessing.
2026-04-21 08:50:08 -07:00