New pruning.py sidecar module with load_pruning_state / save_pruning_state. The sidecar lives at ~/.config/muxplex/pruning.json and is NEVER in SYNCABLE_KEYS — bookkeeping is per-device, not federated.
prune_stale_keys(settings, live_keys, *, pruning_state, grace_seconds, now) drops keys from hidden_sessions and view.sessions after they have been missing past the configurable grace period (default 24h, syncable via stale_key_grace_hours).
Wired into _run_poll_cycle as step 14 with try/except so failures never abort the cycle.
The prune ACTION (settings change) syncs normally via existing LWW; the bookkeeping does not.
24 new tests pass; total muxplex/tests/ = 1263 passed.
Adds a new TLS certificate method ('ca') that generates a persistent local
Certificate Authority and signs leaf certificates against it. This allows
users to install the CA once on client devices and have browser-trusted
HTTPS for plain LAN names (my-host, 192.168.1.5, my-host.local) without
requiring external services like Tailscale.
Key improvements over existing --method selfsigned:
- Persistent CA: the root cert is stored separately and never rotates,
so leaf certificate renewal doesn't require re-trusting on clients
- Auto-detected SANs: includes LAN IP, tailnet name (if applicable),
hostname, and localhost variants
- Per-platform install guide: comprehensive docs/TRUSTING_THE_LOCAL_CA.md
with Windows PowerShell, macOS/Linux, iOS, and Android install steps
Solves PWA installation issues on Windows machines with corporate IT
policy blocking Tailscale: PWAs now persist in standalone mode when the
local CA is trusted in the Windows user cert store.
Changes:
- muxplex/tls.py: added _default_lan_ip(), _default_tailnet_name(),
generate_local_ca(), generate_leaf_signed_by_ca()
- muxplex/cli.py: added 'ca' to --method choices, wired setup_tls()
to generate CA + leaf with auto-detected SAN
- docs/TRUSTING_THE_LOCAL_CA.md: comprehensive per-platform install guide
- README.md: added --method ca documentation and cross-links
- CHANGELOG.md: documented v0.5.0 features
Generated with Amplifier
Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Bump version 0.1.0 → 0.1.1. Add CHANGELOG.md covering all changes
since initial release. Update README clipboard section to reflect
native xterm.js paste handling.
Fixes test_readme_documents_all_settings_keys — federation_key was added
by the federation feature but not documented in README. Also commits the
CLI refactor plan files as historical ADRs.
README now documents all features, 14 config keys, full CLI reference,
keyboard shortcuts, platform support, and project structure. Previous
README covered ~40% of actual functionality. Added docs/plans/README.md
noting these are historical ADRs from the initial build.
Added 9 new README tests verifying all settings keys are documented,
clipboard features, keyboard shortcuts, auth modes, platform support,
ANSI previews, hover preview, and view modes.
Exposes ~/.config/muxplex/settings.json management without hand-editing:
config list — show all settings with (modified) markers
config get <key> — print one value
config set <key> <value> — set with auto type coercion (bool/int/str/list)
config reset [key] — reset one or all to defaults
Example: muxplex config set host 0.0.0.0 && muxplex service restart
- Expand Prerequisites section with bullet format (was a sparse table)
- Add tmux and ttyd per-platform install commands (macOS, Ubuntu/WSL)
- Note that muxplex prints install instructions if either dependency is missing
- Update 'Install as a Service' section with macOS launchd instructions
- Update Usage table to reflect platform-aware install-service behavior
Required fixes:
- main.py: update module docstring, startup comment, and FastAPI title from
'tmux-web coordinator' / 'coordinator service' → 'muxplex' (4 locations)
- test_api.py: replace hasattr/BaseRoute pattern with isinstance(r, (APIRoute,
APIWebSocketRoute)) to satisfy pyright (union-attr error eliminated)
Recommendations applied:
- test_api.py + test_cli.py: auto-formatted with ruff (blank-line normalisation)
- test_cli.py: replace exec(Path('muxplex/__main__.py').read_text()) with
importlib.util.find_spec() to obtain the absolute path — no longer assumes
pytest is invoked from a specific working directory
- README.md: fix architecture table — WebSocket proxy moved from ttyd.py
description to main.py; ttyd.py now correctly described as lifecycle only
All 178 tests pass; python_check clean (0 errors, 0 warnings).
Addresses code quality suggestion from review: requirements.txt was a
redundant secondary source of truth. Dependencies are now exclusively
managed in pyproject.toml with proper runtime/dev separation.
- requirements.txt: replaced with a comment redirecting to pip install -e '[dev]'
- README.md: updated install command from pip install -r requirements.txt
to pip install -e '[dev]'