go-hid's ReadWithTimeout takes a time.Duration, so the bare 250 was
250ns, which truncates to a 0 ms hid_read_timeout. On both Linux
(poll) and macOS (cond_timedwait) 0 ms means non-blocking, so the
button loop spun continuously: ~1.2 cores and ~7.5k context
switches/sec at idle, from startup.
Pass 250*time.Millisecond and match hid.ErrTimeout with errors.Is
ahead of the string fallback. Idle CPU drops to ~0%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yH8jHn1SNzNnL58CRwTi9
Add "; charset=utf-8" to the JSON Content-Type header so Slack's
users.profile.set no longer returns the missing_charset warning.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce a per-key `text_command` + `refresh` feature: the service
periodically runs a shell command and renders its stdout as the key's
text overlay, compositing over the base icon (or a black background for
text-only keys) each tick. `text` acts as the static fallback shown
before the first run or when the command errors/outputs nothing. A
refresh goroutine owns the key's image and also handles an optional poll
block (choosing icon_true/icon_false per tick). Adds `$(...)` sugar in
`text` as shorthand for `text_command`.
- internal/config: add TextCommand/Refresh fields to KeyConfig
- cmd/streamdeck: refreshTextKey goroutine, runTextCommand, unwrapCmdSubst
- config.example.yaml: document the feature with a `flow` pomodoro
live-countdown example (status --short, toggle/skip/stop/gui)
- modules.example.yaml: example config updates
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEoLyNbtbjbDq7aTWAymUG
system_profiler SPUSBDataType was silently omitting the deck on some Macs
(watchdog exited early, never restarted anything) and, when it did report,
the trailing bus number in "Location ID: X / N" flapped without an actual
replug — causing spurious restarts. ioreg sees the device reliably and
sessionID changes only on real re-enumeration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The grigio/obs-cmd v1.0.0 release ships Linux builds as
obs-cmd-x64-linux.tar.gz; the old obs-cmd-v-x86_64-unknown-linux-musl.tar.gz
name no longer exists and curl was piping a 404 page into tar.
- Treat "timeout" and "interrupted system call" from ReadWithTimeout as
non-fatal — hidraw on Linux returns errors instead of (0, nil) for
both, causing false device-dead detection and reconnect loops
- Resolve icons_dir relative to the config file when the path is not
absolute, so the service finds icons regardless of working directory
- Installer now copies bundled icons to the config dir on first install
- install.sh: detects pacman/apt/dnf/zypper, installs Go and hidapi if
absent, prompts for dotfiles dir and creates ~/.config symlink
- Makefile: wire `make install` to install.sh
- README: document interactive install flow and dotfiles tree structure