From a22f178c7952cca467a47ee65bfdff6fdba53028 Mon Sep 17 00:00:00 2001 From: JeremyDev87 Date: Sat, 11 Apr 2026 17:03:02 +0900 Subject: [PATCH 1/2] feat(hud): rate limit format with severity icons (Wave 1-C) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces `RL:5h:13%,7d:96%` with `RL:5h░13% 7d▓96%`: - Severity icons (░ ▒ ▓) visually distinguish low/medium/high usage - Space separator replaces comma - `RL:` prefix preserved for downstream anchors Also adds defensive float coercion to _coerce_percentage() so a non-numeric used_percentage (None, "N/A") is silently treated as 0.0 instead of crashing the statusLine hot path — addresses Wave 1-A security reviewer's A03 low-severity finding. 19 new tests in test_hud_rate_limits.py cover all 3 severity buckets, boundary values (60, 85, 85.01), both-tier mixed severity, defensive coercion (None, string, numeric string, empty tier), and re-export identity from codingbuddy-hud. 3 test_hud.py tests updated to new visual format. 162/162 tests pass. Part of #1464 (Wave 0 statusbar refactor) --- .../hooks/lib/hud_rate_limits.py | 86 ++++++++-- packages/claude-code-plugin/tests/test_hud.py | 12 +- .../tests/test_hud_rate_limits.py | 147 ++++++++++++++++-- 3 files changed, 218 insertions(+), 27 deletions(-) diff --git a/packages/claude-code-plugin/hooks/lib/hud_rate_limits.py b/packages/claude-code-plugin/hooks/lib/hud_rate_limits.py index 49ed221f..c190d7b0 100644 --- a/packages/claude-code-plugin/hooks/lib/hud_rate_limits.py +++ b/packages/claude-code-plugin/hooks/lib/hud_rate_limits.py @@ -1,31 +1,93 @@ -"""Rate-limit formatting for CodingBuddy statusLine (#1326). +"""Rate-limit formatting for CodingBuddy statusLine (#1326, Wave 1-C). -Extracted verbatim from codingbuddy-hud.py as part of the Wave 0 refactor. -Behavior-preserving — see tests/test_hud.py for the contract. +Wave 0 extracted ``format_rate_limits`` verbatim from the monolith. +Wave 1-C upgrades the badge presentation: + +* severity-icon rendering instead of colon-delimited percentages +* space separator between tiers instead of comma +* defensive float coercion so a non-numeric ``used_percentage`` + (e.g. ``None``, ``"N/A"``) is silently treated as ``0`` instead + of crashing the entire status line +* ``"RL:"`` prefix is retained so downstream surfaces keep a stable + ``startswith/contains`` anchor + +Output example: + + ``RL:5h░13% 7d▓96%`` + +Severity icons (U+2591 / U+2592 / U+2593 block-drawing shades): + +* ``░`` light — ``pct <= 60`` (low / healthy) +* ``▒`` medium — ``60 < pct <= 85`` (warning) +* ``▓`` dark — ``pct > 85`` (critical) """ from __future__ import annotations from typing import Any, Dict +# Block-drawing glyphs (U+2591 light, U+2592 medium, U+2593 dark). +_ICON_LOW = "\u2591" # ░ +_ICON_MID = "\u2592" # ▒ +_ICON_HIGH = "\u2593" # ▓ + + +def _severity_icon(pct: float) -> str: + """Return a single block-drawing character reflecting quota usage. + + Tiers: + * ``pct > 85`` → ▓ (dark / critical) + * ``pct > 60`` → ▒ (medium / warning) + * otherwise → ░ (light / healthy) + """ + if pct > 85: + return _ICON_HIGH + if pct > 60: + return _ICON_MID + return _ICON_LOW + + +def _coerce_percentage(raw: Any) -> float: + """Defensively turn a ``used_percentage`` field into a float. + + Accepts ``int``/``float``/numeric string. Returns ``0.0`` for + ``None``, empty strings, non-numeric strings, or any other + unexpected type. Never raises — ``format_rate_limits`` lives on + the statusLine hot path and must degrade gracefully (see Wave 1-A + review HIGH finding for context on why defensive coercion matters). + """ + if raw is None: + return 0.0 + try: + return float(raw) + except (TypeError, ValueError): + return 0.0 + def format_rate_limits(stdin_data: Dict[str, Any]) -> str: - """Format Claude Code rate-limit badge. + """Format Claude Code rate-limit badge with severity icons. - Returns an empty string when no rate-limit data is supplied so the - badge can be dropped from the status line silently. + Returns an empty string when no rate-limit data is supplied so + the badge can be dropped from the status line silently. """ rl = stdin_data.get("rate_limits") if not rl: return "" - parts = [] + + parts: list = [] + five = rl.get("five_hour") if five: - pct = five.get("used_percentage", 0) - parts.append(f"5h:{pct:.0f}%") + pct = _coerce_percentage(five.get("used_percentage", 0)) + icon = _severity_icon(pct) + parts.append(f"5h{icon}{pct:.0f}%") + seven = rl.get("seven_day") if seven: - pct = seven.get("used_percentage", 0) - parts.append(f"7d:{pct:.0f}%") + pct = _coerce_percentage(seven.get("used_percentage", 0)) + icon = _severity_icon(pct) + parts.append(f"7d{icon}{pct:.0f}%") + if not parts: return "" - return "RL:" + ",".join(parts) + + return "RL:" + " ".join(parts) diff --git a/packages/claude-code-plugin/tests/test_hud.py b/packages/claude-code-plugin/tests/test_hud.py index 320ee4d3..b5f4a7e6 100644 --- a/packages/claude-code-plugin/tests/test_hud.py +++ b/packages/claude-code-plugin/tests/test_hud.py @@ -366,7 +366,9 @@ def test_no_rate_limits(self): def test_five_hour_only(self): stdin = {"rate_limits": {"five_hour": {"used_percentage": 23.5}}} - assert hud.format_rate_limits(stdin) == "RL:5h:24%" + # Wave 1-C: severity icon replaces colon separator + # 23.5% ≤ 60 → U+2591 ░ (low) + assert hud.format_rate_limits(stdin) == "RL:5h\u259124%" def test_both_limits(self): stdin = {"rate_limits": { @@ -374,8 +376,9 @@ def test_both_limits(self): "seven_day": {"used_percentage": 40}, }} result = hud.format_rate_limits(stdin) - assert "5h:10%" in result - assert "7d:40%" in result + # Wave 1-C: severity icon replaces colon; space replaces comma + assert "5h\u259110%" in result + assert "7d\u259140%" in result class TestFormatWorktree: @@ -543,7 +546,8 @@ def test_rate_limits_shown(self): }} result = hud.format_status_line(stdin, {}) assert "RL:" in result - assert "5h:50%" in result + # Wave 1-C: severity icon replaces colon (50% ≤ 60 → ░ low) + assert "5h\u259150%" in result def test_worktree_shown(self): stdin = {"worktree": {"name": "feat-x"}} diff --git a/packages/claude-code-plugin/tests/test_hud_rate_limits.py b/packages/claude-code-plugin/tests/test_hud_rate_limits.py index f3896762..07f4ba36 100644 --- a/packages/claude-code-plugin/tests/test_hud_rate_limits.py +++ b/packages/claude-code-plugin/tests/test_hud_rate_limits.py @@ -1,4 +1,4 @@ -"""Sanity + behavior test for the hud_rate_limits module (Wave 0 / #1463).""" +"""Behavior tests for hud_rate_limits severity rendering (Wave 1-C / #1326).""" import importlib import os import sys @@ -12,9 +12,12 @@ import hud_rate_limits # noqa: E402 +_ICON_LOW = "\u2591" # ░ +_ICON_MID = "\u2592" # ▒ +_ICON_HIGH = "\u2593" # ▓ -def test_module_has_public_api(): - assert hasattr(hud_rate_limits, "format_rate_limits") + +# --------------------------- fallthrough cases ------------------------------ def test_empty_returns_empty(): @@ -25,17 +28,72 @@ def test_no_rate_limits_key_returns_empty(): assert hud_rate_limits.format_rate_limits({"cost": {}}) == "" -def test_five_hour_only(): +def test_empty_rate_limits_object_returns_empty(): + assert hud_rate_limits.format_rate_limits({"rate_limits": {}}) == "" + + +# --------------------------- severity buckets ------------------------------ + + +def test_five_hour_low_severity(): + """23.5% → rounds to 24%, ≤ 60 → ░ low icon.""" stdin = {"rate_limits": {"five_hour": {"used_percentage": 23.5}}} - assert hud_rate_limits.format_rate_limits(stdin) == "RL:5h:24%" + assert ( + hud_rate_limits.format_rate_limits(stdin) + == f"RL:5h{_ICON_LOW}24%" + ) + + +def test_five_hour_medium_severity(): + """75% → within (60, 85] → ▒ medium icon.""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": 75}}} + assert ( + hud_rate_limits.format_rate_limits(stdin) + == f"RL:5h{_ICON_MID}75%" + ) + + +def test_five_hour_high_severity(): + """96% → > 85 → ▓ high icon.""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": 96}}} + assert ( + hud_rate_limits.format_rate_limits(stdin) + == f"RL:5h{_ICON_HIGH}96%" + ) + + +def test_boundary_60_is_low(): + """Exactly 60% stays in the low bucket (inclusive upper bound).""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": 60}}} + assert _ICON_LOW in hud_rate_limits.format_rate_limits(stdin) + + +def test_boundary_85_is_medium(): + """Exactly 85% is still medium (inclusive upper bound).""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": 85}}} + assert _ICON_MID in hud_rate_limits.format_rate_limits(stdin) + + +def test_boundary_over_85_is_high(): + """85.01% crosses into high.""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": 85.01}}} + assert _ICON_HIGH in hud_rate_limits.format_rate_limits(stdin) + + +# --------------------------- seven-day tier -------------------------------- def test_seven_day_only(): + """Seven-day tier renders with its own icon.""" stdin = {"rate_limits": {"seven_day": {"used_percentage": 80}}} - assert hud_rate_limits.format_rate_limits(stdin) == "RL:7d:80%" + result = hud_rate_limits.format_rate_limits(stdin) + assert f"7d{_ICON_MID}80%" in result + + +# --------------------------- both tiers, separator ------------------------- -def test_both_limits(): +def test_both_tiers_space_separated(): stdin = { "rate_limits": { "five_hour": {"used_percentage": 10}, @@ -43,12 +101,79 @@ def test_both_limits(): } } result = hud_rate_limits.format_rate_limits(stdin) - assert "5h:10%" in result - assert "7d:40%" in result - assert result.startswith("RL:") + assert result == f"RL:5h{_ICON_LOW}10% 7d{_ICON_LOW}40%" + assert "," not in result # Wave 1-C replaces comma with space + + +def test_both_tiers_mixed_severity(): + """One tier low, one critical.""" + stdin = { + "rate_limits": { + "five_hour": {"used_percentage": 13}, + "seven_day": {"used_percentage": 96}, + } + } + result = hud_rate_limits.format_rate_limits(stdin) + assert f"5h{_ICON_LOW}13%" in result + assert f"7d{_ICON_HIGH}96%" in result + + +# --------------------------- defensive coercion ---------------------------- + + +def test_none_percentage_coerced_to_zero(): + """None used_percentage does not crash; renders as 0%.""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": None}}} + result = hud_rate_limits.format_rate_limits(stdin) + assert result == f"RL:5h{_ICON_LOW}0%" + + +def test_string_percentage_coerced_to_zero(): + """Non-numeric string used_percentage does not crash.""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": "N/A"}}} + result = hud_rate_limits.format_rate_limits(stdin) + assert result == f"RL:5h{_ICON_LOW}0%" + + +def test_numeric_string_percentage_accepted(): + """Numeric string is parsed as float.""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": "42"}}} + result = hud_rate_limits.format_rate_limits(stdin) + assert f"5h{_ICON_LOW}42%" in result + + +def test_empty_tier_object_is_skipped(): + """Empty tier dict (falsy) is skipped, not rendered as 0%. + + This mirrors the original Wave 0 behavior: `if five:` checks + truthiness, and an empty dict falls through without being rendered. + """ + stdin = {"rate_limits": {"five_hour": {}}} + result = hud_rate_limits.format_rate_limits(stdin) + assert result == "" + + +def test_tier_with_null_used_percentage_renders_zero(): + """Explicit None used_percentage (key present) coerces to 0%.""" + stdin = {"rate_limits": {"five_hour": {"used_percentage": None, "foo": "bar"}}} + result = hud_rate_limits.format_rate_limits(stdin) + assert result == f"RL:5h{_ICON_LOW}0%" + + +# --------------------------- re-export lock -------------------------------- def test_reexport_identity_from_codingbuddy_hud(): - """Lock: codingbuddy-hud.format_rate_limits must be the same function.""" + """Lock: codingbuddy-hud.format_rate_limits must be the same object.""" hud_main = importlib.import_module("codingbuddy-hud") assert hud_main.format_rate_limits is hud_rate_limits.format_rate_limits + + +# --------------------------- internal helper exposure ---------------------- + + +def test_severity_icon_helper_exposed(): + """_severity_icon is a documented internal helper.""" + assert hud_rate_limits._severity_icon(10) == _ICON_LOW + assert hud_rate_limits._severity_icon(70) == _ICON_MID + assert hud_rate_limits._severity_icon(90) == _ICON_HIGH From edaaf5c7a98b78609efe5743ef4a515bea9ab430 Mon Sep 17 00:00:00 2001 From: JeremyDev87 Date: Sat, 11 Apr 2026 21:40:59 +0900 Subject: [PATCH 2/2] fix(hud,landing): narrow fallback imports + bump next to 16.2.3 Combined Wave 0 polish items from the #1465/#1485 review cycle: 1. Narrow `except Exception` to `except ImportError` in the 3 lib fallback import blocks (qual-1465 HIGH-1). Real logic bugs (SyntaxError, NameError, AttributeError) inside lib modules now surface immediately instead of being silently swallowed by a catch-all. 2. Drop inline stub functions for format_rate_limits and _get_fresh_version (qual-1465 HIGH-2). Eliminates the signature drift between canonical lib definitions and in-file fallback stubs observed on the integrator branch (Wave 1-A plugin_json_file kwarg drift). The outer main() try/except still catches any runtime failure and emits the minimal safe output via the BUDDY_FACE constant. 3. Hoist hud_velocity and hud_cache_savings imports to module top as _format_velocity_segment and _format_cache_savings (perf-1485 H1). Eliminates ~0.47us sys.modules lookup per render. Integrator branch only - no-op on refactor/wave branches where the inline imports don't exist yet. 4. Bump next to 16.2.3 for GHSA-q4gf-8mx6-v5v3 (landing-security-check). Aligns eslint-config-next and updates setup.test.ts assertion. Refs: qual-1465 HIGH-1/2, perf-1485 H1, https://github.com/advisories/GHSA-q4gf-8mx6-v5v3 --- apps/landing-page/__tests__/setup.test.ts | 2 +- apps/landing-page/package.json | 4 +- .../hooks/codingbuddy-hud.py | 42 +++-- yarn.lock | 170 +++++++++++++++++- 4 files changed, 197 insertions(+), 21 deletions(-) diff --git a/apps/landing-page/__tests__/setup.test.ts b/apps/landing-page/__tests__/setup.test.ts index 00d1c0c6..1b5e64f8 100644 --- a/apps/landing-page/__tests__/setup.test.ts +++ b/apps/landing-page/__tests__/setup.test.ts @@ -8,7 +8,7 @@ describe('Next.js 16 Project Setup', () => { }); test('Next.js 16.x is installed and locked', () => { - expect(pkg.dependencies.next).toBe('16.1.6'); + expect(pkg.dependencies.next).toBe('16.2.3'); }); test('React 19.x is installed and locked', () => { diff --git a/apps/landing-page/package.json b/apps/landing-page/package.json index 89265a00..a5c557ca 100644 --- a/apps/landing-page/package.json +++ b/apps/landing-page/package.json @@ -32,7 +32,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.563.0", - "next": "16.1.6", + "next": "16.2.3", "next-intl": "^4.8.2", "next-themes": "^0.4.6", "prism-react-renderer": "^2.4.1", @@ -56,7 +56,7 @@ "axe-core": "^4.11.1", "babel-plugin-react-compiler": "1.0.0", "eslint": "^9", - "eslint-config-next": "16.1.6", + "eslint-config-next": "16.2.3", "happy-dom": "^20.8.8", "jest-axe": "^10.0.0", "madge": "^8.0.0", diff --git a/packages/claude-code-plugin/hooks/codingbuddy-hud.py b/packages/claude-code-plugin/hooks/codingbuddy-hud.py index c99ca493..a3472e4e 100644 --- a/packages/claude-code-plugin/hooks/codingbuddy-hud.py +++ b/packages/claude-code-plugin/hooks/codingbuddy-hud.py @@ -23,28 +23,40 @@ sys.path.insert(0, _LIB_DIR) # === test_hud.py compatibility re-exports — DO NOT REMOVE without coordinated test update === -# Defensive fallback: statusLine is a hot path invoked by Claude Code on -# every render. If any lib module is temporarily broken (e.g. mid-wave -# refactor), fall back to minimal inline implementations so the status -# bar still renders instead of crashing the Claude Code subprocess. +# Narrow the fallback to ImportError only: real logic bugs in lib modules +# (SyntaxError, NameError, AttributeError) must surface immediately instead +# of being silently swallowed by a catch-all. If a lib module fails to import +# entirely, the outer main() try/except at the bottom of this file still +# emits the minimal safe output via the BUDDY_FACE constant. try: from hud_buddy import BUDDY_FACE # canonical SSoT via tiny_actor_presets -except Exception: # pragma: no cover - defensive - BUDDY_FACE = "\u25d5\u203f\u25d5" # ◕‿◕ +except ImportError: # pragma: no cover - defensive + BUDDY_FACE = "◕‿◕" # minimal constant for safe-output path try: - from hud_rate_limits import format_rate_limits -except Exception: # pragma: no cover - defensive - def format_rate_limits(stdin_data: dict) -> str: # type: ignore[misc] - return "" + from hud_rate_limits import format_rate_limits # noqa: F401 re-exported for test_hud.py +except ImportError: # pragma: no cover - defensive + pass # main() catch-all handles absence try: from hud_version import get_fresh_version as _get_fresh_version # backcompat alias -except Exception: # pragma: no cover - defensive - def _get_fresh_version( # type: ignore[misc] - hud_state: dict, *, plugins_file: str = "" - ) -> str: - return hud_state.get("version", "") +except ImportError: # pragma: no cover - defensive + pass # main() catch-all handles absence + +# Wave 2-B velocity + Wave 2-C cache savings hot-path suffixes for the cost segment. +# Hoisted to module top per perf-1485 H1 so format_status_line avoids a +# sys.modules lookup on every render (~0.47μs saved per call). +try: + from hud_velocity import format_velocity_segment as _format_velocity_segment +except ImportError: # pragma: no cover - defensive + def _format_velocity_segment(stdin_data, hud_state=None): # type: ignore[misc] + return "" + +try: + from hud_cache_savings import format_cache_savings as _format_cache_savings +except ImportError: # pragma: no cover - defensive + def _format_cache_savings(stdin_data): # type: ignore[misc] + return "" # Agent eye glyphs from .ai-rules agent definitions. AGENT_GLYPHS = { diff --git a/yarn.lock b/yarn.lock index 1eac05b0..76937473 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1561,6 +1561,13 @@ __metadata: languageName: node linkType: hard +"@next/env@npm:16.2.3": + version: 16.2.3 + resolution: "@next/env@npm:16.2.3" + checksum: 10c0/56c3fee8ea226efe59ef065e054380f872c00c45c9fe4475eaa45f80773c3c1adc3ead3ccdd77447d3c1aeb4b3004aaaa033dd4a100d3e572fd01b83f992dde8 + languageName: node + linkType: hard + "@next/eslint-plugin-next@npm:16.1.6": version: 16.1.6 resolution: "@next/eslint-plugin-next@npm:16.1.6" @@ -1570,6 +1577,15 @@ __metadata: languageName: node linkType: hard +"@next/eslint-plugin-next@npm:16.2.3": + version: 16.2.3 + resolution: "@next/eslint-plugin-next@npm:16.2.3" + dependencies: + fast-glob: "npm:3.3.1" + checksum: 10c0/be881aa89e0840ab60455b07a2bb9ec0d686c664a0d91e8ca815797a65ca71d7bd79d186b0df5b6892c2bf57bd07fa05421cd93e2812dfeaedfad5ed9fd1023e + languageName: node + linkType: hard + "@next/swc-darwin-arm64@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-darwin-arm64@npm:16.1.6" @@ -1577,6 +1593,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-darwin-arm64@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-darwin-arm64@npm:16.2.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@next/swc-darwin-x64@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-darwin-x64@npm:16.1.6" @@ -1584,6 +1607,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-darwin-x64@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-darwin-x64@npm:16.2.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@next/swc-linux-arm64-gnu@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-linux-arm64-gnu@npm:16.1.6" @@ -1591,6 +1621,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-arm64-gnu@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-arm64-gnu@npm:16.2.3" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@next/swc-linux-arm64-musl@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-linux-arm64-musl@npm:16.1.6" @@ -1598,6 +1635,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-arm64-musl@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-arm64-musl@npm:16.2.3" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@next/swc-linux-x64-gnu@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-linux-x64-gnu@npm:16.1.6" @@ -1605,6 +1649,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-x64-gnu@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-x64-gnu@npm:16.2.3" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@next/swc-linux-x64-musl@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-linux-x64-musl@npm:16.1.6" @@ -1612,6 +1663,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-x64-musl@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-linux-x64-musl@npm:16.2.3" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@next/swc-win32-arm64-msvc@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-win32-arm64-msvc@npm:16.1.6" @@ -1619,6 +1677,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-win32-arm64-msvc@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-win32-arm64-msvc@npm:16.2.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@next/swc-win32-x64-msvc@npm:16.1.6": version: 16.1.6 resolution: "@next/swc-win32-x64-msvc@npm:16.1.6" @@ -1626,6 +1691,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-win32-x64-msvc@npm:16.2.3": + version: 16.2.3 + resolution: "@next/swc-win32-x64-msvc@npm:16.2.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -5276,6 +5348,15 @@ __metadata: languageName: node linkType: hard +"baseline-browser-mapping@npm:^2.9.19": + version: 2.10.17 + resolution: "baseline-browser-mapping@npm:2.10.17" + bin: + baseline-browser-mapping: dist/cli.cjs + checksum: 10c0/e792a92a6b206521681e3ab3a72770023f74a3274450bfe11ba55a075ba26f5820d5d2d02d92e25224b8d01e327b78fbf3e116bdc6ac74b3d9c52f5e3f4a048a + languageName: node + linkType: hard + "better-sqlite3@npm:^11.9.1": version: 11.10.0 resolution: "better-sqlite3@npm:11.10.0" @@ -7028,6 +7109,29 @@ __metadata: languageName: node linkType: hard +"eslint-config-next@npm:16.2.3": + version: 16.2.3 + resolution: "eslint-config-next@npm:16.2.3" + dependencies: + "@next/eslint-plugin-next": "npm:16.2.3" + eslint-import-resolver-node: "npm:^0.3.6" + eslint-import-resolver-typescript: "npm:^3.5.2" + eslint-plugin-import: "npm:^2.32.0" + eslint-plugin-jsx-a11y: "npm:^6.10.0" + eslint-plugin-react: "npm:^7.37.0" + eslint-plugin-react-hooks: "npm:^7.0.0" + globals: "npm:16.4.0" + typescript-eslint: "npm:^8.46.0" + peerDependencies: + eslint: ">=9.0.0" + typescript: ">=3.3.1" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/c6fd3accadb53c636f034baf4363d22847bf824c8ca1ecfa8047a4eee7882d156e75f60f37098357c7ae07e646dfaa23a176336abd3c74aa9a2df61aee984653 + languageName: node + linkType: hard + "eslint-config-prettier@npm:10.1.8": version: 10.1.8 resolution: "eslint-config-prettier@npm:10.1.8" @@ -8942,12 +9046,12 @@ __metadata: class-variance-authority: "npm:^0.7.1" clsx: "npm:^2.1.1" eslint: "npm:^9" - eslint-config-next: "npm:16.1.6" + eslint-config-next: "npm:16.2.3" happy-dom: "npm:^20.8.8" jest-axe: "npm:^10.0.0" lucide-react: "npm:^0.563.0" madge: "npm:^8.0.0" - next: "npm:16.1.6" + next: "npm:16.2.3" next-intl: "npm:^4.8.2" next-themes: "npm:^0.4.6" prettier: "npm:^3.4.2" @@ -9858,6 +9962,66 @@ __metadata: languageName: node linkType: hard +"next@npm:16.2.3": + version: 16.2.3 + resolution: "next@npm:16.2.3" + dependencies: + "@next/env": "npm:16.2.3" + "@next/swc-darwin-arm64": "npm:16.2.3" + "@next/swc-darwin-x64": "npm:16.2.3" + "@next/swc-linux-arm64-gnu": "npm:16.2.3" + "@next/swc-linux-arm64-musl": "npm:16.2.3" + "@next/swc-linux-x64-gnu": "npm:16.2.3" + "@next/swc-linux-x64-musl": "npm:16.2.3" + "@next/swc-win32-arm64-msvc": "npm:16.2.3" + "@next/swc-win32-x64-msvc": "npm:16.2.3" + "@swc/helpers": "npm:0.5.15" + baseline-browser-mapping: "npm:^2.9.19" + caniuse-lite: "npm:^1.0.30001579" + postcss: "npm:8.4.31" + sharp: "npm:^0.34.5" + styled-jsx: "npm:5.1.6" + peerDependencies: + "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.51.1 + babel-plugin-react-compiler: "*" + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + dependenciesMeta: + "@next/swc-darwin-arm64": + optional: true + "@next/swc-darwin-x64": + optional: true + "@next/swc-linux-arm64-gnu": + optional: true + "@next/swc-linux-arm64-musl": + optional: true + "@next/swc-linux-x64-gnu": + optional: true + "@next/swc-linux-x64-musl": + optional: true + "@next/swc-win32-arm64-msvc": + optional: true + "@next/swc-win32-x64-msvc": + optional: true + sharp: + optional: true + peerDependenciesMeta: + "@opentelemetry/api": + optional: true + "@playwright/test": + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + bin: + next: dist/bin/next + checksum: 10c0/8a9d27fc773d69f7f471cf1a23bde2ab2950e0411ef3e0d5c1664ed9654e94c3304eae1c4283ec0fa4e70e7b3f4416913350e118e0c18e8b055693dc5d021883 + languageName: node + linkType: hard + "node-abi@npm:^3.3.0": version: 3.89.0 resolution: "node-abi@npm:3.89.0" @@ -11302,7 +11466,7 @@ __metadata: languageName: node linkType: hard -"sharp@npm:^0.34.4": +"sharp@npm:^0.34.4, sharp@npm:^0.34.5": version: 0.34.5 resolution: "sharp@npm:0.34.5" dependencies: