diff --git a/.claude/skills/e2e-verify/SKILL.md b/.claude/skills/e2e-verify/SKILL.md index c344eda3..d6055ca6 100644 --- a/.claude/skills/e2e-verify/SKILL.md +++ b/.claude/skills/e2e-verify/SKILL.md @@ -8,7 +8,8 @@ description: Verify theprototype.app changes end-to-end with Playwright — the ## The committed suite (start here) `tests/e2e/*.test.cjs` + `helpers.cjs` (`.cjs` — the package is `"type": "module"`). -Run with the dev server up (`npm run dev`, https on 5173): +Run with the dev server up (`npm run dev`, https on 5173 via the repo certs/ — +vite-plugin-mkcert is gone; node >= 24 required, engines-gated): ``` npm run e2e # all suites (~80), sequential, ~25-30 min @@ -269,7 +270,7 @@ drops the P2P session. (the runner just `node`s each file; see net-backoff.test.cjs). Track PASS/FAIL locally and `process.exit(1)` on failure (helpers.finish needs a browser). - svelte-check delta hunting: `npx svelte-check --output machine | grep `; - baseline 2026-08-01 = **438 errors / 62 warnings** (drifts down as flowbite/typed + baseline 2026-08-01 = **435 errors / 62 warnings** (node 24, all A-D migrations in) (drifts down as flowbite/typed code is removed — hold whatever it currently is; add no NEW; the release.yml gate hardcodes the numbers — update it when the baseline moves). Note: in the big JS-mode `.svelte` files (Scene.svelte) `@param {T}` JSDoc on a function is NOT honored — diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 16e99e67..3dbdac1d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,27 +15,10 @@ updates: - minor - patch ignore: - # three moves in lockstep with threlte + postprocessing/n8ao (planned migration) - - dependency-name: three - update-types: [version-update:semver-minor, version-update:semver-major] - # pinned on prereleases; stable bump is part of the three lockstep migration - - dependency-name: '@threlte/*' - # 0.1.x -> 1.x is a Svelte 5 rewrite of the whole flow editor (planned migration) - - dependency-name: '@xyflow/svelte' - update-types: [version-update:semver-major] - # flowbite-svelte 1.x requires tailwind 4 — coupled migration - - dependency-name: flowbite-svelte - update-types: [version-update:semver-major] - - dependency-name: flowbite - update-types: [version-update:semver-major] - - dependency-name: tailwindcss - update-types: [version-update:semver-major] - # vite majors move with @sveltejs/vite-plugin-svelte majors — coupled migration - - dependency-name: vite - update-types: [version-update:semver-major] - - dependency-name: '@sveltejs/vite-plugin-svelte' - update-types: [version-update:semver-major] + # engine: TS 7 until svelte-check peers it (currently ^5||^6) - dependency-name: typescript update-types: [version-update:semver-major] # physics solver behavior can shift on 0.x bumps (rapier revolute-axis gotcha) - dependency-name: '@dimforge/rapier3d-compat' + # 2026-08-01: three/threlte/xyflow/flowbite/tailwind/vite ignores REMOVED - + # the planned migrations (A-D) all shipped; future majors PR normally. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 63184a2e..8cc6fc1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,12 +15,12 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 cache: npm - - run: npm ci --legacy-peer-deps + - run: npm ci - run: npm run build # svelte-check exits non-zero at the legacy baseline; fail ONLY when the - # counts grow past it (baseline 438 errors / 62 warnings, 2026-08-01) + # counts grow past it (baseline 435 errors / 62 warnings, 2026-08-01, node 24) - name: svelte-check baseline gate run: | npm run check 2>&1 | tee check.log || true @@ -34,9 +34,9 @@ jobs: ERRORS=$(echo "$LINE" | awk '{print $2}') WARNINGS=$(echo "$LINE" | awk '{print $5}') fi - echo "svelte-check: $ERRORS errors / $WARNINGS warnings (baseline 438/62)" + echo "svelte-check: $ERRORS errors / $WARNINGS warnings (baseline 435/62)" if [ -z "$ERRORS" ]; then echo "could not parse svelte-check output"; exit 1; fi - if [ "$ERRORS" -gt 438 ] || [ "$WARNINGS" -gt 62 ]; then + if [ "$ERRORS" -gt 435 ] || [ "$WARNINGS" -gt 62 ]; then echo "baseline exceeded"; exit 1 fi - name: zip the build diff --git a/CLAUDE.md b/CLAUDE.md index 3a725d54..8111d220 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -421,18 +421,36 @@ loadable play content. Everything a user does must be visible to connected peers - `event.code` (`Digit1`) for digit shortcuts — `event.key` breaks with Shift. - Stores initialized `writable(null)`/`writable([])` infer `never` — annotate with JSDoc `Writable`; keep NEW files clean (legacy implicit-any baseline stays). -- `npm i` needs `--legacy-peer-deps` (three vs postprocessing peer conflict). +- **Runtime = node >= 24** (engines-gated, engine-strict .npmrc; 2026-08-01). Plain + `npm install` works — the old `--legacy-peer-deps` requirement died with three 0.185 + (postprocessing widened its peer range). Dev https uses the repo's own `certs/` + files via `server.https` in vite.config (vite-plugin-mkcert was dropped). npm 11 + gates postinstall scripts (`allow-scripts` warning) — if a native dep misbehaves + after install, check `npm approve-scripts`. - **Release ritual (V6)**: `npm version minor|patch` + `git push origin main --follow-tags` — the v* tag triggers `.github/workflows/release.yml` (build + - svelte-check baseline gate + GitHub Release). Full doc: committed `RELEASING.md`. - The version bump is the SINGLE source of truth (About / peer handshake / - .tpscene+.tpmodule provenance / static/version.json all derive from it). -- **Deps policy (2026-07-28)**: three/@threlte/*/@xyflow/flowbite*/tailwind/vite/TS are - DELIBERATELY frozen — each has a planned migration in the cloud repo - `plans-core/pending/deps-migrations-post-1.0.md`; Dependabot (grouped monthly, - `.github/dependabot.yml`) ignores them and `npm run deps:check` reports drift - (non-blocking; also runs in the cloud deploy). Don't bump them ad hoc. A playwright - bump needs `npx playwright install chromium` or every suite fails at launch. + svelte-check baseline gate + GitHub Release; UPDATE the gate's hardcoded numbers + when the baseline moves). Full doc: committed `RELEASING.md`. The version bump is + the SINGLE source of truth (About / peer handshake / .tpscene+.tpmodule + provenance / static/version.json all derive from it). +- **Deps policy (2026-08-01, post-migrations)**: the A-D migrations SHIPPED — three + 0.185 + threlte stable, @xyflow/svelte 1.6 (flow editor on runes), tailwind 4 + + flowbite-svelte 1.x (NON-modal native dialogs — see the modal gotcha), vite 7 + + node 24. Still frozen (dependabot ignores + `npm run deps:check` FROZEN list): + TypeScript 7 (until svelte-check peers ^7) and rapier (solver behavior). Everything + else takes normal grouped-monthly Dependabot PRs. A playwright bump needs + `npx playwright install chromium` or every suite fails at launch. svelte-check + baselines DRIFT with dep bumps — re-measure on a pristine worktree before gating. +- **Modal gotcha (flowbite 1.x)**: app modals (Settings/Modules/Sessions/Character/ + profile/Library) are NON-MODAL native dialogs (`modal={false}` → dialog.show()) so + the z-tier chrome above --z-modal stays CLICKABLE (logo one-click close+menu, + Connect bar, approval toasts, ThemedSelect body-portals). Never switch them to + showModal(): the top layer makes everything else INERT — body-portaled menus and + toasts go visible-but-dead, and top-layer popovers do NOT escape inertness. The + ::before pseudo is the backdrop (non-modal dialogs have no ::backdrop); flowbite's + outsideclose bbox math treats clicks on it as outside. ConfirmModal alone stays + truly modal (blocking confirm). ESC = per-dialog onkeydown (no cancel event + non-modal). - PowerShell mangles emoji AND em-dashes when rewriting files, and inline `node -e` quoting breaks — write a scratch `.cjs` and run it with node for any file rewrite containing non-ASCII. Commit messages: **ASCII only** — a `▸`/em-dash inside a diff --git a/package-lock.json b/package-lock.json index 794759c4..f9e0eff6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,11 +38,14 @@ "prettier-plugin-svelte": "^4.1.1", "prettier-plugin-tailwindcss": "^0.8.1", "svelte": "^5.56.8", - "svelte-awesome-color-picker": "~4.1.0", + "svelte-awesome-color-picker": "^4.1.3", "svelte-check": "^4.7.4", "tailwindcss": "^4.3.3", "typescript": "^5.9.3", "vite": "^7.3.4" + }, + "engines": { + "node": ">=24" } }, "node_modules/@alloc/quick-lru": { @@ -1880,13 +1883,13 @@ } }, "node_modules/camera-controls": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.0.tgz", - "integrity": "sha512-w5oULNpijgTRH0ARFJJ0R5ct1nUM3R3WP7/b8A6j9uTGpRfnsypc/RBMPQV8JQDPayUe37p/TZZY1PcUr4czOQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.2.tgz", + "integrity": "sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==", "license": "MIT", "engines": { - "node": ">=20.11.0", - "npm": ">=10.8.2" + "node": ">=22.0.0", + "npm": ">=10.5.1" }, "peerDependencies": { "three": ">=0.126.1" @@ -3691,15 +3694,18 @@ } }, "node_modules/svelte-awesome-color-picker": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/svelte-awesome-color-picker/-/svelte-awesome-color-picker-4.1.0.tgz", - "integrity": "sha512-afiSB3eTBlqu96f4+rjBvqG3eCaLwuneNYHe587Wr4Ien6yQWeztGZunPT0FmiI7wFFBVNUlJQLYutII8LfQUg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/svelte-awesome-color-picker/-/svelte-awesome-color-picker-4.1.3.tgz", + "integrity": "sha512-fYio6XR2vp9WO0ihT6Vlw1Kj278gEZtqfIRde4YBx5OgGjBdQJxFE8jl6OibPQPrmaz625HZPZaSbRflL88/Mg==", "dev": true, "license": "MIT", "dependencies": { "colord": "^2.9.3", "svelte-awesome-slider": "2.0.0" }, + "engines": { + "node": ">=24" + }, "peerDependencies": { "svelte": "^5.0.0" } diff --git a/package.json b/package.json index c2aec83a..f4035e66 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "prettier-plugin-svelte": "^4.1.1", "prettier-plugin-tailwindcss": "^0.8.1", "svelte": "^5.56.8", - "svelte-awesome-color-picker": "~4.1.0", + "svelte-awesome-color-picker": "^4.1.3", "svelte-check": "^4.7.4", "tailwindcss": "^4.3.3", "typescript": "^5.9.3", @@ -55,7 +55,7 @@ "svelte-hamburgers": "^5.0.0", "three": "^0.185.0" }, - "overrides": { - "camera-controls": "3.1.0" + "engines": { + "node": ">=24" } } diff --git a/scripts/deps-check.cjs b/scripts/deps-check.cjs index 6f2c9220..bf71f246 100644 --- a/scripts/deps-check.cjs +++ b/scripts/deps-check.cjs @@ -7,16 +7,7 @@ const { execSync } = require('child_process'); // deps with a planned, deliberate migration — major drift on these is expected const FROZEN = [ - 'three', - '@threlte/core', - '@threlte/extras', - '@threlte/xr', - '@xyflow/svelte', - 'flowbite', - 'flowbite-svelte', - 'tailwindcss', - 'vite', - '@sveltejs/vite-plugin-svelte', + // TS 7 until svelte-check peers ^7; rapier held for solver-behavior stability 'typescript', '@dimforge/rapier3d-compat' ];