aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-28 12:58:42 +0200
committerDanilo M. <danix@danix.xyz>2026-09-28 12:58:42 +0200
commit183dfe3ae34418653aca3d20628b3938c8348c2a (patch)
treec40b09c65d0ee0aa390cbb34a634f0b98c07febc
parentc873e3ca7b51ce159cbfac5f9635d67e542c4c0a (diff)
downloaddesktop-assistant-183dfe3ae34418653aca3d20628b3938c8348c2a.tar.gz
desktop-assistant-183dfe3ae34418653aca3d20628b3938c8348c2a.zip
Replace restart.sh with assistant.sh start|stop|restart|status
start leaves a running assistant or overlay alone and starts only what is missing; restart is the old restart.sh. status lists each process with its uptime, memory and children, a stray arecord left by a dead assistant, the socket, the presentation/gaming pause flags and the log's last lines, and exits 1 if either process is down. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--AGENTS.md6
-rw-r--r--README.md5
-rwxr-xr-xassistant.sh94
-rwxr-xr-xrestart.sh50
4 files changed, 101 insertions, 54 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 2022166..770be39 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -16,7 +16,7 @@ built-in settings. Examples in `examples/`. STT, LLM and TTS stay local;
only the weather and search tools reach the network, and only when a
question needs them. Spec: `docs/superpowers/specs/2026-09-26-tools-and-config-design.md`.
-Run: `python3 assistant.py` (`--test` for the self-check), or `./restart.sh`
+Run: `python3 assistant.py` (`--test` for the self-check), or `./assistant.sh restart`
to replace a running one (and its overlay) detached from the terminal.
---
@@ -542,8 +542,8 @@ pending. Parses the 2.1 MB ChangeLog in ~95 ms, so no announcement.
in `MD_EDITOR` (typora in the user's config), detached.
- Live: counts, security fixes and "kernel 7.2.7" spoken, then it offered
the recap on its own; "si" opened it (2.2 s).
-- The overlay did not show after `restart.sh` started it together with the
- assistant: quickshell's `Socket` never retries a failed connect. Fixed in
+- The overlay did not show after `restart.sh` (now `assistant.sh`)
+ started it together with the assistant: quickshell's `Socket` never retries a failed connect. Fixed in
the quickshell repo (fresh `Socket` per retry), which also covers login,
where the overlay starts first.
diff --git a/README.md b/README.md
index 69fe21f..c6d6f2f 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,10 @@ Paths, the card name, ports and voices can be changed in `config.toml`, see
```sh
python3 assistant.py # run
python3 assistant.py --test # self-check
-./restart.sh # stop a running one, start detached
+./assistant.sh start # detached, with the overlay
+./assistant.sh stop
+./assistant.sh restart # stop a running one, start again
+./assistant.sh status
```
## Configuration and tools
diff --git a/assistant.sh b/assistant.sh
new file mode 100755
index 0000000..e288afd
--- /dev/null
+++ b/assistant.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# desktop-assistant: start, stop, restart or check the voice loop.
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# assistant.sh start|stop|restart|status
+#
+# stop: SIGTERM any running assistant.py (whisper-server and amixer die
+# with it through PDEATHSIG), SIGKILL after 10 s; same for the quickshell
+# overlay (OVERLAY, default the quickshell repo next to this one).
+# start: run both in their own session, detached from the terminal,
+# logging where the Hyprland autostart does; does nothing for one already
+# running. restart: stop, then start. status: processes, children, stray
+# recorders, socket, pause flags and the log's tail; exit 1 if either is
+# down. Run it from the login session: it needs its
+# audio, bus, Wayland display and XDG_RUNTIME_DIR.
+
+set -eu
+
+dir=$(cd "$(dirname "$0")" && pwd)
+log="${XDG_RUNTIME_DIR:?not in a login session}/desktop-assistant.log"
+overlay=$(realpath -m "${OVERLAY:-$dir/../quickshell/assistant}")
+pat='^\S*python3 (-u )?\S*assistant\.py'
+qpat="^qs -p $overlay\$"
+
+kill_wait() {
+ pkill -u "$USER" -f "$1" || return 0
+ for _ in $(seq 50); do
+ pgrep -u "$USER" -f "$1" >/dev/null || return 0
+ sleep 0.2
+ done
+ pkill -KILL -u "$USER" -f "$1" && sleep 0.5 || true
+}
+
+running() { pgrep -u "$USER" -f "$1" >/dev/null; }
+
+stop() {
+ kill_wait "$pat"
+ kill_wait "$qpat"
+}
+
+start() {
+ cd "$dir"
+ running "$pat" || setsid -f python3 -u "$dir/assistant.py" >>"$log" 2>&1 </dev/null
+ running "$qpat" || setsid -f qs -p "$overlay" >/dev/null 2>&1 </dev/null
+ sleep 0.5
+ status
+}
+
+show() {
+ local pid
+ pid=$(pgrep -u "$USER" -of "$2") || { echo "$1: not running"; return 1; }
+ echo "$1: running"
+ ps -o pid=,etime=,rss=,args= -p "$pid" |
+ awk '{ printf " pid %s, up %s, %d MB\n %s", $1, $2, $3 / 1024, $4
+ for (i = 5; i <= NF; i++) printf " %s", $i; print "" }'
+ [ "$1" = assistant ] || return 0
+ pgrep -a -P "$pid" | sed 's/^/ child /'
+}
+
+status() {
+ local rc=0 f
+ show assistant "$pat" || rc=1
+ show overlay "$qpat" || rc=1
+ # Children get PDEATHSIG; one left over means the assistant died under it.
+ pgrep -u "$USER" -af "^arecord .*desktop-assistant\.raw" | sed 's/^/stray: /' || true
+ [ -S "$XDG_RUNTIME_DIR/desktop-assistant.sock" ] && echo "socket: present" || echo "socket: missing"
+ for f in presentation gaming; do
+ [ "$(cat "$XDG_RUNTIME_DIR/status.$f" 2>/dev/null)" = 1 ] && echo "paused: $f mode on"
+ done
+ echo "log: $log"
+ tail -n 5 "$log" 2>/dev/null | sed 's/^/ /'
+ return $rc
+}
+
+case "${1:-}" in
+ start) start ;;
+ stop) stop ;;
+ restart) stop; start ;;
+ status) status ;;
+ *) echo "usage: $0 start|stop|restart|status" >&2; exit 2 ;;
+esac
diff --git a/restart.sh b/restart.sh
deleted file mode 100755
index 24dd5ea..0000000
--- a/restart.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-# desktop-assistant: restart the voice loop, detached from the terminal.
-# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 as published
-# by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# restart.sh: SIGTERM any running assistant.py (whisper-server and amixer
-# die with it through PDEATHSIG), SIGKILL after 10 s, then start a new one
-# in its own session, logging where the Hyprland autostart does. The
-# quickshell overlay (OVERLAY, default the quickshell repo next to this one)
-# is restarted the same way. Run it from the login session: it needs its
-# audio, bus, Wayland display and XDG_RUNTIME_DIR.
-
-set -eu
-
-dir=$(cd "$(dirname "$0")" && pwd)
-log="${XDG_RUNTIME_DIR:?not in a login session}/desktop-assistant.log"
-overlay=$(realpath -m "${OVERLAY:-$dir/../quickshell/assistant}")
-pat='^\S*python3 (-u )?\S*assistant\.py'
-qpat="^qs -p $overlay\$"
-
-stop() {
- pkill -u "$USER" -f "$1" || return 0
- for _ in $(seq 50); do
- pgrep -u "$USER" -f "$1" >/dev/null || return 0
- sleep 0.2
- done
- pkill -KILL -u "$USER" -f "$1" && sleep 0.5 || true
-}
-
-stop "$pat"
-stop "$qpat"
-
-cd "$dir"
-setsid -f python3 -u "$dir/assistant.py" >>"$log" 2>&1 </dev/null
-setsid -f qs -p "$overlay" >/dev/null 2>&1 </dev/null
-sleep 0.5
-pgrep -u "$USER" -af "$pat" || { echo "assistant not running, see $log" >&2; exit 1; }
-pgrep -u "$USER" -af "$qpat" || { echo "overlay not running: qs -p $overlay" >&2; exit 1; }