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/packages/claude-code-plugin/hooks/lib/hud_buddy.py b/packages/claude-code-plugin/hooks/lib/hud_buddy.py index 50da56f0..5194e951 100644 --- a/packages/claude-code-plugin/hooks/lib/hud_buddy.py +++ b/packages/claude-code-plugin/hooks/lib/hud_buddy.py @@ -1,17 +1,148 @@ -"""Buddy face re-export for CodingBuddy statusLine (#1326). +"""Buddy face state engine for CodingBuddy statusLine (#1326, Wave 2-A). -``BUDDY_FACE`` is canonically defined in -``tiny_actor_presets.BUDDY_FACE`` and already covered by -``tests/test_tiny_actor_presets.py`` for value/type assertions. This -module re-exports it so statusLine helpers that conceptually belong to -the HUD layer can depend on a ``hud_*`` module instead of reaching into -``tiny_actor_presets``. +``BUDDY_FACE`` is still canonically defined in +``tiny_actor_presets.BUDDY_FACE`` and re-exported here for import +clarity at the HUD layer. Wave 2-A adds a **state-aware** face +picker so the Buddy appears to "breathe" as the session moves +through its lifecycle phases: -Wave 0 establishes the re-export only. Wave 2-A will extend this file -with breathing Buddy face state logic (e.g., ``get_buddy_face(phase)``). +- **Idle / Ready** → ``◕‿◕`` — resting, calm +- **Thinking / Planning** → ``◔‿◔`` — half-closed eyes, pondering +- **Active / Executing** → ``◕◡◕`` — smiling, working +- **Error / Blocked** → ``◕︵◕`` — concerned, something broke +- **Victory / Completed**→ ``◕ᴗ◕`` — beaming, success + +Priority rules: + +1. ``blocker_count > 0`` always wins (error face) regardless of phase. +2. ``recent_event == "victory"`` wins over phase when set. +3. Otherwise the phase mapping decides. +4. Unknown/empty phase falls back to the canonical idle face. + +Primary entry points: + +- :data:`BUDDY_FACE` — canonical idle glyph (re-exported) +- :data:`FACE_*` — individual state glyphs as constants +- :func:`get_buddy_face` — state-to-glyph lookup +- :func:`select_face_from_state` — HUD-state-dict convenience wrapper """ from __future__ import annotations -from tiny_actor_presets import BUDDY_FACE # canonical SSoT +from typing import Any, Dict, Optional + +from tiny_actor_presets import BUDDY_FACE # canonical SSoT (idle face) + +# ------------------------------------------------------------------------ +# Face glyph constants +# ------------------------------------------------------------------------ + +#: Default / idle face — ``◕‿◕`` (U+25D5 U+203F U+25D5). +FACE_IDLE: str = BUDDY_FACE + +#: Thinking face — ``◔‿◔`` (half-closed eyes). +FACE_THINKING: str = "\u25d4\u203f\u25d4" + +#: Active face — ``◕◡◕`` (smiling, working). +FACE_ACTIVE: str = "\u25d5\u25e1\u25d5" + +#: Error / blocked face — ``◕︵◕`` (concerned). +FACE_ERROR: str = "\u25d5\ufe35\u25d5" + +#: Victory / completed face — ``◕ᴗ◕`` (beaming). +FACE_VICTORY: str = "\u25d5\u1d17\u25d5" + + +# ------------------------------------------------------------------------ +# Phase → face mapping +# ------------------------------------------------------------------------ + +_PHASE_FACE_MAP: Dict[str, str] = { + "ready": FACE_IDLE, + "planning": FACE_THINKING, + "executing": FACE_ACTIVE, + "evaluating": FACE_THINKING, + "cycling": FACE_ACTIVE, + "completed": FACE_VICTORY, +} + + +# ------------------------------------------------------------------------ +# Public API +# ------------------------------------------------------------------------ + + +def get_buddy_face( + phase: Optional[str] = None, + *, + blocker_count: int = 0, + recent_event: Optional[str] = None, +) -> str: + """Return the buddy face glyph for the given state. + + Priority resolution (highest wins): + + 1. ``blocker_count > 0`` → :data:`FACE_ERROR` + 2. ``recent_event == "victory"`` → :data:`FACE_VICTORY` + 3. Phase lookup against :data:`_PHASE_FACE_MAP` + 4. Fallback: :data:`FACE_IDLE` + + Args: + phase: HUD state phase. One of + ``ready``, ``planning``, ``executing``, ``evaluating``, + ``cycling``, ``completed`` (case-insensitive). Unknown + or empty values fall back to the idle face. + blocker_count: Number of blockers detected. Any positive + value triggers the error face. + recent_event: Optional one-off event marker. Currently only + ``"victory"`` is recognised. + + Returns: + A 3-character glyph string, never empty. + """ + # (1) Error: blockers take precedence + try: + if int(blocker_count) > 0: + return FACE_ERROR + except (TypeError, ValueError): + pass # ignore malformed counter, fall through + + # (2) Victory event beats phase + if recent_event and recent_event.lower() == "victory": + return FACE_VICTORY + + # (3) Phase mapping + if phase: + return _PHASE_FACE_MAP.get(phase.lower(), FACE_IDLE) + + # (4) Fallback + return FACE_IDLE + + +def select_face_from_state(hud_state: Dict[str, Any]) -> str: + """Convenience wrapper that extracts face inputs from a hud_state dict. + + Reads: + + - ``phase`` — HUD phase string + - ``blockerCount`` — integer blocker count (default 0) + - ``lastEvent`` — optional one-off event marker + """ + if not hud_state: + return FACE_IDLE + return get_buddy_face( + phase=hud_state.get("phase"), + blocker_count=hud_state.get("blockerCount", 0) or 0, + recent_event=hud_state.get("lastEvent"), + ) + -__all__ = ["BUDDY_FACE"] +__all__ = [ + "BUDDY_FACE", + "FACE_IDLE", + "FACE_THINKING", + "FACE_ACTIVE", + "FACE_ERROR", + "FACE_VICTORY", + "get_buddy_face", + "select_face_from_state", +] diff --git a/packages/claude-code-plugin/tests/test_hud_buddy.py b/packages/claude-code-plugin/tests/test_hud_buddy.py index 4f6ff296..f64b21c9 100644 --- a/packages/claude-code-plugin/tests/test_hud_buddy.py +++ b/packages/claude-code-plugin/tests/test_hud_buddy.py @@ -29,3 +29,171 @@ def test_reexport_identity_from_codingbuddy_hud(): hud_main = importlib.import_module("codingbuddy-hud") assert hud_main.BUDDY_FACE is hud_buddy.BUDDY_FACE assert hud_main.BUDDY_FACE is CANONICAL_BUDDY_FACE + + +# ========================= Wave 2-A: face state engine ====================== + + +def test_face_constants_defined(): + """All five named faces are distinct non-empty strings.""" + faces = { + hud_buddy.FACE_IDLE, + hud_buddy.FACE_THINKING, + hud_buddy.FACE_ACTIVE, + hud_buddy.FACE_ERROR, + hud_buddy.FACE_VICTORY, + } + assert len(faces) == 5 + for face in faces: + assert face # non-empty + assert len(face) >= 3 # 3-char glyphs + + +def test_face_idle_matches_canonical_buddy(): + """FACE_IDLE is the canonical buddy face.""" + assert hud_buddy.FACE_IDLE is hud_buddy.BUDDY_FACE + + +# --- get_buddy_face: phase mapping --- + + +def test_get_face_ready_phase_is_idle(): + assert hud_buddy.get_buddy_face("ready") == hud_buddy.FACE_IDLE + + +def test_get_face_planning_phase_is_thinking(): + assert hud_buddy.get_buddy_face("planning") == hud_buddy.FACE_THINKING + + +def test_get_face_executing_phase_is_active(): + assert hud_buddy.get_buddy_face("executing") == hud_buddy.FACE_ACTIVE + + +def test_get_face_evaluating_phase_is_thinking(): + assert hud_buddy.get_buddy_face("evaluating") == hud_buddy.FACE_THINKING + + +def test_get_face_cycling_phase_is_active(): + assert hud_buddy.get_buddy_face("cycling") == hud_buddy.FACE_ACTIVE + + +def test_get_face_completed_phase_is_victory(): + assert hud_buddy.get_buddy_face("completed") == hud_buddy.FACE_VICTORY + + +def test_get_face_case_insensitive(): + assert hud_buddy.get_buddy_face("PLANNING") == hud_buddy.FACE_THINKING + assert hud_buddy.get_buddy_face("Executing") == hud_buddy.FACE_ACTIVE + + +def test_get_face_unknown_phase_falls_back_to_idle(): + assert hud_buddy.get_buddy_face("waiting") == hud_buddy.FACE_IDLE + assert hud_buddy.get_buddy_face("unknown") == hud_buddy.FACE_IDLE + + +def test_get_face_empty_phase_is_idle(): + assert hud_buddy.get_buddy_face("") == hud_buddy.FACE_IDLE + + +def test_get_face_none_phase_is_idle(): + assert hud_buddy.get_buddy_face(None) == hud_buddy.FACE_IDLE + + +# --- get_buddy_face: priority rules --- + + +def test_blocker_count_beats_phase(): + """Any positive blocker_count triggers the error face.""" + assert ( + hud_buddy.get_buddy_face("executing", blocker_count=1) + == hud_buddy.FACE_ERROR + ) + + +def test_blocker_count_zero_does_not_trigger(): + assert ( + hud_buddy.get_buddy_face("executing", blocker_count=0) + == hud_buddy.FACE_ACTIVE + ) + + +def test_blocker_count_beats_victory(): + """Even a victory event yields error when blockers are present.""" + assert ( + hud_buddy.get_buddy_face( + "completed", blocker_count=3, recent_event="victory" + ) + == hud_buddy.FACE_ERROR + ) + + +def test_blocker_count_malformed_ignored(): + """Non-numeric blocker_count falls through to phase mapping.""" + assert ( + hud_buddy.get_buddy_face("planning", blocker_count="abc") # type: ignore[arg-type] + == hud_buddy.FACE_THINKING + ) + + +def test_recent_event_victory_beats_phase(): + """Victory event wins over phase when no blockers.""" + assert ( + hud_buddy.get_buddy_face("executing", recent_event="victory") + == hud_buddy.FACE_VICTORY + ) + + +def test_recent_event_case_insensitive(): + assert ( + hud_buddy.get_buddy_face("planning", recent_event="VICTORY") + == hud_buddy.FACE_VICTORY + ) + + +def test_recent_event_unknown_ignored(): + assert ( + hud_buddy.get_buddy_face("planning", recent_event="foobar") + == hud_buddy.FACE_THINKING + ) + + +# --- select_face_from_state --- + + +def test_select_face_from_empty_state(): + assert hud_buddy.select_face_from_state({}) == hud_buddy.FACE_IDLE + + +def test_select_face_from_none_state(): + assert hud_buddy.select_face_from_state(None) == hud_buddy.FACE_IDLE # type: ignore[arg-type] + + +def test_select_face_from_planning_state(): + state = {"phase": "planning", "blockerCount": 0} + assert hud_buddy.select_face_from_state(state) == hud_buddy.FACE_THINKING + + +def test_select_face_from_blocked_state(): + state = {"phase": "executing", "blockerCount": 2} + assert hud_buddy.select_face_from_state(state) == hud_buddy.FACE_ERROR + + +def test_select_face_from_victory_state(): + state = {"phase": "completed", "blockerCount": 0, "lastEvent": "victory"} + assert hud_buddy.select_face_from_state(state) == hud_buddy.FACE_VICTORY + + +def test_select_face_from_completed_state_without_victory_marker(): + state = {"phase": "completed", "blockerCount": 0} + assert hud_buddy.select_face_from_state(state) == hud_buddy.FACE_VICTORY + + +# --- __all__ exports --- + + +def test_public_api_exported(): + assert "BUDDY_FACE" in hud_buddy.__all__ + assert "get_buddy_face" in hud_buddy.__all__ + assert "select_face_from_state" in hud_buddy.__all__ + for name in ("FACE_IDLE", "FACE_THINKING", "FACE_ACTIVE", "FACE_ERROR", "FACE_VICTORY"): + assert name in hud_buddy.__all__ 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: