@ateam-ai-mobile/plugin-runtime 0.1.4 → 0.1.7
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-PKDQLNBL.mjs +2873 -0
- package/dist/chunk-PKDQLNBL.mjs.map +1 -0
- package/dist/index.d.mts +1759 -8
- package/dist/index.d.ts +1759 -8
- package/dist/index.js +2467 -1321
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +335 -2139
- package/dist/index.mjs.map +1 -1
- package/dist/loader-5LUVXUY2.mjs +9 -0
- package/dist/loader-5LUVXUY2.mjs.map +1 -0
- package/package.json +2 -2
- package/src/bundles/bundleManager.ts +368 -27
- package/src/bundles/integrity.ts +29 -0
- package/src/bundles/storage.ts +40 -0
- package/src/deviceStateHost.ts +197 -0
- package/src/hooks/usePlugin.ts +1 -1
- package/src/host.ts +80 -8
- package/src/index.ts +90 -1
- package/src/pluginRuntime.ts +97 -0
- package/src/sdk/CameraPreview.tsx +94 -0
- package/src/sdk/device-state.ts +1225 -0
- package/src/sdk/index.ts +35 -3
- package/src/sdk/registration.ts +39 -0
- package/src/sdk/types.ts +345 -8
- package/src/sdk/voice.ts +148 -0
- package/src/tools/loader.ts +167 -0
- package/src/tools/platformTools.ts +41 -0
- package/src/tools/registry.ts +183 -0
- package/src/tools/serverCalls.ts +78 -0
- package/src/tools/sessionSync.ts +107 -0
- package/src/voiceHost.ts +126 -0
package/dist/index.mjs
CHANGED
|
@@ -1,2071 +1,338 @@
|
|
|
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
|
+
getCameraPreviewProvider,
|
|
45
|
+
getHaptics,
|
|
46
|
+
getNativeBundleHash,
|
|
47
|
+
getNativeBundleUrl,
|
|
48
|
+
getNativeComponentId,
|
|
49
|
+
getPlugin,
|
|
50
|
+
getPluginNative,
|
|
51
|
+
hasDeviceTool,
|
|
52
|
+
implementedStateDomains,
|
|
53
|
+
isInlineSurface,
|
|
54
|
+
isMountSurface,
|
|
55
|
+
listDeviceTools,
|
|
56
|
+
listPlugins,
|
|
57
|
+
nativePluginRegistry,
|
|
58
|
+
register,
|
|
59
|
+
registerBundleModules,
|
|
60
|
+
registerDeviceTools,
|
|
61
|
+
registerNativePlugin,
|
|
62
|
+
registerService,
|
|
63
|
+
registerTools,
|
|
64
|
+
resetDeviceToolLoader,
|
|
65
|
+
resolvePluginUrl,
|
|
66
|
+
setBundleStorage,
|
|
67
|
+
setCameraPreviewProvider,
|
|
68
|
+
setDeviceStateProvider,
|
|
69
|
+
setDeviceToolContextProvider,
|
|
70
|
+
setHapticsProvider,
|
|
71
|
+
setPluginNativeProvider,
|
|
72
|
+
setPluginThemeColors,
|
|
73
|
+
supportsNative,
|
|
74
|
+
supportsWebView,
|
|
75
|
+
unregisterDeviceTools,
|
|
76
|
+
unregisterNativePlugin,
|
|
77
|
+
useApi,
|
|
78
|
+
useNativeBridge,
|
|
79
|
+
usePluginTheme,
|
|
80
|
+
useSurfaceStore
|
|
81
|
+
} from "./chunk-PKDQLNBL.mjs";
|
|
82
82
|
|
|
83
|
-
// src/sdk/
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
borderColor: theme.colors.border
|
|
99
|
-
},
|
|
100
|
-
style
|
|
101
|
-
];
|
|
102
|
-
if (onPress) {
|
|
103
|
-
return React.createElement(Pressable2, { style: cardStyle, onPress }, children);
|
|
83
|
+
// src/sdk/device-state.ts
|
|
84
|
+
var device_state_exports = {};
|
|
85
|
+
__export(device_state_exports, {
|
|
86
|
+
DeviceBridgeError: () => DeviceBridgeError,
|
|
87
|
+
explainCapability: () => explainCapability,
|
|
88
|
+
isActionable: () => isActionable,
|
|
89
|
+
neverObserved: () => neverObserved
|
|
90
|
+
});
|
|
91
|
+
var DeviceBridgeError = class extends Error {
|
|
92
|
+
constructor(code, message, opts) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.name = "DeviceBridgeError";
|
|
95
|
+
this.code = code;
|
|
96
|
+
this.domain = opts?.domain;
|
|
97
|
+
this.recoverable = opts?.recoverable;
|
|
104
98
|
}
|
|
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
99
|
};
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
function
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
);
|
|
100
|
+
var CONFIDENCE_ORDER = {
|
|
101
|
+
unknown: 0,
|
|
102
|
+
low: 1,
|
|
103
|
+
medium: 2,
|
|
104
|
+
high: 3
|
|
105
|
+
};
|
|
106
|
+
function isActionable(quality, budget) {
|
|
107
|
+
const { freshness, confidence } = quality;
|
|
108
|
+
if (freshness.state === "unknown" || freshness.state === "stale") return false;
|
|
109
|
+
if (freshness.ageMs === null || freshness.ageMs > budget.maxAgeMs) return false;
|
|
110
|
+
if (budget.minConfidence) {
|
|
111
|
+
const have = CONFIDENCE_ORDER[confidence?.level ?? "unknown"];
|
|
112
|
+
if (have < CONFIDENCE_ORDER[budget.minConfidence]) return false;
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
function neverObserved() {
|
|
117
|
+
return { state: "unknown", observedAt: null, ageMs: null };
|
|
118
|
+
}
|
|
119
|
+
function explainCapability(status) {
|
|
120
|
+
if (status.support === "unsupported") return "this device does not have it";
|
|
121
|
+
if (status.permission === "denied") return "permission was denied";
|
|
122
|
+
if (status.permission === "restricted") return "permission is restricted";
|
|
123
|
+
if (status.permission === "notDetermined") return "permission has not been asked for yet";
|
|
124
|
+
if (status.permission === "limited") return "only limited access was granted";
|
|
125
|
+
if (status.restriction === "policyRestricted") return "this plugin did not declare it";
|
|
126
|
+
if (status.restriction === "backgroundRestricted") return "the app is in the background";
|
|
127
|
+
if (status.restriction === "lowPowerRestricted") return "the device is in low-power mode";
|
|
128
|
+
if (status.availability === "busy") return "it is in use by something else";
|
|
129
|
+
if (status.availability === "temporarilyUnavailable") return "it is temporarily unavailable";
|
|
130
|
+
if (status.availability === "unavailable") return "it is unavailable";
|
|
131
|
+
if (status.support === "unknown" || status.availability === "unknown") {
|
|
132
|
+
return "its state could not be determined";
|
|
189
133
|
}
|
|
190
|
-
return
|
|
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
|
-
);
|
|
134
|
+
return null;
|
|
271
135
|
}
|
|
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
|
-
}
|
|
342
|
-
});
|
|
343
136
|
|
|
344
|
-
// src/
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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);
|
|
137
|
+
// src/voiceHost.ts
|
|
138
|
+
var _provider = null;
|
|
139
|
+
function setVoiceProvider(provider) {
|
|
140
|
+
_provider = provider || null;
|
|
141
|
+
}
|
|
142
|
+
function implementedVoice() {
|
|
143
|
+
return !!_provider;
|
|
144
|
+
}
|
|
145
|
+
function voiceDenial(why) {
|
|
146
|
+
const err = new Error(`voice: ${why}`);
|
|
147
|
+
err.code = "RESTRICTED";
|
|
148
|
+
return err;
|
|
149
|
+
}
|
|
150
|
+
function deniedVoice(why) {
|
|
151
|
+
const fail = () => {
|
|
152
|
+
throw voiceDenial(why);
|
|
380
153
|
};
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
|
154
|
+
return {
|
|
155
|
+
async start() {
|
|
156
|
+
return fail();
|
|
396
157
|
},
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
sm: fontSize.sm,
|
|
400
|
-
md: fontSize.md,
|
|
401
|
-
lg: fontSize.lg,
|
|
402
|
-
xl: fontSize.xl
|
|
158
|
+
stop() {
|
|
159
|
+
fail();
|
|
403
160
|
},
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
md: borderRadius.md,
|
|
407
|
-
lg: borderRadius.lg,
|
|
408
|
-
full: borderRadius.full
|
|
161
|
+
setMuted() {
|
|
162
|
+
fail();
|
|
409
163
|
},
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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`);
|
|
164
|
+
prompt() {
|
|
165
|
+
fail();
|
|
166
|
+
},
|
|
167
|
+
observe() {
|
|
168
|
+
fail();
|
|
169
|
+
},
|
|
170
|
+
getSnapshot() {
|
|
171
|
+
return {
|
|
172
|
+
state: "error",
|
|
173
|
+
sessionId: null,
|
|
174
|
+
muted: false,
|
|
175
|
+
speaking: false,
|
|
176
|
+
listening: false,
|
|
177
|
+
userSpeaking: false,
|
|
178
|
+
lastUserSpeechEndedAt: null,
|
|
179
|
+
lastError: why
|
|
493
180
|
};
|
|
181
|
+
},
|
|
182
|
+
subscribe() {
|
|
183
|
+
return fail();
|
|
184
|
+
},
|
|
185
|
+
transcript() {
|
|
186
|
+
return [];
|
|
494
187
|
}
|
|
495
|
-
}
|
|
188
|
+
};
|
|
496
189
|
}
|
|
497
|
-
function
|
|
498
|
-
const caps = declared || {};
|
|
190
|
+
function scopedVoice(provider, pluginId) {
|
|
499
191
|
return {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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")
|
|
192
|
+
start: (opts) => provider.start(opts, pluginId),
|
|
193
|
+
stop: () => provider.stop(pluginId),
|
|
194
|
+
setMuted: (muted) => provider.setMuted(muted, pluginId),
|
|
195
|
+
prompt: (input) => provider.prompt(input, pluginId),
|
|
196
|
+
observe: (text) => provider.observe(text, pluginId),
|
|
197
|
+
getSnapshot: () => provider.getSnapshot(pluginId),
|
|
198
|
+
subscribe: (cb) => provider.subscribe(cb, pluginId),
|
|
199
|
+
transcript: () => provider.transcript(pluginId)
|
|
513
200
|
};
|
|
514
201
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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;
|
|
538
|
-
}
|
|
539
|
-
};
|
|
540
|
-
var _bundleModules = /* @__PURE__ */ new Map();
|
|
541
|
-
function registerBundleModules(modules) {
|
|
542
|
-
for (const [name, mod] of Object.entries(modules)) {
|
|
543
|
-
_bundleModules.set(name, mod);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
function resolveBundleModule(name) {
|
|
547
|
-
return _bundleModules.get(name);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// src/bundles/bundleManager.ts
|
|
551
|
-
import React2 from "react";
|
|
552
|
-
import {
|
|
553
|
-
useState,
|
|
554
|
-
useEffect as useEffect5,
|
|
555
|
-
useCallback,
|
|
556
|
-
useMemo as useMemo3,
|
|
557
|
-
useRef as useRef3,
|
|
558
|
-
useContext,
|
|
559
|
-
useReducer,
|
|
560
|
-
useLayoutEffect,
|
|
561
|
-
useImperativeHandle,
|
|
562
|
-
useDebugValue
|
|
563
|
-
} from "react";
|
|
564
|
-
import * as ReactNative from "react-native";
|
|
565
|
-
import { apiFetchRaw } from "@ateam-ai-mobile/core";
|
|
566
|
-
|
|
567
|
-
// src/surfaces/SurfaceDrawer.tsx
|
|
568
|
-
import { useEffect as useEffect2, useRef } from "react";
|
|
569
|
-
import {
|
|
570
|
-
View as View4,
|
|
571
|
-
Text as Text3,
|
|
572
|
-
Pressable as Pressable3,
|
|
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
|
|
202
|
+
function gateVoice(declared, pluginId) {
|
|
203
|
+
if (!declared) {
|
|
204
|
+
return deniedVoice(
|
|
205
|
+
"not declared in this plugin's capabilities. Add `capabilities: { voice: true }` to use it."
|
|
685
206
|
);
|
|
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"
|
|
862
207
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
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
|
-
] });
|
|
941
|
-
}
|
|
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
|
|
208
|
+
if (!pluginId) {
|
|
209
|
+
return deniedVoice(
|
|
210
|
+
"no plugin identity \u2014 voice fails closed without a caller to scope the session to."
|
|
211
|
+
);
|
|
1023
212
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
// src/surfaces/SurfaceCard.tsx
|
|
1027
|
-
import {
|
|
1028
|
-
View as View5,
|
|
1029
|
-
Text as Text4,
|
|
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,
|
|
1059
|
-
{
|
|
1060
|
-
accessibilityRole: "button",
|
|
1061
|
-
accessibilityLabel: [icon, title, subtitle].filter(Boolean).join(", "),
|
|
1062
|
-
accessibilityHint: onLongPress ? "Long-press for more options" : void 0,
|
|
1063
|
-
style: styles4.card,
|
|
1064
|
-
onPress: onPress ? handlePress : void 0,
|
|
1065
|
-
onLongPress: onLongPress ? handleLongPress : void 0,
|
|
1066
|
-
disabled: !onPress && !onLongPress,
|
|
1067
|
-
children: [
|
|
1068
|
-
/* @__PURE__ */ jsxs3(View5, { style: styles4.row, children: [
|
|
1069
|
-
icon ? /* @__PURE__ */ jsx3(Text4, { style: styles4.icon, children: icon }) : null,
|
|
1070
|
-
/* @__PURE__ */ jsxs3(View5, { style: { flex: 1 }, children: [
|
|
1071
|
-
/* @__PURE__ */ jsx3(Text4, { style: styles4.title, children: title }),
|
|
1072
|
-
subtitle ? /* @__PURE__ */ jsx3(Text4, { style: styles4.subtitle, children: subtitle }) : null
|
|
1073
|
-
] }),
|
|
1074
|
-
arrow ? /* @__PURE__ */ jsx3(Text4, { style: styles4.arrow, children: "\u2192" }) : null
|
|
1075
|
-
] }),
|
|
1076
|
-
children ? /* @__PURE__ */ jsx3(View5, { style: styles4.body, children }) : null
|
|
1077
|
-
]
|
|
1078
|
-
}
|
|
213
|
+
return _provider ? scopedVoice(_provider, pluginId) : deniedVoice(
|
|
214
|
+
"no voice session in this build \u2014 the app has not mounted a VoiceSessionHost / called setVoiceProvider."
|
|
1079
215
|
);
|
|
1080
216
|
}
|
|
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
217
|
|
|
1126
|
-
// src/
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
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
|
-
] });
|
|
218
|
+
// src/pluginRuntime.ts
|
|
219
|
+
function mergeCaps(decl) {
|
|
220
|
+
if (!decl) return void 0;
|
|
221
|
+
return { ...decl.native, ...decl.capabilities };
|
|
222
|
+
}
|
|
223
|
+
function resolvePluginRuntimeProps(src) {
|
|
224
|
+
const trusted = src.manifest ?? src.plugin ?? null;
|
|
225
|
+
const capabilities = mergeCaps(trusted);
|
|
226
|
+
const stateDomains = trusted?.stateDomains;
|
|
227
|
+
const native = gatePluginNative(getPluginNative(), capabilities, src.pluginId);
|
|
228
|
+
const deviceState = gateDeviceState(stateDomains);
|
|
229
|
+
const voice = gateVoice(!!capabilities?.voice, src.pluginId);
|
|
230
|
+
return { device: native, native, deviceState, voice };
|
|
1201
231
|
}
|
|
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
232
|
|
|
1270
|
-
// src/
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
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;
|
|
233
|
+
// src/tools/platformTools.ts
|
|
234
|
+
var PLATFORM_PLUGIN_ID = "platform:device-tools";
|
|
235
|
+
function registerPlatformDeviceTools() {
|
|
236
|
+
registerDeviceTools(PLATFORM_PLUGIN_ID, [
|
|
237
|
+
{
|
|
238
|
+
name: "device.echo",
|
|
239
|
+
description: "Echo a string back from the user's own device.",
|
|
240
|
+
input_schema: {
|
|
241
|
+
type: "object",
|
|
242
|
+
properties: { text: { type: "string" } },
|
|
243
|
+
required: ["text"]
|
|
244
|
+
},
|
|
245
|
+
run: (args) => ({
|
|
246
|
+
ok: true,
|
|
247
|
+
echoed: args && args.text || "",
|
|
248
|
+
// The proof: a server-side implementation could not say this truthfully.
|
|
249
|
+
ran_on: "device"
|
|
250
|
+
})
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: "device.ping",
|
|
254
|
+
description: "Check that the device is reachable.",
|
|
255
|
+
input_schema: { type: "object", properties: {} },
|
|
256
|
+
run: () => ({ ok: true, ran_on: "device", at: (/* @__PURE__ */ new Date()).toISOString() })
|
|
1308
257
|
}
|
|
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";
|
|
258
|
+
]);
|
|
1337
259
|
}
|
|
1338
260
|
|
|
1339
|
-
// src/
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
261
|
+
// src/tools/sessionSync.ts
|
|
262
|
+
function deviceToolsActionForSession(next, prevTenant2) {
|
|
263
|
+
const tenant = next.authenticated ? next.tenant ?? null : null;
|
|
264
|
+
if (tenant && tenant !== prevTenant2) return { action: "load", tenant };
|
|
265
|
+
if (!tenant && prevTenant2) return { action: "reset", tenant: null };
|
|
266
|
+
return { action: "none", tenant: prevTenant2 };
|
|
267
|
+
}
|
|
268
|
+
var REAL_DEPS = {
|
|
269
|
+
clear: clearDeviceTools,
|
|
270
|
+
registerPlatform: registerPlatformDeviceTools,
|
|
271
|
+
// `./loader` reaches react-native via the bundle manager; import it only when
|
|
272
|
+
// an effect actually fires (real app), never at module load (tests).
|
|
273
|
+
resetLoader: () => {
|
|
274
|
+
void import("./loader-5LUVXUY2.mjs").then((m) => m.resetDeviceToolLoader());
|
|
275
|
+
},
|
|
276
|
+
load: () => {
|
|
277
|
+
void import("./loader-5LUVXUY2.mjs").then((m) => {
|
|
278
|
+
m.resetDeviceToolLoader();
|
|
279
|
+
return m.ensureDeviceToolsLoaded({ force: true });
|
|
1357
280
|
});
|
|
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
281
|
}
|
|
1517
|
-
|
|
282
|
+
};
|
|
283
|
+
var prevTenant = null;
|
|
284
|
+
function syncDeviceToolsForSession(next, deps = REAL_DEPS) {
|
|
285
|
+
const { action, tenant } = deviceToolsActionForSession(next, prevTenant);
|
|
286
|
+
prevTenant = tenant;
|
|
287
|
+
if (action === "load") {
|
|
288
|
+
deps.clear();
|
|
289
|
+
deps.registerPlatform();
|
|
290
|
+
deps.load();
|
|
291
|
+
} else if (action === "reset") {
|
|
292
|
+
deps.resetLoader();
|
|
293
|
+
}
|
|
294
|
+
return action;
|
|
295
|
+
}
|
|
296
|
+
function __resetSessionSyncForTest() {
|
|
297
|
+
prevTenant = null;
|
|
1518
298
|
}
|
|
1519
299
|
|
|
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;
|
|
300
|
+
// src/tools/serverCalls.ts
|
|
301
|
+
var postResult = null;
|
|
302
|
+
function setDeviceToolResultPoster(fn) {
|
|
303
|
+
postResult = fn;
|
|
1551
304
|
}
|
|
1552
|
-
function
|
|
1553
|
-
return
|
|
305
|
+
function isDeviceToolCommand(cmd) {
|
|
306
|
+
return !!cmd && cmd.kind === "device_tool" && typeof cmd.tool === "string" && !!cmd.correlationId;
|
|
1554
307
|
}
|
|
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;
|
|
1644
|
-
}
|
|
1645
|
-
/**
|
|
1646
|
-
* Prewarm: load every plugin bundle in the background after app boot, so a
|
|
1647
|
-
* later open is instant (in-memory hit) instead of round-tripping the
|
|
1648
|
-
* network. Errors are swallowed per-plugin — one bad bundle shouldn't
|
|
1649
|
-
* block others. Concurrency capped at 3.
|
|
1650
|
-
*/
|
|
1651
|
-
async prewarmAll(items) {
|
|
1652
|
-
const queue = [...items];
|
|
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);
|
|
308
|
+
async function handleServerDeviceToolCall(cmd) {
|
|
309
|
+
if (!isDeviceToolCommand(cmd)) return;
|
|
310
|
+
const { tool, args, correlationId } = cmd;
|
|
311
|
+
if (!postResult) {
|
|
312
|
+
console.warn("[deviceTools] server called a tool but no result poster is installed");
|
|
313
|
+
return;
|
|
1738
314
|
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
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"
|
|
315
|
+
try {
|
|
316
|
+
await ensureDeviceToolsLoaded();
|
|
317
|
+
const outcome = await callDeviceTool(tool, args || {});
|
|
318
|
+
console.log(`[deviceTools] server-called ${tool} \u2192 ${outcome.ok ? "ok" : outcome.reason}`);
|
|
319
|
+
await postResult(
|
|
320
|
+
correlationId,
|
|
321
|
+
outcome.ok ? { ok: true, ...unwrap(outcome.result) } : void 0,
|
|
322
|
+
outcome.ok ? void 0 : outcome.error
|
|
1792
323
|
);
|
|
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
|
-
});
|
|
324
|
+
} catch (err) {
|
|
325
|
+
await postResult(correlationId, void 0, err?.message || String(err)).catch(() => {
|
|
1964
326
|
});
|
|
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
|
-
);
|
|
327
|
+
}
|
|
2018
328
|
}
|
|
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
|
-
};
|
|
329
|
+
function unwrap(result) {
|
|
330
|
+
if (result && typeof result === "object" && !Array.isArray(result)) return result;
|
|
331
|
+
return { result };
|
|
2065
332
|
}
|
|
2066
333
|
|
|
2067
334
|
// src/hooks/usePlugin.ts
|
|
2068
|
-
import { useState
|
|
335
|
+
import { useState, useEffect } from "react";
|
|
2069
336
|
function extractBundleUrl(pluginId, manifest) {
|
|
2070
337
|
const render = manifest.render;
|
|
2071
338
|
if (!render || typeof render !== "object") return { url: null, source: "none" };
|
|
@@ -2094,10 +361,10 @@ function extractComponentId(manifest) {
|
|
|
2094
361
|
return render.component || render.reactNative?.component || null;
|
|
2095
362
|
}
|
|
2096
363
|
function usePlugin(pluginId, manifest) {
|
|
2097
|
-
const [plugin, setPlugin] =
|
|
2098
|
-
const [loading, setLoading] =
|
|
2099
|
-
const [error, setError] =
|
|
2100
|
-
const [bundleMissing, setBundleMissing] =
|
|
364
|
+
const [plugin, setPlugin] = useState(null);
|
|
365
|
+
const [loading, setLoading] = useState(true);
|
|
366
|
+
const [error, setError] = useState(null);
|
|
367
|
+
const [bundleMissing, setBundleMissing] = useState(false);
|
|
2101
368
|
const version = manifest.version || "1.0.0";
|
|
2102
369
|
const { url: bundleUrl, ignored: ignoredUrl } = extractBundleUrl(pluginId, manifest);
|
|
2103
370
|
const bundleHash = extractBundleHash(manifest);
|
|
@@ -2106,7 +373,7 @@ function usePlugin(pluginId, manifest) {
|
|
|
2106
373
|
if (ignoredUrl) {
|
|
2107
374
|
console.warn(`[usePlugin] ${pluginId}: IGNORED connector-injected bundleUrl="${ignoredUrl}". The host derives bundle URLs from pluginId via the canonical route.`);
|
|
2108
375
|
}
|
|
2109
|
-
|
|
376
|
+
useEffect(() => {
|
|
2110
377
|
let cancelled = false;
|
|
2111
378
|
(async () => {
|
|
2112
379
|
try {
|
|
@@ -2167,14 +434,14 @@ function usePlugin(pluginId, manifest) {
|
|
|
2167
434
|
}
|
|
2168
435
|
|
|
2169
436
|
// src/hooks/useRemotePlugins.ts
|
|
2170
|
-
import { useEffect as
|
|
437
|
+
import { useEffect as useEffect2, useState as useState2, useCallback } from "react";
|
|
2171
438
|
import { apiFetch } from "@ateam-ai-mobile/core";
|
|
2172
439
|
function useRemotePlugins(solutionId) {
|
|
2173
|
-
const [plugins, setPlugins] =
|
|
2174
|
-
const [loading, setLoading] =
|
|
2175
|
-
const [refreshing, setRefreshing] =
|
|
2176
|
-
const [error, setError] =
|
|
2177
|
-
const fetchRemotePlugins =
|
|
440
|
+
const [plugins, setPlugins] = useState2([]);
|
|
441
|
+
const [loading, setLoading] = useState2(true);
|
|
442
|
+
const [refreshing, setRefreshing] = useState2(false);
|
|
443
|
+
const [error, setError] = useState2(null);
|
|
444
|
+
const fetchRemotePlugins = useCallback(async () => {
|
|
2178
445
|
try {
|
|
2179
446
|
setError(null);
|
|
2180
447
|
const targetSolutionId = solutionId || "current";
|
|
@@ -2219,11 +486,11 @@ function useRemotePlugins(solutionId) {
|
|
|
2219
486
|
setRefreshing(false);
|
|
2220
487
|
}
|
|
2221
488
|
}, [solutionId]);
|
|
2222
|
-
const refresh =
|
|
489
|
+
const refresh = useCallback(async () => {
|
|
2223
490
|
setRefreshing(true);
|
|
2224
491
|
await fetchRemotePlugins();
|
|
2225
492
|
}, [fetchRemotePlugins]);
|
|
2226
|
-
|
|
493
|
+
useEffect2(() => {
|
|
2227
494
|
setLoading(true);
|
|
2228
495
|
fetchRemotePlugins();
|
|
2229
496
|
}, [fetchRemotePlugins]);
|
|
@@ -2235,115 +502,13 @@ function useRemotePlugins(solutionId) {
|
|
|
2235
502
|
refresh
|
|
2236
503
|
};
|
|
2237
504
|
}
|
|
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
505
|
export {
|
|
2342
506
|
ActionButton,
|
|
2343
507
|
ActivityIndicator,
|
|
2344
508
|
AdaOrb,
|
|
2345
509
|
Animated,
|
|
2346
510
|
Badge,
|
|
511
|
+
CameraPreview,
|
|
2347
512
|
Card,
|
|
2348
513
|
EmptyState,
|
|
2349
514
|
ErrorState,
|
|
@@ -2353,6 +518,7 @@ export {
|
|
|
2353
518
|
LoadingState,
|
|
2354
519
|
MemoryBundleStorage,
|
|
2355
520
|
Modal,
|
|
521
|
+
PLATFORM_VOICE_CALLER,
|
|
2356
522
|
Platform,
|
|
2357
523
|
PluginSDK,
|
|
2358
524
|
Pressable,
|
|
@@ -2371,30 +537,60 @@ export {
|
|
|
2371
537
|
TextInput,
|
|
2372
538
|
TouchableOpacity,
|
|
2373
539
|
View,
|
|
540
|
+
__resetSessionSyncForTest,
|
|
2374
541
|
bundleManager,
|
|
542
|
+
callDeviceTool,
|
|
543
|
+
clearDeviceTools,
|
|
2375
544
|
createNativeBridge,
|
|
545
|
+
device_state_exports as deviceStateV2,
|
|
546
|
+
deviceToolsActionForSession,
|
|
547
|
+
ensureDeviceToolsLoaded,
|
|
548
|
+
explainCapability,
|
|
549
|
+
gateDeviceState,
|
|
2376
550
|
gatePluginNative,
|
|
551
|
+
gateVoice,
|
|
552
|
+
getCameraPreviewProvider,
|
|
2377
553
|
getHaptics,
|
|
2378
554
|
getNativeBundleHash,
|
|
2379
555
|
getNativeBundleUrl,
|
|
2380
556
|
getNativeComponentId,
|
|
2381
557
|
getPlugin,
|
|
2382
558
|
getPluginNative,
|
|
559
|
+
handleServerDeviceToolCall,
|
|
560
|
+
hasDeviceTool,
|
|
561
|
+
implementedStateDomains,
|
|
562
|
+
implementedVoice,
|
|
563
|
+
isActionable,
|
|
564
|
+
isDeviceToolCommand,
|
|
2383
565
|
isInlineSurface,
|
|
2384
566
|
isMountSurface,
|
|
567
|
+
listDeviceTools,
|
|
2385
568
|
listPlugins,
|
|
2386
569
|
nativePluginRegistry,
|
|
570
|
+
neverObserved,
|
|
2387
571
|
register,
|
|
2388
572
|
registerBundleModules,
|
|
573
|
+
registerDeviceTools,
|
|
2389
574
|
registerNativePlugin,
|
|
575
|
+
registerPlatformDeviceTools,
|
|
2390
576
|
registerService,
|
|
577
|
+
registerTools,
|
|
578
|
+
resetDeviceToolLoader,
|
|
579
|
+
resolvePluginRuntimeProps,
|
|
2391
580
|
resolvePluginUrl,
|
|
2392
581
|
setBundleStorage,
|
|
582
|
+
setCameraPreviewProvider,
|
|
583
|
+
setDeviceStateProvider,
|
|
584
|
+
setDeviceToolContextProvider,
|
|
585
|
+
setDeviceToolResultPoster,
|
|
2393
586
|
setHapticsProvider,
|
|
2394
587
|
setPluginNativeProvider,
|
|
2395
588
|
setPluginThemeColors,
|
|
589
|
+
setVoiceProvider,
|
|
2396
590
|
supportsNative,
|
|
2397
591
|
supportsWebView,
|
|
592
|
+
syncDeviceToolsForSession,
|
|
593
|
+
unregisterDeviceTools,
|
|
2398
594
|
unregisterNativePlugin,
|
|
2399
595
|
useApi,
|
|
2400
596
|
useNativeBridge,
|