From fa827c6ee2a525eaca19ea7d1837b119be1817da Mon Sep 17 00:00:00 2001 From: nokternol Date: Mon, 9 Mar 2026 21:19:23 +0000 Subject: [PATCH 1/2] =?UTF-8?q?chore(dx):=20tighten=20feedback=20loop=20?= =?UTF-8?q?=E2=80=94=20root=20lint/test,=20husky=20gates,=20check.sh=20sig?= =?UTF-8?q?nal-to-noise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Root npm test composes both workspaces (api + web run their own vitest config, avoiding the Vite 5/6 hoisting conflict with Storybook) - Root npm lint runs biome check . for all files from one place - lint-staged: biome check --write on staged files, auto-restages safe fixes - .husky/pre-commit: lint-staged → tsc (api+web) → vitest (api+web); each step captures output and only prints on failure — failure message is the next action - check.sh rewritten: silent on pass, prints captured logs only for failed steps; summary line shows pass/fail/warn counts at a glance - apps/web/vitest.config.ts: use import.meta.dirname for alias path so config is CWD-agnostic when invoked from any directory - vitest added to root devDependencies (explicit, not relying on workspace hoist) Co-Authored-By: Claude Sonnet 4.6 --- .husky/pre-commit | 34 ++++++++++++++ apps/web/vitest.config.ts | 2 +- package-lock.json | 3 +- package.json | 8 +++- scripts/check.sh | 99 +++++++++++++++++++-------------------- 5 files changed, 91 insertions(+), 55 deletions(-) mode change 100644 => 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 index 2312dc5..343f586 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,35 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/_/husky.sh" + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +FAIL=0 + +# Run a check; capture output; print details only on failure +check() { + local name="$1"; shift + local out + out=$("$@" 2>&1) + local status=$? + if [ $status -eq 0 ]; then + printf '✅ %s\n' "$name" + else + printf '❌ %s\n' "$name" + printf '%s\n' "$out" + FAIL=$((FAIL + 1)) + fi +} + +# 1. Format + safe lint fixes on staged files — lint-staged auto-restages changes npx lint-staged + +# 2. Type safety — catches broken types before they reach CI +check 'TypeScript (api)' npm run typecheck --workspace=apps/api +check 'TypeScript (web)' npm run typecheck --workspace=apps/web + +# 3. Tests — each workspace runs its own vitest config +check 'Tests (api)' npm run test --workspace=apps/api +check 'Tests (web)' npm run test --workspace=apps/web + +[ $FAIL -eq 0 ] diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts index 7088741..2d9111a 100644 --- a/apps/web/vitest.config.ts +++ b/apps/web/vitest.config.ts @@ -6,7 +6,7 @@ export default defineConfig({ plugins: [sveltekit()], resolve: { alias: { - '$env/dynamic/public': resolve('./src/tests/env.ts'), + '$env/dynamic/public': resolve(import.meta.dirname, './src/tests/env.ts'), }, conditions: ['browser'], }, diff --git a/package-lock.json b/package-lock.json index 4ed0c73..f31b60f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "@sveltejs/vite-plugin-svelte": "^4.0.0", "concurrently": "^9.2.1", "husky": "^9.1.7", - "lint-staged": "^16.3.2" + "lint-staged": "^16.3.2", + "vitest": "^2.1.9" } }, "apps/api": { diff --git a/package.json b/package.json index 9cb83b8..2dd3645 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "dev:local": "concurrently -n api,web -c cyan,magenta \"npm run dev -w apps/api\" \"npm run dev -w apps/web\"", "build": "docker compose build", "check": "bash scripts/check.sh", + "lint": "biome check .", + "test": "npm run test -w apps/api && npm run test -w apps/web", "prepare": "node -e \"require('fs').existsSync('.git') && require('child_process').execSync('husky', {stdio:'inherit'})\"", "storybook": "npm run storybook --workspace=apps/web" }, @@ -15,7 +17,11 @@ "@sveltejs/vite-plugin-svelte": "^4.0.0", "concurrently": "^9.2.1", "husky": "^9.1.7", - "lint-staged": "^16.3.2" + "lint-staged": "^16.3.2", + "vitest": "^2.1.9" + }, + "lint-staged": { + "*.{ts,js,svelte,json,css}": "biome check --write --no-errors-on-unmatched" }, "msw": { "workerDirectory": ["apps/web/static"] diff --git a/scripts/check.sh b/scripts/check.sh index 6a406a2..5089562 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -euo pipefail +set -uo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" @@ -12,33 +12,36 @@ fi PASS=0 FAIL=0 WARN=0 +declare -a FAIL_LABELS=() +declare -a FAIL_OUTPUTS=() +declare -a WARN_LABELS=() +declare -a WARN_OUTPUTS=() run_step() { - local label="$1" - shift - echo "" - echo "▶ $label" - if "$@"; then - echo " ✅ $label" + local label="$1"; shift + local out + if out=$("$@" 2>&1); then + echo "✅ $label" PASS=$((PASS + 1)) else - echo " ❌ $label" + echo "❌ $label" FAIL=$((FAIL + 1)) + FAIL_LABELS+=("$label") + FAIL_OUTPUTS+=("$out") fi } -# run_warn: same as run_step but failure is non-blocking — increments WARN, not FAIL. run_warn() { - local label="$1" - shift - echo "" - echo "▶ $label (warning)" - if "$@"; then - echo " ✅ $label" + local label="$1"; shift + local out + if out=$("$@" 2>&1); then + echo "✅ $label" PASS=$((PASS + 1)) else - echo " ⚠️ $label — non-blocking" + echo "⚠️ $label (non-blocking)" WARN=$((WARN + 1)) + WARN_LABELS+=("$label") + WARN_OUTPUTS+=("$out") fi } @@ -46,46 +49,38 @@ echo "════════════════════════ echo " Minime quality checks" echo "════════════════════════════════════" -# Biome: lint + format check (read-only — no auto-mutate; biome ci exits non-zero on any violation) -run_step "Biome lint + format" npx biome ci . - -# TypeScript: typecheck per app -if [ -f "apps/api/tsconfig.json" ]; then - run_step "TypeScript (api)" bash -c "cd apps/api && npx tsc --noEmit" -fi - -if [ -f "apps/web/tsconfig.json" ]; then - run_step "TypeScript (web)" bash -c "cd apps/web && npx svelte-kit sync && npx tsc --noEmit" -fi +run_step "Biome lint + format" npx biome ci . +run_step "TypeScript (api)" npm run typecheck --workspace=apps/api +run_step "TypeScript (web)" npm run typecheck --workspace=apps/web +run_step "Svelte check" npm run check --workspace=apps/web +run_step "Tests (api)" npm run test --workspace=apps/api +run_step "Tests (web)" npm run test --workspace=apps/web +run_step "Web build" npm run build --workspace=apps/web +run_warn "Storybook build" npm run build-storybook --workspace=apps/web -# Svelte: sync + check -if [ -f "apps/web/package.json" ]; then - run_step "Svelte check" bash -c "cd apps/web && npx svelte-kit sync && npx svelte-check --tsconfig ./tsconfig.json" -fi - -# Tests: per app -if [ -f "apps/api/package.json" ] && grep -q '"test"' apps/api/package.json; then - run_step "Tests (api)" bash -c "cd apps/api && npx vitest run --passWithNoTests" -fi - -if [ -f "apps/web/package.json" ] && grep -q '"test"' apps/web/package.json; then - run_step "Tests (web)" bash -c "cd apps/web && npx vitest run --passWithNoTests" -fi +echo "" +echo "════════════════════════════════════" +printf " %d passed" "$PASS" +[ "$FAIL" -gt 0 ] && printf ", %d failed" "$FAIL" +[ "$WARN" -gt 0 ] && printf ", %d warnings" "$WARN" +echo "" +echo "════════════════════════════════════" -# Web build: catches Svelte compile errors that svelte-check misses -if [ -f "apps/web/package.json" ]; then - run_step "Web build" bash -c "cd apps/web && npx vite build" +# Print failure details — only the output for steps that failed +if [ "${#FAIL_LABELS[@]}" -gt 0 ]; then + echo "" + for i in "${!FAIL_LABELS[@]}"; do + echo "── ❌ ${FAIL_LABELS[$i]} ──────────────────────────" + echo "${FAIL_OUTPUTS[$i]}" + done fi -# Storybook build: verifies addon-a11y registers and all stories compile — non-blocking. -# a11y violations surface in the browser panel at dev time, not as CI exit codes. -if [ -f "apps/web/package.json" ] && grep -q '"storybook"' apps/web/package.json; then - run_warn "Storybook build (a11y addon smoke)" bash -c "cd apps/web && npx storybook build --quiet" +if [ "${#WARN_LABELS[@]}" -gt 0 ]; then + echo "" + for i in "${!WARN_LABELS[@]}"; do + echo "── ⚠️ ${WARN_LABELS[$i]} ──────────────────────────" + echo "${WARN_OUTPUTS[$i]}" + done fi -echo "" -echo "════════════════════════════════════" -echo " Results: $PASS passed, $FAIL failed, $WARN warnings" -echo "════════════════════════════════════" - [ "$FAIL" -eq 0 ] From b568a0b0c3c01ce95cc96ff07f5f856a340d8775 Mon Sep 17 00:00:00 2001 From: nokternol Date: Mon, 9 Mar 2026 21:21:17 +0000 Subject: [PATCH 2/2] chore(husky): remove deprecated shell shebang and source lines husky v9 no longer needs #!/usr/bin/env sh or the _/husky.sh source line. They will fail in v10. Removing proactively. Co-Authored-By: Claude Sonnet 4.6 --- .husky/pre-commit | 3 --- 1 file changed, 3 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 343f586..313f566 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,3 @@ -#!/usr/bin/env sh -. "$(dirname "$0")/_/husky.sh" - ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT"