From f990177df85b64066a397a3d5c41ca2c021ca6b1 Mon Sep 17 00:00:00 2001 From: alexbelgium Date: Wed, 15 Jul 2026 14:32:35 +0200 Subject: [PATCH 1/2] fix(claude_desktop): resolve headroom binary via PATH in claude wrapper The /usr/local/bin/claude wrapper hardcoded HEADROOM_BIN as /usr/local/bin/headroom, but the binary is installed at /usr/bin/headroom (symlink to /lsiopy/bin/headroom). The -x check therefore always failed and terminal Claude Code sessions never routed through the Headroom proxy at 127.0.0.1:8787. Resolve the binary with "command -v headroom" instead; an empty result still fails the -x check safely and falls back to launching Claude Code directly. Co-Authored-By: Claude Fable 5 --- claude_desktop/CHANGELOG.md | 4 ++++ claude_desktop/config.yaml | 2 +- claude_desktop/rootfs/usr/local/bin/claude | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/claude_desktop/CHANGELOG.md b/claude_desktop/CHANGELOG.md index c92bbdc23e..1729842d4d 100644 --- a/claude_desktop/CHANGELOG.md +++ b/claude_desktop/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.24 (15-07-2026) + +- Fix the `/usr/local/bin/claude` wrapper never routing terminal Claude Code sessions through the Headroom proxy: it hardcoded `HEADROOM_BIN="/usr/local/bin/headroom"` while the binary is installed at `/usr/bin/headroom`, so the executable check always failed and the wrapper fell back to launching Claude Code directly. Resolve the binary with `command -v headroom` instead. + ## 1.23 (15-07-2026) - Add a `ha-cli` helper that lets Claude configure Home Assistant (automations, scripts, scenes, helpers, dashboards, area/label/floor/entity registries, and service calls) through the Home Assistant Core API instead of a filesystem mount. It authenticates automatically with the add-on's `SUPERVISOR_TOKEN` via the Supervisor Core-API proxy (no token setup), and deliberately cannot reach `configuration.yaml`/`secrets.yaml` or other add-ons' credentials. Toggle with the new `enable_ha_api_helper` option (default on), which also controls a managed guidance block appended to `~/.claude/CLAUDE.md`. diff --git a/claude_desktop/config.yaml b/claude_desktop/config.yaml index 39dc679aaa..e2b62075d2 100644 --- a/claude_desktop/config.yaml +++ b/claude_desktop/config.yaml @@ -105,5 +105,5 @@ slug: claude_desktop tmpfs: true udev: true url: https://github.com/alexbelgium/hassio-addons -version: "1.23" +version: "1.24" video: true diff --git a/claude_desktop/rootfs/usr/local/bin/claude b/claude_desktop/rootfs/usr/local/bin/claude index ec56d152be..f928a846c3 100644 --- a/claude_desktop/rootfs/usr/local/bin/claude +++ b/claude_desktop/rootfs/usr/local/bin/claude @@ -3,7 +3,7 @@ set -o pipefail REAL_CLAUDE="/usr/bin/claude" -HEADROOM_BIN="/usr/local/bin/headroom" +HEADROOM_BIN="$(command -v headroom || true)" HEADROOM_URL="http://127.0.0.1:8787" PERMISSION_MODE="$(bashio::config 'permission_mode')" declare -a CLAUDE_PERMISSION_ARGS=() From 7d2c6eb9b2ea805088428e3e46933711f4078c3a Mon Sep 17 00:00:00 2001 From: alexbelgium Date: Wed, 15 Jul 2026 14:42:41 +0200 Subject: [PATCH 2/2] fix(claude_desktop): self-heal TokenSave graph against corruption on startup The startup indexer chose init vs sync purely on whether .tokensave/tokensave.db existed, so an interrupted init or a hard add-on stop mid-write could leave a partial or malformed SQLite graph that every subsequent boot then ran `sync` against, failing (and staying broken) forever. Prepare each configured repo defensively instead: - serialize the operation under a startup-scoped flock so an overlapping restart or a mid-boot git post-commit/checkout sync hook can't write the same DB concurrently; - refresh an existing index with a retried incremental sync, since SQLITE_BUSY from lock contention is transient, not corruption; - quarantine a genuinely unreadable index (sync still failing after retries) or a half-written one (an interrupted init, detected via a sentinel file) to .tokensave/corrupt-/ and rebuild from scratch, so the graph self-heals rather than propagating corruption. All file operations run as the abc runtime user because the repo .tokensave directory is outside this script's final ownership pass. Co-Authored-By: Claude Fable 5 --- claude_desktop/CHANGELOG.md | 1 + .../rootfs/etc/cont-init.d/82-claude_tools.sh | 67 ++++++++++++++++--- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/claude_desktop/CHANGELOG.md b/claude_desktop/CHANGELOG.md index 1729842d4d..1ea78aa7d0 100644 --- a/claude_desktop/CHANGELOG.md +++ b/claude_desktop/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.24 (15-07-2026) - Fix the `/usr/local/bin/claude` wrapper never routing terminal Claude Code sessions through the Headroom proxy: it hardcoded `HEADROOM_BIN="/usr/local/bin/headroom"` while the binary is installed at `/usr/bin/headroom`, so the executable check always failed and the wrapper fell back to launching Claude Code directly. Resolve the binary with `command -v headroom` instead. +- Harden startup TokenSave indexing so an interrupted `init`/`sync` or a hard add-on stop can no longer leave a corrupt semantic graph that fails every subsequent boot. Each configured repository is now prepared under a startup-scoped `flock` (serialised against overlapping restarts and mid-boot git sync hooks); an existing index is refreshed with a retried incremental `sync` (transient `SQLITE_BUSY` no longer looks like corruption); and only a genuinely unreadable index — or a half-written one flagged by an `init` sentinel — is quarantined to `.tokensave/corrupt-/` and rebuilt from scratch, so the graph self-heals instead of propagating corruption. ## 1.23 (15-07-2026) diff --git a/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh b/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh index 03c343c1f6..be0f65cca4 100755 --- a/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh +++ b/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh @@ -193,15 +193,64 @@ if $TOKENSAVE_ENABLED; then fi TOKENSAVE_REPOS_SEEN[$repo_root]=1 - if [ -f "$repo_root/.tokensave/tokensave.db" ]; then - bashio::log.info "Synchronizing TokenSave index: ${repo_root}" - run_as_runtime_user tokensave sync "$repo_root" \ - || bashio::log.warning "TokenSave sync failed for ${repo_root}" - else - bashio::log.info "Initializing TokenSave index: ${repo_root}" - run_as_runtime_user tokensave init "$repo_root" \ - || bashio::log.warning "TokenSave initialization failed for ${repo_root}" - fi + bashio::log.info "Preparing TokenSave index: ${repo_root}" + # Prepare the per-repo semantic graph defensively so a hard add-on stop or storage + # hiccup can never leave a broken index that fails every subsequent boot: + # * a startup-scoped flock serializes against an overlapping restart (and any git + # post-commit/checkout sync hook that fires mid-boot), so two writers never race; + # * an existing index is refreshed with a cheap incremental `sync`, retried a few + # times because SQLITE_BUSY under lock contention is transient, not corruption; + # * only a genuinely unreadable/malformed index (sync still failing after retries) + # or a half-written one from an interrupted `init` is quarantined and rebuilt, + # so the graph self-heals instead of propagating corruption; + # * `init` is bracketed by a sentinel file so an interrupted full build is detected + # as incomplete on the next start and rebuilt rather than trusted. + # All file operations run as the abc runtime user because the repo `.tokensave` + # directory is not covered by this script's final ownership pass. + # shellcheck disable=SC2016 # single-quoted on purpose: $1/$db/etc. expand in the abc shell + run_as_runtime_user bash -c ' + set -o pipefail + repo_root="$1" + ts_dir="$repo_root/.tokensave" + db="$ts_dir/tokensave.db" + lock="$ts_dir/.startup.lock" + initflag="$ts_dir/.init-incomplete" + mkdir -p "$ts_dir" + exec 9>"$lock" + if ! flock -n 9; then + echo "TokenSave: index busy for $repo_root; skipping startup sync" >&2 + exit 0 + fi + quarantine() { + stamp="$(date +%Y%m%d-%H%M%S)" + bdir="$ts_dir/corrupt-$stamp" + mkdir -p "$bdir" + for f in "$db" "$db-wal" "$db-shm"; do + [ -e "$f" ] && mv -f "$f" "$bdir/" 2>/dev/null || true + done + echo "TokenSave: quarantined suspect index to $bdir" >&2 + } + if [ -f "$db" ] && [ ! -f "$initflag" ]; then + attempt=1 + while :; do + tokensave sync "$repo_root" && exit 0 + [ "$attempt" -ge 3 ] && break + echo "TokenSave: sync attempt $attempt failed for $repo_root; retrying" >&2 + attempt=$((attempt + 1)) + sleep 2 + done + echo "TokenSave: sync failed after retries for $repo_root; rebuilding index" >&2 + quarantine + elif [ -f "$db" ]; then + echo "TokenSave: previous init did not finish for $repo_root; rebuilding index" >&2 + quarantine + fi + : > "$initflag" + tokensave init "$repo_root" && { rm -f "$initflag"; exit 0; } + echo "TokenSave: init failed for $repo_root; will retry on next start" >&2 + exit 1 + ' _ "$repo_root" \ + || bashio::log.warning "TokenSave preparation failed for ${repo_root}" done < <(bashio::config.array 'tokensave_project_paths') fi