Files
noteflow/.hygeine/eslint.json
Travis Vasceannie 0a18f2d23d chore: update linting artifacts
- Updated basedpyright linting results (705 files analyzed, analysis time reduced from 22.928s to 13.105s).
- Updated biome linting artifact with warning about unnecessary hook dependency (preferencesVersion) in MeetingDetail.tsx.
2026-01-08 21:45:05 -05:00

1 line
148 KiB
JSON

[{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/e2e-native-mac/app.spec.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/e2e-native-mac/fixtures.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/e2e-native-mac/test-helpers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/eslint.config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/playwright.config.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/postcss.config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/App.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached-adapter.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached-adapter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/annotations.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/apps.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/audio.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/base.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/calendar.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/diarization.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/entities.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/meetings.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/observability.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/playback.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/preferences.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/projects.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/readonly.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/templates.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/triggers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/cached/webhooks.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/connection-state.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/connection-state.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/constants.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/helpers.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/helpers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/index.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/index.ts","messages":[{"ruleId":"@typescript-eslint/no-unsafe-return","severity":1,"message":"Unsafe return of a value of type `any`.","line":130,"column":11,"nodeType":"ReturnStatement","messageId":"unsafeReturn","endLine":130,"endColumn":48}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * NoteFlow API - Main Export\n *\n * This module provides the main entry point for the NoteFlow API.\n * It automatically detects the runtime environment and initializes\n * the appropriate backend adapter:\n *\n * - Tauri Desktop: Uses TauriAdapter → Rust backend → gRPC server\n * - Web Browser: Uses MockAdapter with simulated data\n *\n * @see noteflow-api-spec-2.json for the complete gRPC API specification\n */\n\nexport * from './interface';\nexport { mockAPI } from './mock-adapter';\nexport { cachedAPI } from './cached-adapter';\nexport { createTauriAPI, initializeTauriAPI, isTauriEnvironment } from './tauri-adapter';\n// Re-export all types and interfaces\nexport * from './types';\n\nimport { preferences } from '@/lib/preferences';\nimport { startTauriEventBridge } from '@/lib/tauri-events';\nimport { type NoteFlowAPI, setAPIInstance } from './interface';\nimport { cachedAPI } from './cached-adapter';\nimport { getConnectionState, setConnectionMode, setConnectionServerUrl } from './connection-state';\nimport { extractErrorMessage } from './helpers';\nimport { mockAPI } from './mock-adapter';\nimport { startReconnection } from './reconnection';\nimport { initializeTauriAPI } from './tauri-adapter';\n\n// ============================================================================\n// API Initialization\n// ============================================================================\n\n/**\n * Initialize the API with the appropriate backend adapter\n *\n * This function is called automatically on module load,\n * but can also be called manually for testing or custom initialization.\n *\n * Sprint GAP-007: Logs active adapter mode to console for debugging.\n * Sprint GAP-009: Event bridge starts before connection to capture early events.\n */\nexport async function initializeAPI(): Promise<NoteFlowAPI> {\n // Always try Tauri first - initializeTauriAPI tests the API and throws if unavailable\n try {\n const tauriAPI = await initializeTauriAPI();\n setAPIInstance(tauriAPI);\n\n try {\n const { invoke } = await import('@tauri-apps/api/core');\n window.__NOTEFLOW_TEST_INVOKE__ = invoke;\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging for API initialization\n console.debug('[NoteFlow API] Test invoke binding unavailable (expected in non-Tauri contexts):', error);\n }\n\n // Sprint GAP-009: Start event bridge before connection to capture early events\n // (e.g., connection errors, early warnings). Non-critical if it fails.\n await startTauriEventBridge().catch((error) => {\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging for API initialization\n console.warn('[NoteFlow API] Event bridge initialization failed - non-critical, continuing:', error);\n });\n\n // Attempt to connect to the gRPC server\n try {\n const preferredUrl = preferences.getServerUrl();\n await tauriAPI.connect(preferredUrl || undefined);\n setConnectionMode('connected');\n await preferences.initialize();\n startReconnection();\n // Sprint GAP-007: Log successful connection\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging per GAP-007 spec\n console.log(\n '[NoteFlow API] Adapter: Tauri | Mode: connected | Server:',\n preferredUrl || 'default'\n );\n return tauriAPI;\n } catch (connectError) {\n // Connection failed - fall back to cached mode but keep Tauri adapter\n const message = extractErrorMessage(connectError, 'Connection failed');\n setConnectionMode('cached', message);\n await preferences.initialize();\n startReconnection();\n // Sprint GAP-007: Log cached mode fallback\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging per GAP-007 spec\n console.warn('[NoteFlow API] Adapter: Tauri | Mode: cached | Reason:', message);\n return tauriAPI; // Keep Tauri adapter for reconnection attempts\n }\n } catch (_tauriError) {\n // Tauri unavailable - use mock API (we're in a browser)\n setConnectionMode('mock');\n setAPIInstance(mockAPI);\n // Sprint GAP-007: Log mock mode\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging per GAP-007 spec\n console.log('[NoteFlow API] Adapter: Mock | Mode: mock | Environment: Browser');\n return mockAPI;\n }\n}\n\n// ============================================================================\n// Auto-initialization\n// ============================================================================\n\n/**\n * Auto-initialize with appropriate adapter based on environment\n *\n * Always tries Tauri first (sync detection is unreliable in Tauri 2.x),\n * falls back to mock if Tauri APIs are unavailable.\n */\nif (typeof window !== 'undefined') {\n // Start with cached mode while we try to initialize\n setAPIInstance(cachedAPI);\n setConnectionMode('cached');\n\n // Always attempt Tauri initialization - it will fail gracefully in browser\n initializeAPI()\n .then((api) => {\n window.__NOTEFLOW_API__ = api;\n // Preserve E2E-only helpers in production bundles (prevents tree-shaking).\n window.__NOTEFLOW_TEST_API__ = {\n checkTestEnvironment: api.checkTestEnvironment?.bind(api),\n injectTestAudio: api.injectTestAudio?.bind(api),\n injectTestTone: api.injectTestTone?.bind(api),\n isE2EMode: () => {\n const win = window as Window & { __NOTEFLOW_E2E__?: boolean };\n if (win.__NOTEFLOW_E2E__ === true) {\n return 'true';\n }\n return import.meta.env.VITE_E2E_MODE;\n },\n updatePreferences: (updates: Partial<ReturnType<typeof preferences.get>>) => {\n const current = preferences.get();\n preferences.replace({ ...current, ...updates });\n },\n forceConnectionState: (mode: 'connected' | 'disconnected' | 'cached' | 'mock', serverUrl?: string | null) => {\n setConnectionMode(mode);\n setConnectionServerUrl(serverUrl ?? null);\n },\n resetRecordingState: async () => {\n const { invoke } = await import('@tauri-apps/api/core');\n return invoke('reset_test_recording_state');\n },\n };\n })\n .catch((_err) => {\n // Tauri unavailable - switch to mock mode\n setConnectionMode('mock');\n setConnectionServerUrl(null);\n setAPIInstance(mockAPI);\n window.__NOTEFLOW_API__ = mockAPI;\n });\n\n window.__NOTEFLOW_CONNECTION__ = { getConnectionState };\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/interface.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/mock-adapter.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/mock-adapter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/mock-data.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/mock-data.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/mock-transcription-stream.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/mock-transcription-stream.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/offline-defaults.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/reconnection.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/reconnection.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/tauri-adapter.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/tauri-adapter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/tauri-constants.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/tauri-constants.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/tauri-transcription-stream.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/transcription-stream.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/core.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/diagnostics.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/enums.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/errors.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/errors.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/calendar.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/identity.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/index.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/ner.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/observability.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/oidc.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/sync.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/features/webhooks.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/index.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/projects.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/ai.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/annotations.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/audio.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/integrations.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/meetings.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/oidc.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/preferences.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/recording-apps.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/templates.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/requests/triggers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/api/types/testing.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/NavLink.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/analytics-card-title.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/analytics-utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/log-entry-config.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/log-entry.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/log-timeline.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/logs-tab.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/logs-tab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/performance-tab.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/performance-tab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/analytics/speech-analysis-tab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/annotation-type-badge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/api-mode-indicator.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/api-mode-indicator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/app-layout.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/app-sidebar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/calendar-connection-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/calendar-events-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/connection-status.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/dev-profiler.tsx","messages":[{"ruleId":"@typescript-eslint/prefer-optional-chain","severity":1,"message":"Prefer using an optional chain expression instead, as it's more concise and easier to read.","line":27,"column":10,"nodeType":null,"messageId":"preferOptionalChain","endLine":27,"endColumn":67,"suggestions":[{"fix":{"range":[569,626],"text":"import.meta?.env.DEV"},"messageId":"optionalChainSuggest","desc":"Change to an optional chain."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import {\n Profiler,\n type ProfilerOnRenderCallback,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport { PROFILER_KEY } from '@/lib/storage-keys';\nconst MAX_SAMPLES = 100;\n\nexport interface ProfileSample {\n id: string;\n phase: 'mount' | 'update';\n actualDuration: number;\n baseDuration: number;\n startTime: number;\n commitTime: number;\n}\n\ntype ProfileListener = (sample: ProfileSample) => void;\n\nconst profileSamples: ProfileSample[] = [];\nconst profileListeners = new Set<ProfileListener>();\n\nfunction isDevMode(): boolean {\n return typeof import.meta !== 'undefined' && import.meta.env.DEV;\n}\n\nfunction readProfilerEnabled(): boolean {\n if (!isDevMode() || typeof window === 'undefined') {\n return false;\n }\n try {\n return window.localStorage.getItem(PROFILER_KEY) === '1';\n } catch {\n return false;\n }\n}\n\nfunction writeProfilerEnabled(enabled: boolean): void {\n if (typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(PROFILER_KEY, enabled ? '1' : '0');\n } catch {\n // Ignore storage errors\n }\n}\n\nfunction emitProfileSample(sample: ProfileSample): void {\n profileSamples.push(sample);\n if (profileSamples.length > MAX_SAMPLES) {\n profileSamples.shift();\n }\n for (const listener of profileListeners) {\n listener(sample);\n }\n if (typeof window !== 'undefined') {\n const windowWithProfile = window as Window & { __NOTEFLOW_PROFILE__?: ProfileSample[] };\n windowWithProfile.__NOTEFLOW_PROFILE__ = profileSamples;\n }\n}\n\nfunction subscribeToProfileSamples(listener: ProfileListener): () => void {\n profileListeners.add(listener);\n return () => profileListeners.delete(listener);\n}\n\nexport function DevProfiler({\n id,\n children,\n}: {\n id: string;\n children: ReactNode;\n}): JSX.Element {\n const [enabled, setEnabled] = useState(readProfilerEnabled);\n\n useEffect(() => {\n if (!isDevMode()) {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!event.ctrlKey || !event.shiftKey) {\n return;\n }\n if (event.key.toLowerCase() !== 'p') {\n return;\n }\n event.preventDefault();\n setEnabled((prev) => {\n const next = !prev;\n writeProfilerEnabled(next);\n return next;\n });\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, []);\n\n const onRender = useMemo<ProfilerOnRenderCallback>(\n () =>\n (profileId, phase, actualDuration, baseDuration, startTime, commitTime) => {\n emitProfileSample({\n id: profileId,\n phase,\n actualDuration,\n baseDuration,\n startTime,\n commitTime,\n });\n },\n []\n );\n\n if (!enabled) {\n return <>{children}</>;\n }\n\n return (\n <>\n <Profiler id={id} onRender={onRender}>\n {children}\n </Profiler>\n <ProfilerOverlay />\n </>\n );\n}\n\nfunction ProfilerOverlay(): JSX.Element | null {\n const [latestSample, setLatestSample] = useState<ProfileSample | null>(null);\n\n useEffect(() => {\n return subscribeToProfileSamples((sample) => setLatestSample(sample));\n }, []);\n\n if (!latestSample) {\n return null;\n }\n\n return (\n <div className=\"fixed bottom-4 right-4 z-[60] rounded-lg border border-border bg-background/95 px-3 py-2 text-xs shadow-lg\">\n <div className=\"font-semibold text-foreground\">Profiler</div>\n <div className=\"text-muted-foreground\">{latestSample.id}</div>\n <div className=\"mt-1 text-foreground\">\n {latestSample.phase} · {latestSample.actualDuration.toFixed(1)}ms\n </div>\n <div className=\"text-[10px] text-muted-foreground\">Toggle: Ctrl+Shift+P</div>\n </div>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/empty-state.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/entity-highlight.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/entity-highlight.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/entity-management-panel.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/entity-management-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/error-boundary.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/icons/status-icons.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/integration-config-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/meeting-card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/meeting-state-badge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/offline-banner.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/offline-banner.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/preferences-sync-bridge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/preferences-sync-status.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/preferences-sync-status.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/priority-badge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/processing-status.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/processing-status.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/projects/ProjectList.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/projects/ProjectMembersPanel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/projects/ProjectScopeFilter.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/projects/ProjectSettingsPanel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/projects/ProjectSidebar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/projects/ProjectSwitcher.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/audio-device-selector.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/audio-device-selector.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/audio-level-meter.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/audio-level-meter.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/buffering-indicator.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/buffering-indicator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/confidence-indicator.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/confidence-indicator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/idle-state.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/idle-state.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/index.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/index.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/listening-state.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/partial-text-display.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/recording-components.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/recording-header.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/recording-header.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/speaker-distribution.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/speaker-distribution.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/stat-card.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/stat-card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/stats-content.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/transcript-segment-card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/vad-indicator.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/recording/vad-indicator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/ai-config-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/audio-devices-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/connection-diagnostics-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/developer-options-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/export-ai-section.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/export-ai-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/index.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/integrations-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/provider-config-card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/quick-actions-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/recording-app-policy-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/server-connection-section.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/summarization-settings-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/summarization-template-creator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/summarization-templates-card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/summarization-templates-list.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/summarization-templates-manager.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/settings/template-content-label.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/simulation-confirmation-dialog.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/speaker-badge.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/speaker-badge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/stats-card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/sync-control-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/sync-history-log.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/sync-status-indicator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/tauri-event-listener.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/timestamped-notes-editor.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/timestamped-notes-editor.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/top-bar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/accordion.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/alert-dialog.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/alert.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/aspect-ratio.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/avatar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/badge.tsx","messages":[],"suppressedMessages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":51,"column":17,"nodeType":"Identifier","messageId":"namedExport","endLine":51,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/breadcrumb.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/button.tsx","messages":[],"suppressedMessages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":60,"column":18,"nodeType":"Identifier","messageId":"namedExport","endLine":60,"endColumn":32,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/calendar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/carousel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/chart.tsx","messages":[],"suppressedMessages":[{"ruleId":"@typescript-eslint/no-unsafe-assignment","severity":1,"message":"Unsafe assignment of an `any` value.","line":175,"column":19,"nodeType":"VariableDeclarator","messageId":"anyAssignment","endLine":175,"endColumn":76,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-unsafe-member-access","severity":1,"message":"Unsafe member access .fill on an `any` value.","line":175,"column":58,"nodeType":"Identifier","messageId":"unsafeMemberExpression","endLine":175,"endColumn":62,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-unsafe-argument","severity":1,"message":"Unsafe argument of type `any` assigned to a parameter of type `Payload<ValueType, NameType>[]`.","line":186,"column":65,"nodeType":"MemberExpression","messageId":"unsafeArgument","endLine":186,"endColumn":77,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-unsafe-assignment","severity":1,"message":"Unsafe assignment of an `any` value.","line":206,"column":31,"nodeType":"Property","messageId":"anyAssignment","endLine":206,"endColumn":59,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-unsafe-assignment","severity":1,"message":"Unsafe assignment of an `any` value.","line":207,"column":31,"nodeType":"Property","messageId":"anyAssignment","endLine":207,"endColumn":63,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"@typescript-eslint/no-unsafe-assignment","severity":1,"message":"Unsafe assignment of an `any` value.","line":274,"column":18,"nodeType":"MemberExpression","messageId":"anyAssignment","endLine":274,"endColumn":28,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/checkbox.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/collapsible.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/command.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/confirmation-dialog.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/context-menu.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/dialog.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/drawer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/dropdown-menu.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/dropdown-menu.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/form.tsx","messages":[],"suppressedMessages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":164,"column":3,"nodeType":"Identifier","messageId":"namedExport","endLine":164,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/hover-card.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/icon-circle.tsx","messages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":80,"column":22,"nodeType":"Identifier","messageId":"namedExport","endLine":80,"endColumn":40}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Circular icon container with variant styles.\n *\n * Used for status indicators, feature icons, and visual badges.\n */\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from '@/lib/cva';\nimport { cn } from '@/lib/utils';\n\nconst iconCircleVariants = cva(\n 'inline-flex items-center justify-center rounded-full shrink-0',\n {\n variants: {\n variant: {\n default: 'bg-muted text-muted-foreground',\n primary: 'bg-primary/10 text-primary',\n success: 'bg-success/10 text-success',\n warning: 'bg-warning/10 text-warning',\n destructive: 'bg-destructive/10 text-destructive',\n info: 'bg-blue-500/10 text-blue-500',\n outline: 'border border-border bg-transparent',\n },\n size: {\n sm: 'h-6 w-6 [&_svg]:h-3 [&_svg]:w-3',\n default: 'h-8 w-8 [&_svg]:h-4 [&_svg]:w-4',\n lg: 'h-10 w-10 [&_svg]:h-5 [&_svg]:w-5',\n xl: 'h-12 w-12 [&_svg]:h-6 [&_svg]:w-6',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n);\n\nexport interface IconCircleProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof iconCircleVariants> {\n /** Icon or content to display */\n children: React.ReactNode;\n}\n\n/**\n * Circular container for icons with consistent sizing and coloring.\n *\n * @example\n * ```tsx\n * import { CheckCircle, AlertTriangle, Info } from 'lucide-react';\n *\n * <IconCircle variant=\"success\">\n * <CheckCircle />\n * </IconCircle>\n *\n * <IconCircle variant=\"warning\" size=\"lg\">\n * <AlertTriangle />\n * </IconCircle>\n *\n * <IconCircle variant=\"info\" size=\"sm\">\n * <Info />\n * </IconCircle>\n * ```\n */\nconst IconCircle = React.forwardRef<HTMLDivElement, IconCircleProps>(\n ({ className, variant, size, children, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(iconCircleVariants({ variant, size, className }))}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\nIconCircle.displayName = 'IconCircle';\n\nexport { IconCircle, iconCircleVariants };\n","usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/inline-label.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/input-otp.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/input.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/label.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/loading-button.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/menubar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/navigation-menu.tsx","messages":[],"suppressedMessages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":113,"column":3,"nodeType":"Identifier","messageId":"namedExport","endLine":113,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/pagination.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/popover.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/progress.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/radio-group.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/resizable.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/resizable.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/scroll-area.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/search-icon.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/select.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/separator.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/sheet.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/sidebar.tsx","messages":[],"suppressedMessages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":735,"column":3,"nodeType":"Identifier","messageId":"namedExport","endLine":735,"endColumn":13,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/skeleton.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/slider.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/sonner.tsx","messages":[],"suppressedMessages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":28,"column":19,"nodeType":"Identifier","messageId":"namedExport","endLine":28,"endColumn":24,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/status-badge.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/switch.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/table.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/tabs.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/textarea.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/toast.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/toaster.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/toggle-group.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/toggle.tsx","messages":[],"suppressedMessages":[{"ruleId":"react-refresh/only-export-components","severity":1,"message":"Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.","line":43,"column":18,"nodeType":"Identifier","messageId":"namedExport","endLine":43,"endColumn":32,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/tooltip.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/ui-components.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/ui/use-toast.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/upcoming-meetings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/webhook-settings-panel.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/workspace-switcher.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/components/workspace-switcher.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/connection-context.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/connection-context.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/connection-state.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/project-context.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/project-state.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/storage.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/workspace-context.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/workspace-context.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/contexts/workspace-state.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/post-processing/events.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/post-processing/state.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-async-data.ts","messages":[{"ruleId":"react-hooks/exhaustive-deps","severity":1,"message":"React Hook useCallback has a missing dependency: 'fetcher'. Either include it or remove the dependency array. If 'fetcher' changes too often, find the parent component that defines it and wrap that definition in useCallback.","line":130,"column":6,"nodeType":"ArrayExpression","endLine":130,"endColumn":41,"suggestions":[{"desc":"Update the dependencies array to be: [skip, fetcher, onSuccess, onError]","fix":{"range":[3835,3870],"text":"[skip, fetcher, onSuccess, onError]"}}]},{"ruleId":"react-hooks/exhaustive-deps","severity":1,"message":"React Hook useCallback has a spread element in its dependency array. This means we can't statically verify whether you've passed the correct dependencies.","line":130,"column":33,"nodeType":"SpreadElement","endLine":130,"endColumn":40}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Generic async data fetching hook with loading and error states.\n *\n * Consolidates the common pattern of:\n * - Fetching data from an async source\n * - Tracking loading state\n * - Handling errors consistently\n * - Providing refetch capability\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { extractErrorMessage } from '@/api/helpers';\n\n/**\n * Result of an async data fetch operation.\n */\nexport interface AsyncDataResult<T> {\n /** The fetched data, or undefined if not yet loaded or on error */\n data: T | undefined;\n /** Whether a fetch is currently in progress */\n isLoading: boolean;\n /** Error message if the last fetch failed */\n error: string | null;\n /** Manually trigger a refetch */\n refetch: () => void;\n /** Reset to initial state (clear data, error, and loading) */\n reset: () => void;\n}\n\n/**\n * Options for useAsyncData hook.\n */\nexport interface UseAsyncDataOptions<T> {\n /** Initial data value (optional) */\n initialData?: T;\n /** Whether to skip the initial fetch (useful for conditional fetching) */\n skip?: boolean;\n /** Callback when fetch succeeds */\n onSuccess?: (data: T) => void;\n /** Callback when fetch fails */\n onError?: (error: string) => void;\n}\n\n/**\n * Hook for fetching async data with loading and error states.\n *\n * @param fetcher - Async function that returns the data\n * @param deps - Dependencies that trigger a refetch when changed\n * @param options - Optional configuration\n * @returns AsyncDataResult with data, loading state, error, and control functions\n *\n * @example\n * ```typescript\n * // Basic usage\n * const { data: meetings, isLoading, error } = useAsyncData(\n * () => api.listMeetings(),\n * []\n * );\n *\n * // With dependencies (refetch when meetingId changes)\n * const { data: meeting, isLoading } = useAsyncData(\n * () => api.getMeeting(meetingId),\n * [meetingId]\n * );\n *\n * // With options\n * const { data, refetch } = useAsyncData(\n * () => api.getSettings(),\n * [],\n * {\n * initialData: defaultSettings,\n * onSuccess: (data) => console.log('Loaded:', data),\n * onError: (err) => showToast(err),\n * }\n * );\n *\n * // Conditional fetching\n * const { data } = useAsyncData(\n * () => api.getMeeting(meetingId),\n * [meetingId],\n * { skip: !meetingId }\n * );\n * ```\n */\nexport function useAsyncData<T>(\n fetcher: () => Promise<T>,\n deps: readonly unknown[],\n options: UseAsyncDataOptions<T> = {}\n): AsyncDataResult<T> {\n const { initialData, skip = false, onSuccess, onError } = options;\n\n const [data, setData] = useState<T | undefined>(initialData);\n const [isLoading, setIsLoading] = useState(!skip);\n const [error, setError] = useState<string | null>(null);\n\n // Track if component is mounted to avoid state updates after unmount\n const isMountedRef = useRef(true);\n // Track current fetch to handle race conditions\n const fetchIdRef = useRef(0);\n\n const doFetch = useCallback(async () => {\n if (skip) {\n return;\n }\n\n const currentFetchId = ++fetchIdRef.current;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await fetcher();\n\n // Only update state if this is still the most recent fetch and component is mounted\n if (isMountedRef.current && currentFetchId === fetchIdRef.current) {\n setData(result);\n setIsLoading(false);\n onSuccess?.(result);\n }\n } catch (err) {\n if (isMountedRef.current && currentFetchId === fetchIdRef.current) {\n const errorMessage = extractErrorMessage(err);\n setError(errorMessage);\n setIsLoading(false);\n onError?.(errorMessage);\n }\n }\n // The fetcher is intentionally excluded - deps are controlled by caller\n // biome-ignore lint/correctness/useExhaustiveDependencies: fetcher is intentionally excluded, user controls deps\n }, [skip, onSuccess, onError, ...deps]);\n\n const refetch = useCallback(() => {\n void doFetch();\n }, [doFetch]);\n\n const reset = useCallback(() => {\n fetchIdRef.current++;\n setData(initialData);\n setIsLoading(false);\n setError(null);\n }, [initialData]);\n\n // Fetch on mount and when deps change\n useEffect(() => {\n void doFetch();\n }, [doFetch]);\n\n // Track mounted state\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n return { data, isLoading, error, refetch, reset };\n}\n\n/**\n * Result type for mutation operations.\n */\nexport interface MutationResult<TData, TVariables> {\n /** Execute the mutation */\n mutate: (variables: TVariables) => Promise<TData | undefined>;\n /** The result data from the last successful mutation */\n data: TData | undefined;\n /** Whether a mutation is currently in progress */\n isLoading: boolean;\n /** Error message if the last mutation failed */\n error: string | null;\n /** Reset the mutation state */\n reset: () => void;\n}\n\n/**\n * Options for useMutation hook.\n */\nexport interface UseMutationOptions<TData> {\n /** Callback when mutation succeeds */\n onSuccess?: (data: TData) => void;\n /** Callback when mutation fails */\n onError?: (error: string) => void;\n}\n\n/**\n * Hook for handling async mutations with loading and error states.\n *\n * @param mutationFn - Async function that performs the mutation\n * @param options - Optional callbacks\n * @returns MutationResult with mutate function, data, loading state, and error\n *\n * @example\n * ```typescript\n * const { mutate: createMeeting, isLoading } = useMutation(\n * (title: string) => api.createMeeting({ title }),\n * {\n * onSuccess: (meeting) => navigate(`/meeting/${meeting.id}`),\n * onError: (err) => showToast(err),\n * }\n * );\n *\n * // Usage\n * await createMeeting('My Meeting');\n * ```\n */\nexport function useMutation<TData, TVariables>(\n mutationFn: (variables: TVariables) => Promise<TData>,\n options: UseMutationOptions<TData> = {}\n): MutationResult<TData, TVariables> {\n const { onSuccess, onError } = options;\n\n const [data, setData] = useState<TData | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const isMountedRef = useRef(true);\n\n const mutate = useCallback(\n async (variables: TVariables): Promise<TData | undefined> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await mutationFn(variables);\n\n if (isMountedRef.current) {\n setData(result);\n setIsLoading(false);\n onSuccess?.(result);\n }\n return result;\n } catch (err) {\n if (isMountedRef.current) {\n const errorMessage = extractErrorMessage(err);\n setError(errorMessage);\n setIsLoading(false);\n onError?.(errorMessage);\n }\n return undefined;\n }\n },\n [mutationFn, onSuccess, onError]\n );\n\n const reset = useCallback(() => {\n setData(undefined);\n setIsLoading(false);\n setError(null);\n }, []);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n return { mutate, data, isLoading, error, reset };\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-audio-devices.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-audio-devices.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-auth-flow.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-calendar-sync.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-cloud-consent.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-cloud-consent.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-diarization.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-diarization.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-entity-extraction.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-guarded-mutation.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-guarded-mutation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-integration-sync.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-integration-sync.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-integration-validation.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-meeting-reminders.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-mobile.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-oauth-flow.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-oauth-flow.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-oidc-providers.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-oidc-providers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-panel-preferences.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-panel-preferences.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-post-processing.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-post-processing.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-preferences-sync.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-project-members.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-project.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-recording-app-policy.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-secure-integration-secrets.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-toast.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-toast.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/hooks/use-webhooks.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/ai-models.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/ai-providers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/audio-device-ids.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/cache/meeting-cache.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/cache/meeting-cache.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/client-log-events.integration.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/client-log-events.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/client-log-events.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/client-logs.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/client-logs.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/config/app-config.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/config/config.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/config/defaults.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/config/index.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/config/provider-endpoints.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/config/server.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/crypto.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/crypto.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/cva.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/cva.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/default-integrations.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/entity-store.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/entity-store.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/error-reporting.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/event-emitter.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/format.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/format.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/integration-utils.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/integration-utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-converters.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-converters.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-group-summarizer.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-group-summarizer.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-groups.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-groups.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-messages.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-messages.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-summarizer.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/log-summarizer.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/oauth-utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/object-utils.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/object-utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/preferences-sync.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/preferences-sync.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/preferences-validation.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/preferences.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/preferences.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/speaker-utils.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/speaker-utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/status-constants.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/storage-keys.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/storage-utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/styles.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/tauri-events.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/tauri-events.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/time.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/timing-constants.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/utils.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/lib/utils.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/main.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Analytics.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Home.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/MeetingDetail.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Meetings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/NotFound.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/People.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/ProjectSettings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Projects.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Recording.logic.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Recording.test.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Recording.tsx","messages":[{"ruleId":"@typescript-eslint/no-unsafe-assignment","severity":1,"message":"Unsafe assignment of an `any` value.","line":63,"column":9,"nodeType":"VariableDeclarator","messageId":"anyAssignment","endLine":63,"endColumn":45}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"// Live Recording Page\n\nimport { AnimatePresence } from 'framer-motion';\nimport {\n BarChart3,\n PanelLeftClose,\n PanelLeftOpen,\n PanelRightClose,\n PanelRightOpen,\n} from 'lucide-react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ImperativePanelHandle } from 'react-resizable-panels';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useVirtualizer } from '@tanstack/react-virtual';\nimport {\n getAPI,\n isTauriEnvironment,\n mockAPI,\n type NoteFlowAPI,\n type TranscriptionStream,\n} from '@/api';\nimport { TauriEvents } from '@/api/tauri-adapter';\nimport type { FinalSegment, Meeting, TranscriptUpdate } from '@/api/types';\nimport {\n IdleState,\n ListeningState,\n PartialTextDisplay,\n RecordingHeader,\n StatsContent,\n TranscriptSegmentCard,\n VADIndicator,\n} from '@/components/recording';\nimport { type NoteEdit, TimestampedNotesEditor } from '@/components/timestamped-notes-editor';\nimport { Button } from '@/components/ui/button';\nimport { Card, CardContent } from '@/components/ui/card';\nimport { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable';\nimport { useConnectionState } from '@/contexts/connection-state';\nimport { useProjects } from '@/contexts/project-state';\nimport {\n COLLAPSED_SIZE_PERCENT,\n MAX_NOTES_SIZE_PERCENT,\n MAX_STATS_SIZE_PERCENT,\n usePanelPreferences,\n} from '@/hooks/use-panel-preferences';\nimport { useGuardedMutation } from '@/hooks/use-guarded-mutation';\nimport { toast } from '@/hooks/use-toast';\nimport { toastError as reportError } from '@/lib/error-reporting';\nimport { formatDateTime } from '@/lib/format';\nimport { preferences } from '@/lib/preferences';\nimport { buildSpeakerNameMap } from '@/lib/speaker-utils';\nimport { useTauriEvent } from '@/lib/tauri-events';\n\ntype RecordingState = 'idle' | 'starting' | 'recording' | 'paused' | 'stopping';\n\nconst AUDIO_LEVEL_THROTTLE_MS = 80;\nconst TRANSCRIPT_VIRTUALIZE_THRESHOLD = 100;\nconst TRANSCRIPT_ESTIMATED_ROW_HEIGHT = 104;\nconst TRANSCRIPT_OVERSCAN = 8;\nconst AUTO_SCROLL_THRESHOLD_PX = 100;\nconst nowMs = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());\n\nfunction isE2EMode(): boolean {\n const flag = import.meta.env.VITE_E2E_MODE;\n if (typeof window !== 'undefined') {\n const windowWithFlag = window as Window & { __NOTEFLOW_E2E__?: boolean };\n if (windowWithFlag.__NOTEFLOW_E2E__ === true) {\n return true;\n }\n }\n return flag === 'true' || flag === '1';\n}\n\nfunction ensureTranscriptionStream(value: unknown): TranscriptionStream {\n if (!value || typeof value !== 'object') {\n throw new Error('Invalid transcription stream');\n }\n const record = value as Record<string, unknown>;\n if (\n typeof record.send !== 'function' ||\n typeof record.onUpdate !== 'function' ||\n typeof record.close !== 'function'\n ) {\n throw new Error('Invalid transcription stream');\n }\n return value as TranscriptionStream;\n}\n\nexport default function RecordingPage() {\n const navigate = useNavigate();\n const { id } = useParams<{ id: string }>();\n const isNewRecording = !id || id === 'new';\n const { activeProject } = useProjects();\n\n // Recording state\n const [recordingState, setRecordingState] = useState<RecordingState>('idle');\n const [meeting, setMeeting] = useState<Meeting | null>(null);\n const [meetingTitle, setMeetingTitle] = useState('');\n\n // Transcription state\n const [segments, setSegments] = useState<FinalSegment[]>([]);\n const [partialText, setPartialText] = useState('');\n const [isVadActive, setIsVadActive] = useState(false);\n const [audioLevel, setAudioLevel] = useState<number | null>(null);\n\n // Notes state\n const [notes, setNotes] = useState<NoteEdit[]>([]);\n\n // Panel preferences (persisted to localStorage)\n const {\n showNotesPanel,\n showStatsPanel,\n notesPanelSize,\n statsPanelSize,\n transcriptPanelSize,\n setShowNotesPanel,\n setShowStatsPanel,\n setNotesPanelSize,\n setStatsPanelSize,\n setTranscriptPanelSize,\n } = usePanelPreferences();\n\n // Entity highlighting state\n const [pinnedEntities, setPinnedEntities] = useState<Set<string>>(new Set());\n\n const handleTogglePinEntity = useCallback((entityId: string) => {\n setPinnedEntities((prev) => {\n const next = new Set(prev);\n if (next.has(entityId)) {\n next.delete(entityId);\n } else {\n next.add(entityId);\n }\n return next;\n });\n }, []);\n\n const [speakerNameMap, setSpeakerNameMap] = useState<Map<string, string>>(new Map());\n\n useEffect(() => {\n if (!meeting?.id || segments.length === 0) {\n setSpeakerNameMap(new Map());\n return;\n }\n const speakerIds = segments.map((segment) => segment.speaker_id);\n const buildMap = () => buildSpeakerNameMap(meeting.id, speakerIds);\n setSpeakerNameMap(buildMap());\n return preferences.subscribe(() => setSpeakerNameMap(buildMap()));\n }, [meeting?.id, segments]);\n\n // Timer\n const [elapsedTime, setElapsedTime] = useState(0);\n const [hasTauriTimer, setHasTauriTimer] = useState(false);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const isTauri = isTauriEnvironment();\n // Sprint GAP-007: Get mode for ApiModeIndicator in RecordingHeader\n const { isConnected, mode: connectionMode } = useConnectionState();\n const { guard } = useGuardedMutation();\n const simulateTranscription = preferences.get().simulate_transcription;\n\n // Transcription stream\n const streamRef = useRef<TranscriptionStream | null>(null);\n const transcriptScrollRef = useRef<HTMLDivElement>(null);\n const isNearBottomRef = useRef(true);\n\n // Panel refs for imperative collapse/expand\n const notesPanelRef = useRef<ImperativePanelHandle>(null);\n const statsPanelRef = useRef<ImperativePanelHandle>(null);\n\n const shouldVirtualizeTranscript = segments.length > TRANSCRIPT_VIRTUALIZE_THRESHOLD;\n const transcriptVirtualizer = useVirtualizer({\n count: segments.length,\n getScrollElement: () => transcriptScrollRef.current,\n estimateSize: () => TRANSCRIPT_ESTIMATED_ROW_HEIGHT,\n overscan: TRANSCRIPT_OVERSCAN,\n });\n\n useEffect(() => {\n const scrollElement = transcriptScrollRef.current;\n if (!scrollElement) {\n return;\n }\n\n const handleScroll = () => {\n const distanceFromBottom =\n scrollElement.scrollHeight - scrollElement.scrollTop - scrollElement.clientHeight;\n isNearBottomRef.current = distanceFromBottom < AUTO_SCROLL_THRESHOLD_PX;\n };\n\n handleScroll();\n scrollElement.addEventListener('scroll', handleScroll);\n return () => {\n scrollElement.removeEventListener('scroll', handleScroll);\n };\n }, []);\n\n // Auto-scroll to bottom for live updates when user is already near the end.\n useEffect(() => {\n const updateSignal =\n segments.length + partialText.length + (recordingState === 'recording' ? 1 : 0);\n const scrollElement = transcriptScrollRef.current;\n if (updateSignal === 0 || !scrollElement || !isNearBottomRef.current) {\n return;\n }\n scrollElement.scrollTop = scrollElement.scrollHeight;\n }, [segments.length, partialText, recordingState]);\n\n // Sync panel collapsed state with preferences\n useEffect(() => {\n const notesPanel = notesPanelRef.current;\n if (notesPanel) {\n if (showNotesPanel && notesPanel.isCollapsed()) {\n notesPanel.expand();\n } else if (!showNotesPanel && !notesPanel.isCollapsed()) {\n notesPanel.collapse();\n }\n }\n }, [showNotesPanel]);\n\n useEffect(() => {\n const statsPanel = statsPanelRef.current;\n if (statsPanel) {\n if (showStatsPanel && statsPanel.isCollapsed()) {\n statsPanel.expand();\n } else if (!showStatsPanel && !statsPanel.isCollapsed()) {\n statsPanel.collapse();\n }\n }\n }, [showStatsPanel]);\n\n // Handlers for panel collapse/expand callbacks\n const handleNotesCollapse = useCallback(() => {\n setShowNotesPanel(false);\n }, [setShowNotesPanel]);\n\n const handleNotesExpand = useCallback(() => {\n setShowNotesPanel(true);\n }, [setShowNotesPanel]);\n\n const handleStatsCollapse = useCallback(() => {\n setShowStatsPanel(false);\n }, [setShowStatsPanel]);\n\n const handleStatsExpand = useCallback(() => {\n setShowStatsPanel(true);\n }, [setShowStatsPanel]);\n\n // Timer effect\n useEffect(() => {\n if (recordingState === 'idle') {\n setHasTauriTimer(false);\n }\n const clearTimer = () => {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n };\n if (isTauri && hasTauriTimer) {\n clearTimer();\n return;\n }\n if (recordingState === 'recording') {\n timerRef.current = setInterval(() => setElapsedTime((prev) => prev + 1), 1000);\n } else {\n clearTimer();\n }\n return clearTimer;\n }, [recordingState, hasTauriTimer, isTauri]);\n\n useEffect(() => {\n if (recordingState !== 'recording') {\n setAudioLevel(null);\n }\n }, [recordingState]);\n\n const lastAudioLevelAtRef = useRef(0);\n useTauriEvent(\n TauriEvents.AUDIO_LEVEL,\n (payload) => {\n if (payload.meeting_id !== meeting?.id) {\n return;\n }\n const now = nowMs();\n if (now - lastAudioLevelAtRef.current < AUDIO_LEVEL_THROTTLE_MS) {\n return;\n }\n lastAudioLevelAtRef.current = now;\n setAudioLevel(payload.level);\n },\n [meeting?.id]\n );\n\n useTauriEvent(\n TauriEvents.RECORDING_TIMER,\n (payload) => {\n if (payload.meeting_id !== meeting?.id) {\n return;\n }\n setHasTauriTimer(true);\n setElapsedTime(payload.elapsed_seconds);\n },\n [meeting?.id]\n );\n\n // Handle transcript updates\n // Toast helpers\n const toastSuccess = useCallback(\n (title: string, description: string) => toast({ title, description }),\n []\n );\n const toastError = useCallback(\n (title: string, error?: unknown) => {\n if (error) {\n reportError({ title, error, fallback: 'Please try again' });\n return;\n }\n toast({ title, description: 'Please try again', variant: 'destructive' });\n },\n []\n );\n\n const handleTranscriptUpdate = useCallback((update: TranscriptUpdate) => {\n if (update.update_type === 'partial') {\n setPartialText(update.partial_text || '');\n } else if (update.update_type === 'final' && update.segment) {\n const seg = update.segment;\n setSegments((prev) => [...prev, seg]);\n setPartialText('');\n } else if (update.update_type === 'vad_start') {\n setIsVadActive(true);\n } else if (update.update_type === 'vad_end') {\n setIsVadActive(false);\n }\n }, []);\n\n // Start recording\n const startRecording = async () => {\n const shouldSimulate = isE2EMode() ? false : preferences.get().simulate_transcription;\n\n // GAP-006: Preflight connect if disconnected (defense in depth)\n // Must happen BEFORE guard, since guard blocks when disconnected.\n // Rust also auto-connects, but this provides explicit UX feedback.\n let didPreflightConnect = false;\n if (!shouldSimulate && !isConnected) {\n try {\n await getAPI().connect();\n didPreflightConnect = true;\n } catch {\n toast({\n title: 'Connection failed',\n description: 'Unable to connect to server. Please check your network and try again.',\n variant: 'destructive',\n });\n return;\n }\n }\n\n // GAP-012: Check for stuck stream state and auto-recover before starting\n if (isTauri && !shouldSimulate) {\n try {\n const streamState = await getAPI().getStreamState();\n if (streamState.state === 'starting' && (streamState.started_at_secs_ago ?? 0) > 10) {\n // resetStreamState() logs internally via addClientLog\n await getAPI().resetStreamState();\n toast({ title: 'Stream recovered', description: 'A stuck stream was automatically reset.' });\n }\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging for stream state\n console.warn('[Recording] Stream state check failed - continuing with Rust timeout protection:', error);\n }\n }\n\n const runStart = async () => {\n setRecordingState('starting');\n\n try {\n const api: NoteFlowAPI = shouldSimulate && !isConnected ? mockAPI : getAPI();\n const newMeeting = await api.createMeeting({\n title: meetingTitle || `Recording ${formatDateTime()}`,\n project_id: activeProject?.id,\n });\n setMeeting(newMeeting);\n\n let stream: TranscriptionStream;\n if (shouldSimulate && isConnected) {\n const mockModule: typeof import('@/api/mock-transcription-stream') = await import(\n '@/api/mock-transcription-stream'\n );\n stream = new mockModule.MockTranscriptionStream(newMeeting.id);\n } else {\n stream = ensureTranscriptionStream(await api.startTranscription(newMeeting.id));\n }\n\n streamRef.current = stream;\n stream.onUpdate(handleTranscriptUpdate);\n\n setRecordingState('recording');\n toastSuccess(\n 'Recording started',\n shouldSimulate ? 'Simulation is active' : 'Transcription is now active'\n );\n } catch (error) {\n setRecordingState('idle');\n toastError('Failed to start recording', error);\n }\n };\n\n if (shouldSimulate || didPreflightConnect || isE2EMode()) {\n // Either simulating, or we just successfully connected via preflight\n await runStart();\n } else {\n // Already connected - use guard as a safety check\n // GAP-012: guard() returns null when blocked (isReadOnly=true)\n // In that case, runStart() never executes, so recordingState stays 'idle'\n // The guard displays an \"Offline mode\" toast to the user\n await guard(runStart, {\n title: 'Offline mode',\n message: 'Recording requires an active server connection.',\n });\n }\n };\n\n // Auto-start recording for existing meeting (trigger accept flow)\n useEffect(() => {\n if (!isTauri || isNewRecording || !id || recordingState !== 'idle') {\n return;\n }\n const startExistingRecording = async () => {\n const shouldSimulate = isE2EMode() ? false : preferences.get().simulate_transcription;\n setRecordingState('starting');\n try {\n // GAP-006: Preflight connect if disconnected (defense in depth)\n if (!isConnected && !shouldSimulate) {\n try {\n await getAPI().connect();\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging for connection failures\n console.warn('[Recording] Preflight connect failed:', error);\n setRecordingState('idle');\n toast({\n title: 'Connection failed',\n description: 'Unable to connect to server. Please check your network and try again.',\n variant: 'destructive',\n });\n return;\n }\n }\n\n // GAP-012: Check for stuck stream state and auto-recover\n if (!shouldSimulate) {\n try {\n const streamState = await getAPI().getStreamState();\n if (streamState.state === 'starting' && (streamState.started_at_secs_ago ?? 0) > 10) {\n // resetStreamState() logs internally via addClientLog\n await getAPI().resetStreamState();\n }\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional debug logging for stream state\n console.warn('[Recording] Stream state check failed on existing meeting - continuing:', error);\n }\n }\n\n const api: NoteFlowAPI = shouldSimulate && !isConnected ? mockAPI : getAPI();\n const existingMeeting = await api.getMeeting({\n meeting_id: id,\n include_segments: false,\n include_summary: false,\n });\n setMeeting(existingMeeting);\n setMeetingTitle(existingMeeting.title);\n if (!['created', 'recording'].includes(existingMeeting.state)) {\n setRecordingState('idle');\n return;\n }\n let stream: TranscriptionStream;\n if (shouldSimulate && isConnected) {\n const mockModule: typeof import('@/api/mock-transcription-stream') = await import(\n '@/api/mock-transcription-stream'\n );\n stream = new mockModule.MockTranscriptionStream(existingMeeting.id);\n } else {\n stream = ensureTranscriptionStream(await api.startTranscription(existingMeeting.id));\n }\n streamRef.current = stream;\n stream.onUpdate(handleTranscriptUpdate);\n setRecordingState('recording');\n toastSuccess(\n 'Recording started',\n shouldSimulate ? 'Simulation is active' : 'Transcription is now active'\n );\n } catch (error) {\n setRecordingState('idle');\n toastError('Failed to start recording', error);\n }\n };\n void startExistingRecording();\n }, [\n handleTranscriptUpdate,\n id,\n isNewRecording,\n isTauri,\n isConnected,\n recordingState,\n toastError,\n toastSuccess,\n ]);\n\n // Stop recording\n const stopRecording = async () => {\n if (!meeting) {\n return;\n }\n const shouldSimulate = preferences.get().simulate_transcription;\n const runStop = async () => {\n setRecordingState('stopping');\n try {\n streamRef.current?.close();\n streamRef.current = null;\n const api = shouldSimulate && !isConnected ? mockAPI : getAPI();\n const stoppedMeeting = await api.stopMeeting(meeting.id);\n setMeeting(stoppedMeeting);\n toastSuccess(\n 'Recording stopped',\n shouldSimulate ? 'Simulation finished' : 'Your meeting has been saved'\n );\n const projectId = meeting.project_id ?? activeProject?.id;\n navigate(projectId ? `/projects/${projectId}/meetings/${meeting.id}` : '/projects');\n } catch (error) {\n setRecordingState('recording');\n toastError('Failed to stop recording', error);\n }\n };\n\n if (shouldSimulate) {\n await runStop();\n } else {\n await guard(runStop, {\n title: 'Offline mode',\n message: 'Stopping a recording requires an active server connection.',\n });\n }\n };\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n streamRef.current?.close();\n };\n }, []);\n\n if (!isTauri && !simulateTranscription) {\n return (\n <div className=\"h-full flex items-center justify-center p-6 bg-background\">\n <Card className=\"max-w-lg w-full\">\n <CardContent className=\"p-6 space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Desktop recording only</h2>\n <p className=\"text-sm text-muted-foreground\">\n Recording and live transcription are available in the desktop app. Use the web app for\n administration, configuration, and reporting.\n </p>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n return (\n <div className=\"h-full flex flex-col bg-background\">\n <RecordingHeader\n recordingState={recordingState}\n meeting={meeting}\n meetingTitle={meetingTitle}\n setMeetingTitle={setMeetingTitle}\n simulateTranscription={simulateTranscription}\n connectionMode={connectionMode}\n elapsedTime={elapsedTime}\n onStartRecording={startRecording}\n onStopRecording={stopRecording}\n />\n\n {/* Content */}\n <ResizablePanelGroup direction=\"horizontal\" className=\"flex-1\">\n {/* Transcript Panel */}\n <ResizablePanel\n id=\"transcript\"\n order={1}\n defaultSize={transcriptPanelSize}\n minSize={30}\n onResize={setTranscriptPanelSize}\n >\n <div ref={transcriptScrollRef} className=\"h-full overflow-auto p-6\">\n {recordingState === 'idle' ? (\n <IdleState />\n ) : (\n <div className=\"max-w-3xl mx-auto space-y-4\">\n {/* VAD Indicator */}\n <VADIndicator isActive={isVadActive} isRecording={recordingState === 'recording'} />\n\n {/* Transcript */}\n <div className=\"space-y-3\">\n {shouldVirtualizeTranscript ? (\n <div\n style={{\n height: transcriptVirtualizer.getTotalSize(),\n position: 'relative',\n }}\n >\n {transcriptVirtualizer.getVirtualItems().map((virtualRow) => {\n const segment = segments[virtualRow.index];\n return (\n <div\n key={segment.segment_id}\n ref={transcriptVirtualizer.measureElement}\n className=\"pb-3\"\n data-index={virtualRow.index}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n <TranscriptSegmentCard\n segment={segment}\n meetingId={meeting?.id}\n speakerName={speakerNameMap.get(segment.speaker_id)}\n pinnedEntities={pinnedEntities}\n onTogglePin={handleTogglePinEntity}\n animate={false}\n />\n </div>\n );\n })}\n </div>\n ) : (\n <AnimatePresence mode=\"popLayout\">\n {segments.map((segment) => (\n <TranscriptSegmentCard\n key={segment.segment_id}\n segment={segment}\n meetingId={meeting?.id}\n speakerName={speakerNameMap.get(segment.speaker_id)}\n pinnedEntities={pinnedEntities}\n onTogglePin={handleTogglePinEntity}\n />\n ))}\n </AnimatePresence>\n )}\n <PartialTextDisplay\n text={partialText}\n pinnedEntities={pinnedEntities}\n onTogglePin={handleTogglePinEntity}\n />\n </div>\n\n {/* Empty State */}\n {segments.length === 0 && !partialText && recordingState === 'recording' && (\n <ListeningState />\n )}\n </div>\n )}\n </div>\n </ResizablePanel>\n\n {/* Notes Panel - always rendered when not idle, uses collapsible */}\n {recordingState !== 'idle' && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel\n ref={notesPanelRef}\n id=\"notes\"\n order={2}\n defaultSize={showNotesPanel ? notesPanelSize : COLLAPSED_SIZE_PERCENT}\n minSize={COLLAPSED_SIZE_PERCENT}\n maxSize={MAX_NOTES_SIZE_PERCENT}\n collapsible\n collapsedSize={COLLAPSED_SIZE_PERCENT}\n onCollapse={handleNotesCollapse}\n onExpand={handleNotesExpand}\n onResize={setNotesPanelSize}\n >\n <div className=\"h-full flex flex-col border-l border-border bg-card/50\">\n {showNotesPanel ? (\n <div className=\"flex-1 flex flex-col p-4 min-h-0\">\n <div className=\"flex items-center justify-between mb-3\">\n <h3 className=\"font-medium text-foreground text-sm\">Notes</h3>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => notesPanelRef.current?.collapse()}\n className=\"h-7 w-7 p-0\"\n title=\"Collapse notes panel\"\n >\n <PanelRightClose className=\"h-4 w-4\" />\n </Button>\n </div>\n <div className=\"flex-1 min-h-0\">\n <TimestampedNotesEditor\n elapsedTime={elapsedTime}\n isRecording={recordingState === 'recording'}\n notes={notes}\n onNotesChange={setNotes}\n />\n </div>\n </div>\n ) : (\n <div className=\"h-full flex flex-col items-center pt-4\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => notesPanelRef.current?.expand()}\n className=\"h-8 w-8 p-0\"\n title=\"Expand notes panel\"\n >\n <PanelRightOpen className=\"h-4 w-4\" />\n </Button>\n <span className=\"text-[10px] text-muted-foreground mt-2 [writing-mode:vertical-rl] rotate-180\">\n Notes\n </span>\n </div>\n )}\n </div>\n </ResizablePanel>\n </>\n )}\n\n {/* Stats Panel - always rendered when not idle, uses collapsible */}\n {recordingState !== 'idle' && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel\n ref={statsPanelRef}\n id=\"stats\"\n order={3}\n defaultSize={showStatsPanel ? statsPanelSize : COLLAPSED_SIZE_PERCENT}\n minSize={COLLAPSED_SIZE_PERCENT}\n maxSize={MAX_STATS_SIZE_PERCENT}\n collapsible\n collapsedSize={COLLAPSED_SIZE_PERCENT}\n onCollapse={handleStatsCollapse}\n onExpand={handleStatsExpand}\n onResize={setStatsPanelSize}\n >\n <div className=\"h-full flex flex-col border-l border-border bg-card/50 overflow-auto\">\n {showStatsPanel ? (\n <div className=\"p-4 space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"font-medium text-foreground\">Recording Stats</h3>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => statsPanelRef.current?.collapse()}\n className=\"h-7 w-7 p-0\"\n title=\"Collapse stats panel\"\n >\n <PanelLeftClose className=\"h-4 w-4\" />\n </Button>\n </div>\n <StatsContent\n elapsedTime={elapsedTime}\n segments={segments}\n meetingId={meeting?.id}\n isRecording={recordingState === 'recording'}\n isVadActive={isVadActive}\n audioLevel={audioLevel}\n speakerNameMap={speakerNameMap}\n />\n </div>\n ) : (\n <div className=\"h-full flex flex-col items-center pt-4\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => statsPanelRef.current?.expand()}\n className=\"h-8 w-8 p-0\"\n title=\"Expand stats panel\"\n >\n <PanelLeftOpen className=\"h-4 w-4\" />\n </Button>\n <span className=\"text-[10px] text-muted-foreground mt-2 [writing-mode:vertical-rl] rotate-180\">\n <BarChart3 className=\"h-3 w-3 mb-1\" />\n Stats\n </span>\n </div>\n )}\n </div>\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n </div>\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Settings.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/Tasks.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/settings/AITab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/settings/AudioTab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/settings/DiagnosticsTab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/settings/IntegrationsTab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/settings/StatusTab.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/pages/settings/settings-helpers.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/test/code-quality.test.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/test/mocks/tauri-plugin-deep-link.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/test/mocks/tauri-plugin-shell.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/test/setup.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/test/vitest.d.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/types/entity.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/types/navigator.d.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/types/task.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/types/window.d.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/src/vite-env.d.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/tailwind.config.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/vite.config.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/vitest.config.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/wdio.conf.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/vasceannie/komodo/stacks/noteflow/client/wdio.mac.conf.ts","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]}]