Releases: dotgibson/dotfiles-core
Releases · dotgibson/dotfiles-core
Release list
v3.9.0
Added
- Neovim: shared
utils/palette.lua— a single source of truth for the active tokyonight
palette. The"storm"style string and therequire("tokyonight.colors").setup{}pcall dance
were duplicated across lualine, bufferline, and the cheatsheet; they now all resolve through this
one module (change the style once). It also exposes a NvChad-base_30semantic map (black2,
statusline_bg,nord_blue,dark_purple, …) so the block/pill styling is written in NvChad's
own vocabulary while still tracking the theme. - Neovim: scroll-percentage indicator in the lualine statusline (right bubble, next to the
cursor location) so you can see how far through a file you are. - Neovim: NvChad-style inline LSP renamer (
utils/renamer.lua) —<leader>rnnow opens a
small cursor-anchored, git-red-bordered prompt prefilled with the symbol (<CR>applies across
the workspace,<Esc>/qcancels) instead of the bare cmdline prompt. - Neovim: colorify-style colour highlighter (
nvim-colorizer.lua, catgoose fork) — inline
colour swatches over the visible viewport: CSS colour literals (#rrggbb,rgb()/hsl()) plus
Tailwind utility-class colours via the Tailwind LSP. ccc.nvim is kept for the interactive
:CccPickpicker (its always-on highlighter is now off).
Changed
- Neovim: statusline & tabline go hybrid-NvChad. The bufferline adopts NvChad's tabufline model
where buffer state is conveyed by BACKGROUND on a solid opaque bar — the active buffer lifts to a
lighter raised block, inactive buffers recede to the bar colour — while the editor stays
transparent. The blink.cmp menu gains NvChad's colored kind-icon column (viaBlinkCmpKind*
highlights) with an icon-left / kind-text-right layout. The<leader>?cheatsheet renders as a
solid opaque card. - Neovim: signature help is owned by blink.cmp. The manual
CursorHoldI
vim.lsp.buf.signature_helpautocmd was removed — blink's own signature window handled the same
case and the two floats could stack while idle.<C-s>stays as the manual trigger. - Neovim: the central Mason install manifest moved out of conform.nvim (which is lazy on
BufWritePre, sorun_on_startreally meant "on first save") into its ownVeryLazy-loaded
plugins/mason-tool-installer.lua, so a fresh box installs its toolchain near startup.
Removed
- Neovim: trimmed unused plugins — the full in-editor debugger stack (nvim-dap,
nvim-dap-ui, nvim-dap-virtual-text, mason-nvim-dap, and every<leader>d*keymap), the test
runner (neotest + neotest-python/-golang), vim-dadbod (DB UI), incline.nvim (dropbar's winbar
covers split identity), aerial.nvim (Trouble + fzf-lua + dropbar cover symbols), nvim-spectre,
git-conflict.nvim, and mini.indentscope — along with their keymaps, which-key groups, and
cheatsheet sections. (16 entries removed fromlazy-lock.json, including transitive dependencies.)
Fixed
- Neovim: heavy linters no longer run on
InsertLeave. golangci-lint / cpplint scan the whole
package per run; they are now restricted toBufWritePost(save-only) while fast per-file linters
keep the snappier cadence. - Neovim: bash-language-server no longer emits
SC1071on zsh. Its built-in shellcheck
integration is disabled (bashIde.shellcheckPath = "") so zsh buffers keep completion/hover
without the "shellcheck only supports sh/bash/…" phantom diagnostic. - Neovim:
:wcan't be broken by a missing mini.nvim. The format-on-save
mini.trailspace.trim()call is now pcall-guarded.
v3.8.0
Changed
- Neovim UI moves to an NvChad-styled statusline + bufferline.
lualinenow uses a
hand-built theme derived from tokyonight's resolved palette (mode/location render as rounded
accent pills, git/cwd as a lighter block, filename on the base run) instead of the bundled
tokyonighttheme — so the blocks read as opaque islands on the transparent bar and follow
NvChad's structure.bufferlinegains palette-aware highlights so the active buffer lifts as a
subtle raised block with an accent underline while inactive buffers dim into the bar. Both are
computed at plugin-load (pcall-guarded), so a fresh box falls back to the bundled/auto theming. - LSP hover, signature help, and the diagnostic float share one padded, rounded card style.
Hover/signature pass an explicit rounded border with width/height caps (a huge docstring becomes
a tidy box); the diagnostic float drops its header row and gains a left pad + width cap.
Signature help now also pops automatically when you rest inside a function's arguments
(CursorHoldI, gated on server support, suppressed while the completion menu is open). which-keyand the<leader>?cheatsheet restyled to mirror NvChad's keymap visualizer.
which-key gets a minimal rounded, padded, left-aligned column popup with NvChad-palette colors
(blue keys, red descriptions, green groups); the cheatsheet's category headings become
full-width accent pill bars (cycling colors) with blue keys — both palette-aware, with a
semantic-link fallback on a bare box.
Fixed
- Neovim
taplo(TOML) root detection.root_markerslisted the glob"*.toml", which
vim.fs.root/vim.fs.finddo not support — so it never matched and taplo always fell back to
.git, giving a lone TOML file outside a repo a cwd root. Replaced with real manifest names
(pyproject.toml,Cargo.toml,foundry.toml,taplo.toml,.taplo.toml,.git). - Neovim
<leader>oi(organize imports) no longer binds where it can't work or races the
formatter. A server that ENUMERATES its code-action kinds withoutsource[.organizeImports]is
now skipped (so the map no longer silently no-ops on e.g.lua_ls); a server that only reports a
baretrueor a provider table without kinds still gets the map, since it can't be ruled out. The
racy fixed-50mspost-format timer is dropped — formatting stays owned by format-on-save and
<leader>cf. - Neovim cursor-restore skips commit buffers.
gitcommit/gitrebasebuffers open at the top
again instead of jumping to a stale mark from a previous commit. - Neovim folding has a single owner.
nvim-ufocomputes folds via its own treesitter+indent
providers, so the globalfoldmethod=expr+ treesitterfoldexprinoptions.luawas redundant
per-buffer work (UFO never readsfoldexpr). Dropped it; UFO now owns folding outright.
Changed (internal)
- Deduped the identical
snippetSupportcapability boilerplate in the Neovimhtml/cssls
server specs into a sharedutils.lsp.with_snippetshelper; standardized autocmd augroups on an
explicit{ clear = true }; corrected a stale comment claiming novim.notify-competing
notifier is installed (fidget is, for LSP progress only — no clash).
v3.7.0
Changed
- Neovim clipboard gains a gated OSC52 last-resort provider. When no native clipboard
backend is on PATH (no Coreclip/clip-paste, noclip.exe, and none ofpbcopy/
wl-copy/xclip/xsel/win32yank),"+y/"+proute over the terminal's OSC52
sequence — closing the "yank does nothing over tmux/psmux/SSH" gap on headless/remote boxes.
A working native provider is never overridden, so a normal desktop is unaffected. - Neovim clipboard paste uses
Get-Clipboard -Rawon Windows, so multi-line pastes no
longer arrive split/CRLF-mangled. - Windows-correct Neovim Python DAP + LuaSnip build. debugpy/venv interpreters resolve to
Scripts\python.exe(andpython, notpython3) on Windows; LuaSnip skips its
make install_jsregexpbuild where there's no toolchain. All gated onhas("win32"). - Neovim LSP capabilities fetch is
pcall-guarded (a blink load failure no longer aborts
the whole server stack), andemmet_lsnow attaches tohtml. - Starship prompt gains venv, package, git-metrics, and WSL indicators.
[python]shows the
active$virtualenv; a$packageversion indicator and an$env_varslot are wired into
format(surfacing a previously-unplacedENGAGEMENTvar and a newWSL_DISTRO_NAMEbadge);
git_metricsis enabled; a documented opt-indocker_versioncustom is included (off by default). git_main_branchresolves the trunk in one call. It readsorigin/HEADdirectly
(git symbolic-ref) and only falls back to probing the trunk-name candidate list when
that is unset — instead of firing up to 18git show-refsubprocesses every call. It sits
on the hot path (gcom/gswm/grbm).git_current_branchuses the git porcelain. It now readsgit branch --show-current
(git 2.22+) instead of the hand-rolledsymbolic-ref+ return-code dance; the short-SHA
fallback on a detached HEAD and the empty result outside a repo are both preserved._core_suggestno longer forks per candidate._core_levgained a fork-free out-var
mode, so scoring a mistyped Core verb against the alias/subcommand list runs in-process
rather than spawning a command substitution for each candidate (~80+ on a badplease).pullalltallies its summary in a singleawkpass instead of fourgrep -cscans of
the same buffer.- Collapsed a dead
status-leftconditional intmux/tmux.confto a constant — all three
branches resolved to the same colour. - Decoupled
--helpfrom header line numbers.update-plugins.sh,
update-nvim-plugins.sh, andfreshness-dashboard.shnow print usage from a heredoc rather
thansed -n '<a>,<b>p' "$0", which silently mis-printed whenever the header comment moved
(the couplingsync-core.shalready documents having removed). - Removed redundant zsh history setopts (
zsh/history.zsh):INC_APPEND_HISTORY(implied
bySHARE_HISTORY) andHIST_IGNORE_DUPS(superseded byHIST_IGNORE_ALL_DUPS) were
no-ops, so they are dropped.
Security
- session-start hook verifies its tool downloads.
install_tarballand the neovim
install in.claude/hooks/session-start.shnow download to a file and check the pinned
SHA-256 fromscripts/tool-versions.envbefore extracting — failing closed when a
checksum is absent or mismatched — instead of pipingcurl … | tarunverified. Brings the
remote-session gate toolchain in line with the CI composite action, which already verifies. - claude-routines run with least-privilege tools. Each job's
--allowedToolsnow mirrors
its routine's ownallowed-toolsfrontmatter rather than granting unrestrictedBash; the
web-reading routines (tool-scout, freshness-triage, modernize, release-readiness,
drift-triage) no longer pair arbitrary shell withWebFetch/WebSearch, closing a
prompt-injection →CLAUDE_CODE_OAUTH_TOKENexfiltration path.drift-triage's command
frontmatter is scoped to match. HISTORY_IGNOREcovers more secret shapes (zsh/history.zsh):--flag=valueforms and
env-assignment credentials (TOKEN=,PASSWORD=,*ACCESS_KEY=,APIKEY) that the
space-only patterns let slip now stay out of the plaintext$HISTFILE.
Fixed
- Cheatsheet uses a non-deprecated highlight API.
nvim/lua/gerrrt/cheatsheet.luanow
callsnvim_buf_set_extmarkinstead of the deprecatednvim_buf_add_highlight(slated for
removal on Neovim nightly), so:Cheatsheet/<leader>?keeps working on current Neovim.
v3.6.1
Documentation
docs(runbook): spell out how release cuts differ by bump type.
RELEASE-RUNBOOK.mdnow adds the Core-release bump-selection table, the step-4
@vNalias split for PATCH/MINOR vs MAJOR, the extra MAJOR rolloutuses:bump,
the htpx SemVer guide, and the "undo a stagedmake release" troubleshooting
path.RELEASE-STRATEGY.mdis updated alongside it so the current-version examples
stay aligned with the live Core release line.
v3.6.0
Added
feat(nvim): five editor quality-of-life tweaks. Cherry-picked from an external
config the handful of behaviours that beat or fill a gap in ours (the rest we already run
better-configured equivalents of). (1)i/a/Aon a blank line auto-indents via"_cc
(black-hole register, guarded oncount == 0so3i/10akeep native behaviour);
(2) an asyncgit fetchonVimEntertoasts when the upstream is ahead ofHEAD— pinned
to the startup cwd, argv-form (Windows-portable), and only reported after a successful
fetch; (3)vimadedims inactive windows and cursorline is now shown only in the active
window (markdown/text/gitcommit keep their cursorline-off policy); (4) a macro-recording
indicator in the lualine mode block; (5)exrcfor project-local config. Thegit fetch
toast andexrcare both gated onDOTFILES_OFFLINEso they stay inert on engagement boxes,
andexrcadditionally relies on Neovim'svim.securetrust prompt for untrusted repos.
v3.5.2
Fixed
fix(tmux): trailing space after the copy-mode icon. The status-bar copy-mode
indicator was#S(glyph abutting the session name); it is now #S— a single
space keeps the pill readable at a glance without otherwise changing the layout.
Documentation
docs(runbook,strategy): document the deliberate dotfiles-Windows minor/major
release flow.RELEASE-RUNBOOK.md§3 only covered the automatic PATCH path
(mirror-sync → auto-tag). A new §3b covers the human-driven minor/major flow: the
version decision via/release-readiness+/release-notes, the
packages.lock.jsonre-pin (including the winget-export-vs-ARP mapping gap that
silently drops installed-but-unmapped apps), CHANGELOG promotion, and
gh release create(there is norelease.ymlon the Windows repo). Simultaneously,
RELEASE-STRATEGY.mdis corrected: dotfiles-Windows is now carved out as the
standalone exception that carries its own vX.Y.Z but nocore/subtree, and the
notes-source column is fixed (--notes-filevia auto-tag.sh is the automatic path;
--generate-notesis only the fallback for empty/unconventional ranges).
v3.5.1
Changed
ci(modern): ban themacos-14runner in the modern-CI floor.macos-14
(Sonoma) images entered deprecation on 2026-07-06 and are fully unsupported on
2026-11-02, soscripts/modern-baseline.ymlnow lists it underbanned_runners
alongsidemacos-13. Pre-emptive and free — the fleet ridesmacos-latest, so no
workflow references the pinned label today;check-modern.shenforces it.
Documentation
docs(matrix):watch→viddyis now a first-class, provisioned tool.
PORTING-MATRIX.mdgains aviddyrow so thewatch→viddyalias Core already
ships (HAVE_VIDDY-guarded inzsh/aliases.zsh) is actually installed — macOS
already had it via Homebrew; the Linux/Kali repos now install it best-effort in
bootstrap.shviacargo install viddy(viddy is a Rust CLI, so the same cargo path
as yazi/dust — Arch, which ships no rust toolchain, prints aparu -S viddyhint).
Inert without the binary, so boxes that skip it keep classicwatch.
v3.5.0
Changed
fix(git): delta'ssyntax-themeis nowansi(wasTwoDark). delta now follows
the terminal's Tokyo Night ANSI palette, matchingBAT_THEME=ansi(already set in
aliases.zsh) sogit diffandbatrender syntax the same way — and matching the
Windows host, which already usedansi. Part of the Windows↔Mac terminal parity pass.
Fixed
fix(nvim):<leader>rcand the alpha dashboard "Config" button openinit.lua
on Windows too. Both hardcoded~/.config/nvim/init.lua, which doesn't exist on the
Windows host — Neovim there reads%LOCALAPPDATA%\nvim— so the binding opened a phantom
path. They now resolve the config dir at runtime viavim.fn.stdpath("config"), so the
same binding lands on the realinit.luaon every platform.
Parity (cross-shell contract)
feat(parity): the aligned tool-swap manifest gainsdf→duf,top/htop→btop,
fm/y→yazi,md→glow (pwshgmd), andping→gping. These were already defined
inzsh/aliases.zsh; adding them toscripts/parity-aliases.txtmakes
parity-check.shenforce them bidirectionally against the pwsh host'sprovides:
contract (the Windows PowerShell port added the matching functions in the same pass).feat(parity):Ctrl+\autosuggest/prediction toggle is nowaligned, not
deliberate. The Windows host bindsCtrl+\to flip PSReadLine'sPredictionSource,
mirroring zsh'sautosuggest-toggle;parity-check.shnow enforces the needle on both
shells. PARITY.md's Aliases prose also now documents the full curated git shorthand set
as aligned across zsh + pwsh.Merge order: the pwsh side of these rows ships in the
dotfiles-Windowsparity PR.
Merge (or land together with) that PR so the weeklyparity-check.yml— which clones
dotfiles-Windowsmain— sees the matching pwsh definitions and stays green.
v3.4.0
Added
feat(freshness): the weekly fleet board gains three live cross-repo signals.
scripts/freshness-dashboard.shnow queries the GitHub API (best-effort, gated ongh+
a token — the workflow provides both, a local run degrades to an "unavailable" note) for:
own-tag release drift (commits each repo has merged since its last release tag — its
own unreleased work, distinct from Core-tag vendoring drift), an open Renovate PR tally
per repo (how many dependency PRs are waiting right now, beside the existing dashboard
links), and judgment-layer routine issues (links to each repo's open.claude-routine
issues — doc-audit, os-package-availability, coverage-gap, … — so the board references the
stale-docs and coverage-hole signals rather than recomputing them). Still a never-failing
reporter (always exits 0).feat(routines): three new judgment routines + a reusable OS-repo routine workflow./shell-review(.claude/commands/shell-review.md) — weekly (Tue 11:00) read of the
week's changedzsh/bashfor runtime footguns lint can't catch (the tmux-scratchpad
and doctor-hint classes), report-first./drift-triage(.claude/commands/drift-triage.md) — weekly (Tue 12:00) interpretation
of Monday'sfleet-driftsweep into ranked per-repo remediation, report-first./os-package-availability(.claude/commands/os-package-availability.md) — audits an OS
repo'sinstall/packages.txt/Brewfilefor renamed/dropped/moved packages against
upstream +PORTING-MATRIX.md. Shipped as a reusable workflow
(.github/workflows/claude-routines-call.yml) so each OS repo consumes it as a ~5-line
@v3caller (inverted checkout, likelint-call.yml) rather than a 6× copy.
All inert-by-default (preflightCLAUDE_CODE_OAUTH_TOKENgate) and report-first.
Changed
perf(zsh): dropzstyle ':completion:*' rehash true— no more per-Tab$PATHstat storm.
rehash true(zsh/options.zsh) forced zsh to rebuild its external-command hash — stat every
directory in$PATH— on every completion attempt, which is perceptible on an NFS home,
linuxbrew, or a large mise-shims$PATH, and fanned out to all eight OS repos. Removed; a
newly-installed binary now surfaces afterhash -ror a new shell (the maint runner already
refreshes the command hash after installs). A regression-guard comment records why it stays out.chore(bin): make.bin/sync-upstream.shoverridable for forks/mirrors.
CORE_REPO_URLandTARGET_BRANCHnow read${VAR:-default}, so a fork, a mirror, or a
renamed org cangsyncwithout editing this vendored file.
Fixed
docs(porting): correct thePORTING-MATRIX.mdpackage cells the/os-package-availability
routine flagged as drifted. Alpineduf/gloware back totesting(they were never
promoted tocommunityon stable, incl. 3.24 — a July flip that claimed otherwise is reverted,
and footnote ¹⁴ restored); Alpinetldrnow showscargo³(testing-only → bootstrap builds
it from source) and Alpineouchis corrected totesting(testing-only, not auto-installed);
and Gentootealdeer/yazi/lazygitare marked GURU-only
(footnote ¹²) alongside a note thatdirenvisapp-shells/direnv, not the non-existent
dev-util/direnv. Matches the OS-repo bootstrap reality (Alpine cargo/go-install fallbacks;
Gentooguru_install). Also: Archatuindrops the stale "(AUR for some)" qualifier and Arch
doggomoves fromAUR³todoggo(both now first-class inextra), and the openSUSE
tealdeerfootnote ¹ is de-hedged (it's in Tumbleweed main OSS, not devel-only).fix(zsh):compinitblock no longer leaks a globalzcdinto every interactive shell.
zsh/options.zshdeclaredlocal zcd=…at the file's sourced top level, where zsh (which has
only function scope) silently promoteslocalto an ordinary global — polluting the
namespace on every shell start across all eight OS repos and contradicting the codebase's own
anon-function convention (zsh/aliases.zsh) andloader.zsh's "no top-levellocal" rule. The
cache body is now wrapped in an anonymous function sozcdis genuinely function-scoped;
compinitdeclares its statetypeset -g, so the completion system persists unchanged.fix(zsh):servenow prints a reachable URL and QR on macOS.
serve(zsh/functions.zsh) gated all tunnel/LAN IP discovery oncommand -v ip, but macOS
ships noip(8), so on a Mac it degraded to a bare "serving on port N" with no LAN URL and no
QR. Added aroute(8)+ipconfigfallback branch — the same Linux/macOS split
tmux/scripts/tmux-netinfo.shalready uses — so tunnel-first, then default-route LAN discovery
works on a Mac. No change on Linux/WSL.fix(nvim): undo dir now derives fromstdpath("state"), not a hardcoded path.
options.luahardcoded~/.local/share/nvim/undodir; it now usesvim.fn.stdpath("state"),
so undo history lands in the right tree under a relocatedXDG_STATE_HOMEand on macOS.fix(nvim): drop the no-opvim.opt.encoding = "UTF-8".
Neovim's internal encoding is always UTF-8; setting it post-startup is a no-op at best and a
footgun at worst. Removed; a comment records why it stays out.fix(tmux): popup previews degrade on Debian / a bare box.
tmux-menu.sh's engagement preview now falls backbat→batcat(Debian renames the binary),
andtmux-sesh.sh's project preview falls backeza→lswhen eza is absent — matching how
the zsh widgets already resolve these.fix(starship): the Linux VPN segment uses a portableip link showprobe, notifconfig.
custom.vpn_linuxshelled out toifconfig(net-tools), which modern distros don't ship by
default, so the tunnel indicator silently never appeared. It now parsesip link show— the
common form supported by BOTH iproute2 AND BusyBox'sipapplet (Alpine's default), so it works
on every Linux target including the BusyBox outlier.custom.vpn_macoskeepsifconfig(native).docs(git): spell out theincludeIfwork-identity failure mode.
Clarified that a missing~/.config/git/config-workmakes git silently fall back to your
default identity (no error), with the exact commands to seed it.fix(git):prune-branchesusesgrep -E, not deprecatedegrep.
Theprune-branchesalias (git/gitconfig) shelled out toegrep, which GNU grep ≥3.8 prints
a deprecation warning for on every invocation. Switched togrep -Ev;xargs -ris kept (GNU
needs it to skip empty input, and modern BSD/macOS xargs supports it), so the alias is quiet on
the Linux target and unchanged in behaviour on the macOS/BSD target it ships to.fix(scripts): checksum refresh falls back toshasum -a 256off-Linux.
scripts/update-tool-checksums.shhard-calledsha256sum(GNU coreutils); a run on the macOS
box (which shipsshasum -a 256, notsha256sum) died. It now probes and falls back, so the
tool works on either platform.fix(maint):dotfiles-maint.shenablesset -uo pipefail.
The unattended daily runner had nosetoptions, so a typo'd env knob expanded to empty and a
mid-pipe failure was masked. Addedset -uo pipefail(every env knob is already:=/:-
defaulted);-estays deliberately omitted so one failed step never aborts the rest — that
remainsstep()'s job.fix(tmux): the popup scripts enableset -u.
tmux-menu.sh,tmux-scratch.sh, andtmux-sesh.shcarried nosetoptions, unlike their
siblings; a typo'd variable would expand to empty silently. Addedset -u(all three already
guard${TMUX:-}/${TERM:-}etc.);-e/pipefailstay off because the fzf pickers exit
non-zero on a normal operator cancel.fix(scripts): the freshness board's live signals honour an env token.
scripts/freshness-dashboard.shgated its GitHub-API "live signals" ongh auth status
alone, whose exit/output varies byghversion — so in CI (which authenticates via
GH_TOKEN, notgh auth login) the release-drift / Renovate-count / routine-issue
sections could be mis-detected as unavailable. It now treats aGH_TOKEN/GITHUB_TOKEN
env var as sufficient (whatgh apiactually uses), falling back togh auth status
for local runs with stored credentials.
v3.3.0
Changed
perf(zsh): cut per-shell subprocess forks on the interactive startup path.
_cache_eval(zsh/tools.zsh) now resolves each tool's binary via zsh's fork-free
$commandshash instead of$(command -v …), removing one command-substitution fork
per cached tool (~8/shell across starship/zoxide/mise/atuin/carapace + the os-layer
gh/uv/ty callers). Thediff --colorcapability probe (zsh/aliases.zsh) is now
cached (keyed on thediffbinary's mtime, invalidated on a toolchain change) instead
of running the realdiffon every shell; a live probe still decides correctly when
the cache dir isn't writable. No behavioural change — same aliases, faster launch.docs(zsh): makecore-doctor's "install missing" hint honest about unpackaged tools.
The batch hint printed a blanket<pkg-manager> install <all-missing>, implying the package
manager can install every tool. On some distros a few modern-CLI tools aren't packaged at
all (they're binary-distributed, and the right method — a distro package,mise use -g,
go install,cargo install, or a vendor repo — varies per tool and distro), so the line
fails on those. The caveat now states that names differ per distro and that not every
tool is packaged everywhere, pointing toPORTING-MATRIX.mdfor the authoritative per-tool
install path instead of implying the package manager covers all of them. Output-only; the
package-manager line itself is unchanged.
Fixed
fix(tmux): scratchpad popup (prefix + T) no longer hijacks the main session on close.
tmux-scratch.shruns the scratchpad as a persistent_popup_scratchpadsession the popup
attaches to. On close, exiting the shell destroys that session, and the global
detach-on-destroy off(tmux.conf) made the popup's client jump to the MAIN session instead
of closing — attaching a second, popup-sized (80%×80%) client, so tmux clamped the main
session to the popup's size and double-drew it (the scratchpad "took over" and the real
terminal was left garbled). The scratch session now setsdetach-on-destroy onfor itself,
so its client detaches (popup closes cleanly) when it's destroyed; real sessions keep the
global jump-don't-exit behaviour.