is_valid_image compared path.suffix (case-preserved) against a
lowercase extension list, so a wallpaper file named e.g. .JPG or .PNG
(common from phone cameras/screenshots) was rejected and set_wallpaper
raised before writing wallpaper_path_path -- silently failing to
persist the wallpaper.
* feat: add shell -r/--restart for race-free shell restarts
Kills any running instance, waits for it to actually disappear from
`qs list`, then starts the shell. Escalates to SIGKILL if the instance
does not exit gracefully within 5s.
Closes#139
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* shell: fail loudly when listing instances fails
Addresses review feedback on the restart path.
`list_instances` returned [] for three different outcomes: no instances,
`qs list` failing, and unparseable output. `wait_for_exit` reads [] as
"the old shell is gone", so a failure there would relaunch with `-n` and
no-op, reintroducing the bug this fixes. Now only the real "no instances"
case returns [], and the rest abort.
`qs list -j` prints a plain text notice to stdout and still exits 0 when
nothing is running, so an empty-stdout check does not detect it.
Also re-snapshot instances before SIGKILL, as the pre-kill list is stale
after waiting 5s and the PIDs may have been reused; abort instead of
warning if an instance survives SIGKILL; and pass check=False explicitly
on the kill for PLW1510.
Co-Authored-By: dxnnv <76127109+dxnnv@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* shell: silence the kill instead of capturing its output
`qs kill` writes "Killed <id>" to stdout, which would show up on every
restart. That was suppressed with capture_output, which reads as if the
output is wanted when it is only being discarded. Redirect stdout to
DEVNULL instead, and leave stderr alone so a real failure still surfaces.
Also drop the session lock aside from the teardown comment; it explains
why the flag exists, not why the wait is there.
Co-Authored-By: soramanew <61896496+soramanew@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* shell: kill every instance gracefully, not just one
`qs kill` without `--pid` only kills a single instance, so a user who had
started a second shell by hand got a graceful kill for one of them and a
SIGKILL for the rest. Target each instance by pid so the graceful and the
force path act on the same set.
The pid extraction moves to `instance_pids()` so both loops read from one
place; that also makes the `KeyError` guard on the SIGKILL redundant.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HC13Dj4qfrhwa7SN4VFUCF
* shell: share the stop and start paths between kill and restart
`--kill` now goes through `stop_instances()` so it terminates the same
set of instances `--restart` does, instead of a bare `qs kill` that only
picks one. The start logic moves into `start_shell()` and restart becomes
its own dispatch branch, leaving `run()` as pure dispatch.
Drop the `"pid" in instance` filter: quickshell always serializes a pid,
and skipping an instance without one only delays the failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wg4NVaizjEuQhgVEZPFExh
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: dxnnv <76127109+dxnnv@users.noreply.github.com>
Co-authored-by: soramanew <61896496+soramanew@users.noreply.github.com>