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