Files
hassio-addons/.claude/skills/hassio-addon-workflow/scripts/preflight.sh
Alexandre 74456a03b6 chore: add hassio-addon-workflow skill for Claude Code (#2939)
* chore: add hassio-addon-workflow skill for Claude Code

Checks in the repo-specific skill so future Claude Code sessions get the
tiered scope->measure->plan->implement->verify workflow, repo traps, and
helper scripts (preflight/measure/env_trace/validate/pr_review) without
depending on a local machine's ~/.claude config.

* fix(skill): address PR review feedback from Copilot and Codex

- SKILL.md: repo-relative script invocation (skill is now checked in);
  correct the CI-gates list — the PR add-on linter is blocking, only the
  weekly Super-Linter is non-blocking
- preflight.sh: git-aware repo detection (worktrees have a .git file)
- pr_review.sh: header now documents resolve's actual --all behavior
- measure.sh: CPU% uses getconf CLK_TCK; sample all processes, not the
  top-24 by RSS
- env_trace.sh: validate VAR as a strict env-var name before regex use
- validate.sh: shellcheck also covers extensionless run/finish; --vs-master
  skips visibly when a linter is missing instead of reporting a false clean

* fix(skill): address CodeRabbit review feedback

- pr_review.sh: resolve exits nonzero unless every thread actually
  resolved; watch exits nonzero and says so when checks settle with
  failures instead of reporting bare "settled"
- validate.sh: pass the config.yaml path to Python as argv instead of
  interpolating $ADDON into the source (CWE-94)
2026-08-04 22:29:20 +02:00

88 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Orient before starting add-on work: what tools exist, are we inside the running add-on, and
# — the one that actually bites — does the checkout match what is running?
#
# Usage: preflight.sh [repo-path] [addon-slug]
set -uo pipefail
REPO="${1:-/data/claude/hassio-addons}"
SLUG="${2:-}"
echo "== tools =="
for c in gh git codex rtk headroom tokensave shellcheck hadolint yamllint python3 jq; do
printf ' %-11s %s\n' "$c" "$(command -v "$c" > /dev/null 2>&1 && echo yes || echo MISSING)"
done
[ -x /data/codex/bin/codex-real ] && echo " codex-real yes (prefer: codex exec --model gpt-5.6-sol)"
echo
echo "== running add-on =="
if [ -n "${BUILD_VERSION:-}" ]; then
echo " BUILD_VERSION=$BUILD_VERSION HOME=${HOME:-?}"
echo " -> live measurement is possible; see measure.sh"
else
echo " not inside a running add-on (no BUILD_VERSION); source-only analysis"
fi
echo
echo "== repo =="
# git-aware check: in a worktree .git is a file, not a directory
if ! git -C "$REPO" rev-parse --git-dir > /dev/null 2>&1; then
echo " no git repo at $REPO"
exit 0
fi
cd "$REPO" || exit 0
branch=$(git branch --show-current 2> /dev/null || echo "(detached)")
echo " path=$REPO"
echo " branch=$branch"
# Another session may be mid-operation in this shared checkout.
echo " recent reflog (entries you did not make mean another session is active):"
git reflog --date=iso -3 2> /dev/null | sed 's/^/ /'
# The trap this exists for: a stale branch looks entirely normal.
if [ -n "${BUILD_VERSION:-}" ]; then
# Hostname is <8-hex>-<slug-with-dashes>. Anchor the hex to 8 chars: an unanchored
# [0-9a-f]* also eats real prefixes (dab-radio -> radio, cafe-monitor -> monitor).
# Slugs may legitimately contain dashes (birdnet-go), so try both forms.
if [ -z "$SLUG" ] && [ -n "${HOSTNAME:-}" ]; then
base=$(printf '%s' "$HOSTNAME" | sed 's/^[0-9a-f]\{8\}-//')
for cand in "$(printf '%s' "$base" | tr '-' '_')" "$base"; do
[ -f "$REPO/$cand/config.yaml" ] && { SLUG="$cand"; break; }
done
[ -z "$SLUG" ] && SLUG="$base"
fi
cfg="$REPO/$SLUG/config.yaml"
if [ ! -f "$cfg" ]; then
echo
echo " could not find $SLUG/config.yaml — pass the slug as \$2 to enable the"
echo " revision check (this is the check the script exists for)." >&2
exit 3
fi
if [ -f "$cfg" ]; then
here=$(grep -E '^version:' "$cfg" | head -1 | tr -d "\"'" | awk '{print $2}')
echo
echo " $SLUG/config.yaml version = $here"
echo " running image BUILD_VERSION = $BUILD_VERSION"
if [ "$here" = "$BUILD_VERSION" ]; then
echo " MATCH — this checkout corresponds to the running image."
else
echo " MISMATCH — this branch is NOT what is running."
git fetch origin master --quiet 2> /dev/null
master=$(git show origin/master:"$SLUG/config.yaml" 2> /dev/null |
grep -E '^version:' | head -1 | tr -d "\"'" | awk '{print $2}')
echo " origin/master version = ${master:-unknown}"
echo " -> work from origin/master; analysing this branch will mislead you."
echo
echo "== suggested isolated worktree (/tmp is noexec; use /data) =="
echo " git worktree add --detach /data/claude/.work/<task> origin/master"
echo " NOTE: never 'git stash' under /data/claude — refs/stash is shared."
exit 2
fi
fi
fi
echo
echo "== suggested isolated worktree (/tmp is noexec; use /data) =="
echo " git worktree add --detach /data/claude/.work/<task> origin/master"
echo " NOTE: never 'git stash' under /data/claude — refs/stash is shared across worktrees."