docs(watcher): point header at Python source modules #163
+7
−3
Annotations
10 errors and 2 warnings
|
Test:
src/dice/DiceScene.tsx#L171
Error: [vitest] No "useLoader" export is defined on the "@react-three/fiber" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:
vi.mock(import("@react-three/fiber"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})
❯ D20Mesh src/dice/DiceScene.tsx:171:19
❯ Object.react_stack_bottom_frame node_modules/react-dom/cjs/react-dom-client.development.js:25904:20
❯ renderWithHooks node_modules/react-dom/cjs/react-dom-client.development.js:7662:22
❯ updateFunctionComponent node_modules/react-dom/cjs/react-dom-client.development.js:10166:19
❯ beginWork node_modules/react-dom/cjs/react-dom-client.development.js:11778:18
❯ runWithFiberInDEV node_modules/react-dom/cjs/react-dom-client.development.js:874:13
❯ performUnitOfWork node_modules/react-dom/cjs/react-dom-client.development.js:17641:22
❯ workLoopSync node_modules/react-dom/cjs/react-dom-client.development.js:17469:41
|
|
Test:
src/dice/DiceScene.tsx#L171
Error: [vitest] No "useLoader" export is defined on the "@react-three/fiber" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:
vi.mock(import("@react-three/fiber"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})
❯ D20Mesh src/dice/DiceScene.tsx:171:19
❯ Object.react_stack_bottom_frame node_modules/react-dom/cjs/react-dom-client.development.js:25904:20
❯ renderWithHooks node_modules/react-dom/cjs/react-dom-client.development.js:7662:22
❯ updateFunctionComponent node_modules/react-dom/cjs/react-dom-client.development.js:10166:19
❯ beginWork node_modules/react-dom/cjs/react-dom-client.development.js:11778:18
❯ runWithFiberInDEV node_modules/react-dom/cjs/react-dom-client.development.js:874:13
❯ performUnitOfWork node_modules/react-dom/cjs/react-dom-client.development.js:17641:22
❯ workLoopSync node_modules/react-dom/cjs/react-dom-client.development.js:17469:41
|
|
Test:
src/dice/DiceScene.tsx#L171
Error: [vitest] No "useLoader" export is defined on the "@react-three/fiber" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:
vi.mock(import("@react-three/fiber"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})
❯ D20Mesh src/dice/DiceScene.tsx:171:19
❯ Object.react_stack_bottom_frame node_modules/react-dom/cjs/react-dom-client.development.js:25904:20
❯ renderWithHooks node_modules/react-dom/cjs/react-dom-client.development.js:7662:22
❯ updateFunctionComponent node_modules/react-dom/cjs/react-dom-client.development.js:10166:19
❯ beginWork node_modules/react-dom/cjs/react-dom-client.development.js:11778:18
❯ runWithFiberInDEV node_modules/react-dom/cjs/react-dom-client.development.js:874:13
❯ performUnitOfWork node_modules/react-dom/cjs/react-dom-client.development.js:17641:22
❯ workLoopSync node_modules/react-dom/cjs/react-dom-client.development.js:17469:41
|
|
Test:
src/dice/DiceScene.tsx#L171
Error: [vitest] No "useLoader" export is defined on the "@react-three/fiber" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:
vi.mock(import("@react-three/fiber"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})
❯ D20Mesh src/dice/DiceScene.tsx:171:19
❯ Object.react_stack_bottom_frame node_modules/react-dom/cjs/react-dom-client.development.js:25904:20
❯ renderWithHooks node_modules/react-dom/cjs/react-dom-client.development.js:7662:22
❯ updateFunctionComponent node_modules/react-dom/cjs/react-dom-client.development.js:10166:19
❯ beginWork node_modules/react-dom/cjs/react-dom-client.development.js:11778:18
❯ runWithFiberInDEV node_modules/react-dom/cjs/react-dom-client.development.js:874:13
❯ performUnitOfWork node_modules/react-dom/cjs/react-dom-client.development.js:17641:22
❯ workLoopSync node_modules/react-dom/cjs/react-dom-client.development.js:17469:41
|
|
Test:
src/__tests__/dice-overlay-wiring-34-5.test.ts#L238
AssertionError: expected 'handleDiceThrow = useCallback(\n (…' to match /face\s*,?\s*\}/
- Expected:
/face\s*,?\s*\}/
+ Received:
"handleDiceThrow = useCallback(
(params: DiceThrowParams, face: number[]) => {
if (!diceRequest) return;
const beatId = pendingBeatIdRef.current;
pendingBeatIdRef.current = null;
send({
type: MessageType.DICE_THROW,
payload: {
request_id: diceRequest.request_id,
throw_params: params,
face,
...(beatId ? { beat_id: beatId } : {}),
},
player_id: \"\",
});
// If this was a beat roll, set thinking — narrator will run server-side
if (beatId) {
setCanType(false);
setThinking(true);
}
},
[diceRequest, send],
)"
❯ src/__tests__/dice-overlay-wiring-34-5.test.ts:238:30
|
|
Test:
src/__tests__/dice-overlay-wiring-34-5.test.ts#L179
AssertionError: expected 'import { lazy, Suspense, useCallback,…' to match /playerId=\{/
- Expected:
/playerId=\{/
+ Received:
"import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from \"react\";
import { Route, Routes, useNavigate, useParams } from \"react-router-dom\";
import { ConnectScreen } from \"@/screens/ConnectScreen\";
import { CharacterCreation, type CreationScene } from \"@/components/CharacterCreation/CharacterCreation\";
import { GameBoard } from \"@/components/GameBoard/GameBoard\";
import { ImageBusProvider } from \"@/providers/ImageBusProvider\";
import type { ResourcePool } from \"@/components/CharacterPanel\";
import { ErrorBoundary } from \"@/components/ErrorBoundary\";
import { GameStateProvider, useGameState } from \"@/providers/GameStateProvider\";
import { useGameSocket } from \"@/hooks/useGameSocket\";
import { useGenreTheme } from \"@/hooks/useGenreTheme\";
import { useChromeArchetype } from \"@/hooks/useChromeArchetype\";
import { useAudioCue } from \"@/hooks/useAudioCue\";
import { useAudio } from \"@/hooks/useAudio\";
import { useStateMirror } from \"@/hooks/useStateMirror\";
import { useSlashCommands } from \"@/hooks/useSlashCommands\";
import { useGameBoardLayout } from \"@/hooks/useGameBoardLayout\";
import { useLayoutMode } from \"@/hooks/useLayoutMode\";
import { MessageType, type GameMessage } from \"@/types/protocol\";
import type { CharacterSheetData } from \"@/components/CharacterSheet\";
import type { InventoryData } from \"@/components/InventoryPanel\";
import type { MapState } from \"@/components/MapOverlay\";
import type { CharacterSummary } from \"@/types/party\";
import type { ConfrontationData, BeatOption } from \"@/components/ConfrontationOverlay\";
import type { TurnStatusEntry } from \"@/components/TurnStatusPanel\";
import type { DiceRequestPayload, DiceResultPayload, DiceThrowParams } from \"@/types/payloads\";
import type { GenresResponse } from \"@/types/genres\";
import { ReconnectBanner } from \"@/components/ReconnectBanner\";
import { PausedBanner } from \"@/components/PausedBanner\";
import { OfflineBanner } from \"@/components/OfflineBanner\";
import { useDisplayName } from \"@/hooks/useDisplayName\";
import { usePeerEventCache } from \"@/hooks/usePeerEventCache\";
const LazyDashboard = lazy(() =>
import(\"@/components/Dashboard/DashboardApp\").then((m) => ({ default: m.DashboardApp })),
);
// DiceOverlay overlay removed — dice now render inline in the Confrontation panel
// via InlineDiceTray. The DiceOverlay component and DiceSpikePage are retained
// for isolated testing.
type SessionPhase = \"connect\" | \"creation\" | \"game\";
const SESSION_KEY = \"sidequest-session\";
// SavedSession stores only the game_slug (MP-01 migration). The old
// playerName+genre+world shape is gone — use game_slug for all reconnect paths.
interface SavedSession {
gameSlug: string;
}
function loadSession(): SavedSession | null {
try {
const raw = sessionStorage.getItem(SESSION_KEY);
if (!raw) return null;
const data = JSON.parse(raw) as SavedSession;
if (data.gameSlug) return data;
return null;
} catch {
return null;
}
}
function saveSession(gameSlug: string) {
try {
sessionStorage.setItem(SESSION_KEY, JSON.stringify({ gameSlug }));
} catch {
// non-critical
}
}
function clearSession() {
try {
sessionStorage.removeItem(SESSION_KEY);
} catch {
// non-critical
}
}
// Bug 2: HMR state persistence — survive Vite hot reload without losing game progress
const HMR_STATE_KEY = \"sidequest-hmr-state\";
interface HmrState {
messages: GameMessage[];
sessionPhase: SessionPhase;
character: Record<string, unknown> | null;
}
function loadHmrState(): HmrState | null {
try {
const raw = sessionStorage.getItem(HMR_STATE_KEY);
if (!raw) return null;
return JSON.parse(raw) as HmrState;
} catch {
return null;
}
}
function saveHmrState(state: HmrState): void {
try {
// Keep only the last 100 messages to avoid quota issues
const trimmed = {
...state,
|
|
Test:
src/__tests__/dice-overlay-wiring-34-5.test.ts#L87
AssertionError: expected 'import { lazy, Suspense, useCallback,…' to match /onThrow=\{/
- Expected:
/onThrow=\{/
+ Received:
"import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from \"react\";
import { Route, Routes, useNavigate, useParams } from \"react-router-dom\";
import { ConnectScreen } from \"@/screens/ConnectScreen\";
import { CharacterCreation, type CreationScene } from \"@/components/CharacterCreation/CharacterCreation\";
import { GameBoard } from \"@/components/GameBoard/GameBoard\";
import { ImageBusProvider } from \"@/providers/ImageBusProvider\";
import type { ResourcePool } from \"@/components/CharacterPanel\";
import { ErrorBoundary } from \"@/components/ErrorBoundary\";
import { GameStateProvider, useGameState } from \"@/providers/GameStateProvider\";
import { useGameSocket } from \"@/hooks/useGameSocket\";
import { useGenreTheme } from \"@/hooks/useGenreTheme\";
import { useChromeArchetype } from \"@/hooks/useChromeArchetype\";
import { useAudioCue } from \"@/hooks/useAudioCue\";
import { useAudio } from \"@/hooks/useAudio\";
import { useStateMirror } from \"@/hooks/useStateMirror\";
import { useSlashCommands } from \"@/hooks/useSlashCommands\";
import { useGameBoardLayout } from \"@/hooks/useGameBoardLayout\";
import { useLayoutMode } from \"@/hooks/useLayoutMode\";
import { MessageType, type GameMessage } from \"@/types/protocol\";
import type { CharacterSheetData } from \"@/components/CharacterSheet\";
import type { InventoryData } from \"@/components/InventoryPanel\";
import type { MapState } from \"@/components/MapOverlay\";
import type { CharacterSummary } from \"@/types/party\";
import type { ConfrontationData, BeatOption } from \"@/components/ConfrontationOverlay\";
import type { TurnStatusEntry } from \"@/components/TurnStatusPanel\";
import type { DiceRequestPayload, DiceResultPayload, DiceThrowParams } from \"@/types/payloads\";
import type { GenresResponse } from \"@/types/genres\";
import { ReconnectBanner } from \"@/components/ReconnectBanner\";
import { PausedBanner } from \"@/components/PausedBanner\";
import { OfflineBanner } from \"@/components/OfflineBanner\";
import { useDisplayName } from \"@/hooks/useDisplayName\";
import { usePeerEventCache } from \"@/hooks/usePeerEventCache\";
const LazyDashboard = lazy(() =>
import(\"@/components/Dashboard/DashboardApp\").then((m) => ({ default: m.DashboardApp })),
);
// DiceOverlay overlay removed — dice now render inline in the Confrontation panel
// via InlineDiceTray. The DiceOverlay component and DiceSpikePage are retained
// for isolated testing.
type SessionPhase = \"connect\" | \"creation\" | \"game\";
const SESSION_KEY = \"sidequest-session\";
// SavedSession stores only the game_slug (MP-01 migration). The old
// playerName+genre+world shape is gone — use game_slug for all reconnect paths.
interface SavedSession {
gameSlug: string;
}
function loadSession(): SavedSession | null {
try {
const raw = sessionStorage.getItem(SESSION_KEY);
if (!raw) return null;
const data = JSON.parse(raw) as SavedSession;
if (data.gameSlug) return data;
return null;
} catch {
return null;
}
}
function saveSession(gameSlug: string) {
try {
sessionStorage.setItem(SESSION_KEY, JSON.stringify({ gameSlug }));
} catch {
// non-critical
}
}
function clearSession() {
try {
sessionStorage.removeItem(SESSION_KEY);
} catch {
// non-critical
}
}
// Bug 2: HMR state persistence — survive Vite hot reload without losing game progress
const HMR_STATE_KEY = \"sidequest-hmr-state\";
interface HmrState {
messages: GameMessage[];
sessionPhase: SessionPhase;
character: Record<string, unknown> | null;
}
function loadHmrState(): HmrState | null {
try {
const raw = sessionStorage.getItem(HMR_STATE_KEY);
if (!raw) return null;
return JSON.parse(raw) as HmrState;
} catch {
return null;
}
}
function saveHmrState(state: HmrState): void {
try {
// Keep only the last 100 messages to avoid quota issues
const trimmed = {
...state,
|
|
Test:
src/__tests__/dice-overlay-wiring-34-5.test.ts#L29
AssertionError: expected 'import { lazy, Suspense, useCallback,…' to match /lazy\(\s*\(\)\s*=>\s*import\(['"].*d…/i
- Expected:
/lazy\(\s*\(\)\s*=>\s*import\(['"].*dice.*DiceOverlay['"]\)/i
+ Received:
"import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from \"react\";
import { Route, Routes, useNavigate, useParams } from \"react-router-dom\";
import { ConnectScreen } from \"@/screens/ConnectScreen\";
import { CharacterCreation, type CreationScene } from \"@/components/CharacterCreation/CharacterCreation\";
import { GameBoard } from \"@/components/GameBoard/GameBoard\";
import { ImageBusProvider } from \"@/providers/ImageBusProvider\";
import type { ResourcePool } from \"@/components/CharacterPanel\";
import { ErrorBoundary } from \"@/components/ErrorBoundary\";
import { GameStateProvider, useGameState } from \"@/providers/GameStateProvider\";
import { useGameSocket } from \"@/hooks/useGameSocket\";
import { useGenreTheme } from \"@/hooks/useGenreTheme\";
import { useChromeArchetype } from \"@/hooks/useChromeArchetype\";
import { useAudioCue } from \"@/hooks/useAudioCue\";
import { useAudio } from \"@/hooks/useAudio\";
import { useStateMirror } from \"@/hooks/useStateMirror\";
import { useSlashCommands } from \"@/hooks/useSlashCommands\";
import { useGameBoardLayout } from \"@/hooks/useGameBoardLayout\";
import { useLayoutMode } from \"@/hooks/useLayoutMode\";
import { MessageType, type GameMessage } from \"@/types/protocol\";
import type { CharacterSheetData } from \"@/components/CharacterSheet\";
import type { InventoryData } from \"@/components/InventoryPanel\";
import type { MapState } from \"@/components/MapOverlay\";
import type { CharacterSummary } from \"@/types/party\";
import type { ConfrontationData, BeatOption } from \"@/components/ConfrontationOverlay\";
import type { TurnStatusEntry } from \"@/components/TurnStatusPanel\";
import type { DiceRequestPayload, DiceResultPayload, DiceThrowParams } from \"@/types/payloads\";
import type { GenresResponse } from \"@/types/genres\";
import { ReconnectBanner } from \"@/components/ReconnectBanner\";
import { PausedBanner } from \"@/components/PausedBanner\";
import { OfflineBanner } from \"@/components/OfflineBanner\";
import { useDisplayName } from \"@/hooks/useDisplayName\";
import { usePeerEventCache } from \"@/hooks/usePeerEventCache\";
const LazyDashboard = lazy(() =>
import(\"@/components/Dashboard/DashboardApp\").then((m) => ({ default: m.DashboardApp })),
);
// DiceOverlay overlay removed — dice now render inline in the Confrontation panel
// via InlineDiceTray. The DiceOverlay component and DiceSpikePage are retained
// for isolated testing.
type SessionPhase = \"connect\" | \"creation\" | \"game\";
const SESSION_KEY = \"sidequest-session\";
// SavedSession stores only the game_slug (MP-01 migration). The old
// playerName+genre+world shape is gone — use game_slug for all reconnect paths.
interface SavedSession {
gameSlug: string;
}
function loadSession(): SavedSession | null {
try {
const raw = sessionStorage.getItem(SESSION_KEY);
if (!raw) return null;
const data = JSON.parse(raw) as SavedSession;
if (data.gameSlug) return data;
return null;
} catch {
return null;
}
}
function saveSession(gameSlug: string) {
try {
sessionStorage.setItem(SESSION_KEY, JSON.stringify({ gameSlug }));
} catch {
// non-critical
}
}
function clearSession() {
try {
sessionStorage.removeItem(SESSION_KEY);
} catch {
// non-critical
}
}
// Bug 2: HMR state persistence — survive Vite hot reload without losing game progress
const HMR_STATE_KEY = \"sidequest-hmr-state\";
interface HmrState {
messages: GameMessage[];
sessionPhase: SessionPhase;
character: Record<string, unknown> | null;
}
function loadHmrState(): HmrState | null {
try {
const raw = sessionStorage.getItem(HMR_STATE_KEY);
if (!raw) return null;
return JSON.parse(raw) as HmrState;
} catch {
return null;
}
}
function saveHmrState(state: HmrState): void {
try {
// Keep only the last
|
|
Test:
src/__tests__/confrontation-wiring.test.tsx#L306
AssertionError: expected 'import { lazy, Suspense, useCallback,…' to match /type:\s*MessageType\.BEAT_SELECTION/
- Expected:
/type:\s*MessageType\.BEAT_SELECTION/
+ Received:
"import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from \"react\";
import { Route, Routes, useNavigate, useParams } from \"react-router-dom\";
import { ConnectScreen } from \"@/screens/ConnectScreen\";
import { CharacterCreation, type CreationScene } from \"@/components/CharacterCreation/CharacterCreation\";
import { GameBoard } from \"@/components/GameBoard/GameBoard\";
import { ImageBusProvider } from \"@/providers/ImageBusProvider\";
import type { ResourcePool } from \"@/components/CharacterPanel\";
import { ErrorBoundary } from \"@/components/ErrorBoundary\";
import { GameStateProvider, useGameState } from \"@/providers/GameStateProvider\";
import { useGameSocket } from \"@/hooks/useGameSocket\";
import { useGenreTheme } from \"@/hooks/useGenreTheme\";
import { useChromeArchetype } from \"@/hooks/useChromeArchetype\";
import { useAudioCue } from \"@/hooks/useAudioCue\";
import { useAudio } from \"@/hooks/useAudio\";
import { useStateMirror } from \"@/hooks/useStateMirror\";
import { useSlashCommands } from \"@/hooks/useSlashCommands\";
import { useGameBoardLayout } from \"@/hooks/useGameBoardLayout\";
import { useLayoutMode } from \"@/hooks/useLayoutMode\";
import { MessageType, type GameMessage } from \"@/types/protocol\";
import type { CharacterSheetData } from \"@/components/CharacterSheet\";
import type { InventoryData } from \"@/components/InventoryPanel\";
import type { MapState } from \"@/components/MapOverlay\";
import type { CharacterSummary } from \"@/types/party\";
import type { ConfrontationData, BeatOption } from \"@/components/ConfrontationOverlay\";
import type { TurnStatusEntry } from \"@/components/TurnStatusPanel\";
import type { DiceRequestPayload, DiceResultPayload, DiceThrowParams } from \"@/types/payloads\";
import type { GenresResponse } from \"@/types/genres\";
import { ReconnectBanner } from \"@/components/ReconnectBanner\";
import { PausedBanner } from \"@/components/PausedBanner\";
import { OfflineBanner } from \"@/components/OfflineBanner\";
import { useDisplayName } from \"@/hooks/useDisplayName\";
import { usePeerEventCache } from \"@/hooks/usePeerEventCache\";
const LazyDashboard = lazy(() =>
import(\"@/components/Dashboard/DashboardApp\").then((m) => ({ default: m.DashboardApp })),
);
// DiceOverlay overlay removed — dice now render inline in the Confrontation panel
// via InlineDiceTray. The DiceOverlay component and DiceSpikePage are retained
// for isolated testing.
type SessionPhase = \"connect\" | \"creation\" | \"game\";
const SESSION_KEY = \"sidequest-session\";
// SavedSession stores only the game_slug (MP-01 migration). The old
// playerName+genre+world shape is gone — use game_slug for all reconnect paths.
interface SavedSession {
gameSlug: string;
}
function loadSession(): SavedSession | null {
try {
const raw = sessionStorage.getItem(SESSION_KEY);
if (!raw) return null;
const data = JSON.parse(raw) as SavedSession;
if (data.gameSlug) return data;
return null;
} catch {
return null;
}
}
function saveSession(gameSlug: string) {
try {
sessionStorage.setItem(SESSION_KEY, JSON.stringify({ gameSlug }));
} catch {
// non-critical
}
}
function clearSession() {
try {
sessionStorage.removeItem(SESSION_KEY);
} catch {
// non-critical
}
}
// Bug 2: HMR state persistence — survive Vite hot reload without losing game progress
const HMR_STATE_KEY = \"sidequest-hmr-state\";
interface HmrState {
messages: GameMessage[];
sessionPhase: SessionPhase;
character: Record<string, unknown> | null;
}
function loadHmrState(): HmrState | null {
try {
const raw = sessionStorage.getItem(HMR_STATE_KEY);
if (!raw) return null;
return JSON.parse(raw) as HmrState;
} catch {
return null;
}
}
function saveHmrState(state: HmrState): void {
try {
// Keep only the last 100 messages to avoid quota i
|
|
Test:
src/__tests__/confrontation-wiring.test.tsx#L266
AssertionError: expected 'import {\n createContext,\n useCall…' to match /ConfrontationWidget.*data=\{confronta…/
- Expected:
/ConfrontationWidget.*data=\{confrontationData\}/
+ Received:
"import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
type ReactNode,
} from \"react\";
import {
DockviewReact,
type DockviewReadyEvent,
type DockviewApi,
type IDockviewPanelProps,
} from \"dockview-react\";
import \"dockview-react/dist/styles/dockview.css\";
import \"@/styles/dockview-theme.css\";
import { useRunningHeader } from \"@/hooks/useRunningHeader\";
import InputBar from \"@/components/InputBar\";
import { MultiplayerTurnBanner } from \"@/components/MultiplayerTurnBanner\";
import { useBreakpoint } from \"@/hooks/useBreakpoint\";
import { useImageBus } from \"@/providers/ImageBusProvider\";
import { useGameBoardLayout } from \"@/hooks/useGameBoardLayout\";
import { useGameBoardHotkeys } from \"@/hooks/useGameBoardHotkeys\";
import { TurnStatusPanel, type TurnStatusEntry } from \"@/components/TurnStatusPanel\";
import type { ResourceThreshold } from \"@/components/GenericResourceBar\";
import type { CharacterSheetData } from \"@/components/CharacterSheet\";
import type { InventoryData } from \"@/components/InventoryPanel\";
import type { MapState } from \"@/components/MapOverlay\";
import type { ConfrontationData } from \"@/components/ConfrontationOverlay\";
import type { KnowledgeEntry, ItemDepletion, ResourceAlert } from \"@/providers/GameStateProvider\";
import type { ResourcePool } from \"@/components/CharacterPanel\";
import type { CharacterSummary } from \"@/types/party\";
import type { useAudio } from \"@/hooks/useAudio\";
import type { NowPlaying } from \"@/hooks/useAudioCue\";
import type { GameMessage } from \"@/types/protocol\";
import type { DiceRequestPayload, DiceResultPayload, DiceThrowParams } from \"@/types/payloads\";
import type { LayoutMode } from \"@/hooks/useLayoutMode\";
import { WIDGET_REGISTRY, type WidgetId } from \"./widgetRegistry\";
import { BackgroundCanvas } from \"./BackgroundCanvas\";
import { MobileTabView } from \"./MobileTabView\";
import { NarrativeWidget } from \"./widgets/NarrativeWidget\";
import { CharacterWidget } from \"./widgets/CharacterWidget\";
import { MapWidget } from \"./widgets/MapWidget\";
import { InventoryWidget } from \"./widgets/InventoryWidget\";
// JournalWidget removed playtest 2026-04-11 — see widgetRegistry.ts comment.
// JournalView and the journal data pipeline are intentionally retained.
import { KnowledgeWidget } from \"./widgets/KnowledgeWidget\";
import { ConfrontationWidget } from \"./widgets/ConfrontationWidget\";
import { AudioWidget } from \"./widgets/AudioWidget\";
import { ImageGalleryWidget } from \"./widgets/ImageGalleryWidget\";
// ────────────────────────────────────────────────────────────────────────────
// Dockview closure bridge
//
// Dockview freezes the `component` reference at panel-creation time
// (see node_modules/dockview/dist/cjs/dockview/reactContentPart.js — the
// `ReactPanelContentPart` constructor stores `this.component = component`
// and the `update()` method only forwards new params, never a new component).
// So if we defined `PanelAdapter` inline with a `useCallback([renderWidgetContent])`
// dep, the adapter's closure over `renderWidgetContent` — and therefore over
// `messages`, `thinking`, `characterSheet`, etc. — would be locked in forever
// at the moment each panel was first added. Any subsequent setState in the
// parent would be invisible inside the dockview panel: the narrative panel
// wouldn't show new turns, the character panel wouldn't show HP changes,
// and so on. Refreshing the page would appear to \"fix\" it because sessionStorage
// hydration gave the first render the correct initial state.
//
// The fix is to make `PanelAdapter` and `dockviewComponents` module-level
// stable references
|
|
Complete job
Node.js 20 actions are deprecated. The following actions are running on Node.js 20 and may not work as expected: actions/checkout@v4, actions/setup-node@v4. Actions will be forced to run with Node.js 24 by default starting June 2nd, 2026. Node.js 20 will be removed from the runner on September 16th, 2026. Please check if updated versions of these actions are available that support Node.js 24. To opt into Node.js 24 now, set the FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true environment variable on the runner or in your workflow file. Once Node.js 24 becomes the default, you can temporarily opt out by setting ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
|
|
Lint (no cache):
src/App.tsx#L1182
React Hook useEffect has a missing dependency: 'displayName'. Either include it or remove the dependency array
|
Loading