@ateam-ai-mobile/plugin-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2388 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ActionButton: () => ActionButton,
34
+ ActivityIndicator: () => import_react_native.ActivityIndicator,
35
+ AdaOrb: () => AdaOrb,
36
+ Animated: () => import_react_native.Animated,
37
+ Badge: () => Badge,
38
+ Card: () => Card,
39
+ EmptyState: () => EmptyState,
40
+ ErrorState: () => ErrorState,
41
+ FlatList: () => import_react_native.FlatList,
42
+ Image: () => import_react_native.Image,
43
+ ListItem: () => ListItem,
44
+ LoadingState: () => LoadingState,
45
+ MemoryBundleStorage: () => MemoryBundleStorage,
46
+ Modal: () => import_react_native.Modal,
47
+ Platform: () => import_react_native.Platform,
48
+ PluginSDK: () => PluginSDK,
49
+ Pressable: () => import_react_native.Pressable,
50
+ RefreshControl: () => import_react_native.RefreshControl,
51
+ ScrollView: () => import_react_native.ScrollView,
52
+ SearchBar: () => SearchBar,
53
+ SectionList: () => import_react_native.SectionList,
54
+ StyleSheet: () => import_react_native.StyleSheet,
55
+ SurfaceCard: () => SurfaceCard,
56
+ SurfaceDispatcher: () => SurfaceDispatcher,
57
+ SurfaceDrawer: () => SurfaceDrawer,
58
+ SurfaceFullscreen: () => SurfaceFullscreen,
59
+ Switch: () => import_react_native.Switch,
60
+ TabBar: () => TabBar,
61
+ Text: () => import_react_native.Text,
62
+ TextInput: () => import_react_native.TextInput,
63
+ TouchableOpacity: () => import_react_native.TouchableOpacity,
64
+ View: () => import_react_native.View,
65
+ bundleManager: () => bundleManager,
66
+ createNativeBridge: () => createNativeBridge,
67
+ getHaptics: () => getHaptics,
68
+ getNativeBundleHash: () => getNativeBundleHash,
69
+ getNativeBundleUrl: () => getNativeBundleUrl,
70
+ getNativeComponentId: () => getNativeComponentId,
71
+ getPlugin: () => getPlugin,
72
+ getPluginNative: () => getPluginNative,
73
+ isInlineSurface: () => isInlineSurface,
74
+ isMountSurface: () => isMountSurface,
75
+ listPlugins: () => listPlugins,
76
+ nativePluginRegistry: () => nativePluginRegistry,
77
+ register: () => register,
78
+ registerBundleModules: () => registerBundleModules,
79
+ registerNativePlugin: () => registerNativePlugin,
80
+ registerService: () => registerService,
81
+ resolvePluginUrl: () => resolvePluginUrl,
82
+ setBundleStorage: () => setBundleStorage,
83
+ setHapticsProvider: () => setHapticsProvider,
84
+ setPluginNativeProvider: () => setPluginNativeProvider,
85
+ setPluginThemeColors: () => setPluginThemeColors,
86
+ supportsNative: () => supportsNative,
87
+ supportsWebView: () => supportsWebView,
88
+ unregisterNativePlugin: () => unregisterNativePlugin,
89
+ useApi: () => useApi,
90
+ useNativeBridge: () => useNativeBridge,
91
+ usePlugin: () => usePlugin,
92
+ usePluginTheme: () => usePluginTheme,
93
+ useRemotePlugins: () => useRemotePlugins,
94
+ useSurfaceStore: () => useSurfaceStore
95
+ });
96
+ module.exports = __toCommonJS(index_exports);
97
+
98
+ // src/sdk/index.ts
99
+ var sdk_exports = {};
100
+ __export(sdk_exports, {
101
+ ActionButton: () => ActionButton,
102
+ ActivityIndicator: () => import_react_native.ActivityIndicator,
103
+ Animated: () => import_react_native.Animated,
104
+ Badge: () => Badge,
105
+ Card: () => Card,
106
+ EmptyState: () => EmptyState,
107
+ ErrorState: () => ErrorState,
108
+ FlatList: () => import_react_native.FlatList,
109
+ Image: () => import_react_native.Image,
110
+ ListItem: () => ListItem,
111
+ LoadingState: () => LoadingState,
112
+ Modal: () => import_react_native.Modal,
113
+ Platform: () => import_react_native.Platform,
114
+ PluginSDK: () => PluginSDK,
115
+ Pressable: () => import_react_native.Pressable,
116
+ RefreshControl: () => import_react_native.RefreshControl,
117
+ ScrollView: () => import_react_native.ScrollView,
118
+ SearchBar: () => SearchBar,
119
+ SectionList: () => import_react_native.SectionList,
120
+ StyleSheet: () => import_react_native.StyleSheet,
121
+ Switch: () => import_react_native.Switch,
122
+ TabBar: () => TabBar,
123
+ Text: () => import_react_native.Text,
124
+ TextInput: () => import_react_native.TextInput,
125
+ TouchableOpacity: () => import_react_native.TouchableOpacity,
126
+ View: () => import_react_native.View,
127
+ register: () => register,
128
+ registerService: () => registerService,
129
+ setPluginThemeColors: () => setPluginThemeColors,
130
+ useApi: () => useApi,
131
+ usePluginTheme: () => usePluginTheme
132
+ });
133
+
134
+ // src/sdk/registration.ts
135
+ function register(id, config) {
136
+ return {
137
+ id,
138
+ type: config.type || "ui",
139
+ capabilities: config.capabilities,
140
+ Component: config.Component
141
+ };
142
+ }
143
+ function registerService(id, config) {
144
+ return {
145
+ id,
146
+ type: "service",
147
+ capabilities: config.capabilities,
148
+ hooks: config.hooks,
149
+ onStart: config.onStart,
150
+ onStop: config.onStop
151
+ };
152
+ }
153
+
154
+ // src/sdk/primitives.ts
155
+ var import_react_native = require("react-native");
156
+
157
+ // src/sdk/components.ts
158
+ var import_react = __toESM(require("react"));
159
+ var import_react_native2 = require("react-native");
160
+ function Card({ theme, children, style, onPress }) {
161
+ const cardStyle = [
162
+ styles.card,
163
+ {
164
+ backgroundColor: theme.colors.surface,
165
+ borderColor: theme.colors.border
166
+ },
167
+ style
168
+ ];
169
+ if (onPress) {
170
+ return import_react.default.createElement(import_react_native2.Pressable, { style: cardStyle, onPress }, children);
171
+ }
172
+ return import_react.default.createElement(import_react_native2.View, { style: cardStyle }, children);
173
+ }
174
+ var BADGE_COLORS = {
175
+ accent: { bg: "accentSoft", text: "accent" },
176
+ success: { bg: "successSoft", text: "success" },
177
+ warning: { bg: "warningSoft", text: "warning" },
178
+ error: { bg: "errorSoft", text: "error" },
179
+ purple: { bg: "purpleSoft", text: "purple" }
180
+ };
181
+ function Badge({ theme, label, color = "accent", style }) {
182
+ const mapping = BADGE_COLORS[color];
183
+ return import_react.default.createElement(
184
+ import_react_native2.View,
185
+ {
186
+ style: [
187
+ styles.badge,
188
+ {
189
+ backgroundColor: theme.colors[mapping.bg],
190
+ borderRadius: theme.borderRadius.sm
191
+ },
192
+ style
193
+ ]
194
+ },
195
+ import_react.default.createElement(import_react_native2.Text, {
196
+ style: [styles.badgeText, { color: theme.colors[mapping.text] }]
197
+ }, label)
198
+ );
199
+ }
200
+ function TabBar({ theme, tabs, activeTab, onTabChange, style }) {
201
+ return import_react.default.createElement(
202
+ import_react_native2.View,
203
+ {
204
+ style: [
205
+ styles.tabBar,
206
+ { borderBottomColor: theme.colors.border },
207
+ style
208
+ ]
209
+ },
210
+ tabs.map(
211
+ (tab) => import_react.default.createElement(
212
+ import_react_native2.Pressable,
213
+ {
214
+ key: tab,
215
+ style: [
216
+ styles.tab,
217
+ {
218
+ borderBottomColor: tab === activeTab ? theme.colors.accent : "transparent"
219
+ }
220
+ ],
221
+ onPress: () => onTabChange(tab)
222
+ },
223
+ import_react.default.createElement(import_react_native2.Text, {
224
+ style: {
225
+ color: tab === activeTab ? theme.colors.accent : theme.colors.textSecondary,
226
+ fontSize: theme.fontSize.sm,
227
+ fontWeight: tab === activeTab ? "600" : "400"
228
+ }
229
+ }, tab)
230
+ )
231
+ )
232
+ );
233
+ }
234
+ function ListItem({ theme, title, subtitle, right, onPress, style }) {
235
+ const content = [
236
+ import_react.default.createElement(
237
+ import_react_native2.View,
238
+ { key: "content", style: styles.listItemContent },
239
+ import_react.default.createElement(import_react_native2.Text, {
240
+ style: { color: theme.colors.text, fontSize: theme.fontSize.md },
241
+ numberOfLines: 1
242
+ }, title),
243
+ subtitle ? import_react.default.createElement(import_react_native2.Text, {
244
+ style: { color: theme.colors.textSecondary, fontSize: theme.fontSize.xs, marginTop: 2 },
245
+ numberOfLines: 1
246
+ }, subtitle) : null
247
+ ),
248
+ right ? import_react.default.createElement(import_react_native2.View, { key: "right" }, right) : null
249
+ ];
250
+ if (onPress) {
251
+ return import_react.default.createElement(
252
+ import_react_native2.Pressable,
253
+ { style: [styles.listItem, { borderBottomColor: theme.colors.border }, style], onPress },
254
+ ...content
255
+ );
256
+ }
257
+ return import_react.default.createElement(
258
+ import_react_native2.View,
259
+ { style: [styles.listItem, { borderBottomColor: theme.colors.border }, style] },
260
+ ...content
261
+ );
262
+ }
263
+ function SearchBar({ theme, value, onChangeText, placeholder = "Search...", style }) {
264
+ return import_react.default.createElement(import_react_native2.TextInput, {
265
+ style: [
266
+ styles.searchBar,
267
+ {
268
+ backgroundColor: theme.colors.input,
269
+ color: theme.colors.text,
270
+ borderColor: theme.colors.border,
271
+ borderRadius: theme.borderRadius.sm,
272
+ fontSize: theme.fontSize.sm
273
+ },
274
+ style
275
+ ],
276
+ value,
277
+ onChangeText,
278
+ placeholder,
279
+ placeholderTextColor: theme.colors.textMuted,
280
+ autoCapitalize: "none",
281
+ autoCorrect: false
282
+ });
283
+ }
284
+ function EmptyState({ theme, title, subtitle, style }) {
285
+ return import_react.default.createElement(
286
+ import_react_native2.View,
287
+ { style: [styles.emptyState, style] },
288
+ import_react.default.createElement(import_react_native2.Text, {
289
+ style: { color: theme.colors.textSecondary, fontSize: theme.fontSize.md, textAlign: "center" }
290
+ }, title),
291
+ subtitle ? import_react.default.createElement(import_react_native2.Text, {
292
+ style: { color: theme.colors.textMuted, fontSize: theme.fontSize.sm, textAlign: "center", marginTop: 4 }
293
+ }, subtitle) : null
294
+ );
295
+ }
296
+ function ErrorState({ theme, message, onRetry, style }) {
297
+ return import_react.default.createElement(
298
+ import_react_native2.View,
299
+ { style: [styles.emptyState, style] },
300
+ import_react.default.createElement(import_react_native2.Text, {
301
+ style: { color: theme.colors.error, fontSize: theme.fontSize.md, textAlign: "center" }
302
+ }, message),
303
+ onRetry ? import_react.default.createElement(
304
+ import_react_native2.Pressable,
305
+ {
306
+ style: [styles.retryButton, { backgroundColor: theme.colors.accentSoft, borderRadius: theme.borderRadius.sm }],
307
+ onPress: onRetry
308
+ },
309
+ import_react.default.createElement(import_react_native2.Text, {
310
+ style: { color: theme.colors.accent, fontSize: theme.fontSize.sm, fontWeight: "600" }
311
+ }, "Retry")
312
+ ) : null
313
+ );
314
+ }
315
+ function LoadingState({ theme, message = "Loading...", style }) {
316
+ return import_react.default.createElement(
317
+ import_react_native2.View,
318
+ { style: [styles.emptyState, style] },
319
+ import_react.default.createElement(import_react_native2.ActivityIndicator, { size: "small", color: theme.colors.accent }),
320
+ import_react.default.createElement(import_react_native2.Text, {
321
+ style: { color: theme.colors.textSecondary, fontSize: theme.fontSize.sm, marginTop: 8 }
322
+ }, message)
323
+ );
324
+ }
325
+ function ActionButton({ theme, label, icon, onPress, style }) {
326
+ return import_react.default.createElement(
327
+ import_react_native2.Pressable,
328
+ {
329
+ style: [
330
+ styles.fab,
331
+ { backgroundColor: theme.colors.accent, borderRadius: theme.borderRadius.full },
332
+ style
333
+ ],
334
+ onPress
335
+ },
336
+ icon || import_react.default.createElement(import_react_native2.Text, { style: styles.fabText }, label || "+")
337
+ );
338
+ }
339
+ var styles = import_react_native2.StyleSheet.create({
340
+ card: {
341
+ padding: 12,
342
+ borderRadius: 12,
343
+ borderWidth: 1,
344
+ marginBottom: 8
345
+ },
346
+ badge: {
347
+ paddingHorizontal: 8,
348
+ paddingVertical: 3
349
+ },
350
+ badgeText: {
351
+ fontSize: 11,
352
+ fontWeight: "600"
353
+ },
354
+ tabBar: {
355
+ flexDirection: "row",
356
+ borderBottomWidth: 1
357
+ },
358
+ tab: {
359
+ flex: 1,
360
+ padding: 12,
361
+ alignItems: "center",
362
+ borderBottomWidth: 2
363
+ },
364
+ listItem: {
365
+ flexDirection: "row",
366
+ alignItems: "center",
367
+ paddingVertical: 12,
368
+ paddingHorizontal: 16,
369
+ borderBottomWidth: import_react_native2.StyleSheet.hairlineWidth
370
+ },
371
+ listItemContent: {
372
+ flex: 1
373
+ },
374
+ searchBar: {
375
+ height: 40,
376
+ paddingHorizontal: 12,
377
+ borderWidth: 1
378
+ },
379
+ emptyState: {
380
+ flex: 1,
381
+ justifyContent: "center",
382
+ alignItems: "center",
383
+ padding: 32
384
+ },
385
+ retryButton: {
386
+ marginTop: 12,
387
+ paddingHorizontal: 16,
388
+ paddingVertical: 8
389
+ },
390
+ fab: {
391
+ position: "absolute",
392
+ bottom: 24,
393
+ right: 24,
394
+ width: 56,
395
+ height: 56,
396
+ justifyContent: "center",
397
+ alignItems: "center",
398
+ shadowColor: "#000",
399
+ shadowOffset: { width: 0, height: 2 },
400
+ shadowOpacity: 0.25,
401
+ shadowRadius: 4,
402
+ elevation: 5
403
+ },
404
+ fabText: {
405
+ color: "#fff",
406
+ fontSize: 24,
407
+ fontWeight: "600"
408
+ }
409
+ });
410
+
411
+ // src/sdk/usePluginTheme.ts
412
+ var import_react2 = require("react");
413
+ var import_core = require("@ateam-ai-mobile/core");
414
+ var adaColors = {
415
+ bg: import_core.ada.paper,
416
+ surface: import_core.ada.paperSoft,
417
+ surfaceAlt: import_core.ada.paperDeep,
418
+ input: import_core.ada.paper,
419
+ border: import_core.ada.border,
420
+ text: import_core.ada.ink,
421
+ textSecondary: import_core.ada.inkSoft,
422
+ textMuted: import_core.ada.inkMuted,
423
+ accent: import_core.ada.orange,
424
+ accentSoft: import_core.ada.orangeSoft,
425
+ success: "#5A8A5C",
426
+ successSoft: "rgba(90,138,92,0.14)",
427
+ warning: "#D49A4E",
428
+ warningSoft: "rgba(212,154,78,0.16)",
429
+ error: "#C15545",
430
+ errorSoft: "rgba(193,85,69,0.14)",
431
+ purple: import_core.ada.orangeDeep,
432
+ purpleSoft: import_core.ada.orangeSoft
433
+ };
434
+ var _colors = adaColors;
435
+ var _isDark = false;
436
+ var _subscribers = /* @__PURE__ */ new Set();
437
+ function setPluginThemeColors(colors, opts) {
438
+ _colors = { ...adaColors, ...colors };
439
+ if (opts?.isDark !== void 0) _isDark = opts.isDark;
440
+ _subscribers.forEach((fn) => fn());
441
+ }
442
+ function subscribe(fn) {
443
+ _subscribers.add(fn);
444
+ return () => {
445
+ _subscribers.delete(fn);
446
+ };
447
+ }
448
+ function usePluginTheme() {
449
+ const colors = (0, import_react2.useSyncExternalStore)(subscribe, () => _colors);
450
+ const isDark = (0, import_react2.useSyncExternalStore)(subscribe, () => _isDark);
451
+ return (0, import_react2.useMemo)(() => ({
452
+ colors,
453
+ spacing: {
454
+ xs: import_core.spacing.xs,
455
+ sm: import_core.spacing.sm,
456
+ md: import_core.spacing.md,
457
+ lg: import_core.spacing.lg,
458
+ xl: import_core.spacing.xl,
459
+ xxl: import_core.spacing.xxl
460
+ },
461
+ fontSize: {
462
+ xs: import_core.fontSize.xs,
463
+ sm: import_core.fontSize.sm,
464
+ md: import_core.fontSize.md,
465
+ lg: import_core.fontSize.lg,
466
+ xl: import_core.fontSize.xl
467
+ },
468
+ borderRadius: {
469
+ sm: import_core.borderRadius.sm,
470
+ md: import_core.borderRadius.md,
471
+ lg: import_core.borderRadius.lg,
472
+ full: import_core.borderRadius.full
473
+ },
474
+ isDark
475
+ }), [colors, isDark]);
476
+ }
477
+
478
+ // src/sdk/useApi.ts
479
+ var import_react3 = require("react");
480
+ function useApi(bridge) {
481
+ return (0, import_react3.useMemo)(() => {
482
+ const apiFn = async (connectorId, tool, args = {}) => {
483
+ if (!bridge) {
484
+ throw new Error("useApi: bridge is required. Pass it from plugin props.");
485
+ }
486
+ return bridge.mcpCall(tool, args, connectorId);
487
+ };
488
+ const callMethod = async (first, second, third) => {
489
+ if (!bridge) {
490
+ throw new Error("useApi: bridge is required. Pass it from plugin props.");
491
+ }
492
+ if (typeof second === "string") {
493
+ return bridge.mcpCall(second, third || {}, first);
494
+ }
495
+ if (typeof third === "string") {
496
+ return bridge.mcpCall(first, second || {}, third);
497
+ }
498
+ return bridge.mcpCall(first, second || {});
499
+ };
500
+ Object.defineProperty(apiFn, "call", {
501
+ value: callMethod,
502
+ writable: false,
503
+ configurable: false
504
+ });
505
+ return apiFn;
506
+ }, [bridge]);
507
+ }
508
+
509
+ // src/sdk/index.ts
510
+ var PluginSDK = { register, registerService };
511
+
512
+ // src/host.ts
513
+ var _haptics = null;
514
+ function setHapticsProvider(haptics) {
515
+ _haptics = haptics;
516
+ }
517
+ function getHaptics() {
518
+ return _haptics;
519
+ }
520
+ function unavailable(api) {
521
+ return new Proxy({}, {
522
+ get: (_t, method) => () => Promise.reject(new Error(`[adas] native.${api}.${String(method)} unavailable \u2014 host did not call setPluginNativeProvider()`))
523
+ });
524
+ }
525
+ var noopNative = {
526
+ camera: unavailable("camera"),
527
+ location: unavailable("location"),
528
+ storage: unavailable("storage"),
529
+ biometrics: unavailable("biometrics"),
530
+ biometricsV2: unavailable("biometricsV2"),
531
+ notifications: unavailable("notifications"),
532
+ haptics: { impact: () => {
533
+ }, notification: () => {
534
+ }, selection: () => {
535
+ } },
536
+ connectivity: { isOnline: () => true, onChange: () => () => {
537
+ } },
538
+ fileSystem: unavailable("fileSystem"),
539
+ cookies: unavailable("cookies"),
540
+ sharing: unavailable("sharing"),
541
+ scanner: unavailable("scanner"),
542
+ nfc: unavailable("nfc")
543
+ };
544
+ var _pluginNative = noopNative;
545
+ function setPluginNativeProvider(native) {
546
+ _pluginNative = native;
547
+ }
548
+ function getPluginNative() {
549
+ return _pluginNative;
550
+ }
551
+ var _nativeRegistry = /* @__PURE__ */ new Map();
552
+ function registerNativePlugin(id, plugin) {
553
+ _nativeRegistry.set(id, plugin);
554
+ }
555
+ function unregisterNativePlugin(id) {
556
+ _nativeRegistry.delete(id);
557
+ }
558
+ var nativePluginRegistry = {
559
+ has(id) {
560
+ return _nativeRegistry.has(id);
561
+ },
562
+ async get(id) {
563
+ const entry = _nativeRegistry.get(id);
564
+ if (!entry) return null;
565
+ if (typeof entry === "function") {
566
+ try {
567
+ return await entry();
568
+ } catch (err) {
569
+ console.warn(`[adas-plugins] lazy native plugin '${id}' failed to load:`, err);
570
+ return null;
571
+ }
572
+ }
573
+ return entry;
574
+ }
575
+ };
576
+ var _bundleModules = /* @__PURE__ */ new Map();
577
+ function registerBundleModules(modules) {
578
+ for (const [name, mod] of Object.entries(modules)) {
579
+ _bundleModules.set(name, mod);
580
+ }
581
+ }
582
+ function resolveBundleModule(name) {
583
+ return _bundleModules.get(name);
584
+ }
585
+
586
+ // src/bundles/bundleManager.ts
587
+ var import_react4 = __toESM(require("react"));
588
+ var import_react5 = require("react");
589
+ var ReactNative = __toESM(require("react-native"));
590
+ var import_core2 = require("@ateam-ai-mobile/core");
591
+
592
+ // src/utils/sha256.ts
593
+ var K = new Uint32Array([
594
+ 1116352408,
595
+ 1899447441,
596
+ 3049323471,
597
+ 3921009573,
598
+ 961987163,
599
+ 1508970993,
600
+ 2453635748,
601
+ 2870763221,
602
+ 3624381080,
603
+ 310598401,
604
+ 607225278,
605
+ 1426881987,
606
+ 1925078388,
607
+ 2162078206,
608
+ 2614888103,
609
+ 3248222580,
610
+ 3835390401,
611
+ 4022224774,
612
+ 264347078,
613
+ 604807628,
614
+ 770255983,
615
+ 1249150122,
616
+ 1555081692,
617
+ 1996064986,
618
+ 2554220882,
619
+ 2821834349,
620
+ 2952996808,
621
+ 3210313671,
622
+ 3336571891,
623
+ 3584528711,
624
+ 113926993,
625
+ 338241895,
626
+ 666307205,
627
+ 773529912,
628
+ 1294757372,
629
+ 1396182291,
630
+ 1695183700,
631
+ 1986661051,
632
+ 2177026350,
633
+ 2456956037,
634
+ 2730485921,
635
+ 2820302411,
636
+ 3259730800,
637
+ 3345764771,
638
+ 3516065817,
639
+ 3600352804,
640
+ 4094571909,
641
+ 275423344,
642
+ 430227734,
643
+ 506948616,
644
+ 659060556,
645
+ 883997877,
646
+ 958139571,
647
+ 1322822218,
648
+ 1537002063,
649
+ 1747873779,
650
+ 1955562222,
651
+ 2024104815,
652
+ 2227730452,
653
+ 2361852424,
654
+ 2428436474,
655
+ 2756734187,
656
+ 3204031479,
657
+ 3329325298
658
+ ]);
659
+ var rotr = (n, x) => x >>> n | x << 32 - n;
660
+ function sha256Hex(message) {
661
+ const utf8 = unescape(encodeURIComponent(message));
662
+ const bytes = new Uint8Array(utf8.length);
663
+ for (let i = 0; i < utf8.length; i++) bytes[i] = utf8.charCodeAt(i);
664
+ const bitLen = bytes.length * 8;
665
+ const padLen = (56 - (bytes.length + 1) % 64 + 64) % 64;
666
+ const buf = new Uint8Array(bytes.length + 1 + padLen + 8);
667
+ buf.set(bytes);
668
+ buf[bytes.length] = 128;
669
+ const len = buf.length;
670
+ buf[len - 4] = bitLen >>> 24 & 255;
671
+ buf[len - 3] = bitLen >>> 16 & 255;
672
+ buf[len - 2] = bitLen >>> 8 & 255;
673
+ buf[len - 1] = bitLen & 255;
674
+ const h = new Uint32Array([
675
+ 1779033703,
676
+ 3144134277,
677
+ 1013904242,
678
+ 2773480762,
679
+ 1359893119,
680
+ 2600822924,
681
+ 528734635,
682
+ 1541459225
683
+ ]);
684
+ const w = new Uint32Array(64);
685
+ for (let i = 0; i < buf.length; i += 64) {
686
+ for (let t = 0; t < 16; t++) {
687
+ const j = i + t * 4;
688
+ w[t] = buf[j] << 24 | buf[j + 1] << 16 | buf[j + 2] << 8 | buf[j + 3];
689
+ }
690
+ for (let t = 16; t < 64; t++) {
691
+ const s0 = rotr(7, w[t - 15]) ^ rotr(18, w[t - 15]) ^ w[t - 15] >>> 3;
692
+ const s1 = rotr(17, w[t - 2]) ^ rotr(19, w[t - 2]) ^ w[t - 2] >>> 10;
693
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1 | 0;
694
+ }
695
+ 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];
696
+ for (let t = 0; t < 64; t++) {
697
+ const S1 = rotr(6, e) ^ rotr(11, e) ^ rotr(25, e);
698
+ const ch = e & f ^ ~e & g;
699
+ const temp1 = hh + S1 + ch + K[t] + w[t] | 0;
700
+ const S0 = rotr(2, a) ^ rotr(13, a) ^ rotr(22, a);
701
+ const maj = a & b ^ a & c ^ b & c;
702
+ const temp2 = S0 + maj | 0;
703
+ hh = g;
704
+ g = f;
705
+ f = e;
706
+ e = d + temp1 | 0;
707
+ d = c;
708
+ c = b;
709
+ b = a;
710
+ a = temp1 + temp2 | 0;
711
+ }
712
+ h[0] = h[0] + a | 0;
713
+ h[1] = h[1] + b | 0;
714
+ h[2] = h[2] + c | 0;
715
+ h[3] = h[3] + d | 0;
716
+ h[4] = h[4] + e | 0;
717
+ h[5] = h[5] + f | 0;
718
+ h[6] = h[6] + g | 0;
719
+ h[7] = h[7] + hh | 0;
720
+ }
721
+ let out = "";
722
+ for (let i = 0; i < 8; i++) {
723
+ out += h[i].toString(16).padStart(8, "0");
724
+ }
725
+ return out;
726
+ }
727
+
728
+ // src/bundles/storage.ts
729
+ var MemoryBundleStorage = class {
730
+ constructor() {
731
+ this.index = {};
732
+ this.files = /* @__PURE__ */ new Map();
733
+ }
734
+ async loadIndex() {
735
+ return this.index;
736
+ }
737
+ async saveIndex(index) {
738
+ this.index = index;
739
+ }
740
+ async readBundle(localPath) {
741
+ return this.files.get(localPath) ?? null;
742
+ }
743
+ async writeBundle(key, content) {
744
+ const localPath = `memory://${key}`;
745
+ this.files.set(localPath, content);
746
+ return localPath;
747
+ }
748
+ async deleteBundle(localPath) {
749
+ this.files.delete(localPath);
750
+ }
751
+ async clearAll() {
752
+ this.index = {};
753
+ this.files.clear();
754
+ }
755
+ };
756
+ var _storage = new MemoryBundleStorage();
757
+ function setBundleStorage(storage) {
758
+ _storage = storage;
759
+ }
760
+ function getBundleStorage() {
761
+ return _storage;
762
+ }
763
+
764
+ // src/bundles/bundleManager.ts
765
+ var ReactShim = {
766
+ __esModule: true,
767
+ default: import_react4.default,
768
+ ...import_react4.default,
769
+ // Explicitly include hooks (React 19 may not have them as own enumerable props)
770
+ useState: import_react5.useState,
771
+ useEffect: import_react5.useEffect,
772
+ useCallback: import_react5.useCallback,
773
+ useMemo: import_react5.useMemo,
774
+ useRef: import_react5.useRef,
775
+ useContext: import_react5.useContext,
776
+ useReducer: import_react5.useReducer,
777
+ useLayoutEffect: import_react5.useLayoutEffect,
778
+ useImperativeHandle: import_react5.useImperativeHandle,
779
+ useDebugValue: import_react5.useDebugValue,
780
+ createElement: import_react4.default.createElement,
781
+ Fragment: import_react4.default.Fragment,
782
+ Component: import_react4.default.Component,
783
+ PureComponent: import_react4.default.PureComponent,
784
+ createContext: import_react4.default.createContext,
785
+ forwardRef: import_react4.default.forwardRef,
786
+ memo: import_react4.default.memo,
787
+ Children: import_react4.default.Children,
788
+ cloneElement: import_react4.default.cloneElement,
789
+ isValidElement: import_react4.default.isValidElement,
790
+ createRef: import_react4.default.createRef,
791
+ lazy: import_react4.default.lazy,
792
+ Suspense: import_react4.default.Suspense
793
+ };
794
+ var PluginSDKShim = Object.freeze({
795
+ ...sdk_exports,
796
+ PluginSDK: Object.freeze({
797
+ ...PluginSDK,
798
+ register: PluginSDK.register
799
+ }),
800
+ register
801
+ });
802
+ var requireShim = (name) => {
803
+ if (name === "react") return ReactShim;
804
+ if (name === "react-native") return ReactNative;
805
+ if (name === "@adas/plugin-sdk") return PluginSDKShim;
806
+ const hostModule = resolveBundleModule(name);
807
+ if (hostModule !== void 0) return hostModule;
808
+ console.warn(`[BundleManager] Unknown module: ${name} \u2014 register it via registerBundleModules()`);
809
+ return {};
810
+ };
811
+ var CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
812
+ var BundleManager = class {
813
+ constructor() {
814
+ /** In-memory module cache: bundleUrl → evaluated module.exports */
815
+ this.modules = /* @__PURE__ */ new Map();
816
+ /** In-flight download deduplication: bundleUrl → Promise */
817
+ this.inflight = /* @__PURE__ */ new Map();
818
+ }
819
+ // ── Public API ──────────────────────────────────────────────
820
+ /**
821
+ * Load a plugin component. Returns the RegisteredUIPlugin object.
822
+ * Handles: in-memory cache → disk cache → download → evaluate → extract.
823
+ *
824
+ * `expectedHash` (SHA-256 hex from cp.getContextPlugin manifest) MUST be
825
+ * provided for any bundle the user has not previously verified — without
826
+ * it, a tampered bundle is `eval`'d as JS with full RN runtime + every
827
+ * native capability the manifest declares.
828
+ */
829
+ async load(pluginId, bundleUrl, version, expectedHash) {
830
+ const cached = this.getComponentFromMemory(pluginId, bundleUrl);
831
+ if (cached) return cached;
832
+ let modulePromise = this.inflight.get(bundleUrl);
833
+ if (!modulePromise) {
834
+ modulePromise = this.loadModule(bundleUrl, version, expectedHash);
835
+ this.inflight.set(bundleUrl, modulePromise);
836
+ modulePromise.catch(() => {
837
+ }).finally(() => this.inflight.delete(bundleUrl));
838
+ }
839
+ await modulePromise;
840
+ const component = this.getComponentFromMemory(pluginId, bundleUrl);
841
+ if (!component) {
842
+ throw new Error(
843
+ `Bundle loaded from ${bundleUrl} but no component found for "${pluginId}". Available exports: ${this.describeModule(this.modules.get(bundleUrl))}`
844
+ );
845
+ }
846
+ return component;
847
+ }
848
+ /**
849
+ * Prewarm: load every plugin bundle in the background after app boot, so a
850
+ * later open is instant (in-memory hit) instead of round-tripping the
851
+ * network. Errors are swallowed per-plugin — one bad bundle shouldn't
852
+ * block others. Concurrency capped at 3.
853
+ */
854
+ async prewarmAll(items) {
855
+ const queue = [...items];
856
+ const concurrency = Math.min(3, queue.length);
857
+ const start = Date.now();
858
+ let okCount = 0;
859
+ let failCount = 0;
860
+ const worker = async () => {
861
+ while (queue.length > 0) {
862
+ const it = queue.shift();
863
+ if (!it) return;
864
+ try {
865
+ await this.load(it.pluginId, it.bundleUrl, it.version, it.bundleHash);
866
+ okCount++;
867
+ } catch (err) {
868
+ failCount++;
869
+ console.log(`[prewarm] ${it.pluginId}: ${err instanceof Error ? err.message : String(err)}`);
870
+ }
871
+ }
872
+ };
873
+ await Promise.all(Array.from({ length: concurrency }, worker));
874
+ console.log(`[prewarm] ${okCount} loaded, ${failCount} failed in ${Date.now() - start}ms`);
875
+ }
876
+ /**
877
+ * Clear all caches (in-memory + storage).
878
+ */
879
+ async clearAll() {
880
+ this.modules.clear();
881
+ try {
882
+ await getBundleStorage().clearAll();
883
+ } catch (err) {
884
+ console.warn("[BundleManager] clearAll error:", err);
885
+ }
886
+ }
887
+ /**
888
+ * Clear cache for a specific plugin/bundle.
889
+ */
890
+ async clearPlugin(pluginId) {
891
+ const storage = getBundleStorage();
892
+ const index = await storage.loadIndex();
893
+ const entry = index[pluginId];
894
+ if (entry) {
895
+ this.modules.delete(entry.bundleUrl);
896
+ delete index[pluginId];
897
+ await storage.saveIndex(index);
898
+ try {
899
+ await storage.deleteBundle(entry.localPath);
900
+ } catch {
901
+ }
902
+ }
903
+ }
904
+ // ── Private: module loading pipeline ────────────────────────
905
+ async loadModule(bundleUrl, version, expectedHash) {
906
+ if (this.modules.has(bundleUrl)) return;
907
+ const storage = getBundleStorage();
908
+ const index = await storage.loadIndex();
909
+ const expectedLc = expectedHash ? expectedHash.toLowerCase() : null;
910
+ let content = null;
911
+ for (const entry of Object.values(index)) {
912
+ if (entry.bundleUrl === bundleUrl && entry.version === version) {
913
+ const age = Date.now() - entry.timestamp;
914
+ const hashOk = expectedLc && entry.bundleHash && entry.bundleHash.toLowerCase() === expectedLc;
915
+ if (age < CACHE_TTL && hashOk) {
916
+ content = await storage.readBundle(entry.localPath);
917
+ if (content) break;
918
+ }
919
+ }
920
+ }
921
+ if (!content) {
922
+ const downloaded = await this.download(bundleUrl, expectedLc);
923
+ content = downloaded.content;
924
+ const safeName = bundleUrl.replace(/[^a-zA-Z0-9]/g, "_").slice(-80);
925
+ try {
926
+ const localPath = await storage.writeBundle(`${safeName}@${version}.js`, content);
927
+ index[bundleUrl] = {
928
+ localPath,
929
+ version,
930
+ timestamp: Date.now(),
931
+ bundleUrl,
932
+ bundleHash: downloaded.sha256
933
+ };
934
+ await storage.saveIndex(index);
935
+ } catch (err) {
936
+ console.warn("[BundleManager] Cache write error:", err);
937
+ }
938
+ }
939
+ const mod = this.evaluate(content, bundleUrl);
940
+ this.modules.set(bundleUrl, mod);
941
+ }
942
+ /**
943
+ * Download + integrity-verify a bundle. Refuses to return when:
944
+ * - manifest hash and computed hash disagree
945
+ * - server's `X-Bundle-SHA256` disagrees with manifest hash
946
+ * - no expected hash AND no server hash header (cannot prove the bundle
947
+ * wasn't tampered with — fail closed rather than trust the wire).
948
+ */
949
+ async download(bundleUrl, expectedHash) {
950
+ const cacheBust = `${bundleUrl}${bundleUrl.includes("?") ? "&" : "?"}t=${Date.now()}`;
951
+ const response = await (0, import_core2.apiFetchRaw)(cacheBust);
952
+ if (!response.ok) {
953
+ const body = await response.text().catch(() => "");
954
+ throw new Error(`Download failed: ${response.status} ${response.statusText} \u2014 ${body.substring(0, 200)}`);
955
+ }
956
+ const content = await response.text();
957
+ if (content.length < 50 || content.trimStart().startsWith("<!")) {
958
+ throw new Error("Bundle content is empty or HTML \u2014 server may have returned an error page");
959
+ }
960
+ const headerHash = (response.headers.get("x-bundle-sha256") || "").toLowerCase();
961
+ const computed = sha256Hex(content);
962
+ if (expectedHash) {
963
+ if (computed !== expectedHash) {
964
+ throw new Error(
965
+ `Bundle integrity FAIL: expected sha256=${expectedHash.slice(0, 12)}... got ${computed.slice(0, 12)}.... Refusing to evaluate.`
966
+ );
967
+ }
968
+ if (headerHash && headerHash !== expectedHash) {
969
+ throw new Error(
970
+ `Bundle hash mismatch: manifest=${expectedHash.slice(0, 12)}... server=${headerHash.slice(0, 12)}.... Refusing to evaluate.`
971
+ );
972
+ }
973
+ } else if (headerHash) {
974
+ if (computed !== headerHash) {
975
+ throw new Error(
976
+ `Bundle body sha256 (${computed.slice(0, 12)}...) does not match server's X-Bundle-SHA256 (${headerHash.slice(0, 12)}...).`
977
+ );
978
+ }
979
+ console.warn(`[BundleManager] No manifest bundleHash \u2014 verified via X-Bundle-SHA256 header only`);
980
+ } else {
981
+ throw new Error(
982
+ `No bundleHash in manifest and no X-Bundle-SHA256 header from server. Refusing to evaluate untrusted bundle.`
983
+ );
984
+ }
985
+ return { content, sha256: computed };
986
+ }
987
+ evaluate(content, bundleUrl) {
988
+ let cleaned = content.replace(
989
+ /__toESM\(require\(("[^"]+")\)(?:,\s*\d+)?\)/g,
990
+ "require($1)"
991
+ );
992
+ cleaned = cleaned.replace(
993
+ /module\.exports\s*=\s*__toCommonJS\((\w+)\)/g,
994
+ "module.exports = $1"
995
+ );
996
+ const mod = { exports: {} };
997
+ try {
998
+ const factory = new Function(
999
+ "module",
1000
+ "exports",
1001
+ "require",
1002
+ "__filename",
1003
+ "__dirname",
1004
+ cleaned
1005
+ );
1006
+ factory(mod, mod.exports, requireShim, bundleUrl, "adas-plugin-bundles");
1007
+ } catch (err) {
1008
+ throw new Error(`Bundle evaluation failed: ${err instanceof Error ? err.message : String(err)}`);
1009
+ }
1010
+ const raw = mod.exports;
1011
+ const materialized = {};
1012
+ for (const key of Object.getOwnPropertyNames(raw)) {
1013
+ try {
1014
+ materialized[key] = raw[key];
1015
+ } catch {
1016
+ }
1017
+ }
1018
+ return materialized;
1019
+ }
1020
+ // ── Private: component extraction ───────────────────────────
1021
+ /**
1022
+ * Find a plugin component in a loaded module.
1023
+ * Handles: default export, direct key match, multi-plugin .id match.
1024
+ */
1025
+ getComponentFromMemory(pluginId, bundleUrl) {
1026
+ const mod = this.modules.get(bundleUrl);
1027
+ if (!mod) return null;
1028
+ const shortName = pluginId.includes(":") ? pluginId.split(":").pop() : pluginId;
1029
+ if (mod[pluginId] && typeof mod[pluginId].Component === "function") {
1030
+ return mod[pluginId];
1031
+ }
1032
+ const pascal = shortName.replace(/(^|-)([a-z])/g, (_, __, c) => c.toUpperCase());
1033
+ if (mod[pascal] && typeof mod[pascal] === "object" && typeof mod[pascal].Component === "function") {
1034
+ return mod[pascal];
1035
+ }
1036
+ if (mod.default && typeof mod.default === "object" && typeof mod.default.Component === "function") {
1037
+ return mod.default;
1038
+ }
1039
+ for (const key of Object.keys(mod)) {
1040
+ const val = mod[key];
1041
+ if (val && typeof val === "object" && val.id === shortName && typeof val.Component === "function") {
1042
+ return val;
1043
+ }
1044
+ }
1045
+ return null;
1046
+ }
1047
+ describeModule(mod) {
1048
+ if (!mod) return "(empty)";
1049
+ return Object.keys(mod).map((k) => {
1050
+ const v = mod[k];
1051
+ if (v && typeof v === "object" && v.id) return `${k}(id="${v.id}")`;
1052
+ return k;
1053
+ }).join(", ");
1054
+ }
1055
+ };
1056
+ var bundleManager = new BundleManager();
1057
+
1058
+ // src/bridge/native.ts
1059
+ var import_react6 = require("react");
1060
+ var import_core3 = require("@ateam-ai-mobile/core");
1061
+ function buildContext(pluginId, connectorId) {
1062
+ const user = (0, import_core3.getUser)();
1063
+ return {
1064
+ tenant: (0, import_core3.getTenant)(),
1065
+ pluginId,
1066
+ connectorId,
1067
+ user: user ? { id: user.actorId || "", name: user.name || "", roles: [] } : void 0
1068
+ };
1069
+ }
1070
+ function useNativeBridge(pluginId, connectorId, commandBufferRef) {
1071
+ const initCallbackRef = (0, import_react6.useRef)(null);
1072
+ const commandListenersRef = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
1073
+ const initializedRef = (0, import_react6.useRef)(false);
1074
+ const fireInit = (0, import_react6.useCallback)(() => {
1075
+ if (initializedRef.current || !initCallbackRef.current) return;
1076
+ initCallbackRef.current(buildContext(pluginId, connectorId));
1077
+ initializedRef.current = true;
1078
+ }, [pluginId, connectorId]);
1079
+ const onInit = (0, import_react6.useCallback)((cb) => {
1080
+ initCallbackRef.current = cb;
1081
+ setTimeout(fireInit, 0);
1082
+ }, [fireInit]);
1083
+ const mcpCall = (0, import_react6.useCallback)(async (toolOrConnector, argsOrTool, cIdOrArgs) => {
1084
+ let tool;
1085
+ let args;
1086
+ let cId;
1087
+ if (typeof argsOrTool === "string") {
1088
+ cId = toolOrConnector;
1089
+ tool = argsOrTool;
1090
+ args = cIdOrArgs || {};
1091
+ } else {
1092
+ tool = toolOrConnector;
1093
+ args = argsOrTool;
1094
+ cId = typeof cIdOrArgs === "string" ? cIdOrArgs : void 0;
1095
+ }
1096
+ const targetConnector = cId || connectorId;
1097
+ if (!targetConnector) {
1098
+ console.warn(`[NativeBridge:${pluginId}] mcpCall failed \u2014 no connectorId. tool=${tool}`);
1099
+ throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);
1100
+ }
1101
+ try {
1102
+ const data = await (0, import_core3.connectorCall)(targetConnector, tool, args);
1103
+ if (!data.ok && data.error) {
1104
+ throw new Error(data.error);
1105
+ }
1106
+ return (0, import_core3.unwrapMcpResult)(data.result);
1107
+ } catch (err) {
1108
+ console.warn(`[NativeBridge:${pluginId}] mcpCall failed \u2192 connector=${targetConnector} tool=${tool}:`, err?.message || err);
1109
+ throw err;
1110
+ }
1111
+ }, [pluginId, connectorId]);
1112
+ const mcpFetch = (0, import_react6.useCallback)(async (body) => {
1113
+ return (0, import_core3.mcpFetch)(body);
1114
+ }, []);
1115
+ const sendCommand = (0, import_react6.useCallback)((type, payload) => {
1116
+ if (type === "plugin.command.result" && payload?.correlationId) {
1117
+ (0, import_core3.postCommandResult)(payload.correlationId, payload.result, payload.error);
1118
+ return;
1119
+ }
1120
+ }, [pluginId]);
1121
+ const onCommand = (0, import_react6.useCallback)((cb) => {
1122
+ commandListenersRef.current.add(cb);
1123
+ if (commandBufferRef) {
1124
+ const buf = commandBufferRef.current;
1125
+ const remaining = [];
1126
+ for (const cmd of buf) {
1127
+ if (cmd.pluginId === pluginId && cmd.command !== "__focus") {
1128
+ try {
1129
+ cb(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
1130
+ } catch {
1131
+ }
1132
+ } else {
1133
+ remaining.push(cmd);
1134
+ }
1135
+ }
1136
+ commandBufferRef.current = remaining;
1137
+ }
1138
+ for (const cmd of import_core3.pluginCommandEmitter.drainPluginCommands(pluginId)) {
1139
+ try {
1140
+ cb(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
1141
+ } catch {
1142
+ }
1143
+ }
1144
+ return () => {
1145
+ commandListenersRef.current.delete(cb);
1146
+ };
1147
+ }, [pluginId, commandBufferRef]);
1148
+ (0, import_react6.useEffect)(() => {
1149
+ const unsub = import_core3.pluginCommandEmitter.on("plugin-command", (cmd) => {
1150
+ if (cmd.pluginId !== pluginId) return;
1151
+ if (cmd.command === "__focus") return;
1152
+ commandListenersRef.current.forEach((fn) => {
1153
+ try {
1154
+ fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
1155
+ } catch {
1156
+ }
1157
+ });
1158
+ });
1159
+ return unsub;
1160
+ }, [pluginId]);
1161
+ (0, import_react6.useEffect)(() => {
1162
+ const timer = setTimeout(() => {
1163
+ const dispatch = (cmd) => {
1164
+ commandListenersRef.current.forEach((fn) => {
1165
+ try {
1166
+ fn(cmd.command, { ...cmd.args, correlationId: cmd.correlationId });
1167
+ } catch {
1168
+ }
1169
+ });
1170
+ };
1171
+ if (commandBufferRef) {
1172
+ const remaining = [];
1173
+ for (const cmd of commandBufferRef.current) {
1174
+ if (cmd.pluginId === pluginId && cmd.command !== "__focus") dispatch(cmd);
1175
+ else remaining.push(cmd);
1176
+ }
1177
+ commandBufferRef.current = remaining;
1178
+ }
1179
+ for (const cmd of import_core3.pluginCommandEmitter.drainPluginCommands(pluginId)) {
1180
+ dispatch(cmd);
1181
+ }
1182
+ }, 500);
1183
+ return () => clearTimeout(timer);
1184
+ }, [pluginId, commandBufferRef]);
1185
+ (0, import_react6.useEffect)(() => {
1186
+ return () => {
1187
+ commandListenersRef.current.clear();
1188
+ initializedRef.current = false;
1189
+ };
1190
+ }, []);
1191
+ const close = (0, import_react6.useCallback)(() => {
1192
+ import_core3.pluginCommandEmitter.emit("plugin-close", { pluginId });
1193
+ }, [pluginId]);
1194
+ const sendMessage = (0, import_react6.useCallback)((text) => {
1195
+ const t = (text || "").trim();
1196
+ if (!t) return;
1197
+ try {
1198
+ import_core3.useChatStore.getState().sendMessage(t);
1199
+ } catch (err) {
1200
+ console.warn("[bridge.sendMessage] failed:", err instanceof Error ? err.message : String(err));
1201
+ }
1202
+ }, []);
1203
+ const prepareMessage = (0, import_react6.useCallback)((text) => {
1204
+ const t = (text || "").trim();
1205
+ if (!t) return;
1206
+ import_core3.pluginCommandEmitter.emit("prepare-chat-message", { text: t });
1207
+ }, []);
1208
+ return (0, import_react6.useMemo)(
1209
+ () => ({ onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage }),
1210
+ [onInit, mcpCall, mcpFetch, sendCommand, onCommand, close, sendMessage, prepareMessage]
1211
+ );
1212
+ }
1213
+ function createNativeBridge(pluginId, connectorId) {
1214
+ const commandListeners = /* @__PURE__ */ new Set();
1215
+ return {
1216
+ onInit(cb) {
1217
+ setTimeout(() => {
1218
+ cb(buildContext(pluginId, connectorId));
1219
+ }, 0);
1220
+ },
1221
+ async mcpCall(tool, args, cId) {
1222
+ const targetConnector = cId || connectorId;
1223
+ if (!targetConnector) {
1224
+ throw new Error(`[NativeBridge:${pluginId}] mcpCall requires a connectorId`);
1225
+ }
1226
+ const data = await (0, import_core3.connectorCall)(targetConnector, tool, args);
1227
+ if (!data.ok && data.error) throw new Error(data.error);
1228
+ return (0, import_core3.unwrapMcpResult)(data.result);
1229
+ },
1230
+ async mcpFetch(body) {
1231
+ return (0, import_core3.mcpFetch)(body);
1232
+ },
1233
+ sendCommand(_type, _payload) {
1234
+ },
1235
+ onCommand(cb) {
1236
+ commandListeners.add(cb);
1237
+ return () => {
1238
+ commandListeners.delete(cb);
1239
+ };
1240
+ },
1241
+ close() {
1242
+ import_core3.pluginCommandEmitter.emit("plugin-close", { pluginId });
1243
+ },
1244
+ sendMessage(text) {
1245
+ const t = (text || "").trim();
1246
+ if (!t) return;
1247
+ try {
1248
+ import_core3.useChatStore.getState().sendMessage(t);
1249
+ } catch (err) {
1250
+ console.warn("[bridge.sendMessage] failed:", err instanceof Error ? err.message : String(err));
1251
+ }
1252
+ },
1253
+ prepareMessage(text) {
1254
+ const t = (text || "").trim();
1255
+ if (!t) return;
1256
+ import_core3.pluginCommandEmitter.emit("prepare-chat-message", { text: t });
1257
+ }
1258
+ };
1259
+ }
1260
+
1261
+ // src/hooks/usePlugin.ts
1262
+ var import_react7 = require("react");
1263
+ function extractBundleUrl(pluginId, manifest) {
1264
+ const render = manifest.render;
1265
+ if (!render || typeof render !== "object") return { url: null, source: "none" };
1266
+ const injected = manifest.bundleUrl || render.bundleUrl || render.reactNative?.bundleUrl || null;
1267
+ const hasNativeComponent = !!(render.reactNative?.component || render.component);
1268
+ if (hasNativeComponent) {
1269
+ return {
1270
+ url: `/api/ui-plugins/${encodeURIComponent(pluginId)}/bundle.js`,
1271
+ source: injected ? "ignored-explicit" : "derived-default",
1272
+ ...injected && { ignored: injected }
1273
+ };
1274
+ }
1275
+ return { url: null, source: "none" };
1276
+ }
1277
+ function extractBundleHash(manifest) {
1278
+ if (manifest.bundleHash) return manifest.bundleHash;
1279
+ const render = manifest.render;
1280
+ if (!render || typeof render !== "object") return void 0;
1281
+ if (render.bundleHash) return render.bundleHash;
1282
+ if (render.reactNative?.bundleHash) return render.reactNative.bundleHash;
1283
+ return void 0;
1284
+ }
1285
+ function extractComponentId(manifest) {
1286
+ const render = manifest.render;
1287
+ if (!render || typeof render !== "object") return null;
1288
+ return render.component || render.reactNative?.component || null;
1289
+ }
1290
+ function usePlugin(pluginId, manifest) {
1291
+ const [plugin, setPlugin] = (0, import_react7.useState)(null);
1292
+ const [loading, setLoading] = (0, import_react7.useState)(true);
1293
+ const [error, setError] = (0, import_react7.useState)(null);
1294
+ const [bundleMissing, setBundleMissing] = (0, import_react7.useState)(false);
1295
+ const version = manifest.version || "1.0.0";
1296
+ const { url: bundleUrl, ignored: ignoredUrl } = extractBundleUrl(pluginId, manifest);
1297
+ const bundleHash = extractBundleHash(manifest);
1298
+ const componentId = extractComponentId(manifest);
1299
+ const lookupId = componentId || pluginId;
1300
+ if (ignoredUrl) {
1301
+ console.warn(`[usePlugin] ${pluginId}: IGNORED connector-injected bundleUrl="${ignoredUrl}". The host derives bundle URLs from pluginId via the canonical route.`);
1302
+ }
1303
+ (0, import_react7.useEffect)(() => {
1304
+ let cancelled = false;
1305
+ (async () => {
1306
+ try {
1307
+ if (nativePluginRegistry.has(lookupId)) {
1308
+ const registered = await nativePluginRegistry.get(lookupId);
1309
+ if (cancelled) return;
1310
+ if (!registered) {
1311
+ throw new Error(`Local plugin not found: ${lookupId}`);
1312
+ }
1313
+ if (registered.type === "service") {
1314
+ throw new Error(`Plugin ${lookupId} is a service plugin and cannot be rendered`);
1315
+ }
1316
+ setPlugin(registered);
1317
+ setLoading(false);
1318
+ return;
1319
+ }
1320
+ if (bundleUrl) {
1321
+ try {
1322
+ const component = await bundleManager.load(pluginId, bundleUrl, version, bundleHash);
1323
+ if (cancelled) return;
1324
+ setPlugin(component);
1325
+ setLoading(false);
1326
+ return;
1327
+ } catch (bundleErr) {
1328
+ const msg = bundleErr instanceof Error ? bundleErr.message : String(bundleErr);
1329
+ console.warn(`[usePlugin] ${pluginId}: Bundle load failed, falling back to WebView:`, msg);
1330
+ if (!cancelled) {
1331
+ setBundleMissing(true);
1332
+ setLoading(false);
1333
+ }
1334
+ return;
1335
+ }
1336
+ }
1337
+ const iframeUrl = manifest?.render?.iframeUrl || manifest?.render?.mode === "adaptive" && manifest?.render?.iframe?.iframeUrl;
1338
+ if (iframeUrl) {
1339
+ if (!cancelled) {
1340
+ setBundleMissing(true);
1341
+ setLoading(false);
1342
+ }
1343
+ return;
1344
+ }
1345
+ throw new Error(
1346
+ `Plugin "${manifest.name || pluginId}" has no bundle URL and is not in the local registry. Check that the solution definition includes a valid render.reactNative.bundleUrl.`
1347
+ );
1348
+ } catch (err) {
1349
+ if (cancelled) return;
1350
+ const msg = err instanceof Error ? err.message : String(err);
1351
+ console.error(`[usePlugin] Failed to load ${pluginId}:`, msg);
1352
+ setError(msg);
1353
+ setLoading(false);
1354
+ }
1355
+ })();
1356
+ return () => {
1357
+ cancelled = true;
1358
+ };
1359
+ }, [pluginId, lookupId, bundleUrl, bundleHash, version]);
1360
+ return { plugin, loading, error, bundleMissing };
1361
+ }
1362
+
1363
+ // src/hooks/useRemotePlugins.ts
1364
+ var import_react8 = require("react");
1365
+ var import_core4 = require("@ateam-ai-mobile/core");
1366
+ function useRemotePlugins(solutionId) {
1367
+ const [plugins, setPlugins] = (0, import_react8.useState)([]);
1368
+ const [loading, setLoading] = (0, import_react8.useState)(true);
1369
+ const [refreshing, setRefreshing] = (0, import_react8.useState)(false);
1370
+ const [error, setError] = (0, import_react8.useState)(null);
1371
+ const fetchRemotePlugins = (0, import_react8.useCallback)(async () => {
1372
+ try {
1373
+ setError(null);
1374
+ const targetSolutionId = solutionId || "current";
1375
+ let data;
1376
+ try {
1377
+ data = await (0, import_core4.apiFetch)(`/api/solutions/${targetSolutionId}/ui-plugins`);
1378
+ } catch (err) {
1379
+ if (err?.message?.includes("404")) {
1380
+ console.warn(`[useRemotePlugins] Solution ${targetSolutionId} not found or has no plugins`);
1381
+ setPlugins([]);
1382
+ return;
1383
+ }
1384
+ throw err;
1385
+ }
1386
+ const uiPlugins = (data.plugins || []).map((plugin) => ({
1387
+ id: plugin.id,
1388
+ name: plugin.name,
1389
+ version: plugin.version || "1.0.0",
1390
+ source: "remote",
1391
+ manifest: {
1392
+ id: plugin.id,
1393
+ name: plugin.name,
1394
+ version: plugin.version || "1.0.0",
1395
+ type: "ui",
1396
+ description: plugin.description || "",
1397
+ capabilities: plugin.capabilities || {},
1398
+ channels: plugin.channels || ["default"],
1399
+ render: plugin.render && typeof plugin.render === "object" ? plugin.render : { mode: "react-native", component: plugin.name || plugin.id },
1400
+ entry_point: plugin.entry_point || plugin.name,
1401
+ sandbox: plugin.sandbox !== false,
1402
+ requires_auth: plugin.requires_auth !== false
1403
+ }
1404
+ }));
1405
+ setPlugins(uiPlugins);
1406
+ } catch (err) {
1407
+ const message = err instanceof Error ? err.message : String(err);
1408
+ console.error("[useRemotePlugins] Failed to fetch plugins:", message);
1409
+ setError(message);
1410
+ setPlugins([]);
1411
+ } finally {
1412
+ setLoading(false);
1413
+ setRefreshing(false);
1414
+ }
1415
+ }, [solutionId]);
1416
+ const refresh = (0, import_react8.useCallback)(async () => {
1417
+ setRefreshing(true);
1418
+ await fetchRemotePlugins();
1419
+ }, [fetchRemotePlugins]);
1420
+ (0, import_react8.useEffect)(() => {
1421
+ setLoading(true);
1422
+ fetchRemotePlugins();
1423
+ }, [fetchRemotePlugins]);
1424
+ return {
1425
+ plugins,
1426
+ loading,
1427
+ error,
1428
+ refreshing,
1429
+ refresh
1430
+ };
1431
+ }
1432
+
1433
+ // src/api/plugins.ts
1434
+ var import_core5 = require("@ateam-ai-mobile/core");
1435
+ var import_core6 = require("@ateam-ai-mobile/core");
1436
+ function supportsNative(manifest) {
1437
+ const mode = manifest.render?.mode;
1438
+ return mode === "react-native" || mode === "adaptive";
1439
+ }
1440
+ function getNativeComponentId(manifest) {
1441
+ if (manifest.render?.mode === "react-native") return manifest.render.component;
1442
+ if (manifest.render?.mode === "adaptive") return manifest.render.reactNative?.component;
1443
+ return null;
1444
+ }
1445
+ function getNativeBundleUrl(manifest) {
1446
+ const direct = manifest.bundleUrl;
1447
+ if (direct) return direct;
1448
+ const render = manifest.render;
1449
+ if (render.mode === "react-native") return render.bundleUrl || null;
1450
+ if (render.mode === "adaptive") return render.reactNative?.bundleUrl || null;
1451
+ return null;
1452
+ }
1453
+ function getNativeBundleHash(manifest) {
1454
+ const direct = manifest.bundleHash;
1455
+ if (direct) return direct;
1456
+ const render = manifest.render;
1457
+ if (render.mode === "react-native") return render.bundleHash || null;
1458
+ if (render.mode === "adaptive") return render.reactNative?.bundleHash || null;
1459
+ return null;
1460
+ }
1461
+ function supportsWebView(manifest) {
1462
+ return manifest.render?.mode === "iframe" || manifest.render?.mode === "adaptive";
1463
+ }
1464
+ async function listPlugins() {
1465
+ const res = await (0, import_core5.apiFetch)("/mcp", {
1466
+ method: "POST",
1467
+ body: JSON.stringify({
1468
+ jsonrpc: "2.0",
1469
+ id: Date.now(),
1470
+ method: "tools/call",
1471
+ params: {
1472
+ name: "cp.listContextPlugins",
1473
+ arguments: {}
1474
+ }
1475
+ })
1476
+ });
1477
+ const structured = res.result?.structuredContent?.plugins;
1478
+ if (structured) return structured;
1479
+ const text = res.result?.content?.[0]?.text;
1480
+ if (!text) return [];
1481
+ try {
1482
+ const parsed = JSON.parse(text);
1483
+ return parsed.plugins || parsed || [];
1484
+ } catch {
1485
+ return [];
1486
+ }
1487
+ }
1488
+ async function getPlugin(pluginId) {
1489
+ const res = await (0, import_core5.apiFetch)("/mcp", {
1490
+ method: "POST",
1491
+ body: JSON.stringify({
1492
+ jsonrpc: "2.0",
1493
+ id: Date.now(),
1494
+ method: "tools/call",
1495
+ params: {
1496
+ name: "cp.getContextPlugin",
1497
+ arguments: { id: pluginId }
1498
+ // Backend expects { id }, NOT { pluginId }
1499
+ }
1500
+ })
1501
+ });
1502
+ if (res.result?.structuredContent) return res.result.structuredContent;
1503
+ const text = res.result?.content?.[0]?.text;
1504
+ if (!text) return null;
1505
+ try {
1506
+ const parsed = JSON.parse(text);
1507
+ if (parsed.error) {
1508
+ console.warn("[getPlugin] Backend error:", parsed.error);
1509
+ return null;
1510
+ }
1511
+ return parsed;
1512
+ } catch {
1513
+ return null;
1514
+ }
1515
+ }
1516
+ function resolvePluginUrl(manifest, tenant) {
1517
+ const render = manifest.render;
1518
+ let url;
1519
+ if (render?.mode === "iframe") {
1520
+ url = render.iframeUrl;
1521
+ } else if (render?.mode === "adaptive") {
1522
+ url = render.iframeUrl || render.iframe?.iframeUrl;
1523
+ }
1524
+ if (!url) return "";
1525
+ if (url.startsWith("http")) {
1526
+ const sep = url.includes("?") ? "&" : "?";
1527
+ return tenant ? `${url}${sep}tenant=${encodeURIComponent(tenant)}` : url;
1528
+ }
1529
+ if (tenant && url.startsWith("/mcp-ui/")) {
1530
+ const tenantUrl = url.replace("/mcp-ui/", `/mcp-ui/${encodeURIComponent(tenant)}/`);
1531
+ return `${(0, import_core6.getCoreApiUrl)()}${tenantUrl}`;
1532
+ }
1533
+ return `${(0, import_core6.getCoreApiUrl)()}${url}`;
1534
+ }
1535
+
1536
+ // src/surfaces/SurfaceDrawer.tsx
1537
+ var import_react10 = require("react");
1538
+ var import_react_native4 = require("react-native");
1539
+ var import_react_native_svg2 = __toESM(require("react-native-svg"));
1540
+ var import_core7 = require("@ateam-ai-mobile/core");
1541
+
1542
+ // src/surfaces/AdaOrb.tsx
1543
+ var import_react9 = require("react");
1544
+ var import_react_native3 = require("react-native");
1545
+ var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
1546
+ var import_react_native_svg = __toESM(require("react-native-svg"));
1547
+ var import_jsx_runtime = require("react/jsx-runtime");
1548
+ var AnimatedCircle = import_react_native_reanimated.default.createAnimatedComponent(import_react_native_svg.Circle);
1549
+ function AdaOrb({ size = 120, state = "idle", inscription = true }) {
1550
+ const showInscription = inscription && size >= 60;
1551
+ const center = size / 2;
1552
+ const coreR = size * 0.32;
1553
+ const innerHaloR = size * 0.42;
1554
+ const outerHaloR = size * 0.5;
1555
+ const coreScale = (0, import_react_native_reanimated.useSharedValue)(1);
1556
+ const innerScale = (0, import_react_native_reanimated.useSharedValue)(1);
1557
+ const outerScale = (0, import_react_native_reanimated.useSharedValue)(1);
1558
+ const outerOpacity = (0, import_react_native_reanimated.useSharedValue)(0.55);
1559
+ const rippleCycle = (0, import_react_native_reanimated.useSharedValue)(0);
1560
+ const orbit1 = (0, import_react_native_reanimated.useSharedValue)(0);
1561
+ const orbit2 = (0, import_react_native_reanimated.useSharedValue)(0);
1562
+ const orbit3 = (0, import_react_native_reanimated.useSharedValue)(0);
1563
+ const beat = (0, import_react_native_reanimated.useSharedValue)(1);
1564
+ (0, import_react9.useEffect)(() => {
1565
+ (0, import_react_native_reanimated.cancelAnimation)(coreScale);
1566
+ (0, import_react_native_reanimated.cancelAnimation)(innerScale);
1567
+ (0, import_react_native_reanimated.cancelAnimation)(outerScale);
1568
+ (0, import_react_native_reanimated.cancelAnimation)(outerOpacity);
1569
+ (0, import_react_native_reanimated.cancelAnimation)(rippleCycle);
1570
+ (0, import_react_native_reanimated.cancelAnimation)(orbit1);
1571
+ (0, import_react_native_reanimated.cancelAnimation)(orbit2);
1572
+ (0, import_react_native_reanimated.cancelAnimation)(orbit3);
1573
+ (0, import_react_native_reanimated.cancelAnimation)(beat);
1574
+ rippleCycle.value = 0;
1575
+ orbit1.value = 0;
1576
+ orbit2.value = 0;
1577
+ orbit3.value = 0;
1578
+ beat.value = 1;
1579
+ let breathMs = 3600;
1580
+ let breathAmount = 0.025;
1581
+ if (state === "listening") {
1582
+ breathMs = 2e3;
1583
+ breathAmount = 0.05;
1584
+ rippleCycle.value = (0, import_react_native_reanimated.withRepeat)(
1585
+ (0, import_react_native_reanimated.withTiming)(1, { duration: 2e3, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.quad) }),
1586
+ -1,
1587
+ false
1588
+ );
1589
+ } else if (state === "thinking") {
1590
+ breathMs = 2400;
1591
+ breathAmount = 0.04;
1592
+ orbit1.value = (0, import_react_native_reanimated.withRepeat)(
1593
+ (0, import_react_native_reanimated.withTiming)(1, { duration: 1100, easing: import_react_native_reanimated.Easing.linear }),
1594
+ -1,
1595
+ false
1596
+ );
1597
+ orbit2.value = (0, import_react_native_reanimated.withRepeat)(
1598
+ (0, import_react_native_reanimated.withTiming)(1, { duration: 1900, easing: import_react_native_reanimated.Easing.linear }),
1599
+ -1,
1600
+ false
1601
+ );
1602
+ orbit3.value = (0, import_react_native_reanimated.withRepeat)(
1603
+ (0, import_react_native_reanimated.withTiming)(-1, { duration: 2700, easing: import_react_native_reanimated.Easing.linear }),
1604
+ -1,
1605
+ false
1606
+ );
1607
+ } else if (state === "speaking") {
1608
+ breathMs = 700;
1609
+ breathAmount = 0.13;
1610
+ beat.value = (0, import_react_native_reanimated.withRepeat)(
1611
+ (0, import_react_native_reanimated.withSequence)(
1612
+ (0, import_react_native_reanimated.withTiming)(1.08, { duration: 90, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.quad) }),
1613
+ (0, import_react_native_reanimated.withTiming)(1, { duration: 130, easing: import_react_native_reanimated.Easing.in(import_react_native_reanimated.Easing.quad) }),
1614
+ (0, import_react_native_reanimated.withTiming)(1.05, { duration: 80, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.quad) }),
1615
+ (0, import_react_native_reanimated.withTiming)(1, { duration: 200, easing: import_react_native_reanimated.Easing.in(import_react_native_reanimated.Easing.quad) }),
1616
+ (0, import_react_native_reanimated.withTiming)(1, { duration: 280 })
1617
+ ),
1618
+ -1,
1619
+ false
1620
+ );
1621
+ }
1622
+ const breathEasing = state === "speaking" ? import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) : import_react_native_reanimated.Easing.inOut(import_react_native_reanimated.Easing.sin);
1623
+ coreScale.value = (0, import_react_native_reanimated.withRepeat)(
1624
+ (0, import_react_native_reanimated.withSequence)(
1625
+ (0, import_react_native_reanimated.withTiming)(1 + breathAmount, { duration: breathMs, easing: breathEasing }),
1626
+ (0, import_react_native_reanimated.withTiming)(1, { duration: breathMs, easing: breathEasing })
1627
+ ),
1628
+ -1,
1629
+ false
1630
+ );
1631
+ innerScale.value = (0, import_react_native_reanimated.withRepeat)(
1632
+ (0, import_react_native_reanimated.withSequence)(
1633
+ (0, import_react_native_reanimated.withTiming)(1 + breathAmount * 1.4, { duration: breathMs * 1.15, easing: breathEasing }),
1634
+ (0, import_react_native_reanimated.withTiming)(1, { duration: breathMs * 1.15, easing: breathEasing })
1635
+ ),
1636
+ -1,
1637
+ false
1638
+ );
1639
+ outerScale.value = (0, import_react_native_reanimated.withRepeat)(
1640
+ (0, import_react_native_reanimated.withSequence)(
1641
+ (0, import_react_native_reanimated.withTiming)(1 + breathAmount * 1.8, { duration: breathMs * 1.3, easing: breathEasing }),
1642
+ (0, import_react_native_reanimated.withTiming)(1, { duration: breathMs * 1.3, easing: breathEasing })
1643
+ ),
1644
+ -1,
1645
+ false
1646
+ );
1647
+ outerOpacity.value = (0, import_react_native_reanimated.withRepeat)(
1648
+ (0, import_react_native_reanimated.withSequence)(
1649
+ (0, import_react_native_reanimated.withTiming)(state === "idle" ? 0.55 : 0.8, { duration: breathMs * 1.3, easing: breathEasing }),
1650
+ (0, import_react_native_reanimated.withTiming)(0.35, { duration: breathMs * 1.3, easing: breathEasing })
1651
+ ),
1652
+ -1,
1653
+ false
1654
+ );
1655
+ }, [state]);
1656
+ const coreProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
1657
+ r: coreR * coreScale.value * beat.value
1658
+ }));
1659
+ const innerProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
1660
+ r: innerHaloR * innerScale.value * beat.value
1661
+ }));
1662
+ const outerProps = (0, import_react_native_reanimated.useAnimatedProps)(() => ({
1663
+ r: outerHaloR * outerScale.value,
1664
+ opacity: outerOpacity.value
1665
+ }));
1666
+ const ripple1Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
1667
+ const t = rippleCycle.value;
1668
+ return {
1669
+ r: outerHaloR * (1 + t * 0.55),
1670
+ opacity: state === "listening" ? 0.55 * (1 - t) : 0
1671
+ };
1672
+ });
1673
+ const ripple2Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
1674
+ const t = (rippleCycle.value + 0.34) % 1;
1675
+ return {
1676
+ r: outerHaloR * (1 + t * 0.55),
1677
+ opacity: state === "listening" ? 0.45 * (1 - t) : 0
1678
+ };
1679
+ });
1680
+ const ripple3Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
1681
+ const t = (rippleCycle.value + 0.67) % 1;
1682
+ return {
1683
+ r: outerHaloR * (1 + t * 0.55),
1684
+ opacity: state === "listening" ? 0.35 * (1 - t) : 0
1685
+ };
1686
+ });
1687
+ const spark1Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
1688
+ const angle = orbit1.value * Math.PI * 2 - Math.PI / 2;
1689
+ const r = coreR * 0.55;
1690
+ return {
1691
+ cx: center + Math.cos(angle) * r,
1692
+ cy: center + Math.sin(angle) * r,
1693
+ opacity: state === "thinking" ? 1 : 0
1694
+ };
1695
+ });
1696
+ const spark2Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
1697
+ const angle = orbit2.value * Math.PI * 2 + Math.PI * 0.6;
1698
+ const r = coreR * 0.85;
1699
+ return {
1700
+ cx: center + Math.cos(angle) * r,
1701
+ cy: center + Math.sin(angle) * r,
1702
+ opacity: state === "thinking" ? 0.9 : 0
1703
+ };
1704
+ });
1705
+ const spark3Props = (0, import_react_native_reanimated.useAnimatedProps)(() => {
1706
+ const angle = orbit3.value * Math.PI * 2 + Math.PI * 1.3;
1707
+ const r = coreR * 1.05;
1708
+ return {
1709
+ cx: center + Math.cos(angle) * r,
1710
+ cy: center + Math.sin(angle) * r,
1711
+ opacity: state === "thinking" ? 0.7 : 0
1712
+ };
1713
+ });
1714
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native3.View, { style: [styles2.wrap, { width: size, height: size }], children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.default, { width: size, height: size, children: [
1715
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.Defs, { children: [
1716
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaCore", cx: "36%", cy: "30%", r: "70%", children: [
1717
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FFE0B0", stopOpacity: "1" }),
1718
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "28%", stopColor: "#FFA85A", stopOpacity: "1" }),
1719
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "65%", stopColor: "#FF7A28", stopOpacity: "1" }),
1720
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#B8410A", stopOpacity: "1" })
1721
+ ] }),
1722
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaInner", cx: "50%", cy: "50%", r: "50%", children: [
1723
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FF8A3C", stopOpacity: "0.55" }),
1724
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#FF7028", stopOpacity: "0" })
1725
+ ] }),
1726
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaOuter", cx: "50%", cy: "50%", r: "50%", children: [
1727
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FF7A28", stopOpacity: "0.4" }),
1728
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#FF6018", stopOpacity: "0" })
1729
+ ] }),
1730
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_svg.RadialGradient, { id: "adaSpark", cx: "50%", cy: "50%", r: "50%", children: [
1731
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "0%", stopColor: "#FFFAEB", stopOpacity: "1" }),
1732
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "60%", stopColor: "#FFD095", stopOpacity: "0.9" }),
1733
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.Stop, { offset: "100%", stopColor: "#FFA85A", stopOpacity: "0" })
1734
+ ] })
1735
+ ] }),
1736
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1737
+ AnimatedCircle,
1738
+ {
1739
+ cx: center,
1740
+ cy: center,
1741
+ stroke: "#FF7A28",
1742
+ strokeWidth: 1.5,
1743
+ fill: "none",
1744
+ animatedProps: ripple1Props
1745
+ }
1746
+ ),
1747
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1748
+ AnimatedCircle,
1749
+ {
1750
+ cx: center,
1751
+ cy: center,
1752
+ stroke: "#FF7A28",
1753
+ strokeWidth: 1.5,
1754
+ fill: "none",
1755
+ animatedProps: ripple2Props
1756
+ }
1757
+ ),
1758
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1759
+ AnimatedCircle,
1760
+ {
1761
+ cx: center,
1762
+ cy: center,
1763
+ stroke: "#FF7A28",
1764
+ strokeWidth: 1.5,
1765
+ fill: "none",
1766
+ animatedProps: ripple3Props
1767
+ }
1768
+ ),
1769
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedCircle, { cx: center, cy: center, fill: "url(#adaOuter)", animatedProps: outerProps }),
1770
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedCircle, { cx: center, cy: center, fill: "url(#adaInner)", animatedProps: innerProps }),
1771
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedCircle, { cx: center, cy: center, fill: "url(#adaCore)", animatedProps: coreProps }),
1772
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1773
+ AnimatedCircle,
1774
+ {
1775
+ r: Math.max(3, size * 0.05),
1776
+ fill: "url(#adaSpark)",
1777
+ animatedProps: spark1Props
1778
+ }
1779
+ ),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1781
+ AnimatedCircle,
1782
+ {
1783
+ r: Math.max(2.5, size * 0.04),
1784
+ fill: "url(#adaSpark)",
1785
+ animatedProps: spark2Props
1786
+ }
1787
+ ),
1788
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1789
+ AnimatedCircle,
1790
+ {
1791
+ r: Math.max(2, size * 0.032),
1792
+ fill: "url(#adaSpark)",
1793
+ animatedProps: spark3Props
1794
+ }
1795
+ ),
1796
+ showInscription && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1797
+ import_react_native_svg.Text,
1798
+ {
1799
+ x: center,
1800
+ y: center + size * 0.11,
1801
+ fontSize: size * 0.34,
1802
+ fontWeight: "600",
1803
+ fill: "#FFF5E0",
1804
+ textAnchor: "middle",
1805
+ letterSpacing: -size * 5e-3,
1806
+ children: "iA"
1807
+ }
1808
+ )
1809
+ ] }) });
1810
+ }
1811
+ var styles2 = import_react_native3.StyleSheet.create({
1812
+ wrap: {
1813
+ alignItems: "center",
1814
+ justifyContent: "center"
1815
+ }
1816
+ });
1817
+
1818
+ // src/surfaces/SurfaceDrawer.tsx
1819
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1820
+ var SCREEN_H = import_react_native4.Dimensions.get("window").height;
1821
+ var fontFam = import_react_native4.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1822
+ function SurfaceDrawer({
1823
+ visible,
1824
+ onClose,
1825
+ title,
1826
+ subtitle,
1827
+ privacy,
1828
+ showOrb = true,
1829
+ heightRatio = 0.85,
1830
+ children
1831
+ }) {
1832
+ const sheetH = Math.round(SCREEN_H * heightRatio);
1833
+ const fadeAnim = (0, import_react10.useRef)(new import_react_native4.Animated.Value(0)).current;
1834
+ const slideAnim = (0, import_react10.useRef)(new import_react_native4.Animated.Value(sheetH)).current;
1835
+ (0, import_react10.useEffect)(() => {
1836
+ if (visible) {
1837
+ import_react_native4.Animated.parallel([
1838
+ import_react_native4.Animated.timing(fadeAnim, { toValue: 1, duration: 220, useNativeDriver: true }),
1839
+ import_react_native4.Animated.spring(slideAnim, { toValue: 0, useNativeDriver: true, tension: 80, friction: 12 })
1840
+ ]).start();
1841
+ } else {
1842
+ fadeAnim.setValue(0);
1843
+ slideAnim.setValue(sheetH);
1844
+ }
1845
+ }, [visible]);
1846
+ const close = () => {
1847
+ import_react_native4.Animated.parallel([
1848
+ import_react_native4.Animated.timing(fadeAnim, { toValue: 0, duration: 160, useNativeDriver: true }),
1849
+ import_react_native4.Animated.timing(slideAnim, { toValue: sheetH, duration: 200, useNativeDriver: true })
1850
+ ]).start(() => onClose());
1851
+ };
1852
+ if (!visible) return null;
1853
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.Animated.View, { style: [styles3.overlay, { opacity: fadeAnim }], pointerEvents: "auto", children: [
1854
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Pressable, { style: import_react_native4.StyleSheet.absoluteFill, onPress: close }),
1855
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1856
+ import_react_native4.Animated.View,
1857
+ {
1858
+ style: [
1859
+ styles3.sheet,
1860
+ { height: sheetH, transform: [{ translateY: slideAnim }] }
1861
+ ],
1862
+ children: [
1863
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles3.handle }),
1864
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles3.header, children: [
1865
+ showOrb ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles3.headerOrb, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AdaOrb, { size: 36, state: "idle" }) }) : null,
1866
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: { flex: 1 }, children: [
1867
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles3.title, children: title }),
1868
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles3.subtitle, children: subtitle }) : null,
1869
+ privacy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles3.privacyPill, children: [
1870
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg2.default, { width: 11, height: 11, viewBox: "0 0 24 24", fill: "none", stroke: import_core7.ada.inkSoft, strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
1871
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M19 11H5a2 2 0 00-2 2v7a2 2 0 002 2h14a2 2 0 002-2v-7a2 2 0 00-2-2z" }),
1872
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M7 11V7a5 5 0 0110 0v4" })
1873
+ ] }),
1874
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles3.privacyText, children: "Only you can see this" })
1875
+ ] }) : null
1876
+ ] }),
1877
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1878
+ import_react_native4.Pressable,
1879
+ {
1880
+ accessibilityRole: "button",
1881
+ accessibilityLabel: "Close",
1882
+ style: styles3.closeBtn,
1883
+ onPress: close,
1884
+ hitSlop: 12,
1885
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: import_core7.ada.inkSoft, strokeWidth: 2.2, strokeLinecap: "round", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M18 6L6 18M6 6l12 12" }) })
1886
+ }
1887
+ )
1888
+ ] }),
1889
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles3.body, children })
1890
+ ]
1891
+ }
1892
+ )
1893
+ ] });
1894
+ }
1895
+ var styles3 = import_react_native4.StyleSheet.create({
1896
+ overlay: {
1897
+ position: "absolute",
1898
+ top: 0,
1899
+ left: 0,
1900
+ right: 0,
1901
+ bottom: 0,
1902
+ backgroundColor: "rgba(26, 20, 16, 0.35)",
1903
+ justifyContent: "flex-end",
1904
+ zIndex: 999,
1905
+ elevation: 999
1906
+ },
1907
+ sheet: {
1908
+ backgroundColor: import_core7.ada.paper,
1909
+ borderTopLeftRadius: 28,
1910
+ borderTopRightRadius: 28,
1911
+ overflow: "hidden"
1912
+ },
1913
+ handle: {
1914
+ width: 40,
1915
+ height: 4,
1916
+ borderRadius: 2,
1917
+ backgroundColor: import_core7.ada.inkMuted,
1918
+ opacity: 0.3,
1919
+ alignSelf: "center",
1920
+ marginTop: 10,
1921
+ marginBottom: 6
1922
+ },
1923
+ header: {
1924
+ flexDirection: "row",
1925
+ alignItems: "center",
1926
+ paddingHorizontal: 22,
1927
+ paddingVertical: 16,
1928
+ gap: 12,
1929
+ borderBottomWidth: 1,
1930
+ borderBottomColor: import_core7.ada.border
1931
+ },
1932
+ headerOrb: {
1933
+ width: 36,
1934
+ height: 36,
1935
+ alignItems: "center",
1936
+ justifyContent: "center"
1937
+ },
1938
+ title: {
1939
+ fontSize: 17,
1940
+ fontWeight: "600",
1941
+ color: import_core7.ada.ink,
1942
+ letterSpacing: -0.2,
1943
+ fontFamily: fontFam
1944
+ },
1945
+ subtitle: {
1946
+ fontSize: 13,
1947
+ fontWeight: "400",
1948
+ color: import_core7.ada.inkSoft,
1949
+ marginTop: 2,
1950
+ letterSpacing: -0.1,
1951
+ fontFamily: fontFam
1952
+ },
1953
+ privacyPill: {
1954
+ flexDirection: "row",
1955
+ alignItems: "center",
1956
+ gap: 5,
1957
+ marginTop: 4
1958
+ },
1959
+ privacyText: {
1960
+ fontSize: 11,
1961
+ fontWeight: "500",
1962
+ color: import_core7.ada.inkSoft,
1963
+ letterSpacing: 0.2,
1964
+ fontFamily: fontFam
1965
+ },
1966
+ closeBtn: {
1967
+ width: 32,
1968
+ height: 32,
1969
+ borderRadius: 16,
1970
+ backgroundColor: import_core7.ada.paperSoft,
1971
+ justifyContent: "center",
1972
+ alignItems: "center"
1973
+ },
1974
+ body: {
1975
+ flex: 1
1976
+ }
1977
+ });
1978
+
1979
+ // src/surfaces/SurfaceCard.tsx
1980
+ var import_react_native5 = require("react-native");
1981
+ var import_core8 = require("@ateam-ai-mobile/core");
1982
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1983
+ var fontFam2 = import_react_native5.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1984
+ function SurfaceCard({
1985
+ icon,
1986
+ title,
1987
+ subtitle,
1988
+ onPress,
1989
+ onLongPress,
1990
+ showArrow,
1991
+ children
1992
+ }) {
1993
+ const arrow = showArrow ?? !!onPress;
1994
+ const handlePress = () => {
1995
+ if (!onPress) return;
1996
+ getHaptics()?.impact("light");
1997
+ onPress();
1998
+ };
1999
+ const handleLongPress = () => {
2000
+ if (!onLongPress) return;
2001
+ getHaptics()?.impact("medium");
2002
+ onLongPress();
2003
+ };
2004
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2005
+ import_react_native5.Pressable,
2006
+ {
2007
+ accessibilityRole: "button",
2008
+ accessibilityLabel: [icon, title, subtitle].filter(Boolean).join(", "),
2009
+ accessibilityHint: onLongPress ? "Long-press for more options" : void 0,
2010
+ style: styles4.card,
2011
+ onPress: onPress ? handlePress : void 0,
2012
+ onLongPress: onLongPress ? handleLongPress : void 0,
2013
+ disabled: !onPress && !onLongPress,
2014
+ children: [
2015
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native5.View, { style: styles4.row, children: [
2016
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.icon, children: icon }) : null,
2017
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native5.View, { style: { flex: 1 }, children: [
2018
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.title, children: title }),
2019
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.subtitle, children: subtitle }) : null
2020
+ ] }),
2021
+ arrow ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Text, { style: styles4.arrow, children: "\u2192" }) : null
2022
+ ] }),
2023
+ children ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.View, { style: styles4.body, children }) : null
2024
+ ]
2025
+ }
2026
+ );
2027
+ }
2028
+ var styles4 = import_react_native5.StyleSheet.create({
2029
+ card: {
2030
+ backgroundColor: import_core8.ada.paperSoft,
2031
+ borderWidth: 1,
2032
+ borderColor: import_core8.ada.border,
2033
+ borderRadius: import_core8.borderRadius.xl,
2034
+ paddingHorizontal: 16,
2035
+ paddingVertical: 14
2036
+ },
2037
+ row: {
2038
+ flexDirection: "row",
2039
+ alignItems: "center",
2040
+ gap: 14
2041
+ },
2042
+ icon: {
2043
+ fontSize: 22
2044
+ },
2045
+ title: {
2046
+ fontSize: 15,
2047
+ fontWeight: "600",
2048
+ color: import_core8.ada.ink,
2049
+ letterSpacing: -0.2,
2050
+ fontFamily: fontFam2
2051
+ },
2052
+ subtitle: {
2053
+ fontSize: 13,
2054
+ fontWeight: "400",
2055
+ color: import_core8.ada.inkMuted,
2056
+ marginTop: 2,
2057
+ letterSpacing: -0.1,
2058
+ fontFamily: fontFam2
2059
+ },
2060
+ arrow: {
2061
+ fontSize: 18,
2062
+ color: import_core8.ada.inkMuted,
2063
+ fontWeight: "400"
2064
+ },
2065
+ body: {
2066
+ marginTop: 10,
2067
+ paddingTop: 10,
2068
+ borderTopWidth: 1,
2069
+ borderTopColor: import_core8.ada.border
2070
+ }
2071
+ });
2072
+
2073
+ // src/surfaces/SurfaceFullscreen.tsx
2074
+ var import_react11 = require("react");
2075
+ var import_react_native6 = require("react-native");
2076
+ var import_react_native_svg3 = __toESM(require("react-native-svg"));
2077
+ var import_core9 = require("@ateam-ai-mobile/core");
2078
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2079
+ var fontFam3 = import_react_native6.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
2080
+ function SurfaceFullscreen({
2081
+ visible,
2082
+ onClose,
2083
+ status,
2084
+ hero,
2085
+ children,
2086
+ showWordmark = true,
2087
+ closeIcon = "x",
2088
+ closeLabel = "Close"
2089
+ }) {
2090
+ const fadeAnim = (0, import_react11.useRef)(new import_react_native6.Animated.Value(0)).current;
2091
+ const heroScale = (0, import_react11.useRef)(new import_react_native6.Animated.Value(0.6)).current;
2092
+ (0, import_react11.useEffect)(() => {
2093
+ if (visible) {
2094
+ import_react_native6.Animated.parallel([
2095
+ import_react_native6.Animated.timing(fadeAnim, { toValue: 1, duration: 280, useNativeDriver: true }),
2096
+ import_react_native6.Animated.spring(heroScale, { toValue: 1, useNativeDriver: true, tension: 60, friction: 11 })
2097
+ ]).start();
2098
+ } else {
2099
+ fadeAnim.setValue(0);
2100
+ heroScale.setValue(0.6);
2101
+ }
2102
+ }, [visible]);
2103
+ const close = () => {
2104
+ import_react_native6.Animated.parallel([
2105
+ import_react_native6.Animated.timing(fadeAnim, { toValue: 0, duration: 180, useNativeDriver: true }),
2106
+ import_react_native6.Animated.timing(heroScale, { toValue: 0.6, duration: 180, useNativeDriver: true })
2107
+ ]).start(() => onClose());
2108
+ };
2109
+ if (!visible) return null;
2110
+ const renderCloseIcon = () => {
2111
+ if (closeIcon === "hangup") {
2112
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.default, { width: 22, height: 22, viewBox: "0 0 24 24", fill: import_core9.ada.paper, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.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" }) });
2113
+ }
2114
+ if (closeIcon === "x") {
2115
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.default, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: import_core9.ada.paper, strokeWidth: 2.5, strokeLinecap: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_svg3.Path, { d: "M18 6L6 18M6 6l12 12" }) });
2116
+ }
2117
+ return closeIcon;
2118
+ };
2119
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native6.Animated.View, { style: [styles5.overlay, { opacity: fadeAnim }], pointerEvents: "auto", children: [
2120
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native6.View, { style: styles5.topBar, children: [
2121
+ showWordmark ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Text, { style: styles5.wordmark, children: "ada" }) : null,
2122
+ status ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Text, { style: styles5.status, children: status }) : null
2123
+ ] }),
2124
+ hero ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.View, { style: styles5.heroWrap, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Animated.View, { style: { transform: [{ scale: heroScale }] }, children: hero }) }) : null,
2125
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.View, { style: styles5.body, children }),
2126
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native6.View, { style: styles5.bottomBar, children: [
2127
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2128
+ import_react_native6.Pressable,
2129
+ {
2130
+ accessibilityRole: "button",
2131
+ accessibilityLabel: closeLabel,
2132
+ style: styles5.closeBtn,
2133
+ onPress: close,
2134
+ hitSlop: 12,
2135
+ children: renderCloseIcon()
2136
+ }
2137
+ ),
2138
+ closeLabel ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.Text, { style: styles5.closeLabel, children: closeLabel }) : null
2139
+ ] })
2140
+ ] });
2141
+ }
2142
+ var styles5 = import_react_native6.StyleSheet.create({
2143
+ overlay: {
2144
+ position: "absolute",
2145
+ top: 0,
2146
+ left: 0,
2147
+ right: 0,
2148
+ bottom: 0,
2149
+ backgroundColor: import_core9.ada.paper,
2150
+ zIndex: 1e3,
2151
+ elevation: 1e3
2152
+ },
2153
+ topBar: {
2154
+ paddingTop: import_react_native6.Platform.OS === "ios" ? 64 : 36,
2155
+ paddingHorizontal: 24,
2156
+ alignItems: "center",
2157
+ gap: 6
2158
+ },
2159
+ wordmark: {
2160
+ fontSize: 14,
2161
+ fontFamily: fontFam3,
2162
+ fontWeight: "500",
2163
+ color: import_core9.ada.inkMuted,
2164
+ letterSpacing: 4
2165
+ },
2166
+ status: {
2167
+ fontSize: 17,
2168
+ fontFamily: fontFam3,
2169
+ fontWeight: "500",
2170
+ color: import_core9.ada.ink,
2171
+ letterSpacing: -0.2
2172
+ },
2173
+ heroWrap: {
2174
+ paddingTop: 24,
2175
+ paddingBottom: 12,
2176
+ alignItems: "center",
2177
+ justifyContent: "center"
2178
+ },
2179
+ body: {
2180
+ flex: 1
2181
+ },
2182
+ bottomBar: {
2183
+ paddingBottom: import_react_native6.Platform.OS === "ios" ? 48 : 32,
2184
+ paddingTop: 12,
2185
+ alignItems: "center",
2186
+ gap: 8
2187
+ },
2188
+ closeBtn: {
2189
+ width: 64,
2190
+ height: 64,
2191
+ borderRadius: 32,
2192
+ backgroundColor: import_core9.ada.ink,
2193
+ justifyContent: "center",
2194
+ alignItems: "center",
2195
+ shadowColor: import_core9.ada.ink,
2196
+ shadowOffset: { width: 0, height: 8 },
2197
+ shadowOpacity: 0.18,
2198
+ shadowRadius: 14,
2199
+ elevation: 8
2200
+ },
2201
+ closeLabel: {
2202
+ fontSize: 13,
2203
+ fontFamily: fontFam3,
2204
+ fontWeight: "500",
2205
+ color: import_core9.ada.inkMuted,
2206
+ letterSpacing: 0.3
2207
+ }
2208
+ });
2209
+
2210
+ // src/registry/store.ts
2211
+ var import_zustand = require("zustand");
2212
+ var useSurfaceStore = (0, import_zustand.create)((set, get) => ({
2213
+ manifests: {},
2214
+ activeDrawer: null,
2215
+ activeFullscreen: null,
2216
+ activeProps: {},
2217
+ mountKey: 0,
2218
+ register: (manifest) => set((s) => ({ manifests: { ...s.manifests, [manifest.id]: manifest } })),
2219
+ unregister: (id) => set((s) => {
2220
+ const next = { ...s.manifests };
2221
+ delete next[id];
2222
+ const nextProps = { ...s.activeProps };
2223
+ delete nextProps[id];
2224
+ return { manifests: next, activeProps: nextProps };
2225
+ }),
2226
+ show: (id, props) => {
2227
+ const m = get().manifests[id];
2228
+ if (!m) {
2229
+ console.warn("[SurfaceStore] show: unknown surface id", id);
2230
+ return;
2231
+ }
2232
+ set((s) => {
2233
+ const nextProps = props !== void 0 ? { ...s.activeProps, [id]: props } : s.activeProps;
2234
+ const mountKey = s.mountKey + 1;
2235
+ if (m.type === "drawer") return { activeDrawer: id, activeProps: nextProps, mountKey };
2236
+ if (m.type === "fullscreen") return { activeFullscreen: id, activeProps: nextProps, mountKey };
2237
+ return { mountKey };
2238
+ });
2239
+ },
2240
+ hide: (id) => {
2241
+ const s = get();
2242
+ if (!id) {
2243
+ const cleanup2 = { ...s.activeProps };
2244
+ if (s.activeDrawer) delete cleanup2[s.activeDrawer];
2245
+ if (s.activeFullscreen) delete cleanup2[s.activeFullscreen];
2246
+ set({ activeDrawer: null, activeFullscreen: null, activeProps: cleanup2 });
2247
+ return;
2248
+ }
2249
+ const cleanup = { ...s.activeProps };
2250
+ delete cleanup[id];
2251
+ const patch = { activeProps: cleanup };
2252
+ if (s.activeDrawer === id) patch.activeDrawer = null;
2253
+ if (s.activeFullscreen === id) patch.activeFullscreen = null;
2254
+ set(patch);
2255
+ },
2256
+ list: (filter) => {
2257
+ const all = Object.values(get().manifests);
2258
+ return all.filter((m) => {
2259
+ if (filter?.type && m.type !== filter.type) return false;
2260
+ if (filter?.visibility && !filter.visibility.includes(m.visibility)) return false;
2261
+ if (filter?.placement) {
2262
+ if (filter.placement === "unset") {
2263
+ if (m.placement) return false;
2264
+ } else if (m.placement !== filter.placement) {
2265
+ return false;
2266
+ }
2267
+ }
2268
+ return true;
2269
+ });
2270
+ }
2271
+ }));
2272
+ function isMountSurface(m) {
2273
+ return m.type === "drawer" || m.type === "fullscreen";
2274
+ }
2275
+ function isInlineSurface(m) {
2276
+ return m.type === "card" || m.type === "header" || m.type === "ambient" || m.type === "nudge";
2277
+ }
2278
+
2279
+ // src/registry/SurfaceDispatcher.tsx
2280
+ var import_react12 = require("react");
2281
+ var import_core10 = require("@ateam-ai-mobile/core");
2282
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2283
+ function SurfaceDispatcher() {
2284
+ const manifests = useSurfaceStore((s) => s.manifests);
2285
+ const activeDrawer = useSurfaceStore((s) => s.activeDrawer);
2286
+ const activeFullscreen = useSurfaceStore((s) => s.activeFullscreen);
2287
+ const activeProps = useSurfaceStore((s) => s.activeProps);
2288
+ const mountKey = useSurfaceStore((s) => s.mountKey);
2289
+ const hide = useSurfaceStore((s) => s.hide);
2290
+ (0, import_react12.useEffect)(() => {
2291
+ const unsub = import_core10.pluginCommandEmitter.on("plugin-close", ({ pluginId } = {}) => {
2292
+ if (!pluginId) return;
2293
+ const s = useSurfaceStore.getState();
2294
+ if (s.activeDrawer === pluginId || s.activeFullscreen === pluginId) {
2295
+ s.hide(pluginId);
2296
+ }
2297
+ });
2298
+ return unsub;
2299
+ }, []);
2300
+ const drawer = activeDrawer ? manifests[activeDrawer] : null;
2301
+ const fullscreen = activeFullscreen ? manifests[activeFullscreen] : null;
2302
+ const drawerProps = activeDrawer ? activeProps[activeDrawer] : void 0;
2303
+ const fullscreenProps = activeFullscreen ? activeProps[activeFullscreen] : void 0;
2304
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2305
+ drawer && drawer.type === "drawer" && drawer.Component ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2306
+ drawer.Component,
2307
+ {
2308
+ dismiss: () => hide(drawer.id),
2309
+ props: drawerProps
2310
+ },
2311
+ `drawer-${drawer.id}-${mountKey}`
2312
+ ) : null,
2313
+ fullscreen && fullscreen.type === "fullscreen" && fullscreen.Component ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2314
+ fullscreen.Component,
2315
+ {
2316
+ dismiss: () => hide(fullscreen.id),
2317
+ props: fullscreenProps
2318
+ },
2319
+ `fullscreen-${fullscreen.id}-${mountKey}`
2320
+ ) : null
2321
+ ] });
2322
+ }
2323
+ // Annotate the CommonJS export names for ESM import in node:
2324
+ 0 && (module.exports = {
2325
+ ActionButton,
2326
+ ActivityIndicator,
2327
+ AdaOrb,
2328
+ Animated,
2329
+ Badge,
2330
+ Card,
2331
+ EmptyState,
2332
+ ErrorState,
2333
+ FlatList,
2334
+ Image,
2335
+ ListItem,
2336
+ LoadingState,
2337
+ MemoryBundleStorage,
2338
+ Modal,
2339
+ Platform,
2340
+ PluginSDK,
2341
+ Pressable,
2342
+ RefreshControl,
2343
+ ScrollView,
2344
+ SearchBar,
2345
+ SectionList,
2346
+ StyleSheet,
2347
+ SurfaceCard,
2348
+ SurfaceDispatcher,
2349
+ SurfaceDrawer,
2350
+ SurfaceFullscreen,
2351
+ Switch,
2352
+ TabBar,
2353
+ Text,
2354
+ TextInput,
2355
+ TouchableOpacity,
2356
+ View,
2357
+ bundleManager,
2358
+ createNativeBridge,
2359
+ getHaptics,
2360
+ getNativeBundleHash,
2361
+ getNativeBundleUrl,
2362
+ getNativeComponentId,
2363
+ getPlugin,
2364
+ getPluginNative,
2365
+ isInlineSurface,
2366
+ isMountSurface,
2367
+ listPlugins,
2368
+ nativePluginRegistry,
2369
+ register,
2370
+ registerBundleModules,
2371
+ registerNativePlugin,
2372
+ registerService,
2373
+ resolvePluginUrl,
2374
+ setBundleStorage,
2375
+ setHapticsProvider,
2376
+ setPluginNativeProvider,
2377
+ setPluginThemeColors,
2378
+ supportsNative,
2379
+ supportsWebView,
2380
+ unregisterNativePlugin,
2381
+ useApi,
2382
+ useNativeBridge,
2383
+ usePlugin,
2384
+ usePluginTheme,
2385
+ useRemotePlugins,
2386
+ useSurfaceStore
2387
+ });
2388
+ //# sourceMappingURL=index.js.map