Bug: On systems without systemd (Unraid OS 7.2.4, BSD, macOS containers,
and other non-systemd Linux hosts), running `muxplex upgrade` or
`muxplex update` crashed immediately with:
FileNotFoundError: [Errno 2] No such file or directory: 'systemctl'
The check ran unconditionally before any install step, so the upgrade
aborted without even attempting to fetch the new version. Introduced
in v0.6.0.
Fix: Add a module-level `_have_systemctl() -> bool` helper to cli.py
(and service.py) that gates every systemd-specific operation behind
`shutil.which("systemctl") is not None`.
Call sites guarded in cli.py (upgrade() function):
1. systemctl --user is-active muxplex (stop-before-upgrade check)
2. systemctl --user stop muxplex (pre-install service stop)
3. Service file regeneration step (service_install() call)
4. systemctl --user is-enabled muxplex (post-install restart check)
5. systemctl --user daemon-reload (post-install daemon reload)
6. systemctl --user start muxplex (post-install service start)
Behaviour on no-systemd systems:
- Skips the is-active check (treats as unmanaged; prints skip note).
- Skips the stop step.
- Still performs the uv/pip install.
- Skips service-file regeneration (prints skip note).
- Skips the daemon-reload / start steps.
- Prints: '! systemd not detected — restart muxplex manually to pick
up the new version' with the running PID if pgrep finds one.
- Still runs `muxplex doctor` for verification (no systemd required).
doctor() change:
- On non-darwin platforms with no systemctl, now prints:
'! Service: systemd not available on this platform'
instead of silently doing nothing or crashing.
service.py change:
- Public API functions (service_install, service_uninstall,
service_start, service_stop, service_restart, service_status,
service_logs) now check _have_systemctl() on the Linux path.
- When absent, print a clear, friendly error pointing the user to
`muxplex serve` instead of letting subprocess raise FileNotFoundError.
Tests added (muxplex/tests/test_cli.py, +8 tests):
- test_have_systemctl_helper_exists
- test_have_systemctl_returns_bool
- test_upgrade_no_systemctl_runs_to_completion (regression)
- test_upgrade_no_systemctl_prints_skip_note
- test_upgrade_no_systemctl_prints_manual_restart_note
- test_upgrade_with_systemctl_runs_systemd_commands
- test_doctor_no_systemctl_shows_graceful_message
- test_doctor_no_systemctl_does_not_crash
The previous transitionend approach (v0.4.5) had a { once: true } bug:
the sidebar transitions two CSS properties (width and min-width), and if
min-width fired first, the listener self-destructed before the width event
arrived — so _refitTerminal() was never called.
Replace the fragile event-based approach with a ResizeObserver on
#terminal-container. This automatically calls _fitAddon.fit() (debounced
50ms) whenever the container dimensions change, handling sidebar toggle,
browser resize, and any future layout change. Remove the now-unnecessary
window._refitTerminal global and the broken transitionend handler.
Bumps version to 0.4.6.
toggleSidebar() flipped the sidebar--collapsed CSS class but never told
xterm.js to recalculate its dimensions. The terminal canvas kept its old
column/row count until a new session was opened (which creates a fresh
terminal that measures correctly on first fit()).
Fix: expose window._refitTerminal() from terminal.js, then call it via
a transitionend listener in toggleSidebar() so the terminal refits once
the 250ms CSS width/transform transition finishes.
Bumps version to 0.4.5.
The test regexes matched `renderSidebar(\w+,\s*\w+)` (exactly 2 params)
but the fix in 821c595 added a third `currentRemoteId` parameter.
Updated to use `\(.*?\)` which matches any parameter count.
Generated with Amplifier
Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Issue 1 (CRITICAL): terminal.js createTerminal() read fontSize from
localStorage.getItem('muxplex.display'), which always returns null after
the server-settings migration. This caused terminal font size to permanently
default to 14 regardless of the server-side fontSize setting.
Fix: Pass getDisplaySettings().fontSize from app.js to window._openTerminal
as a third argument. Update openTerminal(name, remoteId, fontSize) and
createTerminal(fontSize) to use the parameter, removing all localStorage
reads from terminal.js.
Issue 2: Fix 9 stale test references in test_app.mjs that set
_localStorageStore['muxplex.display'] instead of app._setServerSettings().
Tests now correctly exercise the server-settings path.
Issue 3: Fix stale initSidebar test that used
delete _localStorageStore['muxplex.sidebarOpen'] — replaced with
app._setServerSettings(null) since initSidebar reads from _serverSettings.
Also update 5 Python tests in test_frontend_js.py that were checking the
old localStorage-based createTerminal() behavior:
- Renamed test_create_terminal_reads_font_size_from_localstorage to
test_create_terminal_accepts_font_size_parameter
- Renamed test_create_terminal_parses_json_for_font_size to
test_create_terminal_does_not_parse_json_from_localstorage
- Updated 3 remaining tests to use regex that matches createTerminal(fontSize)
instead of createTerminal()
Verification:
- grep -rn 'localStorage' app.js: only tmux-web-device-id (3 lines)
- grep -rn 'muxplex\.display|muxplex\.sidebarOpen' frontend/: zero matches
- All 372 JS tests pass (44 terminal + 328 app)
- All 199 Python frontend_js tests pass