@ateam-ai-mobile/plugin-runtime 0.1.5 → 0.1.8

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/plugins.ts","../src/bundles/bundleManager.ts","../src/sdk/index.ts","../src/sdk/registration.ts","../src/sdk/voice.ts","../src/sdk/primitives.ts","../src/sdk/components.ts","../src/host.ts","../src/sdk/CameraPreview.tsx","../src/sdk/usePluginTheme.ts","../src/sdk/useApi.ts","../src/surfaces/SurfaceDrawer.tsx","../src/surfaces/AdaOrb.tsx","../src/surfaces/SurfaceCard.tsx","../src/surfaces/SurfaceFullscreen.tsx","../src/registry/store.ts","../src/registry/SurfaceDispatcher.tsx","../src/utils/sha256.ts","../src/bundles/integrity.ts","../src/bundles/storage.ts","../src/bridge/native.ts","../src/deviceStateHost.ts","../src/tools/registry.ts","../src/voiceHost.ts","../src/pluginRuntime.ts","../src/tools/loader.ts"],"sourcesContent":["import { apiFetch } from '@ateam-ai-mobile/core';\nimport { getCoreApiUrl } from '@ateam-ai-mobile/core';\n\n/**\n * Summary returned by cp.listContextPlugins — no `render` field.\n * Used for the plugin grid (name, icon, description).\n */\nexport interface PluginSurfaceMeta {\n type: 'drawer' | 'card' | 'fullscreen' | 'header' | 'ambient' | 'nudge';\n visibility?: 'always' | 'user' | 'engine';\n trigger?: { from?: string; gesture?: string };\n icon?: string;\n title?: string;\n subtitle?: string;\n privacy?: boolean;\n prompt?: string;\n}\n\nexport interface PluginSummary {\n id: string;\n name: string;\n version: string;\n description?: string;\n _source?: string; // \"mcp\" for connector plugins\n _connectorId?: string;\n /** Declarative surface placement — added by the surface-SDK migration */\n surface?: PluginSurfaceMeta;\n}\n\n/**\n * Native capability flags (declared in manifest).\n */\nexport interface NativeCapabilities {\n camera?: boolean;\n location?: boolean;\n biometrics?: boolean;\n offline?: boolean;\n backgroundTasks?: boolean;\n fileSystem?: boolean;\n notifications?: boolean;\n bluetooth?: boolean;\n haptics?: boolean;\n}\n\n/**\n * Lifecycle hooks for service/hybrid plugins.\n */\nexport interface PluginHooks {\n onAppStart?: boolean;\n onPushReceived?: boolean;\n onConnectivity?: boolean;\n onForeground?: boolean;\n onBackground?: boolean;\n}\n\n/**\n * Render mode — polymorphic.\n * - 'iframe': existing WebView (backward compat)\n * - 'react-native': native RN component only\n * - 'adaptive': both web and native, host picks best\n */\nexport type PluginRenderMode =\n | { mode: 'iframe'; iframeUrl: string; bundleUrl?: string; bundleHash?: string; external?: boolean }\n | { mode: 'react-native'; component: string; bundleUrl?: string; bundleHash?: string; bundleId?: string }\n | {\n mode: 'adaptive';\n iframe: { iframeUrl: string; external?: boolean };\n reactNative: { component: string; bundleUrl?: string; bundleHash?: string; bundleId?: string };\n };\n\n/**\n * Full manifest returned by cp.getContextPlugin.\n * Extended to support native mobile plugins alongside existing web plugins.\n */\nexport interface PluginManifest extends PluginSummary {\n type?: 'ui' | 'service' | 'hybrid';\n render: PluginRenderMode;\n native?: NativeCapabilities;\n hooks?: PluginHooks;\n channels?: string[] | {\n events: string[];\n actions: string[];\n };\n capabilities?: Record<string, unknown>;\n _mcpEndpoint?: string;\n}\n\n/**\n * Determine if a manifest supports native rendering.\n */\nexport function supportsNative(manifest: PluginManifest): boolean {\n const mode = manifest.render?.mode;\n return mode === 'react-native' || mode === 'adaptive';\n}\n\n/**\n * Get the native component ID from a manifest (if it has native support).\n */\nexport function getNativeComponentId(manifest: PluginManifest): string | null {\n if (manifest.render?.mode === 'react-native') return manifest.render.component;\n if (manifest.render?.mode === 'adaptive') return manifest.render.reactNative?.component;\n return null;\n}\n\n/**\n * Get the native bundle URL from a manifest (if it has native support).\n */\nexport function getNativeBundleUrl(manifest: PluginManifest): string | null {\n // Check direct bundleUrl on manifest or within render structure\n const direct = (manifest as any).bundleUrl;\n if (direct) return direct;\n\n const render = manifest.render;\n if (render.mode === 'react-native') return render.bundleUrl || null;\n if (render.mode === 'adaptive') return render.reactNative?.bundleUrl || null;\n\n return null;\n}\n\n/**\n * Get the SHA-256 integrity hash for a native bundle, if the server provided one.\n * Used post-download to verify the bundle bytes weren't tampered in transit\n * — a MITM-replaced bundle gets `eval`'d as RN code with full capability access.\n */\nexport function getNativeBundleHash(manifest: PluginManifest): string | null {\n const direct = (manifest as any).bundleHash;\n if (direct) return direct;\n const render = manifest.render;\n if (render.mode === 'react-native') return (render as any).bundleHash || null;\n if (render.mode === 'adaptive') return render.reactNative?.bundleHash || null;\n return null;\n}\n\n/**\n * Check if a manifest can be rendered as a WebView (iframe or adaptive with iframe).\n */\nexport function supportsWebView(manifest: PluginManifest): boolean {\n return manifest.render?.mode === 'iframe' || manifest.render?.mode === 'adaptive';\n}\n\n/**\n * List all available UI plugins via MCP JSON-RPC.\n * Returns summary data only (no render field).\n * Protocol: cp.listContextPlugins → core plugins + MCP connector plugins.\n */\nexport async function listPlugins(): Promise<PluginSummary[]> {\n const res = await apiFetch<{\n result: {\n content: Array<{ type: string; text: string }>;\n structuredContent?: { plugins?: PluginSummary[] };\n };\n }>('/mcp', {\n method: 'POST',\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: Date.now(),\n method: 'tools/call',\n params: {\n name: 'cp.listContextPlugins',\n arguments: {},\n },\n }),\n });\n\n // Accept multiple response formats (matches web mcpClient.js fallback chain)\n const structured = res.result?.structuredContent?.plugins;\n if (structured) return structured;\n\n const text = res.result?.content?.[0]?.text;\n if (!text) return [];\n try {\n const parsed = JSON.parse(text);\n return parsed.plugins || parsed || [];\n } catch {\n return [];\n }\n}\n\n/**\n * Get a specific plugin's FULL manifest (with render.iframeUrl).\n * Protocol: cp.getContextPlugin({ id }) → resolves iframeUrl for core/MCP/external.\n *\n * IMPORTANT: The backend parameter is `id`, not `pluginId`.\n */\nexport async function getPlugin(pluginId: string): Promise<PluginManifest | null> {\n const res = await apiFetch<{\n result: {\n content: Array<{ type: string; text: string }>;\n structuredContent?: PluginManifest;\n };\n }>('/mcp', {\n method: 'POST',\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: Date.now(),\n method: 'tools/call',\n params: {\n name: 'cp.getContextPlugin',\n arguments: { id: pluginId }, // Backend expects { id }, NOT { pluginId }\n },\n }),\n });\n\n // Accept structured or text response\n if (res.result?.structuredContent) return res.result.structuredContent;\n\n const text = res.result?.content?.[0]?.text;\n if (!text) return null;\n try {\n const parsed = JSON.parse(text);\n // Backend may return error object\n if (parsed.error) {\n console.warn('[getPlugin] Backend error:', parsed.error);\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve plugin iframe URL to a full URL for WebView.\n * Matches the web frontend's PluginHost.jsx logic:\n * - External (absolute http): append ?tenant=\n * - MCP plugin (/mcp-ui/...): inject tenant into path → /mcp-ui/{tenant}/{connectorId}/...\n * - Core plugin (/assets/...): prepend getCoreApiUrl()\n */\nexport function resolvePluginUrl(manifest: PluginManifest, tenant?: string): string {\n // Extract iframeUrl from different render modes.\n // Adaptive manifests in the wild use a flat shape — `render.iframeUrl` —\n // not the nested `render.iframe.iframeUrl` from the type. Accept both.\n const render = manifest.render as any;\n let url: string | undefined;\n if (render?.mode === 'iframe') {\n url = render.iframeUrl;\n } else if (render?.mode === 'adaptive') {\n url = render.iframeUrl || render.iframe?.iframeUrl;\n }\n // react-native only → no URL\n if (!url) return '';\n\n // Already absolute URL (external plugins like Voice)\n if (url.startsWith('http')) {\n const sep = url.includes('?') ? '&' : '?';\n return tenant ? `${url}${sep}tenant=${encodeURIComponent(tenant)}` : url;\n }\n\n // MCP plugin — inject tenant into path: /mcp-ui/{connectorId}/... → /mcp-ui/{tenant}/{connectorId}/...\n if (tenant && url.startsWith('/mcp-ui/')) {\n const tenantUrl = url.replace('/mcp-ui/', `/mcp-ui/${encodeURIComponent(tenant)}/`);\n return `${getCoreApiUrl()}${tenantUrl}`;\n }\n\n // Core plugin — prepend core API base\n return `${getCoreApiUrl()}${url}`;\n}\n","/**\n * Global Plugin Bundle Manager — singleton.\n *\n * ONE download per bundleUrl (deduplicates multi-plugin bundles); all plugin\n * renderer instances share the same loaded modules. Persistence goes through\n * the BundleStorage adapter (in-memory by default; @ateam-ai-mobile/expo provides disk).\n *\n * Usage:\n * const component = await bundleManager.load(pluginId, bundleUrl, version, hash, grants);\n * // component = { id, type, Component, ... } (RegisteredUIPlugin)\n */\nimport React from 'react';\nimport {\n useState, useEffect, useCallback, useMemo, useRef,\n useContext, useReducer, useLayoutEffect, useImperativeHandle, useDebugValue,\n} from 'react';\nimport * as ReactNative from 'react-native';\nimport { apiFetchRaw, getTenant } from '@ateam-ai-mobile/core';\nimport * as PluginSDKModule from '../sdk';\nimport SurfaceDrawer from '../surfaces/SurfaceDrawer';\nimport SurfaceCard from '../surfaces/SurfaceCard';\nimport SurfaceFullscreen from '../surfaces/SurfaceFullscreen';\nimport { useSurfaceStore } from '../registry/store';\nimport SurfaceDispatcher from '../registry/SurfaceDispatcher';\nimport { resolveBundleModule } from '../host';\nimport { sha256Hex } from '../utils/sha256';\nimport { assertBundleIntegrity } from './integrity';\nimport { getBundleStorage, type BundleCacheEntry, type TrustedToolDeclaration } from './storage';\nimport { registerDeviceTools, unregisterDeviceTools, listDeviceTools } from '../tools/registry';\nimport type { PluginGrants } from '../pluginRuntime';\nimport type { RegisteredUIPlugin } from '../sdk/types';\n\n// ── Require shim ─────────────────────────────────────────────\n// Bundles are built with external: ['react', 'react-native', '@adas/plugin-sdk']\n// so they emit require() calls that this shim resolves at runtime. Anything\n// beyond the built-ins (react-native-webview, expo-linking, …) must be\n// registered by the host via registerBundleModules() — the host is the one\n// that actually has those modules installed.\n\nconst ReactShim: any = {\n __esModule: true,\n default: React,\n ...React,\n // Explicitly include hooks (React 19 may not have them as own enumerable props)\n useState, useEffect, useCallback, useMemo, useRef, useContext,\n useReducer, useLayoutEffect, useImperativeHandle, useDebugValue,\n createElement: React.createElement,\n Fragment: React.Fragment,\n Component: React.Component,\n PureComponent: React.PureComponent,\n createContext: React.createContext,\n forwardRef: React.forwardRef,\n memo: React.memo,\n Children: React.Children,\n cloneElement: React.cloneElement,\n isValidElement: React.isValidElement,\n createRef: React.createRef,\n lazy: React.lazy,\n Suspense: React.Suspense,\n};\n\n// Freeze PluginSDK shim to prevent bundle monkey-patching of register().\n// Surface containers + registry ride along — the reference app's original\n// shim exposed the FULL plugin-sdk index, and bundles built against it may\n// import SurfaceDrawer/useSurfaceStore/etc. from '@adas/plugin-sdk'.\nconst PluginSDKShim = Object.freeze({\n ...PluginSDKModule,\n SurfaceDrawer,\n SurfaceCard,\n SurfaceFullscreen,\n useSurfaceStore,\n SurfaceDispatcher,\n PluginSDK: Object.freeze({\n ...PluginSDKModule.PluginSDK,\n register: PluginSDKModule.PluginSDK.register,\n }),\n register: PluginSDKModule.register,\n});\n\nconst requireShim = (name: string) => {\n if (name === 'react') return ReactShim;\n if (name === 'react-native') return ReactNative;\n if (name === '@adas/plugin-sdk') return PluginSDKShim;\n const hostModule = resolveBundleModule(name);\n if (hostModule !== undefined) return hostModule;\n console.warn(`[BundleManager] Unknown module: ${name} — register it via registerBundleModules()`);\n return {};\n};\n\n// ── Cache constants ──────────────────────────────────────────\n\nconst CACHE_TTL = 7 * 24 * 60 * 60 * 1000; // 7 days\n\n// What findPluginExport looks for: a renderable plugin, or one with a `tools` section.\nconst hasComponent = (val: any): boolean =>\n !!val && typeof val === 'object' && typeof val.Component === 'function';\nconst hasTools = (val: any): boolean =>\n !!val && typeof val === 'object' && Array.isArray(val.tools) && val.tools.length > 0;\n\n// ── BundleManager singleton ──────────────────────────────────\n\n/** Where the bytes currently running came from. */\nexport type LoadedBundleSource = 'download' | 'disk-cache' | 'memory';\n\n/**\n * Provenance of one loaded bundle — what is RUNNING, not what was requested.\n *\n * `hash` is the sha256 of the evaluated bytes. `expected` is the hash the\n * server's manifest advertised for that url. Equal means the phone is running\n * the build the server currently describes; different means it is not, and the\n * pair says so without needing a rebuild, a reinstall or a guess.\n */\nexport interface LoadedBundleInfo {\n bundleUrl: string;\n version: string;\n /** sha256 (hex, lowercase) of the bytes that were evaluated. */\n hash: string | null;\n /** sha256 the server advertised for this url at load time, if any. */\n expected: string | null;\n source: LoadedBundleSource;\n tenant: string | null;\n loadedAt: number;\n}\n\nclass BundleManager {\n /** In-memory module cache: bundleUrl → evaluated module.exports. Holds ONE\n * tenant's modules at a time — the tenant boundary is `cacheTenant` /\n * `requireTenant()`, NOT the key. */\n private modules = new Map<string, any>();\n /** What is actually RUNNING, keyed by bundleUrl (for the current tenant). See\n * getLoadedBundles(). */\n private provenance = new Map<string, LoadedBundleInfo>();\n\n /** In-flight download deduplication: bundleUrl → Promise */\n private inflight = new Map<string, Promise<any>>();\n\n /**\n * The tenant the in-memory caches (modules / provenance / inflight) currently\n * belong to. This is the tenant BOUNDARY for evaluated code.\n *\n * A bundleUrl resolves PER-TENANT on the server — one url, different bytes for\n * different tenants — so a memory hit keyed on url alone would hand tenant B\n * the module tenant A already evaluated and ran. PR #9 scoped the DISK cache\n * (per-tenant index + hash gate); the in-memory map was left url-keyed. This\n * closes that: the caches only ever hold ONE tenant's modules, and a switch\n * drops them before anything is served.\n */\n private cacheTenant: string | null = null;\n\n /**\n * pluginIds this manager registered device tools for. A tenant switch drops\n * the in-memory modules AND unregisters these, so the incoming tenant's bundle\n * re-registers into a clean registry instead of being refused as a duplicate\n * of the previous tenant's tools.\n */\n private registeredToolPluginIds = new Set<string>();\n\n /** bundleUrl → the trusted declaration last recorded on its disk-cache entry\n * this session, so a memory hit with unchanged grants skips the index I/O. */\n private recordedDeclarations = new Map<string, string>();\n\n /**\n * Enforce the in-memory tenant boundary. Call at the top of every public load\n * path, BEFORE any cache read.\n *\n * FAIL CLOSED: without a tenant identity we cannot prove a cached module is\n * this session's, so we drop everything and refuse rather than risk serving\n * one tenant's evaluated code to another. On a tenant change we drop the\n * previous tenant's modules (and their tool registrations) before proceeding.\n */\n /**\n * Monotonic load generation. Bumped on every in-memory wipe (a tenant change,\n * fail-closed, or clearAll). A load captures it at ENTRY; a completion whose\n * generation no longer matches is stale and is discarded before it can commit.\n * This closes the async race the sequential guard cannot: tenant A's in-flight\n * loadModule can resolve AFTER a switch to B — clearing `inflight` does not\n * cancel that Promise — and would otherwise write A's module / provenance /\n * device tools into the singleton now marked cacheTenant=B.\n */\n private epoch = 0;\n\n private requireTenant(): string {\n const tenant = getTenant();\n if (!tenant) {\n this.dropInMemory();\n this.cacheTenant = null;\n throw new Error(\n '[BundleManager] refusing to load a tenant-scoped bundle without a tenant identity (fail closed)',\n );\n }\n if (tenant !== this.cacheTenant) {\n // First load, or a tenant switch: the caches hold the previous tenant's\n // evaluated modules — none of it may cross the boundary.\n this.dropInMemory();\n this.cacheTenant = tenant;\n }\n return tenant;\n }\n\n /** Drop every in-memory cache and unregister the device tools this manager\n * registered — used on a tenant change and by clearAll(). */\n private dropInMemory(): void {\n for (const pluginId of this.registeredToolPluginIds) {\n try { unregisterDeviceTools(pluginId); } catch { /* ignore */ }\n }\n this.registeredToolPluginIds.clear();\n this.recordedDeclarations.clear();\n this.modules.clear();\n this.provenance.clear();\n this.inflight.clear();\n // Bump the generation: any load that started before this wipe is now stale\n // and must not commit its results (see epoch / stale check in loadModule).\n this.epoch++;\n }\n\n /** True once the boundary has moved since a load captured `epoch` — i.e. a\n * tenant switch (or wipe) happened while this load was in flight. Its results\n * belong to a tenant that is no longer current and must be discarded. */\n private isStale(epoch: number, tenant: string): boolean {\n return this.epoch !== epoch || getTenant() !== tenant;\n }\n\n /** Record a memory serve: the running bytes are the already-evaluated module,\n * and `expected` is refreshed from the manifest hash the caller JUST passed —\n * so after a redeploy the record reads hash !== expected (STALE) instead of\n * the old in-sync pair. The ONE place both memory paths (load()'s early return\n * and loadModule's) record reuse. No-op if nothing was recorded yet. */\n private markMemoryHit(bundleUrl: string, expectedHash?: string): void {\n const prev = this.provenance.get(bundleUrl);\n if (prev) {\n this.provenance.set(bundleUrl, { ...prev, source: 'memory', expected: expectedHash?.toLowerCase() ?? prev.expected });\n }\n }\n\n // ── Public API ──────────────────────────────────────────────\n\n /**\n * Load a plugin component. Returns the RegisteredUIPlugin object.\n * Handles: in-memory cache → disk cache → download → evaluate → extract.\n *\n * `expectedHash` (SHA-256 hex from cp.getContextPlugin manifest) MUST be\n * provided for any bundle the user has not previously verified — without\n * it, a tampered bundle is `eval`'d as JS with full RN runtime + every\n * native capability the manifest declares.\n *\n * `grants` is what the MANIFEST grants this plugin (resolvePluginGrants) — the\n * only authority its device tools are registered under. Omitted (e.g. a\n * prewarm from the slim plugin list) → the bundle is loaded but its tools are\n * NOT registered: without the manifest there is nothing trusted to gate them\n * on, and registering with nothing would downgrade a registration the\n * manifest-driven tool loader already made.\n */\n async load(\n pluginId: string,\n bundleUrl: string,\n version: string,\n expectedHash?: string,\n grants?: PluginGrants,\n ): Promise<RegisteredUIPlugin> {\n // Tenant boundary FIRST — fail closed without a tenant, drop the previous\n // tenant's modules on a switch, and CAPTURE the tenant + generation at entry\n // so a switch during the async load is caught before any result is used.\n const tenant = this.requireTenant();\n const epoch = this.epoch;\n\n // 1. In-memory cache — instant\n const cached = this.getComponentFromMemory(pluginId, bundleUrl);\n if (cached) {\n // Record the reuse. load() returns HERE, before loadModule, so without\n // this the provenance would freeze on the first download/disk source and\n // getLoadedBundles() would never report a memory serve. (loadModule's\n // own memory branch covers the loadTools path, which has no early return.)\n this.markMemoryHit(bundleUrl, expectedHash);\n if (grants) await this.commitTools(pluginId, bundleUrl, grants, tenant, epoch);\n return cached;\n }\n\n // 2. Deduplicate in-flight downloads for same bundleUrl\n let modulePromise = this.inflight.get(bundleUrl);\n if (!modulePromise) {\n const promise = this.loadModule(bundleUrl, version, expectedHash, tenant, epoch);\n modulePromise = promise;\n this.inflight.set(bundleUrl, promise);\n // Swallow rejection on the cleanup chain — the original `await` below\n // still surfaces the error to the caller. Delete ONLY our own entry: a\n // tenant switch clears `inflight` and the incoming tenant installs a NEW\n // promise for the same url, so an unconditional delete here would evict\n // B's live entry when stale A finally settles — breaking dedup and letting\n // a duplicate B load start.\n promise.catch(() => {}).finally(() => {\n if (this.inflight.get(bundleUrl) === promise) this.inflight.delete(bundleUrl);\n });\n }\n\n await modulePromise;\n\n // The switch could have landed while we awaited. Even if another tenant has\n // since populated modules[bundleUrl], this load must not return that code.\n if (this.isStale(epoch, tenant)) {\n throw new Error('[BundleManager] tenant changed while loading — discarding (fail closed)');\n }\n\n // Tools register at LOAD, not at mount — and for a UI bundle too, so a hybrid\n // plugin's tools are callable whether or not its component is found.\n if (grants) await this.commitTools(pluginId, bundleUrl, grants, tenant, epoch);\n\n // 3. Extract component for this specific pluginId\n const component = this.getComponentFromMemory(pluginId, bundleUrl);\n if (!component) {\n throw new Error(\n `Bundle loaded from ${bundleUrl} but no component found for \"${pluginId}\". ` +\n `Available exports: ${this.describeModule(this.modules.get(bundleUrl))}`\n );\n }\n\n return component;\n }\n\n /**\n * Load a bundle for its `tools/` section only — no UI required.\n *\n * Same download, same integrity check, same evaluation as `load()`; the only\n * difference is that a bundle exporting tools and no `Component` is a success\n * here rather than \"no component found\". Returns the tool names registered.\n *\n * `grants` is REQUIRED: the tools are registered under `pluginId` with exactly\n * what the manifest grants (see load()), never what the bundle claims.\n */\n async loadTools(\n pluginId: string,\n bundleUrl: string,\n version: string,\n expectedHash: string | undefined,\n grants: PluginGrants,\n ): Promise<string[]> {\n if (!grants) {\n throw new Error(`[BundleManager] loadTools(${pluginId}) needs the manifest's grants (resolvePluginGrants) — refusing to register tools on the bundle's own claim`);\n }\n // Tenant boundary FIRST — same fail-closed / drop-on-switch as load(), and\n // capture the tenant + generation for the stale check after the async load.\n const tenant = this.requireTenant();\n const epoch = this.epoch;\n let modulePromise = this.inflight.get(bundleUrl);\n if (!modulePromise) {\n const promise = this.loadModule(bundleUrl, version, expectedHash, tenant, epoch);\n modulePromise = promise;\n this.inflight.set(bundleUrl, promise);\n // Delete ONLY our own entry — see load() for why an unconditional delete\n // lets stale A evict B's live inflight promise across a tenant switch.\n promise.catch(() => {}).finally(() => {\n if (this.inflight.get(bundleUrl) === promise) this.inflight.delete(bundleUrl);\n });\n }\n await modulePromise;\n\n if (this.isStale(epoch, tenant)) {\n throw new Error('[BundleManager] tenant changed while loading tools — discarding (fail closed)');\n }\n await this.commitTools(pluginId, bundleUrl, grants, tenant, epoch);\n\n const names = listDeviceTools()\n .filter(t => t.pluginId === pluginId)\n .map(t => t.name);\n\n if (names.length === 0) {\n console.warn(\n `[BundleManager] ${pluginId}: bundle loaded from ${bundleUrl} but registered no tools. ` +\n `Available exports: ${this.describeModule(this.modules.get(bundleUrl))}`,\n );\n }\n return names;\n }\n\n /**\n * Prewarm: load every plugin bundle in the background after app boot, so a\n * later open is instant (in-memory hit) instead of round-tripping the\n * network. Errors are swallowed per-plugin — one bad bundle shouldn't\n * block others. Concurrency capped at 3.\n */\n async prewarmAll(items: Array<{\n pluginId: string;\n bundleUrl: string;\n version: string;\n bundleHash?: string;\n /** The manifest's grants, when the caller has the manifest (see load()). */\n grants?: PluginGrants;\n }>): Promise<void> {\n const queue = [...items];\n const concurrency = Math.min(3, queue.length);\n const start = Date.now();\n let okCount = 0;\n let failCount = 0;\n\n const worker = async () => {\n while (queue.length > 0) {\n const it = queue.shift();\n if (!it) return;\n try {\n await this.load(it.pluginId, it.bundleUrl, it.version, it.bundleHash, it.grants);\n okCount++;\n } catch (err) {\n failCount++;\n // Silent — preload is best-effort. Log for diagnostics only.\n console.log(`[prewarm] ${it.pluginId}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n };\n\n await Promise.all(Array.from({ length: concurrency }, worker));\n console.log(`[prewarm] ${okCount} loaded, ${failCount} failed in ${Date.now() - start}ms`);\n }\n\n /**\n * Clear all caches (in-memory + storage).\n */\n async clearAll(): Promise<void> {\n // Full reset — in-memory modules + provenance + inflight + the device tools\n // this manager registered, then the tenant marker and the disk storage.\n this.dropInMemory();\n this.cacheTenant = null;\n try {\n await getBundleStorage().clearAll();\n } catch (err) {\n console.warn('[BundleManager] clearAll error:', err);\n }\n }\n\n /**\n * Clear cache for a specific plugin/bundle.\n */\n async clearPlugin(pluginId: string): Promise<void> {\n const storage = getBundleStorage();\n const index = await storage.loadIndex();\n const entry = index[pluginId];\n if (entry) {\n this.modules.delete(entry.bundleUrl);\n delete index[pluginId];\n await storage.saveIndex(index);\n try {\n await storage.deleteBundle(entry.localPath);\n } catch { /* ignore */ }\n }\n }\n\n /**\n * What every loaded bundle IS, right now: the sha256 of the bytes running,\n * the hash the server advertised, and where they came from.\n *\n * Deliberately not filtered or prettified — this is the raw answer to \"did my\n * redeploy reach the phone?\", and it is comparable directly against the\n * manifest `bundleHash` and the server's X-Bundle-SHA256 header.\n */\n getLoadedBundles(): LoadedBundleInfo[] {\n return [...this.provenance.values()];\n }\n\n // ── Private: module loading pipeline ────────────────────────\n\n private async loadModule(\n bundleUrl: string,\n version: string,\n expectedHash: string | undefined,\n // The tenant + generation captured at the caller's ENTRY. Every step that\n // commits into the singleton (disk write, evaluate, module/provenance set,\n // tool registration) is gated on these still being current — a switch to\n // another tenant during the download must NOT let this load's results land.\n expectedTenant: string,\n expectedEpoch: number,\n ): Promise<void> {\n // The boundary may already have moved before we even start (a switch landed\n // between requireTenant() and here). Fail closed rather than proceed.\n if (this.isStale(expectedEpoch, expectedTenant)) {\n throw new Error('[BundleManager] tenant changed before load started — discarding (fail closed)');\n }\n // Already in memory? Then the running bytes are whatever this session\n // already evaluated — record the reuse so provenance never goes silent.\n if (this.modules.has(bundleUrl)) {\n this.markMemoryHit(bundleUrl, expectedHash);\n return;\n }\n\n const storage = getBundleStorage();\n const index = await storage.loadIndex();\n const expectedLc = expectedHash ? expectedHash.toLowerCase() : null;\n\n // Check disk cache. A cache hit is only valid when the cached SHA-256\n // matches the manifest hash exactly — never trust a cached bundle\n // without proof. The file is read via entry.localPath (the content-addressed\n // path recorded at write time), never reconstructed from url+version, so a\n // hit follows the index straight to the right bytes.\n let content: string | null = null;\n // The SHA-256 that gate-kept THIS content (the manifest hash for a cache hit,\n // the freshly-verified download hash otherwise) — re-checked inline at the\n // eval so a tampered cache file cannot run (see evaluate()).\n let verifiedHash: string | null = null;\n let servedFrom: LoadedBundleSource = 'download';\n for (const entry of Object.values(index)) {\n if (entry.bundleUrl === bundleUrl && entry.version === version) {\n const age = Date.now() - entry.timestamp;\n const hashOk = expectedLc && entry.bundleHash && entry.bundleHash.toLowerCase() === expectedLc;\n if (age < CACHE_TTL && hashOk) {\n content = await storage.readBundle(entry.localPath);\n if (content) { verifiedHash = entry.bundleHash!.toLowerCase(); servedFrom = 'disk-cache'; break; }\n }\n }\n }\n\n // Download if not cached\n if (!content) {\n const downloaded = await this.download(bundleUrl, expectedLc);\n content = downloaded.content;\n verifiedHash = downloaded.sha256.toLowerCase();\n // The download is the long await where a tenant switch is most likely to\n // land. If it did, discard NOW — before we stamp a disk-cache entry with\n // the (now wrong) current tenant.\n if (this.isStale(expectedEpoch, expectedTenant)) {\n throw new Error('[BundleManager] tenant changed during download — discarding (fail closed)');\n }\n // Save with verified hash. CONTENT-ADDRESS the file by its own sha256, NOT\n // by url+version: a bundleUrl+version pair is identical across tenants but\n // resolves to DIFFERENT bytes per tenant, so a url+version filename is\n // SHARED between them. A stale tenant-A writeBundle that completes after a\n // switch to B would then clobber B's cached file bytes at that shared path.\n // Keying the file by verifiedHash gives A's bytes and B's bytes distinct\n // paths that can never collide (identical bytes dedup to one file, which is\n // correct). The index entry below — keyed by url, stamped with the captured\n // tenant + hash + this localPath — is unchanged and stays authoritative.\n try {\n const localPath = await storage.writeBundle(`${verifiedHash}.js`, content);\n // The index entry is the AUTHORITATIVE disk-cache commit: loadFromDiskCache\n // reads the index (a loose file with no entry is never selected), and it\n // trusts the entry's `tenant` stamp as the authorization boundary while\n // passing the entry's OWN hash (an integrity check that cannot fail). So:\n // (a) stamp ownership from the CAPTURED tenant, never live getTenant() —\n // writeBundle awaited, and a switch here would otherwise label A's\n // bytes as B, which the recovery path would later re-run under B;\n // (b) do not publish the entry at all if the tenant/generation moved\n // while we awaited — fail closed, leaving only an orphan file.\n if (!this.isStale(expectedEpoch, expectedTenant)) {\n index[bundleUrl] = {\n localPath,\n version,\n timestamp: Date.now(),\n bundleUrl,\n bundleHash: downloaded.sha256,\n tenant: expectedTenant,\n } satisfies BundleCacheEntry;\n await storage.saveIndex(index);\n }\n } catch (err) {\n console.warn('[BundleManager] Cache write error:', err);\n }\n }\n\n // FINAL boundary check before anything commits into the singleton. This is\n // the one that also covers the disk-cache-hit path (which never entered the\n // download branch above). Everything after this line — evaluate, module set,\n // provenance set, tool registration — writes tenant-scoped state; if the\n // tenant moved while we awaited, none of it may land (fail closed).\n if (this.isStale(expectedEpoch, expectedTenant)) {\n throw new Error('[BundleManager] tenant changed while loading — discarding stale bundle before eval (fail closed)');\n }\n\n // Evaluate — the eval re-hashes `content` against verifiedHash first.\n const mod = this.evaluate(content, bundleUrl, verifiedHash);\n this.modules.set(bundleUrl, mod);\n\n // Record WHAT IS RUNNING. Until this existed, nothing on the device or the\n // server could answer \"which build is the phone actually executing?\" — so a\n // redeploy that failed to arrive was indistinguishable from one that did,\n // and the only diagnosis available was to reinstall and guess.\n // `expected` is the server's advertised manifest hash: when it differs from\n // `hash`, the phone is running something the server did not just describe.\n this.provenance.set(bundleUrl, {\n bundleUrl,\n version,\n hash: verifiedHash,\n expected: expectedLc,\n source: servedFrom,\n // The captured owner — same rule as the disk stamp. The final stale check\n // above guarantees getTenant() === expectedTenant here, but binding it to\n // the captured value keeps the ownership record impossible to mislabel.\n tenant: expectedTenant,\n loadedAt: Date.now(),\n });\n console.log(\n `[BundleManager] RUNNING ${bundleUrl} v${version} sha=${(verifiedHash || 'none').slice(0, 12)} ` +\n `(${servedFrom}${expectedLc && verifiedHash && expectedLc !== verifiedHash ? `, EXPECTED ${expectedLc.slice(0, 12)} — STALE` : ''})`,\n );\n }\n\n /**\n * Register THIS plugin's device tools under the TRUSTED declaration, then\n * record that declaration on the disk-cache entry. Runs on every trusted load\n * — memory hit included — so the grants in force are always the latest the\n * manifest gave (a revoked grant stops applying on the next load, not the next\n * app start). Callers run it only after their stale check.\n */\n private async commitTools(\n pluginId: string,\n bundleUrl: string,\n grants: PluginGrants,\n tenant: string,\n epoch: number,\n ): Promise<void> {\n const declaration: TrustedToolDeclaration = {\n pluginId,\n capabilities: grants.capabilities,\n stateDomains: grants.stateDomains,\n };\n this.registerToolsFromModule(this.modules.get(bundleUrl), declaration);\n await this.recordTrustedDeclaration(bundleUrl, declaration, tenant, epoch);\n }\n\n /**\n * Put the plugin's own `tools` section in the device tool registry — under the\n * pluginId and grants the MANIFEST resolved, never the bundle's own `id`,\n * `capabilities` or `stateDomains`. A bundle is code the manifest authorised\n * by hash; what it may touch is the manifest's to say, same as its rendered\n * surface (resolvePluginRuntimeProps). Its own `id` would also let it register\n * as another plugin — including the host's platform tools, which a same-id\n * re-registration replaces.\n *\n * Only this plugin's export (the same lookup the component uses) is\n * registered. Another export's tools in the same bundle belong to another\n * plugin and register when THAT plugin's manifest loads it.\n */\n private registerToolsFromModule(mod: any, { pluginId, capabilities, stateDomains }: TrustedToolDeclaration): void {\n if (!mod) return;\n\n const own = this.findPluginExport(mod, pluginId, hasTools);\n const others = Object.keys(mod).filter((k) => hasTools(mod[k]) && mod[k] !== own);\n if (others.length > 0) {\n console.warn(\n `[BundleManager] ${pluginId}: not registering tools from export(s) ${others.join(', ')} — ` +\n `they are not this plugin's, and only their own manifest can grant them`,\n );\n }\n if (!own) return;\n\n // The bundle's own declaration grants nothing, but a gap between it and the\n // manifest is the author's bug — name it, or the tool just reads \"not declared\".\n const ungranted = [\n ...(Array.isArray(own.stateDomains) ? own.stateDomains : []).filter((d: any) => !stateDomains?.includes(d)),\n ...Object.keys(own.capabilities || {}).filter((k) => own.capabilities[k] === true && !(capabilities as any)?.[k]),\n ];\n if (ungranted.length > 0) {\n console.warn(\n `[BundleManager] ${pluginId}: bundle declares ${ungranted.join(', ')} but the manifest does not grant it — denied`,\n );\n }\n\n try {\n registerDeviceTools(pluginId, own.tools, capabilities, stateDomains);\n // Remember it so a tenant switch (or clearAll) can unregister the OLD\n // tenant's tools before the incoming tenant re-registers.\n this.registeredToolPluginIds.add(pluginId);\n } catch (err) {\n console.warn(\n `[BundleManager] tool registration failed for ${pluginId}:`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n /**\n * Record the trusted declaration on this tenant's disk-cache entry for the\n * bytes RUNNING — the recovery path (tools/loader loadFromDiskCache) has no\n * manifest and re-registers with exactly this. Only onto an entry this tenant\n * owns whose hash is the running hash: the grant was issued for these bytes,\n * and those are the bytes recovery will evaluate. Best-effort — a lost write\n * leaves no `trusted`, which recovery treats as fail closed.\n */\n private async recordTrustedDeclaration(\n bundleUrl: string,\n declaration: TrustedToolDeclaration,\n tenant: string,\n epoch: number,\n ): Promise<void> {\n const key = JSON.stringify(declaration);\n if (this.recordedDeclarations.get(bundleUrl) === key) return;\n try {\n const storage = getBundleStorage();\n const index = await storage.loadIndex();\n const entry = index[bundleUrl];\n const running = this.provenance.get(bundleUrl)?.hash;\n if (!entry || entry.tenant !== tenant || !running || entry.bundleHash?.toLowerCase() !== running) return;\n if (this.isStale(epoch, tenant)) return;\n if (JSON.stringify(entry.trusted) !== key) {\n index[bundleUrl] = { ...entry, trusted: declaration };\n await storage.saveIndex(index);\n }\n this.recordedDeclarations.set(bundleUrl, key);\n } catch (err) {\n console.warn('[BundleManager] could not record trusted declaration:', err);\n }\n }\n\n /**\n * Download + integrity-verify a bundle. Refuses to return when:\n * - manifest hash and computed hash disagree\n * - server's `X-Bundle-SHA256` disagrees with manifest hash\n * - no expected hash AND no server hash header (cannot prove the bundle\n * wasn't tampered with — fail closed rather than trust the wire).\n */\n private async download(bundleUrl: string, expectedHash: string | null): Promise<{ content: string; sha256: string }> {\n const cacheBust = `${bundleUrl}${bundleUrl.includes('?') ? '&' : '?'}t=${Date.now()}`;\n const response = await apiFetchRaw(cacheBust);\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new Error(`Download failed: ${response.status} ${response.statusText} — ${body.substring(0, 200)}`);\n }\n\n const content = await response.text();\n if (content.length < 50 || content.trimStart().startsWith('<!')) {\n throw new Error('Bundle content is empty or HTML — server may have returned an error page');\n }\n\n const headerHash = (response.headers.get('x-bundle-sha256') || '').toLowerCase();\n const computed = sha256Hex(content);\n\n if (expectedHash) {\n if (computed !== expectedHash) {\n throw new Error(\n `Bundle integrity FAIL: expected sha256=${expectedHash.slice(0, 12)}... got ${computed.slice(0, 12)}.... Refusing to evaluate.`\n );\n }\n if (headerHash && headerHash !== expectedHash) {\n throw new Error(\n `Bundle hash mismatch: manifest=${expectedHash.slice(0, 12)}... server=${headerHash.slice(0, 12)}.... Refusing to evaluate.`\n );\n }\n } else if (headerHash) {\n if (computed !== headerHash) {\n throw new Error(\n `Bundle body sha256 (${computed.slice(0, 12)}...) does not match server's X-Bundle-SHA256 (${headerHash.slice(0, 12)}...).`\n );\n }\n console.warn(`[BundleManager] No manifest bundleHash — verified via X-Bundle-SHA256 header only`);\n } else {\n throw new Error(\n `No bundleHash in manifest and no X-Bundle-SHA256 header from server. Refusing to evaluate untrusted bundle.`\n );\n }\n\n return { content, sha256: computed };\n }\n\n private evaluate(content: string, bundleUrl: string, verifiedHash: string | null): any {\n // R8 SECURITY GATE — mandatory, fail-closed integrity INLINE at the eval, on\n // the exact bytes about to run. The download path verifies too, but a disk-\n // cache hit reads a file whose STORED metadata hash matched; it never re-hashes\n // the actual bytes, so a tampered cache file would execute. Re-hashing here\n // refuses a missing or mismatched hash whatever path produced `content`.\n //\n // NOTE — this is integrity, NOT a sandbox. `new Function` shares this JS\n // realm; a bundle that passes the hash still runs with full in-app authority\n // (its only capability gating is the plugin manifest via gatePluginNative).\n // The hash proves the bytes are the ones the trusted manifest names; it does\n // not isolate them. Publisher SIGNATURE is deliberately NOT required — the\n // manifest hash already comes from an authenticated Core call\n // (docs/decisions/REMOTE_BUNDLE_INTEGRITY.md).\n assertBundleIntegrity(content, verifiedHash, bundleUrl);\n\n // Strip __toESM wrapping — our shim already provides correct ESM objects.\n // esbuild's __toESM + isNodeMode=1 double-wraps and breaks React 19 hooks.\n let cleaned = content.replace(\n /__toESM\\(require\\((\"[^\"]+\")\\)(?:,\\s*\\d+)?\\)/g,\n 'require($1)',\n );\n\n // Strip __toCommonJS wrapper — it creates a getter-based Proxy that\n // collapses all named exports to the same object in Hermes/JSC.\n cleaned = cleaned.replace(\n /module\\.exports\\s*=\\s*__toCommonJS\\((\\w+)\\)/g,\n 'module.exports = $1',\n );\n\n const mod: { exports: any } = { exports: {} };\n try {\n const factory = new Function(\n 'module', 'exports', 'require', '__filename', '__dirname',\n cleaned,\n );\n factory(mod, mod.exports, requireShim, bundleUrl, 'adas-plugin-bundles');\n } catch (err) {\n throw new Error(`Bundle evaluation failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Materialize getter-based exports into plain values.\n // esbuild's __export uses Object.defineProperty getters which can\n // misbehave in Hermes/JSC — force-resolve them now.\n const raw = mod.exports;\n const materialized: Record<string, any> = {};\n for (const key of Object.getOwnPropertyNames(raw)) {\n try {\n materialized[key] = raw[key];\n } catch { /* skip broken getters */ }\n }\n return materialized;\n }\n\n // ── Private: component extraction ───────────────────────────\n\n /** Find a plugin component in a loaded module. */\n private getComponentFromMemory(pluginId: string, bundleUrl: string): RegisteredUIPlugin | null {\n return this.findPluginExport(this.modules.get(bundleUrl), pluginId, hasComponent);\n }\n\n /**\n * Find THIS plugin's export in a loaded module — the one lookup both the\n * component and the device tools use, so a plugin's UI and its tools always\n * come from the same export. `accept` says what the caller needs from it.\n * Handles: direct key match, PascalCase key, default export, multi-plugin .id match.\n */\n private findPluginExport(mod: any, pluginId: string, accept: (val: any) => boolean): any | null {\n if (!mod) return null;\n\n const shortName = pluginId.includes(':') ? pluginId.split(':').pop()! : pluginId;\n\n // 1. Direct key match (full pluginId as key)\n if (accept(mod[pluginId])) return mod[pluginId];\n\n // 2. PascalCase match from shortName (most reliable for combined bundles)\n // e.g., \"memories-panel\" → \"MemoriesPanel\"\n const pascal = shortName.replace(/(^|-)([a-z])/g, (_: string, __: string, c: string) => c.toUpperCase());\n if (accept(mod[pascal])) return mod[pascal];\n\n // 3. Default export (single-plugin bundles)\n if (accept(mod.default)) return mod.default;\n\n // 4. Match by .id field (last resort — can be unreliable in combined bundles)\n for (const key of Object.keys(mod)) {\n const val = mod[key];\n if (val && (val.id === pluginId || val.id === shortName) && accept(val)) return val;\n }\n\n return null;\n }\n\n private describeModule(mod: any): string {\n if (!mod) return '(empty)';\n return Object.keys(mod)\n .map(k => {\n const v = mod[k];\n if (v && typeof v === 'object' && v.id) return `${k}(id=\"${v.id}\")`;\n return k;\n })\n .join(', ');\n }\n}\n\n/** Singleton — shared across all plugin renderers */\nexport const bundleManager = new BundleManager();\n","/**\n * @adas/plugin-sdk namespace — everything a PLUGIN author imports.\n * Remote bundles resolve `require('@adas/plugin-sdk')` to exactly this\n * module via the bundle manager's require shim.\n */\n\n// Registration API\nexport { register, registerService, registerTools } from './registration';\nimport { register, registerService, registerTools } from './registration';\nexport const PluginSDK = { register, registerService, registerTools } as const;\n\n// Types\nexport type {\n PluginBridge,\n PluginNative,\n PluginContext,\n PluginProps,\n ThemeTokens,\n HapticsAPI,\n CameraAPI,\n LocationAPI,\n StorageAPI,\n NotificationsAPI,\n ConnectivityAPI,\n FileSystemAPI,\n CookiesAPI,\n WebViewCookie,\n SharingAPI,\n ScannerAPI,\n NfcAPI,\n BluetoothAPI,\n BluetoothDevice,\n VisionAPI,\n VisionText,\n VisionLabel,\n VisionObject,\n VisionFrameQuality,\n MapsAPI,\n MapsCoordinate,\n MapsAddress,\n MapsPlace,\n MapsRoute,\n MapsRouteStep,\n BiometricsAPI,\n BiometricsAPIv2,\n NativeCapabilities,\n PluginHooks,\n PluginManifest,\n RenderMode,\n RegisteredPlugin,\n RegisteredUIPlugin,\n RegisteredServicePlugin,\n RegisteredToolsPlugin,\n DeviceToolContext,\n DeviceToolDefinition,\n DeviceToolFn,\n} from './types';\n\n// Voice — the live conversational SESSION surface (props.voice).\nexport type {\n VoiceAPI,\n VoiceState,\n VoiceSnapshot,\n VoiceTranscriptEntry,\n VoiceStartOptions,\n VoicePersona,\n VoiceEvent,\n VoiceSubscription,\n VoiceCaller,\n VoiceSessionProvider,\n} from './voice';\n// The privileged platform caller (a value) — the host injects the owner-aware\n// provider and its own surfaces call it as this caller. See VoiceSessionProvider.\nexport { PLATFORM_VOICE_CALLER } from './voice';\n\n// RN primitives (plugins import from the SDK, not from react-native)\nexport {\n View,\n Text,\n ScrollView,\n FlatList,\n SectionList,\n Pressable,\n TouchableOpacity,\n TextInput,\n Image,\n ActivityIndicator,\n Modal,\n Switch,\n StyleSheet,\n Animated,\n Platform,\n RefreshControl,\n} from './primitives';\n\n// Pre-built components\nexport {\n Card,\n Badge,\n TabBar,\n ListItem,\n SearchBar,\n EmptyState,\n ErrorState,\n LoadingState,\n ActionButton,\n} from './components';\n\n// Theme + API hooks\n// Showing the camera is a COMPONENT, not a native module handed to bundles —\n// one door, one lock. See CameraPreview.tsx for why.\nexport { CameraPreview } from './CameraPreview';\nexport type { CameraPreviewProps } from './CameraPreview';\nexport { usePluginTheme, setPluginThemeColors } from './usePluginTheme';\nexport { useApi } from './useApi';\n","/**\n * Plugin registration API.\n * Solution developers use these to register their plugins.\n */\nimport type {\n DeviceToolDefinition,\n NativeCapabilities,\n PluginHooks,\n PluginProps,\n RegisteredUIPlugin,\n RegisteredServicePlugin,\n RegisteredToolsPlugin,\n} from './types';\nimport type { DeviceBridgeDomain } from './device-state';\n\n/**\n * Register a UI or hybrid plugin (has a visual component).\n *\n * `tools` is optional: a plugin may ship UI and local tools together. Tools are\n * picked up when the bundle loads, independently of whether the UI is mounted.\n */\nexport function register(\n id: string,\n config: {\n type?: 'ui' | 'hybrid';\n capabilities?: NativeCapabilities;\n /** L3 DeviceState domains this plugin's UI reads via props.deviceState (e.g.\n * ['spatial','visual']). Carried through so a HOST-registered plugin (no\n * server manifest) can declare its domains — resolvePluginRuntimeProps reads\n * this as the trusted source when there is no manifest. Dropping it here left\n * every registered UI plugin with no L3, silently. Mirrors registerTools. */\n stateDomains?: DeviceBridgeDomain[];\n Component: React.FC<PluginProps>;\n tools?: DeviceToolDefinition[];\n },\n): RegisteredUIPlugin {\n return {\n id,\n type: config.type || 'ui',\n capabilities: config.capabilities,\n stateDomains: config.stateDomains,\n Component: config.Component,\n tools: config.tools,\n };\n}\n\n/**\n * Register a tools-only plugin — a `tools/` section with no UI at all.\n *\n * Nothing here mounts. The tools become callable as soon as the bundle is\n * evaluated, and stay callable with nothing of the plugin on screen.\n */\nexport function registerTools(\n id: string,\n config: {\n capabilities?: NativeCapabilities;\n /** L3 DeviceState domains the tools read via ctx.deviceState (e.g. ['visual']).\n * For a remote bundle the MANIFEST grants them — see RegisteredToolsPlugin. */\n stateDomains?: DeviceBridgeDomain[];\n tools: DeviceToolDefinition[];\n },\n): RegisteredToolsPlugin {\n return {\n id,\n type: 'tools',\n capabilities: config.capabilities,\n stateDomains: config.stateDomains,\n tools: config.tools,\n };\n}\n\n/**\n * Register a headless service plugin (no UI).\n */\nexport function registerService(\n id: string,\n config: {\n capabilities?: NativeCapabilities;\n hooks?: PluginHooks;\n onStart: (props: Omit<PluginProps, 'theme'>) => Promise<void> | void;\n onStop?: () => Promise<void> | void;\n },\n): RegisteredServicePlugin {\n return {\n id,\n type: 'service',\n capabilities: config.capabilities,\n hooks: config.hooks,\n onStart: config.onStart,\n onStop: config.onStop,\n };\n}\n","/**\n * props.voice — the live conversational SESSION a plugin may drive.\n *\n * Voice is a SESSION, not a device sensor. `props.device.*` is mechanical verbs\n * that throw; `props.deviceState.*` is eight semantic domains describing the\n * device. A Realtime conversation is neither — it is a long-lived loop with its\n * own state (connecting/connected), its own transcript, and two ways to take a\n * turn (the user speaks, or the agent speaks first). So it gets its own gated\n * surface, mirroring the deviceState GRAMMAR (start / stop / getSnapshot /\n * subscribe) because a reasoning loop reads it the same way — state with\n * freshness, not bare values.\n *\n * TRUST BOUNDARY. This type is the WHOLE surface. There is deliberately NO way\n * from here to inject fake user speech, read raw audio, reach the WebView, or\n * hide the mic-active indicator — those are new doors, and the reason\n * `CameraPreview` is a component rather than a module is that we keep closing\n * doors of that shape. `prompt()` is an AGENT turn, not a forged user turn.\n *\n * See docs/handoff/SPEC_voice_session_without_the_voice_screen_2026-09-12.md.\n */\n\n/** The session lifecycle — identical vocabulary to the built-in `CallState`. */\nexport type VoiceState = 'idle' | 'connecting' | 'connected' | 'error';\n\n/** One line of the conversation. `tool` entries are device/skill tool activity. */\nexport interface VoiceTranscriptEntry {\n role: 'user' | 'ai' | 'tool';\n text: string;\n ts: number;\n}\n\n/** A point-in-time read of the session — what a reasoning loop polls. */\nexport interface VoiceSnapshot {\n state: VoiceState;\n sessionId: string | null;\n muted: boolean;\n /** The agent is currently producing audio. */\n speaking: boolean;\n /** The user is currently being heard (partial user transcript in flight). */\n listening: boolean;\n /** The user is currently speaking, per the session's own VAD (authoritative,\n * distinct from `listening` which tracks a partial transcript). */\n userSpeaking: boolean;\n /**\n * Epoch ms of the last moment the user STOPPED speaking, or `null` if they\n * have not spoken yet this session. `null` is deliberate and load-bearing: a\n * silence timer must arm on the first real `speaking:false`, never at session\n * start — \"not speaking\" and \"has never spoken\" are different, and arming on\n * the wrong one fires before anyone has said anything.\n */\n lastUserSpeechEndedAt: number | null;\n /** The last error, if `state === 'error'`; also carries a refusal reason when\n * this surface was handed to a plugin that did not declare `voice`. */\n lastError: string | null;\n /** The most recent LOCAL device-tool call the model made through the session\n * (name + epoch ms), or null if none yet. Diagnostic: proves whether the\n * model's call_device_tool actually reached the phone vs was never made. */\n lastDeviceTool: { name: string; at: number } | null;\n /** The sessionId the Core allowset is bound to. Diagnostic: authorization\n * requires it to equal `sessionId`; a mismatch is why tools refuse. */\n authorizedSessionId: string | null;\n}\n\nexport interface VoiceStartOptions {\n /** Hand the mic to a specific skill on connect (voice /session → takeMic),\n * exactly as `sys.focusUiPlugin(\"platform:voice\", { skillSlug })` does. */\n skillSlug?: string;\n /**\n * A PER-CALL persona override, same shape as the authored\n * `solution.voice.persona` ({ name, style }). Declared on the voice\n * session-create call (POST /session `persona`); the server sanitizes it\n * (name/style only, length-capped) and layers it OVER the solution's authored\n * persona for THIS call only — prompt-layer, so it can never touch caller\n * verification or tool allow-lists. Set once at session start and constant\n * for the call, so it adds no per-turn prompt pushes.\n *\n * Use it when a plugin needs its own voice persona without owning a skill\n * (e.g. a guide HUD). A solution-wide persona belongs in solution.voice.\n */\n persona?: VoicePersona;\n /**\n * `'none'` = a CLEAN call: the voice gets none of the workspace's skills — no\n * skill manifest, no skill tools, no platform welcome line, no mid-call\n * skill-state prompt refresh — only the voice basics, this call's persona and\n * the CALLING plugin's own device tools (other solutions' tools registered on\n * the same phone are neither offered nor run). For a plugin that owns its conversation (e.g.\n * a guide HUD). Reduce-only: it can remove what the voice gets, never add.\n * Absent = the workspace's skills, as today. Not combinable with `skillSlug`.\n */\n skills?: 'none';\n}\n\n/** The authored persona shape (solution.voice.persona). */\nexport interface VoicePersona {\n /** The name the voice uses for itself (\"You are <name> …\"). */\n name?: string;\n /** Free-text style/behaviour guidance rendered under the identity line. */\n style?: string;\n}\n\n/**\n * What changed. Coarse on purpose: `state` covers connect/mute/session/partials,\n * `transcript` fires when a finalized line was appended. A subscriber re-reads\n * `getSnapshot()` / `transcript()` — the event is a nudge, not a payload, so the\n * surface never has to keep two shapes of the same fact in sync.\n */\nexport type VoiceEvent = { type: 'state' } | { type: 'transcript' };\n\nexport interface VoiceSubscription {\n unsubscribe(): void;\n}\n\n/**\n * WHO is asking. The one physical session has an OWNER; access is scoped to it.\n *\n * A plugin's caller is its `pluginId` (a string), stamped by gateVoice so the\n * plugin never supplies its own identity. The PLATFORM caller — the built-in\n * voice screen, the user's own surface — is a Symbol, deliberately: a Symbol can\n * never equal any pluginId string, so a plugin cannot forge platform access by\n * naming itself `platform:voice`.\n */\nexport type VoiceCaller = string | symbol;\n\n/** The privileged caller — the platform's own surfaces (the built-in sheet, the\n * mic indicator, the session host). Sees and controls any live session, because\n * it is the USER's direct surface onto their own conversation. Unforgeable. */\nexport const PLATFORM_VOICE_CALLER: unique symbol = Symbol('adas.voice.platform');\n\n/**\n * The OWNER-AWARE session the HOST implements and hands to setVoiceProvider.\n *\n * This is NOT what a plugin receives — a plugin gets a `VoiceAPI` facade\n * (gateVoice) that stamps its `pluginId` as the caller on every call, so the\n * provider can enforce that a plugin only ever reads, controls, or attaches to a\n * session IT owns. One physical session, isolated per authorized identity.\n */\nexport interface VoiceSessionProvider {\n start(opts: VoiceStartOptions | undefined, caller: VoiceCaller): Promise<VoiceSnapshot>;\n stop(caller: VoiceCaller): void;\n setMuted(muted: boolean, caller: VoiceCaller): void;\n prompt(input: string, caller: VoiceCaller): void;\n observe(text: string, caller: VoiceCaller): void;\n getSnapshot(caller: VoiceCaller): VoiceSnapshot;\n subscribe(cb: (event: VoiceEvent) => void, caller: VoiceCaller): VoiceSubscription;\n transcript(caller: VoiceCaller): VoiceTranscriptEntry[];\n}\n\n/**\n * The gated surface a plugin receives as `props.voice`. Present on EVERY plugin;\n * a plugin that did not declare `capabilities: { voice: true }` gets a version\n * whose reads say so and whose actions throw — never a silent no-op, never a\n * fake `idle` (see gateVoice in voiceHost.ts).\n */\nexport interface VoiceAPI {\n /** Open the live loop. Resolves once connected (or rejects on connect error).\n * If a session is ALREADY live, ATTACHES to it and resolves immediately —\n * never a second Realtime loop (one phone, one mic, one bill). */\n start(opts?: VoiceStartOptions): Promise<VoiceSnapshot>;\n /** End the live loop. Safe to call when idle. */\n stop(): void;\n /** Mute/unmute the microphone. The session stays live; the mic indicator\n * reflects it. */\n setMuted(muted: boolean): void;\n /**\n * Make the agent take a turn WITHOUT the user speaking — the guide speaking\n * first. `input` is the instruction for that turn. This is an agent-initiated\n * turn into the SAME session, NOT fabricated user speech: one session, two\n * trigger sources. Throws if the session is not connected.\n */\n prompt(input: string): void;\n /**\n * Stream a silent OBSERVATION into the session — tell the model something\n * without asking it to speak (a `system` conversation item). Cheap and\n * high-frequency (safe once or twice a second): this is the channel for what\n * the camera sees while the user walks. The model answers with the\n * observations in hand the next time it takes a turn (user VAD, or prompt()) —\n * an observation never triggers a turn by itself. Throws if not connected.\n */\n observe(text: string): void;\n /** Point-in-time session state. */\n getSnapshot(): VoiceSnapshot;\n /** Subscribe to state + transcript changes. Returns an unsubscribe handle. */\n subscribe(cb: (event: VoiceEvent) => void): VoiceSubscription;\n /** The conversation so far. */\n transcript(): VoiceTranscriptEntry[];\n}\n","/**\n * Re-exported React Native primitives.\n * Plugins import these from '@adas/plugin-sdk' — never from 'react-native' directly.\n */\nexport {\n View,\n Text,\n ScrollView,\n FlatList,\n SectionList,\n Pressable,\n TouchableOpacity,\n TextInput,\n Image,\n ActivityIndicator,\n Modal,\n Switch,\n StyleSheet,\n Animated,\n Platform,\n RefreshControl,\n} from 'react-native';\n","/**\n * Pre-built UI components for native plugins.\n * These provide consistent styling using ThemeTokens.\n */\nimport React from 'react';\nimport {\n View,\n Text,\n Pressable,\n TextInput,\n ActivityIndicator,\n StyleSheet,\n} from 'react-native';\nimport type { ThemeTokens } from './types';\n\n// ── Card ────────────────────────────────────────────────────\n\ninterface CardProps {\n theme: ThemeTokens;\n children: React.ReactNode;\n style?: any;\n onPress?: () => void;\n}\n\nexport function Card({ theme, children, style, onPress }: CardProps) {\n const cardStyle = [\n styles.card,\n {\n backgroundColor: theme.colors.surface,\n borderColor: theme.colors.border,\n },\n style,\n ];\n\n if (onPress) {\n return React.createElement(Pressable, { style: cardStyle, onPress }, children);\n }\n return React.createElement(View, { style: cardStyle }, children);\n}\n\n// ── Badge ───────────────────────────────────────────────────\n\ninterface BadgeProps {\n theme: ThemeTokens;\n label: string;\n color?: 'accent' | 'success' | 'warning' | 'error' | 'purple';\n style?: any;\n}\n\nconst BADGE_COLORS = {\n accent: { bg: 'accentSoft', text: 'accent' },\n success: { bg: 'successSoft', text: 'success' },\n warning: { bg: 'warningSoft', text: 'warning' },\n error: { bg: 'errorSoft', text: 'error' },\n purple: { bg: 'purpleSoft', text: 'purple' },\n} as const;\n\nexport function Badge({ theme, label, color = 'accent', style }: BadgeProps) {\n const mapping = BADGE_COLORS[color];\n return React.createElement(\n View,\n {\n style: [\n styles.badge,\n {\n backgroundColor: theme.colors[mapping.bg],\n borderRadius: theme.borderRadius.sm,\n },\n style,\n ],\n },\n React.createElement(Text, {\n style: [styles.badgeText, { color: theme.colors[mapping.text] }],\n }, label),\n );\n}\n\n// ── TabBar ──────────────────────────────────────────────────\n\ninterface TabBarProps {\n theme: ThemeTokens;\n tabs: string[];\n activeTab: string;\n onTabChange: (tab: string) => void;\n style?: any;\n}\n\nexport function TabBar({ theme, tabs, activeTab, onTabChange, style }: TabBarProps) {\n return React.createElement(\n View,\n {\n style: [\n styles.tabBar,\n { borderBottomColor: theme.colors.border },\n style,\n ],\n },\n tabs.map((tab) =>\n React.createElement(\n Pressable,\n {\n key: tab,\n style: [\n styles.tab,\n {\n borderBottomColor: tab === activeTab ? theme.colors.accent : 'transparent',\n },\n ],\n onPress: () => onTabChange(tab),\n },\n React.createElement(Text, {\n style: {\n color: tab === activeTab ? theme.colors.accent : theme.colors.textSecondary,\n fontSize: theme.fontSize.sm,\n fontWeight: tab === activeTab ? '600' : '400',\n },\n }, tab),\n ),\n ),\n );\n}\n\n// ── ListItem ────────────────────────────────────────────────\n\ninterface ListItemProps {\n theme: ThemeTokens;\n title: string;\n subtitle?: string;\n right?: React.ReactNode;\n onPress?: () => void;\n style?: any;\n}\n\nexport function ListItem({ theme, title, subtitle, right, onPress, style }: ListItemProps) {\n const content = [\n React.createElement(\n View,\n { key: 'content', style: styles.listItemContent },\n React.createElement(Text, {\n style: { color: theme.colors.text, fontSize: theme.fontSize.md },\n numberOfLines: 1,\n }, title),\n subtitle\n ? React.createElement(Text, {\n style: { color: theme.colors.textSecondary, fontSize: theme.fontSize.xs, marginTop: 2 },\n numberOfLines: 1,\n }, subtitle)\n : null,\n ),\n right ? React.createElement(View, { key: 'right' }, right) : null,\n ];\n\n if (onPress) {\n return React.createElement(\n Pressable,\n { style: [styles.listItem, { borderBottomColor: theme.colors.border }, style], onPress },\n ...content,\n );\n }\n return React.createElement(\n View,\n { style: [styles.listItem, { borderBottomColor: theme.colors.border }, style] },\n ...content,\n );\n}\n\n// ── SearchBar ───────────────────────────────────────────────\n\ninterface SearchBarProps {\n theme: ThemeTokens;\n value: string;\n onChangeText: (text: string) => void;\n placeholder?: string;\n style?: any;\n}\n\nexport function SearchBar({ theme, value, onChangeText, placeholder = 'Search...', style }: SearchBarProps) {\n return React.createElement(TextInput, {\n style: [\n styles.searchBar,\n {\n backgroundColor: theme.colors.input,\n color: theme.colors.text,\n borderColor: theme.colors.border,\n borderRadius: theme.borderRadius.sm,\n fontSize: theme.fontSize.sm,\n },\n style,\n ],\n value,\n onChangeText,\n placeholder,\n placeholderTextColor: theme.colors.textMuted,\n autoCapitalize: 'none',\n autoCorrect: false,\n });\n}\n\n// ── EmptyState ──────────────────────────────────────────────\n\ninterface EmptyStateProps {\n theme: ThemeTokens;\n title: string;\n subtitle?: string;\n style?: any;\n}\n\nexport function EmptyState({ theme, title, subtitle, style }: EmptyStateProps) {\n return React.createElement(\n View,\n { style: [styles.emptyState, style] },\n React.createElement(Text, {\n style: { color: theme.colors.textSecondary, fontSize: theme.fontSize.md, textAlign: 'center' },\n }, title),\n subtitle\n ? React.createElement(Text, {\n style: { color: theme.colors.textMuted, fontSize: theme.fontSize.sm, textAlign: 'center', marginTop: 4 },\n }, subtitle)\n : null,\n );\n}\n\n// ── ErrorState ──────────────────────────────────────────────\n\ninterface ErrorStateProps {\n theme: ThemeTokens;\n message: string;\n onRetry?: () => void;\n style?: any;\n}\n\nexport function ErrorState({ theme, message, onRetry, style }: ErrorStateProps) {\n return React.createElement(\n View,\n { style: [styles.emptyState, style] },\n React.createElement(Text, {\n style: { color: theme.colors.error, fontSize: theme.fontSize.md, textAlign: 'center' },\n }, message),\n onRetry\n ? React.createElement(\n Pressable,\n {\n style: [styles.retryButton, { backgroundColor: theme.colors.accentSoft, borderRadius: theme.borderRadius.sm }],\n onPress: onRetry,\n },\n React.createElement(Text, {\n style: { color: theme.colors.accent, fontSize: theme.fontSize.sm, fontWeight: '600' },\n }, 'Retry'),\n )\n : null,\n );\n}\n\n// ── LoadingState ────────────────────────────────────────────\n\ninterface LoadingStateProps {\n theme: ThemeTokens;\n message?: string;\n style?: any;\n}\n\nexport function LoadingState({ theme, message = 'Loading...', style }: LoadingStateProps) {\n return React.createElement(\n View,\n { style: [styles.emptyState, style] },\n React.createElement(ActivityIndicator, { size: 'small', color: theme.colors.accent }),\n React.createElement(Text, {\n style: { color: theme.colors.textSecondary, fontSize: theme.fontSize.sm, marginTop: 8 },\n }, message),\n );\n}\n\n// ── ActionButton (FAB) ──────────────────────────────────────\n\ninterface ActionButtonProps {\n theme: ThemeTokens;\n label?: string;\n icon?: React.ReactNode;\n onPress: () => void;\n style?: any;\n}\n\nexport function ActionButton({ theme, label, icon, onPress, style }: ActionButtonProps) {\n return React.createElement(\n Pressable,\n {\n style: [\n styles.fab,\n { backgroundColor: theme.colors.accent, borderRadius: theme.borderRadius.full },\n style,\n ],\n onPress,\n },\n icon || React.createElement(Text, { style: styles.fabText }, label || '+'),\n );\n}\n\n// ── Styles ──────────────────────────────────────────────────\n\nconst styles = StyleSheet.create({\n card: {\n padding: 12,\n borderRadius: 12,\n borderWidth: 1,\n marginBottom: 8,\n },\n badge: {\n paddingHorizontal: 8,\n paddingVertical: 3,\n },\n badgeText: {\n fontSize: 11,\n fontWeight: '600',\n },\n tabBar: {\n flexDirection: 'row',\n borderBottomWidth: 1,\n },\n tab: {\n flex: 1,\n padding: 12,\n alignItems: 'center',\n borderBottomWidth: 2,\n },\n listItem: {\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 12,\n paddingHorizontal: 16,\n borderBottomWidth: StyleSheet.hairlineWidth,\n },\n listItemContent: {\n flex: 1,\n },\n searchBar: {\n height: 40,\n paddingHorizontal: 12,\n borderWidth: 1,\n },\n emptyState: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n padding: 32,\n },\n retryButton: {\n marginTop: 12,\n paddingHorizontal: 16,\n paddingVertical: 8,\n },\n fab: {\n position: 'absolute',\n bottom: 24,\n right: 24,\n width: 56,\n height: 56,\n justifyContent: 'center',\n alignItems: 'center',\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.25,\n shadowRadius: 4,\n elevation: 5,\n },\n fabText: {\n color: '#fff',\n fontSize: 24,\n fontWeight: '600',\n },\n});\n","/**\n * Host integration points — the DI seams that keep this package free of\n * Expo imports. The host app (or @ateam-ai-mobile/expo) plugs in concrete providers\n * once at startup; everything here has a safe no-op/in-memory default so\n * a bare host works with zero configuration.\n */\n\nimport type { HapticsAPI, NativeCapabilities, PluginNative } from './sdk/types';\nimport type { RegisteredPlugin } from './sdk/types';\n\n// ── Haptics ────────────────────────────────────────────────────────────────\n\nlet _haptics: HapticsAPI | null = null;\n\n/** Register a haptics implementation (e.g. expo-haptics via @ateam-ai-mobile/expo). */\nexport function setHapticsProvider(haptics: HapticsAPI | null): void {\n _haptics = haptics;\n}\n\n/** No-op safe accessor — surfaces call this for tap feedback. */\nexport function getHaptics(): HapticsAPI | null {\n return _haptics;\n}\n\n// ── PluginNative (device capabilities handed to plugins) ──────────────────\n// The full implementation lives in the HOST (it owns the native modules —\n// e.g. ateam-mobile's device-bridge). Without a provider, plugins get\n// clearly-erroring stubs instead of crashes.\n\nfunction unavailable(api: string): any {\n return new Proxy({}, {\n get: (_t, method) => () =>\n Promise.reject(new Error(`[adas] native.${api}.${String(method)} unavailable — host did not call setPluginNativeProvider()`)),\n });\n}\n\nconst noopNative: PluginNative = {\n camera: unavailable('camera'),\n location: unavailable('location'),\n storage: unavailable('storage'),\n biometrics: unavailable('biometrics'),\n biometricsV2: unavailable('biometricsV2'),\n notifications: unavailable('notifications'),\n haptics: { impact: () => {}, notification: () => {}, selection: () => {}, error: () => {} },\n connectivity: { isOnline: () => true, onChange: () => () => {} },\n fileSystem: unavailable('fileSystem'),\n cookies: unavailable('cookies'),\n sharing: unavailable('sharing'),\n scanner: unavailable('scanner'),\n nfc: unavailable('nfc'),\n bluetooth: unavailable('bluetooth'),\n vision: unavailable('vision'),\n maps: unavailable('maps'),\n};\n\nlet _pluginNative: PluginNative = noopNative;\n\n/** Install the device-capabilities implementation plugins receive as\n * `props.device` (the L1 native modules keep the `native` name; the plugin-\n * facing prop is `device`). The host owns the native modules. */\nexport function setPluginNativeProvider(native: PluginNative): void {\n _pluginNative = native;\n}\n\nexport function getPluginNative(): PluginNative {\n return _pluginNative;\n}\n\n/** Blocked-capability proxy: any call warns and is ignored (no throw) —\n * matches the reference app's behaviour for undeclared capabilities. */\nfunction blocked(api: string, reason?: string): any {\n return new Proxy({}, {\n get: (_t, method) => {\n if (typeof method !== 'string') return undefined;\n return () => {\n console.warn(`[adas] native.${api}.${method} blocked — ${reason ?? `capability '${api}' not declared in the plugin manifest`}`);\n };\n },\n });\n}\n\n/**\n * Gate a PluginNative by the capabilities a plugin's manifest declares.\n * Undeclared capabilities become warn-and-ignore proxies, so a plugin can\n * only touch device APIs it asked for (per-plugin security model, preserved\n * from the reference app). Connectivity is always allowed.\n *\n * Flag mapping mirrors the manifest contract: `storage` is gated by\n * `offline` (offline data ⇒ local storage).\n */\nexport function gatePluginNative(\n native: PluginNative,\n declared?: NativeCapabilities,\n pluginId?: string,\n): PluginNative {\n const caps = declared || {};\n // Per-plugin filesystem + storage isolation, FAIL CLOSED. A declared plugin\n // gets a sandbox/namespace scoped to its OWN id (plugin-files/<pluginId>/,\n // @plugin:<id>: KV, plugin-storage-<id>.db) via the provider's\n // fileSystemFor/storageFor. There is deliberately NO shared fallback: if the\n // id is missing or the provider can't scope, the plugin is BLOCKED, not handed\n // a bucket some other plugin also holds. A silent shared fallback is exactly\n // the P1 that reopened when the UI renderer omitted the id — the isolation must\n // fail closed, never degrade to \"shared\" without anyone noticing.\n const scopedFileSystem =\n native.fileSystemFor && pluginId ? native.fileSystemFor(pluginId) : null;\n const scopedStorage =\n native.storageFor && pluginId ? native.storageFor(pluginId) : null;\n const gated = {\n camera: caps.camera ? native.camera : blocked('camera'),\n location: caps.location ? native.location : blocked('location'),\n storage: caps.offline\n ? (scopedStorage ?? blocked('storage', \"no trusted pluginId to scope storage — refusing shared access (fail closed)\"))\n : blocked('storage'),\n biometrics: caps.biometrics ? native.biometrics : blocked('biometrics'),\n biometricsV2: caps.biometricsV2 ? native.biometricsV2 : blocked('biometricsV2'),\n notifications: caps.notifications ? native.notifications : blocked('notifications'),\n haptics: caps.haptics ? native.haptics : blocked('haptics'),\n connectivity: native.connectivity,\n fileSystem: caps.fileSystem\n ? (scopedFileSystem ?? blocked('fileSystem', \"no trusted pluginId to scope the filesystem — refusing shared access (fail closed)\"))\n : blocked('fileSystem'),\n cookies: caps.cookies ? native.cookies : blocked('cookies'),\n sharing: caps.sharing ? native.sharing : blocked('sharing'),\n scanner: caps.scanner ? native.scanner : blocked('scanner'),\n nfc: caps.nfc ? native.nfc : blocked('nfc'),\n // Gated like the rest even though nothing implements it yet. An undeclared\n // plugin gets the usual blocked proxy; a DECLARED one reaches an API whose\n // every method refuses by name. Both are better than the `undefined` this\n // used to be, which crashed with \"cannot read properties of undefined\".\n bluetooth: caps.bluetooth ? native.bluetooth : blocked('bluetooth'),\n vision: caps.vision ? native.vision : blocked('vision'),\n maps: caps.maps ? native.maps : blocked('maps'),\n // What this plugin DECLARED, carried on the object it already receives.\n //\n // It is how a COMPONENT can be capability-gated: <CameraPreview> is handed\n // `native` and reads this, so showing the camera obeys the same flag as\n // calling it. Without this the preview would be a second door to the camera\n // with only one lock. Non-enumerable so it cannot be mistaken for an API.\n } as any;\n\n Object.defineProperty(gated, '__declaredCapabilities', {\n value: Object.freeze({ ...caps }),\n enumerable: false,\n writable: false,\n });\n return gated;\n}\n\n// ── Camera preview (the plugin-facing way to SHOW the camera) ─────────────\n//\n// A plugin composes <CameraPreview native={native} /> from the SDK; the HOST\n// supplies what actually renders, because only the host has the native module.\n//\n// This exists so we do NOT register raw `expo-camera` for bundles. That would\n// be a third door to the device with no capability gate and no honest failure\n// mode — a plugin could mount a camera without declaring it. Here the pixels\n// stay on the host's side: a plugin can SHOW the camera and still cannot touch\n// a frame.\n\n/** Props the host's preview implementation receives. */\nexport interface CameraPreviewImplProps {\n facing?: 'front' | 'back';\n style?: any;\n renderUnavailable?: (reason: string) => any;\n}\n\nlet _cameraPreview: ((props: CameraPreviewImplProps) => any) | null = null;\n\n/** Install the host's camera preview (e.g. an expo-camera CameraView). */\nexport function setCameraPreviewProvider(\n Component: ((props: CameraPreviewImplProps) => any) | null,\n): void {\n _cameraPreview = Component;\n}\n\n/** Null when the host installed none — the SDK then renders a stated reason,\n * never a black rectangle that looks like a dark room. */\nexport function getCameraPreviewProvider(): ((props: CameraPreviewImplProps) => any) | null {\n return _cameraPreview;\n}\n\n// ── Native (host-bundled) plugin registry ─────────────────────────────────\n// Plugins compiled into the host binary (dev plugins, first-party panels).\n// usePlugin checks this registry before hitting the remote bundle pipeline.\n// Values may be lazy loaders so heavy plugins don't cost app-start time.\n\ntype PluginResolver = RegisteredPlugin | (() => Promise<RegisteredPlugin | null>);\n\nconst _nativeRegistry = new Map<string, PluginResolver>();\n\nexport function registerNativePlugin(id: string, plugin: PluginResolver): void {\n _nativeRegistry.set(id, plugin);\n}\n\nexport function unregisterNativePlugin(id: string): void {\n _nativeRegistry.delete(id);\n}\n\nexport const nativePluginRegistry = {\n has(id: string): boolean {\n return _nativeRegistry.has(id);\n },\n async get(id: string): Promise<RegisteredPlugin | null> {\n const entry = _nativeRegistry.get(id);\n if (!entry) return null;\n if (typeof entry === 'function') {\n try {\n return await entry();\n } catch (err) {\n console.warn(`[adas-plugins] lazy native plugin '${id}' failed to load:`, err);\n return null;\n }\n }\n return entry;\n },\n};\n\n// ── Extra bundle modules ───────────────────────────────────────────────────\n// Remote bundles are built with externals resolved by the require shim in\n// bundleManager. react / react-native / @adas/plugin-sdk are always provided;\n// anything else (react-native-webview, expo-linking, …) must be registered\n// by the host, which actually has those modules installed.\n\nconst _bundleModules = new Map<string, any>();\n\nexport function registerBundleModules(modules: Record<string, any>): void {\n for (const [name, mod] of Object.entries(modules)) {\n _bundleModules.set(name, mod);\n }\n}\n\nexport function resolveBundleModule(name: string): any | undefined {\n return _bundleModules.get(name);\n}\n","/**\n * CameraPreview — the plugin-facing way to SHOW the user what the camera sees.\n *\n * WHY THIS EXISTS RATHER THAN HANDING PLUGINS `expo-camera`.\n *\n * The design has exactly two doors to the device: `props.native.*` (mechanical\n * verbs, capability-gated, throws) and `props.deviceState.*` (semantic state,\n * gated, says unknown). Registering a raw native module for bundles would open\n * a THIRD door with no grammar, no gate and no honest failure mode — a plugin\n * could mount a camera without declaring it, and nothing in the manifest would\n * say so. That is the shape of hole this platform keeps closing, not opening.\n *\n * So the preview is a COMPONENT the plugin composes, and the pixels stay on the\n * host's side of the boundary. A plugin can show the camera; it still cannot\n * touch a frame. Reading frames remains `deviceState.visual` (semantic, with\n * freshness) and analysing them remains `native.vision` (which takes an id and\n * resolves it inside the trusted layer).\n *\n * IT IS GATED BY THE SAME FLAG AS `native.camera`. One door, one lock: a plugin\n * that has not declared `capabilities: { camera: true }` gets a refusal panel\n * saying exactly that, not a black rectangle it might mistake for a dark room.\n *\n * IT NEVER RENDERS NOTHING. Every failure — capability not declared, host has\n * not installed a provider, OS permission refused — draws a panel stating which\n * one. A preview that silently renders empty is indistinguishable from a camera\n * pointed at a wall, and a guide built on it would describe a scene nobody saw.\n */\nimport React from 'react';\nimport { View, Text } from './primitives';\nimport type { PluginNative } from './types';\nimport { getCameraPreviewProvider } from '../host';\n\nexport interface CameraPreviewProps {\n /**\n * The plugin's own `props.native`. REQUIRED, and it is the gate: the runtime\n * stamps the declared capabilities onto this object, so passing it is how the\n * component knows whether this plugin may show a camera at all.\n */\n native: PluginNative;\n facing?: 'front' | 'back';\n style?: any;\n /** Rendered instead of the built-in panel when the preview is unavailable. */\n renderUnavailable?: (reason: string) => React.ReactElement | null;\n}\n\n/** Declared capabilities, stamped onto the gated object by gatePluginNative. */\nfunction declaredCapabilities(native: any): Record<string, boolean> | null {\n return (native && native.__declaredCapabilities) || null;\n}\n\nexport function CameraPreview({ native, facing = 'back', style, renderUnavailable }: CameraPreviewProps) {\n const caps = declaredCapabilities(native);\n\n // The gate. Deliberately checked BEFORE asking the host for a provider, so a\n // plugin cannot learn whether a camera exists without declaring that it wants\n // one — an undeclared plugin gets the same answer on every device.\n if (caps && !caps.camera) {\n return unavailable(\n \"this plugin did not declare `capabilities: { camera: true }`, so it may not show the camera\",\n renderUnavailable,\n style,\n );\n }\n\n const Provider = getCameraPreviewProvider();\n if (!Provider) {\n // The host has not installed a preview implementation. Say so rather than\n // rendering black: \"no provider\" and \"a dark room\" must never look alike.\n return unavailable(\n 'this app does not provide a camera preview (the host has not called setCameraPreviewProvider)',\n renderUnavailable,\n style,\n );\n }\n\n return <Provider facing={facing} style={style} renderUnavailable={renderUnavailable} />;\n}\n\nfunction unavailable(\n reason: string,\n render: CameraPreviewProps['renderUnavailable'],\n style: any,\n): React.ReactElement | null {\n if (render) return render(reason);\n return (\n <View style={[{ flex: 1, backgroundColor: '#000', alignItems: 'center', justifyContent: 'center', padding: 20 }, style]}>\n <Text style={{ color: '#39FF66', fontSize: 12, textAlign: 'center' }}>\n {`NO CAMERA PREVIEW\\n${reason}`}\n </Text>\n </View>\n );\n}\n\nexport default CameraPreview;\n","/**\n * Theme delivered to plugins via `usePluginTheme()`.\n *\n * Theming flows from the HOST — plugin-side fallback hex values are a no-op\n * by design. The default is the Ada warm-paper palette (matching the\n * reference app); hosts with their own brand call `setPluginThemeColors()`\n * once at startup to override.\n */\nimport { useMemo, useSyncExternalStore } from 'react';\nimport { useColorScheme } from 'react-native';\nimport { ada, spacing, fontSize, borderRadius } from '@ateam-ai-mobile/core';\nimport type { ThemeTokens } from './types';\n\ntype ThemeColors = ThemeTokens['colors'];\n\n// Ada palette mapped onto the plugin theme contract — mirrors the reference\n// app's useTheme.ts. Everything renders against warm paper; dark mode is on\n// the roadmap.\nconst adaColors: ThemeColors = {\n bg: ada.paper,\n surface: ada.paperSoft,\n surfaceAlt: ada.paperDeep,\n input: ada.paper,\n border: ada.border,\n text: ada.ink,\n textSecondary: ada.inkSoft,\n textMuted: ada.inkMuted,\n accent: ada.orange,\n accentSoft: ada.orangeSoft,\n success: '#5A8A5C',\n successSoft: 'rgba(90,138,92,0.14)',\n warning: '#D49A4E',\n warningSoft: 'rgba(212,154,78,0.16)',\n error: '#C15545',\n errorSoft: 'rgba(193,85,69,0.14)',\n purple: ada.orangeDeep,\n purpleSoft: ada.orangeSoft,\n};\n\nlet _colors: ThemeColors = adaColors;\n// null = host hasn't pinned it → track the device color scheme live\n// (parity with the reference app, whose isDark followed useColorScheme()).\nlet _isDark: boolean | null = null;\nconst _subscribers = new Set<() => void>();\n\n/** Override the plugin theme (host brand). Call once at startup — mounted\n * plugins re-render with the new tokens. */\nexport function setPluginThemeColors(colors: Partial<ThemeColors>, opts?: { isDark?: boolean }): void {\n _colors = { ...adaColors, ...colors };\n if (opts?.isDark !== undefined) _isDark = opts.isDark;\n _subscribers.forEach(fn => fn());\n}\n\nfunction subscribe(fn: () => void): () => void {\n _subscribers.add(fn);\n return () => { _subscribers.delete(fn); };\n}\n\nexport function usePluginTheme(): ThemeTokens {\n const colors = useSyncExternalStore(subscribe, () => _colors);\n const hostIsDark = useSyncExternalStore(subscribe, () => _isDark);\n const scheme = useColorScheme();\n const isDark = hostIsDark ?? scheme === 'dark';\n\n // Memoize so plugins don't re-render on every host render.\n return useMemo(() => ({\n colors,\n spacing: {\n xs: spacing.xs,\n sm: spacing.sm,\n md: spacing.md,\n lg: spacing.lg,\n xl: spacing.xl,\n xxl: spacing.xxl,\n },\n fontSize: {\n xs: fontSize.xs,\n sm: fontSize.sm,\n md: fontSize.md,\n lg: fontSize.lg,\n xl: fontSize.xl,\n },\n borderRadius: {\n sm: borderRadius.sm,\n md: borderRadius.md,\n lg: borderRadius.lg,\n full: borderRadius.full,\n },\n isDark,\n }), [colors, isDark]);\n}\n","/**\n * Simple plugin API — call any connector tool.\n *\n * Supports THREE usage patterns:\n *\n * // Pattern 1: Direct function call\n * const api = useApi(bridge);\n * const tasks = await api('task-board-mcp', 'tasks.list', {});\n *\n * // Pattern 2: .call(connector, tool, args) — connector first\n * const api = useApi(bridge);\n * const tasks = await api.call('memory-mcp', 'rules.list', {});\n *\n * // Pattern 3: .call(tool, args, connector) — connector last (rn-src plugins use this!)\n * const api = useApi(bridge);\n * const tasks = await api.call('memory.list', { type: 'rule' }, 'memory-mcp');\n *\n * All three work. The .call method auto-detects argument order.\n */\nimport { useMemo } from 'react';\nimport type { PluginBridge } from './types';\n\ninterface PluginApi {\n (connectorId: string, tool: string, args?: Record<string, any>): Promise<any>;\n call(connectorOrTool: string, toolOrArgs?: string | Record<string, any>, argsOrConnector?: Record<string, any> | string): Promise<any>;\n}\n\n/**\n * Create a simple API function to call connector tools.\n */\nexport function useApi(bridge: PluginBridge): PluginApi {\n return useMemo(() => {\n // Core implementation: (connectorId, tool, args) => Promise\n const apiFn = async (connectorId: string, tool: string, args: Record<string, any> = {}): Promise<any> => {\n if (!bridge) {\n throw new Error('useApi: bridge is required. Pass it from plugin props.');\n }\n return bridge.mcpCall(tool, args, connectorId);\n };\n\n // Add .call method that supports ALL THREE patterns:\n // api.call(connector, tool, args) — 2nd arg is string → connector first\n // api.call(tool, args, connector) — 3rd arg is string → connector last (rn-src pattern)\n // api.call(tool, args) — 2 args only → use bridge default connector\n const callMethod = async (\n first: string,\n second?: string | Record<string, any>,\n third?: Record<string, any> | string,\n ): Promise<any> => {\n if (!bridge) {\n throw new Error('useApi: bridge is required. Pass it from plugin props.');\n }\n\n if (typeof second === 'string') {\n // api.call(connector, tool, args) — 2nd arg is tool name string\n return bridge.mcpCall(second, (third as Record<string, any>) || {}, first);\n }\n\n if (typeof third === 'string') {\n // api.call(tool, args, connector) — 3rd arg is connector ID string\n return bridge.mcpCall(first, (second as Record<string, any>) || {}, third);\n }\n\n // api.call(tool, args) — no connector, use bridge default\n return bridge.mcpCall(first, (second as Record<string, any>) || {});\n };\n\n // Override .call on the function to be our custom method\n // (shadows Function.prototype.call intentionally)\n Object.defineProperty(apiFn, 'call', {\n value: callMethod,\n writable: false,\n configurable: false,\n });\n\n return apiFn as PluginApi;\n }, [bridge]);\n}\n","/**\n * SurfaceDrawer — generic bottom-sheet container for plugins.\n *\n * Plugins render their content; SurfaceDrawer provides the Ada chrome:\n * drag handle, header (orb + title + subtitle + optional privacy pill),\n * close button, motion, backdrop dismiss.\n *\n * Usage:\n * <SurfaceDrawer\n * visible={open}\n * onClose={() => setOpen(false)}\n * title=\"What I remember about you\"\n * subtitle=\"Only you can see this\"\n * privacy\n * >\n * <MyPluginContent />\n * </SurfaceDrawer>\n */\nimport { useEffect, useRef, type ReactNode } from 'react';\nimport {\n View,\n Text,\n Pressable,\n StyleSheet,\n Animated,\n Dimensions,\n Platform,\n} from 'react-native';\nimport Svg, { Path } from 'react-native-svg';\nimport { ada } from '@ateam-ai-mobile/core';\nimport AdaOrb from './AdaOrb';\n\nconst SCREEN_H = Dimensions.get('window').height;\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface SurfaceDrawerProps {\n visible: boolean;\n onClose: () => void;\n title: string;\n subtitle?: string;\n /** Show the lock + \"Only you can see this\" privacy pill under the title */\n privacy?: boolean;\n /** Show the small Ada orb in the header (default: true) */\n showOrb?: boolean;\n /** Sheet height ratio of screen (default: 0.85) */\n heightRatio?: number;\n children: ReactNode;\n}\n\nexport default function SurfaceDrawer({\n visible,\n onClose,\n title,\n subtitle,\n privacy,\n showOrb = true,\n heightRatio = 0.85,\n children,\n}: SurfaceDrawerProps) {\n const sheetH = Math.round(SCREEN_H * heightRatio);\n const fadeAnim = useRef(new Animated.Value(0)).current;\n const slideAnim = useRef(new Animated.Value(sheetH)).current;\n\n useEffect(() => {\n if (visible) {\n Animated.parallel([\n Animated.timing(fadeAnim, { toValue: 1, duration: 220, useNativeDriver: true }),\n Animated.spring(slideAnim, { toValue: 0, useNativeDriver: true, tension: 80, friction: 12 }),\n ]).start();\n } else {\n fadeAnim.setValue(0);\n slideAnim.setValue(sheetH);\n }\n }, [visible]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const close = () => {\n Animated.parallel([\n Animated.timing(fadeAnim, { toValue: 0, duration: 160, useNativeDriver: true }),\n Animated.timing(slideAnim, { toValue: sheetH, duration: 200, useNativeDriver: true }),\n ]).start(() => onClose());\n };\n\n if (!visible) return null;\n\n return (\n <Animated.View style={[styles.overlay, { opacity: fadeAnim }]} pointerEvents=\"auto\">\n <Pressable style={StyleSheet.absoluteFill} onPress={close} />\n <Animated.View\n style={[\n styles.sheet,\n { height: sheetH, transform: [{ translateY: slideAnim }] },\n ]}\n >\n {/* Drag handle */}\n <View style={styles.handle} />\n\n {/* Header */}\n <View style={styles.header}>\n {showOrb ? (\n <View style={styles.headerOrb}>\n <AdaOrb size={36} state=\"idle\" />\n </View>\n ) : null}\n <View style={{ flex: 1 }}>\n <Text style={styles.title}>{title}</Text>\n {subtitle ? <Text style={styles.subtitle}>{subtitle}</Text> : null}\n {privacy ? (\n <View style={styles.privacyPill}>\n <Svg width={11} height={11} viewBox=\"0 0 24 24\" fill=\"none\" stroke={ada.inkSoft} strokeWidth={2.5} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <Path d=\"M19 11H5a2 2 0 00-2 2v7a2 2 0 002 2h14a2 2 0 002-2v-7a2 2 0 00-2-2z\" />\n <Path d=\"M7 11V7a5 5 0 0110 0v4\" />\n </Svg>\n <Text style={styles.privacyText}>Only you can see this</Text>\n </View>\n ) : null}\n </View>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Close\"\n style={styles.closeBtn}\n onPress={close}\n hitSlop={12}\n >\n <Svg width={18} height={18} viewBox=\"0 0 24 24\" fill=\"none\" stroke={ada.inkSoft} strokeWidth={2.2} strokeLinecap=\"round\">\n <Path d=\"M18 6L6 18M6 6l12 12\" />\n </Svg>\n </Pressable>\n </View>\n\n {/* Body — caller renders content */}\n <View style={styles.body}>{children}</View>\n </Animated.View>\n </Animated.View>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n position: 'absolute',\n top: 0, left: 0, right: 0, bottom: 0,\n backgroundColor: 'rgba(26, 20, 16, 0.35)',\n justifyContent: 'flex-end',\n zIndex: 999,\n elevation: 999,\n },\n sheet: {\n backgroundColor: ada.paper,\n borderTopLeftRadius: 28,\n borderTopRightRadius: 28,\n overflow: 'hidden',\n },\n handle: {\n width: 40,\n height: 4,\n borderRadius: 2,\n backgroundColor: ada.inkMuted,\n opacity: 0.3,\n alignSelf: 'center',\n marginTop: 10,\n marginBottom: 6,\n },\n header: {\n flexDirection: 'row',\n alignItems: 'center',\n paddingHorizontal: 22,\n paddingVertical: 16,\n gap: 12,\n borderBottomWidth: 1,\n borderBottomColor: ada.border,\n },\n headerOrb: {\n width: 36,\n height: 36,\n alignItems: 'center',\n justifyContent: 'center',\n },\n title: {\n fontSize: 17,\n fontWeight: '600',\n color: ada.ink,\n letterSpacing: -0.2,\n fontFamily: fontFam,\n },\n subtitle: {\n fontSize: 13,\n fontWeight: '400',\n color: ada.inkSoft,\n marginTop: 2,\n letterSpacing: -0.1,\n fontFamily: fontFam,\n },\n privacyPill: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 5,\n marginTop: 4,\n },\n privacyText: {\n fontSize: 11,\n fontWeight: '500',\n color: ada.inkSoft,\n letterSpacing: 0.2,\n fontFamily: fontFam,\n },\n closeBtn: {\n width: 32,\n height: 32,\n borderRadius: 16,\n backgroundColor: ada.paperSoft,\n justifyContent: 'center',\n alignItems: 'center',\n },\n body: {\n flex: 1,\n },\n});\n","import { useEffect } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport Animated, {\n useSharedValue,\n useAnimatedProps,\n withRepeat,\n withTiming,\n withSequence,\n withDelay,\n Easing,\n cancelAnimation,\n} from 'react-native-reanimated';\nimport Svg, { Circle, Defs, RadialGradient, Stop, Text as SvgText } from 'react-native-svg';\n\nconst AnimatedCircle = Animated.createAnimatedComponent(Circle);\n\nexport type AdaOrbState = 'idle' | 'listening' | 'thinking' | 'speaking';\n\ninterface AdaOrbProps {\n size?: number;\n state?: AdaOrbState;\n /** Show the \"iA\" wordmark inside the orb. Suppressed below 60px because\n * glyphs become unreadable at avatar/chevron sizes — render as a plain\n * orb there. Default true. */\n inscription?: boolean;\n}\n\nexport default function AdaOrb({ size = 120, state = 'idle', inscription = true }: AdaOrbProps) {\n const showInscription = inscription && size >= 60;\n const center = size / 2;\n const coreR = size * 0.32;\n const innerHaloR = size * 0.42;\n const outerHaloR = size * 0.5;\n\n // Base breath layers\n const coreScale = useSharedValue(1);\n const innerScale = useSharedValue(1);\n const outerScale = useSharedValue(1);\n const outerOpacity = useSharedValue(0.55);\n\n // Listening: continuous ripple cycle (one shared value, phase-shifted reads)\n const rippleCycle = useSharedValue(0);\n\n // Thinking: 3 orbiting sparks at different speeds + directions\n const orbit1 = useSharedValue(0); // fast inner\n const orbit2 = useSharedValue(0); // medium mid\n const orbit3 = useSharedValue(0); // slow outer (counter)\n\n // Speaking: secondary fast double-beat overlay\n const beat = useSharedValue(1);\n\n useEffect(() => {\n cancelAnimation(coreScale);\n cancelAnimation(innerScale);\n cancelAnimation(outerScale);\n cancelAnimation(outerOpacity);\n cancelAnimation(rippleCycle);\n cancelAnimation(orbit1);\n cancelAnimation(orbit2);\n cancelAnimation(orbit3);\n cancelAnimation(beat);\n\n // Reset state-specific drivers\n rippleCycle.value = 0;\n orbit1.value = 0;\n orbit2.value = 0;\n orbit3.value = 0;\n beat.value = 1;\n\n let breathMs = 3600;\n let breathAmount = 0.025;\n\n if (state === 'listening') {\n breathMs = 2000;\n breathAmount = 0.05;\n // Continuous ripple loop — one cycle = one ripple lifetime\n rippleCycle.value = withRepeat(\n withTiming(1, { duration: 2000, easing: Easing.out(Easing.quad) }),\n -1,\n false,\n );\n } else if (state === 'thinking') {\n breathMs = 2400;\n breathAmount = 0.04;\n // Three sparks orbiting at different speeds + directions — feels like processing\n orbit1.value = withRepeat(\n withTiming(1, { duration: 1100, easing: Easing.linear }),\n -1,\n false,\n );\n orbit2.value = withRepeat(\n withTiming(1, { duration: 1900, easing: Easing.linear }),\n -1,\n false,\n );\n orbit3.value = withRepeat(\n withTiming(-1, { duration: 2700, easing: Easing.linear }),\n -1,\n false,\n );\n } else if (state === 'speaking') {\n breathMs = 700;\n breathAmount = 0.13;\n // Double-beat overlay — quick punch + secondary kick\n beat.value = withRepeat(\n withSequence(\n withTiming(1.08, { duration: 90, easing: Easing.out(Easing.quad) }),\n withTiming(1.0, { duration: 130, easing: Easing.in(Easing.quad) }),\n withTiming(1.05, { duration: 80, easing: Easing.out(Easing.quad) }),\n withTiming(1.0, { duration: 200, easing: Easing.in(Easing.quad) }),\n withTiming(1.0, { duration: 280 }),\n ),\n -1,\n false,\n );\n }\n\n // Base breath — different easing per state\n const breathEasing =\n state === 'speaking' ? Easing.out(Easing.cubic) : Easing.inOut(Easing.sin);\n\n coreScale.value = withRepeat(\n withSequence(\n withTiming(1 + breathAmount, { duration: breathMs, easing: breathEasing }),\n withTiming(1, { duration: breathMs, easing: breathEasing }),\n ),\n -1,\n false,\n );\n innerScale.value = withRepeat(\n withSequence(\n withTiming(1 + breathAmount * 1.4, { duration: breathMs * 1.15, easing: breathEasing }),\n withTiming(1, { duration: breathMs * 1.15, easing: breathEasing }),\n ),\n -1,\n false,\n );\n outerScale.value = withRepeat(\n withSequence(\n withTiming(1 + breathAmount * 1.8, { duration: breathMs * 1.3, easing: breathEasing }),\n withTiming(1, { duration: breathMs * 1.3, easing: breathEasing }),\n ),\n -1,\n false,\n );\n outerOpacity.value = withRepeat(\n withSequence(\n withTiming(state === 'idle' ? 0.55 : 0.8, { duration: breathMs * 1.3, easing: breathEasing }),\n withTiming(0.35, { duration: breathMs * 1.3, easing: breathEasing }),\n ),\n -1,\n false,\n );\n }, [state]);\n\n // Animated props for base layers — multiplied by `beat` so speaking double-pulse stacks\n const coreProps = useAnimatedProps(() => ({\n r: coreR * coreScale.value * beat.value,\n }));\n const innerProps = useAnimatedProps(() => ({\n r: innerHaloR * innerScale.value * beat.value,\n }));\n const outerProps = useAnimatedProps(() => ({\n r: outerHaloR * outerScale.value,\n opacity: outerOpacity.value,\n }));\n\n // Listening ripples — three phase-shifted reads of rippleCycle\n const ripple1Props = useAnimatedProps(() => {\n const t = rippleCycle.value;\n return {\n r: outerHaloR * (1 + t * 0.55),\n opacity: state === 'listening' ? 0.55 * (1 - t) : 0,\n };\n });\n const ripple2Props = useAnimatedProps(() => {\n const t = (rippleCycle.value + 0.34) % 1;\n return {\n r: outerHaloR * (1 + t * 0.55),\n opacity: state === 'listening' ? 0.45 * (1 - t) : 0,\n };\n });\n const ripple3Props = useAnimatedProps(() => {\n const t = (rippleCycle.value + 0.67) % 1;\n return {\n r: outerHaloR * (1 + t * 0.55),\n opacity: state === 'listening' ? 0.35 * (1 - t) : 0,\n };\n });\n\n // Thinking sparks — three at different radii and angular velocities\n const spark1Props = useAnimatedProps(() => {\n const angle = orbit1.value * Math.PI * 2 - Math.PI / 2;\n const r = coreR * 0.55;\n return {\n cx: center + Math.cos(angle) * r,\n cy: center + Math.sin(angle) * r,\n opacity: state === 'thinking' ? 1 : 0,\n };\n });\n const spark2Props = useAnimatedProps(() => {\n const angle = orbit2.value * Math.PI * 2 + Math.PI * 0.6;\n const r = coreR * 0.85;\n return {\n cx: center + Math.cos(angle) * r,\n cy: center + Math.sin(angle) * r,\n opacity: state === 'thinking' ? 0.9 : 0,\n };\n });\n const spark3Props = useAnimatedProps(() => {\n const angle = orbit3.value * Math.PI * 2 + Math.PI * 1.3;\n const r = coreR * 1.05;\n return {\n cx: center + Math.cos(angle) * r,\n cy: center + Math.sin(angle) * r,\n opacity: state === 'thinking' ? 0.7 : 0,\n };\n });\n\n return (\n <View style={[styles.wrap, { width: size, height: size }]}>\n <Svg width={size} height={size}>\n <Defs>\n <RadialGradient id=\"adaCore\" cx=\"36%\" cy=\"30%\" r=\"70%\">\n <Stop offset=\"0%\" stopColor=\"#FFE0B0\" stopOpacity=\"1\" />\n <Stop offset=\"28%\" stopColor=\"#FFA85A\" stopOpacity=\"1\" />\n <Stop offset=\"65%\" stopColor=\"#FF7A28\" stopOpacity=\"1\" />\n <Stop offset=\"100%\" stopColor=\"#B8410A\" stopOpacity=\"1\" />\n </RadialGradient>\n <RadialGradient id=\"adaInner\" cx=\"50%\" cy=\"50%\" r=\"50%\">\n <Stop offset=\"0%\" stopColor=\"#FF8A3C\" stopOpacity=\"0.55\" />\n <Stop offset=\"100%\" stopColor=\"#FF7028\" stopOpacity=\"0\" />\n </RadialGradient>\n <RadialGradient id=\"adaOuter\" cx=\"50%\" cy=\"50%\" r=\"50%\">\n <Stop offset=\"0%\" stopColor=\"#FF7A28\" stopOpacity=\"0.4\" />\n <Stop offset=\"100%\" stopColor=\"#FF6018\" stopOpacity=\"0\" />\n </RadialGradient>\n <RadialGradient id=\"adaSpark\" cx=\"50%\" cy=\"50%\" r=\"50%\">\n <Stop offset=\"0%\" stopColor=\"#FFFAEB\" stopOpacity=\"1\" />\n <Stop offset=\"60%\" stopColor=\"#FFD095\" stopOpacity=\"0.9\" />\n <Stop offset=\"100%\" stopColor=\"#FFA85A\" stopOpacity=\"0\" />\n </RadialGradient>\n </Defs>\n\n {/* Listening ripples — drawn behind orb body */}\n <AnimatedCircle\n cx={center}\n cy={center}\n stroke=\"#FF7A28\"\n strokeWidth={1.5}\n fill=\"none\"\n animatedProps={ripple1Props}\n />\n <AnimatedCircle\n cx={center}\n cy={center}\n stroke=\"#FF7A28\"\n strokeWidth={1.5}\n fill=\"none\"\n animatedProps={ripple2Props}\n />\n <AnimatedCircle\n cx={center}\n cy={center}\n stroke=\"#FF7A28\"\n strokeWidth={1.5}\n fill=\"none\"\n animatedProps={ripple3Props}\n />\n\n {/* Base orb body */}\n <AnimatedCircle cx={center} cy={center} fill=\"url(#adaOuter)\" animatedProps={outerProps} />\n <AnimatedCircle cx={center} cy={center} fill=\"url(#adaInner)\" animatedProps={innerProps} />\n <AnimatedCircle cx={center} cy={center} fill=\"url(#adaCore)\" animatedProps={coreProps} />\n\n {/* Thinking sparks — three orbiting particles drawn on top */}\n <AnimatedCircle\n r={Math.max(3, size * 0.05)}\n fill=\"url(#adaSpark)\"\n animatedProps={spark1Props}\n />\n <AnimatedCircle\n r={Math.max(2.5, size * 0.04)}\n fill=\"url(#adaSpark)\"\n animatedProps={spark2Props}\n />\n <AnimatedCircle\n r={Math.max(2, size * 0.032)}\n fill=\"url(#adaSpark)\"\n animatedProps={spark3Props}\n />\n\n {/* \"iA\" wordmark — matches the app icon. Suppressed at small sizes\n where the glyphs would be unreadable (see showInscription). */}\n {showInscription && (\n <SvgText\n x={center}\n y={center + size * 0.11}\n fontSize={size * 0.34}\n fontWeight=\"600\"\n fill=\"#FFF5E0\"\n textAnchor=\"middle\"\n letterSpacing={-size * 0.005}\n >\n iA\n </SvgText>\n )}\n </Svg>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrap: {\n alignItems: 'center',\n justifyContent: 'center',\n },\n});\n","/**\n * SurfaceCard — a tappable tile shape for plugins that surface as cards\n * (empty-state suggestions, dashboards, daily-brief items).\n *\n * Plugins declare icon + title + subtitle + onPress; the host provides\n * the warm Ada chrome (paper-soft bg, soft border, arrow chevron, haptic).\n *\n * Optional `children` render below the title block for richer previews\n * (e.g. small ring widget, last-meal photo, current weather).\n *\n * Usage:\n * <SurfaceCard\n * icon=\"🥗\"\n * title=\"Today's plate\"\n * subtitle=\"2,100 kcal · 140g protein\"\n * onPress={() => sendPrompt('Tell me about my nutrition today')}\n * />\n */\nimport { type ReactNode } from 'react';\nimport {\n View,\n Text,\n Pressable,\n StyleSheet,\n Platform,\n} from 'react-native';\nimport { getHaptics } from '../host';\nimport { ada, borderRadius } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface SurfaceCardProps {\n /** Emoji or short string icon shown on the left */\n icon?: string;\n /** Card headline (e.g. \"Today's plate\") */\n title: string;\n /** Optional secondary line below title */\n subtitle?: string;\n /** Tap handler. Fires haptic before invoking. */\n onPress?: () => void;\n /** Long-press handler. Fires a heavier haptic. Used by user widgets for\n * the Delete / (later) Hide / Rename context menu. */\n onLongPress?: () => void;\n /** Whether to show the ›-style trailing arrow (default: true if onPress) */\n showArrow?: boolean;\n /** Optional preview content rendered below the title block */\n children?: ReactNode;\n}\n\nexport default function SurfaceCard({\n icon,\n title,\n subtitle,\n onPress,\n onLongPress,\n showArrow,\n children,\n}: SurfaceCardProps) {\n const arrow = showArrow ?? !!onPress;\n const handlePress = () => {\n if (!onPress) return;\n getHaptics()?.impact('light');\n onPress();\n };\n const handleLongPress = () => {\n if (!onLongPress) return;\n getHaptics()?.impact('medium');\n onLongPress();\n };\n\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={[icon, title, subtitle].filter(Boolean).join(', ')}\n accessibilityHint={onLongPress ? 'Long-press for more options' : undefined}\n style={styles.card}\n onPress={onPress ? handlePress : undefined}\n onLongPress={onLongPress ? handleLongPress : undefined}\n disabled={!onPress && !onLongPress}\n >\n <View style={styles.row}>\n {icon ? <Text style={styles.icon}>{icon}</Text> : null}\n <View style={{ flex: 1 }}>\n <Text style={styles.title}>{title}</Text>\n {subtitle ? <Text style={styles.subtitle}>{subtitle}</Text> : null}\n </View>\n {arrow ? <Text style={styles.arrow}>{'\\u2192'}</Text> : null}\n </View>\n {children ? <View style={styles.body}>{children}</View> : null}\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n card: {\n backgroundColor: ada.paperSoft,\n borderWidth: 1,\n borderColor: ada.border,\n borderRadius: borderRadius.xl,\n paddingHorizontal: 16,\n paddingVertical: 14,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 14,\n },\n icon: {\n fontSize: 22,\n },\n title: {\n fontSize: 15,\n fontWeight: '600',\n color: ada.ink,\n letterSpacing: -0.2,\n fontFamily: fontFam,\n },\n subtitle: {\n fontSize: 13,\n fontWeight: '400',\n color: ada.inkMuted,\n marginTop: 2,\n letterSpacing: -0.1,\n fontFamily: fontFam,\n },\n arrow: {\n fontSize: 18,\n color: ada.inkMuted,\n fontWeight: '400',\n },\n body: {\n marginTop: 10,\n paddingTop: 10,\n borderTopWidth: 1,\n borderTopColor: ada.border,\n },\n});\n","/**\n * SurfaceFullscreen — edge-to-edge takeover container for plugins\n * (voice mode, focus modes, photo capture, etc.).\n *\n * Plugins render their content; SurfaceFullscreen provides:\n * - Paper background, fade-in motion\n * - Top status line (\"ada\" wordmark + status text)\n * - Optional hero element above body (e.g. AdaOrb)\n * - Bottom close button with label\n * - Spring entry on the hero (scale 0.6 → 1)\n *\n * Usage:\n * <SurfaceFullscreen\n * visible={open}\n * onClose={hangUp}\n * status=\"Ada is speaking\"\n * hero={<AdaOrb size={180} state=\"speaking\" />}\n * closeIcon=\"hangup\"\n * closeLabel=\"End\"\n * >\n * <Transcript ... />\n * </SurfaceFullscreen>\n */\nimport { useEffect, useRef, type ReactNode } from 'react';\nimport {\n View,\n Text,\n Pressable,\n StyleSheet,\n Animated,\n Platform,\n} from 'react-native';\nimport Svg, { Path } from 'react-native-svg';\nimport { ada } from '@ateam-ai-mobile/core';\n\nconst fontFam = Platform.OS === 'ios' ? 'SF Pro Rounded' : undefined;\n\nexport interface SurfaceFullscreenProps {\n visible: boolean;\n onClose: () => void;\n /** Status text shown under the wordmark */\n status?: string;\n /** Optional hero element above body (typically an AdaOrb) */\n hero?: ReactNode;\n /** Body content */\n children?: ReactNode;\n /** Whether to show the small \"ada\" wordmark (default: true) */\n showWordmark?: boolean;\n /** Built-in close icon flavor or a custom node. Default: 'x' */\n closeIcon?: 'x' | 'hangup' | ReactNode;\n /** Label under the close button (default: \"Close\") */\n closeLabel?: string;\n}\n\nexport default function SurfaceFullscreen({\n visible,\n onClose,\n status,\n hero,\n children,\n showWordmark = true,\n closeIcon = 'x',\n closeLabel = 'Close',\n}: SurfaceFullscreenProps) {\n const fadeAnim = useRef(new Animated.Value(0)).current;\n const heroScale = useRef(new Animated.Value(0.6)).current;\n\n useEffect(() => {\n if (visible) {\n Animated.parallel([\n Animated.timing(fadeAnim, { toValue: 1, duration: 280, useNativeDriver: true }),\n Animated.spring(heroScale, { toValue: 1, useNativeDriver: true, tension: 60, friction: 11 }),\n ]).start();\n } else {\n fadeAnim.setValue(0);\n heroScale.setValue(0.6);\n }\n }, [visible]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const close = () => {\n Animated.parallel([\n Animated.timing(fadeAnim, { toValue: 0, duration: 180, useNativeDriver: true }),\n Animated.timing(heroScale, { toValue: 0.6, duration: 180, useNativeDriver: true }),\n ]).start(() => onClose());\n };\n\n if (!visible) return null;\n\n const renderCloseIcon = () => {\n if (closeIcon === 'hangup') {\n return (\n <Svg width={22} height={22} viewBox=\"0 0 24 24\" fill={ada.paper}>\n <Path d=\"M3.68 16.07l3.92-3.11c.28-.23.68-.28 1.01-.14l2.77 1.15c.36.15.61.5.61.89v2.82c4.34-.76 7.93-4.35 8.69-8.69h-2.82c-.39 0-.74-.25-.89-.61L16.12 5.6c-.13-.33-.09-.73.14-1.01l3.11-3.92c.29-.37.81-.41 1.15-.08l3.24 3.24c.2.2.31.47.31.76C24 14.44 14.44 24 4.59 24c-.29 0-.56-.11-.76-.31L.59 20.45c-.33-.34-.29-.86.09-1.15z\" />\n </Svg>\n );\n }\n if (closeIcon === 'x') {\n return (\n <Svg width={20} height={20} viewBox=\"0 0 24 24\" fill=\"none\" stroke={ada.paper} strokeWidth={2.5} strokeLinecap=\"round\">\n <Path d=\"M18 6L6 18M6 6l12 12\" />\n </Svg>\n );\n }\n return closeIcon;\n };\n\n return (\n <Animated.View style={[styles.overlay, { opacity: fadeAnim }]} pointerEvents=\"auto\">\n {/* Top status */}\n <View style={styles.topBar}>\n {showWordmark ? <Text style={styles.wordmark}>ada</Text> : null}\n {status ? <Text style={styles.status}>{status}</Text> : null}\n </View>\n\n {/* Optional hero (e.g. AdaOrb) — springs in */}\n {hero ? (\n <View style={styles.heroWrap}>\n <Animated.View style={{ transform: [{ scale: heroScale }] }}>\n {hero}\n </Animated.View>\n </View>\n ) : null}\n\n {/* Body — caller content */}\n <View style={styles.body}>{children}</View>\n\n {/* Bottom close */}\n <View style={styles.bottomBar}>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={closeLabel}\n style={styles.closeBtn}\n onPress={close}\n hitSlop={12}\n >\n {renderCloseIcon()}\n </Pressable>\n {closeLabel ? <Text style={styles.closeLabel}>{closeLabel}</Text> : null}\n </View>\n </Animated.View>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n position: 'absolute',\n top: 0, left: 0, right: 0, bottom: 0,\n backgroundColor: ada.paper,\n zIndex: 1000,\n elevation: 1000,\n },\n topBar: {\n paddingTop: Platform.OS === 'ios' ? 64 : 36,\n paddingHorizontal: 24,\n alignItems: 'center',\n gap: 6,\n },\n wordmark: {\n fontSize: 14,\n fontFamily: fontFam,\n fontWeight: '500',\n color: ada.inkMuted,\n letterSpacing: 4,\n },\n status: {\n fontSize: 17,\n fontFamily: fontFam,\n fontWeight: '500',\n color: ada.ink,\n letterSpacing: -0.2,\n },\n heroWrap: {\n paddingTop: 24,\n paddingBottom: 12,\n alignItems: 'center',\n justifyContent: 'center',\n },\n body: {\n flex: 1,\n },\n bottomBar: {\n paddingBottom: Platform.OS === 'ios' ? 48 : 32,\n paddingTop: 12,\n alignItems: 'center',\n gap: 8,\n },\n closeBtn: {\n width: 64,\n height: 64,\n borderRadius: 32,\n backgroundColor: ada.ink,\n justifyContent: 'center',\n alignItems: 'center',\n shadowColor: ada.ink,\n shadowOffset: { width: 0, height: 8 },\n shadowOpacity: 0.18,\n shadowRadius: 14,\n elevation: 8,\n },\n closeLabel: {\n fontSize: 13,\n fontFamily: fontFam,\n fontWeight: '500',\n color: ada.inkMuted,\n letterSpacing: 0.3,\n },\n});\n","/**\n * Surface registry + active-state store.\n *\n * - `manifests`: map of registered surface plugins\n * - `activeDrawer` / `activeFullscreen`: which surface (if any) is currently mounted\n * (only one of each at a time)\n *\n * Plugins are registered by calling `register(...)` from bootstrap or by an\n * \"engine\" event. The dispatcher subscribes to active state and mounts.\n */\nimport { create } from 'zustand';\nimport type {\n SurfaceManifest,\n SurfaceType,\n SurfaceVisibility,\n SurfacePlacement,\n InlineSurfaceManifest,\n MountSurfaceManifest,\n} from './types';\n\ninterface SurfaceState {\n manifests: Record<string, SurfaceManifest>;\n activeDrawer: string | null;\n activeFullscreen: string | null;\n /** Props passed by the engine when summoning a surface via sys.focusUiPlugin.\n * Keyed by surface id; cleared on hide. Plugins read these on first mount. */\n activeProps: Record<string, any>;\n /** Increments on every `show()` call. Used as a React `key` so the Surface\n * Component remounts even if the same surface is shown again — guarantees\n * the plugin's data-fetching effects re-run, so the user always sees fresh\n * data when they open a drawer. */\n mountKey: number;\n\n register: (manifest: SurfaceManifest) => void;\n unregister: (id: string) => void;\n\n /** Open a surface in its declared container. Props (optional) are forwarded\n * to the mounted plugin on first render. */\n show: (id: string, props?: any) => void;\n /** Close the surface with the given id (or whatever is active for the matching type) */\n hide: (id?: string) => void;\n\n /** All registered manifests, optionally filtered.\n * `placement: 'unset'` selects only plugins WITHOUT a placement (default list). */\n list: (filter?: {\n type?: SurfaceType;\n visibility?: SurfaceVisibility[];\n placement?: SurfacePlacement | 'unset';\n }) => SurfaceManifest[];\n}\n\nexport const useSurfaceStore = create<SurfaceState>((set, get) => ({\n manifests: {},\n activeDrawer: null,\n activeFullscreen: null,\n activeProps: {},\n mountKey: 0,\n\n register: (manifest) =>\n set(s => ({ manifests: { ...s.manifests, [manifest.id]: manifest } })),\n\n unregister: (id) =>\n set(s => {\n const next = { ...s.manifests };\n delete next[id];\n const nextProps = { ...s.activeProps };\n delete nextProps[id];\n return { manifests: next, activeProps: nextProps };\n }),\n\n show: (id, props) => {\n const m = get().manifests[id];\n if (!m) {\n console.warn('[SurfaceStore] show: unknown surface id', id);\n return;\n }\n set(s => {\n const nextProps = props !== undefined\n ? { ...s.activeProps, [id]: props }\n : s.activeProps;\n // Bump mountKey on every show so the dispatcher remounts the Component,\n // forcing the plugin's data fetch to re-run with fresh results.\n const mountKey = s.mountKey + 1;\n if (m.type === 'drawer') return { activeDrawer: id, activeProps: nextProps, mountKey };\n if (m.type === 'fullscreen') return { activeFullscreen: id, activeProps: nextProps, mountKey };\n return { mountKey };\n });\n },\n\n hide: (id) => {\n const s = get();\n if (!id) {\n // Hide whichever is active and clear their props\n const cleanup = { ...s.activeProps };\n if (s.activeDrawer) delete cleanup[s.activeDrawer];\n if (s.activeFullscreen) delete cleanup[s.activeFullscreen];\n set({ activeDrawer: null, activeFullscreen: null, activeProps: cleanup });\n return;\n }\n const cleanup = { ...s.activeProps };\n delete cleanup[id];\n const patch: Partial<SurfaceState> = { activeProps: cleanup };\n if (s.activeDrawer === id) patch.activeDrawer = null;\n if (s.activeFullscreen === id) patch.activeFullscreen = null;\n set(patch);\n },\n\n list: (filter) => {\n const all = Object.values(get().manifests);\n return all.filter(m => {\n if (filter?.type && m.type !== filter.type) return false;\n if (filter?.visibility && !filter.visibility.includes(m.visibility)) return false;\n if (filter?.placement) {\n if (filter.placement === 'unset') {\n if (m.placement) return false;\n } else if (m.placement !== filter.placement) {\n return false;\n }\n }\n return true;\n });\n },\n}));\n\n// Convenience guards\nexport function isMountSurface(m: SurfaceManifest): m is MountSurfaceManifest {\n return m.type === 'drawer' || m.type === 'fullscreen';\n}\nexport function isInlineSurface(m: SurfaceManifest): m is InlineSurfaceManifest {\n return m.type === 'card' || m.type === 'header' || m.type === 'ambient' || m.type === 'nudge';\n}\n","/**\n * SurfaceDispatcher — mounted once at the app root.\n *\n * Watches the surface store and:\n * - Mounts the active drawer surface (max one at a time)\n * - Mounts the active fullscreen surface (max one at a time)\n *\n * The mounted Component receives `dismiss` to close itself; the dispatcher\n * clears active-state after dismiss.\n *\n * Inline surfaces (card / header / ambient / nudge) are NOT rendered by the\n * dispatcher — they're queried via `useSurfaceStore().list({ type: 'card' })`\n * and rendered inline by the host screen that owns that placement.\n */\nimport { useEffect } from 'react';\nimport { useSurfaceStore } from './store';\nimport { pluginCommandEmitter } from '@ateam-ai-mobile/core';\n\nexport default function SurfaceDispatcher() {\n const manifests = useSurfaceStore(s => s.manifests);\n const activeDrawer = useSurfaceStore(s => s.activeDrawer);\n const activeFullscreen = useSurfaceStore(s => s.activeFullscreen);\n const activeProps = useSurfaceStore(s => s.activeProps);\n const mountKey = useSurfaceStore(s => s.mountKey);\n const hide = useSurfaceStore(s => s.hide);\n\n // bridge.close() inside a plugin emits a global `plugin-close` event.\n // The legacy plugins overlay listens for this; we mirror that here so\n // surface-mounted plugins (auth-webview, etc.) actually dismiss themselves.\n useEffect(() => {\n const unsub = pluginCommandEmitter.on('plugin-close', ({ pluginId }: { pluginId?: string } = {}) => {\n if (!pluginId) return;\n const s = useSurfaceStore.getState();\n if (s.activeDrawer === pluginId || s.activeFullscreen === pluginId) {\n s.hide(pluginId);\n }\n });\n return unsub;\n }, []);\n\n const drawer = activeDrawer ? manifests[activeDrawer] : null;\n const fullscreen = activeFullscreen ? manifests[activeFullscreen] : null;\n const drawerProps = activeDrawer ? activeProps[activeDrawer] : undefined;\n const fullscreenProps = activeFullscreen ? activeProps[activeFullscreen] : undefined;\n\n // mountKey changes on every show() so React remounts the Component → the\n // plugin's data-fetching useEffects re-run → user sees fresh data each open.\n return (\n <>\n {drawer && drawer.type === 'drawer' && drawer.Component ? (\n <drawer.Component\n key={`drawer-${drawer.id}-${mountKey}`}\n dismiss={() => hide(drawer.id)}\n props={drawerProps}\n />\n ) : null}\n {fullscreen && fullscreen.type === 'fullscreen' && fullscreen.Component ? (\n <fullscreen.Component\n key={`fullscreen-${fullscreen.id}-${mountKey}`}\n dismiss={() => hide(fullscreen.id)}\n props={fullscreenProps}\n />\n ) : null}\n </>\n );\n}\n","/**\n * Pure-JS SHA-256 — used to verify integrity of downloaded plugin bundles.\n * Avoids pulling expo-crypto / a native module into the dependency graph for\n * what amounts to a one-shot post-download check.\n *\n * Hot path: hash a ~100KB-1MB bundle once after download. Performance is\n * acceptable on every supported device (sub-50ms).\n *\n * Algorithm reference: FIPS 180-4. Implementation derived from the public-\n * domain reference code; see https://en.wikipedia.org/wiki/SHA-2#Pseudocode.\n */\n\nconst K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\n\nconst rotr = (n: number, x: number) => (x >>> n) | (x << (32 - n));\n\n/** SHA-256 of a UTF-8 string. Returns the lowercase hex digest. */\nexport function sha256Hex(message: string): string {\n // 1. Encode to UTF-8 bytes\n const utf8 = unescape(encodeURIComponent(message));\n const bytes = new Uint8Array(utf8.length);\n for (let i = 0; i < utf8.length; i++) bytes[i] = utf8.charCodeAt(i);\n\n // 2. Pre-processing: append 0x80, pad with zeros, then append 64-bit big-endian length\n const bitLen = bytes.length * 8;\n const padLen = (56 - (bytes.length + 1) % 64 + 64) % 64;\n const buf = new Uint8Array(bytes.length + 1 + padLen + 8);\n buf.set(bytes);\n buf[bytes.length] = 0x80;\n // 64-bit big-endian length (high 32 bits zeroed — bundles are well under 2^32 bits)\n const len = buf.length;\n buf[len - 4] = (bitLen >>> 24) & 0xff;\n buf[len - 3] = (bitLen >>> 16) & 0xff;\n buf[len - 2] = (bitLen >>> 8) & 0xff;\n buf[len - 1] = bitLen & 0xff;\n\n const h = new Uint32Array([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,\n 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n ]);\n const w = new Uint32Array(64);\n\n // 3. Process each 512-bit chunk\n for (let i = 0; i < buf.length; i += 64) {\n for (let t = 0; t < 16; t++) {\n const j = i + t * 4;\n w[t] = (buf[j] << 24) | (buf[j + 1] << 16) | (buf[j + 2] << 8) | buf[j + 3];\n }\n for (let t = 16; t < 64; t++) {\n const s0 = rotr(7, w[t - 15]) ^ rotr(18, w[t - 15]) ^ (w[t - 15] >>> 3);\n const s1 = rotr(17, w[t - 2]) ^ rotr(19, w[t - 2]) ^ (w[t - 2] >>> 10);\n w[t] = (w[t - 16] + s0 + w[t - 7] + s1) | 0;\n }\n\n let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], hh = h[7];\n for (let t = 0; t < 64; t++) {\n const S1 = rotr(6, e) ^ rotr(11, e) ^ rotr(25, e);\n const ch = (e & f) ^ (~e & g);\n const temp1 = (hh + S1 + ch + K[t] + w[t]) | 0;\n const S0 = rotr(2, a) ^ rotr(13, a) ^ rotr(22, a);\n const maj = (a & b) ^ (a & c) ^ (b & c);\n const temp2 = (S0 + maj) | 0;\n hh = g; g = f; f = e; e = (d + temp1) | 0; d = c; c = b; b = a; a = (temp1 + temp2) | 0;\n }\n\n h[0] = (h[0] + a) | 0; h[1] = (h[1] + b) | 0; h[2] = (h[2] + c) | 0; h[3] = (h[3] + d) | 0;\n h[4] = (h[4] + e) | 0; h[5] = (h[5] + f) | 0; h[6] = (h[6] + g) | 0; h[7] = (h[7] + hh) | 0;\n }\n\n // 4. Produce hex\n let out = '';\n for (let i = 0; i < 8; i++) {\n out += h[i].toString(16).padStart(8, '0');\n }\n return out;\n}\n","/**\n * R8 remote-bundle integrity — the fail-closed check run INLINE, immediately\n * before a remote bundle is evaluated with `new Function`.\n *\n * See docs/decisions/REMOTE_BUNDLE_INTEGRITY.md for the threat model and the\n * (declined) publisher-signature decision. This is INTEGRITY, not a sandbox:\n * it proves the bytes about to run are exactly the ones the trusted manifest\n * hash names; it does not isolate what they can do.\n */\nimport { sha256Hex } from '../utils/sha256';\n\n/**\n * Refuse to evaluate a bundle whose bytes do not match the SHA-256 that\n * gate-kept them. Fail-closed on a MISSING hash too — an unverifiable bundle is\n * treated exactly like a mismatched one. `verifiedHash` is the manifest hash for\n * a cache hit or the freshly-verified download hash; re-hashing `content` here\n * closes the disk-cache-tamper gap the download-time check leaves open.\n */\nexport function assertBundleIntegrity(content: string, verifiedHash: string | null, label: string): void {\n const digest = sha256Hex(content);\n if (!verifiedHash) {\n throw new Error(`[bundle-integrity] refusing to evaluate ${label}: no verified SHA-256 (fail closed).`);\n }\n if (digest !== verifiedHash.toLowerCase()) {\n throw new Error(\n `[bundle-integrity] integrity FAIL at eval for ${label}: content sha256 ${digest.slice(0, 12)}… ≠ verified ${verifiedHash.slice(0, 12)}…. Refusing to evaluate.`,\n );\n }\n}\n","/**\n * Bundle disk-cache adapter. The bundle manager persists downloaded plugin\n * bundles through this interface so the package stays free of Expo/RN\n * storage imports. @ateam-ai-mobile/expo ships a file-system implementation; the\n * default is in-memory (bundles re-download per app session — correct,\n * just slower on cold start).\n */\nimport type { PluginGrants } from '../pluginRuntime';\n\nexport interface BundleCacheEntry {\n localPath: string;\n version: string;\n timestamp: number;\n bundleUrl: string;\n /** SHA-256 (hex, lowercase) of the cached bundle bytes — integrity proof */\n bundleHash?: string;\n /**\n * Tenant whose session downloaded these bytes.\n *\n * A bundle URL is NOT tenant-independent: `/api/ui-plugins/<id>/bundle.js`\n * resolves per-tenant on the server, so the SAME url returns different code\n * for different tenants. On the normal load path the hash gate catches this\n * for free — the expected hash comes from the current tenant's manifest and\n * will not match another tenant's cached bytes. The disk-cache recovery path\n * has no manifest to check against, so it must discriminate by tenant.\n *\n * Absent on entries written before this field existed: unknown ownership, so\n * untrusted. Never read a missing tenant as \"mine\".\n */\n tenant?: string;\n /**\n * The trusted declaration these bytes' device tools were last registered\n * under: the pluginId and grants resolved from the server manifest that named\n * this bundle (resolvePluginGrants). Recorded so the disk-cache recovery path —\n * which runs exactly when there is NO manifest — re-registers with the same\n * authority instead of the bundle's own claim.\n *\n * Absent → no trusted declaration is known for these bytes, so recovery skips\n * the entry (fail closed) and the catalog path registers it once the owning\n * connector answers again.\n */\n trusted?: TrustedToolDeclaration;\n}\n\n/** Who a bundle's device tools belong to and what they are granted — always\n * from the manifest, never from the bundle. */\nexport interface TrustedToolDeclaration extends PluginGrants {\n pluginId: string;\n}\n\n/**\n * Which cached entries belong to `tenant` and may therefore be re-evaluated.\n *\n * Lives here, beside the entry type, so \"may I run this cached code\" has ONE\n * owner rather than being re-answered by each caller. `loadIndex()` returns\n * every entry regardless of owner — it has to, since the manager looks entries\n * up by url and rewrites them — so any caller that EVALUATES cached code must\n * come through this function first.\n *\n * Fail-closed on both unknowns. An empty tenant owns nothing. An entry with no\n * recorded tenant has unknown ownership and is never assumed to be the current\n * one: every device already in the field has unstamped entries, so reading\n * \"missing\" as \"mine\" would keep the hole open exactly where it is hardest to\n * see.\n *\n * Compares the tenant field directly — it never builds a composite key, so\n * there is no separator a tenant name could forge across.\n */\nexport function selectOwnedCacheEntries<T extends { tenant?: string }>(\n entries: T[],\n tenant: string | null | undefined,\n): T[] {\n if (!tenant) return [];\n return (entries || []).filter((e) => !!e && e.tenant === tenant);\n}\n\nexport interface BundleStorage {\n loadIndex(): Promise<Record<string, BundleCacheEntry>>;\n saveIndex(index: Record<string, BundleCacheEntry>): Promise<void>;\n /** Read a cached bundle. Returns null when missing/unreadable. */\n readBundle(localPath: string): Promise<string | null>;\n /** Persist a bundle; returns the localPath to record in the index.\n * `key` is a filesystem-safe name derived from the bundle URL+version. */\n writeBundle(key: string, content: string): Promise<string>;\n deleteBundle(localPath: string): Promise<void>;\n /** Wipe everything (index + bundles). */\n clearAll(): Promise<void>;\n}\n\n/** Default storage: keeps bundles for the lifetime of the JS context only. */\nexport class MemoryBundleStorage implements BundleStorage {\n private index: Record<string, BundleCacheEntry> = {};\n private files = new Map<string, string>();\n\n async loadIndex() {\n return this.index;\n }\n async saveIndex(index: Record<string, BundleCacheEntry>) {\n this.index = index;\n }\n async readBundle(localPath: string) {\n return this.files.get(localPath) ?? null;\n }\n async writeBundle(key: string, content: string) {\n const localPath = `memory://${key}`;\n this.files.set(localPath, content);\n return localPath;\n }\n async deleteBundle(localPath: string) {\n this.files.delete(localPath);\n }\n async clearAll() {\n this.index = {};\n this.files.clear();\n }\n}\n\nlet _storage: BundleStorage = new MemoryBundleStorage();\n\n/** Install a persistent storage implementation (call before first plugin load). */\nexport function setBundleStorage(storage: BundleStorage): void {\n _storage = storage;\n}\n\nexport function getBundleStorage(): BundleStorage {\n return _storage;\n}\n","/**\n * Native bridge for React Native plugins.\n * Direct function calls — no postMessage, no serialization.\n *\n * Identity comes from @ateam-ai-mobile/core config (host-owned auth); tool calls go\n * through the same MCP layer as everything else.\n */\nimport { useCallback, useMemo, useRef, useEffect } from 'react';\nimport type { MutableRefObject } from 'react';\nimport {\n connectorCall,\n mcpFetch as mcpFetchApi,\n unwrapMcpResult,\n postCommandResult,\n getTenant,\n getUser,\n pluginCommandEmitter,\n useChatStore,\n} from '@ateam-ai-mobile/core';\nimport type { PluginBridge, PluginContext } from '../sdk/types';\n\ntype CommandListener = (type: string, payload: any) => void;\n\nfunction buildContext(pluginId: string, connectorId?: string): PluginContext {\n const user = getUser();\n return {\n tenant: getTenant(),\n pluginId,\n connectorId,\n user: user ? { id: user.actorId || '', name: user.name || '', roles: user.roles || [] } : undefined,\n };\n}\n\nexport function useNativeBridge(pluginId: string, connectorId?: string, commandBufferRef?: MutableRefObject<any[]>): PluginBridge {\n const initCallbackRef = useRef<((ctx: PluginContext) => void) | null>(null);\n const commandListenersRef = useRef<Set<CommandListener>>(new Set());\n const initializedRef = useRef(false);\n\n const fireInit = useCallback(() => {\n if (initializedRef.current || !initCallbackRef.current) return;\n initCallbackRef.current(buildContext(pluginId, connectorId));\n initializedRef.current = true;\n }, [pluginId, connectorId]);\n\n const onInit = useCallback((cb: (ctx: PluginContext) => void) => {\n initCallbackRef.current = cb;\n setTimeout(fireInit, 0);\n }, [fireInit]);\n\n const mcpCall = useCallback(async (toolOrConnector: string, argsOrTool: any, cIdOrArgs?: any): Promise<any> => {\n // Support BOTH argument orders:\n // (tool, args, connectorId?) — bridge standard\n // (connectorId, tool, args?) — plugin convenience (matches useApi pattern)\n // Detect: if 2nd arg is a string, caller used (connector, tool, args) order\n let tool: string;\n let args: any;\n let cId: string | undefined;\n\n if (typeof argsOrTool === 'string') {\n // (connectorId, tool, args) order\n cId = toolOrConnector;\n tool = argsOrTool;\n args = cIdOrArgs || {};\n } else {\n // Standard (tool, args, connectorId?) order\n tool = toolOrConnector;\n args = argsOrTool;\n cId = typeof cIdOrArgs === 'string' ? cIdOrArgs : undefined;\n }\n\n const targetConnector = cId || connectorId;\n if (!targetConnector) {\n console.warn(`[NativeBridge:${pluginId}] mcpCall failed — no connectorId. tool=${tool}`);\n throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);\n }\n\n try {\n const data = await connectorCall(targetConnector, tool, args);\n\n if (!data.ok && data.error) {\n throw new Error(data.error);\n }\n return unwrapMcpResult(data.result);\n } catch (err) {\n console.warn(`[NativeBridge:${pluginId}] mcpCall failed → connector=${targetConnector} tool=${tool}:`, (err as any)?.message || err);\n throw err;\n }\n }, [pluginId, connectorId]);\n\n const mcpFetch = useCallback(async (body: any): Promise<any> => {\n return mcpFetchApi(body);\n }, []);\n\n const sendCommand = useCallback((type: string, payload: any) => {\n // Handle command results — mirror web PluginHost pattern\n if (type === 'plugin.command.result' && payload?.correlationId) {\n postCommandResult(payload.correlationId, payload.result, payload.error);\n return;\n }\n }, [pluginId]);\n\n const onCommand = useCallback((cb: CommandListener): (() => void) => {\n commandListenersRef.current.add(cb);\n // Flush buffered commands immediately when a listener registers —\n // the buffer may have commands that arrived before the plugin mounted.\n if (commandBufferRef) {\n const buf = commandBufferRef.current;\n const remaining: any[] = [];\n for (const cmd of buf) {\n if (cmd.pluginId === pluginId && cmd.command !== '__focus') {\n try { cb(cmd.command, { ...cmd.args, correlationId: cmd.correlationId }); } catch {}\n } else {\n remaining.push(cmd);\n }\n }\n commandBufferRef.current = remaining;\n }\n // Also drain the emitter's own recent-commands buffer (covers the\n // surface-dispatcher path which has no commandBufferRef).\n for (const cmd of pluginCommandEmitter.drainPluginCommands(pluginId)) {\n try { cb(cmd.command, { ...cmd.args, correlationId: cmd.correlationId }); } catch {}\n }\n return () => {\n commandListenersRef.current.delete(cb);\n };\n }, [pluginId, commandBufferRef]);\n\n // Dispatch live plugin commands to registered listeners\n useEffect(() => {\n const unsub = pluginCommandEmitter.on('plugin-command', (cmd: any) => {\n if (cmd.pluginId !== pluginId) return;\n if (cmd.command === '__focus') return; // Focus-only, no dispatch\n commandListenersRef.current.forEach(fn => {\n try { fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId }); } catch {}\n });\n });\n return unsub;\n }, [pluginId]);\n\n // Flush buffered commands on mount (commands that arrived before plugin\n // was ready). Two sources, both safe to drain:\n // 1. The parent-passed `commandBufferRef` (legacy overlay path).\n // 2. The emitter's own recent-commands buffer (surface-dispatcher path).\n useEffect(() => {\n const timer = setTimeout(() => {\n const dispatch = (cmd: any) => {\n commandListenersRef.current.forEach(fn => {\n try { fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId }); } catch {}\n });\n };\n\n if (commandBufferRef) {\n const remaining: any[] = [];\n for (const cmd of commandBufferRef.current) {\n if (cmd.pluginId === pluginId && cmd.command !== '__focus') dispatch(cmd);\n else remaining.push(cmd);\n }\n commandBufferRef.current = remaining;\n }\n\n // Always drain the emitter buffer too — the dispatcher path has no\n // parent buffer, and the legacy path may still have lost commands here\n // if they arrived before the parent's listener registered.\n for (const cmd of pluginCommandEmitter.drainPluginCommands(pluginId)) {\n dispatch(cmd);\n }\n }, 500); // Delay to let plugin register its onCommand listener\n return () => clearTimeout(timer);\n }, [pluginId, commandBufferRef]);\n\n useEffect(() => {\n return () => {\n commandListenersRef.current.clear();\n initializedRef.current = false;\n };\n }, []);\n\n const close = useCallback(() => {\n pluginCommandEmitter.emit('plugin-close', { pluginId });\n }, [pluginId]);\n\n /** Send a chat message into the user's thread (e.g. confirmed \"connect my\n * Gmail\"). Pair with bridge.close() to land the user on chat. */\n const sendMessage = useCallback((text: string) => {\n const t = (text || '').trim();\n if (!t) return;\n try {\n useChatStore.getState().sendMessage(t);\n } catch (err) {\n console.warn('[bridge.sendMessage] failed:', err instanceof Error ? err.message : String(err));\n }\n }, []);\n\n /** Prepare (pre-fill) the chat composer without sending. The host chat\n * screen listens for `prepare-chat-message` and stuffs `text` into its\n * input state. Pair with bridge.close(). */\n const prepareMessage = useCallback((text: string) => {\n const t = (text || '').trim();\n if (!t) return;\n pluginCommandEmitter.emit('prepare-chat-message', { text: t });\n }, []);\n\n // Memoize the bridge object to prevent child re-renders — a new object\n // every render → useApi recreates → fetch effects refire → flicker loop.\n return useMemo(\n () => ({ onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage }),\n [onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage],\n );\n}\n\n/**\n * Non-hook version for service plugins (no React lifecycle).\n */\nexport function createNativeBridge(pluginId: string, connectorId?: string): PluginBridge {\n const commandListeners = new Set<CommandListener>();\n\n return {\n onInit(cb) {\n setTimeout(() => {\n cb(buildContext(pluginId, connectorId));\n }, 0);\n },\n\n async mcpCall(tool: string, args: any, cId?: string) {\n const targetConnector = cId || connectorId;\n if (!targetConnector) {\n throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);\n }\n const data = await connectorCall(targetConnector, tool, args);\n if (!data.ok && data.error) throw new Error(data.error);\n return unwrapMcpResult(data.result);\n },\n\n async mcpFetch(body: any) {\n return mcpFetchApi(body);\n },\n\n sendCommand(_type: string, _payload: any) {\n },\n\n onCommand(cb: CommandListener) {\n commandListeners.add(cb);\n return () => { commandListeners.delete(cb); };\n },\n\n close() {\n pluginCommandEmitter.emit('plugin-close', { pluginId });\n },\n\n sendMessage(text: string) {\n const t = (text || '').trim();\n if (!t) return;\n try {\n useChatStore.getState().sendMessage(t);\n } catch (err) {\n console.warn('[bridge.sendMessage] failed:', err instanceof Error ? err.message : String(err));\n }\n },\n\n prepareMessage(text: string) {\n const t = (text || '').trim();\n if (!t) return;\n pluginCommandEmitter.emit('prepare-chat-message', { text: t });\n },\n } as PluginBridge;\n}\n","/**\n * Host DI for the SEMANTIC layer — the `props.deviceState` counterpart of\n * `setPluginNativeProvider`.\n *\n * Kept in its own file rather than added to host.ts, for the same reason the\n * two layers have separate namespaces: the moment they share a module, the\n * next person adds a domain to `PluginNative` or a capability to\n * `stateDomains` and the boundary starts to blur.\n *\n * THE GATE IS NOT THE MECHANICAL ONE. `gatePluginNative` replaces an\n * undeclared capability with a proxy whose methods warn and return `undefined`\n * — so `await native.location.getCurrent()` resolves to `undefined`, and\n * `pos?.latitude` is `undefined`, which flows into a model answer as a\n * confident nothing. A silent undefined is a fabrication vector.\n *\n * Here, an undeclared domain returns a real snapshot in which everything is\n * explicitly `unknown` / `null`, with `freshness.state = 'unknown'`. The\n * plugin gets a well-formed answer that says \"I know nothing\", which no\n * reasonable code path can mistake for data.\n */\nimport type { DeviceBridgeDomain, DeviceState, StateQuality } from './sdk/device-state';\n\n// The `unknown` freshness/confidence shape is the canonical `neverObserved()` +\n// `{ level: 'unknown' }` (see sdk/device-state.ts). It is inlined here rather\n// than imported because this module is imported directly by node --test and the\n// harness resolves only the explicit entry, not a nested extensionless value\n// import. The golden snapshot test pins this shape === neverObserved()'s.\nconst UNKNOWN_QUALITY: StateQuality = {\n freshness: { state: 'unknown', observedAt: null, ageMs: null },\n confidence: { level: 'unknown' },\n};\n\n/**\n * The empty snapshot for a domain the plugin did not declare.\n *\n * Deliberately built per domain rather than one shared `{}`: each snapshot has\n * required fields, and a caller reading `snapshot.position` must get `null`,\n * not a TypeError. Domains not listed fall through to `{ quality }`, which is\n * the one field every snapshot in the design shares.\n */\nfunction deniedSnapshot(domain: DeviceBridgeDomain): any {\n const base = { quality: UNKNOWN_QUALITY };\n switch (domain) {\n case 'spatial':\n return {\n ...base,\n position: null,\n movement: { speedMps: null, bearingDeg: null, distanceRecentM: null, state: 'unknown' },\n orientation: { headingDeg: null },\n recentPath: [],\n };\n case 'visual':\n return {\n ...base,\n camera: { available: false, active: false, facing: 'unknown' },\n latest: null,\n recentTimeline: { windowMs: 0, frames: [] },\n };\n case 'deviceContext':\n return {\n ...base,\n power: { batteryLevel: null, charging: null, lowPowerMode: null },\n thermal: { state: 'unknown' },\n resources: { memoryPressure: 'unknown', storagePressure: 'unknown' },\n };\n case 'connectivity':\n return {\n ...base,\n reachability: 'unknown',\n transport: 'unknown',\n qualityClass: 'unknown',\n stability: 'unknown',\n latencyMs: null,\n };\n case 'interaction':\n return {\n ...base,\n lifecycle: { appState: 'unknown', screenOn: null },\n audio: { captureActive: null, playbackActive: null, route: 'unknown', interruption: 'unknown' },\n };\n case 'activity':\n return {\n ...base,\n // `confidence` is REQUIRED on both blocks in the freeze, precisely\n // because an inferred activity must never be handed over without\n // saying how sure the inference is. An empty snapshot is the least\n // sure of all.\n human: { state: 'unknown', since: null, confidence: { level: 'unknown' } },\n devicePose: { placement: 'unknown', orientation: 'unknown', confidence: { level: 'unknown' } },\n recentTransitions: [],\n };\n case 'environment':\n return {\n ...base,\n lighting: { level: 'unknown', lux: null },\n acoustics: { level: 'unknown', approximateDb: null },\n // 'unknown' rather than 'uncertain': uncertain means we looked and\n // could not decide, and nothing looked at all here.\n enclosure: { state: 'unknown' },\n proximity: { distanceClass: 'unknown' },\n nearbySignals: { bleAvailable: false, beaconCount: null, uwbAvailable: false },\n };\n case 'capability': {\n // Every axis unknown — and note this is NOT the same as `denied`.\n // \"I could not check\" and \"the user said no\" lead to different things\n // being said to the user, which is why the freeze keeps them apart.\n const unknownStatus = { support: 'unknown', permission: 'unknown', availability: 'unknown' };\n return {\n ...base,\n camera: unknownStatus,\n microphone: unknownStatus,\n location: { ...unknownStatus, precision: 'unknown', backgroundPermission: 'unknown' },\n motion: unknownStatus,\n bluetooth: unknownStatus,\n uwb: unknownStatus,\n nfc: unknownStatus,\n notifications: unknownStatus,\n health: unknownStatus,\n backgroundExecution: unknownStatus,\n };\n }\n default:\n return base;\n }\n}\n\n/**\n * A domain the plugin may not use, or that this build does not implement.\n *\n * Reads answer with explicit unknowns. Anything that ACTS — start, stop,\n * subscribe — throws, because there is no honest \"unknown\" for an action: a\n * silent no-op start would leave the caller believing a session is open, and a\n * subscription that never fires reads as \"nothing has changed\".\n */\nfunction deniedDomain(domain: DeviceBridgeDomain, why: string): any {\n return {\n async getSnapshot() { return deniedSnapshot(domain); },\n async start() { throw denial(domain, why); },\n async stop() { throw denial(domain, why); },\n subscribe() { throw denial(domain, why); },\n };\n}\n\nfunction denial(domain: DeviceBridgeDomain, why: string): Error {\n const err: any = new Error(`deviceState.${domain}: ${why}`);\n // Frozen vocabulary. A manifest gate IS a policy, so a manifest denial is\n // policyRestricted — no new error vocabulary needed.\n err.code = 'RESTRICTED';\n err.domain = domain;\n return err;\n}\n\nconst ALL_DOMAINS: DeviceBridgeDomain[] = [\n 'spatial', 'visual', 'activity', 'deviceContext',\n 'connectivity', 'capability', 'environment', 'interaction',\n];\n\nlet _provider: Partial<DeviceState> = {};\n\n/** Host DI: the app supplies the engines it has. Called once at startup. */\nexport function setDeviceStateProvider(state: Partial<DeviceState>): void {\n _provider = state || {};\n}\n\n/**\n * The `deviceState` a plugin receives, gated by what it declared.\n *\n * Every domain is always present — a plugin can call any of the eight without\n * an existence check. What differs is whether it answers with data, or with\n * an explicit \"I know nothing\" and a reason.\n */\nexport function gateDeviceState(declared?: readonly DeviceBridgeDomain[]): DeviceState {\n const allowed = new Set(declared || []);\n const out: any = {};\n\n for (const domain of ALL_DOMAINS) {\n if (!allowed.has(domain)) {\n out[domain] = deniedDomain(\n domain,\n `not declared in this plugin's stateDomains. Add '${domain}' to use it.`,\n );\n continue;\n }\n const engine = (_provider as any)[domain];\n out[domain] = engine ?? deniedDomain(\n domain,\n 'no engine in this build — the native side does not exist yet. See docs/DEVICE_API_STATUS.md.',\n );\n }\n\n return out as DeviceState;\n}\n\n/**\n * The `deviceState` a device TOOL call receives: the same domains, but\n * `subscribe` refuses.\n *\n * A declared domain IS the engine, and the engines live as long as the app. A\n * UI plugin has a mount to unsubscribe in; a tool call has nothing — a listener\n * `run()` adds outlives it and runs on every later event, once per call that\n * added one. Refused loudly rather than quietly scoped to the call: a\n * subscription that stops hearing when `run` returns reads as \"nothing has\n * changed\". Everything else passes through untouched.\n */\nexport function withoutSubscribe(state: DeviceState): DeviceState {\n if (!state) return state;\n const out: any = {};\n for (const domain of ALL_DOMAINS) {\n const d = (state as any)[domain];\n out[domain] = d && Object.assign(Object.create(d), {\n subscribe() {\n throw denial(domain, 'a device tool call has no lifetime to own a subscription. Subscribe from the plugin UI, or read getSnapshot() within the call.');\n },\n });\n }\n return out as DeviceState;\n}\n\n/** Which domains this build can actually answer — for diagnostics. */\nexport function implementedStateDomains(): DeviceBridgeDomain[] {\n return ALL_DOMAINS.filter(d => !!(_provider as any)[d]);\n}\n","/**\n * Device tool registry.\n *\n * A solution's RN plugin may ship a `tools/` section alongside (or instead of)\n * its UI. Those tools are registered HERE, when the bundle is evaluated — not\n * when a screen mounts — so a caller can invoke one with nothing of the plugin\n * on screen.\n *\n * Lookup is by the tool's own domain name (e.g. \"guide.observe\"). Callers never\n * route on a name prefix: whether a tool runs locally is declared by the server\n * in the session payload, and resolved against this registry. The full LOCAL\n * reasoning path (discovery → call → result, and its independence from\n * relay/MCP) is documented in docs/architecture/LOCAL_REASONING_PATH.md (R13).\n */\nimport { createNativeBridge } from '../bridge/native';\nimport { getPluginNative, gatePluginNative } from '../host';\nimport { gateDeviceState, withoutSubscribe } from '../deviceStateHost';\nimport type { DeviceToolContext, DeviceToolDefinition, NativeCapabilities } from '../sdk/types';\nimport type { DeviceBridgeDomain } from '../sdk/device-state';\n\nexport interface DeviceToolSummary {\n name: string;\n pluginId: string;\n description?: string;\n input_schema?: Record<string, unknown>;\n}\n\nexport type DeviceToolOutcome =\n | { ok: true; result: any }\n | { ok: false; error: string; reason: 'not_found' | 'no_context' | 'timeout' | 'failed' };\n\ninterface Entry {\n pluginId: string;\n tool: DeviceToolDefinition;\n capabilities?: NativeCapabilities;\n /** L3 DeviceState domains this plugin declared — gates ctx.deviceState. */\n stateDomains?: DeviceBridgeDomain[];\n}\n\n/** toolName → entry. One name, one implementation. */\nconst registry = new Map<string, Entry>();\n\n/** Optional host override; the SDK supplies a working default (see below). */\nlet contextProvider:\n | ((pluginId: string, capabilities?: NativeCapabilities, stateDomains?: DeviceBridgeDomain[]) => DeviceToolContext)\n | null = null;\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Override how a device tool reaches the Device Bridge. Rarely needed — the\n * default below builds the same bridge/native pair a plugin gets when it\n * renders, gated by the capabilities the plugin declared.\n */\nexport function setDeviceToolContextProvider(\n fn: (pluginId: string, capabilities?: NativeCapabilities, stateDomains?: DeviceBridgeDomain[]) => DeviceToolContext,\n): void {\n contextProvider = fn;\n}\n\n/**\n * Default context: the plugin's own bridge + a capability-gated Device Bridge +\n * the L3 DeviceState gated to the domains the plugin declared. All three are the\n * SAME gated objects the plugin gets when it renders — a tool reaches nothing a\n * UI plugin couldn't. (One thing less: `callDeviceTool` takes `subscribe` away,\n * because a call has no lifetime to own one.)\n */\nfunction defaultContext(\n pluginId: string,\n capabilities?: NativeCapabilities,\n stateDomains?: DeviceBridgeDomain[],\n): DeviceToolContext {\n return {\n bridge: createNativeBridge(pluginId),\n native: gatePluginNative(getPluginNative(), capabilities, pluginId),\n deviceState: gateDeviceState(stateDomains),\n };\n}\n\n/**\n * Register a plugin's tools. Called from the bundle pipeline at load time.\n *\n * A name already taken by ANOTHER plugin is refused — a bundle loaded later\n * must not be able to take over \"guide.observe\" from the plugin that owns it.\n * Re-registering the same plugin (bundle reload) replaces its own entries.\n */\nexport function registerDeviceTools(\n pluginId: string,\n tools: DeviceToolDefinition[],\n capabilities?: NativeCapabilities,\n stateDomains?: DeviceBridgeDomain[],\n): string[] {\n const accepted: string[] = [];\n\n for (const tool of tools || []) {\n if (!tool || typeof tool.name !== 'string' || typeof tool.run !== 'function') {\n console.warn(`[deviceTools] ${pluginId}: skipping malformed tool entry`);\n continue;\n }\n const existing = registry.get(tool.name);\n if (existing && existing.pluginId !== pluginId) {\n console.warn(\n `[deviceTools] ${pluginId}: \"${tool.name}\" already registered by ${existing.pluginId} — refusing to override`,\n );\n continue;\n }\n registry.set(tool.name, { pluginId, tool, capabilities, stateDomains });\n accepted.push(tool.name);\n }\n\n if (accepted.length > 0) {\n console.log(`[deviceTools] ${pluginId} registered: ${accepted.join(', ')}`);\n }\n return accepted;\n}\n\n/** Drop every tool owned by a plugin (bundle eviction / plugin revoked). */\nexport function unregisterDeviceTools(pluginId: string): void {\n for (const [name, entry] of registry.entries()) {\n if (entry.pluginId === pluginId) registry.delete(name);\n }\n}\n\n/** Is `name` registered — and, given `pluginId`, registered BY that plugin?\n * (A clean voice call only lets its owner's own tools run.) */\nexport function hasDeviceTool(name: string, pluginId?: string): boolean {\n const entry = registry.get(name);\n return !!entry && (pluginId === undefined || entry.pluginId === pluginId);\n}\n\nexport function listDeviceTools(): DeviceToolSummary[] {\n return Array.from(registry.entries()).map(([name, { pluginId, tool }]) => ({\n name,\n pluginId,\n description: tool.description,\n input_schema: tool.input_schema,\n }));\n}\n\n/**\n * Invoke a device tool. Never throws — every failure comes back as a typed\n * outcome, because the caller is usually a reasoning loop that has to say\n * something useful out loud rather than swallow an exception.\n */\nexport async function callDeviceTool(\n name: string,\n args: any = {},\n opts: { timeoutMs?: number; signal?: AbortSignal } = {},\n): Promise<DeviceToolOutcome> {\n const entry = registry.get(name);\n if (!entry) {\n return { ok: false, reason: 'not_found', error: `No device tool registered as \"${name}\"` };\n }\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n try {\n const build = contextProvider || defaultContext;\n const built = build(entry.pluginId, entry.capabilities, entry.stateDomains);\n const ctx: DeviceToolContext = {\n ...built,\n // Whoever built the context, a call cannot own a subscription.\n deviceState: withoutSubscribe(built.deviceState),\n signal: opts.signal,\n };\n\n const result = await Promise.race([\n Promise.resolve(entry.tool.run(args, ctx)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`Device tool \"${name}\" timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n }),\n ]);\n\n return { ok: true, result };\n } catch (err: any) {\n const message = err?.message || String(err);\n const timedOut = message.includes('timed out after');\n return { ok: false, reason: timedOut ? 'timeout' : 'failed', error: message };\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** Test/host reset. */\nexport function clearDeviceTools(): void {\n registry.clear();\n}\n","/**\n * Host DI + gate for `props.voice` — the session counterpart of\n * setDeviceStateProvider / setPluginNativeProvider.\n *\n * The app mounts one live voice session (VoiceSessionHost in @ateam-ai-mobile/ui)\n * and hands it here once at startup via setVoiceProvider. gateVoice then decides,\n * per plugin, whether that session is exposed:\n *\n * - declared (`capabilities: { voice: true }`) + a provider present → the real\n * session.\n * - declared but no provider (no session host in this build) → a refusal that\n * names the reason.\n * - NOT declared → a refusal that names the reason.\n *\n * ABSENCE IS AN ANSWER (spec invariant 6). A denied surface never fakes an\n * `idle` snapshot and never silently no-ops: reads report `state: 'error'` with\n * an explicit `lastError`, and actions throw. A silent `idle` would read to a\n * reasoning loop as \"a working session that simply isn't connected yet\" — a\n * fabrication, the same class of bug as an undefined that flows into an answer.\n */\nimport type { VoiceAPI, VoiceSnapshot, VoiceSessionProvider } from './sdk/voice';\n\nlet _provider: VoiceSessionProvider | null = null;\n\n/** Host DI: the app supplies its live (owner-aware) voice session. Called once\n * at startup; pass null to detach (e.g. in a build with no voice). */\nexport function setVoiceProvider(provider: VoiceSessionProvider | null): void {\n _provider = provider || null;\n}\n\n/** Whether this build has a voice session to expose — for diagnostics. */\nexport function implementedVoice(): boolean {\n return !!_provider;\n}\n\nfunction voiceDenial(why: string): Error {\n const err: any = new Error(`voice: ${why}`);\n // Frozen vocabulary (matches gateDeviceState): a capability/manifest gate IS a\n // policy, so a denial is RESTRICTED — no new error vocabulary.\n err.code = 'RESTRICTED';\n return err;\n}\n\n/**\n * The refused surface. Reads answer honestly (\"I am not available, here is\n * why\"); actions throw. Deliberately NOT a fake `idle` and NOT a silent no-op.\n */\nfunction deniedVoice(why: string): VoiceAPI {\n const fail = () => { throw voiceDenial(why); };\n return {\n async start() { return fail(); },\n stop() { fail(); },\n setMuted() { fail(); },\n prompt() { fail(); },\n observe() { fail(); },\n getSnapshot(): VoiceSnapshot {\n return {\n state: 'error',\n sessionId: null,\n muted: false,\n speaking: false,\n listening: false,\n userSpeaking: false,\n lastUserSpeechEndedAt: null,\n lastDeviceTool: null,\n authorizedSessionId: null,\n lastError: why,\n };\n },\n subscribe() { return fail(); },\n transcript() { return []; },\n };\n}\n\n/**\n * A per-plugin VoiceAPI that stamps `pluginId` as the caller on every call, so\n * the owner-aware provider can isolate it. TWO plugins get TWO facades bound to\n * TWO identities; neither can read, control, or attach to the other's live\n * session — even though both declared voice and both share the one physical\n * session. A plugin never supplies its own identity: it is captured here.\n */\nfunction scopedVoice(provider: VoiceSessionProvider, pluginId: string): VoiceAPI {\n return {\n start: (opts) => provider.start(opts, pluginId),\n stop: () => provider.stop(pluginId),\n setMuted: (muted) => provider.setMuted(muted, pluginId),\n prompt: (input) => provider.prompt(input, pluginId),\n observe: (text) => provider.observe(text, pluginId),\n getSnapshot: () => provider.getSnapshot(pluginId),\n subscribe: (cb) => provider.subscribe(cb, pluginId),\n transcript: () => provider.transcript(pluginId),\n };\n}\n\n/**\n * The `voice` a plugin receives, gated by whether it declared the capability AND\n * scoped to its identity.\n *\n * `declared` is `!!capabilities.voice` from the plugin's TRUSTED declaration\n * (resolved in pluginRuntime.ts — the server manifest for a remote plugin, the\n * registry entry for a host-owned one). A downloaded bundle cannot grant itself\n * voice. `pluginId` is the trusted identity the returned facade is bound to.\n *\n * Reading the transcript of a live session is a privacy surface, not just an\n * API: this gate is the only thing between a plugin and everything the user\n * says. Two protections stack: (1) it is coupled to evidence — a live session\n * shows the platform-owned, unsuppressable mic indicator, so there is no path to\n * a transcript without visible proof the mic is/was live; and (2) it is scoped\n * to the owner, so declaring `voice` lets a plugin run ITS OWN conversation, not\n * eavesdrop on another solution's. A missing identity FAILS CLOSED.\n */\nexport function gateVoice(declared: boolean, pluginId: string): VoiceAPI {\n if (!declared) {\n return deniedVoice(\n \"not declared in this plugin's capabilities. Add `capabilities: { voice: true }` to use it.\",\n );\n }\n if (!pluginId) {\n return deniedVoice(\n 'no plugin identity — voice fails closed without a caller to scope the session to.',\n );\n }\n return _provider\n ? scopedVoice(_provider, pluginId)\n : deniedVoice(\n 'no voice session in this build — the app has not mounted a VoiceSessionHost / called setVoiceProvider.',\n );\n}\n","/**\n * The ONE runtime contract that turns a plugin's declarations into its gated\n * device surface — `props.device` / `props.native` (L2) and `props.deviceState`\n * (L3) — for EVERY renderer, on EVERY surface, and for its device tools.\n *\n * WHY THIS EXISTS. Each renderer used to resolve this itself: the embedded route\n * gated both `native` and `deviceState`; the drawer/fullscreen renderer gated\n * only `native` and read `manifest.native` instead of `manifest.capabilities`;\n * the host-built-in surfaces gated `native` off the registry entry and passed no\n * `deviceState` at all. The SAME plugin therefore got full device access on one\n * surface and `undefined` on another — invisible to the author, whose manifest\n * was correct. A seam owned by three renderers is tested by none. This makes it\n * owned by one: every renderer calls resolvePluginRuntimeProps, so they cannot\n * disagree, and a parity test on this function covers all of them at once.\n */\nimport { getPluginNative, gatePluginNative } from './host';\nimport { gateDeviceState } from './deviceStateHost';\nimport { gateVoice } from './voiceHost';\nimport type { PluginNative, NativeCapabilities } from './sdk/types';\nimport type { DeviceState, DeviceBridgeDomain } from './sdk/device-state';\nimport type { VoiceAPI } from './sdk/voice';\n\n/** The gated surface a plugin Component receives. `device` and `native` are the\n * SAME object (native is the deprecated alias). */\nexport interface PluginRuntimeProps {\n device: PluginNative;\n native: PluginNative;\n deviceState: DeviceState;\n voice: VoiceAPI;\n}\n\n/** One declaration source — either the server manifest or the registry entry. */\ninterface PluginDeclaration {\n capabilities?: NativeCapabilities | Record<string, unknown>;\n native?: NativeCapabilities;\n stateDomains?: readonly DeviceBridgeDomain[];\n}\n\nexport interface PluginRuntimeSource {\n pluginId: string;\n /**\n * The server manifest (Core-passed) — the TRUSTED authority for a REMOTE\n * plugin. `capabilities` is the current field Core emits; `native` is the\n * legacy one. A grant absent here is NOT GRANTED (fail closed).\n */\n manifest?: PluginDeclaration | null;\n /**\n * The registry entry — the trusted authority for a HOST-OWNED plugin\n * (registered locally, no server manifest). For a REMOTE plugin this is the\n * downloaded bundle's own claim and is UNTRUSTED for gating; it is used ONLY\n * when there is no manifest.\n */\n plugin?: PluginDeclaration | null;\n}\n\n/** Union the recognized native-capability flags from a source's `native`\n * (legacy) and `capabilities` (current) fields. A grant in EITHER is honored;\n * neither shadows the other. `capabilities` may also carry non-capability\n * metadata (e.g. `device_tools`) — gatePluginNative reads only the flags it\n * knows and ignores the rest. */\nfunction mergeCaps(decl: PluginDeclaration | null | undefined): NativeCapabilities | undefined {\n if (!decl) return undefined;\n return { ...(decl.native as any), ...(decl.capabilities as any) } as NativeCapabilities;\n}\n\n/** What a plugin is GRANTED — resolved from its one trusted source. The same\n * value gates its rendered surface and its device tools (the tool registry\n * receives it through bundleManager.load/loadTools). */\nexport interface PluginGrants {\n capabilities?: NativeCapabilities;\n stateDomains?: DeviceBridgeDomain[];\n}\n\n/**\n * Resolve a plugin's grants — the SINGLE place this happens, for every rendered\n * surface AND for the device tools its bundle registers, so a plugin gets\n * identical access through either.\n *\n * TRUST BOUNDARY. Exactly ONE source is authoritative: the server `manifest` for\n * a remote plugin, the registry `plugin` for a host-owned one. They are NEVER\n * mixed, and a remote plugin's own downloaded bundle claim NEVER expands its\n * capabilities or L3 domains past what the trusted source granted. If the\n * trusted source omits a grant, it is not granted — fail closed. (If Core does\n * not carry `stateDomains` for a remote plugin, the fix is Core passing it, not\n * trusting the bundle: Core already holds the solution's declaration.)\n */\nexport function resolvePluginGrants(src: PluginRuntimeSource): PluginGrants {\n const trusted = src.manifest ?? src.plugin ?? null;\n // Copied, so the grant cannot change after the fact by mutating the source.\n const stateDomains = trusted?.stateDomains ? [...trusted.stateDomains] : undefined;\n return { capabilities: mergeCaps(trusted), stateDomains };\n}\n\n/** Turn a plugin's grants into the gated { device, native, deviceState, voice } it\n * receives on every rendered surface. */\nexport function resolvePluginRuntimeProps(src: PluginRuntimeSource): PluginRuntimeProps {\n const { capabilities, stateDomains } = resolvePluginGrants(src);\n const native = gatePluginNative(getPluginNative(), capabilities, src.pluginId);\n const deviceState = gateDeviceState(stateDomains);\n // Voice is a capability flag, gated the same way — the TRUSTED declaration\n // decides, a downloaded bundle cannot grant itself the session (or the\n // transcript it can read). The facade is bound to the TRUSTED pluginId, so the\n // session is isolated per solution: declaring voice runs YOUR conversation, it\n // does not attach to another plugin's live one.\n const voice = gateVoice(!!(capabilities as any)?.voice, src.pluginId);\n // device and native are intentionally the SAME gated object (R4 rename).\n return { device: native, native, deviceState, voice };\n}\n","/**\n * Device tool loading.\n *\n * A device tool is only callable once its plugin bundle has been evaluated —\n * that is when the tools register (see `./registry`). Nothing else in the app\n * guarantees that: bundle prewarm runs on the home screen and is best-effort, so\n * a user who goes straight into a voice call can reach a tool the phone has\n * never loaded. The model then hears \"no such tool\" and improvises, which looks\n * exactly like a broken feature.\n *\n * So the voice path calls `ensureDeviceToolsLoaded()` before connecting.\n */\nimport { listPlugins, getPlugin, getNativeBundleUrl, getNativeBundleHash } from '../api/plugins';\nimport { bundleManager } from '../bundles/bundleManager';\nimport { listDeviceTools } from './registry';\nimport { getBundleStorage, selectOwnedCacheEntries } from '../bundles/storage';\nimport { resolvePluginGrants } from '../pluginRuntime';\nimport { getTenant } from '@ateam-ai-mobile/core';\n\nlet inflight: Promise<string[]> | null = null;\nlet loadedOnce = false;\n\n/**\n * Load every plugin that declares `capabilities.device_tools`, so its tools are\n * registered and callable. Best-effort and idempotent: safe to call on every\n * call start. Returns the tool names currently registered.\n *\n * Pass `force` after a plugin catalog change (a newly deployed connector).\n */\nexport async function ensureDeviceToolsLoaded({ force = false } = {}): Promise<string[]> {\n if (loadedOnce && !force) return listDeviceTools().map(t => t.name);\n if (inflight) return inflight;\n\n inflight = (async () => {\n try {\n const summaries = await listPlugins();\n\n // The list response is slim, so the manifest is the authority on whether a\n // plugin declares device tools. Fetched in parallel — a cold connector\n // that answers slowly must not hold up a call.\n const manifests = await Promise.all(\n (summaries || []).map(s =>\n getPlugin((s as any).id).catch(() => null),\n ),\n );\n\n const targets = manifests.filter((m: any) => {\n const declared = m?.capabilities?.device_tools;\n return Array.isArray(declared) && declared.length > 0;\n });\n\n if (targets.length === 0) {\n // The catalog can go blind: a solution connector is lazy, and while it\n // is not running its plugins are absent from the list entirely. That is\n // a fact about a server process, not about this phone — the bundle we\n // already downloaded still has the tools in it.\n //\n // So fall back to what is on disk: re-evaluate this tenant's cached\n // bundles under the trusted declaration recorded when a manifest last\n // loaded them (see loadFromDiskCache).\n const recovered = await loadFromDiskCache();\n if (recovered.length > 0) {\n console.log(`[deviceTools] catalog listed none — recovered from cache: ${recovered.join(', ')}`);\n return recovered;\n }\n // Do NOT latch: \"nothing yet\" is usually just \"not yet\".\n console.log('[deviceTools] no device tools available yet — will look again next call');\n return [];\n }\n\n await Promise.all(\n targets.map(async (m: any) => {\n const bundleUrl = getNativeBundleUrl(m);\n if (!bundleUrl) {\n console.warn(`[deviceTools] ${m.id} declares device_tools but has no native bundle`);\n return;\n }\n try {\n // The manifest is the authority on what the tools may touch — the\n // same grants its rendered surface gets, never the bundle's claim.\n await bundleManager.loadTools(\n m.id,\n bundleUrl,\n m.version || '1.0.0',\n getNativeBundleHash(m) || undefined,\n resolvePluginGrants({ pluginId: m.id, manifest: m }),\n );\n } catch (err: any) {\n console.warn(`[deviceTools] ${m.id} failed to load:`, err?.message || String(err));\n }\n }),\n );\n\n const names = listDeviceTools().map(t => t.name);\n // Only latch on success. An empty result is a cold read, not a fact —\n // same reasoning as the server-side discovery cache.\n loadedOnce = names.length > 0;\n console.log(`[deviceTools] ready: ${names.length > 0 ? names.join(', ') : '(none registered — will retry next call)'}`);\n return names;\n } finally {\n inflight = null;\n }\n })();\n\n return inflight;\n}\n\n/**\n * Re-evaluate the CURRENT TENANT'S bundles already cached on disk.\n *\n * Used when the plugin catalog comes back empty — which happens whenever the\n * owning connector is asleep. This is a local read, not a download.\n *\n * TENANT SCOPING IS LOAD-BEARING, NOT DEFENCE IN DEPTH.\n *\n * Every other load path is gated by the manifest hash: the expected hash comes\n * from the current tenant's server, so another tenant's cached bytes simply\n * fail to match and are re-downloaded. This path has no manifest — that is the\n * whole reason it exists — so it passes each entry's OWN stored hash as the\n * expected hash. That check compares an entry to itself and can never fail. It\n * is an integrity check against disk corruption, and it is not, and cannot be,\n * an authorisation check.\n *\n * Without the tenant filter below this loop re-evaluated EVERY cached bundle,\n * so a plugin cached during a session on tenant A registered its device tools\n * into a live session on tenant B, and subsequent tool calls ran tenant-A code\n * holding tenant-B credentials. No id collision was required: bundle urls are\n * identical across tenants and resolve per-tenant on the server, and the code\n * cache deliberately survives logout.\n *\n * An entry with no recorded tenant predates the stamp. Its owner is unknown,\n * which means untrusted — skip it and let the normal catalog path re-download\n * it under a real hash gate.\n *\n * GRANTS COME FROM THE RECORDED MANIFEST, NEVER THE BUNDLE. With no manifest\n * here, the tools register under the `trusted` declaration (pluginId +\n * capabilities + stateDomains) the bundle manager recorded on the entry when a\n * manifest last loaded these bytes. An entry without one — written before the\n * record existed, or never loaded under a manifest — is skipped (fail closed):\n * the only other source is the bundle's own claim, and the catalog path\n * registers it properly once its connector answers.\n */\nasync function loadFromDiskCache(): Promise<string[]> {\n try {\n const index = await getBundleStorage().loadIndex();\n const entries = Object.values(index || {});\n if (entries.length === 0) return [];\n\n const tenant = getTenant();\n if (!tenant) {\n // No active tenant: nothing can be proven to be ours.\n console.warn('[deviceTools] disk-cache recovery skipped — no active tenant');\n return [];\n }\n const mine = selectOwnedCacheEntries(entries, tenant);\n const skipped = entries.length - mine.length;\n if (skipped > 0) {\n console.log(`[deviceTools] disk-cache recovery: ${mine.length} for \"${tenant}\", skipped ${skipped} not owned by it`);\n }\n const declared = mine.filter((e) => !!e.trusted?.pluginId);\n if (declared.length < mine.length) {\n console.log(\n `[deviceTools] disk-cache recovery: skipped ${mine.length - declared.length} with no recorded manifest grant (fail closed)`,\n );\n }\n if (declared.length === 0) return [];\n\n await Promise.all(declared.map(async (e) => {\n try {\n await bundleManager.loadTools(e.trusted!.pluginId, e.bundleUrl, e.version, e.bundleHash, e.trusted!);\n } catch {\n // A cached bundle that no longer loads is not worth failing a call over.\n }\n }));\n return listDeviceTools().map(t => t.name);\n } catch (err: any) {\n console.warn('[deviceTools] disk-cache recovery failed:', err?.message || String(err));\n return [];\n }\n}\n\n/** Forget that we loaded, so the next call re-reads the catalog. */\nexport function resetDeviceToolLoader(): void {\n loadedOnce = false;\n}\n"],"mappings":"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","names":["React","useEffect","useCallback","useMemo","useRef","getTenant","View","Text","Pressable","TextInput","ActivityIndicator","StyleSheet","unavailable","useMemo","useEffect","View","Text","Pressable","StyleSheet","Animated","Platform","Svg","ada","View","StyleSheet","Animated","jsx","styles","jsx","jsxs","Platform","Animated","useEffect","styles","Pressable","StyleSheet","View","Text","Svg","ada","View","Text","Pressable","StyleSheet","Platform","ada","borderRadius","jsx","jsxs","fontFam","Platform","Pressable","styles","View","Text","StyleSheet","useEffect","useRef","View","Text","Pressable","StyleSheet","Animated","Platform","Svg","Path","ada","jsx","jsxs","fontFam","styles","cleanup","useEffect","jsx","jsxs","useEffect","useMemo","useRef","useEffect","pluginCommandEmitter","React","useEffect","useCallback","useMemo","useRef","getTenant","_provider","getTenant"]}