@ateam-ai-mobile/ui 0.1.4 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -34,9 +34,13 @@ __export(index_exports, {
34
34
  ChatInput: () => ChatInput,
35
35
  DaySeparator: () => DaySeparator,
36
36
  EmbeddedPluginWebView: () => EmbeddedPluginWebView,
37
+ HandoffScreen: () => HandoffScreen,
37
38
  JobProgressBar: () => JobProgressBar,
39
+ JoinScreen: () => JoinScreen,
38
40
  Lightbox: () => Lightbox,
41
+ LoginScreen: () => LoginScreen,
39
42
  MessageBubble: () => MessageBubble,
43
+ OpenJoinScreen: () => OpenJoinScreen,
40
44
  Plugin: () => Plugin,
41
45
  PluginSurface: () => PluginSurface,
42
46
  TableCardBlock: () => TableCardBlock,
@@ -44,30 +48,44 @@ __export(index_exports, {
44
48
  TypingIndicator: () => TypingIndicator,
45
49
  UIActionsRow: () => UIActionsRow,
46
50
  VoiceCallSheet: () => VoiceCallSheet,
51
+ VoiceMicIndicator: () => VoiceMicIndicator,
52
+ VoiceSessionHost: () => VoiceSessionHost,
47
53
  WidgetHost: () => WidgetHost,
48
54
  WidgetWebView: () => WidgetWebView,
55
+ WorkspaceBanner: () => WorkspaceBanner,
49
56
  buildPluginBridgeJS: () => buildPluginBridgeJS,
57
+ completeInviteJoin: () => completeInviteJoin,
58
+ completeOpenJoin: () => completeOpenJoin,
59
+ completeProviderSignIn: () => completeProviderSignIn,
60
+ googleClientIds: () => googleClientIds,
61
+ handoffErrorMessage: () => handoffErrorMessage,
62
+ inviteHeadline: () => inviteHeadline,
63
+ openJoinErrorMessage: () => openJoinErrorMessage,
50
64
  openWidget: () => openWidget,
65
+ runHandoffExchange: () => runHandoffExchange,
51
66
  setClipboardProvider: () => setClipboardProvider,
67
+ setOAuthProvider: () => setOAuthProvider,
52
68
  setPluginWebViewExtraHosts: () => setPluginWebViewExtraHosts,
53
69
  setUIActionNavigator: () => setUIActionNavigator,
70
+ shouldRecoverToDefaultTenant: () => shouldRecoverToDefaultTenant,
54
71
  useLightboxStore: () => useLightboxStore,
55
72
  usePluginBridge: () => usePluginBridge,
56
73
  useVoiceCall: () => useVoiceCall,
57
- useWidgetHostStore: () => useWidgetHostStore
74
+ useWidgetHostStore: () => useWidgetHostStore,
75
+ voiceSession: () => voiceSession
58
76
  });
59
77
  module.exports = __toCommonJS(index_exports);
60
78
 
61
79
  // src/AdasChatScreen.tsx
62
80
  var import_react9 = require("react");
63
- var import_react_native11 = require("react-native");
64
- var import_core12 = require("@ateam-ai-mobile/core");
81
+ var import_react_native12 = require("react-native");
82
+ var import_core13 = require("@ateam-ai-mobile/core");
65
83
 
66
84
  // src/chat/MessageBubble.tsx
67
85
  var import_react7 = require("react");
68
- var import_react_native7 = require("react-native");
86
+ var import_react_native8 = require("react-native");
69
87
  var import_react_native_markdown_display = __toESM(require("react-native-markdown-display"));
70
- var import_core9 = require("@ateam-ai-mobile/core");
88
+ var import_core10 = require("@ateam-ai-mobile/core");
71
89
  var import_plugin_runtime6 = require("@ateam-ai-mobile/plugin-runtime");
72
90
 
73
91
  // src/chat/JobProgressBar.tsx
@@ -261,6 +279,13 @@ var import_core7 = require("@ateam-ai-mobile/core");
261
279
  var import_plugin_runtime5 = require("@ateam-ai-mobile/plugin-runtime");
262
280
 
263
281
  // src/providers.ts
282
+ var _oauth = null;
283
+ function setOAuthProvider(oauth) {
284
+ _oauth = oauth;
285
+ }
286
+ function getOAuthProvider() {
287
+ return _oauth;
288
+ }
264
289
  var _clipboard = null;
265
290
  function setClipboardProvider(clipboard) {
266
291
  _clipboard = clipboard;
@@ -785,8 +810,10 @@ function Plugin({ id, manifest, commandBufferRef, props: engineProps }) {
785
810
  const { plugin, loading, error, bundleMissing } = (0, import_plugin_runtime2.usePlugin)(id, manifest);
786
811
  const connectorId = id.startsWith("mcp:") ? id.split(":")[1] : manifest._connectorId;
787
812
  const bridge = (0, import_plugin_runtime2.useNativeBridge)(id, connectorId, commandBufferRef);
788
- const declaredCaps = manifest?.native;
789
- const native = (0, import_react4.useMemo)(() => (0, import_plugin_runtime2.gatePluginNative)((0, import_plugin_runtime2.getPluginNative)(), declaredCaps), [declaredCaps]);
813
+ const { device, native, deviceState, voice } = (0, import_react4.useMemo)(
814
+ () => (0, import_plugin_runtime2.resolvePluginRuntimeProps)({ pluginId: id, manifest, plugin }),
815
+ [id, manifest, plugin]
816
+ );
790
817
  const theme = (0, import_plugin_runtime2.usePluginTheme)();
791
818
  const user = (0, import_core4.getUser)();
792
819
  const context = (0, import_react4.useMemo)(() => ({
@@ -809,7 +836,7 @@ function Plugin({ id, manifest, commandBufferRef, props: engineProps }) {
809
836
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: styles3.center, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: styles3.errorMessage, children: error || "Plugin not found" }) });
810
837
  }
811
838
  const { Component } = plugin;
812
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PluginErrorBoundary, { pluginId: id, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, { bridge, native, theme, context, props: engineProps }) });
839
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PluginErrorBoundary, { pluginId: id, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, { bridge, device, native, deviceState, voice, theme, context, props: engineProps }) });
813
840
  }
814
841
  var styles3 = import_react_native3.StyleSheet.create({
815
842
  center: {
@@ -959,7 +986,8 @@ function UIActionsRow({ actions }) {
959
986
  const focus = a.payload?.id || a.payload?.entity_id || a.payload?.focusId;
960
987
  const surface = import_plugin_runtime5.useSurfaceStore.getState().manifests[id];
961
988
  if (surface) {
962
- import_plugin_runtime5.useSurfaceStore.getState().show(id, focus ? { focus } : void 0);
989
+ const props = { ...focus ? { focus } : {}, ...a.payload?.data || {} };
990
+ import_plugin_runtime5.useSurfaceStore.getState().show(id, Object.keys(props).length ? props : void 0);
963
991
  return;
964
992
  }
965
993
  const params = {};
@@ -1034,47 +1062,107 @@ var styles4 = import_react_native5.StyleSheet.create({
1034
1062
  }
1035
1063
  });
1036
1064
 
1037
- // src/chat/TableCardBlock.tsx
1065
+ // src/chat/QuestionChips.tsx
1038
1066
  var import_react_native6 = require("react-native");
1039
1067
  var import_core8 = require("@ateam-ai-mobile/core");
1040
1068
  var import_jsx_runtime7 = require("react/jsx-runtime");
1041
1069
  var fontFam2 = import_react_native6.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1070
+ function resolveOptions(inputType, options) {
1071
+ if (Array.isArray(options) && options.length) return options.filter((o) => typeof o === "string" && o.trim());
1072
+ if (inputType === "confirm") return ["Yes", "No"];
1073
+ return [];
1074
+ }
1075
+ function QuestionChips({
1076
+ inputType,
1077
+ options
1078
+ }) {
1079
+ const opts = resolveOptions(inputType, options);
1080
+ if (!opts.length) return null;
1081
+ const answer = (label) => {
1082
+ try {
1083
+ import_core8.useChatStore.getState().sendMessage(label);
1084
+ } catch {
1085
+ }
1086
+ };
1087
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: styles5.row, children: opts.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1088
+ import_react_native6.Pressable,
1089
+ {
1090
+ accessibilityRole: "button",
1091
+ accessibilityLabel: label,
1092
+ onPress: () => answer(label),
1093
+ style: ({ pressed }) => [styles5.chip, pressed && styles5.chipPressed],
1094
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles5.label, numberOfLines: 2, children: label })
1095
+ },
1096
+ `${label}-${i}`
1097
+ )) });
1098
+ }
1099
+ var styles5 = import_react_native6.StyleSheet.create({
1100
+ row: {
1101
+ flexDirection: "row",
1102
+ flexWrap: "wrap",
1103
+ gap: 6,
1104
+ marginTop: 10
1105
+ },
1106
+ chip: {
1107
+ paddingHorizontal: 12,
1108
+ paddingVertical: 8,
1109
+ backgroundColor: import_core8.ada.orangeSoft,
1110
+ borderColor: import_core8.ada.orange,
1111
+ borderWidth: 1,
1112
+ borderRadius: 14
1113
+ },
1114
+ chipPressed: {
1115
+ backgroundColor: import_core8.ada.orange
1116
+ },
1117
+ label: {
1118
+ color: import_core8.ada.orangeDeep,
1119
+ fontSize: import_core8.fontSize.xs,
1120
+ fontWeight: "600",
1121
+ fontFamily: fontFam2
1122
+ }
1123
+ });
1124
+
1125
+ // src/chat/TableCardBlock.tsx
1126
+ var import_react_native7 = require("react-native");
1127
+ var import_core9 = require("@ateam-ai-mobile/core");
1128
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1129
+ var fontFam3 = import_react_native7.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1042
1130
  function TableCardBlock({ columns, rows }) {
1043
1131
  if (!columns?.length || !rows?.length) return null;
1044
1132
  const [titleCol, ...detailCols] = columns;
1045
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: styles5.wrap, children: rows.map((row, i) => {
1133
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.wrap, children: rows.map((row, i) => {
1046
1134
  const cells = Array.isArray(row) ? row : [row];
1047
1135
  const title = cells[0];
1048
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native6.View, { style: styles5.card, children: [
1049
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles5.title, children: String(title ?? "") }),
1050
- detailCols.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: styles5.details, children: detailCols.map((col, ci) => {
1136
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles6.card, children: [
1137
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.title, children: String(title ?? "") }),
1138
+ detailCols.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.details, children: detailCols.map((col, ci) => {
1051
1139
  const value = cells[ci + 1];
1052
1140
  if (value == null || value === "") return null;
1053
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native6.View, { style: styles5.row, children: [
1054
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles5.label, children: String(col) }),
1055
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles5.value, children: String(value) })
1141
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles6.row, children: [
1142
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.label, children: String(col) }),
1143
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.value, children: String(value) })
1056
1144
  ] }, ci);
1057
1145
  }) })
1058
1146
  ] }, i);
1059
1147
  }) });
1060
1148
  }
1061
- var styles5 = import_react_native6.StyleSheet.create({
1149
+ var styles6 = import_react_native7.StyleSheet.create({
1062
1150
  wrap: {
1063
1151
  marginVertical: 6,
1064
1152
  gap: 8
1065
1153
  },
1066
1154
  card: {
1067
- backgroundColor: import_core8.ada.paper,
1068
- borderRadius: import_core8.borderRadius.md,
1155
+ backgroundColor: import_core9.ada.paper,
1156
+ borderRadius: import_core9.borderRadius.md,
1069
1157
  borderWidth: 1,
1070
- borderColor: import_core8.ada.border,
1071
- padding: import_core8.spacing.md
1158
+ borderColor: import_core9.ada.border,
1159
+ padding: import_core9.spacing.md
1072
1160
  },
1073
1161
  title: {
1074
- color: import_core8.ada.ink,
1075
- fontSize: import_core8.fontSize.md,
1162
+ color: import_core9.ada.ink,
1163
+ fontSize: import_core9.fontSize.md,
1076
1164
  fontWeight: "600",
1077
- fontFamily: fontFam2,
1165
+ fontFamily: fontFam3,
1078
1166
  letterSpacing: -0.2,
1079
1167
  marginBottom: 6
1080
1168
  },
@@ -1087,9 +1175,9 @@ var styles5 = import_react_native6.StyleSheet.create({
1087
1175
  gap: 8
1088
1176
  },
1089
1177
  label: {
1090
- color: import_core8.ada.inkMuted,
1091
- fontSize: import_core8.fontSize.xs,
1092
- fontFamily: fontFam2,
1178
+ color: import_core9.ada.inkMuted,
1179
+ fontSize: import_core9.fontSize.xs,
1180
+ fontFamily: fontFam3,
1093
1181
  fontWeight: "500",
1094
1182
  width: 84,
1095
1183
  textTransform: "uppercase",
@@ -1098,9 +1186,9 @@ var styles5 = import_react_native6.StyleSheet.create({
1098
1186
  },
1099
1187
  value: {
1100
1188
  flex: 1,
1101
- color: import_core8.ada.inkSoft,
1102
- fontSize: import_core8.fontSize.sm,
1103
- fontFamily: fontFam2,
1189
+ color: import_core9.ada.inkSoft,
1190
+ fontSize: import_core9.fontSize.sm,
1191
+ fontFamily: fontFam3,
1104
1192
  lineHeight: 18
1105
1193
  }
1106
1194
  });
@@ -1114,8 +1202,8 @@ var useLightboxStore = (0, import_zustand2.create)((set) => ({
1114
1202
  }));
1115
1203
 
1116
1204
  // src/chat/MessageBubble.tsx
1117
- var import_jsx_runtime8 = require("react/jsx-runtime");
1118
- var fontFam3 = import_react_native7.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1205
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1206
+ var fontFam4 = import_react_native8.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1119
1207
  function formatTime(date) {
1120
1208
  const h = date.getHours();
1121
1209
  const m = date.getMinutes().toString().padStart(2, "0");
@@ -1133,18 +1221,18 @@ function DaySeparator({ date }) {
1133
1221
  } else {
1134
1222
  label = date.toLocaleDateString(void 0, { weekday: "long", month: "short", day: "numeric" });
1135
1223
  }
1136
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: separatorStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: separatorStyles.pill, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: separatorStyles.text, children: label }) }) });
1224
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: separatorStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: separatorStyles.pill, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: separatorStyles.text, children: label }) }) });
1137
1225
  }
1138
1226
  function isSameDay(a, b) {
1139
1227
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
1140
1228
  }
1141
- var separatorStyles = import_react_native7.StyleSheet.create({
1229
+ var separatorStyles = import_react_native8.StyleSheet.create({
1142
1230
  container: {
1143
1231
  alignItems: "center",
1144
1232
  marginVertical: 14
1145
1233
  },
1146
1234
  pill: {
1147
- backgroundColor: import_core9.ada.paperSoft,
1235
+ backgroundColor: import_core10.ada.paperSoft,
1148
1236
  paddingHorizontal: 14,
1149
1237
  paddingVertical: 5,
1150
1238
  borderRadius: 999
@@ -1152,9 +1240,9 @@ var separatorStyles = import_react_native7.StyleSheet.create({
1152
1240
  text: {
1153
1241
  fontSize: 12,
1154
1242
  fontWeight: "600",
1155
- color: import_core9.ada.inkMuted,
1243
+ color: import_core10.ada.inkMuted,
1156
1244
  letterSpacing: 0.4,
1157
- fontFamily: fontFam3
1245
+ fontFamily: fontFam4
1158
1246
  }
1159
1247
  });
1160
1248
  function MessageBubble({ message }) {
@@ -1162,6 +1250,7 @@ function MessageBubble({ message }) {
1162
1250
  const isSystem = message.role === "system";
1163
1251
  const isNotification = !isUser && message.kind === "notification";
1164
1252
  const st = message.jobProgress?.status;
1253
+ const pq = !isUser ? message.jobProgress?.pendingQuestion : void 0;
1165
1254
  const isProgressOnly = !isUser && (st === "running" || st === "paused") && (!message.content?.trim() || message.content === "Working on it...");
1166
1255
  const [copied, setCopied] = (0, import_react7.useState)("");
1167
1256
  const showCopied = (0, import_react7.useCallback)((label) => {
@@ -1178,84 +1267,92 @@ function MessageBubble({ message }) {
1178
1267
  const handleLongPress = (0, import_react7.useCallback)(() => {
1179
1268
  copyText(message.content);
1180
1269
  }, [message.content, copyText]);
1181
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: [styles6.row, isUser && styles6.rowUser], children: [
1182
- !isUser && !isNotification && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.avatarOrb, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1270
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: [styles7.row, isUser && styles7.rowUser], children: [
1271
+ !isUser && !isNotification && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.avatarOrb, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1183
1272
  import_plugin_runtime6.AdaOrb,
1184
1273
  {
1185
1274
  size: 28,
1186
1275
  state: message.jobProgress?.status === "running" ? "thinking" : "idle"
1187
1276
  }
1188
1277
  ) }),
1189
- isNotification && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.notificationLeftStripe }),
1190
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1191
- import_react_native7.Pressable,
1278
+ isNotification && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.notificationLeftStripe }),
1279
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1280
+ import_react_native8.Pressable,
1192
1281
  {
1193
1282
  accessibilityRole: "text",
1194
1283
  accessibilityLabel: `${isUser ? "You" : isNotification ? "Notification" : "Ada"}: ${message.content}`,
1195
1284
  accessibilityHint: "Long-press to copy",
1196
1285
  onLongPress: handleLongPress,
1197
1286
  style: [
1198
- styles6.bubble,
1199
- isUser && styles6.bubbleUser,
1200
- isSystem && styles6.bubbleSystem,
1201
- isNotification && styles6.bubbleNotification,
1202
- isProgressOnly && styles6.bubbleProgress
1287
+ styles7.bubble,
1288
+ isUser && styles7.bubbleUser,
1289
+ isSystem && styles7.bubbleSystem,
1290
+ isNotification && styles7.bubbleNotification,
1291
+ isProgressOnly && styles7.bubbleProgress
1203
1292
  ],
1204
1293
  children: [
1205
- isNotification && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles6.notificationHeader, children: [
1206
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.notificationHeaderIcon, children: "\u{1F514}" }),
1207
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.notificationHeaderText, children: "Notification" })
1294
+ isNotification && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: styles7.notificationHeader, children: [
1295
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.notificationHeaderIcon, children: "\u{1F514}" }),
1296
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.notificationHeaderText, children: "Notification" })
1208
1297
  ] }),
1209
- message.attachments && message.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.attachments, children: message.attachments.map((att, i) => att.previewUri ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1210
- import_react_native7.Pressable,
1298
+ message.attachments && message.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.attachments, children: message.attachments.map((att, i) => att.previewUri ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1299
+ import_react_native8.Pressable,
1211
1300
  {
1212
1301
  accessibilityRole: "imagebutton",
1213
1302
  accessibilityLabel: `Photo${att.name ? `: ${att.name}` : ""}. Tap to enlarge.`,
1214
1303
  onPress: () => useLightboxStore.getState().show(att.previewUri),
1215
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1216
- import_react_native7.Image,
1304
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1305
+ import_react_native8.Image,
1217
1306
  {
1218
1307
  source: {
1219
1308
  uri: att.previewUri,
1220
1309
  ...att.previewUri.startsWith("http") ? {
1221
- headers: { Authorization: `Bearer ${(0, import_core9.getConfig)().tokenProvider.getToken()}` }
1310
+ headers: { Authorization: `Bearer ${(0, import_core10.getConfig)().tokenProvider.getToken()}` }
1222
1311
  } : {}
1223
1312
  },
1224
- style: styles6.attachmentImage,
1313
+ style: styles7.attachmentImage,
1225
1314
  resizeMode: "cover",
1226
1315
  onError: (e) => console.warn("[Image] Failed to load:", att.previewUri?.slice(0, 100), e.nativeEvent.error)
1227
1316
  }
1228
1317
  )
1229
1318
  },
1230
1319
  i
1231
- ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.attachmentFile, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.attachmentFileName, numberOfLines: 1, children: att.name }) }, i)) }),
1320
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.attachmentFile, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.attachmentFileName, numberOfLines: 1, children: att.name }) }, i)) }),
1232
1321
  isUser ? (
1233
1322
  // Hide the "See attachment" placeholder when the bubble already shows the photo.
1234
- message.content && !(message.content === "See attachment" && message.attachments?.length) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { selectable: true, style: styles6.userText, children: message.content }) : null
1323
+ message.content && !(message.content === "See attachment" && message.attachments?.length) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { selectable: true, style: styles7.userText, children: message.content }) : null
1235
1324
  ) : isProgressOnly ? (
1236
1325
  // No "Working on it…" text — the indicator below is the whole message.
1237
1326
  null
1238
- ) : renderAssistantContent(message.content, copyText),
1239
- !!copied && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.copiedBadge, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.copiedText, children: copied }) }),
1240
- message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolCallsBadge, { calls: message.toolCalls }),
1241
- message.jobProgress && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(JobProgressBar, { progress: message.jobProgress, standalone: isProgressOnly }),
1242
- !isUser && message.actions && message.actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(UIActionsRow, { actions: message.actions }),
1243
- !isProgressOnly && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: [styles6.timeText, isUser && styles6.timeTextUser], children: formatTime(message.timestamp) })
1327
+ ) : (
1328
+ // When the turn asked a question, show its clean question string —
1329
+ // never message.content, which may carry the raw JSON payload.
1330
+ renderAssistantContent(pq?.question || message.content, copyText)
1331
+ ),
1332
+ !!copied && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.copiedBadge, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.copiedText, children: copied }) }),
1333
+ message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolCallsBadge, { calls: message.toolCalls }),
1334
+ message.jobProgress && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(JobProgressBar, { progress: message.jobProgress, standalone: isProgressOnly }),
1335
+ !isUser && message.actions && message.actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(UIActionsRow, { actions: message.actions }),
1336
+ pq && // Per-chain: this bubble's OWN chain has a pending question. Parallel
1337
+ // pending chains each render their own chips (jobProgress is per
1338
+ // bubble); answered questions have no jobProgress → no chips.
1339
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(QuestionChips, { inputType: pq.inputType, options: pq.options }),
1340
+ !isProgressOnly && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: [styles7.timeText, isUser && styles7.timeTextUser], children: formatTime(message.timestamp) })
1244
1341
  ]
1245
1342
  }
1246
1343
  ),
1247
- isUser && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.avatarSpacer })
1344
+ isUser && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.avatarSpacer })
1248
1345
  ] });
1249
1346
  }
1250
1347
  function renderAssistantContent(content, copyText) {
1251
1348
  if (!content) return null;
1252
- if (!content.includes(import_core9.TABLE_BLOCK_OPEN)) {
1253
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MarkdownBubble, { content, copyText });
1349
+ if (!content.includes(import_core10.TABLE_BLOCK_OPEN)) {
1350
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MarkdownBubble, { content, copyText });
1254
1351
  }
1255
1352
  const segments = [];
1256
1353
  let cursor = 0;
1257
1354
  while (cursor < content.length) {
1258
- const open = content.indexOf(import_core9.TABLE_BLOCK_OPEN, cursor);
1355
+ const open = content.indexOf(import_core10.TABLE_BLOCK_OPEN, cursor);
1259
1356
  if (open === -1) {
1260
1357
  segments.push({ kind: "md", content: content.slice(cursor) });
1261
1358
  break;
@@ -1263,37 +1360,37 @@ function renderAssistantContent(content, copyText) {
1263
1360
  if (open > cursor) {
1264
1361
  segments.push({ kind: "md", content: content.slice(cursor, open) });
1265
1362
  }
1266
- const close = content.indexOf(import_core9.TABLE_BLOCK_CLOSE, open + import_core9.TABLE_BLOCK_OPEN.length);
1363
+ const close = content.indexOf(import_core10.TABLE_BLOCK_CLOSE, open + import_core10.TABLE_BLOCK_OPEN.length);
1267
1364
  if (close === -1) {
1268
1365
  segments.push({ kind: "md", content: content.slice(open) });
1269
1366
  break;
1270
1367
  }
1271
- const payload = content.slice(open + import_core9.TABLE_BLOCK_OPEN.length, close);
1368
+ const payload = content.slice(open + import_core10.TABLE_BLOCK_OPEN.length, close);
1272
1369
  segments.push({ kind: "table", content: payload });
1273
- cursor = close + import_core9.TABLE_BLOCK_CLOSE.length;
1370
+ cursor = close + import_core10.TABLE_BLOCK_CLOSE.length;
1274
1371
  }
1275
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: segments.map((seg, i) => {
1372
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: segments.map((seg, i) => {
1276
1373
  if (seg.kind === "md") {
1277
1374
  const trimmed = seg.content.trim();
1278
1375
  if (!trimmed) return null;
1279
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MarkdownBubble, { content: seg.content, copyText }, i);
1376
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MarkdownBubble, { content: seg.content, copyText }, i);
1280
1377
  }
1281
1378
  try {
1282
1379
  const data = JSON.parse(decodeURIComponent(seg.content));
1283
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TableCardBlock, { columns: data.columns, rows: data.rows }, i);
1380
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TableCardBlock, { columns: data.columns, rows: data.rows }, i);
1284
1381
  } catch {
1285
1382
  return null;
1286
1383
  }
1287
1384
  }) });
1288
1385
  }
1289
1386
  function MarkdownBubble({ content, copyText }) {
1290
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1387
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1291
1388
  import_react_native_markdown_display.default,
1292
1389
  {
1293
1390
  style: markdownStyles,
1294
1391
  rules: {
1295
- code_inline: (node) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1296
- import_react_native7.Text,
1392
+ code_inline: (node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1393
+ import_react_native8.Text,
1297
1394
  {
1298
1395
  style: markdownStyles.code_inline,
1299
1396
  onPress: () => copyText(node.content),
@@ -1301,12 +1398,12 @@ function MarkdownBubble({ content, copyText }) {
1301
1398
  },
1302
1399
  node.key
1303
1400
  ),
1304
- fence: (node) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1305
- import_react_native7.Pressable,
1401
+ fence: (node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1402
+ import_react_native8.Pressable,
1306
1403
  {
1307
1404
  onPress: () => copyText(node.content),
1308
1405
  style: markdownStyles.fence,
1309
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: markdownStyles.fenceText, children: node.content })
1406
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: markdownStyles.fenceText, children: node.content })
1310
1407
  },
1311
1408
  node.key
1312
1409
  )
@@ -1318,18 +1415,18 @@ function MarkdownBubble({ content, copyText }) {
1318
1415
  function ToolCallsBadge({ calls }) {
1319
1416
  const [expanded, setExpanded] = (0, import_react7.useState)(false);
1320
1417
  const label = calls.filter((c) => c.name === "send_message_to_skill").map((c) => c.args.skill_name || c.skill).filter(Boolean).join(", ") || "Tool call";
1321
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles6.toolCalls, children: [
1322
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.Pressable, { style: styles6.toolToggle, onPress: () => setExpanded(!expanded), children: [
1323
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.toolLabel, children: label }),
1324
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.toolChevron, children: expanded ? "\u25B2" : "\u25BC" })
1418
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: styles7.toolCalls, children: [
1419
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.Pressable, { style: styles7.toolToggle, onPress: () => setExpanded(!expanded), children: [
1420
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolLabel, children: label }),
1421
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolChevron, children: expanded ? "\u25B2" : "\u25BC" })
1325
1422
  ] }),
1326
- expanded && calls.map((tc, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles6.toolItem, children: [
1327
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.toolName, children: tc.name }),
1328
- tc.skill && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.toolSkill, children: tc.skill })
1423
+ expanded && calls.map((tc, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: styles7.toolItem, children: [
1424
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolName, children: tc.name }),
1425
+ tc.skill && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolSkill, children: tc.skill })
1329
1426
  ] }, i))
1330
1427
  ] });
1331
1428
  }
1332
- var styles6 = import_react_native7.StyleSheet.create({
1429
+ var styles7 = import_react_native8.StyleSheet.create({
1333
1430
  row: {
1334
1431
  flexDirection: "row",
1335
1432
  alignItems: "flex-end",
@@ -1352,15 +1449,15 @@ var styles6 = import_react_native7.StyleSheet.create({
1352
1449
  },
1353
1450
  bubble: {
1354
1451
  maxWidth: "78%",
1355
- backgroundColor: import_core9.ada.botBubble,
1452
+ backgroundColor: import_core10.ada.botBubble,
1356
1453
  borderWidth: 1,
1357
- borderColor: import_core9.ada.botBubbleBorder,
1358
- borderRadius: import_core9.borderRadius.xl,
1454
+ borderColor: import_core10.ada.botBubbleBorder,
1455
+ borderRadius: import_core10.borderRadius.xl,
1359
1456
  paddingHorizontal: 16,
1360
1457
  paddingVertical: 12
1361
1458
  },
1362
1459
  bubbleUser: {
1363
- backgroundColor: import_core9.ada.userBubble,
1460
+ backgroundColor: import_core10.ada.userBubble,
1364
1461
  borderColor: "transparent"
1365
1462
  },
1366
1463
  // Live-chain placeholder: no fill, no border, tighter padding — the
@@ -1372,20 +1469,20 @@ var styles6 = import_react_native7.StyleSheet.create({
1372
1469
  paddingVertical: 2
1373
1470
  },
1374
1471
  bubbleSystem: {
1375
- backgroundColor: import_core9.ada.orangeSoft,
1376
- borderColor: import_core9.ada.orange,
1472
+ backgroundColor: import_core10.ada.orangeSoft,
1473
+ borderColor: import_core10.ada.orange,
1377
1474
  maxWidth: "90%"
1378
1475
  },
1379
1476
  bubbleNotification: {
1380
- backgroundColor: import_core9.ada.orangeSoft,
1477
+ backgroundColor: import_core10.ada.orangeSoft,
1381
1478
  borderColor: "rgba(255, 122, 40, 0.35)",
1382
- borderRadius: import_core9.borderRadius.lg,
1479
+ borderRadius: import_core10.borderRadius.lg,
1383
1480
  maxWidth: "90%"
1384
1481
  },
1385
1482
  notificationLeftStripe: {
1386
1483
  width: 3,
1387
1484
  alignSelf: "stretch",
1388
- backgroundColor: import_core9.ada.orange,
1485
+ backgroundColor: import_core10.ada.orange,
1389
1486
  borderRadius: 2,
1390
1487
  marginRight: 4
1391
1488
  },
@@ -1399,25 +1496,25 @@ var styles6 = import_react_native7.StyleSheet.create({
1399
1496
  fontSize: 12
1400
1497
  },
1401
1498
  notificationHeaderText: {
1402
- color: import_core9.ada.orangeDeep,
1499
+ color: import_core10.ada.orangeDeep,
1403
1500
  fontSize: 11,
1404
1501
  fontWeight: "700",
1405
1502
  letterSpacing: 0.6,
1406
1503
  textTransform: "uppercase",
1407
- fontFamily: fontFam3
1504
+ fontFamily: fontFam4
1408
1505
  },
1409
1506
  userText: {
1410
- color: import_core9.ada.userBubbleText,
1411
- fontSize: import_core9.fontSize.md,
1507
+ color: import_core10.ada.userBubbleText,
1508
+ fontSize: import_core10.fontSize.md,
1412
1509
  lineHeight: 22,
1413
- fontFamily: fontFam3
1510
+ fontFamily: fontFam4
1414
1511
  },
1415
1512
  timeText: {
1416
1513
  fontSize: 11,
1417
- color: import_core9.ada.inkMuted,
1514
+ color: import_core10.ada.inkMuted,
1418
1515
  alignSelf: "flex-end",
1419
1516
  marginTop: 4,
1420
- fontFamily: fontFam3
1517
+ fontFamily: fontFam4
1421
1518
  },
1422
1519
  timeTextUser: {
1423
1520
  color: "rgba(250,246,238,0.55)"
@@ -1451,17 +1548,17 @@ var styles6 = import_react_native7.StyleSheet.create({
1451
1548
  backgroundColor: "#5A8A5C",
1452
1549
  paddingHorizontal: 8,
1453
1550
  paddingVertical: 2,
1454
- borderRadius: import_core9.borderRadius.sm
1551
+ borderRadius: import_core10.borderRadius.sm
1455
1552
  },
1456
1553
  copiedText: {
1457
1554
  color: "#fff",
1458
- fontSize: import_core9.fontSize.xs,
1555
+ fontSize: import_core10.fontSize.xs,
1459
1556
  fontWeight: "600"
1460
1557
  },
1461
1558
  toolCalls: {
1462
1559
  marginTop: 8,
1463
1560
  borderTopWidth: 1,
1464
- borderTopColor: import_core9.ada.border,
1561
+ borderTopColor: import_core10.ada.border,
1465
1562
  paddingTop: 6
1466
1563
  },
1467
1564
  toolToggle: {
@@ -1470,12 +1567,12 @@ var styles6 = import_react_native7.StyleSheet.create({
1470
1567
  gap: 6
1471
1568
  },
1472
1569
  toolLabel: {
1473
- color: import_core9.ada.inkSoft,
1474
- fontSize: import_core9.fontSize.xs,
1570
+ color: import_core10.ada.inkSoft,
1571
+ fontSize: import_core10.fontSize.xs,
1475
1572
  fontWeight: "500"
1476
1573
  },
1477
1574
  toolChevron: {
1478
- color: import_core9.ada.inkMuted,
1575
+ color: import_core10.ada.inkMuted,
1479
1576
  fontSize: 8
1480
1577
  },
1481
1578
  toolItem: {
@@ -1483,21 +1580,21 @@ var styles6 = import_react_native7.StyleSheet.create({
1483
1580
  paddingLeft: 8
1484
1581
  },
1485
1582
  toolName: {
1486
- color: import_core9.ada.inkSoft,
1487
- fontSize: import_core9.fontSize.xs,
1583
+ color: import_core10.ada.inkSoft,
1584
+ fontSize: import_core10.fontSize.xs,
1488
1585
  fontFamily: "monospace"
1489
1586
  },
1490
1587
  toolSkill: {
1491
- color: import_core9.ada.orangeDeep,
1492
- fontSize: import_core9.fontSize.xs
1588
+ color: import_core10.ada.orangeDeep,
1589
+ fontSize: import_core10.fontSize.xs
1493
1590
  }
1494
1591
  });
1495
- var markdownStyles = import_react_native7.StyleSheet.create({
1592
+ var markdownStyles = import_react_native8.StyleSheet.create({
1496
1593
  body: {
1497
- color: import_core9.ada.botBubbleText,
1498
- fontSize: import_core9.fontSize.md,
1594
+ color: import_core10.ada.botBubbleText,
1595
+ fontSize: import_core10.fontSize.md,
1499
1596
  lineHeight: 22,
1500
- fontFamily: fontFam3
1597
+ fontFamily: fontFam4
1501
1598
  },
1502
1599
  paragraph: {
1503
1600
  marginTop: 0,
@@ -1505,35 +1602,35 @@ var markdownStyles = import_react_native7.StyleSheet.create({
1505
1602
  },
1506
1603
  strong: {
1507
1604
  fontWeight: "700",
1508
- color: import_core9.ada.botBubbleText
1605
+ color: import_core10.ada.botBubbleText
1509
1606
  },
1510
1607
  em: {
1511
1608
  fontStyle: "italic"
1512
1609
  },
1513
1610
  code_inline: {
1514
- backgroundColor: import_core9.ada.paperDeep,
1515
- color: import_core9.ada.orangeDeep,
1611
+ backgroundColor: import_core10.ada.paperDeep,
1612
+ color: import_core10.ada.orangeDeep,
1516
1613
  paddingHorizontal: 5,
1517
1614
  paddingVertical: 1,
1518
1615
  borderRadius: 4,
1519
1616
  fontFamily: "monospace",
1520
- fontSize: import_core9.fontSize.sm
1617
+ fontSize: import_core10.fontSize.sm
1521
1618
  },
1522
1619
  fence: {
1523
- backgroundColor: import_core9.ada.paperDeep,
1620
+ backgroundColor: import_core10.ada.paperDeep,
1524
1621
  padding: 10,
1525
1622
  borderRadius: 10
1526
1623
  },
1527
1624
  fenceText: {
1528
1625
  fontFamily: "monospace",
1529
- fontSize: import_core9.fontSize.sm,
1530
- color: import_core9.ada.ink
1626
+ fontSize: import_core10.fontSize.sm,
1627
+ color: import_core10.ada.ink
1531
1628
  },
1532
1629
  link: {
1533
- color: import_core9.ada.orangeDeep
1630
+ color: import_core10.ada.orangeDeep
1534
1631
  },
1535
1632
  list_item: {
1536
- color: import_core9.ada.botBubbleText
1633
+ color: import_core10.ada.botBubbleText
1537
1634
  },
1538
1635
  bullet_list: {
1539
1636
  marginVertical: 4
@@ -1541,13 +1638,13 @@ var markdownStyles = import_react_native7.StyleSheet.create({
1541
1638
  });
1542
1639
 
1543
1640
  // src/chat/TypingIndicator.tsx
1544
- var import_react_native8 = require("react-native");
1641
+ var import_react_native9 = require("react-native");
1545
1642
  var import_plugin_runtime7 = require("@ateam-ai-mobile/plugin-runtime");
1546
- var import_jsx_runtime9 = require("react/jsx-runtime");
1643
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1547
1644
  function TypingIndicator() {
1548
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.row, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_plugin_runtime7.AdaOrb, { size: 32, state: "thinking" }) });
1645
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: styles8.row, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_plugin_runtime7.AdaOrb, { size: 32, state: "thinking" }) });
1549
1646
  }
1550
- var styles7 = import_react_native8.StyleSheet.create({
1647
+ var styles8 = import_react_native9.StyleSheet.create({
1551
1648
  row: {
1552
1649
  flexDirection: "row",
1553
1650
  alignItems: "center",
@@ -1559,11 +1656,11 @@ var styles7 = import_react_native8.StyleSheet.create({
1559
1656
 
1560
1657
  // src/chat/ChatInput.tsx
1561
1658
  var import_react8 = require("react");
1562
- var import_react_native9 = require("react-native");
1659
+ var import_react_native10 = require("react-native");
1563
1660
  var import_react_native_svg = __toESM(require("react-native-svg"));
1564
- var import_core10 = require("@ateam-ai-mobile/core");
1661
+ var import_core11 = require("@ateam-ai-mobile/core");
1565
1662
  var import_plugin_runtime8 = require("@ateam-ai-mobile/plugin-runtime");
1566
- var import_jsx_runtime10 = require("react/jsx-runtime");
1663
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1567
1664
  function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }) {
1568
1665
  const [text, setText] = (0, import_react8.useState)("");
1569
1666
  const [height, setHeight] = (0, import_react8.useState)(40);
@@ -1583,55 +1680,55 @@ function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }) {
1583
1680
  setHeight(40);
1584
1681
  }, [text, loading, onSend]);
1585
1682
  const canSend = text.trim().length > 0;
1586
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: styles8.dock, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native9.View, { style: styles8.inputRow, children: [
1587
- onCallStart && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.Pressable, { style: styles8.callBtn, onPress: onCallStart, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_svg.default, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: import_core10.colors.light.accent, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_svg.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" }) }) }),
1588
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1589
- import_react_native9.TextInput,
1683
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { style: styles9.dock, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.View, { style: styles9.inputRow, children: [
1684
+ onCallStart && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Pressable, { style: styles9.callBtn, onPress: onCallStart, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.default, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: import_core11.colors.light.accent, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.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" }) }) }),
1685
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1686
+ import_react_native10.TextInput,
1590
1687
  {
1591
1688
  ref: inputRef,
1592
- style: [styles8.input, { height: Math.min(Math.max(40, height), 120) }],
1689
+ style: [styles9.input, { height: Math.min(Math.max(40, height), 120) }],
1593
1690
  value: text,
1594
1691
  onChangeText: setText,
1595
1692
  onContentSizeChange: (e) => setHeight(e.nativeEvent.contentSize.height),
1596
1693
  placeholder: placeholder || "Message A-Team...",
1597
- placeholderTextColor: import_core10.colors.light.textMuted,
1694
+ placeholderTextColor: import_core11.colors.light.textMuted,
1598
1695
  multiline: true,
1599
1696
  returnKeyType: "default",
1600
1697
  blurOnSubmit: false,
1601
1698
  onSubmitEditing: () => {
1602
- if (import_react_native9.Platform.OS === "web") handleSend();
1699
+ if (import_react_native10.Platform.OS === "web") handleSend();
1603
1700
  }
1604
1701
  }
1605
1702
  ),
1606
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1607
- import_react_native9.Pressable,
1703
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1704
+ import_react_native10.Pressable,
1608
1705
  {
1609
- style: [styles8.sendBtn, canSend && styles8.sendBtnActive],
1706
+ style: [styles9.sendBtn, canSend && styles9.sendBtnActive],
1610
1707
  onPress: handleSend,
1611
1708
  disabled: !canSend,
1612
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_svg.default, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: canSend ? "#fff" : import_core10.colors.light.textMuted, strokeWidth: 2, children: [
1613
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_svg.Line, { x1: "22", y1: "2", x2: "11", y2: "13" }),
1614
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_svg.Polygon, { points: "22 2 15 22 11 13 2 9 22 2" })
1709
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native_svg.default, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: canSend ? "#fff" : import_core11.colors.light.textMuted, strokeWidth: 2, children: [
1710
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.Line, { x1: "22", y1: "2", x2: "11", y2: "13" }),
1711
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.Polygon, { points: "22 2 15 22 11 13 2 9 22 2" })
1615
1712
  ] })
1616
1713
  }
1617
1714
  )
1618
1715
  ] }) });
1619
1716
  }
1620
- var styles8 = import_react_native9.StyleSheet.create({
1717
+ var styles9 = import_react_native10.StyleSheet.create({
1621
1718
  dock: {
1622
1719
  paddingHorizontal: 12,
1623
1720
  paddingVertical: 8,
1624
- backgroundColor: import_core10.colors.light.bgPrimary,
1721
+ backgroundColor: import_core11.colors.light.bgPrimary,
1625
1722
  borderTopWidth: 0.5,
1626
- borderTopColor: import_core10.colors.light.border
1723
+ borderTopColor: import_core11.colors.light.border
1627
1724
  },
1628
1725
  inputRow: {
1629
1726
  flexDirection: "row",
1630
1727
  alignItems: "flex-end",
1631
- backgroundColor: import_core10.colors.light.bgInput,
1632
- borderRadius: import_core10.borderRadius.xl,
1728
+ backgroundColor: import_core11.colors.light.bgInput,
1729
+ borderRadius: import_core11.borderRadius.xl,
1633
1730
  borderWidth: 1,
1634
- borderColor: import_core10.colors.light.border,
1731
+ borderColor: import_core11.colors.light.border,
1635
1732
  paddingHorizontal: 4,
1636
1733
  paddingVertical: 4,
1637
1734
  gap: 4
@@ -1646,7 +1743,7 @@ var styles8 = import_react_native9.StyleSheet.create({
1646
1743
  input: {
1647
1744
  flex: 1,
1648
1745
  fontSize: 16,
1649
- color: import_core10.colors.light.textPrimary,
1746
+ color: import_core11.colors.light.textPrimary,
1650
1747
  paddingHorizontal: 8,
1651
1748
  paddingVertical: 8,
1652
1749
  maxHeight: 120
@@ -1657,39 +1754,39 @@ var styles8 = import_react_native9.StyleSheet.create({
1657
1754
  borderRadius: 18,
1658
1755
  justifyContent: "center",
1659
1756
  alignItems: "center",
1660
- backgroundColor: import_core10.colors.light.bgTertiary
1757
+ backgroundColor: import_core11.colors.light.bgTertiary
1661
1758
  },
1662
1759
  sendBtnActive: {
1663
- backgroundColor: import_core10.colors.light.accent
1760
+ backgroundColor: import_core11.colors.light.accent
1664
1761
  }
1665
1762
  });
1666
1763
 
1667
1764
  // src/Lightbox.tsx
1668
- var import_react_native10 = require("react-native");
1669
- var import_core11 = require("@ateam-ai-mobile/core");
1670
- var import_jsx_runtime11 = require("react/jsx-runtime");
1765
+ var import_react_native11 = require("react-native");
1766
+ var import_core12 = require("@ateam-ai-mobile/core");
1767
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1671
1768
  function Lightbox() {
1672
1769
  const uri = useLightboxStore((s) => s.uri);
1673
1770
  const hide = useLightboxStore((s) => s.hide);
1674
1771
  if (!uri) return null;
1675
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Modal, { visible: true, transparent: true, animationType: "fade", onRequestClose: hide, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.Pressable, { style: styles9.backdrop, onPress: hide, children: [
1676
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1677
- import_react_native10.Image,
1772
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native11.Modal, { visible: true, transparent: true, animationType: "fade", onRequestClose: hide, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native11.Pressable, { style: styles10.backdrop, onPress: hide, children: [
1773
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1774
+ import_react_native11.Image,
1678
1775
  {
1679
1776
  source: {
1680
1777
  uri,
1681
1778
  ...uri.startsWith("http") ? {
1682
- headers: { Authorization: `Bearer ${(0, import_core11.getConfig)().tokenProvider.getToken()}` }
1779
+ headers: { Authorization: `Bearer ${(0, import_core12.getConfig)().tokenProvider.getToken()}` }
1683
1780
  } : {}
1684
1781
  },
1685
- style: styles9.image,
1782
+ style: styles10.image,
1686
1783
  resizeMode: "contain"
1687
1784
  }
1688
1785
  ),
1689
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { style: styles9.closeHint, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Text, { style: styles9.closeHintText, children: "Tap to close" }) })
1786
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native11.View, { style: styles10.closeHint, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native11.Text, { style: styles10.closeHintText, children: "Tap to close" }) })
1690
1787
  ] }) });
1691
1788
  }
1692
- var styles9 = import_react_native10.StyleSheet.create({
1789
+ var styles10 = import_react_native11.StyleSheet.create({
1693
1790
  backdrop: {
1694
1791
  flex: 1,
1695
1792
  backgroundColor: "rgba(0,0,0,0.92)",
@@ -1711,7 +1808,7 @@ var styles9 = import_react_native10.StyleSheet.create({
1711
1808
  });
1712
1809
 
1713
1810
  // src/AdasChatScreen.tsx
1714
- var import_jsx_runtime12 = require("react/jsx-runtime");
1811
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1715
1812
  function isSameDay2(a, b) {
1716
1813
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
1717
1814
  }
@@ -1721,11 +1818,11 @@ function AdasChatScreen({
1721
1818
  footerAccessory,
1722
1819
  withLightbox = true
1723
1820
  }) {
1724
- const messages = (0, import_core12.useChatStore)((s) => s.messages);
1725
- const loading = (0, import_core12.useChatStore)((s) => s.loading);
1726
- const conversationLoaded = (0, import_core12.useChatStore)((s) => s.conversationLoaded);
1727
- const loadConversation = (0, import_core12.useChatStore)((s) => s.loadConversation);
1728
- const sendMessage = (0, import_core12.useChatStore)((s) => s.sendMessage);
1821
+ const messages = (0, import_core13.useChatStore)((s) => s.messages);
1822
+ const loading = (0, import_core13.useChatStore)((s) => s.loading);
1823
+ const conversationLoaded = (0, import_core13.useChatStore)((s) => s.conversationLoaded);
1824
+ const loadConversation = (0, import_core13.useChatStore)((s) => s.loadConversation);
1825
+ const sendMessage = (0, import_core13.useChatStore)((s) => s.sendMessage);
1729
1826
  const listRef = (0, import_react9.useRef)(null);
1730
1827
  const [refreshing, setRefreshing] = (0, import_react9.useState)(false);
1731
1828
  const [prefill, setPrefill] = (0, import_react9.useState)("");
@@ -1733,12 +1830,12 @@ function AdasChatScreen({
1733
1830
  if (!conversationLoaded) loadConversation();
1734
1831
  }, [conversationLoaded, loadConversation]);
1735
1832
  (0, import_react9.useEffect)(() => {
1736
- const unsub = import_core12.pluginCommandEmitter.on("prepare-chat-message", ({ text }) => {
1833
+ const unsub = import_core13.pluginCommandEmitter.on("prepare-chat-message", ({ text }) => {
1737
1834
  if (text) setPrefill(text);
1738
1835
  });
1739
1836
  return unsub;
1740
1837
  }, []);
1741
- const useInverted = import_react_native11.Platform.OS !== "web";
1838
+ const useInverted = import_react_native12.Platform.OS !== "web";
1742
1839
  const listData = (0, import_react9.useMemo)(
1743
1840
  () => useInverted ? [...messages].reverse() : messages,
1744
1841
  [messages, useInverted]
@@ -1763,23 +1860,23 @@ function AdasChatScreen({
1763
1860
  const renderItem = (0, import_react9.useCallback)(({ item, index }) => {
1764
1861
  const older = useInverted ? listData[index + 1] : listData[index - 1];
1765
1862
  const showDaySep = !older || !isSameDay2(older.timestamp, item.timestamp);
1766
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native11.View, { children: [
1767
- showDaySep && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DaySeparator, { date: item.timestamp }),
1768
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageBubble, { message: item })
1863
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native12.View, { children: [
1864
+ showDaySep && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DaySeparator, { date: item.timestamp }),
1865
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageBubble, { message: item })
1769
1866
  ] });
1770
1867
  }, [listData, useInverted]);
1771
- const typingIndicator = loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TypingIndicator, {}) : null;
1772
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1773
- import_react_native11.KeyboardAvoidingView,
1868
+ const typingIndicator = loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TypingIndicator, {}) : null;
1869
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1870
+ import_react_native12.KeyboardAvoidingView,
1774
1871
  {
1775
- style: styles10.root,
1776
- behavior: import_react_native11.Platform.OS === "ios" ? "padding" : void 0,
1872
+ style: styles11.root,
1873
+ behavior: import_react_native12.Platform.OS === "ios" ? "padding" : void 0,
1777
1874
  children: [
1778
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1779
- import_react_native11.FlatList,
1875
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1876
+ import_react_native12.FlatList,
1780
1877
  {
1781
1878
  ref: listRef,
1782
- style: styles10.list,
1879
+ style: styles11.list,
1783
1880
  data: listData,
1784
1881
  inverted: useInverted,
1785
1882
  keyExtractor: (m) => m.id,
@@ -1787,13 +1884,13 @@ function AdasChatScreen({
1787
1884
  ListHeaderComponent: useInverted ? typingIndicator : null,
1788
1885
  ListFooterComponent: useInverted ? null : typingIndicator,
1789
1886
  onContentSizeChange: useInverted ? void 0 : () => scrollToLatest(false),
1790
- refreshControl: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native11.RefreshControl, { refreshing, onRefresh: handleRefresh, tintColor: import_core12.ada.orange }),
1887
+ refreshControl: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.RefreshControl, { refreshing, onRefresh: handleRefresh, tintColor: import_core13.ada.orange }),
1791
1888
  keyboardShouldPersistTaps: "handled",
1792
- contentContainerStyle: styles10.listContent
1889
+ contentContainerStyle: styles11.listContent
1793
1890
  }
1794
1891
  ),
1795
1892
  footerAccessory,
1796
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1893
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1797
1894
  ChatInput,
1798
1895
  {
1799
1896
  onSend: handleSend,
@@ -1803,16 +1900,16 @@ function AdasChatScreen({
1803
1900
  placeholder
1804
1901
  }
1805
1902
  ),
1806
- withLightbox && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Lightbox, {}),
1807
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(WidgetHost, {})
1903
+ withLightbox && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Lightbox, {}),
1904
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WidgetHost, {})
1808
1905
  ]
1809
1906
  }
1810
1907
  );
1811
1908
  }
1812
- var styles10 = import_react_native11.StyleSheet.create({
1909
+ var styles11 = import_react_native12.StyleSheet.create({
1813
1910
  root: {
1814
1911
  flex: 1,
1815
- backgroundColor: import_core12.ada.paper
1912
+ backgroundColor: import_core13.ada.paper
1816
1913
  },
1817
1914
  list: {
1818
1915
  flex: 1
@@ -1824,42 +1921,42 @@ var styles10 = import_react_native11.StyleSheet.create({
1824
1921
 
1825
1922
  // src/widgets/WidgetWebView.tsx
1826
1923
  var import_react10 = require("react");
1827
- var import_react_native12 = require("react-native");
1924
+ var import_react_native13 = require("react-native");
1828
1925
  var import_react_native_webview2 = require("react-native-webview");
1829
- var import_core13 = require("@ateam-ai-mobile/core");
1830
1926
  var import_core14 = require("@ateam-ai-mobile/core");
1831
- var import_jsx_runtime13 = require("react/jsx-runtime");
1832
- var fontFam4 = import_react_native12.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1927
+ var import_core15 = require("@ateam-ai-mobile/core");
1928
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1929
+ var fontFam5 = import_react_native13.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1833
1930
  function WidgetWebView({ visible, title, bundleUrl, onClose }) {
1834
1931
  const [loading, setLoading] = (0, import_react10.useState)(true);
1835
1932
  const [error, setError] = (0, import_react10.useState)(null);
1836
1933
  const uri = (0, import_react10.useMemo)(() => {
1837
1934
  if (!bundleUrl) return null;
1838
1935
  if (/^https?:\/\//i.test(bundleUrl)) return bundleUrl;
1839
- return `${(0, import_core14.getCoreApiUrl)()}${bundleUrl}`;
1936
+ return `${(0, import_core15.getCoreApiUrl)()}${bundleUrl}`;
1840
1937
  }, [bundleUrl]);
1841
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1842
- import_react_native12.Modal,
1938
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1939
+ import_react_native13.Modal,
1843
1940
  {
1844
1941
  visible,
1845
1942
  animationType: "slide",
1846
1943
  presentationStyle: "pageSheet",
1847
1944
  onRequestClose: onClose,
1848
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native12.View, { style: styles11.root, children: [
1849
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native12.View, { style: styles11.bar, children: [
1850
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.Pressable, { onPress: onClose, hitSlop: 12, style: styles11.closeBtn, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.Text, { style: styles11.closeIcon, children: "\u2715" }) }),
1851
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.Text, { style: styles11.title, numberOfLines: 1, children: title || "Widget" }),
1852
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.View, { style: styles11.closeBtn })
1945
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native13.View, { style: styles12.root, children: [
1946
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native13.View, { style: styles12.bar, children: [
1947
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Pressable, { onPress: onClose, hitSlop: 12, style: styles12.closeBtn, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.closeIcon, children: "\u2715" }) }),
1948
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.title, numberOfLines: 1, children: title || "Widget" }),
1949
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { style: styles12.closeBtn })
1853
1950
  ] }),
1854
- !uri ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.View, { style: styles11.errorWrap, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.Text, { style: styles11.errorText, children: "No bundle available for this widget." }) }) : error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native12.View, { style: styles11.errorWrap, children: [
1855
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.Text, { style: styles11.errorText, children: "Couldn't load widget" }),
1856
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.Text, { style: styles11.errorSub, children: error })
1857
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1858
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1951
+ !uri ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { style: styles12.errorWrap, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.errorText, children: "No bundle available for this widget." }) }) : error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native13.View, { style: styles12.errorWrap, children: [
1952
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.errorText, children: "Couldn't load widget" }),
1953
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.errorSub, children: error })
1954
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1955
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1859
1956
  import_react_native_webview2.WebView,
1860
1957
  {
1861
1958
  source: { uri },
1862
- style: styles11.web,
1959
+ style: styles12.web,
1863
1960
  onLoadStart: () => {
1864
1961
  setLoading(true);
1865
1962
  setError(null);
@@ -1877,16 +1974,16 @@ function WidgetWebView({ visible, title, bundleUrl, onClose }) {
1877
1974
  setSupportMultipleWindows: false
1878
1975
  }
1879
1976
  ),
1880
- loading && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.View, { pointerEvents: "none", style: styles11.spinner, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.ActivityIndicator, { color: import_core13.ada.orange }) })
1977
+ loading && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { pointerEvents: "none", style: styles12.spinner, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.ActivityIndicator, { color: import_core14.ada.orange }) })
1881
1978
  ] })
1882
1979
  ] })
1883
1980
  }
1884
1981
  );
1885
1982
  }
1886
- var styles11 = import_react_native12.StyleSheet.create({
1983
+ var styles12 = import_react_native13.StyleSheet.create({
1887
1984
  root: {
1888
1985
  flex: 1,
1889
- backgroundColor: import_core13.ada.paper
1986
+ backgroundColor: import_core14.ada.paper
1890
1987
  },
1891
1988
  bar: {
1892
1989
  flexDirection: "row",
@@ -1894,8 +1991,8 @@ var styles11 = import_react_native12.StyleSheet.create({
1894
1991
  paddingHorizontal: 14,
1895
1992
  paddingVertical: 12,
1896
1993
  borderBottomWidth: 1,
1897
- borderBottomColor: import_core13.ada.border,
1898
- backgroundColor: import_core13.ada.paperSoft
1994
+ borderBottomColor: import_core14.ada.border,
1995
+ backgroundColor: import_core14.ada.paperSoft
1899
1996
  },
1900
1997
  closeBtn: {
1901
1998
  width: 32,
@@ -1905,7 +2002,7 @@ var styles11 = import_react_native12.StyleSheet.create({
1905
2002
  },
1906
2003
  closeIcon: {
1907
2004
  fontSize: 18,
1908
- color: import_core13.ada.ink,
2005
+ color: import_core14.ada.ink,
1909
2006
  fontWeight: "500"
1910
2007
  },
1911
2008
  title: {
@@ -1913,13 +2010,13 @@ var styles11 = import_react_native12.StyleSheet.create({
1913
2010
  textAlign: "center",
1914
2011
  fontSize: 16,
1915
2012
  fontWeight: "600",
1916
- color: import_core13.ada.ink,
1917
- fontFamily: fontFam4,
2013
+ color: import_core14.ada.ink,
2014
+ fontFamily: fontFam5,
1918
2015
  letterSpacing: -0.2
1919
2016
  },
1920
2017
  web: {
1921
2018
  flex: 1,
1922
- backgroundColor: import_core13.ada.paper
2019
+ backgroundColor: import_core14.ada.paper
1923
2020
  },
1924
2021
  spinner: {
1925
2022
  position: "absolute",
@@ -1936,31 +2033,31 @@ var styles11 = import_react_native12.StyleSheet.create({
1936
2033
  },
1937
2034
  errorText: {
1938
2035
  fontSize: 15,
1939
- color: import_core13.ada.ink,
2036
+ color: import_core14.ada.ink,
1940
2037
  fontWeight: "600",
1941
2038
  marginBottom: 6
1942
2039
  },
1943
2040
  errorSub: {
1944
2041
  fontSize: 13,
1945
- color: import_core13.ada.inkMuted,
2042
+ color: import_core14.ada.inkMuted,
1946
2043
  textAlign: "center"
1947
2044
  }
1948
2045
  });
1949
2046
 
1950
2047
  // src/TenantPicker.tsx
1951
2048
  var import_react11 = require("react");
1952
- var import_react_native13 = require("react-native");
1953
- var import_core15 = require("@ateam-ai-mobile/core");
1954
- var import_jsx_runtime14 = require("react/jsx-runtime");
1955
- var fontFam5 = import_react_native13.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
2049
+ var import_react_native14 = require("react-native");
2050
+ var import_core16 = require("@ateam-ai-mobile/core");
2051
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2052
+ var fontFam6 = import_react_native14.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
1956
2053
  function TenantPicker({ onSwitched, onSelect, currentTenantId }) {
1957
2054
  const [tenants, setTenants] = (0, import_react11.useState)(null);
1958
2055
  const [error, setError] = (0, import_react11.useState)(null);
1959
2056
  const [switching, setSwitching] = (0, import_react11.useState)(null);
1960
- const active = currentTenantId ?? (0, import_core15.getTenant)();
2057
+ const active = currentTenantId ?? (0, import_core16.getTenant)();
1961
2058
  (0, import_react11.useEffect)(() => {
1962
2059
  let cancelled = false;
1963
- (0, import_core15.listMyTenants)().then((list) => {
2060
+ (0, import_core16.listMyTenants)().then((list) => {
1964
2061
  if (!cancelled) setTenants(list);
1965
2062
  }).catch((e) => {
1966
2063
  if (!cancelled) setError(e?.message || "Failed to load teams");
@@ -1978,7 +2075,7 @@ function TenantPicker({ onSwitched, onSelect, currentTenantId }) {
1978
2075
  setError(null);
1979
2076
  setSwitching(t.id);
1980
2077
  try {
1981
- const session = await (0, import_core15.switchTenant)(t.id);
2078
+ const session = await (0, import_core16.switchTenant)(t.id);
1982
2079
  onSwitched?.(session);
1983
2080
  } catch (e) {
1984
2081
  setError(e?.message || "Could not switch team");
@@ -1986,36 +2083,36 @@ function TenantPicker({ onSwitched, onSelect, currentTenantId }) {
1986
2083
  setSwitching(null);
1987
2084
  }
1988
2085
  };
1989
- if (error) return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.error, children: error });
2086
+ if (error) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.error, children: error });
1990
2087
  if (!tenants) {
1991
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { style: styles12.loading, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.ActivityIndicator, { color: import_core15.ada.orange }) });
2088
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.loading, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.ActivityIndicator, { color: import_core16.ada.orange }) });
1992
2089
  }
1993
- if (tenants.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.empty, children: "No teams found for this account." });
1994
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { style: styles12.list, children: tenants.map((t) => {
2090
+ if (tenants.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.empty, children: "No teams found for this account." });
2091
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.list, children: tenants.map((t) => {
1995
2092
  const isActive = t.id === active;
1996
2093
  const isSwitching = switching === t.id;
1997
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1998
- import_react_native13.Pressable,
2094
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2095
+ import_react_native14.Pressable,
1999
2096
  {
2000
2097
  accessibilityRole: "button",
2001
2098
  accessibilityLabel: `Team ${t.name}${isActive ? ", current" : ""}`,
2002
2099
  disabled: !!switching,
2003
2100
  onPress: () => handlePress(t),
2004
- style: [styles12.row, isActive && styles12.rowActive],
2101
+ style: [styles13.row, isActive && styles13.rowActive],
2005
2102
  children: [
2006
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { style: styles12.dot }),
2007
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native13.View, { style: styles12.rowText, children: [
2008
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.name, children: t.name }),
2009
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.slug, children: t.id })
2103
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.dot }),
2104
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native14.View, { style: styles13.rowText, children: [
2105
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.name, children: t.name }),
2106
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.slug, children: t.id })
2010
2107
  ] }),
2011
- isSwitching ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.ActivityIndicator, { color: import_core15.ada.orange }) : isActive ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.check, children: "\u2713" }) : null
2108
+ isSwitching ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.ActivityIndicator, { color: import_core16.ada.orange }) : isActive ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.check, children: "\u2713" }) : null
2012
2109
  ]
2013
2110
  },
2014
2111
  t.id
2015
2112
  );
2016
2113
  }) });
2017
2114
  }
2018
- var styles12 = import_react_native13.StyleSheet.create({
2115
+ var styles13 = import_react_native14.StyleSheet.create({
2019
2116
  list: {
2020
2117
  gap: 10
2021
2118
  },
@@ -2023,40 +2120,40 @@ var styles12 = import_react_native13.StyleSheet.create({
2023
2120
  flexDirection: "row",
2024
2121
  alignItems: "center",
2025
2122
  gap: 12,
2026
- backgroundColor: import_core15.ada.paperSoft,
2027
- borderRadius: import_core15.borderRadius.lg,
2123
+ backgroundColor: import_core16.ada.paperSoft,
2124
+ borderRadius: import_core16.borderRadius.lg,
2028
2125
  borderWidth: 1,
2029
2126
  borderColor: "transparent",
2030
2127
  paddingHorizontal: 16,
2031
2128
  paddingVertical: 14
2032
2129
  },
2033
2130
  rowActive: {
2034
- backgroundColor: import_core15.ada.orangeSoft,
2035
- borderColor: import_core15.ada.orange
2131
+ backgroundColor: import_core16.ada.orangeSoft,
2132
+ borderColor: import_core16.ada.orange
2036
2133
  },
2037
2134
  dot: {
2038
2135
  width: 10,
2039
2136
  height: 10,
2040
2137
  borderRadius: 5,
2041
- backgroundColor: import_core15.ada.orange
2138
+ backgroundColor: import_core16.ada.orange
2042
2139
  },
2043
2140
  rowText: {
2044
2141
  flex: 1
2045
2142
  },
2046
2143
  name: {
2047
- color: import_core15.ada.ink,
2048
- fontSize: import_core15.fontSize.lg,
2144
+ color: import_core16.ada.ink,
2145
+ fontSize: import_core16.fontSize.lg,
2049
2146
  fontWeight: "600",
2050
- fontFamily: fontFam5
2147
+ fontFamily: fontFam6
2051
2148
  },
2052
2149
  slug: {
2053
- color: import_core15.ada.inkMuted,
2054
- fontSize: import_core15.fontSize.sm,
2150
+ color: import_core16.ada.inkMuted,
2151
+ fontSize: import_core16.fontSize.sm,
2055
2152
  fontFamily: "monospace"
2056
2153
  },
2057
2154
  check: {
2058
- color: import_core15.ada.orangeDeep,
2059
- fontSize: import_core15.fontSize.lg,
2155
+ color: import_core16.ada.orangeDeep,
2156
+ fontSize: import_core16.fontSize.lg,
2060
2157
  fontWeight: "700"
2061
2158
  },
2062
2159
  loading: {
@@ -2064,30 +2161,535 @@ var styles12 = import_react_native13.StyleSheet.create({
2064
2161
  alignItems: "center"
2065
2162
  },
2066
2163
  empty: {
2067
- color: import_core15.ada.inkMuted,
2068
- fontSize: import_core15.fontSize.md,
2164
+ color: import_core16.ada.inkMuted,
2165
+ fontSize: import_core16.fontSize.md,
2069
2166
  textAlign: "center",
2070
2167
  paddingVertical: 16
2071
2168
  },
2072
2169
  error: {
2073
2170
  color: "#C15545",
2074
- fontSize: import_core15.fontSize.md,
2171
+ fontSize: import_core16.fontSize.md,
2075
2172
  textAlign: "center",
2076
2173
  paddingVertical: 16
2077
2174
  }
2078
2175
  });
2079
2176
 
2080
- // src/voice/VoiceCallSheet.tsx
2081
- var import_react13 = require("react");
2082
- var import_react_native14 = require("react-native");
2083
- var import_react_native_svg2 = __toESM(require("react-native-svg"));
2084
- var import_react_native_webview3 = require("react-native-webview");
2177
+ // src/WorkspaceBanner.tsx
2178
+ var import_react_native15 = require("react-native");
2085
2179
  var import_core17 = require("@ateam-ai-mobile/core");
2180
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2181
+ var WARM_AMBER2 = "#D49A4E";
2182
+ var WARM_AMBER_SOFT2 = "rgba(212, 154, 78, 0.16)";
2183
+ var WARM_AMBER_BORDER = "rgba(212, 154, 78, 0.4)";
2184
+ function WorkspaceBanner({ topInset = 0 }) {
2185
+ const snapshot = (0, import_core17.useWorkspaceStore)((s) => s.snapshot);
2186
+ if (!snapshot) return null;
2187
+ if (snapshot.state === "active" || snapshot.state === "unknown") return null;
2188
+ if (!snapshot.message) return null;
2189
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2190
+ import_react_native15.View,
2191
+ {
2192
+ style: [styles14.container, { paddingTop: import_core17.spacing.sm + topInset }],
2193
+ accessibilityRole: "alert",
2194
+ accessibilityLabel: snapshot.message,
2195
+ children: [
2196
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native15.View, { style: styles14.dot }),
2197
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native15.Text, { style: styles14.message, children: snapshot.message })
2198
+ ]
2199
+ }
2200
+ );
2201
+ }
2202
+ var styles14 = import_react_native15.StyleSheet.create({
2203
+ container: {
2204
+ flexDirection: "row",
2205
+ alignItems: "flex-start",
2206
+ gap: import_core17.spacing.sm,
2207
+ paddingHorizontal: import_core17.spacing.md,
2208
+ paddingBottom: import_core17.spacing.sm,
2209
+ backgroundColor: WARM_AMBER_SOFT2,
2210
+ borderBottomWidth: import_react_native15.StyleSheet.hairlineWidth,
2211
+ borderBottomColor: WARM_AMBER_BORDER
2212
+ },
2213
+ dot: {
2214
+ width: 8,
2215
+ height: 8,
2216
+ borderRadius: 4,
2217
+ marginTop: 5,
2218
+ backgroundColor: WARM_AMBER2
2219
+ },
2220
+ message: {
2221
+ flex: 1,
2222
+ color: import_core17.ada.ink,
2223
+ fontSize: import_core17.fontSize.sm,
2224
+ lineHeight: import_core17.fontSize.sm * 1.35
2225
+ }
2226
+ });
2227
+
2228
+ // src/auth/HandoffScreen.tsx
2229
+ var import_react12 = require("react");
2230
+ var import_react_native16 = require("react-native");
2231
+ var import_core18 = require("@ateam-ai-mobile/core");
2086
2232
  var import_plugin_runtime9 = require("@ateam-ai-mobile/plugin-runtime");
2087
2233
 
2234
+ // src/auth/handoffExchange.ts
2235
+ async function runHandoffExchange(code, deps) {
2236
+ const res = await deps.exchange(code);
2237
+ if (res.tenant) await deps.onAdoptTenant(res.tenant);
2238
+ await deps.onSignedIn(res.jwt);
2239
+ deps.onDone();
2240
+ }
2241
+ function handoffErrorMessage(msg) {
2242
+ const m = (msg || "").toLowerCase();
2243
+ if (m.includes("429") || m.includes("rate") || m.includes("too many")) {
2244
+ return "Too many attempts \u2014 wait a moment, then get a new sign-in link on the web.";
2245
+ }
2246
+ return "This sign-in link is no longer valid. Get a new one on the web and try again.";
2247
+ }
2248
+
2249
+ // src/auth/HandoffScreen.tsx
2250
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2251
+ var fontFam7 = import_react_native16.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
2252
+ function HandoffScreen({ code, onAdoptTenant, onSignedIn, onDone, onCancel }) {
2253
+ const [err, setErr] = (0, import_react12.useState)(null);
2254
+ const startedForRef = (0, import_react12.useRef)(null);
2255
+ (0, import_react12.useEffect)(() => {
2256
+ if (!code || startedForRef.current === code) return;
2257
+ startedForRef.current = code;
2258
+ runHandoffExchange(code, { exchange: import_core18.exchangeHandoff, onAdoptTenant, onSignedIn, onDone }).catch((e) => setErr(handoffErrorMessage(e?.message)));
2259
+ }, [code, onAdoptTenant, onSignedIn, onDone]);
2260
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.View, { style: styles15.container, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native16.View, { style: styles15.center, children: [
2261
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_plugin_runtime9.AdaOrb, { size: 72, state: err ? "idle" : "thinking" }),
2262
+ !err ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2263
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.title, children: "Signing you in\u2026" }),
2264
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.ActivityIndicator, { color: import_core18.ada.ink, style: { marginTop: 6 } })
2265
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2266
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.title, children: "Couldn\u2019t finish sign-in" }),
2267
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.sub, children: err }),
2268
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Pressable, { onPress: onCancel, hitSlop: 8, style: styles15.back, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.backText, children: "Back to sign in" }) })
2269
+ ] })
2270
+ ] }) });
2271
+ }
2272
+ var styles15 = import_react_native16.StyleSheet.create({
2273
+ container: { flex: 1, backgroundColor: import_core18.ada.paper },
2274
+ center: { flex: 1, alignItems: "center", justifyContent: "center", gap: 14, paddingHorizontal: 32 },
2275
+ title: { fontSize: 20, fontWeight: "600", color: import_core18.ada.ink, fontFamily: fontFam7, marginTop: 8 },
2276
+ sub: { fontSize: 14, lineHeight: 20, color: import_core18.ada.inkSoft, textAlign: "center", fontFamily: fontFam7 },
2277
+ back: { marginTop: 10, paddingVertical: 10 },
2278
+ backText: { fontSize: 15, fontWeight: "600", color: import_core18.ada.orangeDeep, fontFamily: fontFam7 }
2279
+ });
2280
+
2281
+ // src/auth/OpenJoinScreen.tsx
2282
+ var import_react13 = require("react");
2283
+ var import_react_native17 = require("react-native");
2284
+ var import_core19 = require("@ateam-ai-mobile/core");
2285
+ var import_plugin_runtime10 = require("@ateam-ai-mobile/plugin-runtime");
2286
+
2287
+ // src/auth/openJoin.ts
2288
+ async function completeOpenJoin(slug, idToken, deps) {
2289
+ if (!idToken) return false;
2290
+ const consumer = await deps.join(slug, idToken);
2291
+ await deps.onAdoptTenant(slug);
2292
+ await deps.onSignedIn(consumer.jwt);
2293
+ return true;
2294
+ }
2295
+ function openJoinErrorMessage(msg) {
2296
+ const m = (msg || "").toLowerCase();
2297
+ if (m.includes("invite-only") || m.includes("invite only")) {
2298
+ return "This team is invite-only \u2014 ask an admin for an invite link.";
2299
+ }
2300
+ if (m.includes("not found") || m.includes("unknown tenant")) {
2301
+ return "No team with that handle.";
2302
+ }
2303
+ return msg || "Could not join";
2304
+ }
2305
+
2306
+ // src/auth/OpenJoinScreen.tsx
2307
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2308
+ var fontFam8 = import_react_native17.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
2309
+ function OpenJoinScreen({ onAdoptTenant, onSignedIn, onBack }) {
2310
+ const [team, setTeam] = (0, import_react13.useState)("");
2311
+ const [busy, setBusy] = (0, import_react13.useState)(false);
2312
+ const [err, setErr] = (0, import_react13.useState)(null);
2313
+ const [appleAvailable, setAppleAvailable] = (0, import_react13.useState)(false);
2314
+ (0, import_react13.useEffect)(() => {
2315
+ getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
2316
+ }, []);
2317
+ const slug = team.trim().toLowerCase();
2318
+ const canSubmit = slug.length > 0 && !busy;
2319
+ async function run(acquire, join) {
2320
+ if (!slug) return;
2321
+ const oauth = getOAuthProvider();
2322
+ if (!oauth) {
2323
+ setErr("Sign-in is unavailable on this device.");
2324
+ return;
2325
+ }
2326
+ setErr(null);
2327
+ setBusy(true);
2328
+ try {
2329
+ const idToken = await acquire(oauth);
2330
+ await completeOpenJoin(slug, idToken, { join, onAdoptTenant, onSignedIn });
2331
+ } catch (e) {
2332
+ setErr(openJoinErrorMessage(e?.message));
2333
+ } finally {
2334
+ setBusy(false);
2335
+ }
2336
+ }
2337
+ const handleGoogle = () => run((oauth) => oauth.signInWithGoogle(), import_core19.openJoinWithGoogle);
2338
+ const handleApple = () => run((oauth) => oauth.signInWithApple(), import_core19.openJoinWithApple);
2339
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native17.View, { style: styles16.container, children: [
2340
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native17.View, { style: styles16.hero, children: [
2341
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_plugin_runtime10.AdaOrb, { size: 110 }),
2342
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.wordmark, children: "Join a team" }),
2343
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.tagline, children: "Enter the team's handle. If it's open to join, you're in." })
2344
+ ] }),
2345
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native17.View, { style: styles16.form, children: [
2346
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2347
+ import_react_native17.TextInput,
2348
+ {
2349
+ style: styles16.input,
2350
+ value: team,
2351
+ onChangeText: setTeam,
2352
+ placeholder: "team handle (e.g. acme)",
2353
+ placeholderTextColor: import_core19.ada.inkMuted,
2354
+ autoCapitalize: "none",
2355
+ autoCorrect: false,
2356
+ returnKeyType: "done"
2357
+ }
2358
+ ),
2359
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2360
+ import_react_native17.Pressable,
2361
+ {
2362
+ style: [styles16.googleBtn, !canSubmit && styles16.btnDisabled],
2363
+ onPress: handleGoogle,
2364
+ disabled: !canSubmit,
2365
+ children: [
2366
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.googleGlyph, children: "G" }),
2367
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.googleText, children: "Continue with Google" })
2368
+ ]
2369
+ }
2370
+ ),
2371
+ appleAvailable && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.View, { style: { opacity: canSubmit ? 1 : 0.5 }, pointerEvents: canSubmit ? "auto" : "none", children: getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: !canSubmit, style: styles16.appleBtn }) }),
2372
+ busy && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.ActivityIndicator, { color: import_core19.ada.ink, style: { marginTop: 10 } }),
2373
+ !!err && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.err, children: err }),
2374
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Pressable, { onPress: onBack, hitSlop: 8, style: styles16.back, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.backText, children: "Back to sign in" }) })
2375
+ ] })
2376
+ ] });
2377
+ }
2378
+ var styles16 = import_react_native17.StyleSheet.create({
2379
+ container: { flex: 1, backgroundColor: import_core19.ada.paper, justifyContent: "space-between" },
2380
+ hero: { alignItems: "center", marginTop: import_core19.spacing.xxl },
2381
+ wordmark: { fontSize: 26, fontWeight: "800", color: import_core19.ada.ink, marginTop: 14, fontFamily: fontFam8 },
2382
+ tagline: { fontSize: 15, color: import_core19.ada.inkSoft, marginTop: 8, textAlign: "center", paddingHorizontal: 28, fontFamily: fontFam8 },
2383
+ form: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },
2384
+ input: {
2385
+ backgroundColor: import_core19.ada.paperSoft,
2386
+ borderWidth: 1,
2387
+ borderColor: import_core19.ada.border,
2388
+ borderRadius: 14,
2389
+ paddingHorizontal: 16,
2390
+ paddingVertical: 14,
2391
+ fontSize: 16,
2392
+ color: import_core19.ada.ink
2393
+ },
2394
+ googleBtn: {
2395
+ flexDirection: "row",
2396
+ alignItems: "center",
2397
+ justifyContent: "center",
2398
+ gap: 10,
2399
+ backgroundColor: import_core19.ada.ink,
2400
+ paddingVertical: 15,
2401
+ borderRadius: 999
2402
+ },
2403
+ btnDisabled: { opacity: 0.5 },
2404
+ googleGlyph: { color: "#fff", fontSize: 18, fontWeight: "800" },
2405
+ googleText: { color: "#fff", fontSize: 16, fontWeight: "600", fontFamily: fontFam8 },
2406
+ appleBtn: { height: 52, width: "100%" },
2407
+ err: { color: "#C15545", fontSize: 13, textAlign: "center", paddingHorizontal: 16, marginTop: 4 },
2408
+ back: { alignItems: "center", paddingVertical: 10 },
2409
+ backText: { color: import_core19.ada.inkMuted, fontSize: 15, fontWeight: "500" }
2410
+ });
2411
+
2412
+ // src/auth/JoinScreen.tsx
2413
+ var import_react14 = require("react");
2414
+ var import_react_native18 = require("react-native");
2415
+ var import_core20 = require("@ateam-ai-mobile/core");
2416
+ var import_plugin_runtime11 = require("@ateam-ai-mobile/plugin-runtime");
2417
+
2418
+ // src/auth/inviteJoin.ts
2419
+ async function completeInviteJoin(code, idToken, deps) {
2420
+ if (!idToken) return false;
2421
+ const consumer = await deps.join(code, idToken);
2422
+ deps.onDone();
2423
+ await deps.onSignedIn(consumer.jwt);
2424
+ return true;
2425
+ }
2426
+ function inviteHeadline(preview) {
2427
+ if (!preview) return "";
2428
+ return preview.role ? `Join ${preview.org} as ${preview.role}?` : `Join ${preview.org}?`;
2429
+ }
2430
+
2431
+ // src/auth/JoinScreen.tsx
2432
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2433
+ var fontFam9 = import_react_native18.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
2434
+ function JoinScreen({ code, onSignedIn, onDone, onCancel }) {
2435
+ const [preview, setPreview] = (0, import_react14.useState)(null);
2436
+ const [loadErr, setLoadErr] = (0, import_react14.useState)(null);
2437
+ const [busy, setBusy] = (0, import_react14.useState)(false);
2438
+ const [err, setErr] = (0, import_react14.useState)(null);
2439
+ const [appleAvailable, setAppleAvailable] = (0, import_react14.useState)(false);
2440
+ (0, import_react14.useEffect)(() => {
2441
+ if (!code) return;
2442
+ setPreview(null);
2443
+ setLoadErr(null);
2444
+ (0, import_core20.previewInvite)(code).then(setPreview).catch((e) => setLoadErr(e?.message || "Could not load invite"));
2445
+ }, [code]);
2446
+ (0, import_react14.useEffect)(() => {
2447
+ getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
2448
+ }, []);
2449
+ const orgLine = (0, import_react14.useMemo)(() => inviteHeadline(preview), [preview]);
2450
+ async function run(acquire, join) {
2451
+ if (!code) return;
2452
+ const oauth = getOAuthProvider();
2453
+ if (!oauth) {
2454
+ setErr("Sign-in is unavailable on this device.");
2455
+ return;
2456
+ }
2457
+ setErr(null);
2458
+ setBusy(true);
2459
+ try {
2460
+ const idToken = await acquire(oauth);
2461
+ await completeInviteJoin(code, idToken, { join, onDone, onSignedIn });
2462
+ } catch (e) {
2463
+ setErr(e?.message || "Sign-in failed");
2464
+ } finally {
2465
+ setBusy(false);
2466
+ }
2467
+ }
2468
+ const handleGoogle = () => run((oauth) => oauth.signInWithGoogle(), import_core20.joinWithGoogle);
2469
+ const handleApple = () => run((oauth) => oauth.signInWithApple(), import_core20.joinWithApple);
2470
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native18.View, { style: styles17.container, children: [
2471
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native18.View, { style: styles17.hero, children: [
2472
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_plugin_runtime11.AdaOrb, { size: 120 }),
2473
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.wordmark, children: "ada" }),
2474
+ loadErr ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.err, children: loadErr }) : preview ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.tagline, children: orgLine }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.ActivityIndicator, { color: import_core20.ada.ink, style: { marginTop: 12 } })
2475
+ ] }),
2476
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native18.View, { style: styles17.buttons, children: [
2477
+ preview && !loadErr && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2478
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2479
+ import_react_native18.Pressable,
2480
+ {
2481
+ style: [styles17.googleBtn, busy && styles17.btnDisabled],
2482
+ onPress: handleGoogle,
2483
+ disabled: busy,
2484
+ children: [
2485
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.googleGlyph, children: "G" }),
2486
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.googleText, children: "Continue with Google" })
2487
+ ]
2488
+ }
2489
+ ),
2490
+ appleAvailable && getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: busy, style: styles17.appleBtn })
2491
+ ] }),
2492
+ loadErr && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Pressable, { style: styles17.dismiss, onPress: onCancel, hitSlop: 8, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.dismissText, children: "Back to sign in" }) }),
2493
+ !!err && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.err, children: err }),
2494
+ busy && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.ActivityIndicator, { color: import_core20.ada.ink, style: { marginTop: 12 } }),
2495
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.disclaimer, children: "By continuing you agree to Ada's Terms and Privacy Policy." })
2496
+ ] })
2497
+ ] });
2498
+ }
2499
+ var styles17 = import_react_native18.StyleSheet.create({
2500
+ container: { flex: 1, backgroundColor: import_core20.ada.paper, justifyContent: "space-between" },
2501
+ hero: { alignItems: "center", marginTop: import_core20.spacing.xxl * 1.4 },
2502
+ wordmark: { fontSize: 34, fontWeight: "800", color: import_core20.ada.ink, letterSpacing: 4, marginTop: 12, fontFamily: fontFam9 },
2503
+ tagline: { fontSize: 17, color: import_core20.ada.inkSoft, marginTop: 10, textAlign: "center", paddingHorizontal: 24, fontFamily: fontFam9 },
2504
+ buttons: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },
2505
+ googleBtn: {
2506
+ flexDirection: "row",
2507
+ alignItems: "center",
2508
+ justifyContent: "center",
2509
+ gap: 10,
2510
+ backgroundColor: import_core20.ada.ink,
2511
+ paddingVertical: 15,
2512
+ borderRadius: 999
2513
+ },
2514
+ btnDisabled: { opacity: 0.5 },
2515
+ googleGlyph: { color: "#fff", fontSize: 18, fontWeight: "800" },
2516
+ googleText: { color: "#fff", fontSize: 16, fontWeight: "600", fontFamily: fontFam9 },
2517
+ appleBtn: { height: 52, width: "100%" },
2518
+ dismiss: { alignItems: "center", paddingVertical: 10 },
2519
+ dismissText: { color: import_core20.ada.inkMuted, fontSize: 15, fontWeight: "500" },
2520
+ err: { color: "#C15545", fontSize: 13, textAlign: "center", paddingHorizontal: 16, marginTop: 8 },
2521
+ disclaimer: { fontSize: 12, color: import_core20.ada.inkMuted, textAlign: "center", marginTop: 8 }
2522
+ });
2523
+
2524
+ // src/auth/LoginScreen.tsx
2525
+ var import_react15 = require("react");
2526
+ var import_react_native19 = require("react-native");
2527
+ var import_core21 = require("@ateam-ai-mobile/core");
2528
+ var import_plugin_runtime12 = require("@ateam-ai-mobile/plugin-runtime");
2529
+
2530
+ // src/auth/login.ts
2531
+ function googleClientIds(config) {
2532
+ const g = config.providers.google || {};
2533
+ return {
2534
+ webClientId: g.web_client_id || g.client_id || "",
2535
+ iosClientId: g.ios_client_id || ""
2536
+ };
2537
+ }
2538
+ function shouldRecoverToDefaultTenant(errorMsg, currentTenant, defaultTenant) {
2539
+ return /capability not enabled/i.test(errorMsg || "") && currentTenant !== defaultTenant;
2540
+ }
2541
+ async function completeProviderSignIn(idToken, deps) {
2542
+ if (!idToken) return false;
2543
+ const consumer = await deps.exchange(idToken);
2544
+ await deps.onSignedIn(consumer.jwt);
2545
+ return true;
2546
+ }
2547
+
2548
+ // src/auth/LoginScreen.tsx
2549
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2550
+ var fontFam10 = import_react_native19.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
2551
+ function LoginScreen({ activeTenant, defaultTenant, onConsumerDisabled, onSignedIn, onJoinTeam }) {
2552
+ const [config, setConfig] = (0, import_react15.useState)(null);
2553
+ const [error, setError] = (0, import_react15.useState)(null);
2554
+ (0, import_react15.useEffect)(() => {
2555
+ setConfig(null);
2556
+ setError(null);
2557
+ (0, import_core21.fetchConsumerConfig)().then(setConfig).catch(async (err) => {
2558
+ const msg = err?.message || "Failed to load sign-in config";
2559
+ if (shouldRecoverToDefaultTenant(msg, activeTenant, defaultTenant)) {
2560
+ await onConsumerDisabled();
2561
+ return;
2562
+ }
2563
+ setError(msg);
2564
+ });
2565
+ }, [activeTenant, defaultTenant, onConsumerDisabled]);
2566
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native19.View, { style: styles18.container, children: [
2567
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native19.View, { style: styles18.hero, children: [
2568
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_plugin_runtime12.AdaOrb, { size: 140 }),
2569
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.wordmark, children: "ada" }),
2570
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.tagline, children: "Your private personal AI-Team" })
2571
+ ] }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native19.View, { style: styles18.buttonSection, children: [
2573
+ !config && !error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.ActivityIndicator, { color: import_core21.ada.ink }),
2574
+ !!error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.errorText, children: error }),
2575
+ !!config && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SignInButtons, { config, onSignedIn }),
2576
+ onJoinTeam && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Pressable, { onPress: onJoinTeam, hitSlop: 8, style: { paddingVertical: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.joinLink, children: "Join a team by name" }) }),
2577
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.disclaimer, children: "By continuing you agree to Ada's Terms and Privacy Policy." })
2578
+ ] })
2579
+ ] });
2580
+ }
2581
+ function SignInButtons({ config, onSignedIn }) {
2582
+ const [busy, setBusy] = (0, import_react15.useState)(false);
2583
+ const [error, setError] = (0, import_react15.useState)(null);
2584
+ const [appleAvailable, setAppleAvailable] = (0, import_react15.useState)(false);
2585
+ const { webClientId, iosClientId } = (0, import_react15.useMemo)(() => googleClientIds(config), [config]);
2586
+ (0, import_react15.useEffect)(() => {
2587
+ getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
2588
+ }, []);
2589
+ const handleGoogleLogin = async () => {
2590
+ setError(null);
2591
+ if (!webClientId) {
2592
+ setError("Google sign-in is not configured for this tenant");
2593
+ return;
2594
+ }
2595
+ const oauth = getOAuthProvider();
2596
+ if (!oauth) {
2597
+ setError("Sign-in is unavailable on this device.");
2598
+ return;
2599
+ }
2600
+ setBusy(true);
2601
+ try {
2602
+ const idToken = await oauth.signInWithGoogle({ webClientId, iosClientId });
2603
+ await completeProviderSignIn(idToken, { exchange: import_core21.signInWithGoogle, onSignedIn });
2604
+ } catch (err) {
2605
+ setError(err?.message || "Sign-in failed");
2606
+ } finally {
2607
+ setBusy(false);
2608
+ }
2609
+ };
2610
+ const handleAppleLogin = async () => {
2611
+ setError(null);
2612
+ const oauth = getOAuthProvider();
2613
+ if (!oauth) {
2614
+ setError("Sign-in is unavailable on this device.");
2615
+ return;
2616
+ }
2617
+ setBusy(true);
2618
+ try {
2619
+ const idToken = await oauth.signInWithApple();
2620
+ await completeProviderSignIn(idToken, { exchange: import_core21.signInWithApple, onSignedIn });
2621
+ } catch (err) {
2622
+ setError(err?.message || "Apple sign-in failed");
2623
+ } finally {
2624
+ setBusy(false);
2625
+ }
2626
+ };
2627
+ const googleEnabled = !!webClientId && !busy;
2628
+ const appleEnabled = appleAvailable && !!config.providers.apple?.service_id && !busy;
2629
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
2630
+ !!config.providers.google && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2631
+ import_react_native19.Pressable,
2632
+ {
2633
+ style: [styles18.signInBtn, !googleEnabled && styles18.signInBtnDisabled],
2634
+ onPress: handleGoogleLogin,
2635
+ disabled: !googleEnabled,
2636
+ children: [
2637
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.signInGlyph, children: "G" }),
2638
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.signInText, children: "Continue with Google" })
2639
+ ]
2640
+ }
2641
+ ),
2642
+ appleEnabled && getOAuthProvider()?.renderAppleButton({ onPress: handleAppleLogin, disabled: busy, style: styles18.appleBtn }),
2643
+ !!error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.errorText, children: error }),
2644
+ busy && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.ActivityIndicator, { color: import_core21.ada.ink })
2645
+ ] });
2646
+ }
2647
+ var styles18 = import_react_native19.StyleSheet.create({
2648
+ container: {
2649
+ flex: 1,
2650
+ backgroundColor: import_core21.ada.paper,
2651
+ justifyContent: "space-between",
2652
+ paddingHorizontal: 32,
2653
+ paddingBottom: 24
2654
+ },
2655
+ hero: { flex: 1, alignItems: "center", justifyContent: "center", gap: 18 },
2656
+ wordmark: { fontSize: 32, fontWeight: "600", color: import_core21.ada.ink, letterSpacing: 4, fontFamily: fontFam10, marginTop: 8 },
2657
+ tagline: { fontSize: 16, fontWeight: "500", color: import_core21.ada.inkSoft, letterSpacing: -0.1, fontFamily: fontFam10 },
2658
+ buttonSection: { alignItems: "center", gap: 12 },
2659
+ signInBtn: {
2660
+ flexDirection: "row",
2661
+ alignItems: "center",
2662
+ justifyContent: "center",
2663
+ backgroundColor: import_core21.ada.ink,
2664
+ paddingVertical: 16,
2665
+ paddingHorizontal: 24,
2666
+ borderRadius: 999,
2667
+ width: "100%",
2668
+ gap: 12
2669
+ },
2670
+ signInBtnDisabled: { opacity: 0.5 },
2671
+ signInGlyph: { fontSize: 18, fontWeight: "700", color: import_core21.ada.paper, fontFamily: fontFam10 },
2672
+ signInText: { fontSize: 16, fontWeight: "600", color: import_core21.ada.paper, letterSpacing: -0.2, fontFamily: fontFam10 },
2673
+ appleBtn: { width: "100%", height: 52 },
2674
+ errorText: { fontSize: 13, color: "#c43d3d", textAlign: "center", paddingHorizontal: 16 },
2675
+ disclaimer: { fontSize: 12, color: import_core21.ada.inkMuted, textAlign: "center", marginTop: 8, lineHeight: 18, fontFamily: fontFam10 },
2676
+ joinLink: { fontSize: 14, fontWeight: "600", color: import_core21.ada.orangeDeep, textAlign: "center", fontFamily: fontFam10 }
2677
+ });
2678
+
2679
+ // src/voice/VoiceCallSheet.tsx
2680
+ var import_react17 = require("react");
2681
+ var import_react_native20 = require("react-native");
2682
+ var import_react_native_svg2 = __toESM(require("react-native-svg"));
2683
+ var import_core23 = require("@ateam-ai-mobile/core");
2684
+ var import_plugin_runtime14 = require("@ateam-ai-mobile/plugin-runtime");
2685
+
2088
2686
  // src/voice/useVoiceCall.ts
2089
- var import_react12 = require("react");
2090
- var import_core16 = require("@ateam-ai-mobile/core");
2687
+ var import_react16 = require("react");
2688
+
2689
+ // src/voice/voiceSession.ts
2690
+ var import_core22 = require("@ateam-ai-mobile/core");
2691
+ var import_plugin_runtime13 = require("@ateam-ai-mobile/plugin-runtime");
2692
+ var CONNECT_TIMEOUT_MS = 3e4;
2091
2693
  var TOKEN_REFRESH_SKEW_MS = 9e4;
2092
2694
  function tokenNeedsRefresh(token) {
2093
2695
  if (!token) return true;
@@ -2115,7 +2717,6 @@ var INJECT_TRACK_HOOK = `
2115
2717
  }
2116
2718
  }
2117
2719
 
2118
- // 1) Hook getUserMedia \u2014 captures mic streams at request time.
2119
2720
  try {
2120
2721
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
2121
2722
  const origGUM = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
@@ -2129,7 +2730,6 @@ var INJECT_TRACK_HOOK = `
2129
2730
  }
2130
2731
  } catch (e) {}
2131
2732
 
2132
- // 2) Hook RTCPeerConnection.addTrack \u2014 catches whatever the app sends.
2133
2733
  try {
2134
2734
  if (window.RTCPeerConnection) {
2135
2735
  const origPC = window.RTCPeerConnection;
@@ -2149,9 +2749,7 @@ var INJECT_TRACK_HOOK = `
2149
2749
  }
2150
2750
  if (origAddTransceiver) {
2151
2751
  origPC.prototype.addTransceiver = function(arg) {
2152
- if (arg && arg.kind === 'audio') {
2153
- // Transceiver created with kind 'audio' \u2014 sender track set later.
2154
- } else if (arg && arg.kind === undefined && arg.track && arg.track.kind === 'audio') {
2752
+ if (arg && arg.kind === undefined && arg.track && arg.track.kind === 'audio') {
2155
2753
  track(arg.track);
2156
2754
  }
2157
2755
  const tx = origAddTransceiver.apply(this, arguments);
@@ -2164,7 +2762,6 @@ var INJECT_TRACK_HOOK = `
2164
2762
  }
2165
2763
  } catch (e) {}
2166
2764
 
2167
- // 3) Helper exposed for direct calls.
2168
2765
  window._adaSetMuted = function(muted) {
2169
2766
  let n = 0;
2170
2767
  if (Array.isArray(window._allAudioTracks)) {
@@ -2183,7 +2780,6 @@ var buildMuteScript = (muted) => `
2183
2780
  if (typeof window._adaSetMuted === 'function') {
2184
2781
  n = window._adaSetMuted(muted);
2185
2782
  }
2186
- // Last-resort scan if hook somehow missed.
2187
2783
  if (n === 0 && Array.isArray(window._allAudioTracks)) {
2188
2784
  window._allAudioTracks.forEach(function(t) {
2189
2785
  try { t.enabled = !muted; n++; } catch (e) {}
@@ -2192,104 +2788,413 @@ var buildMuteScript = (muted) => `
2192
2788
  console.log('[ada-mute]', muted ? 'MUTED' : 'UNMUTED', 'tracks=', n);
2193
2789
  })(${muted}); true;
2194
2790
  `;
2195
- function useVoiceCall({ skillSlug } = {}) {
2196
- const [callState, setCallState] = (0, import_react12.useState)("idle");
2197
- const [sessionId, setSessionId] = (0, import_react12.useState)(null);
2198
- const [error, setError] = (0, import_react12.useState)(null);
2199
- const [transcript, setTranscript] = (0, import_react12.useState)([]);
2200
- const [aiPartial, setAiPartial] = (0, import_react12.useState)("");
2201
- const [userPartial, setUserPartial] = (0, import_react12.useState)("");
2202
- const [muted, setMuted] = (0, import_react12.useState)(false);
2203
- const webViewRef = (0, import_react12.useRef)(null);
2204
- const handleWebViewMessage = (0, import_react12.useCallback)((event) => {
2791
+ var buildAgentTurnScript = (input) => `
2792
+ (function(input) {
2793
+ if (typeof window.__adasAgentTurn === 'function') {
2794
+ try { window.__adasAgentTurn(input); }
2795
+ catch (e) {
2796
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({
2797
+ type: 'agentTurnFailed', message: String(e && e.message || e),
2798
+ }));
2799
+ }
2800
+ } else if (window.ReactNativeWebView) {
2801
+ window.ReactNativeWebView.postMessage(JSON.stringify({
2802
+ type: 'agentTurnUnsupported',
2803
+ message: 'voice app does not support agent turns (__adasAgentTurn missing) \u2014 update the voice page',
2804
+ }));
2805
+ }
2806
+ })(${JSON.stringify(input)}); true;
2807
+ `;
2808
+ var buildObserveScript = (text) => `
2809
+ (function(text) {
2810
+ if (typeof window.__adasObserve === 'function') {
2811
+ try { window.__adasObserve(text); }
2812
+ catch (e) {
2813
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({
2814
+ type: 'observeFailed', message: String(e && e.message || e),
2815
+ }));
2816
+ }
2817
+ } else if (window.ReactNativeWebView) {
2818
+ window.ReactNativeWebView.postMessage(JSON.stringify({
2819
+ type: 'observeUnsupported',
2820
+ message: 'voice app does not support observe (__adasObserve missing) \u2014 update the voice page',
2821
+ }));
2822
+ }
2823
+ })(${JSON.stringify(text)}); true;
2824
+ `;
2825
+ function originOf(url) {
2826
+ if (!url) return null;
2827
+ const m = /^([a-z][a-z0-9+.-]*:\/\/[^/?#]+)/i.exec(url);
2828
+ return m ? m[1].toLowerCase() : null;
2829
+ }
2830
+ var IDLE = {
2831
+ callState: "idle",
2832
+ sessionId: null,
2833
+ error: null,
2834
+ transcript: [],
2835
+ aiPartial: "",
2836
+ userPartial: "",
2837
+ muted: false,
2838
+ userSpeaking: false,
2839
+ lastUserSpeechEndedAt: null,
2840
+ mounted: false,
2841
+ webViewSource: null,
2842
+ skillSlug: void 0
2843
+ };
2844
+ var VoiceSessionManager = class {
2845
+ constructor() {
2846
+ this.state = { ...IDLE };
2847
+ this.listeners = /* @__PURE__ */ new Set();
2848
+ this.webView = null;
2849
+ this.pending = [];
2850
+ /**
2851
+ * WHO owns the one physical session. Set to the caller that started it from
2852
+ * idle (a plugin's pluginId, or the PLATFORM symbol for the built-in sheet),
2853
+ * and kept after stop until the next start reassigns it — so a plugin can read
2854
+ * its own just-ended transcript but another plugin never can.
2855
+ *
2856
+ * ISOLATION (GPT blocker on 8881225): every access is scoped through this. A
2857
+ * different plugin must not read, control, or attach to another plugin's live
2858
+ * conversation just because it declared voice.
2859
+ */
2860
+ this.owner = null;
2861
+ this.injectedTrackHook = INJECT_TRACK_HOOK;
2862
+ }
2863
+ /** The platform (built-in sheet, mic indicator, session host) sees and
2864
+ * controls any session — it is the user's own surface. A plugin caller may
2865
+ * only touch a session it owns. */
2866
+ canAccess(caller) {
2867
+ return caller === import_plugin_runtime13.PLATFORM_VOICE_CALLER || this.owner === caller;
2868
+ }
2869
+ foreignError() {
2870
+ const err = new Error(
2871
+ "voice: another solution is using the microphone \u2014 one live session per device."
2872
+ );
2873
+ err.code = "RESTRICTED";
2874
+ return err;
2875
+ }
2876
+ // ── Host wiring (used only by VoiceSessionHost) ──────────────
2877
+ /** The offscreen WebView sets its ref here so the session can inject into it. */
2878
+ setWebView(ref) {
2879
+ this.webView = ref;
2880
+ }
2881
+ /** Whole state — the host reads `mounted` + `webViewSource` to decide what to
2882
+ * render, and every reader derives its snapshot from this. */
2883
+ getInternal() {
2884
+ return this.state;
2885
+ }
2886
+ // ── VoiceAPI (what props.voice and useVoiceCall call) ────────
2887
+ async start(opts, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2888
+ if (this.state.callState === "connected") {
2889
+ if (!this.canAccess(caller)) throw this.foreignError();
2890
+ return this.realSnapshot();
2891
+ }
2892
+ if (this.state.callState === "connecting") {
2893
+ if (!this.canAccess(caller)) throw this.foreignError();
2894
+ return this.waitForConnect();
2895
+ }
2205
2896
  try {
2206
- const data = JSON.parse(event.nativeEvent.data);
2207
- console.log("[VoiceWebView] message:", data.type, data.text?.slice?.(0, 50) || data.state || "");
2208
- switch (data.type) {
2209
- case "callState":
2210
- case "call-state":
2211
- setCallState(data.state);
2212
- if (data.sessionId) setSessionId(data.sessionId);
2213
- if (data.error) setError(data.error);
2214
- break;
2215
- case "transcript":
2216
- setTranscript((prev) => [...prev, { role: data.role, text: data.text, ts: Date.now() }]);
2217
- break;
2218
- case "aiPartial":
2219
- setAiPartial(data.text);
2220
- break;
2221
- case "userPartial":
2222
- setUserPartial(data.text);
2223
- break;
2224
- case "clearPartials":
2225
- setAiPartial("");
2226
- setUserPartial("");
2227
- break;
2228
- case "error":
2229
- setError(data.message);
2230
- setCallState("error");
2897
+ await (0, import_plugin_runtime13.ensureDeviceToolsLoaded)();
2898
+ } catch (e) {
2899
+ console.warn("[voiceSession] device tool preload failed:", e?.message || String(e));
2900
+ }
2901
+ try {
2902
+ if (tokenNeedsRefresh((0, import_core22.getToken)())) await (0, import_core22.refreshToken)();
2903
+ } catch {
2904
+ }
2905
+ this.owner = caller;
2906
+ const skillSlug = opts?.skillSlug;
2907
+ this.setState({
2908
+ callState: "connecting",
2909
+ error: null,
2910
+ transcript: [],
2911
+ aiPartial: "",
2912
+ userPartial: "",
2913
+ muted: false,
2914
+ mounted: true,
2915
+ skillSlug,
2916
+ webViewSource: { uri: this.buildUri(skillSlug) }
2917
+ });
2918
+ return this.waitForConnect();
2919
+ }
2920
+ stop(caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2921
+ if (this.state.callState !== "idle" && !this.canAccess(caller)) throw this.foreignError();
2922
+ this.webView?.injectJavaScript?.("window.hangUp && window.hangUp(); true;");
2923
+ this.rejectPending(new Error("voice: session stopped before it connected"));
2924
+ this.setState({
2925
+ ...IDLE,
2926
+ // keep the transcript of the call that just ended for any reader still up
2927
+ transcript: this.state.transcript
2928
+ });
2929
+ }
2930
+ setMuted(muted, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2931
+ if (this.state.callState !== "idle" && !this.canAccess(caller)) throw this.foreignError();
2932
+ this.webView?.injectJavaScript?.(buildMuteScript(muted));
2933
+ this.setState({ muted });
2934
+ }
2935
+ prompt(input, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2936
+ if (this.state.callState !== "connected") {
2937
+ throw new Error("voice: session is not connected \u2014 call start() and await it before prompt().");
2938
+ }
2939
+ if (!this.canAccess(caller)) throw this.foreignError();
2940
+ this.webView?.injectJavaScript?.(buildAgentTurnScript(input));
2941
+ }
2942
+ /**
2943
+ * Stream a silent observation into the live session — tell the model without
2944
+ * asking it to speak. The cheap, high-frequency channel (safe once or twice a
2945
+ * second) behind a future props.voice.observe(); today the host uses it to run
2946
+ * the real-device stream proof (VOICE_RT_STREAM_DEVICE_PROOF) before the gated
2947
+ * plugin API is added. Owner-scoped like every other control.
2948
+ */
2949
+ observe(text, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2950
+ if (this.state.callState !== "connected") {
2951
+ throw new Error("voice: session is not connected \u2014 observe() needs a live session.");
2952
+ }
2953
+ if (!this.canAccess(caller)) throw this.foreignError();
2954
+ this.webView?.injectJavaScript?.(buildObserveScript(text));
2955
+ }
2956
+ getSnapshot(caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2957
+ return this.canAccess(caller) ? this.realSnapshot() : this.foreignSnapshot();
2958
+ }
2959
+ realSnapshot() {
2960
+ const s = this.state;
2961
+ return {
2962
+ state: s.callState,
2963
+ sessionId: s.sessionId,
2964
+ muted: s.muted,
2965
+ speaking: !!s.aiPartial,
2966
+ listening: !!s.userPartial,
2967
+ userSpeaking: s.userSpeaking,
2968
+ lastUserSpeechEndedAt: s.lastUserSpeechEndedAt,
2969
+ lastError: s.error
2970
+ };
2971
+ }
2972
+ foreignSnapshot() {
2973
+ return {
2974
+ state: "idle",
2975
+ sessionId: null,
2976
+ muted: false,
2977
+ speaking: false,
2978
+ listening: false,
2979
+ userSpeaking: false,
2980
+ lastUserSpeechEndedAt: null,
2981
+ lastError: null
2982
+ };
2983
+ }
2984
+ subscribe(cb, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2985
+ const wrapped = (event) => {
2986
+ if (this.canAccess(caller)) cb(event);
2987
+ };
2988
+ this.listeners.add(wrapped);
2989
+ return { unsubscribe: () => {
2990
+ this.listeners.delete(wrapped);
2991
+ } };
2992
+ }
2993
+ transcript(caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
2994
+ return this.canAccess(caller) ? this.state.transcript.slice() : [];
2995
+ }
2996
+ // ── WebView plumbing ─────────────────────────────────────────
2997
+ buildUri(skillSlug) {
2998
+ const token = (0, import_core22.getToken)();
2999
+ const tenant = (0, import_core22.getTenant)();
3000
+ const actorId = (0, import_core22.getUser)()?.actorId || "";
3001
+ const skillParam = skillSlug ? `&skillSlug=${encodeURIComponent(skillSlug)}` : "";
3002
+ return `${(0, import_core22.getVoiceApiUrl)()}/app?mode=mini&embedded=rn&authToken=${encodeURIComponent(token || "")}&tenant=${encodeURIComponent(tenant)}&actorId=${encodeURIComponent(actorId)}${skillParam}`;
3003
+ }
3004
+ /** Handle a postMessage from the WebView. `event` is the RN WebView event. */
3005
+ handleMessage(event) {
3006
+ let data;
3007
+ try {
3008
+ data = JSON.parse(event.nativeEvent.data);
3009
+ } catch {
3010
+ return;
3011
+ }
3012
+ switch (data.type) {
3013
+ case "callState":
3014
+ case "call-state":
3015
+ if (data.state) this.setState({ callState: data.state });
3016
+ if (data.sessionId) this.setState({ sessionId: data.sessionId });
3017
+ if (data.error) this.setState({ error: data.error });
3018
+ if (data.state === "connected") this.resolvePending();
3019
+ if (data.state === "error") this.rejectPending(new Error(data.error || "voice: connection error"));
3020
+ break;
3021
+ case "transcript":
3022
+ this.appendTranscript({ role: data.role, text: data.text, ts: Date.now() });
3023
+ break;
3024
+ case "aiPartial":
3025
+ this.setState({ aiPartial: data.text });
3026
+ break;
3027
+ case "userPartial":
3028
+ this.setState({ userPartial: data.text });
3029
+ break;
3030
+ case "clearPartials":
3031
+ this.setState({ aiPartial: "", userPartial: "" });
3032
+ break;
3033
+ // User VAD from the mini-app. `at` is when it happened; on speaking:false
3034
+ // we stamp lastUserSpeechEndedAt so a solution can gate "speak after N s of
3035
+ // silence" on the first real stop, never before the user has spoken.
3036
+ case "speechActivity": {
3037
+ const speaking = !!data.speaking;
3038
+ const at = typeof data.at === "number" ? data.at : Date.now();
3039
+ this.setState(
3040
+ speaking ? { userSpeaking: true } : { userSpeaking: false, lastUserSpeechEndedAt: at }
3041
+ );
3042
+ break;
3043
+ }
3044
+ case "error":
3045
+ this.setState({ error: data.message, callState: "error" });
3046
+ this.rejectPending(new Error(data.message || "voice: error"));
3047
+ break;
3048
+ // A proactive turn couldn't run (older voice page / hook threw). NON-FATAL:
3049
+ // the session stays live; we only surface why the guide didn't speak.
3050
+ case "agentTurnUnsupported":
3051
+ case "agentTurnFailed":
3052
+ case "observeUnsupported":
3053
+ case "observeFailed":
3054
+ this.setState({ error: data.message || "voice: channel notice" });
3055
+ break;
3056
+ // Device tools — executed locally, origin-checked. The model's function
3057
+ // call already arrived on this phone; only the voice app's own origin may
3058
+ // drive the camera/GPS.
3059
+ case "device-tool-list": {
3060
+ const listSender = originOf(event?.nativeEvent?.url);
3061
+ const listExpected = originOf((0, import_core22.getVoiceApiUrl)());
3062
+ if (!listSender || !listExpected || listSender !== listExpected) break;
3063
+ this.sendDeviceToolList(data.correlationId);
3064
+ break;
3065
+ }
3066
+ case "device-tool-call": {
3067
+ const sender = originOf(event?.nativeEvent?.url);
3068
+ const expected = originOf((0, import_core22.getVoiceApiUrl)());
3069
+ if (!sender || !expected || sender !== expected) {
3070
+ console.warn(`[voiceSession] REFUSED device tool call from "${sender || "unknown origin"}" (expected "${expected}")`);
2231
3071
  break;
3072
+ }
3073
+ void this.runDeviceTool(data);
3074
+ break;
2232
3075
  }
2233
- } catch {
2234
3076
  }
2235
- }, []);
2236
- const startCall = (0, import_react12.useCallback)(async () => {
2237
- setError(null);
2238
- setTranscript([]);
2239
- setAiPartial("");
2240
- setUserPartial("");
3077
+ }
3078
+ /** Answer "what device tools do you have?" — the client is the authority. */
3079
+ sendDeviceToolList(correlationId) {
3080
+ const tools = (0, import_plugin_runtime13.listDeviceTools)().map((t) => ({
3081
+ name: t.name,
3082
+ description: t.description,
3083
+ input_schema: t.input_schema
3084
+ }));
3085
+ this.webView?.injectJavaScript?.(
3086
+ `window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(
3087
+ JSON.stringify({ correlationId, ok: true, tools })
3088
+ )}); true;`
3089
+ );
3090
+ }
3091
+ /** Run a device tool and post the outcome back into the WebView. */
3092
+ async runDeviceTool(data) {
3093
+ const { correlationId, name, args, timeoutMs } = data || {};
3094
+ if (!correlationId || typeof name !== "string") return;
3095
+ let payload;
2241
3096
  try {
2242
- if (tokenNeedsRefresh((0, import_core16.getToken)())) {
2243
- await (0, import_core16.refreshToken)();
3097
+ const outcome = await (0, import_plugin_runtime13.callDeviceTool)(name, args || {}, { timeoutMs });
3098
+ payload = outcome.ok ? { correlationId, ok: true, result: outcome.result } : { correlationId, ok: false, error: outcome.error, reason: outcome.reason };
3099
+ } catch (err) {
3100
+ payload = { correlationId, ok: false, reason: "failed", error: err?.message || String(err) };
3101
+ }
3102
+ this.webView?.injectJavaScript?.(
3103
+ `window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(
3104
+ JSON.stringify(payload)
3105
+ )}); true;`
3106
+ );
3107
+ }
3108
+ // ── internals ────────────────────────────────────────────────
3109
+ setState(partial) {
3110
+ this.state = { ...this.state, ...partial };
3111
+ this.emit({ type: "state" });
3112
+ }
3113
+ appendTranscript(entry) {
3114
+ this.state = { ...this.state, transcript: [...this.state.transcript, entry] };
3115
+ this.emit({ type: "transcript" });
3116
+ }
3117
+ emit(event) {
3118
+ for (const cb of this.listeners) {
3119
+ try {
3120
+ cb(event);
3121
+ } catch (e) {
3122
+ console.warn("[voiceSession] listener threw", e);
2244
3123
  }
2245
- } catch {
2246
3124
  }
2247
- setCallState("connecting");
2248
- }, []);
2249
- const stopCall = (0, import_react12.useCallback)(() => {
2250
- webViewRef.current?.injectJavaScript?.("window.hangUp && window.hangUp(); true;");
2251
- setCallState("idle");
2252
- setAiPartial("");
2253
- setUserPartial("");
2254
- setMuted(false);
2255
- }, []);
2256
- const toggleMute = (0, import_react12.useCallback)(() => {
2257
- setMuted((prev) => {
2258
- const next = !prev;
2259
- webViewRef.current?.injectJavaScript?.(buildMuteScript(next));
2260
- return next;
3125
+ }
3126
+ waitForConnect() {
3127
+ return new Promise((resolve, reject) => {
3128
+ const timer = setTimeout(() => {
3129
+ this.pending = this.pending.filter((p) => p.timer !== timer);
3130
+ reject(new Error("voice: timed out waiting to connect (is VoiceSessionHost mounted?)"));
3131
+ }, CONNECT_TIMEOUT_MS);
3132
+ this.pending.push({ resolve, reject, timer });
2261
3133
  });
3134
+ }
3135
+ resolvePending() {
3136
+ const snap = this.realSnapshot();
3137
+ const waiting = this.pending;
3138
+ this.pending = [];
3139
+ for (const p of waiting) {
3140
+ clearTimeout(p.timer);
3141
+ p.resolve(snap);
3142
+ }
3143
+ }
3144
+ rejectPending(err) {
3145
+ const waiting = this.pending;
3146
+ this.pending = [];
3147
+ for (const p of waiting) {
3148
+ clearTimeout(p.timer);
3149
+ p.reject(err);
3150
+ }
3151
+ }
3152
+ /** TEST ONLY: reset the singleton to a clean idle state (mirrors the
3153
+ * __resetSessionSyncForTest precedent). Not part of any surface. */
3154
+ __resetForTest() {
3155
+ this.rejectPending(new Error("voice: reset"));
3156
+ this.state = { ...IDLE };
3157
+ this.owner = null;
3158
+ this.listeners.clear();
3159
+ this.webView = null;
3160
+ }
3161
+ };
3162
+ var voiceSession = new VoiceSessionManager();
3163
+
3164
+ // src/voice/useVoiceCall.ts
3165
+ function useVoiceCall({ skillSlug } = {}) {
3166
+ const [, force] = (0, import_react16.useReducer)((x) => x + 1, 0);
3167
+ (0, import_react16.useEffect)(() => {
3168
+ const sub = voiceSession.subscribe(() => force());
3169
+ return () => sub.unsubscribe();
2262
3170
  }, []);
2263
- const getWebViewSource = (0, import_react12.useCallback)(() => {
2264
- const token = (0, import_core16.getToken)();
2265
- const tenant = (0, import_core16.getTenant)();
2266
- const actorId = (0, import_core16.getUser)()?.actorId || "";
2267
- const skillParam = skillSlug ? `&skillSlug=${encodeURIComponent(skillSlug)}` : "";
2268
- return {
2269
- uri: `${(0, import_core16.getVoiceApiUrl)()}/app?mode=mini&embedded=rn&authToken=${encodeURIComponent(token || "")}&tenant=${encodeURIComponent(tenant)}&actorId=${encodeURIComponent(actorId)}${skillParam}`
2270
- };
2271
- }, [skillSlug]);
3171
+ const s = voiceSession.getInternal();
3172
+ const startCall = (0, import_react16.useCallback)(
3173
+ (opts) => voiceSession.start(opts ?? { skillSlug }),
3174
+ [skillSlug]
3175
+ );
3176
+ const stopCall = (0, import_react16.useCallback)(() => voiceSession.stop(), []);
3177
+ const toggleMute = (0, import_react16.useCallback)(
3178
+ () => voiceSession.setMuted(!voiceSession.getSnapshot().muted),
3179
+ []
3180
+ );
2272
3181
  return {
2273
- callState,
2274
- sessionId,
2275
- error,
2276
- transcript,
2277
- aiPartial,
2278
- userPartial,
2279
- muted,
3182
+ callState: s.callState,
3183
+ sessionId: s.sessionId,
3184
+ error: s.error,
3185
+ transcript: s.transcript,
3186
+ aiPartial: s.aiPartial,
3187
+ userPartial: s.userPartial,
3188
+ muted: s.muted,
2280
3189
  startCall,
2281
3190
  stopCall,
2282
- toggleMute,
2283
- handleWebViewMessage,
2284
- getWebViewSource,
2285
- webViewRef,
2286
- injectedTrackHook: INJECT_TRACK_HOOK
3191
+ toggleMute
2287
3192
  };
2288
3193
  }
2289
3194
 
2290
3195
  // src/voice/VoiceCallSheet.tsx
2291
- var import_jsx_runtime15 = require("react/jsx-runtime");
2292
- var fontFam6 = import_react_native14.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
3196
+ var import_jsx_runtime21 = require("react/jsx-runtime");
3197
+ var fontFam11 = import_react_native20.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
2293
3198
  var HIGHLIGHT_PATTERNS = [
2294
3199
  /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,
2295
3200
  /(?:\+?\d[\s\-().]?){7,}\d/g,
@@ -2332,8 +3237,8 @@ function HighlightedText({
2332
3237
  baseStyle,
2333
3238
  importantStyle
2334
3239
  }) {
2335
- const segments = (0, import_react13.useMemo)(() => highlightSegments(text), [text]);
2336
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: baseStyle, children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: seg.important ? importantStyle : void 0, children: seg.text }, i)) });
3240
+ const segments = (0, import_react17.useMemo)(() => highlightSegments(text), [text]);
3241
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: baseStyle, children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: seg.important ? importantStyle : void 0, children: seg.text }, i)) });
2337
3242
  }
2338
3243
  function VoiceCallSheet({ visible, onClose, skillSlug }) {
2339
3244
  const {
@@ -2345,31 +3250,27 @@ function VoiceCallSheet({ visible, onClose, skillSlug }) {
2345
3250
  muted,
2346
3251
  startCall,
2347
3252
  stopCall,
2348
- toggleMute,
2349
- handleWebViewMessage,
2350
- getWebViewSource,
2351
- webViewRef,
2352
- injectedTrackHook
3253
+ toggleMute
2353
3254
  } = useVoiceCall({ skillSlug });
2354
- const scrollRef = (0, import_react13.useRef)(null);
2355
- (0, import_react13.useEffect)(() => {
3255
+ const scrollRef = (0, import_react17.useRef)(null);
3256
+ (0, import_react17.useEffect)(() => {
2356
3257
  if (visible && callState === "idle") startCall();
2357
3258
  }, [visible]);
2358
- (0, import_react13.useEffect)(() => {
3259
+ (0, import_react17.useEffect)(() => {
2359
3260
  scrollRef.current?.scrollToEnd?.({ animated: true });
2360
3261
  }, [transcript.length, aiPartial, userPartial]);
2361
3262
  const handleHangUp = () => {
2362
3263
  stopCall();
2363
3264
  onClose();
2364
3265
  };
2365
- const orbState = (0, import_react13.useMemo)(() => {
3266
+ const orbState = (0, import_react17.useMemo)(() => {
2366
3267
  if (callState === "connecting") return "thinking";
2367
3268
  if (callState === "error") return "idle";
2368
3269
  if (aiPartial) return "speaking";
2369
3270
  if (userPartial) return "listening";
2370
3271
  return "idle";
2371
3272
  }, [callState, aiPartial, userPartial]);
2372
- const statusLabel = (0, import_react13.useMemo)(() => {
3273
+ const statusLabel = (0, import_react17.useMemo)(() => {
2373
3274
  if (callState === "connecting") return "Connecting\u2026";
2374
3275
  if (callState === "error") return error || "Couldn\u2019t connect";
2375
3276
  if (aiPartial) return "Ada is speaking";
@@ -2379,92 +3280,76 @@ function VoiceCallSheet({ visible, onClose, skillSlug }) {
2379
3280
  }, [callState, aiPartial, userPartial, error]);
2380
3281
  if (!visible) return null;
2381
3282
  const visibleEntries = transcript.filter((e) => e.role === "user" || e.role === "ai");
2382
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2383
- import_plugin_runtime9.SurfaceFullscreen,
3283
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3284
+ import_plugin_runtime14.SurfaceFullscreen,
2384
3285
  {
2385
3286
  visible,
2386
3287
  onClose: handleHangUp,
2387
3288
  status: statusLabel,
2388
- hero: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_plugin_runtime9.AdaOrb, { size: 180, state: orbState }),
3289
+ hero: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_plugin_runtime14.AdaOrb, { size: 180, state: orbState }),
2389
3290
  closeIcon: "hangup",
2390
3291
  closeLabel: "End",
2391
3292
  children: [
2392
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2393
- import_react_native14.ScrollView,
3293
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3294
+ import_react_native20.ScrollView,
2394
3295
  {
2395
3296
  ref: scrollRef,
2396
- style: styles13.transcript,
2397
- contentContainerStyle: styles13.transcriptContent,
3297
+ style: styles19.transcript,
3298
+ contentContainerStyle: styles19.transcriptContent,
2398
3299
  showsVerticalScrollIndicator: false,
2399
3300
  children: [
2400
- callState === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.errorBox, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.errorText, children: error }) }) : null,
2401
- visibleEntries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native14.View, { style: styles13.entry, children: [
2402
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.role, children: entry.role === "user" ? "YOU" : "ADA" }),
2403
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3301
+ callState === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.View, { style: styles19.errorBox, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.errorText, children: error }) }) : null,
3302
+ visibleEntries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native20.View, { style: styles19.entry, children: [
3303
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.role, children: entry.role === "user" ? "YOU" : "ADA" }),
3304
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2404
3305
  HighlightedText,
2405
3306
  {
2406
3307
  text: entry.text,
2407
- baseStyle: styles13.entryText,
2408
- importantStyle: styles13.important
3308
+ baseStyle: styles19.entryText,
3309
+ importantStyle: styles19.important
2409
3310
  }
2410
3311
  )
2411
3312
  ] }, `${entry.ts}-${i}`)),
2412
- userPartial || aiPartial ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native14.View, { style: styles13.entry, children: [
2413
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.role, children: userPartial ? "YOU" : "ADA" }),
2414
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3313
+ userPartial || aiPartial ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native20.View, { style: styles19.entry, children: [
3314
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.role, children: userPartial ? "YOU" : "ADA" }),
3315
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2415
3316
  HighlightedText,
2416
3317
  {
2417
3318
  text: userPartial || aiPartial,
2418
- baseStyle: styles13.entryTextLive,
2419
- importantStyle: styles13.important
3319
+ baseStyle: styles19.entryTextLive,
3320
+ importantStyle: styles19.important
2420
3321
  }
2421
3322
  )
2422
3323
  ] }) : null
2423
3324
  ]
2424
3325
  }
2425
3326
  ),
2426
- callState === "connected" || callState === "connecting" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native14.View, { style: styles13.muteWrap, pointerEvents: "box-none", children: [
2427
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2428
- import_react_native14.Pressable,
3327
+ callState === "connected" || callState === "connecting" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native20.View, { style: styles19.muteWrap, pointerEvents: "box-none", children: [
3328
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3329
+ import_react_native20.Pressable,
2429
3330
  {
2430
3331
  onPress: toggleMute,
2431
3332
  accessibilityRole: "button",
2432
3333
  accessibilityLabel: muted ? "Unmute microphone" : "Mute microphone",
2433
3334
  accessibilityState: { selected: muted },
2434
- style: [styles13.muteBtn, muted && styles13.muteBtnActive],
3335
+ style: [styles19.muteBtn, muted && styles19.muteBtnActive],
2435
3336
  hitSlop: 12,
2436
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native_svg2.default, { width: 22, height: 22, viewBox: "0 0 24 24", fill: "none", stroke: muted ? import_core17.ada.paper : import_core17.ada.ink, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
2437
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_svg2.Path, { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
2438
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_svg2.Path, { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
2439
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_svg2.Line, { x1: "12", y1: "19", x2: "12", y2: "23" }),
2440
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_svg2.Line, { x1: "8", y1: "23", x2: "16", y2: "23" }),
2441
- muted ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_svg2.Line, { x1: "3", y1: "3", x2: "21", y2: "21", stroke: import_core17.ada.paper, strokeWidth: 2.4 }) : null
3337
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native_svg2.default, { width: 22, height: 22, viewBox: "0 0 24 24", fill: "none", stroke: muted ? import_core23.ada.paper : import_core23.ada.ink, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
3338
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Path, { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
3339
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Path, { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
3340
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Line, { x1: "12", y1: "19", x2: "12", y2: "23" }),
3341
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Line, { x1: "8", y1: "23", x2: "16", y2: "23" }),
3342
+ muted ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Line, { x1: "3", y1: "3", x2: "21", y2: "21", stroke: import_core23.ada.paper, strokeWidth: 2.4 }) : null
2442
3343
  ] })
2443
3344
  }
2444
3345
  ),
2445
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.muteLabel, children: muted ? "Muted" : "Mute" })
2446
- ] }) : null,
2447
- callState !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.hiddenWebView, pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2448
- import_react_native_webview3.WebView,
2449
- {
2450
- ref: webViewRef,
2451
- source: getWebViewSource(),
2452
- style: { flex: 1, backgroundColor: "transparent" },
2453
- onMessage: handleWebViewMessage,
2454
- onError: (e) => console.log("[VoiceWebView] error:", e.nativeEvent?.description),
2455
- injectedJavaScriptBeforeContentLoaded: injectedTrackHook,
2456
- mediaPlaybackRequiresUserAction: false,
2457
- allowsInlineMediaPlayback: true,
2458
- mediaCapturePermissionGrantType: "grant",
2459
- javaScriptEnabled: true,
2460
- originWhitelist: ["*"]
2461
- }
2462
- ) })
3346
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.muteLabel, children: muted ? "Muted" : "Mute" })
3347
+ ] }) : null
2463
3348
  ]
2464
3349
  }
2465
3350
  );
2466
3351
  }
2467
- var styles13 = import_react_native14.StyleSheet.create({
3352
+ var styles19 = import_react_native20.StyleSheet.create({
2468
3353
  transcript: {
2469
3354
  flex: 1,
2470
3355
  paddingHorizontal: 28
@@ -2481,9 +3366,9 @@ var styles13 = import_react_native14.StyleSheet.create({
2481
3366
  },
2482
3367
  role: {
2483
3368
  fontSize: 10,
2484
- fontFamily: fontFam6,
3369
+ fontFamily: fontFam11,
2485
3370
  fontWeight: "700",
2486
- color: import_core17.ada.inkMuted,
3371
+ color: import_core23.ada.inkMuted,
2487
3372
  letterSpacing: 1.4,
2488
3373
  minWidth: 32,
2489
3374
  paddingTop: 3,
@@ -2492,9 +3377,9 @@ var styles13 = import_react_native14.StyleSheet.create({
2492
3377
  entryText: {
2493
3378
  flex: 1,
2494
3379
  fontSize: 14,
2495
- fontFamily: fontFam6,
3380
+ fontFamily: fontFam11,
2496
3381
  fontWeight: "400",
2497
- color: import_core17.ada.inkSoft,
3382
+ color: import_core23.ada.inkSoft,
2498
3383
  lineHeight: 20,
2499
3384
  letterSpacing: -0.1,
2500
3385
  opacity: 0.42
@@ -2502,18 +3387,18 @@ var styles13 = import_react_native14.StyleSheet.create({
2502
3387
  entryTextLive: {
2503
3388
  flex: 1,
2504
3389
  fontSize: 14,
2505
- fontFamily: fontFam6,
3390
+ fontFamily: fontFam11,
2506
3391
  fontWeight: "400",
2507
- color: import_core17.ada.inkSoft,
3392
+ color: import_core23.ada.inkSoft,
2508
3393
  lineHeight: 20,
2509
3394
  letterSpacing: -0.1,
2510
3395
  opacity: 0.7
2511
3396
  },
2512
3397
  important: {
2513
3398
  fontSize: 17,
2514
- fontFamily: fontFam6,
3399
+ fontFamily: fontFam11,
2515
3400
  fontWeight: "700",
2516
- color: import_core17.ada.ink,
3401
+ color: import_core23.ada.ink,
2517
3402
  letterSpacing: -0.1,
2518
3403
  opacity: 1
2519
3404
  },
@@ -2528,14 +3413,14 @@ var styles13 = import_react_native14.StyleSheet.create({
2528
3413
  },
2529
3414
  errorText: {
2530
3415
  fontSize: 13,
2531
- fontFamily: fontFam6,
3416
+ fontFamily: fontFam11,
2532
3417
  fontWeight: "500",
2533
3418
  color: "#fca5a5",
2534
3419
  lineHeight: 18
2535
3420
  },
2536
3421
  muteWrap: {
2537
3422
  position: "absolute",
2538
- bottom: import_react_native14.Platform.OS === "ios" ? 56 : 40,
3423
+ bottom: import_react_native20.Platform.OS === "ios" ? 56 : 40,
2539
3424
  left: 28,
2540
3425
  alignItems: "center",
2541
3426
  gap: 6
@@ -2544,9 +3429,9 @@ var styles13 = import_react_native14.StyleSheet.create({
2544
3429
  width: 56,
2545
3430
  height: 56,
2546
3431
  borderRadius: 28,
2547
- backgroundColor: import_core17.ada.paperSoft,
3432
+ backgroundColor: import_core23.ada.paperSoft,
2548
3433
  borderWidth: 1,
2549
- borderColor: import_core17.ada.border,
3434
+ borderColor: import_core23.ada.border,
2550
3435
  justifyContent: "center",
2551
3436
  alignItems: "center"
2552
3437
  },
@@ -2556,18 +3441,133 @@ var styles13 = import_react_native14.StyleSheet.create({
2556
3441
  },
2557
3442
  muteLabel: {
2558
3443
  fontSize: 12,
2559
- fontFamily: fontFam6,
3444
+ fontFamily: fontFam11,
2560
3445
  fontWeight: "500",
2561
- color: import_core17.ada.inkMuted,
3446
+ color: import_core23.ada.inkMuted,
2562
3447
  letterSpacing: 0.3
2563
- },
2564
- hiddenWebView: {
3448
+ }
3449
+ });
3450
+
3451
+ // src/voice/VoiceSessionHost.tsx
3452
+ var import_react18 = require("react");
3453
+ var import_react_native21 = require("react-native");
3454
+ var import_react_native_webview3 = require("react-native-webview");
3455
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3456
+ function VoiceSessionHost() {
3457
+ const [, force] = (0, import_react18.useReducer)((x) => x + 1, 0);
3458
+ const lastSig = (0, import_react18.useRef)("");
3459
+ (0, import_react18.useEffect)(() => {
3460
+ const sub = voiceSession.subscribe(() => {
3461
+ const s2 = voiceSession.getInternal();
3462
+ const sig = `${s2.mounted}|${s2.webViewSource?.uri || ""}`;
3463
+ if (sig !== lastSig.current) {
3464
+ lastSig.current = sig;
3465
+ force();
3466
+ }
3467
+ });
3468
+ return () => sub.unsubscribe();
3469
+ }, []);
3470
+ const setRef = (0, import_react18.useCallback)((r) => {
3471
+ voiceSession.setWebView(r);
3472
+ }, []);
3473
+ const s = voiceSession.getInternal();
3474
+ if (!s.mounted || !s.webViewSource) return null;
3475
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native21.View, { style: styles20.hidden, pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3476
+ import_react_native_webview3.WebView,
3477
+ {
3478
+ ref: setRef,
3479
+ source: s.webViewSource,
3480
+ style: styles20.web,
3481
+ onMessage: (e) => voiceSession.handleMessage(e),
3482
+ onError: (e) => console.log("[VoiceSessionHost] error:", e.nativeEvent?.description),
3483
+ injectedJavaScriptBeforeContentLoaded: voiceSession.injectedTrackHook,
3484
+ mediaPlaybackRequiresUserAction: false,
3485
+ allowsInlineMediaPlayback: true,
3486
+ mediaCapturePermissionGrantType: "grant",
3487
+ javaScriptEnabled: true,
3488
+ originWhitelist: ["*"]
3489
+ }
3490
+ ) });
3491
+ }
3492
+ var styles20 = import_react_native21.StyleSheet.create({
3493
+ hidden: {
2565
3494
  position: "absolute",
2566
3495
  width: 1,
2567
3496
  height: 1,
2568
3497
  top: -100,
2569
3498
  left: -100,
2570
3499
  opacity: 0
3500
+ },
3501
+ web: { flex: 1, backgroundColor: "transparent" }
3502
+ });
3503
+
3504
+ // src/voice/VoiceMicIndicator.tsx
3505
+ var import_react19 = require("react");
3506
+ var import_react_native22 = require("react-native");
3507
+ var import_core24 = require("@ateam-ai-mobile/core");
3508
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3509
+ var fontFam12 = import_react_native22.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
3510
+ function VoiceMicIndicator({ topInset = 8 }) {
3511
+ const [, force] = (0, import_react19.useReducer)((x) => x + 1, 0);
3512
+ const pulse = (0, import_react19.useRef)(new import_react_native22.Animated.Value(0.4)).current;
3513
+ (0, import_react19.useEffect)(() => {
3514
+ const sub = voiceSession.subscribe(() => force());
3515
+ return () => sub.unsubscribe();
3516
+ }, []);
3517
+ const snap = voiceSession.getSnapshot();
3518
+ const live = snap.state === "connecting" || snap.state === "connected";
3519
+ (0, import_react19.useEffect)(() => {
3520
+ if (!live) return;
3521
+ const loop = import_react_native22.Animated.loop(
3522
+ import_react_native22.Animated.sequence([
3523
+ import_react_native22.Animated.timing(pulse, { toValue: 1, duration: 700, useNativeDriver: true }),
3524
+ import_react_native22.Animated.timing(pulse, { toValue: 0.4, duration: 700, useNativeDriver: true })
3525
+ ])
3526
+ );
3527
+ loop.start();
3528
+ return () => loop.stop();
3529
+ }, [live, pulse]);
3530
+ if (!live) return null;
3531
+ const label = snap.state === "connecting" ? "Connecting\u2026" : snap.muted ? "Mic muted" : "Ada is listening";
3532
+ const dotColor = snap.muted ? import_core24.ada.inkMuted : "#E5484D";
3533
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native22.View, { style: [styles21.wrap, { top: topInset }], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native22.View, { style: styles21.pill, children: [
3534
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native22.Animated.View, { style: [styles21.dot, { backgroundColor: dotColor, opacity: snap.muted ? 1 : pulse }] }),
3535
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native22.Text, { style: styles21.label, children: label })
3536
+ ] }) });
3537
+ }
3538
+ var styles21 = import_react_native22.StyleSheet.create({
3539
+ wrap: {
3540
+ position: "absolute",
3541
+ left: 0,
3542
+ right: 0,
3543
+ alignItems: "center",
3544
+ zIndex: 9999,
3545
+ elevation: 9999
3546
+ },
3547
+ pill: {
3548
+ flexDirection: "row",
3549
+ alignItems: "center",
3550
+ gap: 7,
3551
+ paddingHorizontal: 12,
3552
+ paddingVertical: 6,
3553
+ borderRadius: 999,
3554
+ backgroundColor: import_core24.ada.ink,
3555
+ shadowColor: "#000",
3556
+ shadowOpacity: 0.2,
3557
+ shadowRadius: 8,
3558
+ shadowOffset: { width: 0, height: 2 }
3559
+ },
3560
+ dot: {
3561
+ width: 8,
3562
+ height: 8,
3563
+ borderRadius: 4
3564
+ },
3565
+ label: {
3566
+ fontSize: 12,
3567
+ fontFamily: fontFam12,
3568
+ fontWeight: "600",
3569
+ color: import_core24.ada.paper,
3570
+ letterSpacing: 0.2
2571
3571
  }
2572
3572
  });
2573
3573
  // Annotate the CommonJS export names for ESM import in node:
@@ -2576,9 +3576,13 @@ var styles13 = import_react_native14.StyleSheet.create({
2576
3576
  ChatInput,
2577
3577
  DaySeparator,
2578
3578
  EmbeddedPluginWebView,
3579
+ HandoffScreen,
2579
3580
  JobProgressBar,
3581
+ JoinScreen,
2580
3582
  Lightbox,
3583
+ LoginScreen,
2581
3584
  MessageBubble,
3585
+ OpenJoinScreen,
2582
3586
  Plugin,
2583
3587
  PluginSurface,
2584
3588
  TableCardBlock,
@@ -2586,16 +3590,30 @@ var styles13 = import_react_native14.StyleSheet.create({
2586
3590
  TypingIndicator,
2587
3591
  UIActionsRow,
2588
3592
  VoiceCallSheet,
3593
+ VoiceMicIndicator,
3594
+ VoiceSessionHost,
2589
3595
  WidgetHost,
2590
3596
  WidgetWebView,
3597
+ WorkspaceBanner,
2591
3598
  buildPluginBridgeJS,
3599
+ completeInviteJoin,
3600
+ completeOpenJoin,
3601
+ completeProviderSignIn,
3602
+ googleClientIds,
3603
+ handoffErrorMessage,
3604
+ inviteHeadline,
3605
+ openJoinErrorMessage,
2592
3606
  openWidget,
3607
+ runHandoffExchange,
2593
3608
  setClipboardProvider,
3609
+ setOAuthProvider,
2594
3610
  setPluginWebViewExtraHosts,
2595
3611
  setUIActionNavigator,
3612
+ shouldRecoverToDefaultTenant,
2596
3613
  useLightboxStore,
2597
3614
  usePluginBridge,
2598
3615
  useVoiceCall,
2599
- useWidgetHostStore
3616
+ useWidgetHostStore,
3617
+ voiceSession
2600
3618
  });
2601
3619
  //# sourceMappingURL=index.js.map