@ateam-ai-mobile/core 0.1.5 → 0.1.6

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/api/client.ts","../src/api/mcp.ts","../src/chat/store.ts","../src/utils/emitter.ts","../src/api/tenants.ts","../src/theme/tokens.ts","../src/acs/providers.ts","../src/acs/api.ts","../src/acs/widgetsStore.ts","../src/acs/homeActionsStore.ts","../src/acs/ws.ts"],"sourcesContent":["/**\n * SDK configuration — the single injection point between the host app and\n * the ADAS core. The host owns authentication, identity, and URL discovery;\n * the SDK reads everything through the config registered via initAdas().\n *\n * There is intentionally ONE active config per JS context (module singleton):\n * the chat store, WebSocket, and API client below it are app-wide singletons\n * too, and a second tenant/backend inside one app is not a supported v1 case.\n */\n\nimport type { AttachmentCache } from './storage/types';\n\n/** Result of a host-driven token refresh. Mirrors the semantics the API\n * client depends on: only 'auth_failed' logs the user out; 'transient'\n * (network blip, 5xx) keeps the session so the next call can retry. */\nexport interface RefreshOutcome {\n ok: 'ok' | 'auth_failed' | 'transient';\n status: number;\n reason?: string;\n}\n\n/**\n * Host-implemented auth bridge. The SDK never shows login UI and never\n * stores credentials — the host authenticates its own users and hands the\n * SDK a way to read/refresh the ADAS JWT it minted for them (via the\n * server-to-server token exchange).\n */\nexport interface TokenProvider {\n /** Current ADAS JWT, or null when signed out. Called on every request —\n * keep it synchronous and cheap (read from memory, not disk). */\n getToken(): string | null;\n /** Called on 401. Host should mint/refresh the ADAS token and return the\n * outcome; 'ok' makes the SDK retry the failed request once. */\n refresh(): Promise<RefreshOutcome>;\n /** Auth is genuinely dead (refresh rejected, or retry still 401). Host\n * should treat this as sign-out for the embedded experience. */\n onAuthFailure?: () => void;\n}\n\nexport interface AdasUser {\n actorId: string;\n name?: string;\n email?: string;\n /** Roles from the host's identity (e.g. JWT claims) — forwarded to plugins\n * as PluginContext.user.roles. */\n roles?: string[];\n}\n\n/** A URL that is either static or resolved on each read. Hosts with a\n * runtime env switcher (dev/prod) pass a getter so the SDK always sees the\n * currently-selected backend without re-calling initAdas(). */\nexport type UrlSource = string | (() => string);\n\nexport interface AdasConfig {\n /** Core API base URL, e.g. https://app.ateam-ai.com. Pass a getter to\n * support a runtime env switch without re-initializing. */\n coreUrl: UrlSource;\n /** Voice service base URL (optional — only voice features need it). */\n voiceUrl?: UrlSource;\n /** Consumer-auth base URL, e.g. https://consumer-auth.ateam-ai.com. Only\n * needed for `switchTenant()` (re-scoping the session to another tenant\n * the user belongs to). */\n consumerAuthUrl?: UrlSource;\n tokenProvider: TokenProvider;\n /** Tenant slug — used for plugin URL resolution and voice, never sent as a\n * header (the backend derives the tenant from the JWT). Pass a getter when\n * the host resolves the tenant after startup (storage hydration, runtime\n * tenant switch). */\n tenant?: string | (() => string);\n /** Current end user as known to the host. actorId is used as the chat\n * reply context; without it, replies route to 'unknown'. */\n getUser?: () => AdasUser | null;\n /** Optional persistence for outgoing image/file attachments so previews\n * survive app restarts. No-op when omitted (previews live in memory for\n * the session only). @ateam-ai-mobile/ui ships an Expo/RN implementation. */\n attachmentCache?: AttachmentCache;\n /** Called by `switchTenant()` with the freshly-minted session for the\n * target tenant. The host MUST persist it here (store the new JWT so\n * tokenProvider.getToken() returns it, and update the active tenant) —\n * the SDK never stores credentials. Awaited before the chat reconnects. */\n onSession?: (session: AdasSession) => void | Promise<void>;\n}\n\n/** A tenant-scoped session minted by the platform (e.g. via switchTenant). */\nexport interface AdasSession {\n jwt: string;\n tenant: { id: string; name: string };\n actor: { id: string; email: string | null; roles: string[] };\n}\n\nlet _config: AdasConfig | null = null;\n\n/** Register the SDK configuration. Call once at app start, before any other\n * SDK API. Calling again replaces the config (e.g. env switch) — combine\n * with chat.clearChat() and closeChatStream() for a clean swap. */\nexport function initAdas(config: AdasConfig): void {\n _config = config;\n}\n\nexport function isAdasInitialized(): boolean {\n return _config !== null;\n}\n\nexport function getConfig(): AdasConfig {\n if (!_config) {\n throw new Error('[adas] SDK not initialized — call initAdas(config) before using any ADAS API');\n }\n return _config;\n}\n\nfunction resolveUrl(src: UrlSource): string {\n return (typeof src === 'function' ? src() : src).replace(/\\/$/, '');\n}\n\nexport function getCoreApiUrl(): string {\n return resolveUrl(getConfig().coreUrl);\n}\n\nexport function getCoreWsUrl(): string {\n return getCoreApiUrl().replace(/^http/, 'ws');\n}\n\nexport function getVoiceApiUrl(): string {\n const url = getConfig().voiceUrl;\n if (!url) throw new Error('[adas] voiceUrl not configured');\n return resolveUrl(url);\n}\n\nexport function getConsumerAuthApiUrl(): string {\n const url = getConfig().consumerAuthUrl;\n if (!url) throw new Error('[adas] consumerAuthUrl not configured — required for switchTenant()');\n return resolveUrl(url);\n}\n\nexport function getTenant(): string {\n const t = getConfig().tenant;\n return (typeof t === 'function' ? t() : t) || '';\n}\n\nexport function getUser(): AdasUser | null {\n return getConfig().getUser?.() || null;\n}\n\n// ─── Internal token helpers (thin wrappers over the host's TokenProvider) ──\n\nexport function getToken(): string | null {\n return getConfig().tokenProvider.getToken();\n}\n\nexport async function refreshToken(): Promise<RefreshOutcome> {\n return getConfig().tokenProvider.refresh();\n}\n\nexport function notifyAuthFailure(): void {\n getConfig().tokenProvider.onAuthFailure?.();\n}\n","import { getCoreApiUrl, getVoiceApiUrl, getToken, refreshToken, notifyAuthFailure } from '../config';\n\ntype FetchOptions = RequestInit & {\n baseUrl?: 'core' | 'voice';\n};\n\n/**\n * Base API client with JWT injection and 401 refresh handling.\n *\n * Auth failure semantics (preserved from the reference app): a transient\n * 5xx or network blip on the RETRY after a successful refresh must NOT be\n * treated as sign-out. notifyAuthFailure() fires only when auth is genuinely\n * broken:\n * - Refresh itself was rejected with 401/403 → auth failure\n * - Retry with the fresh JWT still returns 401/403 → auth failure\n * Anything else throws but keeps the session intact — the caller may retry\n * on the next user action.\n */\nexport async function apiFetch<T = unknown>(\n path: string,\n options: FetchOptions = {},\n): Promise<T> {\n const { baseUrl = 'core', ...fetchOptions } = options;\n const base = baseUrl === 'voice' ? getVoiceApiUrl() : getCoreApiUrl();\n const url = `${base}${path}`;\n\n const token = getToken();\n\n const headers: Record<string, string> = {\n ...(fetchOptions.headers as Record<string, string>),\n };\n\n if (token && !headers['Authorization']) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Note: we intentionally DO NOT send a tenant header. The backend derives\n // the tenant from the JWT — a client-supplied tenant paired with a leaked\n // JWT is a tenant-pivot footgun. Tenant comes from the token, not the client.\n\n if (!headers['Content-Type'] && fetchOptions.body && typeof fetchOptions.body === 'string') {\n headers['Content-Type'] = 'application/json';\n }\n\n const res = await fetch(url, { ...fetchOptions, headers });\n\n if (res.status === 401 && token) {\n console.warn(`[adas] 401 on ${path} — attempting refresh`);\n const outcome = await refreshToken();\n if (outcome.ok === 'ok') {\n const newToken = getToken();\n headers['Authorization'] = `Bearer ${newToken}`;\n const retryRes = await fetch(url, { ...fetchOptions, headers });\n if (retryRes.ok) {\n return retryRes.json() as Promise<T>;\n }\n if (retryRes.status === 401 || retryRes.status === 403) {\n // Still auth-broken with a fresh JWT — genuinely dead session.\n console.warn(`[adas] retry after refresh still ${retryRes.status} on ${path} — auth failure`);\n notifyAuthFailure();\n throw new Error('Session expired');\n }\n // Non-auth error on retry. Surface it, but the session is fine.\n const text = await retryRes.text().catch(() => '');\n throw new Error(`API ${retryRes.status}: ${text}`);\n }\n if (outcome.ok === 'auth_failed') {\n console.warn(`[adas] refresh auth_failed on ${path} (${outcome.reason}) — auth failure`);\n notifyAuthFailure();\n throw new Error('Session expired');\n }\n // 'transient' — network/5xx on refresh. Keep the session; surface the 401.\n throw new Error(`API 401: refresh transient (${outcome.reason})`);\n }\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API ${res.status}: ${text}`);\n }\n\n return res.json() as Promise<T>;\n}\n\n/**\n * Fetch with raw response (non-JSON responses, streaming bodies).\n */\nexport async function apiFetchRaw(\n path: string,\n options: FetchOptions = {},\n): Promise<Response> {\n const { baseUrl = 'core', ...fetchOptions } = options;\n const base = baseUrl === 'voice' ? getVoiceApiUrl() : getCoreApiUrl();\n const url = `${base}${path}`;\n\n const token = getToken();\n const headers: Record<string, string> = {\n ...(fetchOptions.headers as Record<string, string>),\n };\n\n if (token && !headers['Authorization']) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n return fetch(url, { ...fetchOptions, headers });\n}\n","/**\n * Shared MCP client — single API layer for ALL plugin communication.\n *\n * Two call patterns:\n * 1. connectorCall(connectorId, tool, args) → POST /api/connectors/:id/call\n * 2. mcpFetch(body) → POST /mcp (raw JSON-RPC passthrough)\n */\nimport { apiFetchRaw } from './client';\n\n/**\n * Call a tool on a specific connector via POST /api/connectors/:id/call.\n *\n * NOTE: intentionally bypasses the /mcp proxy (which routes to adas-mcp).\n * adas-mcp only knows skill-generated tools, NOT raw connector tools like\n * triggers.list — the direct connector API is the reliable path.\n */\nexport async function connectorCall(\n connectorId: string,\n tool: string,\n args: Record<string, any> = {},\n): Promise<{ ok: boolean; result: any; error?: string }> {\n try {\n const res = await apiFetchRaw(\n `/api/connectors/${encodeURIComponent(connectorId)}/call`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool, args }),\n },\n );\n\n if (!res.ok) {\n const text = await res.text();\n return { ok: false, result: null, error: `HTTP ${res.status}: ${text}` };\n }\n\n const data = await res.json();\n // Normalize: Core may return { ok, result } or raw MCP { content: [...] }\n if (data.ok !== undefined) return data;\n return { ok: true, result: data };\n } catch (err) {\n return { ok: false, result: null, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/** Raw JSON-RPC passthrough to /mcp. Returns the full JSON-RPC response. */\nexport async function mcpFetch(body: any): Promise<any> {\n const res = await apiFetchRaw('/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: typeof body === 'string' ? body : JSON.stringify(body),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`MCP fetch failed: HTTP ${res.status}: ${text}`);\n }\n\n return res.json();\n}\n\n/** JSON-RPC tools/call to /mcp (for core tools like cp.fe_api). */\nexport async function mcpToolCall(\n toolName: string,\n args: Record<string, any> = {},\n): Promise<any> {\n return mcpFetch({\n jsonrpc: '2.0',\n id: Date.now(),\n method: 'tools/call',\n params: { name: toolName, arguments: args },\n });\n}\n\n/** Post a plugin command result back to Core. */\nexport async function postCommandResult(\n correlationId: string,\n result: any,\n error?: string,\n): Promise<void> {\n await apiFetchRaw('/api/plugin-command-result', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ correlationId, result, error }),\n });\n}\n\n/**\n * Unwrap MCP JSON-RPC text content → parsed business data.\n * Server returns: { content: [{ type: \"text\", text: \"{...}\" }] }\n */\nexport function unwrapMcpResult(result: any): any {\n if (!result) return result;\n if (!result.content) return result;\n const textItem = Array.isArray(result.content)\n ? result.content.find((c: any) => c.type === 'text')\n : null;\n if (!textItem?.text) return result;\n try {\n return JSON.parse(textItem.text);\n } catch {\n return textItem.text;\n }\n}\n","/**\n * Chat store — talks to the ADAS Core API.\n *\n * Flow:\n * 1. loadConversation() → GET /api/conversation → display history\n * 2. sendMessage(text) → POST /api/chat { goal } → returns jobId\n * 3. WebSocket (poll fallback) → real-time progress\n * 4. When done → GET /api/conversation → formatted response\n *\n * Platform notes: no Expo/AsyncStorage imports. Attachment persistence is\n * delegated to the host via config.attachmentCache; identity and tokens come\n * from the host via initAdas().\n */\nimport { create } from 'zustand';\nimport { getCoreApiUrl, getCoreWsUrl, getToken, getTenant, getUser, getConfig } from '../config';\nimport { pluginCommandEmitter } from '../utils/emitter';\nimport type { OutgoingAttachment } from '../storage/types';\nimport type { Message, MessageAttachment, JobProgress, UIAction } from './types';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ChatState {\n messages: Message[];\n loading: boolean;\n error: string | null;\n activeJobId: string | null;\n conversationLoaded: boolean;\n /** Load conversation history from Core */\n loadConversation: () => Promise<void>;\n /** Send a message via POST /api/chat — creates a job, streams progress */\n sendMessage: (text: string, skillSlug?: string, attachments?: OutgoingAttachment[]) => Promise<void>;\n /** Respond to a paused sys.askUser question */\n respondToQuestion: (jobId: string, inputId: string, answer: string) => Promise<void>;\n /** Update in-flight job progress (called by the stream handler) */\n updateJobProgress: (jobId: string, progress: Partial<JobProgress>) => void;\n /** Reset chat (also re-fetches history on next mount — used on auth switch) */\n clearChat: () => void;\n /** Start a fresh empty chat without re-fetching history */\n newChat: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction coreHeaders(): Record<string, string> {\n const token = getToken();\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (token) headers['Authorization'] = `Bearer ${token}`;\n return headers;\n}\n\nfunction isTerminalStatus(status?: unknown): boolean {\n const s = typeof status === 'string' ? status.toLowerCase() : '';\n return s === 'done' || s === 'error' || s === 'failed' || s === 'completed';\n}\n\nfunction normalizeJobStatus(snap: any): JobProgress['status'] {\n const status = typeof snap?.status === 'string' ? snap.status.toLowerCase() : '';\n if (status === 'done' || status === 'completed') return 'done';\n if (status === 'error' || status === 'failed') return 'error';\n if (status === 'paused' || status === 'waiting') return 'paused';\n if (status === 'unknown') return 'unknown';\n return 'running';\n}\n\nfunction extractPendingQuestion(snap: any): any {\n return snap?.pendingQuestion || snap?.state?.pendingQuestion || snap?.state?.waiting || null;\n}\n\nfunction extractActorId(snap: any): string | undefined {\n const actorId =\n snap?.actorId ||\n snap?.actor?.actorId ||\n snap?.actor?.id ||\n snap?.state?.actorId ||\n snap?.state?.actor?.actorId ||\n snap?.state?.actor?.id;\n return typeof actorId === 'string' && actorId.length > 0 ? actorId : undefined;\n}\n\nfunction extractLiveProgress(snap: any): JobProgress['liveProgress'] | undefined {\n const lp = snap?.liveProgress || snap?.state?.__live_progress;\n const latest = Array.isArray(lp) ? lp[lp.length - 1] : lp;\n if (!latest?.message) return undefined;\n return {\n message: String(latest.message || ''),\n ...(latest.step != null ? { step: latest.step } : {}),\n ...(latest.total != null ? { total: latest.total } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Extract the most-recently-called tool from job exec steps.\n// snap.state.steps.__exec = { iter_0: [{tool, ok, reason}], iter_1: [...] }\n// ---------------------------------------------------------------------------\nfunction extractCurrentTool(state: any): string | undefined {\n const exec = state?.steps?.__exec;\n if (!exec || typeof exec !== 'object') return undefined;\n const latest = Object.keys(exec)\n .map(k => ({ k, n: parseInt(k.replace('iter_', ''), 10) }))\n .filter(({ n }) => !isNaN(n))\n .sort((a, b) => b.n - a.n)[0];\n if (!latest) return undefined;\n const steps = exec[latest.k];\n if (!Array.isArray(steps) || !steps.length) return undefined;\n const last = steps[steps.length - 1];\n return (last?.tool || last?.phase) as string | undefined;\n}\n\nfunction snapshotToProgress(snap: any, rootJobId: string): Partial<JobProgress> {\n const pq = extractPendingQuestion(snap);\n const progress: Partial<JobProgress> = {\n jobId: rootJobId,\n actorId: extractActorId(snap),\n status: pq ? 'paused' : normalizeJobStatus(snap),\n subStatus: snap?.subStatus || snap?.phase || snap?.state?.visual?.phase,\n phase: snap?.phase || snap?.state?.visual?.phase,\n iteration: snap?.iteration || snap?.state?.plannerIter,\n skillSlug: snap?.skillSlug || snap?.activeSkill,\n currentTool: snap?.currentTool || snap?.lastTool || extractCurrentTool(snap?.state),\n };\n\n const liveProgress = extractLiveProgress(snap);\n if (liveProgress) progress.liveProgress = liveProgress;\n\n // Human-language status (additive; absent when disabled/uncached).\n if (typeof snap?.humanStatus === 'string' && snap.humanStatus) progress.humanStatus = snap.humanStatus;\n if (snap?.humanLabels && typeof snap.humanLabels === 'object') progress.humanLabels = snap.humanLabels;\n\n if (pq) {\n progress.pendingQuestion = {\n inputId: pq.correlation_id || pq.correlationId || pq.inputId || '',\n question: pq.prompt_message || pq.question || 'The assistant needs your input',\n inputType: pq.inputType || 'text',\n options: pq.options || pq.requested_fields,\n placeholder: pq.placeholder,\n };\n }\n\n return progress;\n}\n\nfunction isTerminalSnapshot(snap: any): boolean {\n if (extractPendingQuestion(snap)) return false;\n return snap?.done === true || isTerminalStatus(snap?.status);\n}\n\n/**\n * Sentinel delimiters used to embed structured table data inside a flat\n * message string. UI layers split on these and render the contents with a\n * native table component instead of markdown tables — markdown tables look\n * terrible on narrow phone screens.\n *\n * Unicode Private Use Area chars (U+E100/U+E101) so they never collide with\n * anything the model could legitimately emit.\n */\nexport const TABLE_BLOCK_OPEN = '\\uE100';\nexport const TABLE_BLOCK_CLOSE = '\\uE101';\n\n/**\n * Render a `{ columns: [...], rows: [...] }` payload as a sentinel-wrapped\n * JSON marker. Returns null if the shape doesn't match.\n */\nfunction renderTableShape(content: any): string | null {\n if (!content || typeof content !== 'object') return null;\n const cols = Array.isArray(content.columns) ? content.columns : null;\n const rows = Array.isArray(content.rows) ? content.rows : null;\n if (!cols || !rows) return null;\n // encodeURIComponent so the JSON can never contain newlines or sentinel chars.\n const payload = encodeURIComponent(JSON.stringify({ columns: cols, rows }));\n return `${TABLE_BLOCK_OPEN}${payload}${TABLE_BLOCK_CLOSE}`;\n}\n\n/**\n * Extract display text from a conversation turn's assistant blocks.\n * Handles multiple block kinds (text, code, json, markdown, table, html).\n */\nexport function blocksToText(blocks?: Array<{ kind: string; content: any }>): string {\n if (!blocks || blocks.length === 0) return '';\n return blocks.map(b => {\n if (b.kind === 'text' || b.kind === 'markdown' || b.kind === 'description') {\n return typeof b.content === 'string' ? b.content : '';\n }\n if (b.kind === 'code') {\n const code = typeof b.content === 'object' ? b.content.content : b.content;\n return `\\`\\`\\`\\n${code}\\n\\`\\`\\``;\n }\n if (b.kind === 'table' && b.content && typeof b.content === 'object') {\n const md = renderTableShape(b.content);\n if (md) return md;\n // Fall through to generic JSON rendering if shape is unexpected.\n }\n if (b.kind === 'json') {\n // Skip pendingQuestion state objects — internal sys.askUser data\n if (b.content && typeof b.content === 'object' && 'pendingQuestion' in b.content) return '';\n // Polisher sometimes wraps tables as kind:'json' when the content has\n // columns/rows — render those as table blocks too.\n const md = renderTableShape(b.content);\n if (md) return md;\n return '```json\\n' + JSON.stringify(b.content, null, 2) + '\\n```';\n }\n if (b.kind === 'html') {\n return typeof b.content === 'string' ? b.content : '';\n }\n return typeof b.content === 'string' ? b.content : JSON.stringify(b.content);\n }).filter(Boolean).join('\\n\\n');\n}\n\n/** Extract image/file attachments from conversation blocks */\nfunction blocksToAttachments(blocks?: Array<{ kind: string; hash?: string; url?: string; mimeType?: string; name?: string }>): MessageAttachment[] | undefined {\n if (!blocks || blocks.length === 0) return undefined;\n const atts: MessageAttachment[] = [];\n for (const b of blocks) {\n if ((b.kind === 'image' || b.kind === 'file') && (b.url || b.hash)) {\n atts.push({\n mimeType: b.mimeType || (b.kind === 'image' ? 'image/jpeg' : 'application/octet-stream'),\n name: b.name || 'attachment',\n previewUri: b.url ? `${getCoreApiUrl()}${b.url}` : undefined,\n });\n }\n }\n return atts.length > 0 ? atts : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\n\nexport const useChatStore = create<ChatState>((set, get) => ({\n messages: [],\n loading: false,\n error: null,\n activeJobId: null,\n conversationLoaded: false,\n\n // -----------------------------------------------------------------------\n // Load conversation history from Core\n // GET /api/conversation → array of turns [{user, assistant, jobId, ...}]\n // -----------------------------------------------------------------------\n loadConversation: async () => {\n try {\n const attachmentCache = getConfig().attachmentCache;\n await attachmentCache?.ready();\n\n const res = await fetch(`${getCoreApiUrl()}/api/conversation?limit=20`, {\n headers: coreHeaders(),\n });\n if (!res.ok) {\n console.warn('[adas-chat] Failed to load conversation:', res.status);\n set({ conversationLoaded: true });\n return;\n }\n\n const data = await res.json();\n if (!data.ok || !data.items) {\n set({ conversationLoaded: true });\n return;\n }\n\n // Persisted turns from /api/conversation are the SOLE source of history.\n // Live job state is mirrored only via WS into the placeholder bubble\n // created by sendMessage; in-flight local state is preserved below.\n const items: any[] = [...data.items].reverse();\n const persistedMessages: Message[] = [];\n const seenJobIds = new Set<string>();\n for (const turn of items) {\n // Deduplicate by jobId (chain jobs can produce duplicate turns)\n if (turn.jobId && seenJobIds.has(turn.jobId)) continue;\n if (turn.jobId) seenJobIds.add(turn.jobId);\n\n // User message\n const userText = blocksToText(turn.user?.blocks);\n let userAtts = blocksToAttachments(turn.user?.blocks);\n // Merge locally cached attachments if API doesn't have them\n if (!userAtts && turn.jobId) {\n userAtts = attachmentCache?.get(turn.jobId);\n }\n const turnChainId = typeof turn.chainId === 'string' ? turn.chainId : undefined;\n if (userText || userAtts) {\n persistedMessages.push({\n id: `user-${turn.jobId}`,\n role: 'user',\n content: userText || '',\n timestamp: new Date(turn.startedAt || Date.now()),\n skillSlug: turn.skillSlug,\n ...(userAtts ? { attachments: userAtts } : {}),\n ...(turnChainId ? { chainId: turnChainId } : {}),\n });\n }\n // Assistant response\n const assistantText = blocksToText(turn.assistant?.blocks);\n const assistantAtts = blocksToAttachments(turn.assistant?.blocks);\n const assistantActions = Array.isArray(turn.assistant?.actions) ? turn.assistant.actions : undefined;\n const turnKind = typeof turn.kind === 'string' ? turn.kind : undefined;\n if (assistantText || assistantAtts || assistantActions?.length) {\n persistedMessages.push({\n id: `bot-${turn.jobId}`,\n role: 'assistant',\n content: assistantText || '',\n timestamp: new Date(turn.finishedAt || turn.startedAt || Date.now()),\n skillSlug: turn.skillSlug,\n ...(assistantAtts ? { attachments: assistantAtts } : {}),\n ...(assistantActions?.length ? { actions: assistantActions } : {}),\n ...(turnChainId ? { chainId: turnChainId } : {}),\n ...(turnKind ? { kind: turnKind } : {}),\n });\n }\n }\n\n // Preserve in-flight LOCAL state across pull-to-refresh. /api/conversation\n // is the truth for HISTORY; anything mid-flight lives only as a local\n // WS-driven placeholder created by sendMessage.\n const current = get().messages;\n const keptPlaceholders: Message[] = [];\n for (const m of current) {\n if (!m.id.startsWith('job-') || !m.jobProgress || !m.chainId) continue;\n const matchIdx = persistedMessages.findIndex(pm =>\n pm.role === 'assistant' && pm.chainId === m.chainId\n );\n if (matchIdx >= 0) {\n // The persisted turn for this chain has arrived. Move the live\n // progress overlay (pill) onto it — but only while still in flight.\n const st = m.jobProgress.status;\n if (st === 'running' || st === 'paused') {\n persistedMessages[matchIdx] = { ...persistedMessages[matchIdx], jobProgress: m.jobProgress };\n }\n // Drop the placeholder either way.\n } else {\n // No persisted turn yet — chain still in flight. Keep it.\n keptPlaceholders.push(m);\n }\n }\n\n // Optimistic user bubbles (id=`user-<ms>` from sendMessage). Keep until\n // a persisted user turn arrives. Dedup by chainId — content match has\n // false positives (\"Yes\", \"Continue\", etc.).\n const isLocalUserId = (id: string) => /^user-\\d+$/.test(id);\n const keptUserBubbles = current.filter(m => {\n if (m.role !== 'user' || !isLocalUserId(m.id)) return false;\n if (!m.chainId) return true; // POST in flight — can't dedup yet\n return !persistedMessages.some(pm =>\n pm.role === 'user' && pm.chainId === m.chainId\n );\n });\n\n const finalMessages = [...persistedMessages, ...keptUserBubbles, ...keptPlaceholders];\n finalMessages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n\n let firstRunning: Message | undefined = keptPlaceholders.find(m => m.jobProgress?.status === 'running');\n\n // Cold-start / post-refresh reattach: WS subscriptions die on app\n // restart. Fetch ALL active chains for this actor (chain-native SlimChain\n // API) and reattach EACH — multiple concurrent chains must all come back\n // in progress, not just the most-recently-updated one. Falls back to the\n // legacy single-chain /api/chain/current on older backends.\n try {\n let activeChains: any[] = [];\n const chainsRes = await fetch(`${getCoreApiUrl()}/api/chains/active`, {\n headers: coreHeaders(),\n });\n if (chainsRes.ok) {\n const body = await chainsRes.json();\n activeChains = Array.isArray(body?.chains) ? body.chains : [];\n } else {\n // Legacy backend without the plural endpoint — single most-recent chain.\n const legacy = await fetch(`${getCoreApiUrl()}/api/chain/current`, {\n headers: coreHeaders(),\n });\n if (legacy.ok) {\n const lb = await legacy.json();\n if (lb?.data?.id) activeChains = [lb.data];\n }\n }\n\n for (const slim of activeChains) {\n if (!slim?.id) continue;\n const chainId = String(slim.id);\n const alreadyTracked = finalMessages.some(m =>\n m.role === 'assistant' && m.jobProgress?.jobId === chainId\n );\n if (alreadyTracked) continue;\n\n // Chain-native status: prefer the whole-chain aggregate (chainStatus)\n // over the active job's per-job status, so e.g. a chain still running\n // across a handoff isn't shown as \"done\". A pending question still\n // overrides to \"paused\" inside snapshotToProgress.\n const progress = snapshotToProgress(\n { ...slim, status: slim.chainStatus || slim.status },\n chainId,\n );\n const chainCreatedAt = typeof slim.createdAt === 'number'\n ? slim.createdAt\n : (typeof slim.lastUpdate === 'number' ? slim.lastUpdate : Date.now());\n const chainLastUpdate = typeof slim.lastUpdate === 'number' ? slim.lastUpdate : chainCreatedAt;\n const jobProgress = {\n jobId: chainId,\n actorId: extractActorId(slim),\n status: 'running',\n chainStartedAt: chainCreatedAt,\n ...progress,\n } as JobProgress;\n\n // Synthesize the user bubble if a hard refresh wiped the optimistic\n // one and the chain hasn't persisted its turn yet.\n const goal = typeof slim.goal === 'string' ? slim.goal : '';\n const userExists = finalMessages.some(m =>\n m.role === 'user' && (m.chainId === chainId || (goal && m.content === goal))\n );\n if (goal && !userExists) {\n finalMessages.push({\n id: `user-${chainId}`,\n role: 'user',\n content: goal,\n timestamp: new Date(chainCreatedAt),\n chainId,\n });\n }\n\n // Assistant side: attach to matching persisted turn if one exists;\n // otherwise push a placeholder bubble.\n let matchIdx = -1;\n for (let i = finalMessages.length - 1; i >= 0; i--) {\n const m = finalMessages[i];\n if (m.role === 'assistant' && m.chainId === chainId) {\n matchIdx = i;\n break;\n }\n }\n if (matchIdx >= 0) {\n finalMessages[matchIdx] = { ...finalMessages[matchIdx], jobProgress };\n if (jobProgress.status === 'running' && !firstRunning) firstRunning = finalMessages[matchIdx];\n } else {\n const reattachBubble: Message = {\n id: `job-${chainId}`,\n role: 'assistant',\n content: 'Working on it...',\n timestamp: new Date(chainLastUpdate),\n jobProgress,\n chainId,\n };\n finalMessages.push(reattachBubble);\n if (jobProgress.status === 'running' && !firstRunning) firstRunning = reattachBubble;\n }\n\n // Re-open the live subscription for this chain.\n streamJob(chainId, getTenant(), getToken());\n }\n\n finalMessages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n } catch {}\n\n set({\n messages: finalMessages,\n conversationLoaded: true,\n error: null,\n activeJobId: firstRunning?.jobProgress?.jobId || null,\n loading: !!firstRunning,\n });\n } catch (err: any) {\n console.warn('[adas-chat] Error loading conversation:', err.message);\n set({ conversationLoaded: true });\n }\n },\n\n // -----------------------------------------------------------------------\n // Send message via Core API\n // POST /api/chat { goal } → { jobId } → stream → fetch turn result\n // -----------------------------------------------------------------------\n sendMessage: async (text: string, skillSlug?: string, attachments?: OutgoingAttachment[]) => {\n // No `if (loading) return` guard: Chain Additions needs the user to send\n // WHILE a chain is running. The backend router decides attach/cancel/new.\n\n const userMsg: Message = {\n id: `user-${Date.now()}`,\n role: 'user',\n content: text,\n timestamp: new Date(),\n ...(attachments?.length ? {\n attachments: attachments.map(a => ({\n mimeType: a.mimeType,\n name: a.name,\n previewUri: a.mimeType.startsWith('image/') ? `data:${a.mimeType};base64,${a.data}` : undefined,\n }))\n } : {}),\n };\n\n set(s => ({ messages: [...s.messages, userMsg], loading: true, error: null }));\n\n try {\n // Backend auto-resolves the skill via conversation continuity → channel\n // routing → default. triggerContext.channel + replyContext.chatId are\n // required by handoff-controller-mcp's schema — without them handoffs\n // fail silently.\n const actor = getUser();\n const body: Record<string, unknown> = {\n goal: text,\n // Opt in to the Chain Additions router (attach/cancel/new while a\n // chain runs). Backend ignores it where not applicable — safe to send.\n chainRouting: true,\n triggerContext: {\n channel: 'mobile',\n replyContext: { chatId: actor?.actorId || 'unknown' },\n },\n };\n if (skillSlug) body.skillSlug = skillSlug;\n if (attachments?.length) body.attachments = attachments;\n\n const res = await fetch(`${getCoreApiUrl()}/api/chat`, {\n method: 'POST',\n headers: coreHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n let errMsg = `Server error (${res.status})`;\n try {\n const text = await res.text();\n // Don't show raw HTML — extract a short message\n if (text.startsWith('<') || text.startsWith('<!')) {\n errMsg = res.status === 502 ? 'Server is temporarily unavailable. Please try again.' : `Server error (${res.status})`;\n } else {\n const parsed = JSON.parse(text);\n errMsg = parsed.error || errMsg;\n }\n } catch {}\n throw new Error(errMsg);\n }\n\n const data = await res.json();\n\n if (!data.ok) {\n throw new Error(data.error || 'Failed to send message');\n }\n\n // Chain Additions: the router may ATTACH this message to the running\n // chain or CANCEL it. These replies carry NO jobId — handle them and\n // don't start a second stream.\n if (data.mode === 'chain_addition' || data.mode === 'chain_cancel') {\n const ack = data.mode === 'chain_addition'\n ? (data.ack || 'Got it — added to the running task.')\n : 'Stopping the task…';\n set(s => ({\n messages: s.messages\n .map(m => (m.id === userMsg.id && data.chainId) ? { ...m, chainId: data.chainId } : m)\n .concat({\n id: `ack-${Date.now()}`,\n role: 'assistant',\n content: ack,\n timestamp: new Date(),\n ...(data.chainId ? { chainId: data.chainId } : {}),\n }),\n }));\n return;\n }\n\n const jobId = data.id || data.jobId;\n if (!jobId) {\n throw new Error('No job ID returned');\n }\n\n // Cache attachments so they survive loadConversation reload. Awaited\n // intentionally — fire-and-forget can lose the write on quick reload.\n if (attachments?.length) {\n await getConfig().attachmentCache?.save(jobId, attachments);\n }\n\n // Placeholder assistant bubble = live mirror of the active chain.\n // Carries chainId so a subsequent loadConversation refresh can adopt\n // this placeholder's progress. For the root job, chainId == jobId.\n const progressMsg: Message = {\n id: `job-${jobId}`,\n role: 'assistant',\n content: 'Working on it...',\n timestamp: new Date(),\n jobProgress: {\n jobId,\n actorId: actor?.actorId,\n status: 'running',\n subStatus: 'Starting...',\n chainStartedAt: Date.now(),\n },\n chainId: jobId,\n };\n\n // Attach chainId to the optimistic user bubble so loadConversation can\n // dedup against persisted user turns by chainId.\n set(s => ({\n messages: s.messages.map(m =>\n m.id === userMsg.id ? { ...m, chainId: jobId } : m\n ).concat(progressMsg),\n activeJobId: jobId,\n }));\n\n // Start streaming for real-time progress\n streamJob(jobId, getTenant(), getToken());\n } catch (err: any) {\n set(s => ({\n messages: [...s.messages, {\n id: `error-${Date.now()}`,\n role: 'system' as const,\n content: `Error: ${err.message}`,\n timestamp: new Date(),\n }],\n loading: false,\n }));\n }\n },\n\n // -----------------------------------------------------------------------\n // Respond to sys.askUser paused question\n // -----------------------------------------------------------------------\n respondToQuestion: async (jobId: string, inputId: string, answer: string) => {\n try {\n const res = await fetch(`${getCoreApiUrl()}/api/job/${jobId}/respond`, {\n method: 'POST',\n headers: coreHeaders(),\n body: JSON.stringify({ inputId, answer }),\n });\n const data = await res.json();\n if (!data.ok) {\n console.warn('[adas-chat] Failed to respond to question:', data.error);\n }\n } catch (err: any) {\n console.warn('[adas-chat] Error responding to question:', err.message);\n }\n },\n\n // -----------------------------------------------------------------------\n // Update job progress (called by the stream handler)\n // -----------------------------------------------------------------------\n updateJobProgress: (jobId: string, progress: Partial<JobProgress>) => {\n set(s => ({\n messages: s.messages.map(m => {\n if (m.jobProgress?.jobId === jobId) {\n const updated = { ...m.jobProgress, ...progress };\n // Clear pendingQuestion when status is no longer paused\n if (progress.status && progress.status !== 'paused') {\n updated.pendingQuestion = undefined;\n }\n // Persisted turns (id `bot-…`) own their content/actions from\n // /api/conversation — the live mirror must never overwrite them.\n const isPersisted = m.id.startsWith('bot-');\n const content = isPersisted\n ? m.content\n : (progress.resultMessage\n || progress.pendingQuestion?.question\n || m.content);\n const actions = isPersisted\n ? m.actions\n : (progress.resultActions?.length ? progress.resultActions : m.actions);\n return {\n ...m,\n jobProgress: updated as JobProgress,\n content,\n ...(actions ? { actions } : {}),\n };\n }\n return m;\n }),\n loading: (progress.status === 'done' || progress.status === 'error' || progress.status === 'paused')\n ? false\n : s.loading,\n activeJobId: (progress.status === 'done' || progress.status === 'error' || progress.status === 'paused')\n ? null\n : s.activeJobId,\n }));\n },\n\n clearChat: () => {\n set({\n messages: [],\n loading: false,\n error: null,\n activeJobId: null,\n conversationLoaded: false,\n });\n },\n newChat: () => {\n set({\n messages: [],\n loading: false,\n error: null,\n activeJobId: null,\n conversationLoaded: true,\n });\n },\n}));\n\n// ---------------------------------------------------------------------------\n// WebSocket Streaming — persistent connection, reused across jobs\n// ---------------------------------------------------------------------------\n\n// Track processed plugin command correlationIds to avoid duplicates\nconst _processedPluginCmds = new Set<string>();\n\nfunction dispatchPluginCommands(cmds: any[]) {\n for (const cmd of cmds) {\n const corrId = cmd?.correlationId || cmd?.correlation_id;\n if (corrId && _processedPluginCmds.has(corrId)) continue;\n if (corrId) _processedPluginCmds.add(corrId);\n\n pluginCommandEmitter.emit('plugin-command', cmd);\n const pluginId = cmd?.pluginId || cmd?.plugin_id || cmd?.args?.plugin_id;\n if (pluginId) {\n const props = cmd?.props ?? cmd?.args?.props ?? undefined;\n pluginCommandEmitter.emit('focus-plugin', { pluginId, props });\n }\n }\n}\n\n// Persistent WS connection — stays open across jobs\nlet _ws: WebSocket | null = null;\nlet _wsReady = false;\nlet _currentJobId: string | null = null;\n\nfunction ensureWs(tenant: string, token: string | null): WebSocket {\n if (_ws && _wsReady) return _ws;\n\n const wsUrl = `${getCoreWsUrl()}/ws?token=${encodeURIComponent(token || '')}&tenant=${encodeURIComponent(tenant)}`;\n const ws = new WebSocket(wsUrl);\n _ws = ws;\n _wsReady = false;\n\n ws.onopen = () => {\n _wsReady = true;\n // If a job is waiting for the connection, subscribe now\n if (_currentJobId) {\n ws.send(JSON.stringify({ type: 'subscribe', jobId: _currentJobId }));\n }\n };\n\n ws.onmessage = (ev) => {\n try {\n const msg = JSON.parse(typeof ev.data === 'string' ? ev.data : '');\n const { event, data } = msg;\n const { updateJobProgress } = useChatStore.getState();\n // Route by the event's OWN chain id — the server streams ALL of the\n // user's active chains down one connection, so each event updates its\n // own bubble. Fall back to the last-subscribed job for older backends.\n const jobId = (data && (data.id || data.chainId)) || _currentJobId;\n\n // Always process plugin_command events even when _currentJobId is null\n // (e.g., during handoff relay)\n if (event === 'plugin_command') {\n dispatchPluginCommands([data]);\n return;\n }\n if (event === 'plugin-command-ack' || event === 'pong') return;\n\n if (!jobId) return;\n\n switch (event) {\n case 'init':\n case 'job':\n case 'update': {\n const snap = data;\n const progress = snapshotToProgress(snap, jobId);\n\n if (isTerminalSnapshot(snap)) {\n // Handoff chain: root job finished but relay job is still running.\n // The backend broadcasts relay progress as synthetic updates on\n // this same subscription — stay subscribed and show running.\n if (snap.status === 'done' && (snap.isHandoff || snap.state?.handoffTransfer)) {\n updateJobProgress(jobId, { status: 'running' });\n return;\n }\n _currentJobId = null;\n if (progress.status === 'paused' && progress.pendingQuestion) {\n updateJobProgress(jobId, progress);\n } else {\n fetchTurnResult(jobId, snap);\n }\n return;\n }\n\n updateJobProgress(jobId, progress);\n break;\n }\n case 'chain_final':\n // Authoritative chain-termination event (fires once when the WHOLE\n // chain is done — handoff-forgiven). Preferred over per-job `final`.\n _currentJobId = null;\n fetchTurnResult(jobId, data);\n break;\n case 'final':\n _currentJobId = null;\n fetchTurnResult(jobId, data);\n break;\n }\n } catch (err) {\n console.warn('[adas-chat] WS parse error:', err);\n }\n };\n\n ws.onerror = () => {\n _ws = null;\n _wsReady = false;\n // Fall back to polling for current job\n if (_currentJobId) {\n const jid = _currentJobId;\n _currentJobId = null;\n pollJob(jid, token);\n }\n };\n\n ws.onclose = () => {\n _ws = null;\n _wsReady = false;\n if (_currentJobId) {\n const jid = _currentJobId;\n _currentJobId = null;\n pollJob(jid, token);\n }\n };\n\n return ws;\n}\n\nfunction streamJob(jobId: string, tenant: string, token: string | null) {\n _currentJobId = jobId;\n const ws = ensureWs(tenant, token);\n\n // If WS is already open, subscribe immediately; otherwise onopen handles it\n if (_wsReady) {\n ws.send(JSON.stringify({ type: 'subscribe', jobId }));\n }\n}\n\n/** Tear down the live connection (env/auth switch, SDK unmount). */\nexport function closeChatStream(): void {\n _currentJobId = null;\n if (_ws) {\n try { _ws.close(); } catch {}\n }\n _ws = null;\n _wsReady = false;\n}\n\n/**\n * When a job completes, fetch the conversation turn to get the formatted\n * response. Falls back to extracting from the job snapshot.\n */\nasync function fetchTurnResult(jobId: string, jobSnap: any) {\n // Clean up dedup set (cap to prevent unbounded growth)\n if (_processedPluginCmds.size > 200) _processedPluginCmds.clear();\n const { updateJobProgress } = useChatStore.getState();\n const status = normalizeJobStatus(jobSnap) === 'error' ? 'error' : 'done';\n\n // Handoff chain: if this job handed off, wait for the chain to settle by\n // polling job status — done:true only when the relay job completes.\n if (jobSnap.isHandoff || jobSnap.state?.handoffTransfer || jobSnap.result?.contentType === 'handoff') {\n try {\n for (let i = 0; i < 40; i++) { // up to ~60s\n const statusRes = await fetch(`${getCoreApiUrl()}/api/job/${jobId}/status`, {\n headers: coreHeaders(),\n });\n if (statusRes.ok) {\n const statusData = await statusRes.json();\n if (statusData.done && !statusData.isHandoff) {\n break;\n }\n updateJobProgress(jobId, { status: 'running' });\n }\n await new Promise(r => setTimeout(r, 1500));\n }\n } catch {}\n }\n\n // Fetch the most recent conversation turn. By actor rather than by jobId,\n // because handoff chains create child jobs — the real reply lives on the\n // LAST child, not on the root job we submitted.\n for (let attempt = 0; attempt < 5; attempt++) {\n try {\n const res = await fetch(`${getCoreApiUrl()}/api/conversation?limit=1`, {\n headers: coreHeaders(),\n });\n\n if (res.ok) {\n const data = await res.json();\n const items = Array.isArray(data.items) ? data.items : [];\n const turn = items[0];\n if (turn?.assistant || turn?.turn?.assistant) {\n const assistant = turn.assistant || turn.turn?.assistant;\n const text = blocksToText(assistant.blocks);\n const actions: UIAction[] | undefined =\n Array.isArray(assistant.actions) && assistant.actions.length\n ? assistant.actions\n : undefined;\n if (text) {\n updateJobProgress(jobId, {\n status,\n resultMessage: text,\n ...(actions ? { resultActions: actions } : {}),\n });\n return;\n }\n }\n }\n } catch {}\n await new Promise(r => setTimeout(r, 800));\n }\n\n // Fallback: extract from job snapshot\n const fallback =\n jobSnap.result?.message ||\n jobSnap.state?.finalReply ||\n (status === 'error' ? 'Something went wrong. Please try again.' : 'Done.');\n\n updateJobProgress(jobId, { status, resultMessage: fallback });\n}\n\n// ---------------------------------------------------------------------------\n// Polling fallback (when WS is unavailable)\n// ---------------------------------------------------------------------------\n\nasync function pollJob(jobId: string, token: string | null) {\n const { updateJobProgress } = useChatStore.getState();\n\n for (let i = 0; i < 120; i++) {\n try {\n const res = await fetch(`${getCoreApiUrl()}/api/job/${jobId}/status`, {\n headers: {\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n });\n\n if (!res.ok) {\n if (res.status === 404) return;\n continue;\n }\n\n const snap = await res.json();\n const progress = snapshotToProgress(snap, jobId);\n\n // sys.askUser — same logic as the WS handler\n if (progress.status === 'paused' && progress.pendingQuestion) {\n updateJobProgress(jobId, progress);\n return; // Stop polling — waiting for user input\n }\n\n updateJobProgress(jobId, progress);\n\n if (isTerminalSnapshot(snap)) {\n fetchTurnResult(jobId, snap);\n return;\n }\n } catch {}\n\n await new Promise(r => setTimeout(r, 1500));\n }\n\n // Timeout\n updateJobProgress(jobId, {\n status: 'error',\n resultMessage: 'Job timed out. Please try again.',\n });\n}\n","/**\n * Lightweight event emitter bridging the chat job stream → plugin bridges\n * (React Native has no Node 'events' module).\n *\n * Events: 'plugin-command' (raw command), 'focus-plugin' ({ pluginId, props }),\n * 'plugin-close' ({ pluginId }), 'prepare-chat-message' ({ text }).\n */\n\ntype Listener = (data: any) => void;\n\nexport interface BufferedCommand {\n pluginId: string;\n command: string;\n args?: any;\n correlationId?: string;\n _bufferedAt: number;\n}\n\nconst RECENT_TTL_MS = 10000;\nconst RECENT_MAX = 20;\n\nexport class PluginCommandEmitter {\n private listeners = new Map<string, Set<Listener>>();\n // Ring buffer of plugin commands seen recently. Lets a plugin that mounts\n // AFTER its first command was emitted (e.g. a surface mounted by the\n // dispatcher in response to focus-plugin) still pick that command up via\n // `drainPluginCommands(pluginId)`. Self-cleans on TTL + size cap.\n private recent: BufferedCommand[] = [];\n\n on(event: string, fn: Listener): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n this.listeners.get(event)!.add(fn);\n return () => this.off(event, fn);\n }\n\n off(event: string, fn: Listener): void {\n this.listeners.get(event)?.delete(fn);\n }\n\n emit(event: string, data: any): void {\n if (event === 'plugin-command' && data && data.pluginId && data.command && data.command !== '__focus') {\n this.recent.push({\n pluginId: data.pluginId,\n command: data.command,\n args: data.args,\n correlationId: data.correlationId,\n _bufferedAt: Date.now(),\n });\n if (this.recent.length > RECENT_MAX) this.recent.shift();\n }\n this.listeners.get(event)?.forEach((fn) => {\n try { fn(data); } catch {}\n });\n }\n\n /** Pop and return any plugin-commands targeted at `pluginId` that were\n * emitted within the last RECENT_TTL_MS. Used by the native bridge on\n * mount so the surface-dispatcher path doesn't drop the first command. */\n drainPluginCommands(pluginId: string): BufferedCommand[] {\n const now = Date.now();\n const out: BufferedCommand[] = [];\n const remaining: BufferedCommand[] = [];\n for (const cmd of this.recent) {\n if (now - cmd._bufferedAt > RECENT_TTL_MS) continue; // expired, drop\n if (cmd.pluginId === pluginId) out.push(cmd);\n else remaining.push(cmd);\n }\n this.recent = remaining;\n return out;\n }\n}\n\n/** App-wide bus for plugin commands arriving over the chat stream. */\nexport const pluginCommandEmitter = new PluginCommandEmitter();\n","import { getConsumerAuthApiUrl, getToken, getConfig, type AdasSession } from '../config';\nimport { useChatStore, closeChatStream } from '../chat/store';\n\nexport interface TenantMembership {\n id: string;\n name: string;\n role: string | null;\n}\n\n/**\n * List the tenants the CURRENT user belongs to (GET /api/tenants/list).\n *\n * The list is membership-scoped: for consumer JWTs the backend returns ONLY\n * tenants where the user's login identity (google/apple oauth or embed id)\n * has an active actor; builder JWTs get their user-doc memberships. It never\n * leaks the full tenant list. Returns [] when signed out or unknown.\n */\nexport async function listMyTenants(): Promise<TenantMembership[]> {\n const token = getToken();\n if (!token) return [];\n try {\n const res = await fetch(`${getConsumerAuthApiUrl()}/platform/consumer/my-tenants`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n const data = await res.json().catch(() => null);\n if (!res.ok || !data?.ok || !Array.isArray(data.tenants)) return [];\n return data.tenants.map((t: any) => ({\n id: t.id,\n name: t.name || t.id,\n role: t.role ?? null,\n }));\n } catch {\n return [];\n }\n}\n\n/**\n * Re-scope the whole session to another tenant the user already belongs to.\n *\n * The backend treats the JWT tenant claim as the sole source of truth, so\n * switching = minting a fresh JWT for the target tenant's actor. The SDK\n * owns the call (POST consumer-auth /platform/consumer/switch-tenant, authed\n * by the current token); the HOST persists the new session via\n * `config.onSession` (the SDK never stores credentials). The chat stream is\n * then torn down and cleared so it reconnects against the new tenant.\n *\n * Requires `consumerAuthUrl` and `onSession` in the initAdas() config.\n * Throws on any non-OK response (e.g. not a member of the target tenant).\n */\nexport async function switchTenant(targetTenantId: string): Promise<AdasSession> {\n const token = getToken();\n if (!token) throw new Error('[adas] switchTenant: not signed in');\n\n const res = await fetch(`${getConsumerAuthApiUrl()}/platform/consumer/switch-tenant`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ target_tenant: targetTenantId }),\n });\n\n const data = await res.json().catch(() => null);\n if (!res.ok || !data?.ok || !data.jwt) {\n throw new Error(data?.error || `switchTenant failed (${res.status})`);\n }\n\n const session: AdasSession = {\n jwt: data.jwt,\n tenant: data.tenant,\n actor: data.actor,\n };\n\n // Host persists the new token + active tenant BEFORE we reconnect, so the\n // fresh stream/requests pick up the target-tenant credentials.\n const onSession = getConfig().onSession;\n if (!onSession) {\n throw new Error('[adas] switchTenant: config.onSession is required to persist the new session');\n }\n await onSession(session);\n\n // Tear down the old-tenant stream and history; the chat screen reloads\n // against the new tenant on its next mount / loadConversation().\n closeChatStream();\n useChatStore.getState().clearChat();\n\n return session;\n}\n","// ADAS design tokens — shared by @ateam-ai-mobile/ui and host apps that want to match.\n\nexport const colors = {\n dark: {\n bgPrimary: '#0a0e14',\n bgSecondary: '#111820',\n bgTertiary: '#1a2230',\n bgInput: '#0d1219',\n bgHover: '#1e2a3a',\n border: 'rgba(255, 255, 255, 0.08)',\n borderHover: 'rgba(255, 255, 255, 0.15)',\n textPrimary: '#e8ecf1',\n textSecondary: '#8b95a5',\n textMuted: '#5a6577',\n accent: '#2563eb',\n accentHover: '#3b82f6',\n accentSoft: 'rgba(37, 99, 235, 0.15)',\n green: '#16a34a',\n greenSoft: 'rgba(22, 163, 74, 0.15)',\n red: '#dc2626',\n redSoft: 'rgba(220, 38, 38, 0.15)',\n amber: '#f59e0b',\n amberSoft: 'rgba(245, 158, 11, 0.15)',\n purple: '#8b5cf6',\n purpleSoft: 'rgba(139, 92, 246, 0.15)',\n // Message-specific\n userBubble: '#2563eb',\n botBubble: '#1a2230',\n botBubbleBorder: 'rgba(255, 255, 255, 0.08)',\n },\n light: {\n bgPrimary: '#ffffff',\n bgSecondary: '#f8f9fa',\n bgTertiary: '#f1f3f5',\n bgInput: '#ffffff',\n bgHover: '#e9ecef',\n border: 'rgba(0, 0, 0, 0.08)',\n borderHover: 'rgba(0, 0, 0, 0.15)',\n textPrimary: '#1a1a2e',\n textSecondary: '#6b7280',\n textMuted: '#9ca3af',\n accent: '#2563eb',\n accentHover: '#1d4ed8',\n accentSoft: 'rgba(37, 99, 235, 0.1)',\n green: '#16a34a',\n greenSoft: 'rgba(22, 163, 74, 0.1)',\n red: '#dc2626',\n redSoft: 'rgba(220, 38, 38, 0.1)',\n amber: '#f59e0b',\n amberSoft: 'rgba(245, 158, 11, 0.1)',\n purple: '#8b5cf6',\n purpleSoft: 'rgba(139, 92, 246, 0.1)',\n userBubble: '#2563eb',\n botBubble: '#f1f3f5',\n botBubbleBorder: 'rgba(0, 0, 0, 0.08)',\n },\n} as const;\n\n// Ada palette — warm, paper, personal. Used by the consumer chat experience.\nexport const ada = {\n paper: '#FAF6EE',\n paperSoft: '#F2EADC',\n paperDeep: '#EBE0CC',\n ink: '#1a1410',\n inkSoft: '#5a4d3f',\n inkMuted: '#9a8870',\n border: 'rgba(26, 20, 16, 0.08)',\n borderStrong: 'rgba(26, 20, 16, 0.16)',\n orange: '#FF7A28',\n orangeDeep: '#B8410A',\n orangeSoft: 'rgba(255, 122, 40, 0.14)',\n userBubble: '#1a1410',\n userBubbleText: '#FAF6EE',\n botBubble: '#F2EADC',\n botBubbleBorder: 'rgba(26, 20, 16, 0.06)',\n botBubbleText: '#1a1410',\n} as const;\n\nexport const spacing = {\n xs: 4,\n sm: 8,\n md: 12,\n lg: 16,\n xl: 20,\n xxl: 24,\n xxxl: 32,\n} as const;\n\nexport const fontSize = {\n xs: 11,\n sm: 13,\n md: 15,\n lg: 17,\n xl: 20,\n xxl: 24,\n title: 28,\n} as const;\n\nexport const borderRadius = {\n sm: 8,\n md: 12,\n lg: 16,\n xl: 20,\n full: 9999,\n} as const;\n","/**\n * ACS host DI seams. Both optional — the ACS layer works without them:\n * no reachability reporting, and the home-actions cache lives in memory only.\n */\n\n/** Host hook fired on every ACS fetch outcome — a response (any status)\n * proves the server is reachable; a thrown fetch means it isn't. The\n * reference app wires this to its connectivity banner store. */\nexport interface AcsReachabilityReporter {\n up: () => void;\n down: () => void;\n}\n\nlet _reachability: AcsReachabilityReporter | null = null;\n\nexport function setAcsReachabilityReporter(r: AcsReachabilityReporter | null): void {\n _reachability = r;\n}\n\nexport function reportAcsServerUp(): void {\n try { _reachability?.up(); } catch {}\n}\n\nexport function reportAcsServerDown(): void {\n try { _reachability?.down(); } catch {}\n}\n\n/** Minimal async KV used to persist the home-actions feed across cold starts\n * (AsyncStorage-shaped). @ateam-ai-mobile/expo wires AsyncStorage in\n * setupExpoProviders(); without a provider the cache is a no-op. */\nexport interface AcsKvStorage {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n}\n\nlet _kv: AcsKvStorage | null = null;\n\nexport function setAcsCacheStorage(kv: AcsKvStorage | null): void {\n _kv = kv;\n}\n\nexport function getAcsCacheStorage(): AcsKvStorage | null {\n return _kv;\n}\n","/**\n * Client for Core's /api/acs/* proxy → ACS service. Powers the \"widgets\"\n * surface on home: AI-generated artifacts that render as carousel tiles and\n * full-screen interactive panels via the bundleUrl — plus the home\n * \"top actions\" feed.\n *\n * Endpoints:\n * POST /api/acs/surface — list active artifacts for a surface\n * POST /api/acs/event — usage tracking (clicked/dismissed/etc.)\n * GET /api/acs/made-for-you — full library, all lifecycle stages\n * DELETE /api/acs/artifacts/{id} — user-initiated retire (idempotent)\n * PATCH /api/acs/artifacts/{id} — visibility + rename\n * PUT /api/acs/order — drag-reorder\n * GET /api/acs/home-actions — top-actions feed (+ PATCH/PUT order)\n * WS topics acs.artifacts / acs.home-actions — cross-device sync (see ./ws)\n */\n\nimport { getCoreApiUrl, getToken } from '../config';\nimport { reportAcsServerUp, reportAcsServerDown } from './providers';\n\nexport interface AcsArtifact {\n id: string;\n name: string;\n description?: string;\n iconHint?: string;\n manifest?: Record<string, any>;\n bundleUrl: string;\n version: number;\n provenance?: Record<string, any>;\n\n // Tile-shape fields (consumers branch on these when present; safe defaults\n // when absent).\n kind?: 'user' | 'featured';\n visibility?: 'pinned' | 'hidden';\n pinOrder?: number;\n canDelete?: boolean;\n canRename?: boolean;\n canHide?: boolean;\n previewMode?: 'live' | 'snapshot' | 'none';\n previewUrl?: string;\n}\n\n// Closed-ish enum — accept arbitrary strings so the backend can introduce new\n// surface names without a client release blocking it.\nexport type AcsSurface = 'home' | 'library' | (string & {});\n\n// Closed enum on the backend side.\nexport type AcsEvent = 'clicked' | 'dismissed' | 'acted' | 'ignored';\n\nexport type AcsDeleteReason =\n | 'user_long_press_delete'\n | 'user_swipe_delete'\n | 'user_bulk_delete'\n | (string & {});\n\nexport type AcsPatchReason =\n | 'user_long_press_hide'\n | 'user_long_press_unhide'\n | 'user_long_press_rename'\n | (string & {});\n\nasync function authedFetch(path: string, init?: RequestInit): Promise<Response> {\n const token = getToken();\n try {\n const res = await fetch(`${getCoreApiUrl()}${path}`, {\n ...init,\n headers: {\n 'Content-Type': 'application/json',\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n ...(init?.headers || {}),\n },\n });\n // Any response (even 4xx/5xx) proves the server is reachable.\n reportAcsServerUp();\n return res;\n } catch (e) {\n // Thrown = network error / timeout / DNS / TLS → server unreachable.\n reportAcsServerDown();\n throw e;\n }\n}\n\n/**\n * List artifacts surfaced for the given surface name. Returns [] on error\n * (network, auth, or empty result) — callers shouldn't have to distinguish.\n * Use surface=\"home\" for the carousel.\n */\nexport async function listSurface(\n surface: AcsSurface,\n context?: Record<string, any>,\n): Promise<AcsArtifact[]> {\n try {\n const res = await authedFetch('/api/acs/surface', {\n method: 'POST',\n body: JSON.stringify({ surface, ...(context ? { context } : {}) }),\n });\n if (!res.ok) {\n console.warn(`[acs] /surface ${surface} returned ${res.status}`);\n return [];\n }\n const data = await res.json();\n return Array.isArray(data?.items) ? (data.items as AcsArtifact[]) : [];\n } catch (e: any) {\n console.warn('[acs] /surface failed:', e?.message || e);\n return [];\n }\n}\n\n/**\n * Full library — every artifact across all lifecycle stages. Used by a\n * Library screen's Yours + Hidden sections.\n */\nexport async function listMadeForYou(): Promise<AcsArtifact[]> {\n try {\n const res = await authedFetch('/api/acs/made-for-you', { method: 'GET' });\n if (!res.ok) {\n console.warn(`[acs] /made-for-you returned ${res.status}`);\n return [];\n }\n const data = await res.json();\n return Array.isArray(data?.artifacts) ? (data.artifacts as AcsArtifact[]) : [];\n } catch (e: any) {\n console.warn('[acs] /made-for-you failed:', e?.message || e);\n return [];\n }\n}\n\nexport interface DeleteResult {\n ok: boolean;\n /** True when the server already had this artifact retired. Treat as success. */\n already?: boolean;\n /** True for HTTP 404 — artifact gone or never owned by caller. Treat as success\n * (remove from local state) per the backend's contract: no existence leak. */\n notFound?: boolean;\n /** HTTP status returned by the server. */\n status: number;\n error?: string;\n}\n\n/**\n * Retire a user widget. Per backend contract:\n * 200 ok → success\n * 200 ok + already:true → idempotent, treat as success\n * 404 → already gone or not owned, treat as success\n * 5xx / network → real failure, caller should rollback optimistic remove\n */\nexport async function deleteArtifact(\n artifactId: string,\n reason: AcsDeleteReason = 'user_long_press_delete',\n): Promise<DeleteResult> {\n try {\n const res = await authedFetch(\n `/api/acs/artifacts/${encodeURIComponent(artifactId)}`,\n { method: 'DELETE', body: JSON.stringify({ reason }) },\n );\n const data = await res.json().catch(() => ({} as any));\n if (res.ok) {\n return { ok: true, already: !!data?.already, status: res.status };\n }\n if (res.status === 404) {\n return { ok: true, notFound: true, status: 404 };\n }\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\nexport interface PatchResult {\n ok: boolean;\n /** Updated tile when the server returns the new state. */\n artifact?: AcsArtifact;\n already?: boolean;\n notFound?: boolean;\n status: number;\n error?: string;\n}\n\n/**\n * Update an artifact's visibility (hide/unhide) and/or name (rename). One\n * call covers both because backend offers a single PATCH endpoint with\n * optional fields. At least one of visibility/name must be provided.\n *\n * Per backend contract (mirrors DELETE semantics):\n * 200 ok → success\n * 200 ok + already:true → idempotent no-op, treat as success\n * 404 → not found / not owned, treat as success\n * 400 / 403 → real failure, surface to user\n * 5xx / network → real failure, caller should rollback\n */\nexport async function patchArtifact(\n artifactId: string,\n body: { visibility?: 'pinned' | 'hidden'; name?: string },\n reason: AcsPatchReason,\n): Promise<PatchResult> {\n try {\n const res = await authedFetch(\n `/api/acs/artifacts/${encodeURIComponent(artifactId)}`,\n { method: 'PATCH', body: JSON.stringify({ ...body, reason }) },\n );\n const data = await res.json().catch(() => ({} as any));\n if (res.ok) {\n return {\n ok: true,\n already: !!data?.already,\n artifact: data?.artifact || undefined,\n status: res.status,\n };\n }\n if (res.status === 404) {\n return { ok: true, notFound: true, status: 404 };\n }\n return {\n ok: false,\n status: res.status,\n error: data?.error || `HTTP ${res.status}`,\n };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\n/**\n * Persist a new pin order. Body lists currently-pinned artifact IDs in the\n * new visual order; server validates ownership + pinned state of each ID.\n *\n * Returns { ok: false, error } on failure. 400 means the array contained\n * an id that's not owned or not pinned — caller should refetch /surface\n * and re-render rather than fight the server.\n */\nexport async function setOrder(pinned: string[]): Promise<{ ok: boolean; status: number; error?: string }> {\n try {\n const res = await authedFetch('/api/acs/order', {\n method: 'PUT',\n body: JSON.stringify({ pinned }),\n });\n if (res.ok) return { ok: true, status: res.status };\n const data = await res.json().catch(() => ({} as any));\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\n/**\n * Record a usage event. Fire-and-forget — never throws, never blocks the UI.\n * Use surface to tell the backend which surface the event came from\n * (e.g. 'home' for the carousel).\n */\nexport async function recordEvent(\n artifactId: string,\n event: AcsEvent,\n surface?: AcsSurface,\n): Promise<void> {\n try {\n await authedFetch('/api/acs/event', {\n method: 'POST',\n body: JSON.stringify({ artifactId, event, ...(surface ? { surface } : {}) }),\n });\n } catch {\n // intentional swallow — usage tracking failures shouldn't surface to the user\n }\n}\n\n// ─── Home Actions (top-actions feed) ────────────────────────────────────\n// Server-managed recommended-actions feed for the home \"What's on your mind?\"\n// screen. The card universe is open + agent-authored; the only fixed contract\n// is this wire shape + the leaf dispatch (send_message | open_widget).\n// Backend: GET /api/acs/home-actions, PUT /order, PATCH /:id,\n// WS topic acs.home-actions.\n\nexport type HomeActionLeaf =\n | { type: 'send_message'; prompt: string; skillSlug?: string }\n | { type: 'open_widget'; artifactId: string }\n | { type: string; [k: string]: any }; // forward-compat: open_url/run_tool/…\n\nexport interface HomeAction {\n actionId: string;\n pinOrder?: number;\n title: string;\n subtitle?: string;\n icon?: string;\n action: HomeActionLeaf;\n source?: 'curated' | 'pinned_by_user' | 'skill_authored' | (string & {});\n canDismiss?: boolean;\n canPin?: boolean;\n pinned?: boolean;\n}\n\n/** List the home top-actions feed. Returns [] on any error. */\nexport async function listHomeActions(): Promise<HomeAction[]> {\n try {\n const res = await authedFetch('/api/acs/home-actions', { method: 'GET' });\n if (!res.ok) {\n console.warn(`[acs] /home-actions returned ${res.status}`);\n return [];\n }\n const data = await res.json();\n return Array.isArray(data?.actions) ? (data.actions as HomeAction[]) : [];\n } catch (e: any) {\n console.warn('[acs] /home-actions failed:', e?.message || e);\n return [];\n }\n}\n\nexport type HomeActionReason =\n | 'user_pin' | 'user_unpin' | 'user_dismiss' | 'user_drag_reorder'\n | (string & {});\n\n/** Pin/unpin or dismiss a card. 200 already / 404 both count as success. */\nexport async function patchHomeAction(\n actionId: string,\n body: { pinned?: boolean; dismissed?: boolean },\n reason: HomeActionReason,\n): Promise<{ ok: boolean; action?: HomeAction; status: number; error?: string }> {\n try {\n const res = await authedFetch(\n `/api/acs/home-actions/${encodeURIComponent(actionId)}`,\n { method: 'PATCH', body: JSON.stringify({ ...body, reason }) },\n );\n const data = await res.json().catch(() => ({} as any));\n if (res.ok) return { ok: true, action: data?.action || undefined, status: res.status };\n if (res.status === 404) return { ok: true, status: 404 };\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\n/** Persist a new card order. Optimistic; caller rolls back on failure. */\nexport async function setHomeActionOrder(\n order: string[],\n): Promise<{ ok: boolean; status: number; error?: string }> {\n try {\n const res = await authedFetch('/api/acs/home-actions/order', {\n method: 'PUT',\n body: JSON.stringify({ order }),\n });\n if (res.ok) return { ok: true, status: res.status };\n const data = await res.json().catch(() => ({} as any));\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n","/**\n * Tracks the user's ACS widget tiles for the home carousel. Single source of\n * truth for /api/acs/surface state. Optimistic ops with rollback on failure\n * — backend contract treats 404 / already:true as success (per spec), so the\n * store mirrors that policy: a delete that the server says was already done\n * stays removed locally.\n *\n * Cross-device freshness: the WS subscription (./ws) forwards `acs.artifacts`\n * events into the applyServer* methods; hosts should also refresh() on app\n * foreground (\"WS is best-effort; the GET is the source of truth\").\n */\n\nimport { create } from 'zustand';\nimport {\n listSurface,\n deleteArtifact,\n patchArtifact,\n setOrder,\n recordEvent,\n type AcsArtifact,\n type AcsDeleteReason,\n} from './api';\n\ninterface WidgetsState {\n /** Tiles to render in the home carousel. Order matches what /surface\n * returned; sort by pinOrder when present. */\n tiles: AcsArtifact[];\n /** True after the first /surface fetch completes (success OR empty). */\n hydrated: boolean;\n /** True while a /surface request is in flight. */\n loading: boolean;\n /** Last error string from /surface; null on success or pre-fetch. */\n error: string | null;\n\n /** First load — idempotent; safe to call from multiple effects. */\n hydrate: () => Promise<void>;\n /** Force re-fetch; call on app foreground and after destructive ops. */\n refresh: () => Promise<void>;\n /** Reset to empty (sign-out, env switch). */\n clear: () => void;\n\n /**\n * Optimistic remove. Returns { ok: false, error } only on real network /\n * 5xx failures — 404 and already:true rollback to ok:true per the backend\n * contract (no existence leak; the row is gone either way).\n */\n remove: (artifactId: string, reason?: AcsDeleteReason) => Promise<{ ok: boolean; error?: string }>;\n\n /** Optimistic hide (visibility → 'hidden'). Tile disappears from carousel. */\n hide: (artifactId: string) => Promise<{ ok: boolean; error?: string }>;\n\n /** Optimistic unhide (visibility → 'pinned'). Tile reappears in carousel. */\n unhide: (artifactId: string) => Promise<{ ok: boolean; error?: string }>;\n\n /** Optimistic rename. Trims input and rejects empty / overlong names locally. */\n rename: (artifactId: string, name: string) => Promise<{ ok: boolean; error?: string }>;\n\n /**\n * Persist a new pin order to the server. `pinnedIds` is the visible order\n * of currently-pinned tiles. Optimistic — applies locally first, rolls\n * back on server rejection.\n */\n reorder: (pinnedIds: string[]) => Promise<{ ok: boolean; error?: string }>;\n\n // ─── Server-driven mutations (no API call) ─────────────────────────────\n // The WS subscription (./ws) forwards `acs.artifacts` events into these\n // methods. They ONLY mutate local state — they DO NOT call the API (the\n // server is the source of the event, calling back would loop).\n\n /** WS 'updated' event — replace the tile by id (hide/unhide/rename land here). */\n applyServerUpdate: (artifact: AcsArtifact) => void;\n /** WS 'retired' event — remove the tile by id. */\n applyServerRetire: (artifactId: string) => void;\n /** WS 'order' event — re-rank tiles to match the pinned ID array. */\n applyServerOrder: (pinnedIds: string[]) => void;\n\n /** Fire-and-forget usage event. Caller doesn't await. */\n track: (artifactId: string, event: 'clicked' | 'dismissed' | 'acted' | 'ignored') => void;\n}\n\nexport const useWidgetsStore = create<WidgetsState>((set, get) => ({\n tiles: [],\n hydrated: false,\n loading: false,\n error: null,\n\n hydrate: async () => {\n if (get().hydrated || get().loading) return;\n await get().refresh();\n },\n\n refresh: async () => {\n if (get().loading) return;\n set({ loading: true, error: null });\n try {\n const tiles = await listSurface('home');\n set({ tiles, loading: false, hydrated: true });\n } catch (e: any) {\n set({ loading: false, hydrated: true, error: e?.message || 'Failed to load widgets' });\n }\n },\n\n clear: () => set({ tiles: [], hydrated: false, loading: false, error: null }),\n\n remove: async (artifactId, reason = 'user_long_press_delete') => {\n const before = get().tiles;\n // Optimistic: snap removed immediately so the user sees the tile vanish.\n set({ tiles: before.filter(t => t.id !== artifactId) });\n\n const result = await deleteArtifact(artifactId, reason);\n if (result.ok) {\n // Includes 200, 200 already:true, and 404 — all \"gone server-side too\".\n return { ok: true };\n }\n\n // Real failure — rollback.\n set({ tiles: before });\n return { ok: false, error: result.error || `HTTP ${result.status}` };\n },\n\n hide: async (artifactId) => {\n const before = get().tiles;\n set({\n tiles: before.map(t =>\n t.id === artifactId ? { ...t, visibility: 'hidden' as const } : t,\n ),\n });\n const r = await patchArtifact(artifactId, { visibility: 'hidden' }, 'user_long_press_hide');\n if (r.ok) {\n // If the server returned the updated artifact, sync our copy to it\n // (covers race conditions and server-side normalisation).\n if (r.artifact) {\n set({\n tiles: get().tiles.map(t => (t.id === artifactId ? { ...t, ...r.artifact! } : t)),\n });\n }\n return { ok: true };\n }\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n unhide: async (artifactId) => {\n const before = get().tiles;\n set({\n tiles: before.map(t =>\n t.id === artifactId ? { ...t, visibility: 'pinned' as const } : t,\n ),\n });\n const r = await patchArtifact(artifactId, { visibility: 'pinned' }, 'user_long_press_unhide');\n if (r.ok) {\n if (r.artifact) {\n set({\n tiles: get().tiles.map(t => (t.id === artifactId ? { ...t, ...r.artifact! } : t)),\n });\n }\n return { ok: true };\n }\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n rename: async (artifactId, name) => {\n // Local validation mirrors backend's 60-char cap from the spec. Keep\n // this strict so we don't hit the API with garbage that will 400 anyway.\n const trimmed = name.trim();\n if (!trimmed) return { ok: false, error: 'Name cannot be empty' };\n if (trimmed.length > 60) return { ok: false, error: 'Name must be 60 characters or less' };\n\n const before = get().tiles;\n set({\n tiles: before.map(t => (t.id === artifactId ? { ...t, name: trimmed } : t)),\n });\n const r = await patchArtifact(artifactId, { name: trimmed }, 'user_long_press_rename');\n if (r.ok) {\n if (r.artifact) {\n set({\n tiles: get().tiles.map(t => (t.id === artifactId ? { ...t, ...r.artifact! } : t)),\n });\n }\n return { ok: true };\n }\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n reorder: async (pinnedIds) => {\n const before = get().tiles;\n // Optimistic: assign pinOrder by position in pinnedIds. Hidden tiles\n // are not touched. If the server rejects, we roll back to `before`.\n const idToOrder = new Map(pinnedIds.map((id, i) => [id, i] as const));\n set({\n tiles: before.map(t => {\n const o = idToOrder.get(t.id);\n return o == null ? t : { ...t, pinOrder: o };\n }),\n });\n const r = await setOrder(pinnedIds);\n if (r.ok) return { ok: true };\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n applyServerUpdate: (artifact) => {\n set({\n tiles: get().tiles.map(t => (t.id === artifact.id ? { ...t, ...artifact } : t)),\n });\n },\n\n applyServerRetire: (artifactId) => {\n set({ tiles: get().tiles.filter(t => t.id !== artifactId) });\n },\n\n applyServerOrder: (pinnedIds) => {\n const idToOrder = new Map(pinnedIds.map((id, i) => [id, i] as const));\n set({\n tiles: get().tiles.map(t => {\n const o = idToOrder.get(t.id);\n return o == null ? t : { ...t, pinOrder: o };\n }),\n });\n },\n\n track: (artifactId, event) => {\n // Fire-and-forget. Surface tagged so backend analytics knows where the\n // click happened (home carousel vs library, etc.).\n recordEvent(artifactId, event, 'home');\n },\n}));\n","/**\n * The home \"What's on your mind?\" top-actions feed. Server-managed: the list,\n * its order, pin and dismiss state all live on the backend (ACS home-actions\n * API). This store is a thin local mirror with optimistic mutations + rollback\n * — same discipline as widgetsStore.\n *\n * The cards themselves are agent-authored and open-ended; clients only know\n * the wire shape + the fixed leaf dispatch (send_message | open_widget), so\n * this store stays dumb on purpose.\n */\n\nimport { create } from 'zustand';\nimport {\n listHomeActions,\n patchHomeAction,\n setHomeActionOrder,\n type HomeAction,\n} from './api';\nimport { getAcsCacheStorage } from './providers';\n\n// Persisted (when the host wires setAcsCacheStorage) so the home cards render\n// instantly on cold start and survive a dead/empty server response. The\n// server is still source of truth — when a non-empty result arrives we\n// overwrite the cache; an empty/failed fetch leaves the last good cards on\n// screen.\nconst CACHE_KEY = 'ateam.homeActions.v1';\n\nfunction persist(actions: HomeAction[]): void {\n // Fire-and-forget; never block the UI on disk.\n getAcsCacheStorage()?.setItem(CACHE_KEY, JSON.stringify(actions)).catch(() => {});\n}\n\ninterface HomeActionsState {\n actions: HomeAction[];\n hydrated: boolean;\n loading: boolean;\n\n hydrate: () => Promise<void>;\n refresh: () => Promise<void>;\n clear: () => void;\n\n /** Optimistic dismiss — removes locally, rolls back on real failure. */\n dismiss: (actionId: string) => Promise<{ ok: boolean; error?: string }>;\n /** Optimistic pin/unpin. */\n setPinned: (actionId: string, pinned: boolean) => Promise<{ ok: boolean; error?: string }>;\n /** Optimistic reorder — `orderedIds` is the new visual order. */\n reorder: (orderedIds: string[]) => Promise<{ ok: boolean; error?: string }>;\n\n // ─── WS-driven (local mutation only, no API call) ───\n applyServerUpsert: (action: HomeAction) => void;\n applyServerRemove: (actionId: string) => void;\n applyServerOrder: (orderedIds: string[]) => void;\n}\n\nfunction sortByPin(a: HomeAction, b: HomeAction): number {\n // pinned first, then pinOrder asc, then stable.\n if (!!a.pinned !== !!b.pinned) return a.pinned ? -1 : 1;\n const ao = typeof a.pinOrder === 'number' ? a.pinOrder : Number.MAX_SAFE_INTEGER;\n const bo = typeof b.pinOrder === 'number' ? b.pinOrder : Number.MAX_SAFE_INTEGER;\n return ao - bo;\n}\n\nexport const useHomeActionsStore = create<HomeActionsState>((set, get) => ({\n actions: [],\n hydrated: false,\n loading: false,\n\n hydrate: async () => {\n if (get().hydrated || get().loading) return;\n // 1. Paint cached cards immediately (survives cold start / offline).\n try {\n const cached = await getAcsCacheStorage()?.getItem(CACHE_KEY);\n if (cached) {\n const parsed = JSON.parse(cached) as HomeAction[];\n if (Array.isArray(parsed) && parsed.length > 0) {\n // Preserve the order we cached (which was the server's priority\n // order) — home layouts may split positionally, so re-sorting\n // would reshuffle the hero cards.\n set({ actions: parsed, hydrated: true });\n }\n }\n } catch { /* corrupt cache — ignore, server refresh will fix it */ }\n // 2. Then refresh from the server.\n await get().refresh();\n },\n\n refresh: async () => {\n if (get().loading) return;\n set({ loading: true });\n const actions = await listHomeActions();\n // Only overwrite when the server actually returned cards. An empty result\n // (dead API, transient 5xx, or genuinely-empty) must NOT wipe the cards\n // already on screen — keep the last good set persisted.\n if (actions.length > 0) {\n // Server delivers cards already priority-ordered — do NOT re-sort\n // (home layouts may be positional, e.g. a top-3 / rest split).\n set({ actions, loading: false, hydrated: true });\n persist(actions);\n } else {\n set({ loading: false, hydrated: true });\n }\n },\n\n // clear() wipes in-memory state on sign-out AND drops the disk cache — a\n // different user must not see the prior user's cards.\n clear: () => {\n set({ actions: [], hydrated: false, loading: false });\n getAcsCacheStorage()?.setItem(CACHE_KEY, '[]').catch(() => {});\n },\n\n dismiss: async (actionId) => {\n const before = get().actions;\n const next = before.filter(a => a.actionId !== actionId);\n set({ actions: next });\n persist(next);\n const r = await patchHomeAction(actionId, { dismissed: true }, 'user_dismiss');\n if (r.ok) return { ok: true };\n set({ actions: before });\n persist(before);\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n setPinned: async (actionId, pinned) => {\n const before = get().actions;\n const next = before.map(a => (a.actionId === actionId ? { ...a, pinned } : a)).sort(sortByPin);\n set({ actions: next });\n persist(next);\n const r = await patchHomeAction(actionId, { pinned }, pinned ? 'user_pin' : 'user_unpin');\n if (r.ok) {\n if (r.action) {\n const merged = get().actions.map(a => (a.actionId === actionId ? { ...a, ...r.action! } : a)).sort(sortByPin);\n set({ actions: merged });\n persist(merged);\n }\n return { ok: true };\n }\n set({ actions: before });\n persist(before);\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n reorder: async (orderedIds) => {\n const before = get().actions;\n const idx = new Map(orderedIds.map((id, i) => [id, i] as const));\n const next = before.map(a => {\n const o = idx.get(a.actionId);\n return o == null ? a : { ...a, pinOrder: o };\n }).sort(sortByPin);\n set({ actions: next });\n persist(next);\n const r = await setHomeActionOrder(orderedIds);\n if (r.ok) return { ok: true };\n set({ actions: before });\n persist(before);\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n applyServerUpsert: (action) => {\n const rest = get().actions.filter(a => a.actionId !== action.actionId);\n const next = [...rest, action].sort(sortByPin);\n set({ actions: next });\n persist(next);\n },\n applyServerRemove: (actionId) => {\n const next = get().actions.filter(a => a.actionId !== actionId);\n set({ actions: next });\n persist(next);\n },\n applyServerOrder: (orderedIds) => {\n const idx = new Map(orderedIds.map((id, i) => [id, i] as const));\n const next = get().actions.map(a => {\n const o = idx.get(a.actionId);\n return o == null ? a : { ...a, pinOrder: o };\n }).sort(sortByPin);\n set({ actions: next });\n persist(next);\n },\n}));\n","/**\n * Long-lived WebSocket subscription to the `acs.artifacts` and\n * `acs.home-actions` topics. Protocol (backend websocket.js):\n *\n * client → server : { type: \"subscribe\", topic: \"acs.artifacts\" }\n * server → client : { event: \"subscribed\", data: { topic: \"acs.artifacts\" } }\n * server → client : { topic: \"acs.artifacts\", event: \"updated\", artifact: {...} }\n * server → client : { topic: \"acs.artifacts\", event: \"retired\", artifactId: \"...\" }\n * server → client : { topic: \"acs.artifacts\", event: \"order\", pinned: [...] }\n *\n * Events flow into the stores' applyServer* methods so we don't loop (those\n * methods mutate local state only — no API calls).\n *\n * Lifecycle:\n * connectAcsWs(token, tenant) starts a single connection + subscribe.\n * On disconnect, exponential-backoff reconnect (capped). Call\n * notifyAcsWsForeground() from the host's AppState listener to\n * force-reconnect when the socket dropped while backgrounded (this module\n * is host-agnostic — no react-native import — so the host owns AppState).\n * On signout, disconnectAcsWs() closes the socket and stops reconnects.\n *\n * Backend's spec note: \"WS is best-effort; the GET is the source of truth\"\n * — so widgetsStore.refresh() on foreground stays the safety net even when\n * the WS is healthy. This file is the realtime cherry on top.\n */\n\nimport { getCoreWsUrl } from '../config';\nimport { useWidgetsStore } from './widgetsStore';\nimport { useHomeActionsStore } from './homeActionsStore';\n\nlet _ws: WebSocket | null = null;\nlet _wantOpen = false;\nlet _retryAttempt = 0;\nlet _retryTimer: ReturnType<typeof setTimeout> | null = null;\nlet _token: string | null = null;\nlet _tenant: string | null = null;\n\nconst TOPIC = 'acs.artifacts';\nconst TOPIC_HOME = 'acs.home-actions';\nconst MAX_BACKOFF_MS = 30_000;\n\nfunction backoffMs(attempt: number): number {\n // 0.5s, 1s, 2s, 4s, ... capped at 30s. Tiny jitter to avoid thundering herd.\n const base = Math.min(MAX_BACKOFF_MS, 500 * Math.pow(2, attempt));\n const jitter = Math.random() * 250;\n return base + jitter;\n}\n\nfunction send(obj: any) {\n if (_ws && _ws.readyState === 1) {\n try { _ws.send(JSON.stringify(obj)); } catch (e) { console.warn('[acsWs] send failed', e); }\n }\n}\n\nfunction handleEvent(msg: any) {\n // The subscribe confirmation comes as { event: \"subscribed\", data: {...} }\n // (no `topic` field). Real events come as { topic, event, ...payload }.\n if (msg?.event === 'subscribed') {\n console.log('[acsWs] subscribed to', msg?.data?.topic);\n return;\n }\n\n // Home-actions feed events route to its own store.\n if (msg?.topic === TOPIC_HOME) {\n const home = useHomeActionsStore.getState();\n switch (msg.event) {\n case 'updated':\n if (msg.action && typeof msg.action.actionId === 'string') home.applyServerUpsert(msg.action);\n break;\n case 'removed':\n if (typeof msg.actionId === 'string') home.applyServerRemove(msg.actionId);\n break;\n case 'order':\n if (Array.isArray(msg.order)) home.applyServerOrder(msg.order.filter((id: any) => typeof id === 'string'));\n break;\n case 'refreshed':\n home.refresh();\n break;\n default:\n break;\n }\n return;\n }\n\n if (msg?.topic !== TOPIC) return;\n\n const store = useWidgetsStore.getState();\n switch (msg.event) {\n case 'updated':\n if (msg.artifact && typeof msg.artifact.id === 'string') {\n store.applyServerUpdate(msg.artifact);\n }\n break;\n case 'retired':\n if (typeof msg.artifactId === 'string') {\n store.applyServerRetire(msg.artifactId);\n }\n break;\n case 'order':\n if (Array.isArray(msg.pinned)) {\n store.applyServerOrder(msg.pinned.filter((id: any) => typeof id === 'string'));\n }\n break;\n case 'created':\n // Backend spec lists `created` as TODO. Until it ships, host foreground\n // refresh catches new widgets. When it lands the WS will also fire\n // `updated` for the new tile, which is already handled. For now, treat\n // any inbound created the same as updated.\n if (msg.artifact && typeof msg.artifact.id === 'string') {\n store.applyServerUpdate(msg.artifact);\n }\n break;\n default:\n // Unknown event — ignore so we stay forward-compatible with new types.\n break;\n }\n}\n\nfunction openSocket() {\n if (_ws) return;\n if (!_token || !_tenant) return;\n\n const url = `${getCoreWsUrl()}/ws?token=${encodeURIComponent(_token)}&tenant=${encodeURIComponent(_tenant)}`;\n console.log(`[acsWs] opening`);\n const ws = new WebSocket(url);\n _ws = ws;\n\n ws.onopen = () => {\n _retryAttempt = 0;\n send({ type: 'subscribe', topic: TOPIC });\n send({ type: 'subscribe', topic: TOPIC_HOME });\n };\n ws.onmessage = (e) => {\n try {\n const msg = JSON.parse(typeof e.data === 'string' ? e.data : '');\n handleEvent(msg);\n } catch (err) {\n // Non-JSON or malformed frame — ignore, log for debugging.\n console.warn('[acsWs] parse failed', err);\n }\n };\n ws.onerror = (e: any) => {\n console.warn('[acsWs] error', e?.message || e);\n };\n ws.onclose = () => {\n _ws = null;\n if (!_wantOpen) return;\n const delay = backoffMs(_retryAttempt++);\n console.log(`[acsWs] closed; reconnecting in ${Math.round(delay)}ms (attempt ${_retryAttempt})`);\n if (_retryTimer) clearTimeout(_retryTimer);\n _retryTimer = setTimeout(openSocket, delay);\n };\n}\n\n/**\n * Call from the host's AppState listener when the app returns to the\n * foreground — if the socket dropped while backgrounded, reconnect\n * immediately rather than waiting out the backoff timer.\n */\nexport function notifyAcsWsForeground() {\n if (_wantOpen && !_ws) {\n if (_retryTimer) { clearTimeout(_retryTimer); _retryTimer = null; }\n _retryAttempt = 0;\n openSocket();\n }\n}\n\n/**\n * Start the ACS WS subscription. Idempotent — calling twice with the same\n * token/tenant is a no-op. Call once the host says the user is signed in\n * (JWT available).\n */\nexport function connectAcsWs(token: string, tenant: string) {\n if (_ws && _wantOpen && _token === token && _tenant === tenant) return;\n // Token or tenant changed → tear down + reopen.\n if (_ws) {\n try { _ws.close(); } catch {}\n _ws = null;\n }\n _token = token;\n _tenant = tenant;\n _wantOpen = true;\n openSocket();\n}\n\n/**\n * Stop the ACS WS subscription. Call on signout / env switch.\n */\nexport function disconnectAcsWs() {\n _wantOpen = false;\n _token = null;\n _tenant = null;\n if (_retryTimer) { clearTimeout(_retryTimer); _retryTimer = null; }\n if (_ws) {\n try { _ws.close(); } catch {}\n _ws = null;\n }\n}\n"],"mappings":"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","names":["text","create","create","create","create","_ws"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/api/client.ts","../src/api/mcp.ts","../src/session.ts","../src/chat/store.ts","../src/utils/emitter.ts","../src/api/tenants.ts","../src/theme/tokens.ts","../src/acs/providers.ts","../src/acs/api.ts","../src/acs/widgetsStore.ts","../src/acs/homeActionsStore.ts","../src/acs/ws.ts"],"sourcesContent":["/**\n * SDK configuration — the single injection point between the host app and\n * the ADAS core. The host owns authentication, identity, and URL discovery;\n * the SDK reads everything through the config registered via initAdas().\n *\n * There is intentionally ONE active config per JS context (module singleton):\n * the chat store, WebSocket, and API client below it are app-wide singletons\n * too, and a second tenant/backend inside one app is not a supported v1 case.\n */\n\nimport type { AttachmentCache } from './storage/types';\n\n/** Result of a host-driven token refresh. Mirrors the semantics the API\n * client depends on: only 'auth_failed' logs the user out; 'transient'\n * (network blip, 5xx) keeps the session so the next call can retry. */\nexport interface RefreshOutcome {\n ok: 'ok' | 'auth_failed' | 'transient';\n status: number;\n reason?: string;\n}\n\n/**\n * Host-implemented auth bridge. The SDK never shows login UI and never\n * stores credentials — the host authenticates its own users and hands the\n * SDK a way to read/refresh the ADAS JWT it minted for them (via the\n * server-to-server token exchange).\n */\nexport interface TokenProvider {\n /** Current ADAS JWT, or null when signed out. Called on every request —\n * keep it synchronous and cheap (read from memory, not disk). */\n getToken(): string | null;\n /** Called on 401. Host should mint/refresh the ADAS token and return the\n * outcome; 'ok' makes the SDK retry the failed request once. */\n refresh(): Promise<RefreshOutcome>;\n /** Auth is genuinely dead (refresh rejected, or retry still 401). Host\n * should treat this as sign-out for the embedded experience. */\n onAuthFailure?: () => void;\n}\n\nexport interface AdasUser {\n actorId: string;\n name?: string;\n email?: string;\n /** Roles from the host's identity (e.g. JWT claims) — forwarded to plugins\n * as PluginContext.user.roles. */\n roles?: string[];\n}\n\n/** A URL that is either static or resolved on each read. Hosts with a\n * runtime env switcher (dev/prod) pass a getter so the SDK always sees the\n * currently-selected backend without re-calling initAdas(). */\nexport type UrlSource = string | (() => string);\n\nexport interface AdasConfig {\n /** Core API base URL, e.g. https://app.ateam-ai.com. Pass a getter to\n * support a runtime env switch without re-initializing. */\n coreUrl: UrlSource;\n /** Voice service base URL (optional — only voice features need it). */\n voiceUrl?: UrlSource;\n /** Consumer-auth base URL, e.g. https://consumer-auth.ateam-ai.com. Only\n * needed for `switchTenant()` (re-scoping the session to another tenant\n * the user belongs to). */\n consumerAuthUrl?: UrlSource;\n tokenProvider: TokenProvider;\n /** Tenant slug — used for plugin URL resolution and voice, never sent as a\n * header (the backend derives the tenant from the JWT). Pass a getter when\n * the host resolves the tenant after startup (storage hydration, runtime\n * tenant switch). */\n tenant?: string | (() => string);\n /** Current end user as known to the host. actorId is used as the chat\n * reply context; without it, replies route to 'unknown'. */\n getUser?: () => AdasUser | null;\n /** Optional persistence for outgoing image/file attachments so previews\n * survive app restarts. No-op when omitted (previews live in memory for\n * the session only). @ateam-ai-mobile/ui ships an Expo/RN implementation. */\n attachmentCache?: AttachmentCache;\n /** Called by `switchTenant()` with the freshly-minted session for the\n * target tenant. The host MUST persist it here (store the new JWT so\n * tokenProvider.getToken() returns it, and update the active tenant) —\n * the SDK never stores credentials. Awaited before the chat reconnects. */\n onSession?: (session: AdasSession) => void | Promise<void>;\n}\n\n/** A tenant-scoped session minted by the platform (e.g. via switchTenant). */\nexport interface AdasSession {\n jwt: string;\n tenant: { id: string; name: string };\n actor: { id: string; email: string | null; roles: string[] };\n}\n\nlet _config: AdasConfig | null = null;\n\n/** Register the SDK configuration. Call once at app start, before any other\n * SDK API. Calling again replaces the config (e.g. env switch) — combine\n * with chat.clearChat() and closeChatStream() for a clean swap. */\nexport function initAdas(config: AdasConfig): void {\n _config = config;\n}\n\nexport function isAdasInitialized(): boolean {\n return _config !== null;\n}\n\nexport function getConfig(): AdasConfig {\n if (!_config) {\n throw new Error('[adas] SDK not initialized — call initAdas(config) before using any ADAS API');\n }\n return _config;\n}\n\nfunction resolveUrl(src: UrlSource): string {\n return (typeof src === 'function' ? src() : src).replace(/\\/$/, '');\n}\n\nexport function getCoreApiUrl(): string {\n return resolveUrl(getConfig().coreUrl);\n}\n\nexport function getCoreWsUrl(): string {\n return getCoreApiUrl().replace(/^http/, 'ws');\n}\n\nexport function getVoiceApiUrl(): string {\n const url = getConfig().voiceUrl;\n if (!url) throw new Error('[adas] voiceUrl not configured');\n return resolveUrl(url);\n}\n\nexport function getConsumerAuthApiUrl(): string {\n const url = getConfig().consumerAuthUrl;\n if (!url) throw new Error('[adas] consumerAuthUrl not configured — required for switchTenant()');\n return resolveUrl(url);\n}\n\nexport function getTenant(): string {\n const t = getConfig().tenant;\n return (typeof t === 'function' ? t() : t) || '';\n}\n\nexport function getUser(): AdasUser | null {\n return getConfig().getUser?.() || null;\n}\n\n// ─── Internal token helpers (thin wrappers over the host's TokenProvider) ──\n\nexport function getToken(): string | null {\n return getConfig().tokenProvider.getToken();\n}\n\nexport async function refreshToken(): Promise<RefreshOutcome> {\n return getConfig().tokenProvider.refresh();\n}\n\nexport function notifyAuthFailure(): void {\n getConfig().tokenProvider.onAuthFailure?.();\n}\n","import { getCoreApiUrl, getVoiceApiUrl, getToken, refreshToken, notifyAuthFailure } from '../config';\n\ntype FetchOptions = RequestInit & {\n baseUrl?: 'core' | 'voice';\n};\n\n/**\n * Base API client with JWT injection and 401 refresh handling.\n *\n * Auth failure semantics (preserved from the reference app): a transient\n * 5xx or network blip on the RETRY after a successful refresh must NOT be\n * treated as sign-out. notifyAuthFailure() fires only when auth is genuinely\n * broken:\n * - Refresh itself was rejected with 401/403 → auth failure\n * - Retry with the fresh JWT still returns 401/403 → auth failure\n * Anything else throws but keeps the session intact — the caller may retry\n * on the next user action.\n */\nexport async function apiFetch<T = unknown>(\n path: string,\n options: FetchOptions = {},\n): Promise<T> {\n const { baseUrl = 'core', ...fetchOptions } = options;\n const base = baseUrl === 'voice' ? getVoiceApiUrl() : getCoreApiUrl();\n const url = `${base}${path}`;\n\n const token = getToken();\n\n const headers: Record<string, string> = {\n ...(fetchOptions.headers as Record<string, string>),\n };\n\n if (token && !headers['Authorization']) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Note: we intentionally DO NOT send a tenant header. The backend derives\n // the tenant from the JWT — a client-supplied tenant paired with a leaked\n // JWT is a tenant-pivot footgun. Tenant comes from the token, not the client.\n\n if (!headers['Content-Type'] && fetchOptions.body && typeof fetchOptions.body === 'string') {\n headers['Content-Type'] = 'application/json';\n }\n\n const res = await fetch(url, { ...fetchOptions, headers });\n\n if (res.status === 401 && token) {\n console.warn(`[adas] 401 on ${path} — attempting refresh`);\n const outcome = await refreshToken();\n if (outcome.ok === 'ok') {\n const newToken = getToken();\n headers['Authorization'] = `Bearer ${newToken}`;\n const retryRes = await fetch(url, { ...fetchOptions, headers });\n if (retryRes.ok) {\n return retryRes.json() as Promise<T>;\n }\n if (retryRes.status === 401 || retryRes.status === 403) {\n // Still auth-broken with a fresh JWT — genuinely dead session.\n console.warn(`[adas] retry after refresh still ${retryRes.status} on ${path} — auth failure`);\n notifyAuthFailure();\n throw new Error('Session expired');\n }\n // Non-auth error on retry. Surface it, but the session is fine.\n const text = await retryRes.text().catch(() => '');\n throw new Error(`API ${retryRes.status}: ${text}`);\n }\n if (outcome.ok === 'auth_failed') {\n console.warn(`[adas] refresh auth_failed on ${path} (${outcome.reason}) — auth failure`);\n notifyAuthFailure();\n throw new Error('Session expired');\n }\n // 'transient' — network/5xx on refresh. Keep the session; surface the 401.\n throw new Error(`API 401: refresh transient (${outcome.reason})`);\n }\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API ${res.status}: ${text}`);\n }\n\n return res.json() as Promise<T>;\n}\n\n/**\n * Fetch with raw response (non-JSON responses, streaming bodies).\n */\nexport async function apiFetchRaw(\n path: string,\n options: FetchOptions = {},\n): Promise<Response> {\n const { baseUrl = 'core', ...fetchOptions } = options;\n const base = baseUrl === 'voice' ? getVoiceApiUrl() : getCoreApiUrl();\n const url = `${base}${path}`;\n\n const token = getToken();\n const headers: Record<string, string> = {\n ...(fetchOptions.headers as Record<string, string>),\n };\n\n if (token && !headers['Authorization']) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n return fetch(url, { ...fetchOptions, headers });\n}\n","/**\n * Shared MCP client — single API layer for ALL plugin communication.\n *\n * Two call patterns:\n * 1. connectorCall(connectorId, tool, args) → POST /api/connectors/:id/call\n * 2. mcpFetch(body) → POST /mcp (raw JSON-RPC passthrough)\n */\nimport { apiFetchRaw } from './client';\n\n/**\n * Call a tool on a specific connector via POST /api/connectors/:id/call.\n *\n * NOTE: intentionally bypasses the /mcp proxy (which routes to adas-mcp).\n * adas-mcp only knows skill-generated tools, NOT raw connector tools like\n * triggers.list — the direct connector API is the reliable path.\n */\nexport async function connectorCall(\n connectorId: string,\n tool: string,\n args: Record<string, any> = {},\n): Promise<{ ok: boolean; result: any; error?: string }> {\n try {\n const res = await apiFetchRaw(\n `/api/connectors/${encodeURIComponent(connectorId)}/call`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool, args }),\n },\n );\n\n if (!res.ok) {\n const text = await res.text();\n return { ok: false, result: null, error: `HTTP ${res.status}: ${text}` };\n }\n\n const data = await res.json();\n // Normalize: Core may return { ok, result } or raw MCP { content: [...] }\n if (data.ok !== undefined) return data;\n return { ok: true, result: data };\n } catch (err) {\n return { ok: false, result: null, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/** Raw JSON-RPC passthrough to /mcp. Returns the full JSON-RPC response. */\nexport async function mcpFetch(body: any): Promise<any> {\n const res = await apiFetchRaw('/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: typeof body === 'string' ? body : JSON.stringify(body),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`MCP fetch failed: HTTP ${res.status}: ${text}`);\n }\n\n return res.json();\n}\n\n/** JSON-RPC tools/call to /mcp (for core tools like cp.fe_api). */\nexport async function mcpToolCall(\n toolName: string,\n args: Record<string, any> = {},\n): Promise<any> {\n return mcpFetch({\n jsonrpc: '2.0',\n id: Date.now(),\n method: 'tools/call',\n params: { name: toolName, arguments: args },\n });\n}\n\n/** Post a plugin command result back to Core. */\nexport async function postCommandResult(\n correlationId: string,\n result: any,\n error?: string,\n): Promise<void> {\n await apiFetchRaw('/api/plugin-command-result', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ correlationId, result, error }),\n });\n}\n\n/**\n * Unwrap MCP JSON-RPC text content → parsed business data.\n * Server returns: { content: [{ type: \"text\", text: \"{...}\" }] }\n */\nexport function unwrapMcpResult(result: any): any {\n if (!result) return result;\n if (!result.content) return result;\n const textItem = Array.isArray(result.content)\n ? result.content.find((c: any) => c.type === 'text')\n : null;\n if (!textItem?.text) return result;\n try {\n return JSON.parse(textItem.text);\n } catch {\n return textItem.text;\n }\n}\n","// packages/core/src/session.ts\n//\n// THE single answer to \"where am I / what am I talking to / who am I\", derived\n// from the SDK config the REQUESTS themselves use — getTenant / getConsumerAuthApiUrl\n// / getCoreApiUrl / getUser. Because the label reads from the same place the\n// request reads, they cannot disagree. Host-agnostic: any host that calls\n// initAdas() gets a correct session with no parallel copy to drift.\n//\n// Rule: DERIVE, NEVER STORE — see Docs/DERIVE_NEVER_STORE.md. This lives in the\n// SDK (not a host app) so iOS/Android/RN hosts share one derivation; the host's\n// React hook (e.g. useSession) is a thin wrapper that just re-renders on change.\n\nimport { getTenant, getConsumerAuthApiUrl, getCoreApiUrl, getUser } from './config';\n\nexport type SessionEnv = 'dev' | 'prod';\n\nexport interface Session {\n /** Tenant slug the app is actually scoped to (getTenant = signed-in tenant,\n * falling back to the pre-auth choice). Null when neither is set. */\n tenant: string | null;\n /** Human label for the tenant — slug today; callers must not compute their own. */\n tenantName: string;\n /** dev | prod — derived from the resolved host, never a stored word. */\n env: SessionEnv;\n /** The actual backend host — a host can't be ambiguous the way a word can. */\n host: string;\n actorId: string | null;\n email: string | null;\n}\n\nfunction hostOf(u: string | undefined | null): string {\n if (!u) return '';\n try { return new URL(u).host; } catch { return u; }\n}\n\n/** Is a resolved base URL a dev backend? Keyed on the hostname (dev-app…,\n * dev-consumer-auth…) so it matches wherever the request goes. */\nexport function isDevHost(u: string | undefined | null): boolean {\n const h = hostOf(u);\n return !!h && (h.includes('dev-') || /(^|\\.)dev\\./.test(h));\n}\n\n/** Compute the session from the live SDK config. Plain function — a host hook\n * wraps this for reactivity; imperative code can call it directly. */\nexport function getSession(): Session {\n let consumerUrl = '';\n try { consumerUrl = getConsumerAuthApiUrl(); } catch { /* not configured yet */ }\n let coreUrl = '';\n try { coreUrl = getCoreApiUrl(); } catch { /* not configured yet */ }\n\n const tenant = getTenant() || null;\n const user = getUser();\n\n return {\n tenant,\n tenantName: tenant || '—',\n env: isDevHost(consumerUrl) || isDevHost(coreUrl) ? 'dev' : 'prod',\n host: hostOf(consumerUrl || coreUrl),\n actorId: user?.actorId ?? null,\n email: user?.email ?? null,\n };\n}\n","/**\n * Chat store — talks to the ADAS Core API.\n *\n * Flow:\n * 1. loadConversation() → GET /api/conversation → display history\n * 2. sendMessage(text) → POST /api/chat { goal } → returns jobId\n * 3. WebSocket (poll fallback) → real-time progress\n * 4. When done → GET /api/conversation → formatted response\n *\n * Platform notes: no Expo/AsyncStorage imports. Attachment persistence is\n * delegated to the host via config.attachmentCache; identity and tokens come\n * from the host via initAdas().\n */\nimport { create } from 'zustand';\nimport { getCoreApiUrl, getCoreWsUrl, getToken, getTenant, getUser, getConfig } from '../config';\nimport { pluginCommandEmitter } from '../utils/emitter';\nimport type { OutgoingAttachment } from '../storage/types';\nimport type { Message, MessageAttachment, JobProgress, UIAction } from './types';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ChatState {\n messages: Message[];\n loading: boolean;\n error: string | null;\n activeJobId: string | null;\n conversationLoaded: boolean;\n /** Load conversation history from Core */\n loadConversation: () => Promise<void>;\n /** Send a message via POST /api/chat — creates a job, streams progress */\n sendMessage: (text: string, skillSlug?: string, attachments?: OutgoingAttachment[]) => Promise<void>;\n /** Respond to a paused sys.askUser question */\n respondToQuestion: (jobId: string, inputId: string, answer: string) => Promise<void>;\n /** Update in-flight job progress (called by the stream handler) */\n updateJobProgress: (jobId: string, progress: Partial<JobProgress>) => void;\n /** Reset chat (also re-fetches history on next mount — used on auth switch) */\n clearChat: () => void;\n /** Start a fresh empty chat without re-fetching history */\n newChat: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction coreHeaders(): Record<string, string> {\n const token = getToken();\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (token) headers['Authorization'] = `Bearer ${token}`;\n return headers;\n}\n\nfunction isTerminalStatus(status?: unknown): boolean {\n const s = typeof status === 'string' ? status.toLowerCase() : '';\n return s === 'done' || s === 'error' || s === 'failed' || s === 'completed';\n}\n\nfunction normalizeJobStatus(snap: any): JobProgress['status'] {\n const status = typeof snap?.status === 'string' ? snap.status.toLowerCase() : '';\n if (status === 'done' || status === 'completed') return 'done';\n if (status === 'error' || status === 'failed') return 'error';\n if (status === 'paused' || status === 'waiting') return 'paused';\n if (status === 'unknown') return 'unknown';\n return 'running';\n}\n\nfunction extractPendingQuestion(snap: any): any {\n return snap?.pendingQuestion || snap?.state?.pendingQuestion || snap?.state?.waiting || null;\n}\n\nfunction extractActorId(snap: any): string | undefined {\n const actorId =\n snap?.actorId ||\n snap?.actor?.actorId ||\n snap?.actor?.id ||\n snap?.state?.actorId ||\n snap?.state?.actor?.actorId ||\n snap?.state?.actor?.id;\n return typeof actorId === 'string' && actorId.length > 0 ? actorId : undefined;\n}\n\nfunction extractLiveProgress(snap: any): JobProgress['liveProgress'] | undefined {\n const lp = snap?.liveProgress || snap?.state?.__live_progress;\n const latest = Array.isArray(lp) ? lp[lp.length - 1] : lp;\n if (!latest?.message) return undefined;\n return {\n message: String(latest.message || ''),\n ...(latest.step != null ? { step: latest.step } : {}),\n ...(latest.total != null ? { total: latest.total } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Extract the most-recently-called tool from job exec steps.\n// snap.state.steps.__exec = { iter_0: [{tool, ok, reason}], iter_1: [...] }\n// ---------------------------------------------------------------------------\nfunction extractCurrentTool(state: any): string | undefined {\n const exec = state?.steps?.__exec;\n if (!exec || typeof exec !== 'object') return undefined;\n const latest = Object.keys(exec)\n .map(k => ({ k, n: parseInt(k.replace('iter_', ''), 10) }))\n .filter(({ n }) => !isNaN(n))\n .sort((a, b) => b.n - a.n)[0];\n if (!latest) return undefined;\n const steps = exec[latest.k];\n if (!Array.isArray(steps) || !steps.length) return undefined;\n const last = steps[steps.length - 1];\n return (last?.tool || last?.phase) as string | undefined;\n}\n\nfunction snapshotToProgress(snap: any, rootJobId: string): Partial<JobProgress> {\n const pq = extractPendingQuestion(snap);\n const progress: Partial<JobProgress> = {\n jobId: rootJobId,\n actorId: extractActorId(snap),\n status: pq ? 'paused' : normalizeJobStatus(snap),\n subStatus: snap?.subStatus || snap?.phase || snap?.state?.visual?.phase,\n phase: snap?.phase || snap?.state?.visual?.phase,\n iteration: snap?.iteration || snap?.state?.plannerIter,\n skillSlug: snap?.skillSlug || snap?.activeSkill,\n currentTool: snap?.currentTool || snap?.lastTool || extractCurrentTool(snap?.state),\n };\n\n const liveProgress = extractLiveProgress(snap);\n if (liveProgress) progress.liveProgress = liveProgress;\n\n // Human-language status (additive; absent when disabled/uncached).\n if (typeof snap?.humanStatus === 'string' && snap.humanStatus) progress.humanStatus = snap.humanStatus;\n if (snap?.humanLabels && typeof snap.humanLabels === 'object') progress.humanLabels = snap.humanLabels;\n\n if (pq) {\n progress.pendingQuestion = {\n inputId: pq.correlation_id || pq.correlationId || pq.inputId || '',\n question: pq.prompt_message || pq.question || 'The assistant needs your input',\n inputType: pq.inputType || 'text',\n options: pq.options || pq.requested_fields,\n placeholder: pq.placeholder,\n };\n }\n\n return progress;\n}\n\nfunction isTerminalSnapshot(snap: any): boolean {\n if (extractPendingQuestion(snap)) return false;\n return snap?.done === true || isTerminalStatus(snap?.status);\n}\n\n/**\n * Sentinel delimiters used to embed structured table data inside a flat\n * message string. UI layers split on these and render the contents with a\n * native table component instead of markdown tables — markdown tables look\n * terrible on narrow phone screens.\n *\n * Unicode Private Use Area chars (U+E100/U+E101) so they never collide with\n * anything the model could legitimately emit.\n */\nexport const TABLE_BLOCK_OPEN = '\\uE100';\nexport const TABLE_BLOCK_CLOSE = '\\uE101';\n\n/**\n * Render a `{ columns: [...], rows: [...] }` payload as a sentinel-wrapped\n * JSON marker. Returns null if the shape doesn't match.\n */\nfunction renderTableShape(content: any): string | null {\n if (!content || typeof content !== 'object') return null;\n const cols = Array.isArray(content.columns) ? content.columns : null;\n const rows = Array.isArray(content.rows) ? content.rows : null;\n if (!cols || !rows) return null;\n // encodeURIComponent so the JSON can never contain newlines or sentinel chars.\n const payload = encodeURIComponent(JSON.stringify({ columns: cols, rows }));\n return `${TABLE_BLOCK_OPEN}${payload}${TABLE_BLOCK_CLOSE}`;\n}\n\n/**\n * Extract display text from a conversation turn's assistant blocks.\n * Handles multiple block kinds (text, code, json, markdown, table, html).\n */\nexport function blocksToText(blocks?: Array<{ kind: string; content: any }>): string {\n if (!blocks || blocks.length === 0) return '';\n // Mirror the web renderer: when a human-readable text/markdown block exists in\n // the same turn, drop internal-state json/code blocks (planning state,\n // askUser payloads) — otherwise they render as a raw ```json blob AFTER the\n // real answer. Standalone json/code (no text block, e.g. a table-only turn)\n // still renders as before.\n const hasTextBlock = blocks.some(\n b => b.kind === 'text' || b.kind === 'markdown' || b.kind === 'description',\n );\n return blocks.map(b => {\n if ((b.kind === 'json' || b.kind === 'code') && hasTextBlock) return '';\n if (b.kind === 'text' || b.kind === 'markdown' || b.kind === 'description') {\n return typeof b.content === 'string' ? b.content : '';\n }\n if (b.kind === 'code') {\n const code = typeof b.content === 'object' ? b.content.content : b.content;\n return `\\`\\`\\`\\n${code}\\n\\`\\`\\``;\n }\n if (b.kind === 'table' && b.content && typeof b.content === 'object') {\n const md = renderTableShape(b.content);\n if (md) return md;\n // Fall through to generic JSON rendering if shape is unexpected.\n }\n if (b.kind === 'json') {\n // Skip pendingQuestion state objects — internal sys.askUser data\n if (b.content && typeof b.content === 'object' && 'pendingQuestion' in b.content) return '';\n // Polisher sometimes wraps tables as kind:'json' when the content has\n // columns/rows — render those as table blocks too.\n const md = renderTableShape(b.content);\n if (md) return md;\n return '```json\\n' + JSON.stringify(b.content, null, 2) + '\\n```';\n }\n if (b.kind === 'html') {\n return typeof b.content === 'string' ? b.content : '';\n }\n return typeof b.content === 'string' ? b.content : JSON.stringify(b.content);\n }).filter(Boolean).join('\\n\\n');\n}\n\n/** Extract image/file attachments from conversation blocks */\nfunction blocksToAttachments(blocks?: Array<{ kind: string; hash?: string; url?: string; mimeType?: string; name?: string }>): MessageAttachment[] | undefined {\n if (!blocks || blocks.length === 0) return undefined;\n const atts: MessageAttachment[] = [];\n for (const b of blocks) {\n if ((b.kind === 'image' || b.kind === 'file') && (b.url || b.hash)) {\n atts.push({\n mimeType: b.mimeType || (b.kind === 'image' ? 'image/jpeg' : 'application/octet-stream'),\n name: b.name || 'attachment',\n previewUri: b.url ? `${getCoreApiUrl()}${b.url}` : undefined,\n });\n }\n }\n return atts.length > 0 ? atts : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\n\nexport const useChatStore = create<ChatState>((set, get) => ({\n messages: [],\n loading: false,\n error: null,\n activeJobId: null,\n conversationLoaded: false,\n\n // -----------------------------------------------------------------------\n // Load conversation history from Core\n // GET /api/conversation → array of turns [{user, assistant, jobId, ...}]\n // -----------------------------------------------------------------------\n loadConversation: async () => {\n try {\n const attachmentCache = getConfig().attachmentCache;\n await attachmentCache?.ready();\n\n const res = await fetch(`${getCoreApiUrl()}/api/conversation?limit=20`, {\n headers: coreHeaders(),\n });\n if (!res.ok) {\n console.warn('[adas-chat] Failed to load conversation:', res.status);\n set({ conversationLoaded: true });\n return;\n }\n\n const data = await res.json();\n if (!data.ok || !data.items) {\n set({ conversationLoaded: true });\n return;\n }\n\n // Persisted turns from /api/conversation are the SOLE source of history.\n // Live job state is mirrored only via WS into the placeholder bubble\n // created by sendMessage; in-flight local state is preserved below.\n const items: any[] = [...data.items].reverse();\n const persistedMessages: Message[] = [];\n const seenJobIds = new Set<string>();\n for (const turn of items) {\n // Deduplicate by jobId (chain jobs can produce duplicate turns)\n if (turn.jobId && seenJobIds.has(turn.jobId)) continue;\n if (turn.jobId) seenJobIds.add(turn.jobId);\n\n // User message\n const userText = blocksToText(turn.user?.blocks);\n let userAtts = blocksToAttachments(turn.user?.blocks);\n // Merge locally cached attachments if API doesn't have them\n if (!userAtts && turn.jobId) {\n userAtts = attachmentCache?.get(turn.jobId);\n }\n const turnChainId = typeof turn.chainId === 'string' ? turn.chainId : undefined;\n if (userText || userAtts) {\n persistedMessages.push({\n id: `user-${turn.jobId}`,\n role: 'user',\n content: userText || '',\n timestamp: new Date(turn.startedAt || Date.now()),\n skillSlug: turn.skillSlug,\n ...(userAtts ? { attachments: userAtts } : {}),\n ...(turnChainId ? { chainId: turnChainId } : {}),\n });\n }\n // Assistant response\n const assistantText = blocksToText(turn.assistant?.blocks);\n const assistantAtts = blocksToAttachments(turn.assistant?.blocks);\n const assistantActions = Array.isArray(turn.assistant?.actions) ? turn.assistant.actions : undefined;\n const turnKind = typeof turn.kind === 'string' ? turn.kind : undefined;\n if (assistantText || assistantAtts || assistantActions?.length) {\n persistedMessages.push({\n id: `bot-${turn.jobId}`,\n role: 'assistant',\n content: assistantText || '',\n timestamp: new Date(turn.finishedAt || turn.startedAt || Date.now()),\n skillSlug: turn.skillSlug,\n ...(assistantAtts ? { attachments: assistantAtts } : {}),\n ...(assistantActions?.length ? { actions: assistantActions } : {}),\n ...(turnChainId ? { chainId: turnChainId } : {}),\n ...(turnKind ? { kind: turnKind } : {}),\n });\n }\n }\n\n // Preserve in-flight LOCAL state across pull-to-refresh. /api/conversation\n // is the truth for HISTORY; anything mid-flight lives only as a local\n // WS-driven placeholder created by sendMessage.\n const current = get().messages;\n const keptPlaceholders: Message[] = [];\n for (const m of current) {\n if (!m.id.startsWith('job-') || !m.jobProgress || !m.chainId) continue;\n const matchIdx = persistedMessages.findIndex(pm =>\n pm.role === 'assistant' && pm.chainId === m.chainId\n );\n if (matchIdx >= 0) {\n // The persisted turn for this chain has arrived. Move the live\n // progress overlay (pill) onto it — but only while still in flight.\n const st = m.jobProgress.status;\n if (st === 'running' || st === 'paused') {\n persistedMessages[matchIdx] = { ...persistedMessages[matchIdx], jobProgress: m.jobProgress };\n }\n // Drop the placeholder either way.\n } else {\n // No persisted turn yet — chain still in flight. Keep it.\n keptPlaceholders.push(m);\n }\n }\n\n // Optimistic user bubbles (id=`user-<ms>` from sendMessage). Keep until\n // a persisted user turn arrives. Dedup by chainId — content match has\n // false positives (\"Yes\", \"Continue\", etc.).\n const isLocalUserId = (id: string) => /^user-\\d+$/.test(id);\n const keptUserBubbles = current.filter(m => {\n if (m.role !== 'user' || !isLocalUserId(m.id)) return false;\n if (!m.chainId) return true; // POST in flight — can't dedup yet\n return !persistedMessages.some(pm =>\n pm.role === 'user' && pm.chainId === m.chainId\n );\n });\n\n const finalMessages = [...persistedMessages, ...keptUserBubbles, ...keptPlaceholders];\n finalMessages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n\n let firstRunning: Message | undefined = keptPlaceholders.find(m => m.jobProgress?.status === 'running');\n\n // Cold-start / post-refresh reattach: WS subscriptions die on app\n // restart. Fetch ALL active chains for this actor (chain-native SlimChain\n // API) and reattach EACH — multiple concurrent chains must all come back\n // in progress, not just the most-recently-updated one. Falls back to the\n // legacy single-chain /api/chain/current on older backends.\n try {\n let activeChains: any[] = [];\n const chainsRes = await fetch(`${getCoreApiUrl()}/api/chains/active`, {\n headers: coreHeaders(),\n });\n if (chainsRes.ok) {\n const body = await chainsRes.json();\n activeChains = Array.isArray(body?.chains) ? body.chains : [];\n } else {\n // Legacy backend without the plural endpoint — single most-recent chain.\n const legacy = await fetch(`${getCoreApiUrl()}/api/chain/current`, {\n headers: coreHeaders(),\n });\n if (legacy.ok) {\n const lb = await legacy.json();\n if (lb?.data?.id) activeChains = [lb.data];\n }\n }\n\n for (const slim of activeChains) {\n if (!slim?.id) continue;\n const chainId = String(slim.id);\n const alreadyTracked = finalMessages.some(m =>\n m.role === 'assistant' && m.jobProgress?.jobId === chainId\n );\n if (alreadyTracked) continue;\n\n // Chain-native status: prefer the whole-chain aggregate (chainStatus)\n // over the active job's per-job status, so e.g. a chain still running\n // across a handoff isn't shown as \"done\". A pending question still\n // overrides to \"paused\" inside snapshotToProgress.\n const progress = snapshotToProgress(\n { ...slim, status: slim.chainStatus || slim.status },\n chainId,\n );\n const chainCreatedAt = typeof slim.createdAt === 'number'\n ? slim.createdAt\n : (typeof slim.lastUpdate === 'number' ? slim.lastUpdate : Date.now());\n const chainLastUpdate = typeof slim.lastUpdate === 'number' ? slim.lastUpdate : chainCreatedAt;\n const jobProgress = {\n jobId: chainId,\n actorId: extractActorId(slim),\n status: 'running',\n chainStartedAt: chainCreatedAt,\n ...progress,\n } as JobProgress;\n\n // Synthesize the user bubble if a hard refresh wiped the optimistic\n // one and the chain hasn't persisted its turn yet.\n const goal = typeof slim.goal === 'string' ? slim.goal : '';\n const userExists = finalMessages.some(m =>\n m.role === 'user' && (m.chainId === chainId || (goal && m.content === goal))\n );\n if (goal && !userExists) {\n finalMessages.push({\n id: `user-${chainId}`,\n role: 'user',\n content: goal,\n timestamp: new Date(chainCreatedAt),\n chainId,\n });\n }\n\n // Assistant side: attach to matching persisted turn if one exists;\n // otherwise push a placeholder bubble.\n let matchIdx = -1;\n for (let i = finalMessages.length - 1; i >= 0; i--) {\n const m = finalMessages[i];\n if (m.role === 'assistant' && m.chainId === chainId) {\n matchIdx = i;\n break;\n }\n }\n if (matchIdx >= 0) {\n finalMessages[matchIdx] = { ...finalMessages[matchIdx], jobProgress };\n if (jobProgress.status === 'running' && !firstRunning) firstRunning = finalMessages[matchIdx];\n } else {\n const reattachBubble: Message = {\n id: `job-${chainId}`,\n role: 'assistant',\n content: 'Working on it...',\n timestamp: new Date(chainLastUpdate),\n jobProgress,\n chainId,\n };\n finalMessages.push(reattachBubble);\n if (jobProgress.status === 'running' && !firstRunning) firstRunning = reattachBubble;\n }\n\n // Re-open the live subscription for this chain.\n streamJob(chainId, getTenant(), getToken());\n }\n\n finalMessages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n } catch {}\n\n set({\n messages: finalMessages,\n conversationLoaded: true,\n error: null,\n activeJobId: firstRunning?.jobProgress?.jobId || null,\n loading: !!firstRunning,\n });\n } catch (err: any) {\n console.warn('[adas-chat] Error loading conversation:', err.message);\n set({ conversationLoaded: true });\n }\n },\n\n // -----------------------------------------------------------------------\n // Send message via Core API\n // POST /api/chat { goal } → { jobId } → stream → fetch turn result\n // -----------------------------------------------------------------------\n sendMessage: async (text: string, skillSlug?: string, attachments?: OutgoingAttachment[]) => {\n // No `if (loading) return` guard: Chain Additions needs the user to send\n // WHILE a chain is running. The backend router decides attach/cancel/new.\n\n const userMsg: Message = {\n id: `user-${Date.now()}`,\n role: 'user',\n content: text,\n timestamp: new Date(),\n ...(attachments?.length ? {\n attachments: attachments.map(a => ({\n mimeType: a.mimeType,\n name: a.name,\n previewUri: a.mimeType.startsWith('image/') ? `data:${a.mimeType};base64,${a.data}` : undefined,\n }))\n } : {}),\n };\n\n set(s => ({ messages: [...s.messages, userMsg], loading: true, error: null }));\n\n try {\n // Backend auto-resolves the skill via conversation continuity → channel\n // routing → default. triggerContext.channel + replyContext.chatId are\n // required by handoff-controller-mcp's schema — without them handoffs\n // fail silently.\n const actor = getUser();\n const body: Record<string, unknown> = {\n goal: text,\n // Opt in to the Chain Additions router (attach/cancel/new while a\n // chain runs). Backend ignores it where not applicable — safe to send.\n chainRouting: true,\n triggerContext: {\n channel: 'mobile',\n replyContext: { chatId: actor?.actorId || 'unknown' },\n },\n };\n if (skillSlug) body.skillSlug = skillSlug;\n if (attachments?.length) body.attachments = attachments;\n\n const res = await fetch(`${getCoreApiUrl()}/api/chat`, {\n method: 'POST',\n headers: coreHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n let errMsg = `Server error (${res.status})`;\n try {\n const text = await res.text();\n // Don't show raw HTML — extract a short message\n if (text.startsWith('<') || text.startsWith('<!')) {\n errMsg = res.status === 502 ? 'Server is temporarily unavailable. Please try again.' : `Server error (${res.status})`;\n } else {\n const parsed = JSON.parse(text);\n errMsg = parsed.error || errMsg;\n }\n } catch {}\n throw new Error(errMsg);\n }\n\n const data = await res.json();\n\n if (!data.ok) {\n throw new Error(data.error || 'Failed to send message');\n }\n\n // Chain Additions: the router may ATTACH this message to the running\n // chain or CANCEL it. These replies carry NO jobId — handle them and\n // don't start a second stream.\n if (data.mode === 'chain_addition' || data.mode === 'chain_cancel') {\n const ack = data.mode === 'chain_addition'\n ? (data.ack || 'Got it — added to the running task.')\n : 'Stopping the task…';\n set(s => ({\n messages: s.messages\n .map(m => (m.id === userMsg.id && data.chainId) ? { ...m, chainId: data.chainId } : m)\n .concat({\n id: `ack-${Date.now()}`,\n role: 'assistant',\n content: ack,\n timestamp: new Date(),\n ...(data.chainId ? { chainId: data.chainId } : {}),\n }),\n }));\n return;\n }\n\n const jobId = data.id || data.jobId;\n if (!jobId) {\n throw new Error('No job ID returned');\n }\n\n // Cache attachments so they survive loadConversation reload. Awaited\n // intentionally — fire-and-forget can lose the write on quick reload.\n if (attachments?.length) {\n await getConfig().attachmentCache?.save(jobId, attachments);\n }\n\n // Placeholder assistant bubble = live mirror of the active chain.\n // Carries chainId so a subsequent loadConversation refresh can adopt\n // this placeholder's progress. For the root job, chainId == jobId.\n const progressMsg: Message = {\n id: `job-${jobId}`,\n role: 'assistant',\n content: 'Working on it...',\n timestamp: new Date(),\n jobProgress: {\n jobId,\n actorId: actor?.actorId,\n status: 'running',\n subStatus: 'Starting...',\n chainStartedAt: Date.now(),\n },\n chainId: jobId,\n };\n\n // Attach chainId to the optimistic user bubble so loadConversation can\n // dedup against persisted user turns by chainId.\n set(s => ({\n messages: s.messages.map(m =>\n m.id === userMsg.id ? { ...m, chainId: jobId } : m\n ).concat(progressMsg),\n activeJobId: jobId,\n }));\n\n // Start streaming for real-time progress\n streamJob(jobId, getTenant(), getToken());\n } catch (err: any) {\n set(s => ({\n messages: [...s.messages, {\n id: `error-${Date.now()}`,\n role: 'system' as const,\n content: `Error: ${err.message}`,\n timestamp: new Date(),\n }],\n loading: false,\n }));\n }\n },\n\n // -----------------------------------------------------------------------\n // Respond to sys.askUser paused question\n // -----------------------------------------------------------------------\n respondToQuestion: async (jobId: string, inputId: string, answer: string) => {\n try {\n const res = await fetch(`${getCoreApiUrl()}/api/job/${jobId}/respond`, {\n method: 'POST',\n headers: coreHeaders(),\n body: JSON.stringify({ inputId, answer }),\n });\n const data = await res.json();\n if (!data.ok) {\n console.warn('[adas-chat] Failed to respond to question:', data.error);\n }\n } catch (err: any) {\n console.warn('[adas-chat] Error responding to question:', err.message);\n }\n },\n\n // -----------------------------------------------------------------------\n // Update job progress (called by the stream handler)\n // -----------------------------------------------------------------------\n updateJobProgress: (jobId: string, progress: Partial<JobProgress>) => {\n set(s => ({\n messages: s.messages.map(m => {\n if (m.jobProgress?.jobId === jobId) {\n const updated = { ...m.jobProgress, ...progress };\n // Clear pendingQuestion when status is no longer paused\n if (progress.status && progress.status !== 'paused') {\n updated.pendingQuestion = undefined;\n }\n // Persisted turns (id `bot-…`) own their content/actions from\n // /api/conversation — the live mirror must never overwrite them.\n const isPersisted = m.id.startsWith('bot-');\n const content = isPersisted\n ? m.content\n : (progress.resultMessage\n || progress.pendingQuestion?.question\n || m.content);\n const actions = isPersisted\n ? m.actions\n : (progress.resultActions?.length ? progress.resultActions : m.actions);\n return {\n ...m,\n jobProgress: updated as JobProgress,\n content,\n ...(actions ? { actions } : {}),\n };\n }\n return m;\n }),\n loading: (progress.status === 'done' || progress.status === 'error' || progress.status === 'paused')\n ? false\n : s.loading,\n activeJobId: (progress.status === 'done' || progress.status === 'error' || progress.status === 'paused')\n ? null\n : s.activeJobId,\n }));\n },\n\n clearChat: () => {\n set({\n messages: [],\n loading: false,\n error: null,\n activeJobId: null,\n conversationLoaded: false,\n });\n },\n newChat: () => {\n set({\n messages: [],\n loading: false,\n error: null,\n activeJobId: null,\n conversationLoaded: true,\n });\n },\n}));\n\n// ---------------------------------------------------------------------------\n// WebSocket Streaming — persistent connection, reused across jobs\n// ---------------------------------------------------------------------------\n\n// Track processed plugin command correlationIds to avoid duplicates\nconst _processedPluginCmds = new Set<string>();\n\nfunction dispatchPluginCommands(cmds: any[]) {\n for (const cmd of cmds) {\n const corrId = cmd?.correlationId || cmd?.correlation_id;\n if (corrId && _processedPluginCmds.has(corrId)) continue;\n if (corrId) _processedPluginCmds.add(corrId);\n\n pluginCommandEmitter.emit('plugin-command', cmd);\n const pluginId = cmd?.pluginId || cmd?.plugin_id || cmd?.args?.plugin_id;\n if (pluginId) {\n const props = cmd?.props ?? cmd?.args?.props ?? undefined;\n pluginCommandEmitter.emit('focus-plugin', { pluginId, props });\n }\n }\n}\n\n// Persistent WS connection — stays open across jobs\nlet _ws: WebSocket | null = null;\nlet _wsReady = false;\nlet _currentJobId: string | null = null;\n\nfunction ensureWs(tenant: string, token: string | null): WebSocket {\n if (_ws && _wsReady) return _ws;\n\n const wsUrl = `${getCoreWsUrl()}/ws?token=${encodeURIComponent(token || '')}&tenant=${encodeURIComponent(tenant)}`;\n const ws = new WebSocket(wsUrl);\n _ws = ws;\n _wsReady = false;\n\n ws.onopen = () => {\n _wsReady = true;\n // If a job is waiting for the connection, subscribe now\n if (_currentJobId) {\n ws.send(JSON.stringify({ type: 'subscribe', jobId: _currentJobId }));\n }\n };\n\n ws.onmessage = (ev) => {\n try {\n const msg = JSON.parse(typeof ev.data === 'string' ? ev.data : '');\n const { event, data } = msg;\n const { updateJobProgress } = useChatStore.getState();\n // Route by the event's OWN chain id — the server streams ALL of the\n // user's active chains down one connection, so each event updates its\n // own bubble. Fall back to the last-subscribed job for older backends.\n const jobId = (data && (data.id || data.chainId)) || _currentJobId;\n\n // Always process plugin_command events even when _currentJobId is null\n // (e.g., during handoff relay)\n if (event === 'plugin_command') {\n dispatchPluginCommands([data]);\n return;\n }\n if (event === 'plugin-command-ack' || event === 'pong') return;\n\n if (!jobId) return;\n\n switch (event) {\n case 'init':\n case 'job':\n case 'update': {\n const snap = data;\n const progress = snapshotToProgress(snap, jobId);\n\n if (isTerminalSnapshot(snap)) {\n // Handoff chain: root job finished but relay job is still running.\n // The backend broadcasts relay progress as synthetic updates on\n // this same subscription — stay subscribed and show running.\n if (snap.status === 'done' && (snap.isHandoff || snap.state?.handoffTransfer)) {\n updateJobProgress(jobId, { status: 'running' });\n return;\n }\n _currentJobId = null;\n if (progress.status === 'paused' && progress.pendingQuestion) {\n updateJobProgress(jobId, progress);\n } else {\n fetchTurnResult(jobId, snap);\n }\n return;\n }\n\n updateJobProgress(jobId, progress);\n break;\n }\n case 'chain_final':\n // Authoritative chain-termination event (fires once when the WHOLE\n // chain is done — handoff-forgiven). Preferred over per-job `final`.\n _currentJobId = null;\n fetchTurnResult(jobId, data);\n break;\n case 'final':\n _currentJobId = null;\n fetchTurnResult(jobId, data);\n break;\n }\n } catch (err) {\n console.warn('[adas-chat] WS parse error:', err);\n }\n };\n\n ws.onerror = () => {\n _ws = null;\n _wsReady = false;\n // Fall back to polling for current job\n if (_currentJobId) {\n const jid = _currentJobId;\n _currentJobId = null;\n pollJob(jid, token);\n }\n };\n\n ws.onclose = () => {\n _ws = null;\n _wsReady = false;\n if (_currentJobId) {\n const jid = _currentJobId;\n _currentJobId = null;\n pollJob(jid, token);\n }\n };\n\n return ws;\n}\n\nfunction streamJob(jobId: string, tenant: string, token: string | null) {\n _currentJobId = jobId;\n const ws = ensureWs(tenant, token);\n\n // If WS is already open, subscribe immediately; otherwise onopen handles it\n if (_wsReady) {\n ws.send(JSON.stringify({ type: 'subscribe', jobId }));\n }\n}\n\n/** Tear down the live connection (env/auth switch, SDK unmount). */\nexport function closeChatStream(): void {\n _currentJobId = null;\n if (_ws) {\n try { _ws.close(); } catch {}\n }\n _ws = null;\n _wsReady = false;\n}\n\n/**\n * When a job completes, fetch the conversation turn to get the formatted\n * response. Falls back to extracting from the job snapshot.\n */\nasync function fetchTurnResult(jobId: string, jobSnap: any) {\n // Clean up dedup set (cap to prevent unbounded growth)\n if (_processedPluginCmds.size > 200) _processedPluginCmds.clear();\n const { updateJobProgress } = useChatStore.getState();\n const status = normalizeJobStatus(jobSnap) === 'error' ? 'error' : 'done';\n\n // Handoff chain: if this job handed off, wait for the chain to settle by\n // polling job status — done:true only when the relay job completes.\n if (jobSnap.isHandoff || jobSnap.state?.handoffTransfer || jobSnap.result?.contentType === 'handoff') {\n try {\n for (let i = 0; i < 40; i++) { // up to ~60s\n const statusRes = await fetch(`${getCoreApiUrl()}/api/job/${jobId}/status`, {\n headers: coreHeaders(),\n });\n if (statusRes.ok) {\n const statusData = await statusRes.json();\n if (statusData.done && !statusData.isHandoff) {\n break;\n }\n updateJobProgress(jobId, { status: 'running' });\n }\n await new Promise(r => setTimeout(r, 1500));\n }\n } catch {}\n }\n\n // Fetch the most recent conversation turn. By actor rather than by jobId,\n // because handoff chains create child jobs — the real reply lives on the\n // LAST child, not on the root job we submitted.\n for (let attempt = 0; attempt < 5; attempt++) {\n try {\n const res = await fetch(`${getCoreApiUrl()}/api/conversation?limit=1`, {\n headers: coreHeaders(),\n });\n\n if (res.ok) {\n const data = await res.json();\n const items = Array.isArray(data.items) ? data.items : [];\n const turn = items[0];\n if (turn?.assistant || turn?.turn?.assistant) {\n const assistant = turn.assistant || turn.turn?.assistant;\n const text = blocksToText(assistant.blocks);\n const actions: UIAction[] | undefined =\n Array.isArray(assistant.actions) && assistant.actions.length\n ? assistant.actions\n : undefined;\n if (text) {\n updateJobProgress(jobId, {\n status,\n resultMessage: text,\n ...(actions ? { resultActions: actions } : {}),\n });\n return;\n }\n }\n }\n } catch {}\n await new Promise(r => setTimeout(r, 800));\n }\n\n // Fallback: extract from job snapshot\n const fallback =\n jobSnap.result?.message ||\n jobSnap.state?.finalReply ||\n (status === 'error' ? 'Something went wrong. Please try again.' : 'Done.');\n\n updateJobProgress(jobId, { status, resultMessage: fallback });\n}\n\n// ---------------------------------------------------------------------------\n// Polling fallback (when WS is unavailable)\n// ---------------------------------------------------------------------------\n\nasync function pollJob(jobId: string, token: string | null) {\n const { updateJobProgress } = useChatStore.getState();\n\n for (let i = 0; i < 120; i++) {\n try {\n const res = await fetch(`${getCoreApiUrl()}/api/job/${jobId}/status`, {\n headers: {\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n });\n\n if (!res.ok) {\n if (res.status === 404) return;\n continue;\n }\n\n const snap = await res.json();\n const progress = snapshotToProgress(snap, jobId);\n\n // sys.askUser — same logic as the WS handler\n if (progress.status === 'paused' && progress.pendingQuestion) {\n updateJobProgress(jobId, progress);\n return; // Stop polling — waiting for user input\n }\n\n updateJobProgress(jobId, progress);\n\n if (isTerminalSnapshot(snap)) {\n fetchTurnResult(jobId, snap);\n return;\n }\n } catch {}\n\n await new Promise(r => setTimeout(r, 1500));\n }\n\n // Timeout\n updateJobProgress(jobId, {\n status: 'error',\n resultMessage: 'Job timed out. Please try again.',\n });\n}\n","/**\n * Lightweight event emitter bridging the chat job stream → plugin bridges\n * (React Native has no Node 'events' module).\n *\n * Events: 'plugin-command' (raw command), 'focus-plugin' ({ pluginId, props }),\n * 'plugin-close' ({ pluginId }), 'prepare-chat-message' ({ text }).\n */\n\ntype Listener = (data: any) => void;\n\nexport interface BufferedCommand {\n pluginId: string;\n command: string;\n args?: any;\n correlationId?: string;\n _bufferedAt: number;\n}\n\nconst RECENT_TTL_MS = 10000;\nconst RECENT_MAX = 20;\n\nexport class PluginCommandEmitter {\n private listeners = new Map<string, Set<Listener>>();\n // Ring buffer of plugin commands seen recently. Lets a plugin that mounts\n // AFTER its first command was emitted (e.g. a surface mounted by the\n // dispatcher in response to focus-plugin) still pick that command up via\n // `drainPluginCommands(pluginId)`. Self-cleans on TTL + size cap.\n private recent: BufferedCommand[] = [];\n\n on(event: string, fn: Listener): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n this.listeners.get(event)!.add(fn);\n return () => this.off(event, fn);\n }\n\n off(event: string, fn: Listener): void {\n this.listeners.get(event)?.delete(fn);\n }\n\n emit(event: string, data: any): void {\n if (event === 'plugin-command' && data && data.pluginId && data.command && data.command !== '__focus') {\n this.recent.push({\n pluginId: data.pluginId,\n command: data.command,\n args: data.args,\n correlationId: data.correlationId,\n _bufferedAt: Date.now(),\n });\n if (this.recent.length > RECENT_MAX) this.recent.shift();\n }\n this.listeners.get(event)?.forEach((fn) => {\n try { fn(data); } catch {}\n });\n }\n\n /** Pop and return any plugin-commands targeted at `pluginId` that were\n * emitted within the last RECENT_TTL_MS. Used by the native bridge on\n * mount so the surface-dispatcher path doesn't drop the first command. */\n drainPluginCommands(pluginId: string): BufferedCommand[] {\n const now = Date.now();\n const out: BufferedCommand[] = [];\n const remaining: BufferedCommand[] = [];\n for (const cmd of this.recent) {\n if (now - cmd._bufferedAt > RECENT_TTL_MS) continue; // expired, drop\n if (cmd.pluginId === pluginId) out.push(cmd);\n else remaining.push(cmd);\n }\n this.recent = remaining;\n return out;\n }\n}\n\n/** App-wide bus for plugin commands arriving over the chat stream. */\nexport const pluginCommandEmitter = new PluginCommandEmitter();\n","import { getConsumerAuthApiUrl, getToken, getConfig, type AdasSession } from '../config';\nimport { useChatStore, closeChatStream } from '../chat/store';\n\nexport interface TenantMembership {\n id: string;\n name: string;\n role: string | null;\n}\n\n/**\n * List the tenants the CURRENT user belongs to (GET /api/tenants/list).\n *\n * The list is membership-scoped: for consumer JWTs the backend returns ONLY\n * tenants where the user's login identity (google/apple oauth or embed id)\n * has an active actor; builder JWTs get their user-doc memberships. It never\n * leaks the full tenant list. Returns [] when signed out or unknown.\n */\nexport async function listMyTenants(): Promise<TenantMembership[]> {\n const token = getToken();\n if (!token) return [];\n try {\n const res = await fetch(`${getConsumerAuthApiUrl()}/platform/consumer/my-tenants`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n const data = await res.json().catch(() => null);\n if (!res.ok || !data?.ok || !Array.isArray(data.tenants)) return [];\n return data.tenants.map((t: any) => ({\n id: t.id,\n name: t.name || t.id,\n role: t.role ?? null,\n }));\n } catch {\n return [];\n }\n}\n\n/**\n * Re-scope the whole session to another tenant the user already belongs to.\n *\n * The backend treats the JWT tenant claim as the sole source of truth, so\n * switching = minting a fresh JWT for the target tenant's actor. The SDK\n * owns the call (POST consumer-auth /platform/consumer/switch-tenant, authed\n * by the current token); the HOST persists the new session via\n * `config.onSession` (the SDK never stores credentials). The chat stream is\n * then torn down and cleared so it reconnects against the new tenant.\n *\n * Requires `consumerAuthUrl` and `onSession` in the initAdas() config.\n * Throws on any non-OK response (e.g. not a member of the target tenant).\n */\nexport async function switchTenant(targetTenantId: string): Promise<AdasSession> {\n const token = getToken();\n if (!token) throw new Error('[adas] switchTenant: not signed in');\n\n const res = await fetch(`${getConsumerAuthApiUrl()}/platform/consumer/switch-tenant`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ target_tenant: targetTenantId }),\n });\n\n const data = await res.json().catch(() => null);\n if (!res.ok || !data?.ok || !data.jwt) {\n throw new Error(data?.error || `switchTenant failed (${res.status})`);\n }\n\n const session: AdasSession = {\n jwt: data.jwt,\n tenant: data.tenant,\n actor: data.actor,\n };\n\n // Host persists the new token + active tenant BEFORE we reconnect, so the\n // fresh stream/requests pick up the target-tenant credentials.\n const onSession = getConfig().onSession;\n if (!onSession) {\n throw new Error('[adas] switchTenant: config.onSession is required to persist the new session');\n }\n await onSession(session);\n\n // Tear down the old-tenant stream and history; the chat screen reloads\n // against the new tenant on its next mount / loadConversation().\n closeChatStream();\n useChatStore.getState().clearChat();\n\n return session;\n}\n","// ADAS design tokens — shared by @ateam-ai-mobile/ui and host apps that want to match.\n\nexport const colors = {\n dark: {\n bgPrimary: '#0a0e14',\n bgSecondary: '#111820',\n bgTertiary: '#1a2230',\n bgInput: '#0d1219',\n bgHover: '#1e2a3a',\n border: 'rgba(255, 255, 255, 0.08)',\n borderHover: 'rgba(255, 255, 255, 0.15)',\n textPrimary: '#e8ecf1',\n textSecondary: '#8b95a5',\n textMuted: '#5a6577',\n accent: '#2563eb',\n accentHover: '#3b82f6',\n accentSoft: 'rgba(37, 99, 235, 0.15)',\n green: '#16a34a',\n greenSoft: 'rgba(22, 163, 74, 0.15)',\n red: '#dc2626',\n redSoft: 'rgba(220, 38, 38, 0.15)',\n amber: '#f59e0b',\n amberSoft: 'rgba(245, 158, 11, 0.15)',\n purple: '#8b5cf6',\n purpleSoft: 'rgba(139, 92, 246, 0.15)',\n // Message-specific\n userBubble: '#2563eb',\n botBubble: '#1a2230',\n botBubbleBorder: 'rgba(255, 255, 255, 0.08)',\n },\n light: {\n bgPrimary: '#ffffff',\n bgSecondary: '#f8f9fa',\n bgTertiary: '#f1f3f5',\n bgInput: '#ffffff',\n bgHover: '#e9ecef',\n border: 'rgba(0, 0, 0, 0.08)',\n borderHover: 'rgba(0, 0, 0, 0.15)',\n textPrimary: '#1a1a2e',\n textSecondary: '#6b7280',\n textMuted: '#9ca3af',\n accent: '#2563eb',\n accentHover: '#1d4ed8',\n accentSoft: 'rgba(37, 99, 235, 0.1)',\n green: '#16a34a',\n greenSoft: 'rgba(22, 163, 74, 0.1)',\n red: '#dc2626',\n redSoft: 'rgba(220, 38, 38, 0.1)',\n amber: '#f59e0b',\n amberSoft: 'rgba(245, 158, 11, 0.1)',\n purple: '#8b5cf6',\n purpleSoft: 'rgba(139, 92, 246, 0.1)',\n userBubble: '#2563eb',\n botBubble: '#f1f3f5',\n botBubbleBorder: 'rgba(0, 0, 0, 0.08)',\n },\n} as const;\n\n// Ada palette — warm, paper, personal. Used by the consumer chat experience.\nexport const ada = {\n paper: '#FAF6EE',\n paperSoft: '#F2EADC',\n paperDeep: '#EBE0CC',\n ink: '#1a1410',\n inkSoft: '#5a4d3f',\n inkMuted: '#9a8870',\n border: 'rgba(26, 20, 16, 0.08)',\n borderStrong: 'rgba(26, 20, 16, 0.16)',\n orange: '#FF7A28',\n orangeDeep: '#B8410A',\n orangeSoft: 'rgba(255, 122, 40, 0.14)',\n userBubble: '#1a1410',\n userBubbleText: '#FAF6EE',\n botBubble: '#F2EADC',\n botBubbleBorder: 'rgba(26, 20, 16, 0.06)',\n botBubbleText: '#1a1410',\n} as const;\n\nexport const spacing = {\n xs: 4,\n sm: 8,\n md: 12,\n lg: 16,\n xl: 20,\n xxl: 24,\n xxxl: 32,\n} as const;\n\nexport const fontSize = {\n xs: 11,\n sm: 13,\n md: 15,\n lg: 17,\n xl: 20,\n xxl: 24,\n title: 28,\n} as const;\n\nexport const borderRadius = {\n sm: 8,\n md: 12,\n lg: 16,\n xl: 20,\n full: 9999,\n} as const;\n","/**\n * ACS host DI seams. Both optional — the ACS layer works without them:\n * no reachability reporting, and the home-actions cache lives in memory only.\n */\n\n/** Host hook fired on every ACS fetch outcome — a response (any status)\n * proves the server is reachable; a thrown fetch means it isn't. The\n * reference app wires this to its connectivity banner store. */\nexport interface AcsReachabilityReporter {\n up: () => void;\n down: () => void;\n}\n\nlet _reachability: AcsReachabilityReporter | null = null;\n\nexport function setAcsReachabilityReporter(r: AcsReachabilityReporter | null): void {\n _reachability = r;\n}\n\nexport function reportAcsServerUp(): void {\n try { _reachability?.up(); } catch {}\n}\n\nexport function reportAcsServerDown(): void {\n try { _reachability?.down(); } catch {}\n}\n\n/** Minimal async KV used to persist the home-actions feed across cold starts\n * (AsyncStorage-shaped). @ateam-ai-mobile/expo wires AsyncStorage in\n * setupExpoProviders(); without a provider the cache is a no-op. */\nexport interface AcsKvStorage {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n}\n\nlet _kv: AcsKvStorage | null = null;\n\nexport function setAcsCacheStorage(kv: AcsKvStorage | null): void {\n _kv = kv;\n}\n\nexport function getAcsCacheStorage(): AcsKvStorage | null {\n return _kv;\n}\n","/**\n * Client for Core's /api/acs/* proxy → ACS service. Powers the \"widgets\"\n * surface on home: AI-generated artifacts that render as carousel tiles and\n * full-screen interactive panels via the bundleUrl — plus the home\n * \"top actions\" feed.\n *\n * Endpoints:\n * POST /api/acs/surface — list active artifacts for a surface\n * POST /api/acs/event — usage tracking (clicked/dismissed/etc.)\n * GET /api/acs/made-for-you — full library, all lifecycle stages\n * DELETE /api/acs/artifacts/{id} — user-initiated retire (idempotent)\n * PATCH /api/acs/artifacts/{id} — visibility + rename\n * PUT /api/acs/order — drag-reorder\n * GET /api/acs/home-actions — top-actions feed (+ PATCH/PUT order)\n * WS topics acs.artifacts / acs.home-actions — cross-device sync (see ./ws)\n */\n\nimport { getCoreApiUrl, getToken } from '../config';\nimport { reportAcsServerUp, reportAcsServerDown } from './providers';\n\nexport interface AcsArtifact {\n id: string;\n name: string;\n description?: string;\n iconHint?: string;\n manifest?: Record<string, any>;\n bundleUrl: string;\n version: number;\n provenance?: Record<string, any>;\n\n // Tile-shape fields (consumers branch on these when present; safe defaults\n // when absent).\n kind?: 'user' | 'featured';\n visibility?: 'pinned' | 'hidden';\n pinOrder?: number;\n canDelete?: boolean;\n canRename?: boolean;\n canHide?: boolean;\n previewMode?: 'live' | 'snapshot' | 'none';\n previewUrl?: string;\n}\n\n// Closed-ish enum — accept arbitrary strings so the backend can introduce new\n// surface names without a client release blocking it.\nexport type AcsSurface = 'home' | 'library' | (string & {});\n\n// Closed enum on the backend side.\nexport type AcsEvent = 'clicked' | 'dismissed' | 'acted' | 'ignored';\n\nexport type AcsDeleteReason =\n | 'user_long_press_delete'\n | 'user_swipe_delete'\n | 'user_bulk_delete'\n | (string & {});\n\nexport type AcsPatchReason =\n | 'user_long_press_hide'\n | 'user_long_press_unhide'\n | 'user_long_press_rename'\n | (string & {});\n\nasync function authedFetch(path: string, init?: RequestInit): Promise<Response> {\n const token = getToken();\n try {\n const res = await fetch(`${getCoreApiUrl()}${path}`, {\n ...init,\n headers: {\n 'Content-Type': 'application/json',\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n ...(init?.headers || {}),\n },\n });\n // Any response (even 4xx/5xx) proves the server is reachable.\n reportAcsServerUp();\n return res;\n } catch (e) {\n // Thrown = network error / timeout / DNS / TLS → server unreachable.\n reportAcsServerDown();\n throw e;\n }\n}\n\n/**\n * List artifacts surfaced for the given surface name. Returns [] on error\n * (network, auth, or empty result) — callers shouldn't have to distinguish.\n * Use surface=\"home\" for the carousel.\n */\nexport async function listSurface(\n surface: AcsSurface,\n context?: Record<string, any>,\n): Promise<AcsArtifact[]> {\n try {\n const res = await authedFetch('/api/acs/surface', {\n method: 'POST',\n body: JSON.stringify({ surface, ...(context ? { context } : {}) }),\n });\n if (!res.ok) {\n console.warn(`[acs] /surface ${surface} returned ${res.status}`);\n return [];\n }\n const data = await res.json();\n return Array.isArray(data?.items) ? (data.items as AcsArtifact[]) : [];\n } catch (e: any) {\n console.warn('[acs] /surface failed:', e?.message || e);\n return [];\n }\n}\n\n/**\n * Full library — every artifact across all lifecycle stages. Used by a\n * Library screen's Yours + Hidden sections.\n */\nexport async function listMadeForYou(): Promise<AcsArtifact[]> {\n try {\n const res = await authedFetch('/api/acs/made-for-you', { method: 'GET' });\n if (!res.ok) {\n console.warn(`[acs] /made-for-you returned ${res.status}`);\n return [];\n }\n const data = await res.json();\n return Array.isArray(data?.artifacts) ? (data.artifacts as AcsArtifact[]) : [];\n } catch (e: any) {\n console.warn('[acs] /made-for-you failed:', e?.message || e);\n return [];\n }\n}\n\nexport interface DeleteResult {\n ok: boolean;\n /** True when the server already had this artifact retired. Treat as success. */\n already?: boolean;\n /** True for HTTP 404 — artifact gone or never owned by caller. Treat as success\n * (remove from local state) per the backend's contract: no existence leak. */\n notFound?: boolean;\n /** HTTP status returned by the server. */\n status: number;\n error?: string;\n}\n\n/**\n * Retire a user widget. Per backend contract:\n * 200 ok → success\n * 200 ok + already:true → idempotent, treat as success\n * 404 → already gone or not owned, treat as success\n * 5xx / network → real failure, caller should rollback optimistic remove\n */\nexport async function deleteArtifact(\n artifactId: string,\n reason: AcsDeleteReason = 'user_long_press_delete',\n): Promise<DeleteResult> {\n try {\n const res = await authedFetch(\n `/api/acs/artifacts/${encodeURIComponent(artifactId)}`,\n { method: 'DELETE', body: JSON.stringify({ reason }) },\n );\n const data = await res.json().catch(() => ({} as any));\n if (res.ok) {\n return { ok: true, already: !!data?.already, status: res.status };\n }\n if (res.status === 404) {\n return { ok: true, notFound: true, status: 404 };\n }\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\nexport interface PatchResult {\n ok: boolean;\n /** Updated tile when the server returns the new state. */\n artifact?: AcsArtifact;\n already?: boolean;\n notFound?: boolean;\n status: number;\n error?: string;\n}\n\n/**\n * Update an artifact's visibility (hide/unhide) and/or name (rename). One\n * call covers both because backend offers a single PATCH endpoint with\n * optional fields. At least one of visibility/name must be provided.\n *\n * Per backend contract (mirrors DELETE semantics):\n * 200 ok → success\n * 200 ok + already:true → idempotent no-op, treat as success\n * 404 → not found / not owned, treat as success\n * 400 / 403 → real failure, surface to user\n * 5xx / network → real failure, caller should rollback\n */\nexport async function patchArtifact(\n artifactId: string,\n body: { visibility?: 'pinned' | 'hidden'; name?: string },\n reason: AcsPatchReason,\n): Promise<PatchResult> {\n try {\n const res = await authedFetch(\n `/api/acs/artifacts/${encodeURIComponent(artifactId)}`,\n { method: 'PATCH', body: JSON.stringify({ ...body, reason }) },\n );\n const data = await res.json().catch(() => ({} as any));\n if (res.ok) {\n return {\n ok: true,\n already: !!data?.already,\n artifact: data?.artifact || undefined,\n status: res.status,\n };\n }\n if (res.status === 404) {\n return { ok: true, notFound: true, status: 404 };\n }\n return {\n ok: false,\n status: res.status,\n error: data?.error || `HTTP ${res.status}`,\n };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\n/**\n * Persist a new pin order. Body lists currently-pinned artifact IDs in the\n * new visual order; server validates ownership + pinned state of each ID.\n *\n * Returns { ok: false, error } on failure. 400 means the array contained\n * an id that's not owned or not pinned — caller should refetch /surface\n * and re-render rather than fight the server.\n */\nexport async function setOrder(pinned: string[]): Promise<{ ok: boolean; status: number; error?: string }> {\n try {\n const res = await authedFetch('/api/acs/order', {\n method: 'PUT',\n body: JSON.stringify({ pinned }),\n });\n if (res.ok) return { ok: true, status: res.status };\n const data = await res.json().catch(() => ({} as any));\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\n/**\n * Record a usage event. Fire-and-forget — never throws, never blocks the UI.\n * Use surface to tell the backend which surface the event came from\n * (e.g. 'home' for the carousel).\n */\nexport async function recordEvent(\n artifactId: string,\n event: AcsEvent,\n surface?: AcsSurface,\n): Promise<void> {\n try {\n await authedFetch('/api/acs/event', {\n method: 'POST',\n body: JSON.stringify({ artifactId, event, ...(surface ? { surface } : {}) }),\n });\n } catch {\n // intentional swallow — usage tracking failures shouldn't surface to the user\n }\n}\n\n// ─── Home Actions (top-actions feed) ────────────────────────────────────\n// Server-managed recommended-actions feed for the home \"What's on your mind?\"\n// screen. The card universe is open + agent-authored; the only fixed contract\n// is this wire shape + the leaf dispatch (send_message | open_widget).\n// Backend: GET /api/acs/home-actions, PUT /order, PATCH /:id,\n// WS topic acs.home-actions.\n\nexport type HomeActionLeaf =\n | { type: 'send_message'; prompt: string; skillSlug?: string }\n | { type: 'open_widget'; artifactId: string }\n | { type: string; [k: string]: any }; // forward-compat: open_url/run_tool/…\n\nexport interface HomeAction {\n actionId: string;\n pinOrder?: number;\n title: string;\n subtitle?: string;\n icon?: string;\n action: HomeActionLeaf;\n source?: 'curated' | 'pinned_by_user' | 'skill_authored' | (string & {});\n canDismiss?: boolean;\n canPin?: boolean;\n pinned?: boolean;\n}\n\n/** List the home top-actions feed. Returns [] on any error. */\nexport async function listHomeActions(): Promise<HomeAction[]> {\n try {\n const res = await authedFetch('/api/acs/home-actions', { method: 'GET' });\n if (!res.ok) {\n console.warn(`[acs] /home-actions returned ${res.status}`);\n return [];\n }\n const data = await res.json();\n return Array.isArray(data?.actions) ? (data.actions as HomeAction[]) : [];\n } catch (e: any) {\n console.warn('[acs] /home-actions failed:', e?.message || e);\n return [];\n }\n}\n\nexport type HomeActionReason =\n | 'user_pin' | 'user_unpin' | 'user_dismiss' | 'user_drag_reorder'\n | (string & {});\n\n/** Pin/unpin or dismiss a card. 200 already / 404 both count as success. */\nexport async function patchHomeAction(\n actionId: string,\n body: { pinned?: boolean; dismissed?: boolean },\n reason: HomeActionReason,\n): Promise<{ ok: boolean; action?: HomeAction; status: number; error?: string }> {\n try {\n const res = await authedFetch(\n `/api/acs/home-actions/${encodeURIComponent(actionId)}`,\n { method: 'PATCH', body: JSON.stringify({ ...body, reason }) },\n );\n const data = await res.json().catch(() => ({} as any));\n if (res.ok) return { ok: true, action: data?.action || undefined, status: res.status };\n if (res.status === 404) return { ok: true, status: 404 };\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n\n/** Persist a new card order. Optimistic; caller rolls back on failure. */\nexport async function setHomeActionOrder(\n order: string[],\n): Promise<{ ok: boolean; status: number; error?: string }> {\n try {\n const res = await authedFetch('/api/acs/home-actions/order', {\n method: 'PUT',\n body: JSON.stringify({ order }),\n });\n if (res.ok) return { ok: true, status: res.status };\n const data = await res.json().catch(() => ({} as any));\n return { ok: false, status: res.status, error: data?.error || `HTTP ${res.status}` };\n } catch (e: any) {\n return { ok: false, status: 0, error: e?.message || 'network error' };\n }\n}\n","/**\n * Tracks the user's ACS widget tiles for the home carousel. Single source of\n * truth for /api/acs/surface state. Optimistic ops with rollback on failure\n * — backend contract treats 404 / already:true as success (per spec), so the\n * store mirrors that policy: a delete that the server says was already done\n * stays removed locally.\n *\n * Cross-device freshness: the WS subscription (./ws) forwards `acs.artifacts`\n * events into the applyServer* methods; hosts should also refresh() on app\n * foreground (\"WS is best-effort; the GET is the source of truth\").\n */\n\nimport { create } from 'zustand';\nimport {\n listSurface,\n deleteArtifact,\n patchArtifact,\n setOrder,\n recordEvent,\n type AcsArtifact,\n type AcsDeleteReason,\n} from './api';\n\ninterface WidgetsState {\n /** Tiles to render in the home carousel. Order matches what /surface\n * returned; sort by pinOrder when present. */\n tiles: AcsArtifact[];\n /** True after the first /surface fetch completes (success OR empty). */\n hydrated: boolean;\n /** True while a /surface request is in flight. */\n loading: boolean;\n /** Last error string from /surface; null on success or pre-fetch. */\n error: string | null;\n\n /** First load — idempotent; safe to call from multiple effects. */\n hydrate: () => Promise<void>;\n /** Force re-fetch; call on app foreground and after destructive ops. */\n refresh: () => Promise<void>;\n /** Reset to empty (sign-out, env switch). */\n clear: () => void;\n\n /**\n * Optimistic remove. Returns { ok: false, error } only on real network /\n * 5xx failures — 404 and already:true rollback to ok:true per the backend\n * contract (no existence leak; the row is gone either way).\n */\n remove: (artifactId: string, reason?: AcsDeleteReason) => Promise<{ ok: boolean; error?: string }>;\n\n /** Optimistic hide (visibility → 'hidden'). Tile disappears from carousel. */\n hide: (artifactId: string) => Promise<{ ok: boolean; error?: string }>;\n\n /** Optimistic unhide (visibility → 'pinned'). Tile reappears in carousel. */\n unhide: (artifactId: string) => Promise<{ ok: boolean; error?: string }>;\n\n /** Optimistic rename. Trims input and rejects empty / overlong names locally. */\n rename: (artifactId: string, name: string) => Promise<{ ok: boolean; error?: string }>;\n\n /**\n * Persist a new pin order to the server. `pinnedIds` is the visible order\n * of currently-pinned tiles. Optimistic — applies locally first, rolls\n * back on server rejection.\n */\n reorder: (pinnedIds: string[]) => Promise<{ ok: boolean; error?: string }>;\n\n // ─── Server-driven mutations (no API call) ─────────────────────────────\n // The WS subscription (./ws) forwards `acs.artifacts` events into these\n // methods. They ONLY mutate local state — they DO NOT call the API (the\n // server is the source of the event, calling back would loop).\n\n /** WS 'updated' event — replace the tile by id (hide/unhide/rename land here). */\n applyServerUpdate: (artifact: AcsArtifact) => void;\n /** WS 'retired' event — remove the tile by id. */\n applyServerRetire: (artifactId: string) => void;\n /** WS 'order' event — re-rank tiles to match the pinned ID array. */\n applyServerOrder: (pinnedIds: string[]) => void;\n\n /** Fire-and-forget usage event. Caller doesn't await. */\n track: (artifactId: string, event: 'clicked' | 'dismissed' | 'acted' | 'ignored') => void;\n}\n\nexport const useWidgetsStore = create<WidgetsState>((set, get) => ({\n tiles: [],\n hydrated: false,\n loading: false,\n error: null,\n\n hydrate: async () => {\n if (get().hydrated || get().loading) return;\n await get().refresh();\n },\n\n refresh: async () => {\n if (get().loading) return;\n set({ loading: true, error: null });\n try {\n const tiles = await listSurface('home');\n set({ tiles, loading: false, hydrated: true });\n } catch (e: any) {\n set({ loading: false, hydrated: true, error: e?.message || 'Failed to load widgets' });\n }\n },\n\n clear: () => set({ tiles: [], hydrated: false, loading: false, error: null }),\n\n remove: async (artifactId, reason = 'user_long_press_delete') => {\n const before = get().tiles;\n // Optimistic: snap removed immediately so the user sees the tile vanish.\n set({ tiles: before.filter(t => t.id !== artifactId) });\n\n const result = await deleteArtifact(artifactId, reason);\n if (result.ok) {\n // Includes 200, 200 already:true, and 404 — all \"gone server-side too\".\n return { ok: true };\n }\n\n // Real failure — rollback.\n set({ tiles: before });\n return { ok: false, error: result.error || `HTTP ${result.status}` };\n },\n\n hide: async (artifactId) => {\n const before = get().tiles;\n set({\n tiles: before.map(t =>\n t.id === artifactId ? { ...t, visibility: 'hidden' as const } : t,\n ),\n });\n const r = await patchArtifact(artifactId, { visibility: 'hidden' }, 'user_long_press_hide');\n if (r.ok) {\n // If the server returned the updated artifact, sync our copy to it\n // (covers race conditions and server-side normalisation).\n if (r.artifact) {\n set({\n tiles: get().tiles.map(t => (t.id === artifactId ? { ...t, ...r.artifact! } : t)),\n });\n }\n return { ok: true };\n }\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n unhide: async (artifactId) => {\n const before = get().tiles;\n set({\n tiles: before.map(t =>\n t.id === artifactId ? { ...t, visibility: 'pinned' as const } : t,\n ),\n });\n const r = await patchArtifact(artifactId, { visibility: 'pinned' }, 'user_long_press_unhide');\n if (r.ok) {\n if (r.artifact) {\n set({\n tiles: get().tiles.map(t => (t.id === artifactId ? { ...t, ...r.artifact! } : t)),\n });\n }\n return { ok: true };\n }\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n rename: async (artifactId, name) => {\n // Local validation mirrors backend's 60-char cap from the spec. Keep\n // this strict so we don't hit the API with garbage that will 400 anyway.\n const trimmed = name.trim();\n if (!trimmed) return { ok: false, error: 'Name cannot be empty' };\n if (trimmed.length > 60) return { ok: false, error: 'Name must be 60 characters or less' };\n\n const before = get().tiles;\n set({\n tiles: before.map(t => (t.id === artifactId ? { ...t, name: trimmed } : t)),\n });\n const r = await patchArtifact(artifactId, { name: trimmed }, 'user_long_press_rename');\n if (r.ok) {\n if (r.artifact) {\n set({\n tiles: get().tiles.map(t => (t.id === artifactId ? { ...t, ...r.artifact! } : t)),\n });\n }\n return { ok: true };\n }\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n reorder: async (pinnedIds) => {\n const before = get().tiles;\n // Optimistic: assign pinOrder by position in pinnedIds. Hidden tiles\n // are not touched. If the server rejects, we roll back to `before`.\n const idToOrder = new Map(pinnedIds.map((id, i) => [id, i] as const));\n set({\n tiles: before.map(t => {\n const o = idToOrder.get(t.id);\n return o == null ? t : { ...t, pinOrder: o };\n }),\n });\n const r = await setOrder(pinnedIds);\n if (r.ok) return { ok: true };\n set({ tiles: before });\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n applyServerUpdate: (artifact) => {\n set({\n tiles: get().tiles.map(t => (t.id === artifact.id ? { ...t, ...artifact } : t)),\n });\n },\n\n applyServerRetire: (artifactId) => {\n set({ tiles: get().tiles.filter(t => t.id !== artifactId) });\n },\n\n applyServerOrder: (pinnedIds) => {\n const idToOrder = new Map(pinnedIds.map((id, i) => [id, i] as const));\n set({\n tiles: get().tiles.map(t => {\n const o = idToOrder.get(t.id);\n return o == null ? t : { ...t, pinOrder: o };\n }),\n });\n },\n\n track: (artifactId, event) => {\n // Fire-and-forget. Surface tagged so backend analytics knows where the\n // click happened (home carousel vs library, etc.).\n recordEvent(artifactId, event, 'home');\n },\n}));\n","/**\n * The home \"What's on your mind?\" top-actions feed. Server-managed: the list,\n * its order, pin and dismiss state all live on the backend (ACS home-actions\n * API). This store is a thin local mirror with optimistic mutations + rollback\n * — same discipline as widgetsStore.\n *\n * The cards themselves are agent-authored and open-ended; clients only know\n * the wire shape + the fixed leaf dispatch (send_message | open_widget), so\n * this store stays dumb on purpose.\n */\n\nimport { create } from 'zustand';\nimport {\n listHomeActions,\n patchHomeAction,\n setHomeActionOrder,\n type HomeAction,\n} from './api';\nimport { getAcsCacheStorage } from './providers';\n\n// Persisted (when the host wires setAcsCacheStorage) so the home cards render\n// instantly on cold start and survive a dead/empty server response. The\n// server is still source of truth — when a non-empty result arrives we\n// overwrite the cache; an empty/failed fetch leaves the last good cards on\n// screen.\nconst CACHE_KEY = 'ateam.homeActions.v1';\n\nfunction persist(actions: HomeAction[]): void {\n // Fire-and-forget; never block the UI on disk.\n getAcsCacheStorage()?.setItem(CACHE_KEY, JSON.stringify(actions)).catch(() => {});\n}\n\ninterface HomeActionsState {\n actions: HomeAction[];\n hydrated: boolean;\n loading: boolean;\n\n hydrate: () => Promise<void>;\n refresh: () => Promise<void>;\n clear: () => void;\n\n /** Optimistic dismiss — removes locally, rolls back on real failure. */\n dismiss: (actionId: string) => Promise<{ ok: boolean; error?: string }>;\n /** Optimistic pin/unpin. */\n setPinned: (actionId: string, pinned: boolean) => Promise<{ ok: boolean; error?: string }>;\n /** Optimistic reorder — `orderedIds` is the new visual order. */\n reorder: (orderedIds: string[]) => Promise<{ ok: boolean; error?: string }>;\n\n // ─── WS-driven (local mutation only, no API call) ───\n applyServerUpsert: (action: HomeAction) => void;\n applyServerRemove: (actionId: string) => void;\n applyServerOrder: (orderedIds: string[]) => void;\n}\n\nfunction sortByPin(a: HomeAction, b: HomeAction): number {\n // pinned first, then pinOrder asc, then stable.\n if (!!a.pinned !== !!b.pinned) return a.pinned ? -1 : 1;\n const ao = typeof a.pinOrder === 'number' ? a.pinOrder : Number.MAX_SAFE_INTEGER;\n const bo = typeof b.pinOrder === 'number' ? b.pinOrder : Number.MAX_SAFE_INTEGER;\n return ao - bo;\n}\n\nexport const useHomeActionsStore = create<HomeActionsState>((set, get) => ({\n actions: [],\n hydrated: false,\n loading: false,\n\n hydrate: async () => {\n if (get().hydrated || get().loading) return;\n // 1. Paint cached cards immediately (survives cold start / offline).\n try {\n const cached = await getAcsCacheStorage()?.getItem(CACHE_KEY);\n if (cached) {\n const parsed = JSON.parse(cached) as HomeAction[];\n if (Array.isArray(parsed) && parsed.length > 0) {\n // Preserve the order we cached (which was the server's priority\n // order) — home layouts may split positionally, so re-sorting\n // would reshuffle the hero cards.\n set({ actions: parsed, hydrated: true });\n }\n }\n } catch { /* corrupt cache — ignore, server refresh will fix it */ }\n // 2. Then refresh from the server.\n await get().refresh();\n },\n\n refresh: async () => {\n if (get().loading) return;\n set({ loading: true });\n const actions = await listHomeActions();\n // Only overwrite when the server actually returned cards. An empty result\n // (dead API, transient 5xx, or genuinely-empty) must NOT wipe the cards\n // already on screen — keep the last good set persisted.\n if (actions.length > 0) {\n // Server delivers cards already priority-ordered — do NOT re-sort\n // (home layouts may be positional, e.g. a top-3 / rest split).\n set({ actions, loading: false, hydrated: true });\n persist(actions);\n } else {\n set({ loading: false, hydrated: true });\n }\n },\n\n // clear() wipes in-memory state on sign-out AND drops the disk cache — a\n // different user must not see the prior user's cards.\n clear: () => {\n set({ actions: [], hydrated: false, loading: false });\n getAcsCacheStorage()?.setItem(CACHE_KEY, '[]').catch(() => {});\n },\n\n dismiss: async (actionId) => {\n const before = get().actions;\n const next = before.filter(a => a.actionId !== actionId);\n set({ actions: next });\n persist(next);\n const r = await patchHomeAction(actionId, { dismissed: true }, 'user_dismiss');\n if (r.ok) return { ok: true };\n set({ actions: before });\n persist(before);\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n setPinned: async (actionId, pinned) => {\n const before = get().actions;\n const next = before.map(a => (a.actionId === actionId ? { ...a, pinned } : a)).sort(sortByPin);\n set({ actions: next });\n persist(next);\n const r = await patchHomeAction(actionId, { pinned }, pinned ? 'user_pin' : 'user_unpin');\n if (r.ok) {\n if (r.action) {\n const merged = get().actions.map(a => (a.actionId === actionId ? { ...a, ...r.action! } : a)).sort(sortByPin);\n set({ actions: merged });\n persist(merged);\n }\n return { ok: true };\n }\n set({ actions: before });\n persist(before);\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n reorder: async (orderedIds) => {\n const before = get().actions;\n const idx = new Map(orderedIds.map((id, i) => [id, i] as const));\n const next = before.map(a => {\n const o = idx.get(a.actionId);\n return o == null ? a : { ...a, pinOrder: o };\n }).sort(sortByPin);\n set({ actions: next });\n persist(next);\n const r = await setHomeActionOrder(orderedIds);\n if (r.ok) return { ok: true };\n set({ actions: before });\n persist(before);\n return { ok: false, error: r.error || `HTTP ${r.status}` };\n },\n\n applyServerUpsert: (action) => {\n const rest = get().actions.filter(a => a.actionId !== action.actionId);\n const next = [...rest, action].sort(sortByPin);\n set({ actions: next });\n persist(next);\n },\n applyServerRemove: (actionId) => {\n const next = get().actions.filter(a => a.actionId !== actionId);\n set({ actions: next });\n persist(next);\n },\n applyServerOrder: (orderedIds) => {\n const idx = new Map(orderedIds.map((id, i) => [id, i] as const));\n const next = get().actions.map(a => {\n const o = idx.get(a.actionId);\n return o == null ? a : { ...a, pinOrder: o };\n }).sort(sortByPin);\n set({ actions: next });\n persist(next);\n },\n}));\n","/**\n * Long-lived WebSocket subscription to the `acs.artifacts` and\n * `acs.home-actions` topics. Protocol (backend websocket.js):\n *\n * client → server : { type: \"subscribe\", topic: \"acs.artifacts\" }\n * server → client : { event: \"subscribed\", data: { topic: \"acs.artifacts\" } }\n * server → client : { topic: \"acs.artifacts\", event: \"updated\", artifact: {...} }\n * server → client : { topic: \"acs.artifacts\", event: \"retired\", artifactId: \"...\" }\n * server → client : { topic: \"acs.artifacts\", event: \"order\", pinned: [...] }\n *\n * Events flow into the stores' applyServer* methods so we don't loop (those\n * methods mutate local state only — no API calls).\n *\n * Lifecycle:\n * connectAcsWs(token, tenant) starts a single connection + subscribe.\n * On disconnect, exponential-backoff reconnect (capped). Call\n * notifyAcsWsForeground() from the host's AppState listener to\n * force-reconnect when the socket dropped while backgrounded (this module\n * is host-agnostic — no react-native import — so the host owns AppState).\n * On signout, disconnectAcsWs() closes the socket and stops reconnects.\n *\n * Backend's spec note: \"WS is best-effort; the GET is the source of truth\"\n * — so widgetsStore.refresh() on foreground stays the safety net even when\n * the WS is healthy. This file is the realtime cherry on top.\n */\n\nimport { getCoreWsUrl } from '../config';\nimport { useWidgetsStore } from './widgetsStore';\nimport { useHomeActionsStore } from './homeActionsStore';\n\nlet _ws: WebSocket | null = null;\nlet _wantOpen = false;\nlet _retryAttempt = 0;\nlet _retryTimer: ReturnType<typeof setTimeout> | null = null;\nlet _token: string | null = null;\nlet _tenant: string | null = null;\n\nconst TOPIC = 'acs.artifacts';\nconst TOPIC_HOME = 'acs.home-actions';\nconst MAX_BACKOFF_MS = 30_000;\n\nfunction backoffMs(attempt: number): number {\n // 0.5s, 1s, 2s, 4s, ... capped at 30s. Tiny jitter to avoid thundering herd.\n const base = Math.min(MAX_BACKOFF_MS, 500 * Math.pow(2, attempt));\n const jitter = Math.random() * 250;\n return base + jitter;\n}\n\nfunction send(obj: any) {\n if (_ws && _ws.readyState === 1) {\n try { _ws.send(JSON.stringify(obj)); } catch (e) { console.warn('[acsWs] send failed', e); }\n }\n}\n\nfunction handleEvent(msg: any) {\n // The subscribe confirmation comes as { event: \"subscribed\", data: {...} }\n // (no `topic` field). Real events come as { topic, event, ...payload }.\n if (msg?.event === 'subscribed') {\n console.log('[acsWs] subscribed to', msg?.data?.topic);\n return;\n }\n\n // Home-actions feed events route to its own store.\n if (msg?.topic === TOPIC_HOME) {\n const home = useHomeActionsStore.getState();\n switch (msg.event) {\n case 'updated':\n if (msg.action && typeof msg.action.actionId === 'string') home.applyServerUpsert(msg.action);\n break;\n case 'removed':\n if (typeof msg.actionId === 'string') home.applyServerRemove(msg.actionId);\n break;\n case 'order':\n if (Array.isArray(msg.order)) home.applyServerOrder(msg.order.filter((id: any) => typeof id === 'string'));\n break;\n case 'refreshed':\n home.refresh();\n break;\n default:\n break;\n }\n return;\n }\n\n if (msg?.topic !== TOPIC) return;\n\n const store = useWidgetsStore.getState();\n switch (msg.event) {\n case 'updated':\n if (msg.artifact && typeof msg.artifact.id === 'string') {\n store.applyServerUpdate(msg.artifact);\n }\n break;\n case 'retired':\n if (typeof msg.artifactId === 'string') {\n store.applyServerRetire(msg.artifactId);\n }\n break;\n case 'order':\n if (Array.isArray(msg.pinned)) {\n store.applyServerOrder(msg.pinned.filter((id: any) => typeof id === 'string'));\n }\n break;\n case 'created':\n // Backend spec lists `created` as TODO. Until it ships, host foreground\n // refresh catches new widgets. When it lands the WS will also fire\n // `updated` for the new tile, which is already handled. For now, treat\n // any inbound created the same as updated.\n if (msg.artifact && typeof msg.artifact.id === 'string') {\n store.applyServerUpdate(msg.artifact);\n }\n break;\n default:\n // Unknown event — ignore so we stay forward-compatible with new types.\n break;\n }\n}\n\nfunction openSocket() {\n if (_ws) return;\n if (!_token || !_tenant) return;\n\n const url = `${getCoreWsUrl()}/ws?token=${encodeURIComponent(_token)}&tenant=${encodeURIComponent(_tenant)}`;\n console.log(`[acsWs] opening`);\n const ws = new WebSocket(url);\n _ws = ws;\n\n ws.onopen = () => {\n _retryAttempt = 0;\n send({ type: 'subscribe', topic: TOPIC });\n send({ type: 'subscribe', topic: TOPIC_HOME });\n };\n ws.onmessage = (e) => {\n try {\n const msg = JSON.parse(typeof e.data === 'string' ? e.data : '');\n handleEvent(msg);\n } catch (err) {\n // Non-JSON or malformed frame — ignore, log for debugging.\n console.warn('[acsWs] parse failed', err);\n }\n };\n ws.onerror = (e: any) => {\n console.warn('[acsWs] error', e?.message || e);\n };\n ws.onclose = () => {\n _ws = null;\n if (!_wantOpen) return;\n const delay = backoffMs(_retryAttempt++);\n console.log(`[acsWs] closed; reconnecting in ${Math.round(delay)}ms (attempt ${_retryAttempt})`);\n if (_retryTimer) clearTimeout(_retryTimer);\n _retryTimer = setTimeout(openSocket, delay);\n };\n}\n\n/**\n * Call from the host's AppState listener when the app returns to the\n * foreground — if the socket dropped while backgrounded, reconnect\n * immediately rather than waiting out the backoff timer.\n */\nexport function notifyAcsWsForeground() {\n if (_wantOpen && !_ws) {\n if (_retryTimer) { clearTimeout(_retryTimer); _retryTimer = null; }\n _retryAttempt = 0;\n openSocket();\n }\n}\n\n/**\n * Start the ACS WS subscription. Idempotent — calling twice with the same\n * token/tenant is a no-op. Call once the host says the user is signed in\n * (JWT available).\n */\nexport function connectAcsWs(token: string, tenant: string) {\n if (_ws && _wantOpen && _token === token && _tenant === tenant) return;\n // Token or tenant changed → tear down + reopen.\n if (_ws) {\n try { _ws.close(); } catch {}\n _ws = null;\n }\n _token = token;\n _tenant = tenant;\n _wantOpen = true;\n openSocket();\n}\n\n/**\n * Stop the ACS WS subscription. Call on signout / env switch.\n */\nexport function disconnectAcsWs() {\n _wantOpen = false;\n _token = null;\n _tenant = null;\n if (_retryTimer) { clearTimeout(_retryTimer); _retryTimer = null; }\n if (_ws) {\n try { _ws.close(); } catch {}\n _ws = null;\n }\n}\n"],"mappings":"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","names":["text","create","create","create","create","_ws"]}