YuKu's promised screenshot revealed the real section-6 chaos: the live
line 'block + msg + current package' is longer than 80 columns, so
every redraw WRAPPED to a new line instead of overwriting — the screen
filled with duplicate partial progress lines.
The line is now composed once and clamped to $(tput cols) - 2 with an
ASCII '..' tail. 80-col pty run: zero wrapped live lines (the only
>82-char output left is plain-mode dnf, unchanged by design).
YuKu: 'slow the flicker a bit (half or one-third speed)'. The 16-colour
blue<->grey pulse now ticks at 150ms (600ms full cycle, calm); the
256-colour terminal breathe keeps its 50ms deep ramp. Per-depth tick
variable; same in the vendored helper.
Rate proven by pty trace: 8 frames in a 1.2s transaction = 150ms
exactly. (Frame-counting via grep -c undercounts — \r overwrites
collapse frames onto one line; count matches, not lines.)
The on/off pulse shifted the whole line by one character during the
dark frames (off-frame printed one space fewer than the block frame).
Per YuKu: keep the block ALWAYS present and alternate its colour
instead — blue (44) <-> dark grey (100, bright black). Layout is
constant, pulse is colour-based, nothing moves but the block itself.
Also: disable_selinux now mkdir -p's /etc/selinux before writing a
fresh config (harness caught a die on a missing parent dir).
YuKu tests on the bare Linux VT (not a terminal emulator): my 16-colour
fallback alternated blue (44) / bright blue (104), which render nearly
identically on VGA consoles -> fused into 'solid blue'. If TERM
misreports 256, 48;5;N codes are ignored outright.
Fixes:
- TERM linux*/console* forces the 16-colour path regardless of tput.
- 16-colour mode now PULSES THE BLOCK ON/OFF (2 frames blue block,
2 frames no block, ~2.5Hz) instead of shade alternation — visible
on any console hardware, no colour fidelity required.
- 256-colour terminals keep the deep 17->45 breathe ramp.
Verified: TERM=linux pty shows block/no-block alternation with zero
48;5 codes; TERM=xterm-256color keeps the 8-shade ramp; unattended +
piped regressions green.
At 20fps the previous narrow ramp (shades 17-33) flicker-fused into an
apparent SOLID block on the VM. Amplitude now spans dark navy (17) to
bright blue (45) in 12 steps — every frame is visibly different, cycle
is 0.6s. Speed unchanged.
YuKu: 'the breathing is super slow'. Frame interval down from 150ms
to 50ms (~7fps -> ~20fps pulse). Same change in the vendored
lib/ui-block.sh helper for consistency.
ui_quiet_run now paints a TTY-safe status BLOCK: a background-coloured
SPACE (never a glyph, no font/locale dependency — the braille lesson).
busy : blue block breathing through a 256-colour ramp (48;5;17..33)
with the live dnf action after it
ok : solid green block + package count
fail : solid RED block (spec: YuKu changed the red X to a red block)
followed by the log tail
Colour-depth aware: 256-colour ramp -> 16-colour blue/bright-blue ->
plain ASCII spinner when the terminal reports no colour. LANG=C pty
run shows zero non-ASCII bytes.
Also vendors lib/ui-block.sh (the standalone helper from the Telegram
session prototype; fail changed to red block) and installs the
ui_block_close EXIT trap — with a return 0, because an EXIT trap's
status becomes the script's exit code (harness caught every-successful-
run exiting 1 through that path).
The braille spinner frames and the em-dash separator are multibyte
UTF-8; on the VM session they rendered as changing random letters, not
a spinner. Frames are now the classic | / - \ cycle, the separator is
':', and the two user-facing info lines that carried em-dashes are
ASCII too. Verified under LANG=C LC_ALL=C in a pty: zero non-ASCII
bytes in the entire output.
gum spin rendered static on the real VM during long transactions.
ui_quiet_run now draws its own line: braille spinner frame + the
package dnf is currently working on (from the transaction log), at
150ms ticks. Works without gum (pure bash), gated on interactive
terminal, not on gum.
set -e + pipefail bug found via pty trace: the first tick races the
child's first log line, grep exits 1 (no match) and pipefail turns the
whole substitution nonzero, killing the script silently at the first
frame. || true on the substitution pipeline fixes it.
ui_quiet_run wraps every install_packages/install_optional/group
install/remove and the system update: while gum is available and the
run is interactive, dnf output is hidden behind a spinner, then a
single 'Installing: <pkgs> (N packages)' line. Full output is appended
to $SETUP_DNF_LOG (/tmp/fedora-setup-dnf-<uid>.log); on failure the
last 20 lines print in red so nothing is lost. Unattended and no-gum
runs keep plain full output (logs/cron contract).
Also: fallback ui_choose accepts 'x' to exit (muscle memory from the
old menu), fixed a stray stdout newline leaking into captured answers
(same class as the earlier '\nno' bug), fixed pluralization.
Harness: piped fallback, pty gum run incl. a failing VirtualBox pick
(red failure + log tail, menu survives, subsequent qemu install ok),
unattended regression.
Fresh-VM timeline explained: on run 1 virt-manager installs AFTER the
niri module's prereq check ran (menu dispatch order), so the group add
was evaluated against a package state that did not include it yet. A
second run 'fixed' it — matching the observed behavior.
- New ensure_libvirt_group runs in the Summary section, seeing the FINAL
package state; menu/module-time check kept as an early pass.
- pkg_installed is AND-semantics (all must be installed); the gate needs
OR. New pkg_installed_any helper; both gates switched to it.
- Also fixed a set -e trap: '$done_any && ok' returned 1 (killing the
script) when no optional tools were picked — replaced with an if.
All four gate cases harness-proven: virt-only, menu-pick, no-virt,
already-in-group.
- On btrfs, snapshots + zstd compression now just happen (no prompt);
--snapper=no remains the explicit opt-out.
- Vendor scripts/snapper-*.sh + config/snapper.actions from
SysGuides/sysguides-snapper-fedora (MIT, upstream 0a28eb4) into
vendor/snapper/ and install from there — no runtime clone of an
external repo, and no dependency on exec bits (fixes the
'./install.sh: Permission denied' failure seen on the test VM).
- grub-btrfs still cloned at runtime from Antynea/grub-btrfs with the
Fedora config applied; everything else is local now.
New section between base and DE menus:
- 'Disable SELinux permanently?' — default no; writes SELINUX=disabled with a
backup, warns about the security tradeoff.
- When / is btrfs: 'snapper + grub-btrfs + compression?' — default yes. Shows
subvolume list + fstab, appends ,compress=zstd:1 to btrfs fstab entries that
lack a compress= option (idempotent, fstab backed up), then runs the
SysGuides sysguides-snapper-fedora installer (snapper root+home, grub-btrfs,
DNF5 pre/post snapshot actions).
- Flags for unattended runs: --selinux=keep|disabled, --snapper=yes|no.
- Fix found by the harness: the flag initializers sat after the arg loop and
wiped parsed values; --snapper=no was silently ignored. Initializers moved
before the loop.
README + section renumbering updated.
The corrections commit replaced the lib/+modules/ entrypoint with the
older single-file version, reintroducing the DEBUG_MODE unbound-variable
crash, the unguarded clear, and TWM dispatch pointing at nonexistent
root-level scripts. lib/ and modules/ were orphaned.
Restores the tested restructured setup.sh + the SC2034 fix in lib/common.sh.
Splits setup.sh into lib/common.sh, lib/session.sh and seven modules
(3 DE, 4 TWM). Targets a bare Fedora 44+ install.
Fixes carried over from the first build:
- DEBUG_MODE was unbound under set -u, aborting the script at the version banner
- mangled 'echohttps://...' line left over from the starburst split
- set -e was missing entirely; --debug flag parsing restored
- unguarded 'clear' aborted the run without TERM
- $PRETTY_NAME unguarded under set -u
- modules were sourced, leaking shell options into the parent
- Flathub added twice (system-wide + per-user)
- no dnf5-plugins check before using 'dnf config-manager'
- no Fedora release gate
- /usr/share/xsessions assumed to exist when writing session entries