- Delete unused add_service_to_host/remove_service_from_host from state.py
(42 lines of dead code never called anywhere)
- Extract _stream_output_lines helper in executor.py to deduplicate
identical read_stream functions in _run_local_command and _run_ssh_command
- Simplify unique-list logic in compose.py using dict.fromkeys()
instead of manual seen/unique set/list pattern
Total: -67 lines
- Remove dead code: `run_host_operation` in cli/common.py (never called)
- Inline `_report_*` helpers in lifecycle.py (each called once)
- Merge `validate_host` into `validate_hosts` with flexible str|list param
- Merge `_report_no_config_found` and `_report_config_path_not_exists`
into single `_report_missing_config` function
- Simplify `_get_editor` from 18 lines to 6 using walrus operator
- Extract `COMPOSE_FILENAMES` constant to avoid duplication in config.py
- Extract `_stream_subprocess` helper to reduce duplication in streaming.py
Net reduction: ~130 lines of code with no functionality changes.
* feat(web): Show (local) label in sidebar host selector
Add local host detection to sidebar partial, matching the console page
behavior where the current machine is labeled with "(local)" in the
host dropdown.
* refactor: Extract get_local_host() helper to deps.py
DRY up the local host detection logic that was duplicated between
console and sidebar_partial routes.
* revert
One-shot containers (like CLI tools) were showing a perpetual loading
spinner because they weren't in `docker compose ps` output. Now we:
- Use `ps -a` to include stopped/exited containers
- Display exit code: neutral badge for clean exit (0), error badge for failures
- Show "created" state for containers that were never started
500% background-size showed too much of the gradient at rest,
revealing green (#bfff80) at the button edge. 650% shows ~15%
of the gradient, landing safely on white while still improving
color visibility during animation.
The 900% background-size meant only ~11% of the gradient was visible
at any time. On smaller screens, the rainbow colors would flash by
too quickly during the intro animation, appearing mostly white.
Use a CSS variable for background-size and reduce it to 500% on
mobile (<768px), showing ~20% of the gradient for a more visible
rainbow effect.
After a self-update, the browser tries to reconnect to the old task_id
but the in-memory task registry is empty (new container). Show a
helpful message instead of a scary "Error" message.
* fix(web): Ensure URL updates after HTMX navigation in command palette
Use history.pushState() after HTMX swap completes to ensure
window.location.pathname is correct when rebuilding commands.
* docs: Add rule about unchecked checklists in PR descriptions
* fix(web): Add PATH for self-update SSH command
Non-interactive SSH sessions don't source profile files, so `cf` isn't
found when installed in ~/.local/bin. Prepend common install locations
to PATH before running the remote command.
* fix(web): Enable TTY for self-update SSH to show progress bars
Non-interactive SSH sessions don't source profile files, so `cf` isn't
found when installed in ~/.local/bin. Prepend common install locations
to PATH before running the remote command.
* refactor: Store SSH keys in subdirectory for cleaner volume mounting
Change SSH key location from ~/.ssh/compose-farm (file) to
~/.ssh/compose-farm/id_ed25519 (file in directory).
This allows docker-compose to mount just the compose-farm directory
to /root/.ssh without exposing all host SSH keys to the container.
Also make host path the default option in docker-compose.yml with
clearer comments about the two options.
* docs: Update README for new SSH key directory structure
* docs: Clarify cf ssh setup must run inside container
Use run_parallel_with_progress for visual feedback during host checks.
Results are now sorted alphabetically for consistent output.
Also adds code style rule to CLAUDE.md about keeping imports at top level.
When triggering Apply or Refresh from the command palette on a non-dashboard
page, navigate to the dashboard first and then execute the action, opening
the terminal output.
* fix(web): Fix console page not initializing on HTMX navigation
Move inline script from {% block scripts %} to inside {% block content %}
so it's included in HTMX swaps. The script block was outside #main-content,
so hx-select="#main-content" was discarding it during navigation.
Also wrap script in IIFE to prevent let re-declaration errors when
navigating back to the console page.
* refactor(web): Simplify console script using var instead of IIFE
Local shell sessions weren't receiving SIGINT (Ctrl+C) because the PTY
wasn't set as the controlling terminal. Add preexec_fn that calls
setsid() and TIOCSCTTY to properly set up the terminal.