diff --git a/CHANGELOG.md b/CHANGELOG.md index fedb838..bb4ded8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [6.0.11] - 2026-04-10 + +### Fixed +- **Idempotenter Bun-Installer** — `install.sh` und `install.bat` bereinigen vor `bun add -g file:...` jetzt vorhandene `ttdash`-Einträge aus Bun’s globalem Manifest und löschen bei Bedarf das fehlerhafte globale `bun.lock`, damit wiederholte Upgrades keine doppelten `package.json`-Keys mehr erzeugen + ## [6.0.10] - 2026-04-09 ### Added diff --git a/install.bat b/install.bat index bec1387..3124e3d 100644 --- a/install.bat +++ b/install.bat @@ -1,11 +1,15 @@ @echo off setlocal enabledelayedexpansion +set "SCRIPT_DIR=%~dp0" +cd /d "%SCRIPT_DIR%" || exit /b 1 set "INSTALL_TOOL=npm" set "BUILD_TOOL=npm" set "GLOBAL_TOOL=npm" set "APP_VERSION=unbekannt" +set "APP_NAME=ttdash" for /f "usebackq delims=" %%v in (`powershell -NoProfile -Command "(Get-Content -Raw 'package.json' | ConvertFrom-Json).version"`) do set "APP_VERSION=%%v" +for /f "usebackq delims=" %%n in (`powershell -NoProfile -Command "(Get-Content -Raw 'package.json' | ConvertFrom-Json).name"`) do set "APP_NAME=%%n" echo. echo ttdash v%APP_VERSION% installer @@ -70,6 +74,18 @@ echo √ Build abgeschlossen (dist/) echo. echo [3/3] Installiere global... if /i "%GLOBAL_TOOL%"=="bun" ( + for /f "usebackq delims=" %%p in (`bun pm bin -g 2^>nul`) do set "BUN_GLOBAL_BIN=%%p" + if defined BUN_GLOBAL_BIN ( + for %%d in ("%BUN_GLOBAL_BIN%\..") do set "BUN_ROOT=%%~fd" + set "BUN_GLOBAL_PACKAGE_JSON=%BUN_ROOT%\install\global\package.json" + set "BUN_GLOBAL_LOCKFILE=%BUN_ROOT%\install\global\bun.lock" + set "BUN_CLEANUP_STATUS=" + for /f "usebackq delims=" %%s in (`bun --eval "const fs = require('fs'); const file = process.env.BUN_GLOBAL_PACKAGE_JSON; const name = process.env.APP_NAME; if (!file || !fs.existsSync(file)) { console.log('clean'); process.exit(0); } const raw = fs.readFileSync(file, 'utf8'); const parsed = JSON.parse(raw); const deps = { ...(parsed.dependencies || {}) }; const hadEntry = Object.prototype.hasOwnProperty.call(deps, name); if (hadEntry) { delete deps[name]; } const next = { ...parsed }; if (Object.keys(deps).length > 0) { next.dependencies = deps; } else { delete next.dependencies; } const normalized = JSON.stringify(next, null, 2) + '\n'; const normalizedChanged = raw !== normalized; if (normalizedChanged || hadEntry) { fs.writeFileSync(file, normalized); } if (hadEntry) { console.log('removed'); } else if (normalizedChanged) { console.log('normalized'); } else { console.log('clean'); }" 2^>nul`) do set "BUN_CLEANUP_STATUS=%%s" + if /i not "!BUN_CLEANUP_STATUS!"=="clean" ( + if exist "%BUN_GLOBAL_LOCKFILE%" del /f /q "%BUN_GLOBAL_LOCKFILE%" >nul 2>&1 + echo - Vorhandenen Bun-Globaleintrag fuer %APP_NAME% bereinigt + ) + ) echo - Versuche bun add -g file:%cd% call bun add -g file:%cd% >nul 2>&1 if !errorlevel! neq 0 ( diff --git a/install.sh b/install.sh index 3458680..f12fd65 100755 --- a/install.sh +++ b/install.sh @@ -13,19 +13,95 @@ step=0 total=3 install_tool="npm" global_tool="npm" -version="$(sed -n 's/.*"version": "\(.*\)".*/\1/p' package.json | head -1)" +script_source="${BASH_SOURCE[0]:-$0}" +script_dir="$(cd "$(dirname "$script_source")" && pwd)" +manifest_file="$script_dir/package.json" +version="$(sed -n 's/.*"version": "\(.*\)".*/\1/p' "$manifest_file" | head -1)" +package_name="$(sed -n 's/.*"name": "\(.*\)".*/\1/p' "$manifest_file" | head -1)" if [ -z "$version" ]; then version="unbekannt" fi +if [ -z "$package_name" ]; then + package_name="ttdash" +fi + info() { step=$((step + 1)); printf "\n${BLUE}${BOLD}[$step/$total]${NC} %s\n" "$1"; } ok() { printf " ${GREEN}✓${NC} %s\n" "$1"; } fail() { printf " ${RED}✗${NC} %s\n" "$1"; exit 1; } warn() { printf " ${RED}!${NC} %s\n" "$1"; } note() { printf " ${DIM}› %s${NC}\n" "$1"; } -cd "$(dirname "$0")" +prepare_bun_global_install() { + local bun_global_bin_dir bun_root bun_global_dir bun_global_package_json bun_global_lock cleanup_status + + bun_global_bin_dir="$(bun pm bin -g 2>/dev/null || true)" + if [ -z "$bun_global_bin_dir" ]; then + return 0 + fi + + bun_root="$(dirname "$bun_global_bin_dir")" + bun_global_dir="$bun_root/install/global" + bun_global_package_json="$bun_global_dir/package.json" + bun_global_lock="$bun_global_dir/bun.lock" + + if [ ! -f "$bun_global_package_json" ]; then + return 0 + fi + + cleanup_status="$( + BUN_GLOBAL_PACKAGE_JSON="$bun_global_package_json" \ + BUN_PACKAGE_NAME="$package_name" \ + bun --eval 'const fs = require("fs"); +const file = process.env.BUN_GLOBAL_PACKAGE_JSON; +const name = process.env.BUN_PACKAGE_NAME; +const raw = fs.readFileSync(file, "utf8"); +const parsed = JSON.parse(raw); +const deps = { ...(parsed.dependencies || {}) }; +const hadEntry = Object.prototype.hasOwnProperty.call(deps, name); + +if (hadEntry) { + delete deps[name]; +} + +const next = { ...parsed }; +if (Object.keys(deps).length > 0) { + next.dependencies = deps; +} else { + delete next.dependencies; +} + +const normalized = JSON.stringify(next, null, 2) + "\n"; +const normalizedChanged = raw !== normalized; + +if (normalizedChanged || hadEntry) { + fs.writeFileSync(file, normalized); +} + +if (hadEntry) { + console.log("removed"); +} else if (normalizedChanged) { + console.log("normalized"); +} else { + console.log("clean"); +}' + )" || { + warn "Vorhandener Bun-Globaleintrag konnte nicht bereinigt werden" + return 0 + } + + if [ "$cleanup_status" = "clean" ]; then + return 0 + fi + + note "Bereinige vorhandenen Bun-Globaleintrag für $package_name" + if [ -f "$bun_global_lock" ]; then + rm -f "$bun_global_lock" + fi +} + +cd "$script_dir" printf "${BOLD}ttdash v%s${NC} installer\n" "$version" printf "${DIM}%s${NC}\n" "$(pwd)" @@ -79,6 +155,7 @@ fi # 3 — Global install info "Installiere global..." if [ "$global_tool" = "bun" ]; then + prepare_bun_global_install note "Versuche globale Installation mit bun add -g file:$(pwd)" if bun add -g "file:$(pwd)" 2>&1 | tail -1; then ok "Global via Bun installiert" diff --git a/package-lock.json b/package-lock.json index 187dc93..96623b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ttdash", - "version": "6.0.10", + "version": "6.0.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ttdash", - "version": "6.0.10", + "version": "6.0.11", "license": "MIT", "dependencies": { "i18next": "^26.0.3", diff --git a/package.json b/package.json index 859654e..cc71885 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ttdash", - "version": "6.0.10", + "version": "6.0.11", "description": "Local dashboard for toktrack usage data", "main": "server.js", "repository": { diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 62cdd0c..9526ae3 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,4 +1,4 @@ -export const VERSION = '6.0.10' +export const VERSION = '6.0.11' export const MODEL_COLORS: Record = { 'Opus 4.6': 'hsl(262, 60%, 55%)',