From 8f508e15116e0b4950f0cf8ad1117f8cf59d2cf7 Mon Sep 17 00:00:00 2001 From: JeremyDev87 Date: Sat, 11 Apr 2026 21:00:34 +0900 Subject: [PATCH 1/2] feat(hud): mode rainbow ANSI coloring (Wave 2-D) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renders the statusLine mode label with per-mode ANSI truecolor gradients + tier-specific glyphs: PLAN -> ◇ blue (solid) ACT -> ◆ green (solid) EVAL -> ◈ purple (solid) AUTO -> ◊ rainbow (6-stop gradient: red->orange->yellow->green->blue->purple) NO_COLOR env var (https://no-color.org) honoured: any non-empty value disables color and returns plain text. New lib/hud_rainbow.py: - MODE_PALETTE: per-mode RGB anchor list - is_color_enabled(env): NO_COLOR check - mode_glyph(mode): per-mode Unicode glyph lookup - gradient_ansi(text, palette): character-by-character RGB wrap - render_mode_rainbow(mode, *, enabled, env): end-to-end renderer - strip_ansi(s): CSI escape removal helper (for tests + layout) 35 new tests cover: NO_COLOR parsing, glyph lookup (4 modes + unknown + case-insensitive), gradient (single/multi/empty), render (all 4 modes + enabled/disabled/env fallback + unknown mode + case-insensitive), strip_ansi (noop/escapes/empty/mixed), MODE_PALETTE schema. 164/164 pass. Part of #1464 (Wave 0 statusbar refactor) --- .../hooks/lib/hud_rainbow.py | 226 +++++++++++++++++- .../tests/test_hud_rainbow.py | 222 ++++++++++++++++- 2 files changed, 435 insertions(+), 13 deletions(-) diff --git a/packages/claude-code-plugin/hooks/lib/hud_rainbow.py b/packages/claude-code-plugin/hooks/lib/hud_rainbow.py index 65be9372..a4208052 100644 --- a/packages/claude-code-plugin/hooks/lib/hud_rainbow.py +++ b/packages/claude-code-plugin/hooks/lib/hud_rainbow.py @@ -1,13 +1,221 @@ -"""Mode rainbow ANSI colouring for CodingBuddy statusLine (#1326). +"""Mode rainbow ANSI coloring for CodingBuddy statusLine (#1326, Wave 2-D). -Wave 0 skeleton — reserved for **Wave 2-D**. +Renders the statusLine mode label with per-mode ANSI coloring and a +tier-specific glyph so users can tell at a glance which workflow +mode is active: -Planned contents (Wave 2-D owner fills): - * ``MODE_PALETTE: dict[str, tuple[int, int, int]]`` — per-mode RGB - gradient anchors (PLAN/ACT/EVAL/AUTO) - * ``gradient_ansi(text: str, palette: tuple) -> str`` - * ``render_mode_rainbow(mode: str, text: str) -> str`` + PLAN → ◇ blue (planning — cool, deliberate) + ACT → ◆ green (executing — go) + EVAL → ◈ purple (evaluating — reflective) + AUTO → ◊ rainbow (cycling — energetic gradient) -Wave 2-D will wire the rainbow into ``format_status_line`` (or its -``hud_layout`` successor) in place of the plain text mode label. +Color output honours the ``NO_COLOR`` environment variable +(https://no-color.org) — when it is set to any non-empty value, +:func:`render_mode_rainbow` emits plain text without escape codes so +redirected/logged output stays clean. + +Primary entry points: + +- :func:`is_color_enabled` — check the NO_COLOR env var +- :func:`mode_glyph` — per-mode Unicode glyph +- :func:`gradient_ansi` — character-by-character RGB gradient +- :func:`render_mode_rainbow` — end-to-end mode label renderer """ +from __future__ import annotations + +import os +from typing import Dict, List, Tuple + +# ------------------------------------------------------------------------ +# Constants +# ------------------------------------------------------------------------ + +# ANSI escape codes +_CSI = "\x1b[" +_RESET = f"{_CSI}0m" + +# Basic 8-bit color codes (38;5;N) for simple modes. +_FG_BLUE = 33 # bright blue +_FG_GREEN = 42 # bright green +_FG_PURPLE = 135 # bright purple +_FG_RED = 196 +_FG_ORANGE = 208 +_FG_YELLOW = 226 +_FG_CYAN = 51 + +# Per-mode glyphs (mirror AGENT_GLYPHS in codingbuddy-hud.py). +_MODE_GLYPHS: Dict[str, str] = { + "PLAN": "\u25c7", # ◇ + "ACT": "\u25c6", # ◆ + "EVAL": "\u25c8", # ◈ + "AUTO": "\u25ca", # ◊ +} + +# Per-mode RGB anchor pairs for gradient rendering. AUTO uses a +# 6-stop rainbow; PLAN/ACT/EVAL use a single solid hue applied to +# every character. +MODE_PALETTE: Dict[str, List[Tuple[int, int, int]]] = { + "PLAN": [(64, 128, 255)], # steady blue + "ACT": [(64, 200, 96)], # steady green + "EVAL": [(180, 96, 220)], # steady purple + "AUTO": [ + (255, 64, 64), # red + (255, 144, 32), # orange + (255, 224, 32), # yellow + (64, 200, 96), # green + (64, 128, 255), # blue + (180, 96, 220), # purple + ], +} + +# Reset sequence exposed for callers (tests). +RESET: str = _RESET + + +# ------------------------------------------------------------------------ +# Environment detection +# ------------------------------------------------------------------------ + + +def is_color_enabled(env: Dict[str, str] = None) -> bool: # type: ignore[assignment] + """Return True when ANSI color output should be produced. + + Honours the ``NO_COLOR`` standard (https://no-color.org): any + non-empty value disables color. When ``env`` is omitted, reads + from :data:`os.environ`. + """ + if env is None: + env = os.environ + value = env.get("NO_COLOR", "") + return not value + + +# ------------------------------------------------------------------------ +# Glyph helper +# ------------------------------------------------------------------------ + + +def mode_glyph(mode: str) -> str: + """Return the Unicode glyph for a mode, or an empty string. + + Mode matching is case-insensitive. Unknown modes return + an empty string so callers can render just the text label. + """ + if not mode: + return "" + return _MODE_GLYPHS.get(mode.upper(), "") + + +# ------------------------------------------------------------------------ +# Gradient renderer +# ------------------------------------------------------------------------ + + +def _rgb_escape(r: int, g: int, b: int) -> str: + """Return the ANSI truecolor foreground escape for ``(r, g, b)``.""" + return f"{_CSI}38;2;{r};{g};{b}m" + + +def gradient_ansi(text: str, palette: List[Tuple[int, int, int]]) -> str: + """Apply a character-by-character gradient to ``text``. + + When ``palette`` has a single color, every character is rendered + in that color. When it has multiple colors, each character is + linearly mapped to a stop on the palette so the first character + is ``palette[0]`` and the last character is ``palette[-1]``. + + Returns ``text`` unchanged (without escapes) when ``palette`` is + empty or ``text`` is empty. + """ + if not text or not palette: + return text + + if len(palette) == 1: + r, g, b = palette[0] + return f"{_rgb_escape(r, g, b)}{text}{_RESET}" + + n_chars = len(text) + n_stops = len(palette) + out: List[str] = [] + for i, ch in enumerate(text): + # Map character index to palette stop (0..n_stops-1) + stop = int(i * n_stops / max(n_chars, 1)) + stop = min(stop, n_stops - 1) + r, g, b = palette[stop] + out.append(f"{_rgb_escape(r, g, b)}{ch}") + out.append(_RESET) + return "".join(out) + + +# ------------------------------------------------------------------------ +# End-to-end renderer +# ------------------------------------------------------------------------ + + +def render_mode_rainbow( + mode: str, + *, + enabled: bool = None, # type: ignore[assignment] + env: Dict[str, str] = None, # type: ignore[assignment] +) -> str: + """Render the mode label with glyph + ANSI color. + + Output format: + + `` `` + + The label text is the uppercased mode name. When color is + enabled, the whole string (glyph + space + label) is wrapped + in the mode's palette via :func:`gradient_ansi`. When color + is disabled, plain text is returned. + + Args: + mode: Workflow mode name (case-insensitive: PLAN/ACT/EVAL/AUTO). + enabled: Explicit override. ``None`` (default) defers to + :func:`is_color_enabled` which honours ``NO_COLOR``. + env: Optional environment override for testing. + + Returns an empty string when ``mode`` is empty. + """ + if not mode: + return "" + + mode_upper = mode.upper() + glyph = mode_glyph(mode_upper) + label = f"{glyph} {mode_upper}" if glyph else mode_upper + + if enabled is None: + enabled = is_color_enabled(env) + if not enabled: + return label + + palette = MODE_PALETTE.get(mode_upper) + if not palette: + return label # unknown mode: plain text + + return gradient_ansi(label, palette) + + +def strip_ansi(s: str) -> str: + """Remove ANSI CSI sequences from ``s`` (helper for tests and layout). + + Simple state machine — recognises ``ESC [`` ... ``m`` escape + runs. Sufficient for the escapes this module emits. + """ + if not s or "\x1b" not in s: + return s + out: List[str] = [] + i = 0 + n = len(s) + while i < n: + ch = s[i] + if ch == "\x1b" and i + 1 < n and s[i + 1] == "[": + # Skip until 'm' + j = i + 2 + while j < n and s[j] != "m": + j += 1 + i = j + 1 + continue + out.append(ch) + i += 1 + return "".join(out) diff --git a/packages/claude-code-plugin/tests/test_hud_rainbow.py b/packages/claude-code-plugin/tests/test_hud_rainbow.py index 29333634..07b55981 100644 --- a/packages/claude-code-plugin/tests/test_hud_rainbow.py +++ b/packages/claude-code-plugin/tests/test_hud_rainbow.py @@ -1,4 +1,4 @@ -"""Skeleton sanity for hud_rainbow — Wave 2-D placeholder (#1463).""" +"""Behavior tests for hud_rainbow ANSI coloring (Wave 2-D / #1326).""" import os import sys @@ -9,7 +9,221 @@ if _p not in sys.path: sys.path.insert(0, _p) +import hud_rainbow # noqa: E402 -def test_module_loads(): - """Contract: hud_rainbow must be importable. Wave 2-D will add real assertions.""" - import hud_rainbow # noqa: F401 + +# --------------------------- is_color_enabled ------------------------------ + + +def test_color_enabled_when_no_env_var(): + assert hud_rainbow.is_color_enabled(env={}) is True + + +def test_color_disabled_by_no_color_env(): + """NO_COLOR=1 disables color output.""" + assert hud_rainbow.is_color_enabled(env={"NO_COLOR": "1"}) is False + + +def test_color_disabled_by_any_nonempty_no_color(): + """Any non-empty NO_COLOR value disables color (per spec).""" + assert hud_rainbow.is_color_enabled(env={"NO_COLOR": "true"}) is False + assert hud_rainbow.is_color_enabled(env={"NO_COLOR": "yes"}) is False + + +def test_color_enabled_when_no_color_is_empty_string(): + """Empty NO_COLOR value means color is allowed.""" + assert hud_rainbow.is_color_enabled(env={"NO_COLOR": ""}) is True + + +def test_color_env_default_uses_os_environ(monkeypatch): + """When env=None, reads from os.environ.""" + monkeypatch.delenv("NO_COLOR", raising=False) + assert hud_rainbow.is_color_enabled() is True + monkeypatch.setenv("NO_COLOR", "1") + assert hud_rainbow.is_color_enabled() is False + + +# --------------------------- mode_glyph ----------------------------------- + + +def test_mode_glyph_plan(): + assert hud_rainbow.mode_glyph("PLAN") == "\u25c7" # ◇ + + +def test_mode_glyph_act(): + assert hud_rainbow.mode_glyph("ACT") == "\u25c6" # ◆ + + +def test_mode_glyph_eval(): + assert hud_rainbow.mode_glyph("EVAL") == "\u25c8" # ◈ + + +def test_mode_glyph_auto(): + assert hud_rainbow.mode_glyph("AUTO") == "\u25ca" # ◊ + + +def test_mode_glyph_case_insensitive(): + assert hud_rainbow.mode_glyph("plan") == "\u25c7" + + +def test_mode_glyph_unknown_returns_empty(): + assert hud_rainbow.mode_glyph("Ready") == "" + assert hud_rainbow.mode_glyph("DEBUG") == "" + + +def test_mode_glyph_empty_input(): + assert hud_rainbow.mode_glyph("") == "" + + +# --------------------------- gradient_ansi -------------------------------- + + +def test_gradient_single_color_wraps_text(): + """Single color palette wraps entire text in one escape.""" + result = hud_rainbow.gradient_ansi("PLAN", [(0, 0, 255)]) + assert "PLAN" in result + assert result.startswith("\x1b[38;2;0;0;255m") + assert result.endswith("\x1b[0m") + + +def test_gradient_multiple_colors_per_char(): + """Multi-stop palette assigns a color per character.""" + palette = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] + result = hud_rainbow.gradient_ansi("abc", palette) + assert "a" in result + assert "b" in result + assert "c" in result + # At least one red and one blue escape present + assert "38;2;255;0;0" in result + assert "38;2;0;0;255" in result + + +def test_gradient_empty_text_returns_empty(): + assert hud_rainbow.gradient_ansi("", [(255, 0, 0)]) == "" + + +def test_gradient_empty_palette_returns_text_unchanged(): + assert hud_rainbow.gradient_ansi("PLAN", []) == "PLAN" + + +def test_gradient_ends_with_reset(): + result = hud_rainbow.gradient_ansi("X", [(100, 100, 100)]) + assert result.endswith(hud_rainbow.RESET) + + +# --------------------------- render_mode_rainbow -------------------------- + + +def test_render_plan_has_glyph_and_label(): + result = hud_rainbow.render_mode_rainbow("PLAN", enabled=False) + assert "\u25c7" in result # ◇ + assert "PLAN" in result + + +def test_render_act_has_glyph_and_label(): + result = hud_rainbow.render_mode_rainbow("ACT", enabled=False) + assert "\u25c6" in result # ◆ + assert "ACT" in result + + +def test_render_eval_has_glyph_and_label(): + result = hud_rainbow.render_mode_rainbow("EVAL", enabled=False) + assert "\u25c8" in result # ◈ + assert "EVAL" in result + + +def test_render_auto_has_glyph_and_label(): + result = hud_rainbow.render_mode_rainbow("AUTO", enabled=False) + assert "\u25ca" in result # ◊ + assert "AUTO" in result + + +def test_render_disabled_strips_ansi(): + """With enabled=False, output is plain text.""" + result = hud_rainbow.render_mode_rainbow("PLAN", enabled=False) + assert "\x1b[" not in result + assert result == "\u25c7 PLAN" + + +def test_render_enabled_wraps_ansi(): + """With enabled=True, output contains ANSI escape codes.""" + result = hud_rainbow.render_mode_rainbow("PLAN", enabled=True) + assert "\x1b[" in result + assert "\u25c7" in result + assert "PLAN" in result + assert result.endswith("\x1b[0m") + + +def test_render_auto_uses_multi_color_gradient(): + """AUTO mode applies a multi-stop rainbow.""" + result = hud_rainbow.render_mode_rainbow("AUTO", enabled=True) + # Rainbow palette has 6 distinct color escapes + assert result.count("\x1b[38;2;") >= 2 + + +def test_render_no_color_env_forces_plain(monkeypatch): + """NO_COLOR env var forces plain output.""" + monkeypatch.setenv("NO_COLOR", "1") + result = hud_rainbow.render_mode_rainbow("PLAN") + assert "\x1b[" not in result + + +def test_render_unknown_mode_plain(): + """Unknown mode still renders as plain uppercase text.""" + result = hud_rainbow.render_mode_rainbow("Ready", enabled=True) + assert "READY" in result + # No ANSI escapes because no palette entry for unknown mode + assert "\x1b[" not in result + + +def test_render_empty_mode_returns_empty(): + assert hud_rainbow.render_mode_rainbow("") == "" + + +def test_render_case_insensitive(): + """Mode name matching is case-insensitive.""" + result = hud_rainbow.render_mode_rainbow("plan", enabled=False) + assert "PLAN" in result + assert "\u25c7" in result + + +# --------------------------- strip_ansi ----------------------------------- + + +def test_strip_ansi_removes_escapes(): + colored = hud_rainbow.render_mode_rainbow("PLAN", enabled=True) + stripped = hud_rainbow.strip_ansi(colored) + assert stripped == "\u25c7 PLAN" + + +def test_strip_ansi_noop_on_plain_text(): + assert hud_rainbow.strip_ansi("hello") == "hello" + + +def test_strip_ansi_empty_string(): + assert hud_rainbow.strip_ansi("") == "" + + +def test_strip_ansi_preserves_text_between_escapes(): + s = "\x1b[31mred\x1b[0m and \x1b[32mgreen\x1b[0m" + assert hud_rainbow.strip_ansi(s) == "red and green" + + +# --------------------------- MODE_PALETTE --------------------------------- + + +def test_mode_palette_has_all_four_modes(): + for mode in ("PLAN", "ACT", "EVAL", "AUTO"): + assert mode in hud_rainbow.MODE_PALETTE + assert len(hud_rainbow.MODE_PALETTE[mode]) >= 1 + + +def test_mode_palette_auto_is_rainbow(): + """AUTO palette is a multi-stop gradient.""" + assert len(hud_rainbow.MODE_PALETTE["AUTO"]) >= 3 + + +def test_mode_palette_solid_modes_have_single_stop(): + """PLAN, ACT, EVAL are solid colors (single stop).""" + for mode in ("PLAN", "ACT", "EVAL"): + assert len(hud_rainbow.MODE_PALETTE[mode]) == 1 From 446cc84fe5d6b21a34e545cc2bf404e1df5cfbc9 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: