@adminide-stack/yantra-mobile 12.0.28-alpha.72 → 12.0.28-alpha.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -75,10 +75,6 @@ function AudioRecorderPanel({
75
75
  let cancelled = false;
76
76
  const start = async () => {
77
77
  try {
78
- await setAudioModeAsync({
79
- allowsRecording: true,
80
- playsInSilentMode: true
81
- });
82
78
  await recorder.prepareToRecordAsync();
83
79
  if (cancelled || !isMountedRef.current) return;
84
80
  recorder.record();
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRecorderPanel.js","sources":["../../../src/features/audio-input/AudioRecorderPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { ActivityIndicator, Animated, Easing, Pressable, StyleSheet, View } from 'react-native';\nimport { Feather, Ionicons } from '@expo/vector-icons';\nimport { RecordingPresets, setAudioModeAsync, useAudioRecorder, useAudioRecorderState } from 'expo-audio';\nimport { transcribeAudio } from '../../api/stt';\n\n/**\n * Mirrors the web ceiling in\n * `packages-modules/account/browser/src/features/audio-input/components/AudioRecorder.tsx`.\n * Three minutes is a soft Whisper ceiling — past that, accuracy and upload\n * time both degrade more than the marginal extra context is worth.\n */\nconst MAX_DURATION_MS = 3 * 60 * 1000;\n\nexport interface AudioRecorderPanelProps {\n isDark: boolean;\n /**\n * Called once with the final transcribed string after the user taps \"Send\".\n * The host screen typically appends this to its composer state and re-focuses\n * the text input — mirroring the web `handleTranscriptionComplete` flow.\n */\n onTranscriptionComplete: (text: string) => void;\n /** Called when the user discards the recording (X) or recording cannot start. */\n onCancel: () => void;\n /** Optional error sink — host can surface a toast/banner. */\n onError?: (error: string) => void;\n}\n\n/**\n * Inline voice-capture panel that replaces the composer while recording —\n * the React Native port of the web `AudioRecorder` component\n * (`packages-modules/account/browser/src/features/audio-input/components/AudioRecorder.tsx`).\n *\n * Flow (parity with web):\n * 1. Mount → request mic permission → set audio mode → prepare + start recording.\n * 2. While recording, display a live timer and pulsing record dot.\n * 3. User taps \"Send\" → stop recorder → upload `recorder.uri` to Groq Whisper\n * via `transcribeAudio` → return the transcribed text to the host via\n * `onTranscriptionComplete`.\n * 4. User taps \"Cancel\" (X) → stop + discard, no upload.\n * 5. If recording exceeds `MAX_DURATION_MS`, auto-finalize as if the user\n * tapped Send (matches web safety net).\n *\n * The panel is intentionally NOT rendered inside the `InputToolBar`'s `topContent`\n * slot — web fully swaps the toolbar for the recorder. Keeping the toolbar\n * visible during recording invites accidental sends with empty input and an\n * unfocused recorder state.\n */\nexport function AudioRecorderPanel({ isDark, onTranscriptionComplete, onCancel, onError }: AudioRecorderPanelProps) {\n const recorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY);\n const recorderState = useAudioRecorderState(recorder, 200);\n const [isTranscribing, setIsTranscribing] = useState(false);\n\n /**\n * Guard against re-entry. `useEffect` runs once on mount but a fast double-\n * tap on the mic can produce two panel mounts in dev mode (StrictMode);\n * `hasStartedRef` ensures we don't start a second recorder against the\n * same shared object.\n */\n const hasStartedRef = useRef(false);\n const isMountedRef = useRef(true);\n /**\n * Caches the result of the in-flight transcription/cleanup pipeline so the\n * MAX_DURATION watcher and the explicit Send button can both call\n * `finalize()` without racing each other into a double-upload.\n */\n const sendInFlightRef = useRef(false);\n\n /**\n * Pulsing dot for the \"REC\" indicator. Pure UI sugar; avoids importing\n * reanimated for a 2-keyframe loop.\n */\n const pulse = useRef(new Animated.Value(1)).current;\n useEffect(() => {\n const loop = Animated.loop(\n Animated.sequence([\n Animated.timing(pulse, {\n toValue: 0.3,\n duration: 700,\n easing: Easing.inOut(Easing.ease),\n useNativeDriver: true,\n }),\n Animated.timing(pulse, {\n toValue: 1,\n duration: 700,\n easing: Easing.inOut(Easing.ease),\n useNativeDriver: true,\n }),\n ]),\n );\n loop.start();\n return () => loop.stop();\n }, [pulse]);\n\n const stopAndCleanup = useCallback(async () => {\n try {\n if (recorderState.isRecording || recorder.isRecording) {\n await recorder.stop().catch(() => undefined);\n }\n } catch {\n /* best-effort */\n }\n try {\n /*\n * Releasing the recording audio session matters more on iOS — leaving\n * `allowsRecording: true` will dim playback for the rest of the app\n * lifecycle. We tolerate failures because the AVAudioSession may\n * already be torn down by the time we get here.\n */\n await setAudioModeAsync({ allowsRecording: false, playsInSilentMode: true });\n } catch {\n /* best-effort */\n }\n }, [recorder, recorderState.isRecording]);\n\n /**\n * One-shot finalize: stop → upload → emit transcript. Swallowed errors get\n * surfaced via `onError` so the host can show a toast. We always clear\n * `sendInFlightRef` even on error so a retry path is possible if needed.\n */\n const finalize = useCallback(async () => {\n if (sendInFlightRef.current || isTranscribing) return;\n sendInFlightRef.current = true;\n if (isMountedRef.current) setIsTranscribing(true);\n try {\n await stopAndCleanup();\n const uri = recorder.uri;\n if (!uri) {\n throw new Error('No recording produced');\n }\n const text = await transcribeAudio({ uri, mimeType: 'audio/m4a', filename: 'audio.m4a' });\n if (isMountedRef.current) {\n onTranscriptionComplete(text);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(msg);\n onCancel();\n } finally {\n sendInFlightRef.current = false;\n if (isMountedRef.current) setIsTranscribing(false);\n }\n }, [isTranscribing, recorder, stopAndCleanup, onTranscriptionComplete, onError, onCancel]);\n\n useEffect(() => {\n if (hasStartedRef.current) return;\n hasStartedRef.current = true;\n let cancelled = false;\n const start = async () => {\n try {\n /*\n * IMPORTANT: We intentionally do NOT call\n * `AudioModule.requestRecordingPermissionsAsync()` or\n * `AudioModule.getRecordingPermissionsAsync()` here.\n *\n * expo-audio 0.4.x's `AudioRecordingRequester.getPermissions()`\n * (AudioRecordingRequester.swift:15) crashes with a native\n * SIGABRT via `EXFatal` → `RCTFatal` on a background dispatch\n * queue in TestFlight/release builds (see crash report: Thread\n * 13, EXPermissionsService → AudioRecordingRequester). Because\n * the abort happens on a native thread, no JS try/catch can\n * intercept it.\n *\n * Instead, `setAudioModeAsync({ allowsRecording: true })` sets\n * AVAudioSession's category to PlayAndRecord, which triggers\n * the native iOS microphone permission dialog on first access\n * (same dialog, different code path — bypasses the broken\n * EXPermissionsService requester). If permission is denied or\n * the session can't be configured, `setAudioModeAsync` or\n * `prepareToRecordAsync` will reject their promises normally,\n * and the catch block handles it gracefully.\n */\n await setAudioModeAsync({ allowsRecording: true, playsInSilentMode: true });\n await recorder.prepareToRecordAsync();\n if (cancelled || !isMountedRef.current) return;\n recorder.record();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(msg);\n onCancel();\n }\n };\n void start();\n return () => {\n cancelled = true;\n };\n // Mount-only effect: recorder/start refs are stable for the life of the panel.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n return () => {\n isMountedRef.current = false;\n /*\n * Unmount cleanup: fire-and-forget. We don't await anything here\n * because React doesn't allow async destructors and we can't\n * guarantee the recorder shared object outlives this tick. The\n * stopAndCleanup util is null-safe.\n */\n void stopAndCleanup();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n /**\n * Max-duration safety net. `RecorderState.durationMillis` already reports\n * elapsed time in milliseconds (see `expo-audio` `Audio.types.ts`), which\n * lines up directly with our `MAX_DURATION_MS` ceiling (web parity).\n */\n useEffect(() => {\n if (!recorderState.isRecording) return;\n const elapsedMs = recorderState.durationMillis ?? 0;\n if (elapsedMs >= MAX_DURATION_MS && !sendInFlightRef.current) {\n void finalize();\n }\n }, [recorderState.isRecording, recorderState.durationMillis, finalize]);\n\n const handleCancelPress = useCallback(async () => {\n if (isTranscribing) return;\n await stopAndCleanup();\n onCancel();\n }, [isTranscribing, stopAndCleanup, onCancel]);\n\n const handleSendPress = useCallback(() => {\n void finalize();\n }, [finalize]);\n\n const formatted = useMemo(() => {\n const totalSeconds = Math.floor((recorderState.durationMillis ?? 0) / 1000);\n const m = Math.floor(totalSeconds / 60);\n const s = totalSeconds % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }, [recorderState.durationMillis]);\n\n const bg = isDark ? '#0f172a' : '#ffffff';\n const border = isDark ? 'rgba(148,163,184,0.18)' : '#e4e4e7';\n const fg = isDark ? '#e5e7eb' : '#18181b';\n const muted = isDark ? '#94a3b8' : '#71717a';\n const cancelBg = isDark ? 'rgba(148,163,184,0.08)' : '#f4f4f5';\n\n const showSpinner = isTranscribing;\n const isRecording = recorderState.isRecording && !showSpinner;\n const statusLabel = showSpinner ? 'Transcribing…' : isRecording ? formatted : 'Initializing…';\n\n return (\n <View\n accessibilityRole=\"summary\"\n accessibilityLabel=\"Voice recorder\"\n style={[styles.container, { backgroundColor: bg, borderColor: border }]}\n >\n <View style={styles.statusRow}>\n {showSpinner ? (\n <ActivityIndicator size=\"small\" color={fg} />\n ) : (\n <Animated.View style={[styles.recDot, { opacity: isRecording ? pulse : 0.35 }]} />\n )}\n <Animated.Text style={[styles.timer, { color: fg }]} accessibilityLiveRegion=\"polite\">\n {statusLabel}\n </Animated.Text>\n {isRecording && <Animated.Text style={[styles.maxLabel, { color: muted }]}>/ 3:00</Animated.Text>}\n </View>\n <View style={styles.actionsRow}>\n <Pressable\n onPress={handleCancelPress}\n disabled={isTranscribing}\n accessibilityLabel=\"Cancel recording\"\n accessibilityRole=\"button\"\n style={({ pressed }) => [\n styles.iconBtn,\n {\n backgroundColor: cancelBg,\n borderColor: border,\n opacity: isTranscribing ? 0.4 : pressed ? 0.7 : 1,\n },\n ]}\n >\n <Ionicons name=\"close\" size={16} color={fg} />\n </Pressable>\n <Pressable\n onPress={handleSendPress}\n disabled={isTranscribing || !isRecording}\n accessibilityLabel=\"Stop and transcribe\"\n accessibilityRole=\"button\"\n style={({ pressed }) => [\n styles.sendBtn,\n {\n opacity: isTranscribing ? 0.7 : !isRecording ? 0.5 : pressed ? 0.85 : 1,\n },\n ]}\n >\n {isTranscribing ? (\n <ActivityIndicator size=\"small\" color=\"#ffffff\" />\n ) : (\n <Feather name=\"arrow-up\" size={16} color=\"#ffffff\" />\n )}\n </Pressable>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n borderRadius: 24,\n borderWidth: 1,\n paddingVertical: 10,\n paddingHorizontal: 14,\n gap: 12,\n shadowColor: '#0f172a',\n shadowOpacity: 0.08,\n shadowRadius: 12,\n shadowOffset: { width: 0, height: 4 },\n elevation: 4,\n },\n statusRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 8,\n flexShrink: 1,\n },\n recDot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n backgroundColor: '#ef4444',\n },\n timer: {\n fontSize: 13,\n fontWeight: '600',\n fontVariant: ['tabular-nums'],\n },\n maxLabel: {\n fontSize: 11,\n },\n actionsRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 8,\n },\n iconBtn: {\n width: 32,\n height: 32,\n borderRadius: 16,\n borderWidth: 1,\n alignItems: 'center',\n justifyContent: 'center',\n },\n sendBtn: {\n width: 32,\n height: 32,\n borderRadius: 16,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: '#18181b',\n },\n});\n\nexport default AudioRecorderPanel;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AudioRecorderPanel.js","sources":["../../../src/features/audio-input/AudioRecorderPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { ActivityIndicator, Animated, Easing, Pressable, StyleSheet, View } from 'react-native';\nimport { Feather, Ionicons } from '@expo/vector-icons';\nimport { RecordingPresets, setAudioModeAsync, useAudioRecorder, useAudioRecorderState } from 'expo-audio';\nimport { transcribeAudio } from '../../api/stt';\n\n/**\n * Mirrors the web ceiling in\n * `packages-modules/account/browser/src/features/audio-input/components/AudioRecorder.tsx`.\n * Three minutes is a soft Whisper ceiling — past that, accuracy and upload\n * time both degrade more than the marginal extra context is worth.\n */\nconst MAX_DURATION_MS = 3 * 60 * 1000;\n\nexport interface AudioRecorderPanelProps {\n isDark: boolean;\n /**\n * Called once with the final transcribed string after the user taps \"Send\".\n * The host screen typically appends this to its composer state and re-focuses\n * the text input — mirroring the web `handleTranscriptionComplete` flow.\n */\n onTranscriptionComplete: (text: string) => void;\n /** Called when the user discards the recording (X) or recording cannot start. */\n onCancel: () => void;\n /** Optional error sink — host can surface a toast/banner. */\n onError?: (error: string) => void;\n}\n\n/**\n * Inline voice-capture panel that replaces the composer while recording —\n * the React Native port of the web `AudioRecorder` component\n * (`packages-modules/account/browser/src/features/audio-input/components/AudioRecorder.tsx`).\n *\n * Flow (parity with web):\n * 1. Mount → request mic permission → set audio mode → prepare + start recording.\n * 2. While recording, display a live timer and pulsing record dot.\n * 3. User taps \"Send\" → stop recorder → upload `recorder.uri` to Groq Whisper\n * via `transcribeAudio` → return the transcribed text to the host via\n * `onTranscriptionComplete`.\n * 4. User taps \"Cancel\" (X) → stop + discard, no upload.\n * 5. If recording exceeds `MAX_DURATION_MS`, auto-finalize as if the user\n * tapped Send (matches web safety net).\n *\n * The panel is intentionally NOT rendered inside the `InputToolBar`'s `topContent`\n * slot — web fully swaps the toolbar for the recorder. Keeping the toolbar\n * visible during recording invites accidental sends with empty input and an\n * unfocused recorder state.\n */\nexport function AudioRecorderPanel({ isDark, onTranscriptionComplete, onCancel, onError }: AudioRecorderPanelProps) {\n const recorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY);\n const recorderState = useAudioRecorderState(recorder, 200);\n const [isTranscribing, setIsTranscribing] = useState(false);\n\n /**\n * Guard against re-entry. `useEffect` runs once on mount but a fast double-\n * tap on the mic can produce two panel mounts in dev mode (StrictMode);\n * `hasStartedRef` ensures we don't start a second recorder against the\n * same shared object.\n */\n const hasStartedRef = useRef(false);\n const isMountedRef = useRef(true);\n /**\n * Caches the result of the in-flight transcription/cleanup pipeline so the\n * MAX_DURATION watcher and the explicit Send button can both call\n * `finalize()` without racing each other into a double-upload.\n */\n const sendInFlightRef = useRef(false);\n\n /**\n * Pulsing dot for the \"REC\" indicator. Pure UI sugar; avoids importing\n * reanimated for a 2-keyframe loop.\n */\n const pulse = useRef(new Animated.Value(1)).current;\n useEffect(() => {\n const loop = Animated.loop(\n Animated.sequence([\n Animated.timing(pulse, {\n toValue: 0.3,\n duration: 700,\n easing: Easing.inOut(Easing.ease),\n useNativeDriver: true,\n }),\n Animated.timing(pulse, {\n toValue: 1,\n duration: 700,\n easing: Easing.inOut(Easing.ease),\n useNativeDriver: true,\n }),\n ]),\n );\n loop.start();\n return () => loop.stop();\n }, [pulse]);\n\n const stopAndCleanup = useCallback(async () => {\n try {\n if (recorderState.isRecording || recorder.isRecording) {\n await recorder.stop().catch(() => undefined);\n }\n } catch {\n /* best-effort */\n }\n try {\n /*\n * Releasing the recording audio session matters more on iOS — leaving\n * `allowsRecording: true` will dim playback for the rest of the app\n * lifecycle. We tolerate failures because the AVAudioSession may\n * already be torn down by the time we get here.\n */\n await setAudioModeAsync({ allowsRecording: false, playsInSilentMode: true });\n } catch {\n /* best-effort */\n }\n }, [recorder, recorderState.isRecording]);\n\n /**\n * One-shot finalize: stop → upload → emit transcript. Swallowed errors get\n * surfaced via `onError` so the host can show a toast. We always clear\n * `sendInFlightRef` even on error so a retry path is possible if needed.\n */\n const finalize = useCallback(async () => {\n if (sendInFlightRef.current || isTranscribing) return;\n sendInFlightRef.current = true;\n if (isMountedRef.current) setIsTranscribing(true);\n try {\n await stopAndCleanup();\n const uri = recorder.uri;\n if (!uri) {\n throw new Error('No recording produced');\n }\n const text = await transcribeAudio({ uri, mimeType: 'audio/m4a', filename: 'audio.m4a' });\n if (isMountedRef.current) {\n onTranscriptionComplete(text);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(msg);\n onCancel();\n } finally {\n sendInFlightRef.current = false;\n if (isMountedRef.current) setIsTranscribing(false);\n }\n }, [isTranscribing, recorder, stopAndCleanup, onTranscriptionComplete, onError, onCancel]);\n\n useEffect(() => {\n if (hasStartedRef.current) return;\n hasStartedRef.current = true;\n let cancelled = false;\n const start = async () => {\n try {\n /*\n * Host screen already called `requestMicPermission()` (expo-audio\n * docs flow) before mounting this panel — go straight to\n * prepare + record.\n */\n await recorder.prepareToRecordAsync();\n if (cancelled || !isMountedRef.current) return;\n recorder.record();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(msg);\n onCancel();\n }\n };\n void start();\n return () => {\n cancelled = true;\n };\n // Mount-only effect: recorder/start refs are stable for the life of the panel.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n return () => {\n isMountedRef.current = false;\n /*\n * Unmount cleanup: fire-and-forget. We don't await anything here\n * because React doesn't allow async destructors and we can't\n * guarantee the recorder shared object outlives this tick. The\n * stopAndCleanup util is null-safe.\n */\n void stopAndCleanup();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n /**\n * Max-duration safety net. `RecorderState.durationMillis` already reports\n * elapsed time in milliseconds (see `expo-audio` `Audio.types.ts`), which\n * lines up directly with our `MAX_DURATION_MS` ceiling (web parity).\n */\n useEffect(() => {\n if (!recorderState.isRecording) return;\n const elapsedMs = recorderState.durationMillis ?? 0;\n if (elapsedMs >= MAX_DURATION_MS && !sendInFlightRef.current) {\n void finalize();\n }\n }, [recorderState.isRecording, recorderState.durationMillis, finalize]);\n\n const handleCancelPress = useCallback(async () => {\n if (isTranscribing) return;\n await stopAndCleanup();\n onCancel();\n }, [isTranscribing, stopAndCleanup, onCancel]);\n\n const handleSendPress = useCallback(() => {\n void finalize();\n }, [finalize]);\n\n const formatted = useMemo(() => {\n const totalSeconds = Math.floor((recorderState.durationMillis ?? 0) / 1000);\n const m = Math.floor(totalSeconds / 60);\n const s = totalSeconds % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }, [recorderState.durationMillis]);\n\n const bg = isDark ? '#0f172a' : '#ffffff';\n const border = isDark ? 'rgba(148,163,184,0.18)' : '#e4e4e7';\n const fg = isDark ? '#e5e7eb' : '#18181b';\n const muted = isDark ? '#94a3b8' : '#71717a';\n const cancelBg = isDark ? 'rgba(148,163,184,0.08)' : '#f4f4f5';\n\n const showSpinner = isTranscribing;\n const isRecording = recorderState.isRecording && !showSpinner;\n const statusLabel = showSpinner ? 'Transcribing…' : isRecording ? formatted : 'Initializing…';\n\n return (\n <View\n accessibilityRole=\"summary\"\n accessibilityLabel=\"Voice recorder\"\n style={[styles.container, { backgroundColor: bg, borderColor: border }]}\n >\n <View style={styles.statusRow}>\n {showSpinner ? (\n <ActivityIndicator size=\"small\" color={fg} />\n ) : (\n <Animated.View style={[styles.recDot, { opacity: isRecording ? pulse : 0.35 }]} />\n )}\n <Animated.Text style={[styles.timer, { color: fg }]} accessibilityLiveRegion=\"polite\">\n {statusLabel}\n </Animated.Text>\n {isRecording && <Animated.Text style={[styles.maxLabel, { color: muted }]}>/ 3:00</Animated.Text>}\n </View>\n <View style={styles.actionsRow}>\n <Pressable\n onPress={handleCancelPress}\n disabled={isTranscribing}\n accessibilityLabel=\"Cancel recording\"\n accessibilityRole=\"button\"\n style={({ pressed }) => [\n styles.iconBtn,\n {\n backgroundColor: cancelBg,\n borderColor: border,\n opacity: isTranscribing ? 0.4 : pressed ? 0.7 : 1,\n },\n ]}\n >\n <Ionicons name=\"close\" size={16} color={fg} />\n </Pressable>\n <Pressable\n onPress={handleSendPress}\n disabled={isTranscribing || !isRecording}\n accessibilityLabel=\"Stop and transcribe\"\n accessibilityRole=\"button\"\n style={({ pressed }) => [\n styles.sendBtn,\n {\n opacity: isTranscribing ? 0.7 : !isRecording ? 0.5 : pressed ? 0.85 : 1,\n },\n ]}\n >\n {isTranscribing ? (\n <ActivityIndicator size=\"small\" color=\"#ffffff\" />\n ) : (\n <Feather name=\"arrow-up\" size={16} color=\"#ffffff\" />\n )}\n </Pressable>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n borderRadius: 24,\n borderWidth: 1,\n paddingVertical: 10,\n paddingHorizontal: 14,\n gap: 12,\n shadowColor: '#0f172a',\n shadowOpacity: 0.08,\n shadowRadius: 12,\n shadowOffset: { width: 0, height: 4 },\n elevation: 4,\n },\n statusRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 8,\n flexShrink: 1,\n },\n recDot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n backgroundColor: '#ef4444',\n },\n timer: {\n fontSize: 13,\n fontWeight: '600',\n fontVariant: ['tabular-nums'],\n },\n maxLabel: {\n fontSize: 11,\n },\n actionsRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 8,\n },\n iconBtn: {\n width: 32,\n height: 32,\n borderRadius: 16,\n borderWidth: 1,\n alignItems: 'center',\n justifyContent: 'center',\n },\n sendBtn: {\n width: 32,\n height: 32,\n borderRadius: 16,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: '#18181b',\n },\n});\n\nexport default AudioRecorderPanel;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import {AudioModule,setAudioModeAsync}from'expo-audio';async function requestMicPermission() {
2
+ try {
3
+ const status = await AudioModule.requestRecordingPermissionsAsync();
4
+ if (!status.granted) {
5
+ return {
6
+ granted: false,
7
+ error: "Microphone permission is required for voice input."
8
+ };
9
+ }
10
+ await setAudioModeAsync({
11
+ playsInSilentMode: true,
12
+ allowsRecording: true
13
+ });
14
+ return {
15
+ granted: true
16
+ };
17
+ } catch (err) {
18
+ const msg = err instanceof Error ? err.message : String(err);
19
+ return {
20
+ granted: false,
21
+ error: msg
22
+ };
23
+ }
24
+ }export{requestMicPermission};//# sourceMappingURL=useAudioPermission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAudioPermission.js","sources":["../../../src/features/audio-input/useAudioPermission.ts"],"sourcesContent":["import { AudioModule, setAudioModeAsync } from 'expo-audio';\n\nexport type MicPermissionResult = {\n granted: boolean;\n error?: string;\n};\n\n/**\n * Official expo-audio v53 recording flow — called when the user taps the mic\n * (user-initiated), not at screen mount:\n *\n * 1. AudioModule.requestRecordingPermissionsAsync()\n * 2. setAudioModeAsync({ playsInSilentMode: true, allowsRecording: true })\n *\n * `expo-audio`'s native `record()` checks permission state set by step 1.\n * iOS `setAudioModeAsync` alone can show the system dialog but does NOT update\n * expo-audio's internal grant flag → `AudioPermissionsException` on `record()`.\n *\n * Requires `NSMicrophoneUsageDescription` in the built Info.plist (expo-audio\n * plugin + ios.infoPlist). Without it, step 1 can native-crash in older builds.\n */\nexport async function requestMicPermission(): Promise<MicPermissionResult> {\n try {\n const status = await AudioModule.requestRecordingPermissionsAsync();\n if (!status.granted) {\n return {\n granted: false,\n error: 'Microphone permission is required for voice input.',\n };\n }\n await setAudioModeAsync({\n playsInSilentMode: true,\n allowsRecording: true,\n });\n return { granted: true };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { granted: false, error: msg };\n }\n}\n"],"names":[],"mappings":"uDAoBA,eAAsB,oBAAqD,GAAA;AACzE,EAAI,IAAA;AACF,IAAM,MAAA,MAAA,GAAS,MAAM,WAAA,CAAY,gCAAiC,EAAA;AAClE,IAAI,IAAA,CAAC,OAAO,OAAS,EAAA;AACnB,MAAO,OAAA;AAAA,QACL,OAAS,EAAA,KAAA;AAAA,QACT,KAAO,EAAA;AAAA,OACT;AAAA;AAEF,IAAA,MAAM,iBAAkB,CAAA;AAAA,MACtB,iBAAmB,EAAA,IAAA;AAAA,MACnB,eAAiB,EAAA;AAAA,KAClB,CAAA;AACD,IAAO,OAAA;AAAA,MACL,OAAS,EAAA;AAAA,KACX;AAAA,WACO,GAAK,EAAA;AACZ,IAAA,MAAM,MAAM,GAAe,YAAA,KAAA,GAAQ,GAAI,CAAA,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,IAAO,OAAA;AAAA,MACL,OAAS,EAAA,KAAA;AAAA,MACT,KAAO,EAAA;AAAA,KACT;AAAA;AAEJ"}
@@ -1,4 +1,4 @@
1
- import {jsxs,jsx}from'react/jsx-runtime';import {useMemo,useState,useEffect,useRef,useCallback}from'react';import {useColorScheme,useWindowDimensions,Platform,Keyboard,TouchableWithoutFeedback,StyleSheet,View}from'react-native';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {useNavigation,useRoute}from'@react-navigation/native';import {MessagesContainerUI}from'@messenger-box/platform-mobile';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useChatStream}from'../../hooks/useChatStream.js';import {YantraBrandLoader,YANTRA_LOADER_SIZE_COMPACT}from'../../components/YantraBrandLoader.js';import ThinkingIndicator from'../../components/ThinkingIndicator.js';import {mobileTokens}from'../../theme/mobileTokens.js';import DeepSearchModal from'../Home/components/DeepSearchModal.js';import {normalizeSummaryText,extractDeepSearchSources}from'../Home/deepSearchUtils.js';import {AudioRecorderPanel}from'../../features/audio-input/AudioRecorderPanel.js';import {MicErrorBoundary}from'../../features/audio-input/MicErrorBoundary.js';const COMPOSER_SCROLL_RESERVE_PX = 164;
1
+ import {jsxs,jsx}from'react/jsx-runtime';import {useMemo,useState,useEffect,useRef,useCallback}from'react';import {useColorScheme,useWindowDimensions,Platform,Keyboard,TouchableWithoutFeedback,StyleSheet,View}from'react-native';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {useNavigation,useRoute}from'@react-navigation/native';import {MessagesContainerUI}from'@messenger-box/platform-mobile';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useChatStream}from'../../hooks/useChatStream.js';import {YantraBrandLoader,YANTRA_LOADER_SIZE_COMPACT}from'../../components/YantraBrandLoader.js';import ThinkingIndicator from'../../components/ThinkingIndicator.js';import {mobileTokens}from'../../theme/mobileTokens.js';import DeepSearchModal from'../Home/components/DeepSearchModal.js';import {normalizeSummaryText,extractDeepSearchSources}from'../Home/deepSearchUtils.js';import {AudioRecorderPanel}from'../../features/audio-input/AudioRecorderPanel.js';import {MicErrorBoundary}from'../../features/audio-input/MicErrorBoundary.js';import {requestMicPermission}from'../../features/audio-input/useAudioPermission.js';const COMPOSER_SCROLL_RESERVE_PX = 164;
2
2
  const SENDING_LOADER_COMPOSER_RESERVE_PX = 156;
3
3
  function ChatScreen() {
4
4
  var _a, _b;
@@ -132,7 +132,17 @@ function ChatScreen() {
132
132
  if (hasQuery) return;
133
133
  setVoiceError(null);
134
134
  Keyboard.dismiss();
135
- setShowAudioRecorder(true);
135
+ void (async () => {
136
+ const {
137
+ granted,
138
+ error
139
+ } = await requestMicPermission();
140
+ if (!granted) {
141
+ setVoiceError(error || "Microphone is not available.");
142
+ return;
143
+ }
144
+ setShowAudioRecorder(true);
145
+ })();
136
146
  }, [hasQuery]);
137
147
  const handleTranscriptionComplete = useCallback((text) => {
138
148
  const cleaned = (text != null ? text : "").trim();
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/screens/Chat/index.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Keyboard,\n Platform,\n StyleSheet,\n TextInput,\n TouchableWithoutFeedback,\n View,\n useColorScheme,\n useWindowDimensions,\n} from 'react-native';\nimport { Box, InputToolBar, Text, getDefaultLeftItems, getDefaultRightItems } from '@admin-layout/gluestack-ui-mobile';\nimport { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { useNavigation, useRoute } from '@react-navigation/native';\nimport { MessagesContainerUI } from '@messenger-box/platform-mobile';\nimport { useCdecliConnection } from '../../contexts/CdecliConnectionContext';\nimport { useChatStream, type UseChatStreamRouting } from '../../hooks/useChatStream';\nimport { YantraBrandLoader, YANTRA_LOADER_SIZE_COMPACT } from '../../components/YantraBrandLoader';\nimport ThinkingIndicator from '../../components/ThinkingIndicator';\nimport { mobileTokens } from '../../theme/mobileTokens';\nimport DeepSearchModal from '../Home/components/DeepSearchModal';\nimport { extractDeepSearchSources, normalizeSummaryText, type DeepSearchSourceItem } from '../Home/deepSearchUtils';\nimport type { ModeSubmission, RoutingMode } from '../Home/types';\nimport { AudioRecorderPanel } from '../../features/audio-input/AudioRecorderPanel';\nimport { MicErrorBoundary } from '../../features/audio-input/MicErrorBoundary';\n\n/** Reserve so the streaming-loader and bottom of the message list don't overlap the composer. */\nconst COMPOSER_SCROLL_RESERVE_PX = 164;\nconst SENDING_LOADER_COMPOSER_RESERVE_PX = 156;\n\n/** Route params passed by Home (or by deep-link) when entering the Chat surface. */\nexport interface ChatScreenRouteParams {\n /** Channel id is required — the screen is keyed on the conversation. */\n channelId: string;\n /** Org slug used by gateway/account context. */\n orgName?: string | null;\n /**\n * First user message to auto-fire when the screen mounts. Home generates\n * this when the user submits from the empty composer so the assistant\n * starts streaming on Chat without an extra round trip.\n */\n initialQuery?: string | null;\n /**\n * Seed for the composer's mode (`'chat'` | `'deep-search'`).\n *\n * Set by `HomeScreen` to carry the user's last selection across the\n * navigation hop (\"research from home → research-shaped composer on chat\").\n * `ChatHistoryScreen` does NOT forward this — revisits always land on the\n * default `'chat'` mode, matching Home's defaults, and the user is free to\n * switch from there.\n *\n * After mount, this param is purely a seed: the screen keeps its own\n * `activeMode` so the user can toggle freely while inside the thread.\n */\n initialMode?: RoutingMode;\n /** Optional attachments forwarded with the initial message. */\n initialAttachments?: ModeSubmission['attachments'];\n}\n\nexport default function ChatScreen() {\n const navigation = useNavigation<any>();\n const route = useRoute<any>();\n\n const params = (route?.params ?? {}) as Partial<ChatScreenRouteParams>;\n const channelId = useMemo(() => {\n const raw = typeof params.channelId === 'string' ? params.channelId.trim() : '';\n return raw.length > 0 ? raw : null;\n }, [params.channelId]);\n const initialQuery = useMemo(() => {\n const raw = typeof params.initialQuery === 'string' ? params.initialQuery.trim() : '';\n return raw.length > 0 ? raw : null;\n }, [params.initialQuery]);\n const initialAttachments = params.initialAttachments;\n\n const colorScheme = useColorScheme();\n const isDark = colorScheme === 'dark';\n const { width: screenWidth } = useWindowDimensions();\n const contentMaxWidth = Math.min(720, Math.max(360, screenWidth - 24));\n\n const surfaceColor = isDark ? '#0f172a' : mobileTokens.color.surface;\n const secondaryTextColor = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n\n const insets = useSafeAreaInsets();\n const [keyboardHeight, setKeyboardHeight] = useState(0);\n useEffect(() => {\n if (Platform.OS === 'ios') {\n const frameSub = Keyboard.addListener('keyboardWillChangeFrame', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const showSub = Keyboard.addListener('keyboardWillShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardWillHide', () => setKeyboardHeight(0));\n return () => {\n frameSub.remove();\n showSub.remove();\n hideSub.remove();\n };\n }\n const showSub = Keyboard.addListener('keyboardDidShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardDidHide', () => setKeyboardHeight(0));\n return () => {\n showSub.remove();\n hideSub.remove();\n };\n }, []);\n\n /**\n * Gateway + chat stream routing.\n *\n * The CDeCLI lifecycle is owned app-wide by `CdecliConnectionProvider`,\n * so we just register this screen's channelId and read the shared status.\n * This avoids racing `gatewayConnect` mutations with the header's\n * `GatewayConnector` (which previously ran its own `useCdecliAutoConnect`\n * and could clobber the chat session binding).\n */\n const cdecli = useCdecliConnection();\n const cdecliSelected = cdecli.cdecliSelected;\n const cdecliConnected = cdecliSelected && cdecli.channelConnected;\n const effectivePersistenceMode = cdecli.persistenceMode ?? 'frontend';\n\n useEffect(() => {\n if (!channelId) return undefined;\n cdecli.setActiveChannelId(channelId);\n return () => {\n cdecli.setActiveChannelId(undefined);\n };\n }, [channelId, cdecli.setActiveChannelId]);\n\n const chatRouting: UseChatStreamRouting = useMemo(\n () =>\n cdecliConnected\n ? {\n kind: 'cdecli',\n channelConnected: cdecli.channelConnected,\n accountId: cdecli.accountId,\n persistenceMode: effectivePersistenceMode,\n }\n : { kind: 'groq' },\n [cdecliConnected, cdecli.channelConnected, cdecli.accountId, effectivePersistenceMode],\n );\n\n const chat = useChatStream(channelId, chatRouting);\n const { messages, response, error: chatError, isLoading, isStreaming, messagesLoading, sendMessage, cancel } = chat;\n\n /*\n * Composer state — kept local so it doesn't leak across navigations.\n *\n * `valueRef` mirrors the controlled `value` so `handleSend` can read the\n * latest text without taking a dependency on it. Without this, `handleSend`\n * (and therefore `micSendButton.onSend`) would be recreated on every\n * keystroke, which is unnecessary churn for `InputToolBar`.\n *\n * `inputRef` is forwarded to InputToolBar's TextInput so we can call\n * `.clear()` imperatively after sending. On iOS, the native text buffer\n * can stay desynced from the controlled `value` for a frame when a state\n * update is followed by an async dispatch in the same gesture — the\n * \"send-and-clear\" race. The imperative clear closes that gap deterministically.\n */\n const [value, setValue] = useState('');\n const valueRef = useRef(value);\n valueRef.current = value;\n const inputRef = useRef<TextInput>(null);\n const trimmed = value.trim();\n const hasQuery = trimmed.length > 0;\n const canSubmit = hasQuery && Boolean(channelId);\n\n /**\n * Composer mode is FREELY user-controlled, mirroring `HomeScreen`.\n *\n * Seed:\n * • From Home (which forwards `initialMode` alongside `initialQuery`):\n * start in whatever mode the user picked there so the \"research from\n * home → research-shaped chat\" hand-off feels continuous.\n * • From ChatHistory (which intentionally does NOT pass `initialMode`):\n * default to `'chat'`, same as Home's empty composer.\n *\n * Post-mount this is a normal local state — the search/zap pills toggle\n * it on tap, and every place that previously branched on\n * `params.initialMode` now branches on `activeMode` instead.\n */\n const [activeMode, setActiveMode] = useState<RoutingMode>(() =>\n params.initialMode === 'deep-search' ? 'deep-search' : 'chat',\n );\n const handleModeSwitch = useCallback((mode: RoutingMode) => {\n setActiveMode(mode);\n }, []);\n const isDeepSearchMode = activeMode === 'deep-search';\n\n /**\n * Inline voice recorder state — parity with HomeScreen and the web\n * `YantraSearchComposer.showAudioRecorder` flow. When active, the panel\n * fully replaces the InputToolBar so the toolbar's mic→send button\n * doesn't compete with the panel's own send/cancel affordances.\n */\n const [showAudioRecorder, setShowAudioRecorder] = useState(false);\n const [voiceError, setVoiceError] = useState<string | null>(null);\n\n /**\n * Auto-fire the initial query once when the screen mounts on a fresh channel.\n * Home creates the channel optimistically and forwards the user prompt here so\n * the first assistant token arrives without an extra interaction.\n *\n * If the user has CDeCLI selected we MUST wait for the gateway to finish connecting\n * before firing — otherwise the routing memo still resolves to `{ kind: 'groq' }` and\n * the request goes to the Groq fallback (which doesn't have an API key client-side and\n * returns a 401 \"Invalid API Key\"). Once CDeCLI reaches `connected` (or definitively\n * fails to), we fire and let `useChatStream` route through messenger-gateway.\n */\n const autoFiredRef = useRef(false);\n useEffect(() => {\n if (autoFiredRef.current) return;\n if (!channelId || !initialQuery) return;\n if (cdecliSelected && cdecli.status !== 'connected' && cdecli.status !== 'error') return;\n\n autoFiredRef.current = true;\n // Deep-search auto-fire from Home: open the structured modal at the\n // same instant we kick off the send so the user sees the research view\n // streaming in rather than raw assistant turns. Tied to the\n // sendMessage call (same event) to avoid a race where the modal opens\n // before/after the actual send.\n //\n // We branch on the LOCAL `isDeepSearchMode` instead of\n // `params.initialMode`. At auto-fire time they're equal (the local\n // state was seeded from the param), and using the local state means\n // future toggles drive the same code path consistently.\n if (isDeepSearchMode) {\n setIsDeepSearchModalOpen(true);\n }\n void sendMessage(initialQuery, initialAttachments as any, channelId);\n try {\n navigation.setParams({ initialQuery: null, initialAttachments: null });\n } catch {\n /* setParams may be unavailable in tests; clearing is best-effort. */\n }\n }, [\n channelId,\n initialQuery,\n initialAttachments,\n sendMessage,\n navigation,\n cdecliSelected,\n cdecli.status,\n isDeepSearchMode,\n ]);\n\n const handleSend = useCallback(\n (text?: string) => {\n const t = (text ?? valueRef.current).trim();\n if (!t || isLoading || !channelId) return;\n // Clear both ways: the controlled state (so React's model stays\n // consistent on next render) AND the native buffer via the ref\n // (so the visible text disappears on the same frame the user\n // pressed send, even before React flushes).\n setValue('');\n inputRef.current?.clear();\n // Deep-search mode: every new query pops the structured research\n // modal back open (parity with the previous Home flow, where every\n // submit re-opened the DeepSearchModal). Without this, a user who\n // closed the modal once would see plain assistant turns for every\n // subsequent send. Reads the LOCAL `isDeepSearchMode` so the user\n // can toggle modes mid-thread and have sends behave accordingly.\n if (isDeepSearchMode) {\n setIsDeepSearchModalOpen(true);\n }\n void sendMessage(t, undefined, channelId);\n },\n [isLoading, channelId, sendMessage, isDeepSearchMode],\n );\n\n const handleValueChange = useCallback((e: any) => {\n setValue(e?.nativeEvent?.text ?? '');\n }, []);\n\n /**\n * Mic affordance — web parity (`handleMicClick` in `YantraSearchComposer.tsx`).\n * The shared `MicSendButton` in `InputToolBar.tsx` only routes to `onMic`\n * when the input has no content, so we only need to handle the empty-input\n * case here.\n *\n * We do NOT pre-flight with `AudioModule.requestRecordingPermissionsAsync()`\n * because expo-audio 0.4.x's `AudioRecordingRequester.getPermissions()`\n * crashes with a native SIGABRT (`EXFatal`) on a background dispatch queue\n * in TestFlight/release builds. The JS try/catch cannot intercept a native\n * abort on Thread 13. Instead, the panel's mount effect calls\n * `setAudioModeAsync({ allowsRecording: true })` which triggers the iOS\n * permission dialog via AVAudioSession — a code path that does not go\n * through the broken `EXPermissionsService` requester. If that fails, the\n * panel's catch block and the wrapping `MicErrorBoundary` ensure a\n * graceful fallback.\n */\n const handleMicPress = useCallback(() => {\n if (hasQuery) return;\n setVoiceError(null);\n Keyboard.dismiss();\n setShowAudioRecorder(true);\n }, [hasQuery]);\n\n /**\n * On a successful Whisper round-trip, paste the transcript into the input\n * field, close the recorder, and let the user review/send manually. Matches\n * web's `handleTranscriptionComplete`: we deliberately do NOT auto-fire\n * `sendMessage` because the user often wants to edit the dictation first.\n */\n const handleTranscriptionComplete = useCallback((text: string) => {\n const cleaned = (text ?? '').trim();\n setShowAudioRecorder(false);\n if (!cleaned) return;\n setValue((prev) => {\n const next = prev.trim().length > 0 ? `${prev.trim()} ${cleaned}` : cleaned;\n /*\n * Keep `inputRef`'s native text in sync with our controlled value\n * for the same reason `handleSend` does (the iOS native buffer\n * can lag the React state across a single gesture). `setNativeProps`\n * is the safe way to do this without re-rendering.\n */\n requestAnimationFrame(() => {\n inputRef.current?.setNativeProps?.({ text: next });\n inputRef.current?.focus?.();\n });\n return next;\n });\n }, []);\n\n const handleRecorderCancel = useCallback(() => {\n setShowAudioRecorder(false);\n }, []);\n\n const handleRecorderError = useCallback((error: string) => {\n setVoiceError(error);\n }, []);\n\n const waitingForAssistant = useMemo(() => {\n if ((!isLoading && !isStreaming) || messages.length === 0) return false;\n return messages[messages.length - 1]?.role === 'user';\n }, [isLoading, isStreaming, messages]);\n\n const composerScrollBottomPadding = COMPOSER_SCROLL_RESERVE_PX;\n\n /*\n * NOTE: the previous read-only `isDeepSearchChannel` derivation has been\n * removed. Mode is now a freely-toggleable local state (`activeMode`)\n * driven by tapping the search/zap pills, mirroring HomeScreen. All\n * downstream branches use `isDeepSearchMode` declared with the rest of\n * the composer state above.\n */\n\n /**\n * Deep-search overlay state.\n *\n * Restored from the previous Home-screen flow (commit history): a deep-search\n * channel renders the structured `DeepSearchModal` (query / live summary /\n * sources / research process) on top of the regular Chat conversation. Closing\n * the modal reveals the same channel's MessagesContainerUI underneath so the\n * user can still see the raw turns.\n *\n * Trigger semantics — IMPORTANT:\n * • Opens ONLY when a request is actually fired in this session:\n * - Home → Chat auto-fire of `initialQuery`\n * - User sends a new message in a deep-search channel from the composer\n * - Explicit retry from inside the modal\n * • Does NOT open on plain entry from ChatHistoryScreen. That's a revisit\n * of an already-completed thread — no new API call, nothing live to\n * stream, so popping the modal would just be a confusing flash. The\n * user still sees the deep-search rendering in the chat conversation\n * underneath, and any new send re-opens the live view.\n *\n * Local UI state (accordions, open flag) lives here; data state (query /\n * summary / sources) is DERIVED from the chat stream, not stored separately,\n * so there's no drift between the modal and the underlying conversation.\n */\n const [isDeepSearchModalOpen, setIsDeepSearchModalOpen] = useState(false);\n const [researchProcessOpen, setResearchProcessOpen] = useState(true);\n const [sourcesAccordionOpen, setSourcesAccordionOpen] = useState(true);\n\n /**\n * Modal data is always scoped to the CURRENT run, not the whole channel.\n * In a multi-turn deep-search channel each send is its own \"run\": one user\n * query → one assistant summary. If we sourced from \"first user message\" /\n * \"any assistant message\", a follow-up send would keep showing the previous\n * run's query and stale sources during the transient window between the new\n * user message being appended and the first stream token arriving.\n *\n * Cursor: the LAST user message in the thread. The assistant content for\n * the current run is either:\n * • `response` while the stream is filling (token-by-token), OR\n * • the assistant message that comes AFTER the last user (run complete), OR\n * • empty — covers the brief \"user message appended, no response yet\"\n * window so the modal flips to \"Running...\" with no stale body.\n */\n const lastUserIndex = useMemo(() => {\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n if (messages[i]?.role === 'user') return i;\n }\n return -1;\n }, [messages]);\n\n const deepSearchQuery = useMemo(() => {\n if (lastUserIndex >= 0) {\n const txt = messages[lastUserIndex]?.content?.trim();\n if (txt) return txt;\n }\n return initialQuery ?? null;\n }, [messages, lastUserIndex, initialQuery]);\n\n const latestAssistantContent = useMemo(() => {\n if (response && response.trim()) return response;\n if (lastUserIndex < 0) return '';\n // Look for an assistant turn strictly AFTER the last user message.\n // Anything before it belongs to a prior run and must not leak into\n // the modal for the current one.\n for (let i = lastUserIndex + 1; i < messages.length; i += 1) {\n if (messages[i]?.role === 'assistant') {\n return messages[i]?.content ?? '';\n }\n }\n return '';\n }, [response, messages, lastUserIndex]);\n\n const deepSearchSummary = useMemo(() => normalizeSummaryText(latestAssistantContent), [latestAssistantContent]);\n const deepSearchSources: DeepSearchSourceItem[] = useMemo(\n () => extractDeepSearchSources(latestAssistantContent),\n [latestAssistantContent],\n );\n\n const handleDeepSearchClose = useCallback(() => {\n if (isStreaming) cancel();\n setIsDeepSearchModalOpen(false);\n }, [isStreaming, cancel]);\n\n const handleDeepSearchRetry = useCallback(() => {\n if (!deepSearchQuery || isStreaming || !channelId) return;\n void sendMessage(deepSearchQuery, undefined, channelId);\n }, [deepSearchQuery, isStreaming, channelId, sendMessage]);\n const leftItems = useMemo(\n () =>\n getDefaultLeftItems({\n search: { active: !isDeepSearchMode, onClick: () => handleModeSwitch('chat') },\n zap: { active: isDeepSearchMode, onClick: () => handleModeSwitch('deep-search') },\n lightbulb: {\n onClick: () => {\n // eslint-disable-next-line no-console\n console.log('build mode');\n },\n },\n }),\n [isDeepSearchMode, handleModeSwitch],\n );\n const rightItems = useMemo(\n () =>\n getDefaultRightItems({\n tag: { enabled: false },\n chip: { enabled: false },\n camera: { enabled: false },\n image: { enabled: false },\n attach: { enabled: false },\n }),\n [],\n );\n /**\n * Composer placeholder.\n *\n * Mirrors Home so the composer feels like the same affordance across the\n * \"first message\" and \"continuing thread\" surfaces — only the surrounding\n * UI changes, the input stays a stable anchor. We intentionally do NOT\n * surface a \"Loading conversation…\" state in the placeholder: the message\n * list already shows a dedicated hydrating loader, and switching the\n * placeholder for ~1 frame creates a visible flash on every entry.\n */\n const inputPlaceholder = isDeepSearchMode ? 'Research anything...' : 'Ask anything...';\n\n const inputConfig = useMemo(\n () => ({\n value,\n onChange: handleValueChange,\n placeholder: inputPlaceholder,\n disabled: isLoading || !channelId,\n inputRef,\n }),\n [value, handleValueChange, inputPlaceholder, isLoading, channelId],\n );\n const micSendButton = useMemo(\n () => ({\n hasContent: canSubmit,\n onSend: () => handleSend(),\n onMic: handleMicPress,\n disabled: isLoading || !channelId,\n isLoading,\n onStop: isStreaming ? cancel : undefined,\n }),\n [canSubmit, handleSend, handleMicPress, isLoading, channelId, isStreaming, cancel],\n );\n\n /**\n * Loader visibility:\n * - `isHydrating`: Apollo channel history is being fetched and we have nothing to show yet.\n * - `isWaitingForGateway`: Home navigated us here with an `initialQuery`, but CDeCLI is still\n * establishing the workspace session, so the auto-fire is deferred. Show a \"Connecting…\"\n * placeholder instead of an empty thread so the user doesn't think their send was dropped.\n */\n const isHydrating = messagesLoading && messages.length === 0 && !response;\n const isWaitingForGateway =\n !autoFiredRef.current &&\n !!channelId &&\n !!initialQuery &&\n cdecliSelected &&\n cdecli.status !== 'connected' &&\n cdecli.status !== 'error';\n const showSendingLoader = waitingForAssistant;\n const pinSendingLoaderNearComposer = messages.length > 0 || Boolean((response ?? '').trim());\n\n return (\n <SafeAreaView edges={['left', 'right', 'bottom']} style={{ flex: 1, backgroundColor: surfaceColor }}>\n <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>\n <Box flex={1} width=\"100%\" position=\"relative\">\n {(chatError || cdecli.error) && (\n <Box\n mb=\"$2\"\n mx=\"$4\"\n p=\"$3\"\n borderRadius=\"$md\"\n style={{\n backgroundColor: isDark ? '#2b1a1d' : '#fef2f2',\n borderWidth: 1,\n borderColor: isDark ? '#7f1d1d' : '#fecaca',\n }}\n >\n <Text fontSize=\"$sm\" style={{ color: isDark ? '#fecaca' : '#991b1b' }}>\n {chatError || cdecli.error}\n </Text>\n </Box>\n )}\n {!channelId ? (\n <Box flex={1} alignItems=\"center\" justifyContent=\"center\">\n <YantraBrandLoader size={YANTRA_LOADER_SIZE_COMPACT} />\n <Text style={[styles.statusText, { color: secondaryTextColor }]}>No channel selected</Text>\n </Box>\n ) : isHydrating ? (\n /**\n * Channel hydration (entering Chat from history or a deep\n * link) reuses the same `ThinkingIndicator` row as the\n * chat-history list — thin spinning arc + muted caption.\n * Keeps the loading vocabulary consistent across screens\n * and avoids the previous branded loader + \"Loading\n * conversation\" copy that read as a different state.\n */\n <Box flex={1} alignItems=\"center\" justifyContent=\"center\">\n <ThinkingIndicator color={secondaryTextColor} />\n </Box>\n ) : isWaitingForGateway ? (\n <Box flex={1} alignItems=\"center\" justifyContent=\"center\">\n <YantraBrandLoader size={YANTRA_LOADER_SIZE_COMPACT} />\n <Text style={[styles.statusText, { color: secondaryTextColor }]}>Connecting gateway…</Text>\n </Box>\n ) : (\n <Box flex={1} width=\"100%\" alignSelf=\"stretch\">\n <MessagesContainerUI\n mode=\"chat\"\n showBackButton={false}\n compactTop\n messagesContainerStyle={{\n paddingHorizontal: 0,\n paddingTop: 0,\n paddingBottom: composerScrollBottomPadding,\n margin: 0,\n marginTop: 0,\n alignSelf: 'center',\n width: contentMaxWidth,\n }}\n listContentStyle={{\n paddingTop: 0,\n paddingBottom: composerScrollBottomPadding,\n margin: 0,\n marginTop: 0,\n width: contentMaxWidth,\n alignSelf: 'center',\n justifyContent: 'flex-end',\n }}\n messages={messages.map((msg, index) => ({\n id: `msg-${index}-${msg.role}`,\n role: msg.role,\n content: msg.content,\n metadata: (msg as any).metadata,\n }))}\n streamingContent={response}\n currentUser={{ id: 'user' }}\n onSend={handleSend}\n disabled={isLoading || !channelId}\n isLoading={isLoading}\n onStop={isStreaming ? cancel : undefined}\n renderPlanInputToolbar={() => null}\n renderBuildInputToolbar={() => null}\n />\n </Box>\n )}\n {/* Bottom composer — anchored above the keyboard. */}\n <View\n style={[\n styles.bottomComposerWrap,\n {\n bottom: Math.max(0, keyboardHeight - insets.bottom),\n paddingBottom: Math.max(insets.bottom - 6, 2),\n },\n ]}\n >\n <View style={[styles.bottomComposerInner, { width: contentMaxWidth }]}>\n {voiceError ? (\n <View\n style={[\n styles.voiceErrorBanner,\n {\n backgroundColor: isDark ? '#2b1a1d' : '#fef2f2',\n borderColor: isDark ? '#7f1d1d' : '#fecaca',\n },\n ]}\n >\n <Text style={[styles.voiceErrorText, { color: isDark ? '#fecaca' : '#991b1b' }]}>\n {voiceError}\n </Text>\n </View>\n ) : null}\n {showAudioRecorder ? (\n /*\n * Render-time JS errors thrown by `useAudioRecorder`\n * (e.g. expo-audio native module missing, recorder\n * constructor throws in a release build) are caught\n * by the boundary and converted into a soft cancel\n * via the same handlers the panel itself uses on\n * runtime errors. Without this, a throw during the\n * panel's render phase kills the JS thread in\n * release / TestFlight.\n */\n <MicErrorBoundary onCancel={handleRecorderCancel} onError={handleRecorderError}>\n <AudioRecorderPanel\n isDark={isDark}\n onTranscriptionComplete={handleTranscriptionComplete}\n onCancel={handleRecorderCancel}\n onError={handleRecorderError}\n />\n </MicErrorBoundary>\n ) : (\n <InputToolBar\n inputConfig={inputConfig}\n leftItems={leftItems}\n rightItems={rightItems}\n templateButton={null}\n templateModalConfig={null}\n micSendButton={micSendButton}\n />\n )}\n </View>\n </View>\n {showSendingLoader ? (\n <View\n pointerEvents=\"none\"\n style={\n pinSendingLoaderNearComposer\n ? [\n styles.sendingLoaderAboveComposer,\n {\n bottom: Math.max(insets.bottom, 12) + SENDING_LOADER_COMPOSER_RESERVE_PX,\n },\n ]\n : styles.sendingLoaderEmptyState\n }\n >\n <ThinkingIndicator color={secondaryTextColor} />\n </View>\n ) : null}\n </Box>\n </TouchableWithoutFeedback>\n {/*\n * DeepSearchModal is rendered OUTSIDE the keyboard-dismiss wrapper so\n * taps inside the modal don't dismiss the keyboard, and it's a native\n * <Modal> internally so it correctly sits on top of the Chat surface\n * (composer included) on both iOS and Android.\n */}\n {isDeepSearchMode ? (\n <DeepSearchModal\n visible={isDeepSearchModalOpen}\n query={deepSearchQuery}\n summaryText={deepSearchSummary}\n sources={deepSearchSources}\n isStreaming={isStreaming}\n researchProcessOpen={researchProcessOpen}\n sourcesAccordionOpen={sourcesAccordionOpen}\n onToggleResearchProcess={() => setResearchProcessOpen((prev) => !prev)}\n onToggleSourcesAccordion={() => setSourcesAccordionOpen((prev) => !prev)}\n onRetry={handleDeepSearchRetry}\n onStop={cancel}\n onClose={handleDeepSearchClose}\n />\n ) : null}\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n statusText: {\n marginTop: 14,\n fontSize: 13,\n fontWeight: '500',\n },\n bottomComposerWrap: {\n position: 'absolute',\n width: '100%',\n left: 0,\n right: 0,\n bottom: 0,\n alignItems: 'center',\n justifyContent: 'flex-end',\n shadowColor: '#0f172a',\n shadowOpacity: 0.08,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: -2 },\n backgroundColor: 'transparent',\n elevation: 6,\n },\n bottomComposerInner: {\n paddingHorizontal: 14,\n paddingTop: 10,\n paddingBottom: 4,\n },\n voiceErrorBanner: {\n marginBottom: 8,\n paddingHorizontal: 12,\n paddingVertical: 8,\n borderRadius: 10,\n borderWidth: 1,\n },\n voiceErrorText: {\n fontSize: 12,\n fontWeight: '500',\n },\n sendingLoaderEmptyState: {\n position: 'absolute',\n left: 0,\n right: 0,\n top: 0,\n bottom: 0,\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: 40,\n },\n sendingLoaderAboveComposer: {\n position: 'absolute',\n left: 0,\n right: 0,\n alignItems: 'center',\n justifyContent: 'flex-end',\n paddingBottom: 8,\n zIndex: 40,\n },\n});\n"],"names":["_a","_b","showSub","hideSub"],"mappings":"0rCAkBA,MAAM,0BAA6B,GAAA,GAAA;AACnC,MAAM,kCAAqC,GAAA,GAAA;AA8B3C,SAAwB,UAAa,GAAA;AAjDrC,EAAA,IAAA,EAAA,EAAA,EAAA;AAkDE,EAAA,MAAM,aAAa,aAAmB,EAAA;AACtC,EAAA,MAAM,QAAQ,QAAc,EAAA;AAC5B,EAAA,MAAM,MAAU,GAAA,CAAA,EAAA,GAAA,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAO,MAAP,KAAA,IAAA,GAAA,EAAA,GAAiB,EAAC;AAClC,EAAM,MAAA,SAAA,GAAY,QAAQ,MAAM;AAC9B,IAAM,MAAA,GAAA,GAAM,OAAO,MAAO,CAAA,SAAA,KAAc,WAAW,MAAO,CAAA,SAAA,CAAU,MAAS,GAAA,EAAA;AAC7E,IAAO,OAAA,GAAA,CAAI,MAAS,GAAA,CAAA,GAAI,GAAM,GAAA,IAAA;AAAA,GAC7B,EAAA,CAAC,MAAO,CAAA,SAAS,CAAC,CAAA;AACrB,EAAM,MAAA,YAAA,GAAe,QAAQ,MAAM;AACjC,IAAM,MAAA,GAAA,GAAM,OAAO,MAAO,CAAA,YAAA,KAAiB,WAAW,MAAO,CAAA,YAAA,CAAa,MAAS,GAAA,EAAA;AACnF,IAAO,OAAA,GAAA,CAAI,MAAS,GAAA,CAAA,GAAI,GAAM,GAAA,IAAA;AAAA,GAC7B,EAAA,CAAC,MAAO,CAAA,YAAY,CAAC,CAAA;AACxB,EAAA,MAAM,qBAAqB,MAAO,CAAA,kBAAA;AAClC,EAAA,MAAM,cAAc,cAAe,EAAA;AACnC,EAAA,MAAM,SAAS,WAAgB,KAAA,MAAA;AAC/B,EAAM,MAAA;AAAA,IACJ,KAAO,EAAA;AAAA,MACL,mBAAoB,EAAA;AACxB,EAAM,MAAA,eAAA,GAAkB,KAAK,GAAI,CAAA,GAAA,EAAK,KAAK,GAAI,CAAA,GAAA,EAAK,WAAc,GAAA,EAAE,CAAC,CAAA;AACrE,EAAA,MAAM,YAAe,GAAA,MAAA,GAAS,SAAY,GAAA,YAAA,CAAa,KAAM,CAAA,OAAA;AAC7D,EAAA,MAAM,kBAAqB,GAAA,MAAA,GAAS,SAAY,GAAA,YAAA,CAAa,KAAM,CAAA,SAAA;AACnE,EAAA,MAAM,SAAS,iBAAkB,EAAA;AACjC,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAAS,CAAC,CAAA;AACtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,QAAA,CAAS,OAAO,KAAO,EAAA;AACzB,MAAA,MAAM,QAAW,GAAA,QAAA,CAAS,WAAY,CAAA,yBAAA,EAA2B,CAAM,KAAA,KAAA;AA1E7E,QAAA,IAAAA,GAAAC,EAAAA,GAAAA;AA0EgF,QAAkBA,OAAAA,iBAAAA,CAAAA,CAAAA,GAAAA,GAAAA,CAAAD,MAAA,KAAM,CAAA,cAAA,KAAN,gBAAAA,GAAsB,CAAA,MAAA,KAAtB,IAAAC,GAAAA,GAAAA,GAAgC,CAAC,CAAA;AAAA,OAAC,CAAA;AAC9H,MAAA,MAAMC,QAAU,GAAA,QAAA,CAAS,WAAY,CAAA,kBAAA,EAAoB,CAAM,KAAA,KAAA;AA3ErE,QAAA,IAAAF,GAAAC,EAAAA,GAAAA;AA2EwE,QAAkBA,OAAAA,iBAAAA,CAAAA,CAAAA,GAAAA,GAAAA,CAAAD,MAAA,KAAM,CAAA,cAAA,KAAN,gBAAAA,GAAsB,CAAA,MAAA,KAAtB,IAAAC,GAAAA,GAAAA,GAAgC,CAAC,CAAA;AAAA,OAAC,CAAA;AACtH,MAAA,MAAME,WAAU,QAAS,CAAA,WAAA,CAAY,oBAAoB,MAAM,iBAAA,CAAkB,CAAC,CAAC,CAAA;AACnF,MAAA,OAAO,MAAM;AACX,QAAA,QAAA,CAAS,MAAO,EAAA;AAChB,QAAAD,SAAQ,MAAO,EAAA;AACf,QAAAC,SAAQ,MAAO,EAAA;AAAA,OACjB;AAAA;AAEF,IAAA,MAAM,OAAU,GAAA,QAAA,CAAS,WAAY,CAAA,iBAAA,EAAmB,CAAM,KAAA,KAAA;AAnFlE,MAAA,IAAAH,GAAAC,EAAAA,GAAAA;AAmFqE,MAAkBA,OAAAA,iBAAAA,CAAAA,CAAAA,GAAAA,GAAAA,CAAAD,MAAA,KAAM,CAAA,cAAA,KAAN,gBAAAA,GAAsB,CAAA,MAAA,KAAtB,IAAAC,GAAAA,GAAAA,GAAgC,CAAC,CAAA;AAAA,KAAC,CAAA;AACrH,IAAA,MAAM,UAAU,QAAS,CAAA,WAAA,CAAY,mBAAmB,MAAM,iBAAA,CAAkB,CAAC,CAAC,CAAA;AAClF,IAAA,OAAO,MAAM;AACX,MAAA,OAAA,CAAQ,MAAO,EAAA;AACf,MAAA,OAAA,CAAQ,MAAO,EAAA;AAAA,KACjB;AAAA,GACF,EAAG,EAAE,CAAA;AAWL,EAAA,MAAM,SAAS,mBAAoB,EAAA;AACnC,EAAA,MAAM,iBAAiB,MAAO,CAAA,cAAA;AAC9B,EAAM,MAAA,eAAA,GAAkB,kBAAkB,MAAO,CAAA,gBAAA;AACjD,EAAM,MAAA,wBAAA,GAAA,CAA2B,EAAO,GAAA,MAAA,CAAA,eAAA,KAAP,IAA0B,GAAA,EAAA,GAAA,UAAA;AAC3D,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,CAAC,WAAkB,OAAA,MAAA;AACvB,IAAA,MAAA,CAAO,mBAAmB,SAAS,CAAA;AACnC,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,CAAO,mBAAmB,MAAS,CAAA;AAAA,KACrC;AAAA,GACC,EAAA,CAAC,SAAW,EAAA,MAAA,CAAO,kBAAkB,CAAC,CAAA;AACzC,EAAM,MAAA,WAAA,GAAoC,OAAQ,CAAA,MAAM,eAAkB,GAAA;AAAA,IACxE,IAAM,EAAA,QAAA;AAAA,IACN,kBAAkB,MAAO,CAAA,gBAAA;AAAA,IACzB,WAAW,MAAO,CAAA,SAAA;AAAA,IAClB,eAAiB,EAAA;AAAA,GACf,GAAA;AAAA,IACF,IAAM,EAAA;AAAA,GACR,EAAG,CAAC,eAAiB,EAAA,MAAA,CAAO,kBAAkB,MAAO,CAAA,SAAA,EAAW,wBAAwB,CAAC,CAAA;AACzF,EAAM,MAAA,IAAA,GAAO,aAAc,CAAA,SAAA,EAAW,WAAW,CAAA;AACjD,EAAM,MAAA;AAAA,IACJ,QAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAO,EAAA,SAAA;AAAA,IACP,SAAA;AAAA,IACA,WAAA;AAAA,IACA,eAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACE,GAAA,IAAA;AAgBJ,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,EAAE,CAAA;AACrC,EAAM,MAAA,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAU,GAAA,KAAA;AACnB,EAAM,MAAA,QAAA,GAAW,OAAkB,IAAI,CAAA;AACvC,EAAM,MAAA,OAAA,GAAU,MAAM,IAAK,EAAA;AAC3B,EAAM,MAAA,QAAA,GAAW,QAAQ,MAAS,GAAA,CAAA;AAClC,EAAM,MAAA,SAAA,GAAY,QAAY,IAAA,OAAA,CAAQ,SAAS,CAAA;AAgB/C,EAAM,MAAA,CAAC,UAAY,EAAA,aAAa,CAAI,GAAA,QAAA,CAAsB,MAAM,MAAO,CAAA,WAAA,KAAgB,aAAgB,GAAA,aAAA,GAAgB,MAAM,CAAA;AAC7H,EAAM,MAAA,gBAAA,GAAmB,WAAY,CAAA,CAAC,IAAsB,KAAA;AAC1D,IAAA,aAAA,CAAc,IAAI,CAAA;AAAA,GACpB,EAAG,EAAE,CAAA;AACL,EAAA,MAAM,mBAAmB,UAAe,KAAA,aAAA;AAQxC,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,KAAK,CAAA;AAChE,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAAwB,IAAI,CAAA;AAahE,EAAM,MAAA,YAAA,GAAe,OAAO,KAAK,CAAA;AACjC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,aAAa,OAAS,EAAA;AAC1B,IAAI,IAAA,CAAC,SAAa,IAAA,CAAC,YAAc,EAAA;AACjC,IAAA,IAAI,kBAAkB,MAAO,CAAA,MAAA,KAAW,WAAe,IAAA,MAAA,CAAO,WAAW,OAAS,EAAA;AAClF,IAAA,YAAA,CAAa,OAAU,GAAA,IAAA;AAWvB,IAAA,IAAI,gBAAkB,EAAA;AACpB,MAAA,wBAAA,CAAyB,IAAI,CAAA;AAAA;AAE/B,IAAK,KAAA,WAAA,CAAY,YAAc,EAAA,kBAAA,EAA2B,SAAS,CAAA;AACnE,IAAI,IAAA;AACF,MAAA,UAAA,CAAW,SAAU,CAAA;AAAA,QACnB,YAAc,EAAA,IAAA;AAAA,QACd,kBAAoB,EAAA;AAAA,OACrB,CAAA;AAAA,KACK,CAAA,OAAA,CAAA,EAAA;AAAA;AAER,GACF,EAAG,CAAC,SAAA,EAAW,YAAc,EAAA,kBAAA,EAAoB,WAAa,EAAA,UAAA,EAAY,cAAgB,EAAA,MAAA,CAAO,MAAQ,EAAA,gBAAgB,CAAC,CAAA;AAC1H,EAAM,MAAA,UAAA,GAAa,WAAY,CAAA,CAAC,IAAkB,KAAA;AA9NpD,IAAAD,IAAAA,GAAAA;AA+NI,IAAA,MAAM,CAAK,GAAA,CAAA,IAAA,IAAA,IAAA,GAAA,IAAA,GAAQ,QAAS,CAAA,OAAA,EAAS,IAAK,EAAA;AAC1C,IAAA,IAAI,CAAC,CAAA,IAAK,SAAa,IAAA,CAAC,SAAW,EAAA;AAKnC,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,CAAAA,GAAA,GAAA,QAAA,CAAS,OAAT,KAAA,IAAA,GAAA,MAAA,GAAAA,GAAkB,CAAA,KAAA,EAAA;AAOlB,IAAA,IAAI,gBAAkB,EAAA;AACpB,MAAA,wBAAA,CAAyB,IAAI,CAAA;AAAA;AAE/B,IAAK,KAAA,WAAA,CAAY,CAAG,EAAA,MAAA,EAAW,SAAS,CAAA;AAAA,KACvC,CAAC,SAAA,EAAW,SAAW,EAAA,WAAA,EAAa,gBAAgB,CAAC,CAAA;AACxD,EAAM,MAAA,iBAAA,GAAoB,WAAY,CAAA,CAAC,CAAW,KAAA;AAlPpD,IAAA,IAAAA,GAAAC,EAAAA,GAAAA;AAmPI,IAASA,QAAAA,CAAAA,CAAAA,GAAAA,GAAAA,CAAAD,MAAA,CAAG,IAAA,IAAA,GAAA,MAAA,GAAA,CAAA,CAAA,WAAA,KAAH,gBAAAA,GAAgB,CAAA,IAAA,KAAhB,IAAAC,GAAAA,GAAAA,GAAwB,EAAE,CAAA;AAAA,GACrC,EAAG,EAAE,CAAA;AAmBL,EAAM,MAAA,cAAA,GAAiB,YAAY,MAAM;AACvC,IAAA,IAAI,QAAU,EAAA;AACd,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,QAAA,CAAS,OAAQ,EAAA;AACjB,IAAA,oBAAA,CAAqB,IAAI,CAAA;AAAA,GAC3B,EAAG,CAAC,QAAQ,CAAC,CAAA;AAQb,EAAM,MAAA,2BAAA,GAA8B,WAAY,CAAA,CAAC,IAAiB,KAAA;AAChE,IAAM,MAAA,OAAA,GAAA,CAAW,IAAQ,IAAA,IAAA,GAAA,IAAA,GAAA,EAAA,EAAI,IAAK,EAAA;AAClC,IAAA,oBAAA,CAAqB,KAAK,CAAA;AAC1B,IAAA,IAAI,CAAC,OAAS,EAAA;AACd,IAAA,QAAA,CAAS,CAAQ,IAAA,KAAA;AACf,MAAA,MAAM,IAAO,GAAA,IAAA,CAAK,IAAK,EAAA,CAAE,MAAS,GAAA,CAAA,GAAI,CAAG,EAAA,IAAA,CAAK,IAAK,EAAC,CAAI,CAAA,EAAA,OAAO,CAAK,CAAA,GAAA,OAAA;AAOpE,MAAA,qBAAA,CAAsB,MAAM;AAhSlC,QAAA,IAAAD,KAAAC,GAAA,EAAA,EAAA,EAAA,EAAA;AAiSQ,QAAAA,CAAAA,GAAAA,GAAAA,CAAAD,GAAA,GAAA,QAAA,CAAS,OAAT,KAAA,IAAA,GAAA,MAAA,GAAAA,IAAkB,cAAlB,KAAA,IAAA,GAAA,MAAA,GAAAC,GAAA,CAAA,IAAA,CAAAD,GAAmC,EAAA;AAAA,UACjC,IAAM,EAAA;AAAA,SACR,CAAA;AACA,QAAS,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,QAAA,CAAA,OAAA,KAAT,mBAAkB,KAAlB,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,EAAA,CAAA;AAAA,OACD,CAAA;AACD,MAAO,OAAA,IAAA;AAAA,KACR,CAAA;AAAA,GACH,EAAG,EAAE,CAAA;AACL,EAAM,MAAA,oBAAA,GAAuB,YAAY,MAAM;AAC7C,IAAA,oBAAA,CAAqB,KAAK,CAAA;AAAA,GAC5B,EAAG,EAAE,CAAA;AACL,EAAM,MAAA,mBAAA,GAAsB,WAAY,CAAA,CAAC,KAAkB,KAAA;AACzD,IAAA,aAAA,CAAc,KAAK,CAAA;AAAA,GACrB,EAAG,EAAE,CAAA;AACL,EAAM,MAAA,mBAAA,GAAsB,QAAQ,MAAM;AA/S5C,IAAAA,IAAAA,GAAAA;AAgTI,IAAA,IAAI,CAAC,SAAa,IAAA,CAAC,eAAe,QAAS,CAAA,MAAA,KAAW,GAAU,OAAA,KAAA;AAChE,IAAOA,OAAAA,CAAAA,CAAAA,GAAAA,GAAA,SAAS,QAAS,CAAA,MAAA,GAAS,CAAC,CAA5B,KAAA,IAAA,GAAA,MAAA,GAAAA,IAA+B,IAAS,MAAA,MAAA;AAAA,GAC9C,EAAA,CAAC,SAAW,EAAA,WAAA,EAAa,QAAQ,CAAC,CAAA;AACrC,EAAA,MAAM,2BAA8B,GAAA,0BAAA;AAkCpC,EAAA,MAAM,CAAC,qBAAA,EAAuB,wBAAwB,CAAA,GAAI,SAAS,KAAK,CAAA;AACxE,EAAA,MAAM,CAAC,mBAAA,EAAqB,sBAAsB,CAAA,GAAI,SAAS,IAAI,CAAA;AACnE,EAAA,MAAM,CAAC,oBAAA,EAAsB,uBAAuB,CAAA,GAAI,SAAS,IAAI,CAAA;AAiBrE,EAAM,MAAA,aAAA,GAAgB,QAAQ,MAAM;AAxWtC,IAAAA,IAAAA,GAAAA;AAyWI,IAAA,KAAA,IAAS,IAAI,QAAS,CAAA,MAAA,GAAS,GAAG,CAAK,IAAA,CAAA,EAAG,KAAK,CAAG,EAAA;AAChD,MAAIA,IAAAA,CAAAA,CAAAA,GAAAA,GAAA,SAAS,CAAC,CAAA,KAAV,gBAAAA,GAAa,CAAA,IAAA,MAAS,QAAe,OAAA,CAAA;AAAA;AAE3C,IAAO,OAAA,EAAA;AAAA,GACT,EAAG,CAAC,QAAQ,CAAC,CAAA;AACb,EAAM,MAAA,eAAA,GAAkB,QAAQ,MAAM;AA9WxC,IAAA,IAAAA,GAAAC,EAAAA,GAAAA;AA+WI,IAAA,IAAI,iBAAiB,CAAG,EAAA;AACtB,MAAM,MAAA,GAAA,GAAA,CAAMA,GAAAD,GAAAA,CAAAA,GAAAA,GAAA,QAAS,CAAA,aAAa,MAAtB,IAAAA,GAAAA,MAAAA,GAAAA,GAAAA,CAAyB,OAAzB,KAAA,IAAA,GAAA,MAAA,GAAAC,GAAkC,CAAA,IAAA,EAAA;AAC9C,MAAA,IAAI,KAAY,OAAA,GAAA;AAAA;AAElB,IAAA,OAAO,YAAgB,IAAA,IAAA,GAAA,YAAA,GAAA,IAAA;AAAA,GACtB,EAAA,CAAC,QAAU,EAAA,aAAA,EAAe,YAAY,CAAC,CAAA;AAC1C,EAAM,MAAA,sBAAA,GAAyB,QAAQ,MAAM;AArX/C,IAAA,IAAAD,KAAAC,GAAA,EAAA,EAAA;AAsXI,IAAA,IAAI,QAAY,IAAA,QAAA,CAAS,IAAK,EAAA,EAAU,OAAA,QAAA;AACxC,IAAI,IAAA,aAAA,GAAgB,GAAU,OAAA,EAAA;AAI9B,IAAA,KAAA,IAAS,IAAI,aAAgB,GAAA,CAAA,EAAG,IAAI,QAAS,CAAA,MAAA,EAAQ,KAAK,CAAG,EAAA;AAC3D,MAAA,IAAA,CAAA,CAAID,MAAA,QAAS,CAAA,CAAC,MAAV,IAAAA,GAAAA,MAAAA,GAAAA,GAAAA,CAAa,UAAS,WAAa,EAAA;AACrC,QAAO,OAAA,CAAA,EAAA,GAAA,CAAAC,MAAA,QAAS,CAAA,CAAC,MAAV,IAAAA,GAAAA,MAAAA,GAAAA,GAAAA,CAAa,YAAb,IAAwB,GAAA,EAAA,GAAA,EAAA;AAAA;AACjC;AAEF,IAAO,OAAA,EAAA;AAAA,GACN,EAAA,CAAC,QAAU,EAAA,QAAA,EAAU,aAAa,CAAC,CAAA;AACtC,EAAM,MAAA,iBAAA,GAAoB,QAAQ,MAAM,oBAAA,CAAqB,sBAAsB,CAAG,EAAA,CAAC,sBAAsB,CAAC,CAAA;AAC9G,EAAM,MAAA,iBAAA,GAA4C,QAAQ,MAAM,wBAAA,CAAyB,sBAAsB,CAAG,EAAA,CAAC,sBAAsB,CAAC,CAAA;AAC1I,EAAM,MAAA,qBAAA,GAAwB,YAAY,MAAM;AAC9C,IAAA,IAAI,aAAoB,MAAA,EAAA;AACxB,IAAA,wBAAA,CAAyB,KAAK,CAAA;AAAA,GAC7B,EAAA,CAAC,WAAa,EAAA,MAAM,CAAC,CAAA;AACxB,EAAM,MAAA,qBAAA,GAAwB,YAAY,MAAM;AAC9C,IAAA,IAAI,CAAC,eAAA,IAAmB,WAAe,IAAA,CAAC,SAAW,EAAA;AACnD,IAAK,KAAA,WAAA,CAAY,eAAiB,EAAA,MAAA,EAAW,SAAS,CAAA;AAAA,KACrD,CAAC,eAAA,EAAiB,WAAa,EAAA,SAAA,EAAW,WAAW,CAAC,CAAA;AACzD,EAAM,MAAA,SAAA,GAAY,OAAQ,CAAA,MAAM,mBAAoB,CAAA;AAAA,IAClD,MAAQ,EAAA;AAAA,MACN,QAAQ,CAAC,gBAAA;AAAA,MACT,OAAA,EAAS,MAAM,gBAAA,CAAiB,MAAM;AAAA,KACxC;AAAA,IACA,GAAK,EAAA;AAAA,MACH,MAAQ,EAAA,gBAAA;AAAA,MACR,OAAA,EAAS,MAAM,gBAAA,CAAiB,aAAa;AAAA,KAC/C;AAAA,IACA,SAAW,EAAA;AAAA,MACT,SAAS,MAAM;AAEb,QAAA,OAAA,CAAQ,IAAI,YAAY,CAAA;AAAA;AAC1B;AACF,GACD,CAAA,EAAG,CAAC,gBAAA,EAAkB,gBAAgB,CAAC,CAAA;AACxC,EAAM,MAAA,UAAA,GAAa,OAAQ,CAAA,MAAM,oBAAqB,CAAA;AAAA,IACpD,GAAK,EAAA;AAAA,MACH,OAAS,EAAA;AAAA,KACX;AAAA,IACA,IAAM,EAAA;AAAA,MACJ,OAAS,EAAA;AAAA,KACX;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,OAAS,EAAA;AAAA,KACX;AAAA,IACA,KAAO,EAAA;AAAA,MACL,OAAS,EAAA;AAAA,KACX;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,OAAS,EAAA;AAAA;AACX,GACD,CAAG,EAAA,EAAE,CAAA;AAWN,EAAM,MAAA,gBAAA,GAAmB,mBAAmB,sBAAyB,GAAA,iBAAA;AACrE,EAAM,MAAA,WAAA,GAAc,QAAQ,OAAO;AAAA,IACjC,KAAA;AAAA,IACA,QAAU,EAAA,iBAAA;AAAA,IACV,WAAa,EAAA,gBAAA;AAAA,IACb,QAAA,EAAU,aAAa,CAAC,SAAA;AAAA,IACxB;AAAA,MACE,CAAC,KAAA,EAAO,mBAAmB,gBAAkB,EAAA,SAAA,EAAW,SAAS,CAAC,CAAA;AACtE,EAAM,MAAA,aAAA,GAAgB,QAAQ,OAAO;AAAA,IACnC,UAAY,EAAA,SAAA;AAAA,IACZ,MAAA,EAAQ,MAAM,UAAW,EAAA;AAAA,IACzB,KAAO,EAAA,cAAA;AAAA,IACP,QAAA,EAAU,aAAa,CAAC,SAAA;AAAA,IACxB,SAAA;AAAA,IACA,MAAA,EAAQ,cAAc,MAAS,GAAA;AAAA,GACjC,CAAA,EAAI,CAAC,SAAW,EAAA,UAAA,EAAY,gBAAgB,SAAW,EAAA,SAAA,EAAW,WAAa,EAAA,MAAM,CAAC,CAAA;AAStF,EAAA,MAAM,WAAc,GAAA,eAAA,IAAmB,QAAS,CAAA,MAAA,KAAW,KAAK,CAAC,QAAA;AACjE,EAAA,MAAM,mBAAsB,GAAA,CAAC,YAAa,CAAA,OAAA,IAAW,CAAC,CAAC,SAAA,IAAa,CAAC,CAAC,gBAAgB,cAAkB,IAAA,MAAA,CAAO,MAAW,KAAA,WAAA,IAAe,OAAO,MAAW,KAAA,OAAA;AAC3J,EAAA,MAAM,iBAAoB,GAAA,mBAAA;AAC1B,EAAM,MAAA,4BAAA,GAA+B,SAAS,MAAS,GAAA,CAAA,IAAK,SAAS,QAAY,IAAA,IAAA,GAAA,QAAA,GAAA,EAAA,EAAI,MAAM,CAAA;AAC3F,EAAO,uBAAA,IAAA,CAAC,gBAAa,KAAO,EAAA,CAAC,QAAQ,OAAS,EAAA,QAAQ,GAAG,KAAO,EAAA;AAAA,IAC9D,IAAM,EAAA,CAAA;AAAA,IACN,eAAiB,EAAA;AAAA,GAET,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,wBAAyB,EAAA,EAAA,OAAA,EAAS,QAAS,CAAA,OAAA,EAAS,UAAY,EAAA,KAAA,EAC7D,QAAC,kBAAA,IAAA,CAAA,GAAA,EAAA,EAAI,IAAM,EAAA,CAAA,EAAG,KAAM,EAAA,MAAA,EAAO,UAAS,UAC9B,EAAA,QAAA,EAAA;AAAA,MAAA,CAAA,SAAA,IAAa,MAAO,CAAA,KAAA,qBAAW,GAAA,CAAA,GAAA,EAAA,EAAI,EAAG,EAAA,IAAA,EAAK,EAAG,EAAA,IAAA,EAAK,CAAE,EAAA,IAAA,EAAK,YAAa,EAAA,KAAA,EAAM,KAAO,EAAA;AAAA,QAChG,eAAA,EAAiB,SAAS,SAAY,GAAA,SAAA;AAAA,QACtC,WAAa,EAAA,CAAA;AAAA,QACb,WAAA,EAAa,SAAS,SAAY,GAAA;AAAA,OAEhB,EAAA,QAAA,kBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,QAAA,EAAS,OAAM,KAAO,EAAA;AAAA,QAC5C,KAAA,EAAO,SAAS,SAAY,GAAA;AAAA,OAEP,EAAA,QAAA,EAAA,SAAA,IAAa,MAAO,CAAA,KAAA,EACzB,CACJ,EAAA,CAAA;AAAA,MACH,CAAC,4BAAa,IAAA,CAAA,GAAA,EAAA,EAAI,MAAM,CAAG,EAAA,UAAA,EAAW,QAAS,EAAA,cAAA,EAAe,QACvD,EAAA,QAAA,EAAA;AAAA,wBAAC,GAAA,CAAA,iBAAA,EAAA,EAAkB,MAAM,0BAA4B,EAAA,CAAA;AAAA,wBACpD,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,UAAY,EAAA;AAAA,UACjD,KAAO,EAAA;AAAA,SACR,GAAG,QAAmB,EAAA,qBAAA,EAAA;AAAA,OAAA,EACT,CAAS,GAAA,WAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBASxB,GAAA,CAAA,GAAA,EAAA,EAAI,IAAM,EAAA,CAAA,EAAG,UAAW,EAAA,QAAA,EAAS,cAAe,EAAA,QAAA,EAC7B,QAAC,kBAAA,GAAA,CAAA,iBAAA,EAAA,EAAkB,KAAO,EAAA,kBAAA,EAAoB,CAClD,EAAA;AAAA,UAAU,mBAAA,wBAAuB,GAAI,EAAA,EAAA,IAAA,EAAM,GAAG,UAAW,EAAA,QAAA,EAAS,gBAAe,QAC7E,EAAA,QAAA,EAAA;AAAA,wBAAC,GAAA,CAAA,iBAAA,EAAA,EAAkB,MAAM,0BAA4B,EAAA,CAAA;AAAA,wBACpD,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,UAAY,EAAA;AAAA,UACjD,KAAO,EAAA;AAAA,SACR,GAAG,QAAmB,EAAA,0BAAA,EAAA;AAAA,OAAA,EACT,oBAAU,GAAA,CAAA,GAAA,EAAA,EAAI,IAAM,EAAA,CAAA,EAAG,OAAM,MAAO,EAAA,SAAA,EAAU,SAC1C,EAAA,QAAA,kBAAA,GAAA,CAAC,uBAAoB,IAAK,EAAA,MAAA,EAAO,gBAAgB,KAAO,EAAA,UAAA,EAAU,MAAC,sBAAwB,EAAA;AAAA,QAC3G,iBAAmB,EAAA,CAAA;AAAA,QACnB,UAAY,EAAA,CAAA;AAAA,QACZ,aAAe,EAAA,2BAAA;AAAA,QACf,MAAQ,EAAA,CAAA;AAAA,QACR,SAAW,EAAA,CAAA;AAAA,QACX,SAAW,EAAA,QAAA;AAAA,QACX,KAAO,EAAA;AAAA,SACN,gBAAkB,EAAA;AAAA,QACnB,UAAY,EAAA,CAAA;AAAA,QACZ,aAAe,EAAA,2BAAA;AAAA,QACf,MAAQ,EAAA,CAAA;AAAA,QACR,SAAW,EAAA,CAAA;AAAA,QACX,KAAO,EAAA,eAAA;AAAA,QACP,SAAW,EAAA,QAAA;AAAA,QACX,cAAgB,EAAA;AAAA,SACf,QAAU,EAAA,QAAA,CAAS,GAAI,CAAA,CAAC,KAAK,KAAW,MAAA;AAAA,QACzC,EAAI,EAAA,CAAA,IAAA,EAAO,KAAK,CAAA,CAAA,EAAI,IAAI,IAAI,CAAA,CAAA;AAAA,QAC5B,MAAM,GAAI,CAAA,IAAA;AAAA,QACV,SAAS,GAAI,CAAA,OAAA;AAAA,QACb,UAAW,GAAY,CAAA;AAAA,OACvB,CAAA,CAAA,EAAG,gBAAkB,EAAA,QAAA,EAAU,WAAa,EAAA;AAAA,QAC5C,EAAI,EAAA;AAAA,SACH,MAAQ,EAAA,UAAA,EAAY,UAAU,SAAa,IAAA,CAAC,WAAW,SAAsB,EAAA,MAAA,EAAQ,WAAc,GAAA,MAAA,GAAS,QAAW,sBAAwB,EAAA,MAAM,MAAM,uBAAyB,EAAA,MAAM,MAAM,CACrL,EAAA,CAAA;AAAA,sBAEH,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,kBAAoB,EAAA;AAAA,QACnD,QAAQ,IAAK,CAAA,GAAA,CAAI,CAAG,EAAA,cAAA,GAAiB,OAAO,MAAM,CAAA;AAAA,QAClD,eAAe,IAAK,CAAA,GAAA,CAAI,MAAO,CAAA,MAAA,GAAS,GAAG,CAAC;AAAA,OAC7C,CACe,EAAA,QAAA,kBAAA,IAAA,CAAC,QAAK,KAAO,EAAA,CAAC,OAAO,mBAAqB,EAAA;AAAA,QACtD,KAAO,EAAA;AAAA,OACR,CACkB,EAAA,QAAA,EAAA;AAAA,QAAA,UAAA,mBAAc,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,gBAAkB,EAAA;AAAA,UACnE,eAAA,EAAiB,SAAS,SAAY,GAAA,SAAA;AAAA,UACtC,WAAA,EAAa,SAAS,SAAY,GAAA;AAAA,SACnC,CACuB,EAAA,QAAA,kBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,CAAC,OAAO,cAAgB,EAAA;AAAA,UACzD,KAAA,EAAO,SAAS,SAAY,GAAA;AAAA,SAC7B,CAAA,EAC0B,QACL,EAAA,UAAA,EAAA,CAAA,EACJ,CAAU,GAAA,IAAA;AAAA,QACb,iBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAWhB,GAAA,CAAA,gBAAA,EAAA,EAAiB,QAAU,EAAA,oBAAA,EAAsB,SAAS,mBACnC,EAAA,QAAA,kBAAA,GAAA,CAAC,kBAAmB,EAAA,EAAA,MAAA,EAAgB,yBAAyB,2BAA6B,EAAA,QAAA,EAAU,oBAAsB,EAAA,OAAA,EAAS,qBAAqB,CAC5J,EAAA;AAAA,4BAAuB,GAAA,CAAC,gBAAa,WAA0B,EAAA,SAAA,EAAsB,YAAwB,cAAgB,EAAA,IAAA,EAAM,mBAAqB,EAAA,IAAA,EAAM,aAA8B,EAAA;AAAA,OAAA,EACpM,CACJ,EAAA,CAAA;AAAA,MACC,iBAAA,uBAAqB,IAAK,EAAA,EAAA,aAAA,EAAc,QAAO,KAAO,EAAA,4BAAA,GAA+B,CAAC,MAAA,CAAO,0BAA4B,EAAA;AAAA,QACpI,QAAQ,IAAK,CAAA,GAAA,CAAI,MAAO,CAAA,MAAA,EAAQ,EAAE,CAAI,GAAA;AAAA,OACvC,IAAI,MAAO,CAAA,uBAAA,EACQ,8BAAC,iBAAkB,EAAA,EAAA,KAAA,EAAO,kBAAoB,EAAA,CAAA,EAClD,CAAU,GAAA;AAAA,KAAA,EAClB,CACJ,EAAA,CAAA;AAAA,IAOC,gBAAmB,mBAAA,GAAA,CAAC,eAAgB,EAAA,EAAA,OAAA,EAAS,uBAAuB,KAAO,EAAA,eAAA,EAAiB,WAAa,EAAA,iBAAA,EAAmB,SAAS,iBAAmB,EAAA,WAAA,EAA0B,mBAA0C,EAAA,oBAAA,EAA4C,yBAAyB,MAAM,sBAAA,CAAuB,CAAQ,IAAA,KAAA,CAAC,IAAI,CAAA,EAAG,wBAA0B,EAAA,MAAM,wBAAwB,CAAQ,IAAA,KAAA,CAAC,IAAI,CAAA,EAAG,SAAS,qBAAuB,EAAA,MAAA,EAAQ,MAAQ,EAAA,OAAA,EAAS,uBAAuB,CAAK,GAAA;AAAA,GAChf,EAAA,CAAA;AACR;AACA,MAAM,MAAA,GAAS,WAAW,MAAO,CAAA;AAAA,EAC/B,UAAY,EAAA;AAAA,IACV,SAAW,EAAA,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,kBAAoB,EAAA;AAAA,IAClB,QAAU,EAAA,UAAA;AAAA,IACV,KAAO,EAAA,MAAA;AAAA,IACP,IAAM,EAAA,CAAA;AAAA,IACN,KAAO,EAAA,CAAA;AAAA,IACP,MAAQ,EAAA,CAAA;AAAA,IACR,UAAY,EAAA,QAAA;AAAA,IACZ,cAAgB,EAAA,UAAA;AAAA,IAChB,WAAa,EAAA,SAAA;AAAA,IACb,aAAe,EAAA,IAAA;AAAA,IACf,YAAc,EAAA,CAAA;AAAA,IACd,YAAc,EAAA;AAAA,MACZ,KAAO,EAAA,CAAA;AAAA,MACP,MAAQ,EAAA;AAAA,KACV;AAAA,IACA,eAAiB,EAAA,aAAA;AAAA,IACjB,SAAW,EAAA;AAAA,GACb;AAAA,EACA,mBAAqB,EAAA;AAAA,IACnB,iBAAmB,EAAA,EAAA;AAAA,IACnB,UAAY,EAAA,EAAA;AAAA,IACZ,aAAe,EAAA;AAAA,GACjB;AAAA,EACA,gBAAkB,EAAA;AAAA,IAChB,YAAc,EAAA,CAAA;AAAA,IACd,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA,CAAA;AAAA,IACjB,YAAc,EAAA,EAAA;AAAA,IACd,WAAa,EAAA;AAAA,GACf;AAAA,EACA,cAAgB,EAAA;AAAA,IACd,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,uBAAyB,EAAA;AAAA,IACvB,QAAU,EAAA,UAAA;AAAA,IACV,IAAM,EAAA,CAAA;AAAA,IACN,KAAO,EAAA,CAAA;AAAA,IACP,GAAK,EAAA,CAAA;AAAA,IACL,MAAQ,EAAA,CAAA;AAAA,IACR,cAAgB,EAAA,QAAA;AAAA,IAChB,UAAY,EAAA,QAAA;AAAA,IACZ,MAAQ,EAAA;AAAA,GACV;AAAA,EACA,0BAA4B,EAAA;AAAA,IAC1B,QAAU,EAAA,UAAA;AAAA,IACV,IAAM,EAAA,CAAA;AAAA,IACN,KAAO,EAAA,CAAA;AAAA,IACP,UAAY,EAAA,QAAA;AAAA,IACZ,cAAgB,EAAA,UAAA;AAAA,IAChB,aAAe,EAAA,CAAA;AAAA,IACf,MAAQ,EAAA;AAAA;AAEZ,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/screens/Chat/index.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Keyboard,\n Platform,\n StyleSheet,\n TextInput,\n TouchableWithoutFeedback,\n View,\n useColorScheme,\n useWindowDimensions,\n} from 'react-native';\nimport { Box, InputToolBar, Text, getDefaultLeftItems, getDefaultRightItems } from '@admin-layout/gluestack-ui-mobile';\nimport { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { useNavigation, useRoute } from '@react-navigation/native';\nimport { MessagesContainerUI } from '@messenger-box/platform-mobile';\nimport { useCdecliConnection } from '../../contexts/CdecliConnectionContext';\nimport { useChatStream, type UseChatStreamRouting } from '../../hooks/useChatStream';\nimport { YantraBrandLoader, YANTRA_LOADER_SIZE_COMPACT } from '../../components/YantraBrandLoader';\nimport ThinkingIndicator from '../../components/ThinkingIndicator';\nimport { mobileTokens } from '../../theme/mobileTokens';\nimport DeepSearchModal from '../Home/components/DeepSearchModal';\nimport { extractDeepSearchSources, normalizeSummaryText, type DeepSearchSourceItem } from '../Home/deepSearchUtils';\nimport type { ModeSubmission, RoutingMode } from '../Home/types';\nimport { AudioRecorderPanel } from '../../features/audio-input/AudioRecorderPanel';\nimport { MicErrorBoundary } from '../../features/audio-input/MicErrorBoundary';\nimport { requestMicPermission } from '../../features/audio-input/useAudioPermission';\n\n/** Reserve so the streaming-loader and bottom of the message list don't overlap the composer. */\nconst COMPOSER_SCROLL_RESERVE_PX = 164;\nconst SENDING_LOADER_COMPOSER_RESERVE_PX = 156;\n\n/** Route params passed by Home (or by deep-link) when entering the Chat surface. */\nexport interface ChatScreenRouteParams {\n /** Channel id is required — the screen is keyed on the conversation. */\n channelId: string;\n /** Org slug used by gateway/account context. */\n orgName?: string | null;\n /**\n * First user message to auto-fire when the screen mounts. Home generates\n * this when the user submits from the empty composer so the assistant\n * starts streaming on Chat without an extra round trip.\n */\n initialQuery?: string | null;\n /**\n * Seed for the composer's mode (`'chat'` | `'deep-search'`).\n *\n * Set by `HomeScreen` to carry the user's last selection across the\n * navigation hop (\"research from home → research-shaped composer on chat\").\n * `ChatHistoryScreen` does NOT forward this — revisits always land on the\n * default `'chat'` mode, matching Home's defaults, and the user is free to\n * switch from there.\n *\n * After mount, this param is purely a seed: the screen keeps its own\n * `activeMode` so the user can toggle freely while inside the thread.\n */\n initialMode?: RoutingMode;\n /** Optional attachments forwarded with the initial message. */\n initialAttachments?: ModeSubmission['attachments'];\n}\n\nexport default function ChatScreen() {\n const navigation = useNavigation<any>();\n const route = useRoute<any>();\n\n const params = (route?.params ?? {}) as Partial<ChatScreenRouteParams>;\n const channelId = useMemo(() => {\n const raw = typeof params.channelId === 'string' ? params.channelId.trim() : '';\n return raw.length > 0 ? raw : null;\n }, [params.channelId]);\n const initialQuery = useMemo(() => {\n const raw = typeof params.initialQuery === 'string' ? params.initialQuery.trim() : '';\n return raw.length > 0 ? raw : null;\n }, [params.initialQuery]);\n const initialAttachments = params.initialAttachments;\n\n const colorScheme = useColorScheme();\n const isDark = colorScheme === 'dark';\n const { width: screenWidth } = useWindowDimensions();\n const contentMaxWidth = Math.min(720, Math.max(360, screenWidth - 24));\n\n const surfaceColor = isDark ? '#0f172a' : mobileTokens.color.surface;\n const secondaryTextColor = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n\n const insets = useSafeAreaInsets();\n const [keyboardHeight, setKeyboardHeight] = useState(0);\n useEffect(() => {\n if (Platform.OS === 'ios') {\n const frameSub = Keyboard.addListener('keyboardWillChangeFrame', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const showSub = Keyboard.addListener('keyboardWillShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardWillHide', () => setKeyboardHeight(0));\n return () => {\n frameSub.remove();\n showSub.remove();\n hideSub.remove();\n };\n }\n const showSub = Keyboard.addListener('keyboardDidShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardDidHide', () => setKeyboardHeight(0));\n return () => {\n showSub.remove();\n hideSub.remove();\n };\n }, []);\n\n /**\n * Gateway + chat stream routing.\n *\n * The CDeCLI lifecycle is owned app-wide by `CdecliConnectionProvider`,\n * so we just register this screen's channelId and read the shared status.\n * This avoids racing `gatewayConnect` mutations with the header's\n * `GatewayConnector` (which previously ran its own `useCdecliAutoConnect`\n * and could clobber the chat session binding).\n */\n const cdecli = useCdecliConnection();\n const cdecliSelected = cdecli.cdecliSelected;\n const cdecliConnected = cdecliSelected && cdecli.channelConnected;\n const effectivePersistenceMode = cdecli.persistenceMode ?? 'frontend';\n\n useEffect(() => {\n if (!channelId) return undefined;\n cdecli.setActiveChannelId(channelId);\n return () => {\n cdecli.setActiveChannelId(undefined);\n };\n }, [channelId, cdecli.setActiveChannelId]);\n\n const chatRouting: UseChatStreamRouting = useMemo(\n () =>\n cdecliConnected\n ? {\n kind: 'cdecli',\n channelConnected: cdecli.channelConnected,\n accountId: cdecli.accountId,\n persistenceMode: effectivePersistenceMode,\n }\n : { kind: 'groq' },\n [cdecliConnected, cdecli.channelConnected, cdecli.accountId, effectivePersistenceMode],\n );\n\n const chat = useChatStream(channelId, chatRouting);\n const { messages, response, error: chatError, isLoading, isStreaming, messagesLoading, sendMessage, cancel } = chat;\n\n /*\n * Composer state — kept local so it doesn't leak across navigations.\n *\n * `valueRef` mirrors the controlled `value` so `handleSend` can read the\n * latest text without taking a dependency on it. Without this, `handleSend`\n * (and therefore `micSendButton.onSend`) would be recreated on every\n * keystroke, which is unnecessary churn for `InputToolBar`.\n *\n * `inputRef` is forwarded to InputToolBar's TextInput so we can call\n * `.clear()` imperatively after sending. On iOS, the native text buffer\n * can stay desynced from the controlled `value` for a frame when a state\n * update is followed by an async dispatch in the same gesture — the\n * \"send-and-clear\" race. The imperative clear closes that gap deterministically.\n */\n const [value, setValue] = useState('');\n const valueRef = useRef(value);\n valueRef.current = value;\n const inputRef = useRef<TextInput>(null);\n const trimmed = value.trim();\n const hasQuery = trimmed.length > 0;\n const canSubmit = hasQuery && Boolean(channelId);\n\n /**\n * Composer mode is FREELY user-controlled, mirroring `HomeScreen`.\n *\n * Seed:\n * • From Home (which forwards `initialMode` alongside `initialQuery`):\n * start in whatever mode the user picked there so the \"research from\n * home → research-shaped chat\" hand-off feels continuous.\n * • From ChatHistory (which intentionally does NOT pass `initialMode`):\n * default to `'chat'`, same as Home's empty composer.\n *\n * Post-mount this is a normal local state — the search/zap pills toggle\n * it on tap, and every place that previously branched on\n * `params.initialMode` now branches on `activeMode` instead.\n */\n const [activeMode, setActiveMode] = useState<RoutingMode>(() =>\n params.initialMode === 'deep-search' ? 'deep-search' : 'chat',\n );\n const handleModeSwitch = useCallback((mode: RoutingMode) => {\n setActiveMode(mode);\n }, []);\n const isDeepSearchMode = activeMode === 'deep-search';\n\n /**\n * Inline voice recorder state — parity with HomeScreen and the web\n * `YantraSearchComposer.showAudioRecorder` flow. When active, the panel\n * fully replaces the InputToolBar so the toolbar's mic→send button\n * doesn't compete with the panel's own send/cancel affordances.\n */\n const [showAudioRecorder, setShowAudioRecorder] = useState(false);\n const [voiceError, setVoiceError] = useState<string | null>(null);\n\n /**\n * Auto-fire the initial query once when the screen mounts on a fresh channel.\n * Home creates the channel optimistically and forwards the user prompt here so\n * the first assistant token arrives without an extra interaction.\n *\n * If the user has CDeCLI selected we MUST wait for the gateway to finish connecting\n * before firing — otherwise the routing memo still resolves to `{ kind: 'groq' }` and\n * the request goes to the Groq fallback (which doesn't have an API key client-side and\n * returns a 401 \"Invalid API Key\"). Once CDeCLI reaches `connected` (or definitively\n * fails to), we fire and let `useChatStream` route through messenger-gateway.\n */\n const autoFiredRef = useRef(false);\n useEffect(() => {\n if (autoFiredRef.current) return;\n if (!channelId || !initialQuery) return;\n if (cdecliSelected && cdecli.status !== 'connected' && cdecli.status !== 'error') return;\n\n autoFiredRef.current = true;\n // Deep-search auto-fire from Home: open the structured modal at the\n // same instant we kick off the send so the user sees the research view\n // streaming in rather than raw assistant turns. Tied to the\n // sendMessage call (same event) to avoid a race where the modal opens\n // before/after the actual send.\n //\n // We branch on the LOCAL `isDeepSearchMode` instead of\n // `params.initialMode`. At auto-fire time they're equal (the local\n // state was seeded from the param), and using the local state means\n // future toggles drive the same code path consistently.\n if (isDeepSearchMode) {\n setIsDeepSearchModalOpen(true);\n }\n void sendMessage(initialQuery, initialAttachments as any, channelId);\n try {\n navigation.setParams({ initialQuery: null, initialAttachments: null });\n } catch {\n /* setParams may be unavailable in tests; clearing is best-effort. */\n }\n }, [\n channelId,\n initialQuery,\n initialAttachments,\n sendMessage,\n navigation,\n cdecliSelected,\n cdecli.status,\n isDeepSearchMode,\n ]);\n\n const handleSend = useCallback(\n (text?: string) => {\n const t = (text ?? valueRef.current).trim();\n if (!t || isLoading || !channelId) return;\n // Clear both ways: the controlled state (so React's model stays\n // consistent on next render) AND the native buffer via the ref\n // (so the visible text disappears on the same frame the user\n // pressed send, even before React flushes).\n setValue('');\n inputRef.current?.clear();\n // Deep-search mode: every new query pops the structured research\n // modal back open (parity with the previous Home flow, where every\n // submit re-opened the DeepSearchModal). Without this, a user who\n // closed the modal once would see plain assistant turns for every\n // subsequent send. Reads the LOCAL `isDeepSearchMode` so the user\n // can toggle modes mid-thread and have sends behave accordingly.\n if (isDeepSearchMode) {\n setIsDeepSearchModalOpen(true);\n }\n void sendMessage(t, undefined, channelId);\n },\n [isLoading, channelId, sendMessage, isDeepSearchMode],\n );\n\n const handleValueChange = useCallback((e: any) => {\n setValue(e?.nativeEvent?.text ?? '');\n }, []);\n\n /**\n * Mic affordance — web parity (`handleMicClick` in `YantraSearchComposer.tsx`).\n * Requests expo-audio recording permission on tap (docs flow) so native\n * `record()` sees a granted permission before the panel mounts.\n */\n const handleMicPress = useCallback(() => {\n if (hasQuery) return;\n setVoiceError(null);\n Keyboard.dismiss();\n void (async () => {\n const { granted, error } = await requestMicPermission();\n if (!granted) {\n setVoiceError(error || 'Microphone is not available.');\n return;\n }\n setShowAudioRecorder(true);\n })();\n }, [hasQuery]);\n\n /**\n * On a successful Whisper round-trip, paste the transcript into the input\n * field, close the recorder, and let the user review/send manually. Matches\n * web's `handleTranscriptionComplete`: we deliberately do NOT auto-fire\n * `sendMessage` because the user often wants to edit the dictation first.\n */\n const handleTranscriptionComplete = useCallback((text: string) => {\n const cleaned = (text ?? '').trim();\n setShowAudioRecorder(false);\n if (!cleaned) return;\n setValue((prev) => {\n const next = prev.trim().length > 0 ? `${prev.trim()} ${cleaned}` : cleaned;\n /*\n * Keep `inputRef`'s native text in sync with our controlled value\n * for the same reason `handleSend` does (the iOS native buffer\n * can lag the React state across a single gesture). `setNativeProps`\n * is the safe way to do this without re-rendering.\n */\n requestAnimationFrame(() => {\n inputRef.current?.setNativeProps?.({ text: next });\n inputRef.current?.focus?.();\n });\n return next;\n });\n }, []);\n\n const handleRecorderCancel = useCallback(() => {\n setShowAudioRecorder(false);\n }, []);\n\n const handleRecorderError = useCallback((error: string) => {\n setVoiceError(error);\n }, []);\n\n const waitingForAssistant = useMemo(() => {\n if ((!isLoading && !isStreaming) || messages.length === 0) return false;\n return messages[messages.length - 1]?.role === 'user';\n }, [isLoading, isStreaming, messages]);\n\n const composerScrollBottomPadding = COMPOSER_SCROLL_RESERVE_PX;\n\n /*\n * NOTE: the previous read-only `isDeepSearchChannel` derivation has been\n * removed. Mode is now a freely-toggleable local state (`activeMode`)\n * driven by tapping the search/zap pills, mirroring HomeScreen. All\n * downstream branches use `isDeepSearchMode` declared with the rest of\n * the composer state above.\n */\n\n /**\n * Deep-search overlay state.\n *\n * Restored from the previous Home-screen flow (commit history): a deep-search\n * channel renders the structured `DeepSearchModal` (query / live summary /\n * sources / research process) on top of the regular Chat conversation. Closing\n * the modal reveals the same channel's MessagesContainerUI underneath so the\n * user can still see the raw turns.\n *\n * Trigger semantics — IMPORTANT:\n * • Opens ONLY when a request is actually fired in this session:\n * - Home → Chat auto-fire of `initialQuery`\n * - User sends a new message in a deep-search channel from the composer\n * - Explicit retry from inside the modal\n * • Does NOT open on plain entry from ChatHistoryScreen. That's a revisit\n * of an already-completed thread — no new API call, nothing live to\n * stream, so popping the modal would just be a confusing flash. The\n * user still sees the deep-search rendering in the chat conversation\n * underneath, and any new send re-opens the live view.\n *\n * Local UI state (accordions, open flag) lives here; data state (query /\n * summary / sources) is DERIVED from the chat stream, not stored separately,\n * so there's no drift between the modal and the underlying conversation.\n */\n const [isDeepSearchModalOpen, setIsDeepSearchModalOpen] = useState(false);\n const [researchProcessOpen, setResearchProcessOpen] = useState(true);\n const [sourcesAccordionOpen, setSourcesAccordionOpen] = useState(true);\n\n /**\n * Modal data is always scoped to the CURRENT run, not the whole channel.\n * In a multi-turn deep-search channel each send is its own \"run\": one user\n * query → one assistant summary. If we sourced from \"first user message\" /\n * \"any assistant message\", a follow-up send would keep showing the previous\n * run's query and stale sources during the transient window between the new\n * user message being appended and the first stream token arriving.\n *\n * Cursor: the LAST user message in the thread. The assistant content for\n * the current run is either:\n * • `response` while the stream is filling (token-by-token), OR\n * • the assistant message that comes AFTER the last user (run complete), OR\n * • empty — covers the brief \"user message appended, no response yet\"\n * window so the modal flips to \"Running...\" with no stale body.\n */\n const lastUserIndex = useMemo(() => {\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n if (messages[i]?.role === 'user') return i;\n }\n return -1;\n }, [messages]);\n\n const deepSearchQuery = useMemo(() => {\n if (lastUserIndex >= 0) {\n const txt = messages[lastUserIndex]?.content?.trim();\n if (txt) return txt;\n }\n return initialQuery ?? null;\n }, [messages, lastUserIndex, initialQuery]);\n\n const latestAssistantContent = useMemo(() => {\n if (response && response.trim()) return response;\n if (lastUserIndex < 0) return '';\n // Look for an assistant turn strictly AFTER the last user message.\n // Anything before it belongs to a prior run and must not leak into\n // the modal for the current one.\n for (let i = lastUserIndex + 1; i < messages.length; i += 1) {\n if (messages[i]?.role === 'assistant') {\n return messages[i]?.content ?? '';\n }\n }\n return '';\n }, [response, messages, lastUserIndex]);\n\n const deepSearchSummary = useMemo(() => normalizeSummaryText(latestAssistantContent), [latestAssistantContent]);\n const deepSearchSources: DeepSearchSourceItem[] = useMemo(\n () => extractDeepSearchSources(latestAssistantContent),\n [latestAssistantContent],\n );\n\n const handleDeepSearchClose = useCallback(() => {\n if (isStreaming) cancel();\n setIsDeepSearchModalOpen(false);\n }, [isStreaming, cancel]);\n\n const handleDeepSearchRetry = useCallback(() => {\n if (!deepSearchQuery || isStreaming || !channelId) return;\n void sendMessage(deepSearchQuery, undefined, channelId);\n }, [deepSearchQuery, isStreaming, channelId, sendMessage]);\n const leftItems = useMemo(\n () =>\n getDefaultLeftItems({\n search: { active: !isDeepSearchMode, onClick: () => handleModeSwitch('chat') },\n zap: { active: isDeepSearchMode, onClick: () => handleModeSwitch('deep-search') },\n lightbulb: {\n onClick: () => {\n // eslint-disable-next-line no-console\n console.log('build mode');\n },\n },\n }),\n [isDeepSearchMode, handleModeSwitch],\n );\n const rightItems = useMemo(\n () =>\n getDefaultRightItems({\n tag: { enabled: false },\n chip: { enabled: false },\n camera: { enabled: false },\n image: { enabled: false },\n attach: { enabled: false },\n }),\n [],\n );\n /**\n * Composer placeholder.\n *\n * Mirrors Home so the composer feels like the same affordance across the\n * \"first message\" and \"continuing thread\" surfaces — only the surrounding\n * UI changes, the input stays a stable anchor. We intentionally do NOT\n * surface a \"Loading conversation…\" state in the placeholder: the message\n * list already shows a dedicated hydrating loader, and switching the\n * placeholder for ~1 frame creates a visible flash on every entry.\n */\n const inputPlaceholder = isDeepSearchMode ? 'Research anything...' : 'Ask anything...';\n\n const inputConfig = useMemo(\n () => ({\n value,\n onChange: handleValueChange,\n placeholder: inputPlaceholder,\n disabled: isLoading || !channelId,\n inputRef,\n }),\n [value, handleValueChange, inputPlaceholder, isLoading, channelId],\n );\n const micSendButton = useMemo(\n () => ({\n hasContent: canSubmit,\n onSend: () => handleSend(),\n onMic: handleMicPress,\n disabled: isLoading || !channelId,\n isLoading,\n onStop: isStreaming ? cancel : undefined,\n }),\n [canSubmit, handleSend, handleMicPress, isLoading, channelId, isStreaming, cancel],\n );\n\n /**\n * Loader visibility:\n * - `isHydrating`: Apollo channel history is being fetched and we have nothing to show yet.\n * - `isWaitingForGateway`: Home navigated us here with an `initialQuery`, but CDeCLI is still\n * establishing the workspace session, so the auto-fire is deferred. Show a \"Connecting…\"\n * placeholder instead of an empty thread so the user doesn't think their send was dropped.\n */\n const isHydrating = messagesLoading && messages.length === 0 && !response;\n const isWaitingForGateway =\n !autoFiredRef.current &&\n !!channelId &&\n !!initialQuery &&\n cdecliSelected &&\n cdecli.status !== 'connected' &&\n cdecli.status !== 'error';\n const showSendingLoader = waitingForAssistant;\n const pinSendingLoaderNearComposer = messages.length > 0 || Boolean((response ?? '').trim());\n\n return (\n <SafeAreaView edges={['left', 'right', 'bottom']} style={{ flex: 1, backgroundColor: surfaceColor }}>\n <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>\n <Box flex={1} width=\"100%\" position=\"relative\">\n {(chatError || cdecli.error) && (\n <Box\n mb=\"$2\"\n mx=\"$4\"\n p=\"$3\"\n borderRadius=\"$md\"\n style={{\n backgroundColor: isDark ? '#2b1a1d' : '#fef2f2',\n borderWidth: 1,\n borderColor: isDark ? '#7f1d1d' : '#fecaca',\n }}\n >\n <Text fontSize=\"$sm\" style={{ color: isDark ? '#fecaca' : '#991b1b' }}>\n {chatError || cdecli.error}\n </Text>\n </Box>\n )}\n {!channelId ? (\n <Box flex={1} alignItems=\"center\" justifyContent=\"center\">\n <YantraBrandLoader size={YANTRA_LOADER_SIZE_COMPACT} />\n <Text style={[styles.statusText, { color: secondaryTextColor }]}>No channel selected</Text>\n </Box>\n ) : isHydrating ? (\n /**\n * Channel hydration (entering Chat from history or a deep\n * link) reuses the same `ThinkingIndicator` row as the\n * chat-history list — thin spinning arc + muted caption.\n * Keeps the loading vocabulary consistent across screens\n * and avoids the previous branded loader + \"Loading\n * conversation\" copy that read as a different state.\n */\n <Box flex={1} alignItems=\"center\" justifyContent=\"center\">\n <ThinkingIndicator color={secondaryTextColor} />\n </Box>\n ) : isWaitingForGateway ? (\n <Box flex={1} alignItems=\"center\" justifyContent=\"center\">\n <YantraBrandLoader size={YANTRA_LOADER_SIZE_COMPACT} />\n <Text style={[styles.statusText, { color: secondaryTextColor }]}>Connecting gateway…</Text>\n </Box>\n ) : (\n <Box flex={1} width=\"100%\" alignSelf=\"stretch\">\n <MessagesContainerUI\n mode=\"chat\"\n showBackButton={false}\n compactTop\n messagesContainerStyle={{\n paddingHorizontal: 0,\n paddingTop: 0,\n paddingBottom: composerScrollBottomPadding,\n margin: 0,\n marginTop: 0,\n alignSelf: 'center',\n width: contentMaxWidth,\n }}\n listContentStyle={{\n paddingTop: 0,\n paddingBottom: composerScrollBottomPadding,\n margin: 0,\n marginTop: 0,\n width: contentMaxWidth,\n alignSelf: 'center',\n justifyContent: 'flex-end',\n }}\n messages={messages.map((msg, index) => ({\n id: `msg-${index}-${msg.role}`,\n role: msg.role,\n content: msg.content,\n metadata: (msg as any).metadata,\n }))}\n streamingContent={response}\n currentUser={{ id: 'user' }}\n onSend={handleSend}\n disabled={isLoading || !channelId}\n isLoading={isLoading}\n onStop={isStreaming ? cancel : undefined}\n renderPlanInputToolbar={() => null}\n renderBuildInputToolbar={() => null}\n />\n </Box>\n )}\n {/* Bottom composer — anchored above the keyboard. */}\n <View\n style={[\n styles.bottomComposerWrap,\n {\n bottom: Math.max(0, keyboardHeight - insets.bottom),\n paddingBottom: Math.max(insets.bottom - 6, 2),\n },\n ]}\n >\n <View style={[styles.bottomComposerInner, { width: contentMaxWidth }]}>\n {voiceError ? (\n <View\n style={[\n styles.voiceErrorBanner,\n {\n backgroundColor: isDark ? '#2b1a1d' : '#fef2f2',\n borderColor: isDark ? '#7f1d1d' : '#fecaca',\n },\n ]}\n >\n <Text style={[styles.voiceErrorText, { color: isDark ? '#fecaca' : '#991b1b' }]}>\n {voiceError}\n </Text>\n </View>\n ) : null}\n {showAudioRecorder ? (\n /*\n * Render-time JS errors thrown by `useAudioRecorder`\n * (e.g. expo-audio native module missing, recorder\n * constructor throws in a release build) are caught\n * by the boundary and converted into a soft cancel\n * via the same handlers the panel itself uses on\n * runtime errors. Without this, a throw during the\n * panel's render phase kills the JS thread in\n * release / TestFlight.\n */\n <MicErrorBoundary onCancel={handleRecorderCancel} onError={handleRecorderError}>\n <AudioRecorderPanel\n isDark={isDark}\n onTranscriptionComplete={handleTranscriptionComplete}\n onCancel={handleRecorderCancel}\n onError={handleRecorderError}\n />\n </MicErrorBoundary>\n ) : (\n <InputToolBar\n inputConfig={inputConfig}\n leftItems={leftItems}\n rightItems={rightItems}\n templateButton={null}\n templateModalConfig={null}\n micSendButton={micSendButton}\n />\n )}\n </View>\n </View>\n {showSendingLoader ? (\n <View\n pointerEvents=\"none\"\n style={\n pinSendingLoaderNearComposer\n ? [\n styles.sendingLoaderAboveComposer,\n {\n bottom: Math.max(insets.bottom, 12) + SENDING_LOADER_COMPOSER_RESERVE_PX,\n },\n ]\n : styles.sendingLoaderEmptyState\n }\n >\n <ThinkingIndicator color={secondaryTextColor} />\n </View>\n ) : null}\n </Box>\n </TouchableWithoutFeedback>\n {/*\n * DeepSearchModal is rendered OUTSIDE the keyboard-dismiss wrapper so\n * taps inside the modal don't dismiss the keyboard, and it's a native\n * <Modal> internally so it correctly sits on top of the Chat surface\n * (composer included) on both iOS and Android.\n */}\n {isDeepSearchMode ? (\n <DeepSearchModal\n visible={isDeepSearchModalOpen}\n query={deepSearchQuery}\n summaryText={deepSearchSummary}\n sources={deepSearchSources}\n isStreaming={isStreaming}\n researchProcessOpen={researchProcessOpen}\n sourcesAccordionOpen={sourcesAccordionOpen}\n onToggleResearchProcess={() => setResearchProcessOpen((prev) => !prev)}\n onToggleSourcesAccordion={() => setSourcesAccordionOpen((prev) => !prev)}\n onRetry={handleDeepSearchRetry}\n onStop={cancel}\n onClose={handleDeepSearchClose}\n />\n ) : null}\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n statusText: {\n marginTop: 14,\n fontSize: 13,\n fontWeight: '500',\n },\n bottomComposerWrap: {\n position: 'absolute',\n width: '100%',\n left: 0,\n right: 0,\n bottom: 0,\n alignItems: 'center',\n justifyContent: 'flex-end',\n shadowColor: '#0f172a',\n shadowOpacity: 0.08,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: -2 },\n backgroundColor: 'transparent',\n elevation: 6,\n },\n bottomComposerInner: {\n paddingHorizontal: 14,\n paddingTop: 10,\n paddingBottom: 4,\n },\n voiceErrorBanner: {\n marginBottom: 8,\n paddingHorizontal: 12,\n paddingVertical: 8,\n borderRadius: 10,\n borderWidth: 1,\n },\n voiceErrorText: {\n fontSize: 12,\n fontWeight: '500',\n },\n sendingLoaderEmptyState: {\n position: 'absolute',\n left: 0,\n right: 0,\n top: 0,\n bottom: 0,\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: 40,\n },\n sendingLoaderAboveComposer: {\n position: 'absolute',\n left: 0,\n right: 0,\n alignItems: 'center',\n justifyContent: 'flex-end',\n paddingBottom: 8,\n zIndex: 40,\n },\n});\n"],"names":["_a","_b","showSub","hideSub"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import {jsx,jsxs}from'react/jsx-runtime';import React,{useRef,useState,useMemo,useEffect,useCallback}from'react';import {useWindowDimensions,useColorScheme,Platform,Keyboard,TouchableWithoutFeedback,View,StyleSheet,Pressable}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {useNavigation,useRoute,CommonActions}from'@react-navigation/native';import {v4}from'uuid';import {ContributionSchemaId}from'common';import {useGetContextDataQuery,useGetPageSettingsQuery}from'common/graphql';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {useChatMutations}from'../../hooks/useChatApi.js';import {AudioRecorderPanel}from'../../features/audio-input/AudioRecorderPanel.js';import {MicErrorBoundary}from'../../features/audio-input/MicErrorBoundary.js';import {mobileTokens}from'../../theme/mobileTokens.js';var __defProp = Object.defineProperty;
1
+ import {jsx,jsxs}from'react/jsx-runtime';import React,{useRef,useState,useMemo,useEffect,useCallback}from'react';import {useWindowDimensions,useColorScheme,Platform,Keyboard,TouchableWithoutFeedback,View,StyleSheet,Pressable}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {useNavigation,useRoute,CommonActions}from'@react-navigation/native';import {v4}from'uuid';import {ContributionSchemaId}from'common';import {useGetContextDataQuery,useGetPageSettingsQuery}from'common/graphql';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {useChatMutations}from'../../hooks/useChatApi.js';import {AudioRecorderPanel}from'../../features/audio-input/AudioRecorderPanel.js';import {MicErrorBoundary}from'../../features/audio-input/MicErrorBoundary.js';import {requestMicPermission}from'../../features/audio-input/useAudioPermission.js';import {mobileTokens}from'../../theme/mobileTokens.js';var __defProp = Object.defineProperty;
2
2
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
3
  var __hasOwnProp = Object.prototype.hasOwnProperty;
4
4
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -276,7 +276,17 @@ function HomeScreenContent({
276
276
  if (hasQuery) return;
277
277
  setVoiceError(null);
278
278
  Keyboard.dismiss();
279
- setShowAudioRecorder(true);
279
+ void (async () => {
280
+ const {
281
+ granted,
282
+ error
283
+ } = await requestMicPermission();
284
+ if (!granted) {
285
+ setVoiceError(error || "Microphone is not available.");
286
+ return;
287
+ }
288
+ setShowAudioRecorder(true);
289
+ })();
280
290
  }, [hasQuery]);
281
291
  const handleTranscriptionComplete = useCallback((text) => {
282
292
  const cleaned = (text != null ? text : "").trim();
@@ -1 +1 @@
1
- {"version":3,"file":"HomeScreen.js","sources":["../../../src/screens/Home/HomeScreen.tsx"],"sourcesContent":["import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Keyboard,\n Platform,\n Pressable,\n StyleSheet,\n TouchableWithoutFeedback,\n View,\n useColorScheme,\n useWindowDimensions,\n} from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { Box, InputToolBar, Text, getDefaultLeftItems, getDefaultRightItems } from '@admin-layout/gluestack-ui-mobile';\nimport { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { useNavigation, useRoute, CommonActions } from '@react-navigation/native';\nimport { v4 as uuidv4 } from 'uuid';\nimport { ContributionSchemaId } from 'common';\nimport { useGetContextDataQuery, useGetPageSettingsQuery } from 'common/graphql';\nimport { usePrerequisiteIds } from '../../hooks/usePrerequisiteIds';\nimport { useChatMutations } from '../../hooks/useChatApi';\nimport { AudioRecorderPanel } from '../../features/audio-input/AudioRecorderPanel';\nimport { MicErrorBoundary } from '../../features/audio-input/MicErrorBoundary';\nimport type { ModeSubmission, RoutingMode } from './types';\nimport { mobileTokens } from '../../theme/mobileTokens';\n\n/**\n * Build the channel `title` we persist on creation. This is the server-side mode\n * signal (web parity: `useYantraComposerChannelSubmit`): the backend inspects the\n * title prefix to route deep-search requests differently from plain chat. The\n * UI never displays this raw string — `buildSessionFromChannel` filters\n * `chat-channel-…` / `deep-search-…` titles out of the history label cascade\n * and derives the visible label from the user's first message instead.\n *\n * Previously we used the user's prompt directly as the title for friendlier\n * history rows, but that silently disabled the server's mode detection — every\n * \"deep-search\" submission landed as a plain chat. Restored to the web scheme.\n */\nfunction buildChannelTitle(mode: RoutingMode, channelId: string): string {\n return mode === 'deep-search' ? `deep-search-${channelId}` : `chat-channel-${channelId}`;\n}\n\nexport type { RoutingMode, ModeSubmission };\n\nexport interface HomeScreenProps {\n initialMode?: RoutingMode;\n onSubmit?: (submission: ModeSubmission) => void;\n onStop?: () => void;\n isLoading?: boolean;\n disabled?: boolean;\n}\n\nfunction organizationFromSettingsValue(settings: unknown): string | null {\n if (settings == null) return null;\n if (typeof settings === 'string') {\n try {\n const parsed = JSON.parse(settings) as { organization?: string };\n const o = parsed?.organization;\n return typeof o === 'string' && o.trim() ? o.trim() : null;\n } catch {\n return null;\n }\n }\n if (typeof settings === 'object' && settings !== null && 'organization' in settings) {\n const o = (settings as { organization?: unknown }).organization;\n return typeof o === 'string' && o.trim() ? o.trim() : null;\n }\n return null;\n}\n\nfunction projectFromSettingsValue(settings: unknown): string | null {\n if (settings == null) return null;\n if (typeof settings === 'string') {\n try {\n const parsed = JSON.parse(settings) as { project?: string };\n const p = parsed?.project;\n return typeof p === 'string' && p.trim() ? p.trim() : null;\n } catch {\n return null;\n }\n }\n if (typeof settings === 'object' && settings !== null && 'project' in settings) {\n const p = (settings as { project?: unknown }).project;\n return typeof p === 'string' && p.trim() ? p.trim() : null;\n }\n return null;\n}\n\ninterface EmptyStateSectionProps {\n isDark: boolean;\n secondaryTextColor: string;\n primaryTextColor: string;\n activeMode: RoutingMode;\n onModeSwitch: (mode: RoutingMode) => void;\n}\n\nconst EmptyStateSection = React.memo(function EmptyStateSection({\n isDark,\n secondaryTextColor,\n primaryTextColor,\n activeMode,\n onModeSwitch,\n}: EmptyStateSectionProps) {\n return (\n <Box flex={1} width=\"100%\">\n <View style={styles.emptyCenterTitleWrap}>\n <Text style={[styles.emptyEyebrow, { color: secondaryTextColor }]}>Choose your mode</Text>\n <View\n style={[\n styles.emptyModePillRow,\n {\n backgroundColor: isDark ? 'rgba(30, 41, 59, 0.9)' : '#eef2ff',\n borderColor: isDark ? 'rgba(148, 163, 184, 0.26)' : 'rgba(67, 56, 202, 0.15)',\n },\n ]}\n >\n <Pressable\n onPress={() => onModeSwitch('chat')}\n style={[\n styles.emptyModePill,\n activeMode === 'chat' && styles.emptyModePillActive,\n activeMode === 'chat' && { backgroundColor: isDark ? '#312e81' : '#4338ca' },\n ]}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Switch to chat mode\"\n >\n <MaterialCommunityIcons\n name=\"magnify\"\n size={14}\n color={activeMode === 'chat' ? '#ffffff' : secondaryTextColor}\n />\n <Text\n style={[\n styles.emptyModePillLabel,\n { color: activeMode === 'chat' ? '#ffffff' : secondaryTextColor },\n ]}\n >\n Chat\n </Text>\n </Pressable>\n <Pressable\n onPress={() => onModeSwitch('deep-search')}\n style={[\n styles.emptyModePill,\n activeMode === 'deep-search' && styles.emptyModePillActive,\n activeMode === 'deep-search' && { backgroundColor: isDark ? '#312e81' : '#4338ca' },\n ]}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Switch to deep-search mode\"\n >\n <MaterialCommunityIcons\n name=\"lightning-bolt-outline\"\n size={14}\n color={activeMode === 'deep-search' ? '#ffffff' : secondaryTextColor}\n />\n <Text\n style={[\n styles.emptyModePillLabel,\n { color: activeMode === 'deep-search' ? '#ffffff' : secondaryTextColor },\n ]}\n >\n Deep Search\n </Text>\n </Pressable>\n {/**\n * Build mode — third pill rendered as a peer of Chat and\n * Deep Search so the segmented control matches the web\n * composer's `search · zap · lightbulb` axis. Inert for\n * now: tapping logs to the console and intentionally does\n * NOT call `onModeSwitch`, so the indigo active fill never\n * lands on Build until the underlying workflow flow exists\n * (matches the same inert treatment the lightbulb gets in\n * the composer toolbar). When `'workflow'` joins\n * `RoutingMode`, swap the press handler to\n * `onModeSwitch('workflow')` and add the `activeMode`\n * styles in the same shape as the two above.\n */}\n <Pressable\n onPress={() => {\n // eslint-disable-next-line no-console\n console.log('build mode');\n }}\n style={styles.emptyModePill}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Build mode (preview)\"\n >\n <MaterialCommunityIcons name=\"lightbulb-outline\" size={14} color={secondaryTextColor} />\n <Text style={[styles.emptyModePillLabel, { color: secondaryTextColor }]}>Build</Text>\n </Pressable>\n </View>\n <Text style={[styles.emptyCenterTitle, { color: primaryTextColor }]}>How do you want to start?</Text>\n <Text style={[styles.emptySubtitle, { color: secondaryTextColor }]}>\n Use Chat for quick help, Deep Search for source-backed answers, or Build to assemble workflows.\n </Text>\n </View>\n </Box>\n );\n});\n\nfunction HomeScreenContent({\n initialMode = 'chat',\n onSubmit: onSubmitProp,\n isLoading: isLoadingProp = false,\n disabled = false,\n}: HomeScreenProps) {\n const { width: screenWidth } = useWindowDimensions();\n const colorScheme = useColorScheme();\n const isDark = colorScheme === 'dark';\n const navigation = useNavigation<any>();\n const route = useRoute<any>();\n const hasRehydratedOrgRef = useRef(false);\n\n const [value, setValue] = useState('');\n const [activeMode, setActiveMode] = useState<RoutingMode>(initialMode);\n /**\n * `showAudioRecorder` swaps the InputToolBar for the inline voice recorder\n * panel — same pattern as the web composer\n * (`YantraSearchComposer.tsx`'s `showAudioRecorder` branch).\n */\n const [showAudioRecorder, setShowAudioRecorder] = useState(false);\n const [voiceError, setVoiceError] = useState<string | null>(null);\n\n const { createChannel } = useChatMutations();\n const { orgName: resolvedOrgName, projectId } = usePrerequisiteIds();\n const { data: contextData } = useGetContextDataQuery();\n const cdecodeUri = contextData?.getContextData?.cdecodeUri;\n const { data: pageSettingsData } = useGetPageSettingsQuery({\n variables: {\n resourceUri: cdecodeUri as never,\n options: {\n schemaId: ContributionSchemaId.Configuration,\n configKey: 'account.default',\n includeMarketplace: true,\n },\n },\n skip: !cdecodeUri,\n fetchPolicy: 'cache-first',\n });\n const fallbackOrgNameFromSettings = useMemo(\n () => organizationFromSettingsValue(pageSettingsData?.pageSettings?.settings),\n [pageSettingsData],\n );\n const fallbackProjectIdFromSettings = useMemo(\n () => projectFromSettingsValue(pageSettingsData?.pageSettings?.settings),\n [pageSettingsData],\n );\n const routeOrgName = ((route?.params?.orgName as string | undefined) ?? '').trim() || null;\n const effectiveOrgName = resolvedOrgName || fallbackOrgNameFromSettings || routeOrgName || null;\n const effectiveProjectId = projectId || fallbackProjectIdFromSettings || null;\n\n const trimmedQuery = value.trim();\n const hasQuery = trimmedQuery.length > 0;\n const canSubmit = hasQuery && Boolean(routeOrgName || effectiveOrgName);\n const isLoading = isLoadingProp;\n const isResearchMode = activeMode === 'deep-search';\n const inputPlaceholder = !effectiveOrgName\n ? 'Initializing workspace...'\n : isResearchMode\n ? 'Research anything...'\n : 'Ask anything...';\n\n const insets = useSafeAreaInsets();\n const [keyboardHeight, setKeyboardHeight] = useState(0);\n\n useEffect(() => {\n if (Platform.OS === 'ios') {\n const frameSub = Keyboard.addListener('keyboardWillChangeFrame', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const showSub = Keyboard.addListener('keyboardWillShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardWillHide', () => setKeyboardHeight(0));\n return () => {\n frameSub.remove();\n showSub.remove();\n hideSub.remove();\n };\n }\n const showSub = Keyboard.addListener('keyboardDidShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardDidHide', () => setKeyboardHeight(0));\n return () => {\n showSub.remove();\n hideSub.remove();\n };\n }, []);\n\n const handleModeSwitch = useCallback((mode: RoutingMode) => {\n setActiveMode(mode);\n }, []);\n\n /**\n * Mirrors the web `useYantraComposerChannelSubmit`: on submit we generate a client-side\n * channel id, fire-and-forget the createChannel mutation, then navigate immediately to\n * the Chat screen with the user's prompt. The Chat screen mounts, awaits the in-flight\n * creation just before saveMessages, and starts streaming the assistant response.\n */\n const navigateToChat = useCallback(\n (channelId: string, query: string, mode: RoutingMode, attachments?: ModeSubmission['attachments']) => {\n const params: Record<string, unknown> = {\n channelId,\n orgName: effectiveOrgName ?? routeOrgName ?? undefined,\n initialQuery: query,\n initialMode: mode,\n };\n if (attachments && attachments.length > 0) {\n params.initialAttachments = attachments;\n }\n navigation.dispatch(\n CommonActions.navigate({\n name: 'MainStack.Chat',\n params,\n }),\n );\n },\n [navigation, effectiveOrgName, routeOrgName],\n );\n\n const handleSubmit = useCallback(\n async (attachments?: ModeSubmission['attachments']) => {\n if (!canSubmit || isLoading || disabled) return;\n\n const submission: ModeSubmission = {\n mode: activeMode,\n query: trimmedQuery,\n attachments,\n };\n if (onSubmitProp) {\n onSubmitProp(submission);\n }\n\n if (!effectiveOrgName || !effectiveProjectId) {\n console.warn('[HomeScreen] orgName/projectId not ready — skipping submit.');\n return;\n }\n\n const requestedChannelId = uuidv4();\n /**\n * Title is the server's mode signal (`deep-search-…` vs `chat-channel-…`).\n * It's NOT the history label — the history list derives that from the\n * first user message via `buildSessionFromChannel`.\n */\n const title = buildChannelTitle(activeMode, requestedChannelId);\n\n const queryToForward = trimmedQuery;\n const attachmentsToForward = attachments;\n setValue('');\n\n void createChannel({\n id: requestedChannelId,\n title,\n isShared: false,\n sharedSlug: null,\n isArchived: false,\n isPinned: false,\n model: null,\n systemPrompt: null,\n orgName: effectiveOrgName,\n projectId: effectiveProjectId,\n } as any).catch((err) => {\n console.error('[HomeScreen] createChannel failed:', err);\n });\n\n navigateToChat(requestedChannelId, queryToForward, activeMode, attachmentsToForward);\n },\n [\n canSubmit,\n isLoading,\n disabled,\n activeMode,\n trimmedQuery,\n onSubmitProp,\n effectiveOrgName,\n effectiveProjectId,\n createChannel,\n navigateToChat,\n ],\n );\n\n const surfaceColor = isDark ? '#0f172a' : mobileTokens.color.surface;\n const primaryTextColor = isDark ? '#e5e7eb' : mobileTokens.color.text;\n const secondaryTextColor = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n const contentMaxWidth = Math.min(720, Math.max(360, screenWidth - 24));\n\n useEffect(() => {\n const currentOrgName = (route?.params?.orgName as string | undefined)?.trim() || '';\n if (!effectiveOrgName || currentOrgName === effectiveOrgName) return;\n navigation.setParams?.({ orgName: effectiveOrgName });\n }, [navigation, route?.params?.orgName, effectiveOrgName]);\n\n useEffect(() => {\n const currentOrgName = (route?.params?.orgName as string | undefined)?.trim() || '';\n if (hasRehydratedOrgRef.current || currentOrgName || !effectiveOrgName) return;\n\n hasRehydratedOrgRef.current = true;\n navigation.getParent()?.dispatch(\n CommonActions.navigate('MainStack', {\n screen: 'MainStack.Layout.Home',\n params: { orgName: effectiveOrgName },\n merge: true,\n key: Date.now().toString(),\n }),\n );\n }, [navigation, route?.params?.orgName, effectiveOrgName]);\n\n const handleValueChange = useCallback((e: any) => {\n setValue(e.nativeEvent.text);\n }, []);\n\n /**\n * Mic affordance — web parity (`handleMicClick` in `YantraSearchComposer.tsx`).\n *\n * Only opens the recorder when the input is empty: if the user already has\n * a draft, the same button must act as Send (the `MicSendButton` in\n * `InputToolBar.tsx` already swaps its glyph from mic→send based on\n * `hasContent`, so this branch only fires when the icon is visibly a mic).\n *\n * We do NOT pre-flight with `AudioModule.requestRecordingPermissionsAsync()`\n * because expo-audio 0.4.x's `AudioRecordingRequester.getPermissions()`\n * crashes with a native SIGABRT (`EXFatal`) on a background dispatch queue\n * in TestFlight/release builds. The JS try/catch cannot intercept a native\n * abort on Thread 13. Instead, the panel's mount effect calls\n * `setAudioModeAsync({ allowsRecording: true })` which triggers the iOS\n * permission dialog via AVAudioSession — a code path that does not go\n * through the broken `EXPermissionsService` requester. If that fails, the\n * panel's catch block and the wrapping `MicErrorBoundary` ensure a\n * graceful fallback.\n */\n const handleMicPress = useCallback(() => {\n if (hasQuery) return;\n setVoiceError(null);\n Keyboard.dismiss();\n setShowAudioRecorder(true);\n }, [hasQuery]);\n\n const handleTranscriptionComplete = useCallback((text: string) => {\n const cleaned = (text ?? '').trim();\n setShowAudioRecorder(false);\n if (!cleaned) return;\n /*\n * Append on top of any existing draft (web `setQuery((prev) => …)`).\n * Single-space separator keeps the transcript readable when the user\n * dictates multiple times before sending.\n */\n setValue((prev) => (prev.trim().length > 0 ? `${prev.trim()} ${cleaned}` : cleaned));\n }, []);\n\n const handleRecorderCancel = useCallback(() => {\n setShowAudioRecorder(false);\n }, []);\n\n const handleRecorderError = useCallback((error: string) => {\n /*\n * Surface the failure to the user but don't trap them in the recorder —\n * `AudioRecorderPanel` already calls `onCancel` after an error, so we\n * just record the message here for the (lightweight) banner below.\n */\n setVoiceError(error);\n }, []);\n\n const leftItems = useMemo(\n () =>\n getDefaultLeftItems({\n search: {\n active: activeMode === 'chat',\n onClick: () => handleModeSwitch('chat'),\n },\n zap: {\n active: activeMode === 'deep-search',\n onClick: () => handleModeSwitch('deep-search'),\n },\n lightbulb: {\n onClick: () => {\n // eslint-disable-next-line no-console\n console.log('build mode');\n },\n },\n }),\n [activeMode, handleModeSwitch],\n );\n\n const rightItems = useMemo(\n () =>\n getDefaultRightItems({\n tag: { enabled: false },\n chip: { enabled: false },\n camera: { enabled: false },\n image: { enabled: false },\n attach: { enabled: false },\n }),\n [],\n );\n\n const inputConfig = useMemo(\n () => ({\n value,\n onChange: handleValueChange,\n placeholder: inputPlaceholder,\n disabled: isLoading || disabled,\n }),\n [value, handleValueChange, inputPlaceholder, isLoading, disabled],\n );\n\n const micSendButton = useMemo(\n () => ({\n hasContent: canSubmit,\n onSend: () => handleSubmit(),\n onMic: handleMicPress,\n disabled: isLoading || disabled,\n isLoading,\n }),\n [canSubmit, handleSubmit, handleMicPress, isLoading, disabled],\n );\n\n return (\n <SafeAreaView edges={['left', 'right', 'bottom']} style={{ flex: 1, backgroundColor: surfaceColor }}>\n <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>\n <Box flex={1} width=\"100%\" position=\"relative\">\n <EmptyStateSection\n isDark={isDark}\n secondaryTextColor={secondaryTextColor}\n primaryTextColor={primaryTextColor}\n activeMode={activeMode}\n onModeSwitch={handleModeSwitch}\n />\n <View\n style={[\n styles.bottomComposerWrap,\n {\n bottom: Math.max(0, keyboardHeight - insets.bottom),\n paddingBottom: Math.max(insets.bottom - 6, 2),\n },\n ]}\n >\n <View style={[styles.bottomComposerInner, { width: contentMaxWidth }]}>\n {voiceError ? (\n <View\n style={[\n styles.voiceErrorBanner,\n {\n backgroundColor: isDark ? '#2b1a1d' : '#fef2f2',\n borderColor: isDark ? '#7f1d1d' : '#fecaca',\n },\n ]}\n >\n <Text style={[styles.voiceErrorText, { color: isDark ? '#fecaca' : '#991b1b' }]}>\n {voiceError}\n </Text>\n </View>\n ) : null}\n {showAudioRecorder ? (\n /*\n * Render-time JS errors thrown by `useAudioRecorder`\n * (e.g. expo-audio native module missing, recorder\n * constructor throws in a release build) are caught\n * by the boundary and converted into a soft cancel\n * via the same handlers the panel itself uses on\n * runtime errors. Without this, a throw during the\n * panel's render phase kills the JS thread in\n * release / TestFlight.\n */\n <MicErrorBoundary onCancel={handleRecorderCancel} onError={handleRecorderError}>\n <AudioRecorderPanel\n isDark={isDark}\n onTranscriptionComplete={handleTranscriptionComplete}\n onCancel={handleRecorderCancel}\n onError={handleRecorderError}\n />\n </MicErrorBoundary>\n ) : (\n <InputToolBar\n inputConfig={inputConfig}\n leftItems={leftItems}\n rightItems={rightItems}\n templateButton={null}\n templateModalConfig={null}\n micSendButton={micSendButton}\n />\n )}\n </View>\n </View>\n </Box>\n </TouchableWithoutFeedback>\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n emptyCenterTitleWrap: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'flex-start',\n paddingHorizontal: 24,\n paddingTop: 88,\n paddingBottom: 52,\n maxWidth: 520,\n alignSelf: 'center',\n },\n emptyEyebrow: {\n fontSize: 12,\n fontWeight: '600',\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n marginBottom: 10,\n },\n emptyCenterTitle: {\n marginTop: 2,\n fontSize: 30,\n fontWeight: '700',\n textAlign: 'center',\n letterSpacing: -0.5,\n },\n emptySubtitle: {\n marginTop: 12,\n fontSize: 14,\n lineHeight: 22,\n textAlign: 'center',\n paddingHorizontal: 16,\n maxWidth: 360,\n },\n bottomComposerWrap: {\n position: 'absolute',\n width: '100%',\n left: 0,\n right: 0,\n bottom: 0,\n alignItems: 'center',\n justifyContent: 'flex-end',\n shadowColor: '#0f172a',\n shadowOpacity: 0.08,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: -2 },\n backgroundColor: 'transparent',\n elevation: 6,\n },\n bottomComposerInner: {\n paddingHorizontal: 14,\n paddingTop: 10,\n paddingBottom: 4,\n },\n voiceErrorBanner: {\n marginBottom: 8,\n paddingHorizontal: 12,\n paddingVertical: 8,\n borderRadius: 10,\n borderWidth: 1,\n },\n voiceErrorText: {\n fontSize: 12,\n fontWeight: '500',\n },\n emptyModePillRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 8,\n marginBottom: 22,\n borderRadius: 16,\n padding: 6,\n borderWidth: 1,\n shadowColor: '#312e81',\n shadowOpacity: 0.08,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: 3 },\n elevation: 3,\n },\n emptyModePill: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n paddingHorizontal: 12,\n paddingVertical: 7,\n borderRadius: 11,\n },\n emptyModePillActive: {\n shadowColor: '#312e81',\n shadowOpacity: 0.18,\n shadowRadius: 6,\n shadowOffset: { width: 0, height: 2 },\n elevation: 2,\n },\n emptyModePillLabel: {\n fontSize: 12,\n fontWeight: '600',\n },\n});\n\nconst HomeScreen: FC<HomeScreenProps> = (props) => <HomeScreenContent {...props} />;\n\nexport default HomeScreen;\n"],"names":["EmptyStateSection","_a","_b","showSub","hideSub","uuidv4","_c"],"mappings":"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"}
1
+ {"version":3,"file":"HomeScreen.js","sources":["../../../src/screens/Home/HomeScreen.tsx"],"sourcesContent":["import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Keyboard,\n Platform,\n Pressable,\n StyleSheet,\n TouchableWithoutFeedback,\n View,\n useColorScheme,\n useWindowDimensions,\n} from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { Box, InputToolBar, Text, getDefaultLeftItems, getDefaultRightItems } from '@admin-layout/gluestack-ui-mobile';\nimport { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { useNavigation, useRoute, CommonActions } from '@react-navigation/native';\nimport { v4 as uuidv4 } from 'uuid';\nimport { ContributionSchemaId } from 'common';\nimport { useGetContextDataQuery, useGetPageSettingsQuery } from 'common/graphql';\nimport { usePrerequisiteIds } from '../../hooks/usePrerequisiteIds';\nimport { useChatMutations } from '../../hooks/useChatApi';\nimport { AudioRecorderPanel } from '../../features/audio-input/AudioRecorderPanel';\nimport { MicErrorBoundary } from '../../features/audio-input/MicErrorBoundary';\nimport { requestMicPermission } from '../../features/audio-input/useAudioPermission';\nimport type { ModeSubmission, RoutingMode } from './types';\nimport { mobileTokens } from '../../theme/mobileTokens';\n\n/**\n * Build the channel `title` we persist on creation. This is the server-side mode\n * signal (web parity: `useYantraComposerChannelSubmit`): the backend inspects the\n * title prefix to route deep-search requests differently from plain chat. The\n * UI never displays this raw string — `buildSessionFromChannel` filters\n * `chat-channel-…` / `deep-search-…` titles out of the history label cascade\n * and derives the visible label from the user's first message instead.\n *\n * Previously we used the user's prompt directly as the title for friendlier\n * history rows, but that silently disabled the server's mode detection — every\n * \"deep-search\" submission landed as a plain chat. Restored to the web scheme.\n */\nfunction buildChannelTitle(mode: RoutingMode, channelId: string): string {\n return mode === 'deep-search' ? `deep-search-${channelId}` : `chat-channel-${channelId}`;\n}\n\nexport type { RoutingMode, ModeSubmission };\n\nexport interface HomeScreenProps {\n initialMode?: RoutingMode;\n onSubmit?: (submission: ModeSubmission) => void;\n onStop?: () => void;\n isLoading?: boolean;\n disabled?: boolean;\n}\n\nfunction organizationFromSettingsValue(settings: unknown): string | null {\n if (settings == null) return null;\n if (typeof settings === 'string') {\n try {\n const parsed = JSON.parse(settings) as { organization?: string };\n const o = parsed?.organization;\n return typeof o === 'string' && o.trim() ? o.trim() : null;\n } catch {\n return null;\n }\n }\n if (typeof settings === 'object' && settings !== null && 'organization' in settings) {\n const o = (settings as { organization?: unknown }).organization;\n return typeof o === 'string' && o.trim() ? o.trim() : null;\n }\n return null;\n}\n\nfunction projectFromSettingsValue(settings: unknown): string | null {\n if (settings == null) return null;\n if (typeof settings === 'string') {\n try {\n const parsed = JSON.parse(settings) as { project?: string };\n const p = parsed?.project;\n return typeof p === 'string' && p.trim() ? p.trim() : null;\n } catch {\n return null;\n }\n }\n if (typeof settings === 'object' && settings !== null && 'project' in settings) {\n const p = (settings as { project?: unknown }).project;\n return typeof p === 'string' && p.trim() ? p.trim() : null;\n }\n return null;\n}\n\ninterface EmptyStateSectionProps {\n isDark: boolean;\n secondaryTextColor: string;\n primaryTextColor: string;\n activeMode: RoutingMode;\n onModeSwitch: (mode: RoutingMode) => void;\n}\n\nconst EmptyStateSection = React.memo(function EmptyStateSection({\n isDark,\n secondaryTextColor,\n primaryTextColor,\n activeMode,\n onModeSwitch,\n}: EmptyStateSectionProps) {\n return (\n <Box flex={1} width=\"100%\">\n <View style={styles.emptyCenterTitleWrap}>\n <Text style={[styles.emptyEyebrow, { color: secondaryTextColor }]}>Choose your mode</Text>\n <View\n style={[\n styles.emptyModePillRow,\n {\n backgroundColor: isDark ? 'rgba(30, 41, 59, 0.9)' : '#eef2ff',\n borderColor: isDark ? 'rgba(148, 163, 184, 0.26)' : 'rgba(67, 56, 202, 0.15)',\n },\n ]}\n >\n <Pressable\n onPress={() => onModeSwitch('chat')}\n style={[\n styles.emptyModePill,\n activeMode === 'chat' && styles.emptyModePillActive,\n activeMode === 'chat' && { backgroundColor: isDark ? '#312e81' : '#4338ca' },\n ]}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Switch to chat mode\"\n >\n <MaterialCommunityIcons\n name=\"magnify\"\n size={14}\n color={activeMode === 'chat' ? '#ffffff' : secondaryTextColor}\n />\n <Text\n style={[\n styles.emptyModePillLabel,\n { color: activeMode === 'chat' ? '#ffffff' : secondaryTextColor },\n ]}\n >\n Chat\n </Text>\n </Pressable>\n <Pressable\n onPress={() => onModeSwitch('deep-search')}\n style={[\n styles.emptyModePill,\n activeMode === 'deep-search' && styles.emptyModePillActive,\n activeMode === 'deep-search' && { backgroundColor: isDark ? '#312e81' : '#4338ca' },\n ]}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Switch to deep-search mode\"\n >\n <MaterialCommunityIcons\n name=\"lightning-bolt-outline\"\n size={14}\n color={activeMode === 'deep-search' ? '#ffffff' : secondaryTextColor}\n />\n <Text\n style={[\n styles.emptyModePillLabel,\n { color: activeMode === 'deep-search' ? '#ffffff' : secondaryTextColor },\n ]}\n >\n Deep Search\n </Text>\n </Pressable>\n {/**\n * Build mode — third pill rendered as a peer of Chat and\n * Deep Search so the segmented control matches the web\n * composer's `search · zap · lightbulb` axis. Inert for\n * now: tapping logs to the console and intentionally does\n * NOT call `onModeSwitch`, so the indigo active fill never\n * lands on Build until the underlying workflow flow exists\n * (matches the same inert treatment the lightbulb gets in\n * the composer toolbar). When `'workflow'` joins\n * `RoutingMode`, swap the press handler to\n * `onModeSwitch('workflow')` and add the `activeMode`\n * styles in the same shape as the two above.\n */}\n <Pressable\n onPress={() => {\n // eslint-disable-next-line no-console\n console.log('build mode');\n }}\n style={styles.emptyModePill}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Build mode (preview)\"\n >\n <MaterialCommunityIcons name=\"lightbulb-outline\" size={14} color={secondaryTextColor} />\n <Text style={[styles.emptyModePillLabel, { color: secondaryTextColor }]}>Build</Text>\n </Pressable>\n </View>\n <Text style={[styles.emptyCenterTitle, { color: primaryTextColor }]}>How do you want to start?</Text>\n <Text style={[styles.emptySubtitle, { color: secondaryTextColor }]}>\n Use Chat for quick help, Deep Search for source-backed answers, or Build to assemble workflows.\n </Text>\n </View>\n </Box>\n );\n});\n\nfunction HomeScreenContent({\n initialMode = 'chat',\n onSubmit: onSubmitProp,\n isLoading: isLoadingProp = false,\n disabled = false,\n}: HomeScreenProps) {\n const { width: screenWidth } = useWindowDimensions();\n const colorScheme = useColorScheme();\n const isDark = colorScheme === 'dark';\n const navigation = useNavigation<any>();\n const route = useRoute<any>();\n const hasRehydratedOrgRef = useRef(false);\n\n const [value, setValue] = useState('');\n const [activeMode, setActiveMode] = useState<RoutingMode>(initialMode);\n /**\n * `showAudioRecorder` swaps the InputToolBar for the inline voice recorder\n * panel — same pattern as the web composer\n * (`YantraSearchComposer.tsx`'s `showAudioRecorder` branch).\n */\n const [showAudioRecorder, setShowAudioRecorder] = useState(false);\n const [voiceError, setVoiceError] = useState<string | null>(null);\n\n const { createChannel } = useChatMutations();\n const { orgName: resolvedOrgName, projectId } = usePrerequisiteIds();\n const { data: contextData } = useGetContextDataQuery();\n const cdecodeUri = contextData?.getContextData?.cdecodeUri;\n const { data: pageSettingsData } = useGetPageSettingsQuery({\n variables: {\n resourceUri: cdecodeUri as never,\n options: {\n schemaId: ContributionSchemaId.Configuration,\n configKey: 'account.default',\n includeMarketplace: true,\n },\n },\n skip: !cdecodeUri,\n fetchPolicy: 'cache-first',\n });\n const fallbackOrgNameFromSettings = useMemo(\n () => organizationFromSettingsValue(pageSettingsData?.pageSettings?.settings),\n [pageSettingsData],\n );\n const fallbackProjectIdFromSettings = useMemo(\n () => projectFromSettingsValue(pageSettingsData?.pageSettings?.settings),\n [pageSettingsData],\n );\n const routeOrgName = ((route?.params?.orgName as string | undefined) ?? '').trim() || null;\n const effectiveOrgName = resolvedOrgName || fallbackOrgNameFromSettings || routeOrgName || null;\n const effectiveProjectId = projectId || fallbackProjectIdFromSettings || null;\n\n const trimmedQuery = value.trim();\n const hasQuery = trimmedQuery.length > 0;\n const canSubmit = hasQuery && Boolean(routeOrgName || effectiveOrgName);\n const isLoading = isLoadingProp;\n const isResearchMode = activeMode === 'deep-search';\n const inputPlaceholder = !effectiveOrgName\n ? 'Initializing workspace...'\n : isResearchMode\n ? 'Research anything...'\n : 'Ask anything...';\n\n const insets = useSafeAreaInsets();\n const [keyboardHeight, setKeyboardHeight] = useState(0);\n\n useEffect(() => {\n if (Platform.OS === 'ios') {\n const frameSub = Keyboard.addListener('keyboardWillChangeFrame', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const showSub = Keyboard.addListener('keyboardWillShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardWillHide', () => setKeyboardHeight(0));\n return () => {\n frameSub.remove();\n showSub.remove();\n hideSub.remove();\n };\n }\n const showSub = Keyboard.addListener('keyboardDidShow', (event) =>\n setKeyboardHeight(event.endCoordinates?.height ?? 0),\n );\n const hideSub = Keyboard.addListener('keyboardDidHide', () => setKeyboardHeight(0));\n return () => {\n showSub.remove();\n hideSub.remove();\n };\n }, []);\n\n const handleModeSwitch = useCallback((mode: RoutingMode) => {\n setActiveMode(mode);\n }, []);\n\n /**\n * Mirrors the web `useYantraComposerChannelSubmit`: on submit we generate a client-side\n * channel id, fire-and-forget the createChannel mutation, then navigate immediately to\n * the Chat screen with the user's prompt. The Chat screen mounts, awaits the in-flight\n * creation just before saveMessages, and starts streaming the assistant response.\n */\n const navigateToChat = useCallback(\n (channelId: string, query: string, mode: RoutingMode, attachments?: ModeSubmission['attachments']) => {\n const params: Record<string, unknown> = {\n channelId,\n orgName: effectiveOrgName ?? routeOrgName ?? undefined,\n initialQuery: query,\n initialMode: mode,\n };\n if (attachments && attachments.length > 0) {\n params.initialAttachments = attachments;\n }\n navigation.dispatch(\n CommonActions.navigate({\n name: 'MainStack.Chat',\n params,\n }),\n );\n },\n [navigation, effectiveOrgName, routeOrgName],\n );\n\n const handleSubmit = useCallback(\n async (attachments?: ModeSubmission['attachments']) => {\n if (!canSubmit || isLoading || disabled) return;\n\n const submission: ModeSubmission = {\n mode: activeMode,\n query: trimmedQuery,\n attachments,\n };\n if (onSubmitProp) {\n onSubmitProp(submission);\n }\n\n if (!effectiveOrgName || !effectiveProjectId) {\n console.warn('[HomeScreen] orgName/projectId not ready — skipping submit.');\n return;\n }\n\n const requestedChannelId = uuidv4();\n /**\n * Title is the server's mode signal (`deep-search-…` vs `chat-channel-…`).\n * It's NOT the history label — the history list derives that from the\n * first user message via `buildSessionFromChannel`.\n */\n const title = buildChannelTitle(activeMode, requestedChannelId);\n\n const queryToForward = trimmedQuery;\n const attachmentsToForward = attachments;\n setValue('');\n\n void createChannel({\n id: requestedChannelId,\n title,\n isShared: false,\n sharedSlug: null,\n isArchived: false,\n isPinned: false,\n model: null,\n systemPrompt: null,\n orgName: effectiveOrgName,\n projectId: effectiveProjectId,\n } as any).catch((err) => {\n console.error('[HomeScreen] createChannel failed:', err);\n });\n\n navigateToChat(requestedChannelId, queryToForward, activeMode, attachmentsToForward);\n },\n [\n canSubmit,\n isLoading,\n disabled,\n activeMode,\n trimmedQuery,\n onSubmitProp,\n effectiveOrgName,\n effectiveProjectId,\n createChannel,\n navigateToChat,\n ],\n );\n\n const surfaceColor = isDark ? '#0f172a' : mobileTokens.color.surface;\n const primaryTextColor = isDark ? '#e5e7eb' : mobileTokens.color.text;\n const secondaryTextColor = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n const contentMaxWidth = Math.min(720, Math.max(360, screenWidth - 24));\n\n useEffect(() => {\n const currentOrgName = (route?.params?.orgName as string | undefined)?.trim() || '';\n if (!effectiveOrgName || currentOrgName === effectiveOrgName) return;\n navigation.setParams?.({ orgName: effectiveOrgName });\n }, [navigation, route?.params?.orgName, effectiveOrgName]);\n\n useEffect(() => {\n const currentOrgName = (route?.params?.orgName as string | undefined)?.trim() || '';\n if (hasRehydratedOrgRef.current || currentOrgName || !effectiveOrgName) return;\n\n hasRehydratedOrgRef.current = true;\n navigation.getParent()?.dispatch(\n CommonActions.navigate('MainStack', {\n screen: 'MainStack.Layout.Home',\n params: { orgName: effectiveOrgName },\n merge: true,\n key: Date.now().toString(),\n }),\n );\n }, [navigation, route?.params?.orgName, effectiveOrgName]);\n\n const handleValueChange = useCallback((e: any) => {\n setValue(e.nativeEvent.text);\n }, []);\n\n /**\n * Mic affordance — web parity (`handleMicClick` in `YantraSearchComposer.tsx`).\n *\n * Only opens the recorder when the input is empty: if the user already has\n * a draft, the same button must act as Send (the `MicSendButton` in\n * `InputToolBar.tsx` already swaps its glyph from mic→send based on\n * `hasContent`, so this branch only fires when the icon is visibly a mic).\n *\n * Requests expo-audio recording permission on tap (docs flow) so native\n * `record()` sees a granted permission before the panel mounts.\n */\n const handleMicPress = useCallback(() => {\n if (hasQuery) return;\n setVoiceError(null);\n Keyboard.dismiss();\n void (async () => {\n const { granted, error } = await requestMicPermission();\n if (!granted) {\n setVoiceError(error || 'Microphone is not available.');\n return;\n }\n setShowAudioRecorder(true);\n })();\n }, [hasQuery]);\n\n const handleTranscriptionComplete = useCallback((text: string) => {\n const cleaned = (text ?? '').trim();\n setShowAudioRecorder(false);\n if (!cleaned) return;\n /*\n * Append on top of any existing draft (web `setQuery((prev) => …)`).\n * Single-space separator keeps the transcript readable when the user\n * dictates multiple times before sending.\n */\n setValue((prev) => (prev.trim().length > 0 ? `${prev.trim()} ${cleaned}` : cleaned));\n }, []);\n\n const handleRecorderCancel = useCallback(() => {\n setShowAudioRecorder(false);\n }, []);\n\n const handleRecorderError = useCallback((error: string) => {\n /*\n * Surface the failure to the user but don't trap them in the recorder —\n * `AudioRecorderPanel` already calls `onCancel` after an error, so we\n * just record the message here for the (lightweight) banner below.\n */\n setVoiceError(error);\n }, []);\n\n const leftItems = useMemo(\n () =>\n getDefaultLeftItems({\n search: {\n active: activeMode === 'chat',\n onClick: () => handleModeSwitch('chat'),\n },\n zap: {\n active: activeMode === 'deep-search',\n onClick: () => handleModeSwitch('deep-search'),\n },\n lightbulb: {\n onClick: () => {\n // eslint-disable-next-line no-console\n console.log('build mode');\n },\n },\n }),\n [activeMode, handleModeSwitch],\n );\n\n const rightItems = useMemo(\n () =>\n getDefaultRightItems({\n tag: { enabled: false },\n chip: { enabled: false },\n camera: { enabled: false },\n image: { enabled: false },\n attach: { enabled: false },\n }),\n [],\n );\n\n const inputConfig = useMemo(\n () => ({\n value,\n onChange: handleValueChange,\n placeholder: inputPlaceholder,\n disabled: isLoading || disabled,\n }),\n [value, handleValueChange, inputPlaceholder, isLoading, disabled],\n );\n\n const micSendButton = useMemo(\n () => ({\n hasContent: canSubmit,\n onSend: () => handleSubmit(),\n onMic: handleMicPress,\n disabled: isLoading || disabled,\n isLoading,\n }),\n [canSubmit, handleSubmit, handleMicPress, isLoading, disabled],\n );\n\n return (\n <SafeAreaView edges={['left', 'right', 'bottom']} style={{ flex: 1, backgroundColor: surfaceColor }}>\n <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>\n <Box flex={1} width=\"100%\" position=\"relative\">\n <EmptyStateSection\n isDark={isDark}\n secondaryTextColor={secondaryTextColor}\n primaryTextColor={primaryTextColor}\n activeMode={activeMode}\n onModeSwitch={handleModeSwitch}\n />\n <View\n style={[\n styles.bottomComposerWrap,\n {\n bottom: Math.max(0, keyboardHeight - insets.bottom),\n paddingBottom: Math.max(insets.bottom - 6, 2),\n },\n ]}\n >\n <View style={[styles.bottomComposerInner, { width: contentMaxWidth }]}>\n {voiceError ? (\n <View\n style={[\n styles.voiceErrorBanner,\n {\n backgroundColor: isDark ? '#2b1a1d' : '#fef2f2',\n borderColor: isDark ? '#7f1d1d' : '#fecaca',\n },\n ]}\n >\n <Text style={[styles.voiceErrorText, { color: isDark ? '#fecaca' : '#991b1b' }]}>\n {voiceError}\n </Text>\n </View>\n ) : null}\n {showAudioRecorder ? (\n /*\n * Render-time JS errors thrown by `useAudioRecorder`\n * (e.g. expo-audio native module missing, recorder\n * constructor throws in a release build) are caught\n * by the boundary and converted into a soft cancel\n * via the same handlers the panel itself uses on\n * runtime errors. Without this, a throw during the\n * panel's render phase kills the JS thread in\n * release / TestFlight.\n */\n <MicErrorBoundary onCancel={handleRecorderCancel} onError={handleRecorderError}>\n <AudioRecorderPanel\n isDark={isDark}\n onTranscriptionComplete={handleTranscriptionComplete}\n onCancel={handleRecorderCancel}\n onError={handleRecorderError}\n />\n </MicErrorBoundary>\n ) : (\n <InputToolBar\n inputConfig={inputConfig}\n leftItems={leftItems}\n rightItems={rightItems}\n templateButton={null}\n templateModalConfig={null}\n micSendButton={micSendButton}\n />\n )}\n </View>\n </View>\n </Box>\n </TouchableWithoutFeedback>\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n emptyCenterTitleWrap: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'flex-start',\n paddingHorizontal: 24,\n paddingTop: 88,\n paddingBottom: 52,\n maxWidth: 520,\n alignSelf: 'center',\n },\n emptyEyebrow: {\n fontSize: 12,\n fontWeight: '600',\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n marginBottom: 10,\n },\n emptyCenterTitle: {\n marginTop: 2,\n fontSize: 30,\n fontWeight: '700',\n textAlign: 'center',\n letterSpacing: -0.5,\n },\n emptySubtitle: {\n marginTop: 12,\n fontSize: 14,\n lineHeight: 22,\n textAlign: 'center',\n paddingHorizontal: 16,\n maxWidth: 360,\n },\n bottomComposerWrap: {\n position: 'absolute',\n width: '100%',\n left: 0,\n right: 0,\n bottom: 0,\n alignItems: 'center',\n justifyContent: 'flex-end',\n shadowColor: '#0f172a',\n shadowOpacity: 0.08,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: -2 },\n backgroundColor: 'transparent',\n elevation: 6,\n },\n bottomComposerInner: {\n paddingHorizontal: 14,\n paddingTop: 10,\n paddingBottom: 4,\n },\n voiceErrorBanner: {\n marginBottom: 8,\n paddingHorizontal: 12,\n paddingVertical: 8,\n borderRadius: 10,\n borderWidth: 1,\n },\n voiceErrorText: {\n fontSize: 12,\n fontWeight: '500',\n },\n emptyModePillRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 8,\n marginBottom: 22,\n borderRadius: 16,\n padding: 6,\n borderWidth: 1,\n shadowColor: '#312e81',\n shadowOpacity: 0.08,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: 3 },\n elevation: 3,\n },\n emptyModePill: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n paddingHorizontal: 12,\n paddingVertical: 7,\n borderRadius: 11,\n },\n emptyModePillActive: {\n shadowColor: '#312e81',\n shadowOpacity: 0.18,\n shadowRadius: 6,\n shadowOffset: { width: 0, height: 2 },\n elevation: 2,\n },\n emptyModePillLabel: {\n fontSize: 12,\n fontWeight: '600',\n },\n});\n\nconst HomeScreen: FC<HomeScreenProps> = (props) => <HomeScreenContent {...props} />;\n\nexport default HomeScreen;\n"],"names":["EmptyStateSection","_a","_b","showSub","hideSub","uuidv4","_c"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminide-stack/yantra-mobile",
3
- "version": "12.0.28-alpha.72",
3
+ "version": "12.0.28-alpha.74",
4
4
  "description": "Sample core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -49,5 +49,5 @@
49
49
  "typescript": {
50
50
  "definition": "lib/index.d.ts"
51
51
  },
52
- "gitHead": "1fbfac7c9a123950a206bb0e103ade9bd8b5f695"
52
+ "gitHead": "10df4b590c174847c31c57e639f7142fddbcc8a5"
53
53
  }