Merge pull request #2865 from alexbelgium/fix/claude-wrapper-headroom-path

fix(claude_desktop): headroom wrapper path + TokenSave startup corruption hardening
This commit is contained in:
Alexandre
2026-07-15 14:58:12 +02:00
committed by GitHub
4 changed files with 65 additions and 11 deletions

View File

@@ -1,3 +1,8 @@
## 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-<timestamp>/` and rebuilt from scratch, so the graph self-heals instead of propagating corruption.
## 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`.

View File

@@ -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

View File

@@ -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

View File

@@ -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=()