diff --git a/package.json b/package.json index 141cf8005..5a5c096cc 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,13 @@ "description": "Native high-fidelity client for Qobuz™ subscribers on Linux with Hi-Fi audio support (uses the Qobuz API; not certified by Qobuz)", "type": "module", "scripts": { - "dev": "svelte-kit sync && vite dev --force", + "dev": "svelte-kit sync && vite dev", "dev:clean-runtime": "bash ./scripts/clean-dev-runtime.sh", + "dev:ghost-doctor": "bash ./scripts/dev-ghost-doctor.sh", + "dev:ghost-reset": "bash ./scripts/dev-ghost-doctor.sh --no-start", + "dev:ultra-restore": "bash ./scripts/dev-ultra-restore.sh", + "dev:ultra-reset": "bash ./scripts/dev-ultra-restore.sh --no-start", + "dev:ultra-full-reset": "bash ./scripts/dev-ultra-restore.sh --full --no-start", "dev:tauri": "./scripts/dev-with-env.sh", "build": "vite build", "preview": "vite preview", diff --git a/scripts/check-no-t-shadow.sh b/scripts/check-no-t-shadow.sh index 87f7d410e..8012957f9 100644 --- a/scripts/check-no-t-shadow.sh +++ b/scripts/check-no-t-shadow.sh @@ -20,20 +20,21 @@ check_pattern() { } # Template loop variable shadowing. -check_pattern "template each-loop shadowing (as t)" '\{#each[^\n]* as t\b' +check_pattern "template each-loop shadowing (as t)" '\{#each[^\n]*\bas t\b' -# Dangerous callbacks in files using $t(...). -while IFS= read -r file; do - if rg -q '\b(map|forEach|filter|find|some|every|reduce)\(\s*t\s*=>|\b(map|forEach|filter|find|some|every|reduce)\(\s*\(\s*t\b[^)]*\)\s*=>|\b(map|forEach|filter|find|some|every|reduce)\(\s*\([^)]*,\s*t\b[^)]*\)\s*=>' "${file}"; then - echo - echo "Found callback shadowing in file using \$t(...): ${file}" - rg -n '\b(map|forEach|filter|find|some|every|reduce)\(\s*t\s*=>|\b(map|forEach|filter|find|some|every|reduce)\(\s*\(\s*t\b[^)]*\)\s*=>|\b(map|forEach|filter|find|some|every|reduce)\(\s*\([^)]*,\s*t\b[^)]*\)\s*=>' "${file}" - had_issues=1 - fi -done < <(rg -l --glob '*.svelte' '\$t\(' "${SRC_DIR}") +# Plain variable/function-loop names using `t`. +check_pattern "variable declaration named t" '\b(const|let|var)\s+t\b' +check_pattern "for-loop variable named t" 'for\s*\(\s*(const|let|var)\s+t\b' -# Any $derived expression using variable name t. -check_pattern "usage of t inside \$derived" '\$derived\([^)]*\bt\b' +# Callback parameters named `t` (single or parenthesized). +check_pattern "arrow callback parameter named t" '\bt\s*=>|\(\s*t(?:\s*:[^)]*)?\s*\)\s*=>|\(\s*[^,)]*,\s*t(?:\s*:[^)]*)?\s*\)\s*=>' + +# get(t) is fragile in Svelte files that import i18n store `t`. +check_pattern "get(t) usage in .svelte files" '\bget\s*\(\s*t\s*\)' + +# Lightweight same-line checks for $derived expressions. +check_pattern "store translation access inside \$derived (same line)" '\$derived(?:\.by)?\([^)]*(\$t\(|get\(t\))' +check_pattern "usage of t inside \$derived (same line)" '\$derived(?:\.by)?\([^)]*\bt\b' if [[ "${had_issues}" -ne 0 ]]; then diff --git a/scripts/clean-dev-runtime.sh b/scripts/clean-dev-runtime.sh index daeba34b1..f5e66107c 100755 --- a/scripts/clean-dev-runtime.sh +++ b/scripts/clean-dev-runtime.sh @@ -26,3 +26,6 @@ done rm -rf .svelte-kit .vite node_modules/.vite build dist .cache echo "[qbz] Dev runtime cleaned (processes + ports 1420/1421 + cache directories)." + +# Run guardrail check so runtime clean does not hide code-level ghost triggers. +bash ./scripts/check-no-t-shadow.sh diff --git a/scripts/dev-ghost-doctor.sh b/scripts/dev-ghost-doctor.sh new file mode 100755 index 000000000..89422370f --- /dev/null +++ b/scripts/dev-ghost-doctor.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "${ROOT_DIR}" + +NO_START=false +if [[ "${1:-}" == "--no-start" ]]; then + NO_START=true +fi + +echo "[qbz] Ghost doctor: checking for t-shadow and fragile i18n patterns..." +bash ./scripts/check-no-t-shadow.sh + +echo "[qbz] Ghost doctor: cleaning runtime state..." +bash ./scripts/clean-dev-runtime.sh + +if [[ "${NO_START}" == "true" ]]; then + echo "[qbz] Ghost doctor complete (no-start mode)." + exit 0 +fi + +echo "[qbz] Ghost doctor: starting tauri dev in foreground..." +exec npm run tauri dev diff --git a/scripts/dev-ultra-restore.sh b/scripts/dev-ultra-restore.sh new file mode 100755 index 000000000..d80a90dd7 --- /dev/null +++ b/scripts/dev-ultra-restore.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "${ROOT_DIR}" + +FULL=false +NO_START=false +RUN_CHECK=false + +for arg in "$@"; do + case "$arg" in + --full|-f) + FULL=true + ;; + --no-start) + NO_START=true + ;; + --check) + RUN_CHECK=true + ;; + *) + echo "[qbz] Unknown option: ${arg}" + echo "Usage: bash ./scripts/dev-ultra-restore.sh [--full|-f] [--no-start] [--check]" + exit 1 + ;; + esac +done + +echo "[qbz] Ultra restore: stopping dev processes..." +pkill -f '[n]ode .*vite dev' || true +pkill -f '[n]ode .*tauri dev' || true +pkill -f '[c]argo run' || true +pkill -f '[t]arget/debug/qbz' || true +pkill -f '[t]arget/debug/qbz-nix' || true + +echo "[qbz] Ultra restore: freeing dev ports..." +for port in 1420 1421; do + pids="$(lsof -ti :"${port}" -sTCP:LISTEN 2>/dev/null || true)" + if [[ -n "${pids}" ]]; then + kill ${pids} 2>/dev/null || true + sleep 0.5 + still_alive="$(lsof -ti :"${port}" -sTCP:LISTEN 2>/dev/null || true)" + if [[ -n "${still_alive}" ]]; then + kill -9 ${still_alive} 2>/dev/null || true + fi + fi +done + +echo "[qbz] Ultra restore: clearing frontend caches..." +rm -rf \ + .svelte-kit \ + .vite \ + build \ + dist \ + .cache \ + node_modules/.vite \ + node_modules/.vite_temp \ + node_modules/.svelte \ + node_modules/.cache \ + node_modules/.postcss \ + tsconfig.tsbuildinfo \ + .eslintcache + +echo "[qbz] Ultra restore: clearing temp vite directories..." +rm -rf /tmp/vite-* 2>/dev/null || true + +if [[ "${FULL}" == "true" ]]; then + echo "[qbz] Ultra restore: full mode enabled (Rust/Tauri clean)..." + rm -rf src-tauri/target/debug/.fingerprint src-tauri/target/debug/incremental + if command -v cargo >/dev/null 2>&1; then + cargo clean --manifest-path src-tauri/Cargo.toml || true + fi +fi + +echo "[qbz] Ultra restore: running ghost guard checks..." +bash ./scripts/check-no-t-shadow.sh + +if [[ "${RUN_CHECK}" == "true" ]]; then + echo "[qbz] Ultra restore: running svelte-check..." + npm run -s check +fi + +if [[ "${NO_START}" == "true" ]]; then + echo "[qbz] Ultra restore complete (no-start mode)." + exit 0 +fi + +echo "[qbz] Ultra restore: starting tauri dev in foreground..." +exec npm run tauri dev