@appilots/sdk 0.11.3 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunk5UVMNKPT_js = require('./chunk-5UVMNKPT.js');
4
- var chunkUFMTRGML_js = require('./chunk-UFMTRGML.js');
5
- var chunkSUMIABJK_js = require('./chunk-SUMIABJK.js');
6
- var React7 = require('react');
3
+ var chunkGDCBLSYT_js = require('./chunk-GDCBLSYT.js');
4
+ var chunkJGUDXRXN_js = require('./chunk-JGUDXRXN.js');
5
+ var chunkQAZ4TN3Z_js = require('./chunk-QAZ4TN3Z.js');
6
+ var React8 = require('react');
7
7
  var reactNative = require('react-native');
8
8
  var reactNativeSafeAreaContext = require('react-native-safe-area-context');
9
9
  var Svg = require('react-native-svg');
@@ -28,13 +28,13 @@ function _interopNamespace(e) {
28
28
  return Object.freeze(n);
29
29
  }
30
30
 
31
- var React7__namespace = /*#__PURE__*/_interopNamespace(React7);
31
+ var React8__namespace = /*#__PURE__*/_interopNamespace(React8);
32
32
  var Svg__default = /*#__PURE__*/_interopDefault(Svg);
33
33
 
34
34
  var NO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
35
35
  var _warned = false;
36
36
  function useSafeAreaInsetsOrDefault() {
37
- const insets = React7.useContext(reactNativeSafeAreaContext.SafeAreaInsetsContext);
37
+ const insets = React8.useContext(reactNativeSafeAreaContext.SafeAreaInsetsContext);
38
38
  if (insets) return insets;
39
39
  if (!_warned) {
40
40
  _warned = true;
@@ -44,17 +44,54 @@ function useSafeAreaInsetsOrDefault() {
44
44
  }
45
45
  return NO_INSETS;
46
46
  }
47
+ function probeHostModalOpen() {
48
+ const stack = [chunkQAZ4TN3Z_js.getFiberRoot()];
49
+ const seen = /* @__PURE__ */ new Set();
50
+ while (stack.length) {
51
+ const node = stack.pop();
52
+ if (!node || seen.has(node)) continue;
53
+ seen.add(node);
54
+ if (node.sibling) stack.push(node.sibling);
55
+ if (chunkQAZ4TN3Z_js.shouldSkipSubtree(node)) continue;
56
+ if (chunkQAZ4TN3Z_js.isModalFiber(node) && node.child) return true;
57
+ if (node.child) stack.push(node.child);
58
+ }
59
+ return false;
60
+ }
61
+ function useHostModalOpen(enabled) {
62
+ const [open, setOpen] = React8.useState(false);
63
+ React8.useEffect(() => {
64
+ if (!enabled) {
65
+ setOpen(false);
66
+ return;
67
+ }
68
+ let closedSince;
69
+ const sample = () => {
70
+ if (probeHostModalOpen()) {
71
+ closedSince = void 0;
72
+ setOpen(true);
73
+ } else {
74
+ closedSince ??= Date.now();
75
+ if (Date.now() - closedSince >= 300) setOpen(false);
76
+ }
77
+ };
78
+ sample();
79
+ const timer = setInterval(sample, 150);
80
+ return () => clearInterval(timer);
81
+ }, [enabled]);
82
+ return enabled && open;
83
+ }
47
84
 
48
85
  // src/components/breadcrumbPresentation.ts
49
86
  var DEFAULT_BREADCRUMB_PALETTE = {
50
- primary: chunkSUMIABJK_js.defaultLightTheme.colors.primary,
51
- text: chunkSUMIABJK_js.defaultLightTheme.colors.text,
52
- textSecondary: chunkSUMIABJK_js.defaultLightTheme.colors.textSecondary,
53
- surface: chunkSUMIABJK_js.defaultLightTheme.colors.surface,
54
- border: chunkSUMIABJK_js.defaultLightTheme.colors.border,
55
- success: chunkSUMIABJK_js.defaultLightTheme.colors.success,
56
- warning: chunkSUMIABJK_js.defaultLightTheme.colors.warning,
57
- error: chunkSUMIABJK_js.defaultLightTheme.colors.error
87
+ primary: chunkQAZ4TN3Z_js.defaultLightTheme.colors.primary,
88
+ text: chunkQAZ4TN3Z_js.defaultLightTheme.colors.text,
89
+ textSecondary: chunkQAZ4TN3Z_js.defaultLightTheme.colors.textSecondary,
90
+ surface: chunkQAZ4TN3Z_js.defaultLightTheme.colors.surface,
91
+ border: chunkQAZ4TN3Z_js.defaultLightTheme.colors.border,
92
+ success: chunkQAZ4TN3Z_js.defaultLightTheme.colors.success,
93
+ warning: chunkQAZ4TN3Z_js.defaultLightTheme.colors.warning,
94
+ error: chunkQAZ4TN3Z_js.defaultLightTheme.colors.error
58
95
  };
59
96
  var KNOWN_TINTS = {
60
97
  [DEFAULT_BREADCRUMB_PALETTE.primary.toUpperCase()]: "#EEF2FF",
@@ -101,13 +138,15 @@ var PT_BR_CONFIRM_FALLBACK = {
101
138
  confirmDestructiveApprove: "Sim, executar",
102
139
  confirmApprove: "Confirmar",
103
140
  confirmCancel: "Cancelar",
104
- confirmThisAction: "esta a\xE7\xE3o"
141
+ confirmThisAction: "esta a\xE7\xE3o",
142
+ confirmExpired: "Esta confirma\xE7\xE3o expirou. Pe\xE7a de novo ao assistente para continuar."
105
143
  };
106
144
  function deriveConfirmCardContent(action, palette = DEFAULT_BREADCRUMB_PALETTE, strings) {
107
145
  const payload = action.payload ?? {};
108
146
  const isDestructive = isDestructiveAction(action);
109
147
  const copy = { ...PT_BR_CONFIRM_FALLBACK, ...strings ?? {} };
110
- const actionName = typeof payload.actionDescription === "string" && payload.actionDescription || copy.confirmThisAction;
148
+ const described = typeof payload.actionDescription === "string" ? payload.actionDescription : "";
149
+ const actionName = described || copy.confirmThisAction;
111
150
  const message = typeof payload.message === "string" && payload.message || copy.confirmMessage.replace("{action}", actionName);
112
151
  const title = typeof payload.title === "string" && payload.title || (isDestructive ? copy.confirmDestructiveTitle : copy.confirmTitle);
113
152
  const confirmLabel = typeof payload.confirmLabel === "string" && payload.confirmLabel || (isDestructive ? copy.confirmDestructiveApprove : copy.confirmApprove);
@@ -118,6 +157,10 @@ function deriveConfirmCardContent(action, palette = DEFAULT_BREADCRUMB_PALETTE,
118
157
  message,
119
158
  confirmLabel,
120
159
  cancelLabel,
160
+ // A bare "Confirm" heard out of context says nothing about what it does.
161
+ confirmA11yLabel: described ? `${confirmLabel}: ${described}` : confirmLabel,
162
+ cancelA11yLabel: described ? `${cancelLabel}: ${described}` : cancelLabel,
163
+ expiredMessage: copy.confirmExpired ?? PT_BR_CONFIRM_FALLBACK.confirmExpired,
121
164
  glyph: isDestructive ? "\u26A0" : "?",
122
165
  actionColor: isDestructive ? palette.error : palette.primary,
123
166
  cardBackground: palette.surface,
@@ -127,6 +170,79 @@ function deriveConfirmCardContent(action, palette = DEFAULT_BREADCRUMB_PALETTE,
127
170
  cancelTextColor: palette.textSecondary
128
171
  };
129
172
  }
173
+ var TARGET_ANNOUNCEMENT = {
174
+ "pt-BR": {
175
+ press: "Tocando em {label}",
176
+ toggle: "Alternando {label}",
177
+ focus: "Selecionando {label}",
178
+ fill: "Preenchendo {label}"
179
+ },
180
+ en: {
181
+ press: "Tapping {label}",
182
+ toggle: "Toggling {label}",
183
+ focus: "Selecting {label}",
184
+ fill: "Filling in {label}"
185
+ },
186
+ es: {
187
+ press: "Tocando {label}",
188
+ toggle: "Cambiando {label}",
189
+ focus: "Seleccionando {label}",
190
+ fill: "Rellenando {label}"
191
+ },
192
+ fr: {
193
+ press: "Appui sur {label}",
194
+ toggle: "Bascule de {label}",
195
+ focus: "S\xE9lection de {label}",
196
+ fill: "Saisie de {label}"
197
+ }
198
+ };
199
+ function targetAnnouncement(verb, label, locale = "pt-BR") {
200
+ return (TARGET_ANNOUNCEMENT[locale] ?? TARGET_ANNOUNCEMENT["pt-BR"])[verb].replace(
201
+ "{label}",
202
+ label
203
+ );
204
+ }
205
+ function executorNamesTarget(action) {
206
+ if (action.type === "form_fill") return true;
207
+ if (action.type !== "ui_interaction") return false;
208
+ const interaction = action.payload?.action;
209
+ return !["scroll", "scroll_to"].includes(String(interaction ?? "press"));
210
+ }
211
+ function actionAnnouncement(action, locale, named) {
212
+ const { state, label } = chunkQAZ4TN3Z_js.describeAction(action, locale);
213
+ if (state === "failed") return label;
214
+ const executorNames = executorNamesTarget(action);
215
+ if (state === "running") return executorNames ? null : label;
216
+ if (state === "success") return executorNames && !named ? label : null;
217
+ return null;
218
+ }
219
+ var reduceMotion = false;
220
+ var listeners = /* @__PURE__ */ new Set();
221
+ var subscription;
222
+ function set(value) {
223
+ if (value === reduceMotion) return;
224
+ reduceMotion = value;
225
+ for (const listener of listeners) listener();
226
+ }
227
+ function subscribe(onChange) {
228
+ listeners.add(onChange);
229
+ if (!subscription) {
230
+ subscription = reactNative.AccessibilityInfo.addEventListener("reduceMotionChanged", set);
231
+ reactNative.AccessibilityInfo.isReduceMotionEnabled().then(set, () => {
232
+ });
233
+ }
234
+ return () => {
235
+ listeners.delete(onChange);
236
+ if (listeners.size === 0) {
237
+ subscription?.remove();
238
+ subscription = void 0;
239
+ }
240
+ };
241
+ }
242
+ var get = () => reduceMotion;
243
+ function useReduceMotion() {
244
+ return React8.useSyncExternalStore(subscribe, get, get);
245
+ }
130
246
 
131
247
  // src/components/ActionBreadcrumb.tsx
132
248
  function ActionBreadcrumb({
@@ -136,9 +252,11 @@ function ActionBreadcrumb({
136
252
  fontFamily,
137
253
  palette,
138
254
  confirmStrings,
255
+ locale,
139
256
  requireApprovalFor,
140
257
  onApprove,
141
- onReject
258
+ onReject,
259
+ onConfirmCardGone
142
260
  }) {
143
261
  if (actions.length === 0) return null;
144
262
  const resolvedPalette = {
@@ -147,7 +265,7 @@ function ActionBreadcrumb({
147
265
  primary: primaryColor,
148
266
  text: textColor
149
267
  };
150
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles.container }, actions.map((action) => /* @__PURE__ */ React7__namespace.default.createElement(
268
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles.container }, actions.map((action) => /* @__PURE__ */ React8__namespace.default.createElement(
151
269
  BreadcrumbRow,
152
270
  {
153
271
  key: action.id,
@@ -157,16 +275,18 @@ function ActionBreadcrumb({
157
275
  fontFamily,
158
276
  palette: resolvedPalette,
159
277
  confirmStrings,
278
+ locale,
160
279
  needsApproval: requireApprovalFor?.(action) ?? false,
161
280
  onApprove,
162
- onReject
281
+ onReject,
282
+ onConfirmCardGone
163
283
  }
164
284
  )));
165
285
  }
166
286
  function BreadcrumbRow(props) {
167
287
  const { action, needsApproval } = props;
168
288
  if (action.type === "confirm" && action.status === "pending" && needsApproval) {
169
- return /* @__PURE__ */ React7__namespace.default.createElement(
289
+ return /* @__PURE__ */ React8__namespace.default.createElement(
170
290
  ConfirmCard,
171
291
  {
172
292
  action,
@@ -174,11 +294,12 @@ function BreadcrumbRow(props) {
174
294
  fontFamily: props.fontFamily,
175
295
  confirmStrings: props.confirmStrings,
176
296
  onApprove: props.onApprove,
177
- onReject: props.onReject
297
+ onReject: props.onReject,
298
+ onGone: props.onConfirmCardGone
178
299
  }
179
300
  );
180
301
  }
181
- return /* @__PURE__ */ React7__namespace.default.createElement(RegularBreadcrumbRow, { ...props });
302
+ return /* @__PURE__ */ React8__namespace.default.createElement(RegularBreadcrumbRow, { ...props });
182
303
  }
183
304
  function RegularBreadcrumbRow({
184
305
  action,
@@ -186,49 +307,49 @@ function RegularBreadcrumbRow({
186
307
  textColor,
187
308
  fontFamily,
188
309
  palette,
310
+ locale,
189
311
  needsApproval,
190
312
  onApprove,
191
313
  onReject
192
314
  }) {
193
- const { label, state } = chunkSUMIABJK_js.describeAction(action);
315
+ const { label, state } = chunkQAZ4TN3Z_js.describeAction(action, locale);
194
316
  const tone = deriveStateTone(palette)[state];
195
- const fade = React7.useRef(new reactNative.Animated.Value(0)).current;
196
- const pulse = React7.useRef(new reactNative.Animated.Value(1)).current;
197
- const lastState = React7.useRef(state);
198
- React7.useEffect(() => {
317
+ const fade = React8.useRef(new reactNative.Animated.Value(0)).current;
318
+ const pulse = React8.useRef(new reactNative.Animated.Value(1)).current;
319
+ const lastState = React8.useRef(state);
320
+ const reduceMotion2 = useReduceMotion();
321
+ React8.useEffect(() => {
322
+ if (reduceMotion2) {
323
+ fade.setValue(1);
324
+ return;
325
+ }
199
326
  reactNative.Animated.timing(fade, {
200
327
  toValue: 1,
201
328
  duration: 180,
202
329
  useNativeDriver: true
203
330
  }).start();
204
- }, [fade]);
205
- React7.useEffect(() => {
331
+ }, [fade, reduceMotion2]);
332
+ React8.useEffect(() => {
206
333
  if (lastState.current === state) return;
207
334
  lastState.current = state;
335
+ if (reduceMotion2) return;
208
336
  pulse.setValue(0.4);
209
337
  reactNative.Animated.timing(pulse, {
210
338
  toValue: 1,
211
339
  duration: 220,
212
340
  useNativeDriver: true
213
341
  }).start();
214
- }, [state, pulse]);
342
+ }, [state, pulse, reduceMotion2]);
215
343
  const isDestructive = isDestructiveAction(action);
216
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Animated.View, { style: [styles.row, { opacity: fade }] }, /* @__PURE__ */ React7__namespace.default.createElement(
217
- reactNative.Animated.View,
344
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Animated.View, { style: [styles.row, { opacity: fade }] }, /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Animated.View, { style: [styles.labelGroup, { opacity: pulse }] }, /* @__PURE__ */ React8__namespace.default.createElement(StateIcon, { state, tone, primaryColor }), /* @__PURE__ */ React8__namespace.default.createElement(
345
+ reactNative.Text,
218
346
  {
219
- style: { opacity: pulse, flexDirection: "row", alignItems: "flex-start", flex: 1 }
347
+ style: [styles.label, { color: state === "failed" ? tone.color : textColor, fontFamily }],
348
+ accessibilityLabel: `${state}: ${label}`
220
349
  },
221
- /* @__PURE__ */ React7__namespace.default.createElement(StateIcon, { state, tone, primaryColor }),
222
- /* @__PURE__ */ React7__namespace.default.createElement(
223
- reactNative.Text,
224
- {
225
- style: [styles.label, { color: state === "failed" ? tone.color : textColor, fontFamily }],
226
- accessibilityLabel: `${state}: ${label}`
227
- },
228
- label,
229
- isDestructive && /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [styles.destructiveTag, { color: palette.error }] }, " \u26A0 destrutiva")
230
- )
231
- ), needsApproval && action.status === "pending" && onApprove && onReject && /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles.approvalButtons }, /* @__PURE__ */ React7__namespace.default.createElement(
350
+ label,
351
+ isDestructive && /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [styles.destructiveTag, { color: palette.error }] }, " \u26A0 destrutiva")
352
+ )), needsApproval && action.status === "pending" && onApprove && onReject && /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles.approvalButtons }, /* @__PURE__ */ React8__namespace.default.createElement(
232
353
  reactNative.TouchableOpacity,
233
354
  {
234
355
  onPress: () => onReject(action.id),
@@ -237,8 +358,8 @@ function RegularBreadcrumbRow({
237
358
  accessibilityLabel: "Rejeitar a\xE7\xE3o",
238
359
  testID: "assistant-action-reject"
239
360
  },
240
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [styles.rejectBtnText, { color: palette.error }] }, "Rejeitar")
241
- ), /* @__PURE__ */ React7__namespace.default.createElement(
361
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [styles.rejectBtnText, { color: palette.error }] }, "Rejeitar")
362
+ ), /* @__PURE__ */ React8__namespace.default.createElement(
242
363
  reactNative.TouchableOpacity,
243
364
  {
244
365
  onPress: () => onApprove(action.id),
@@ -247,16 +368,18 @@ function RegularBreadcrumbRow({
247
368
  accessibilityLabel: "Aprovar a\xE7\xE3o",
248
369
  testID: "assistant-action-approve"
249
370
  },
250
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: styles.approveBtnText }, "Aprovar")
371
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: styles.approveBtnText }, "Aprovar")
251
372
  )));
252
373
  }
374
+ var MIN_TOUCH_TARGET = 44;
253
375
  function ConfirmCard({
254
376
  action,
255
377
  palette,
256
378
  fontFamily,
257
379
  confirmStrings,
258
380
  onApprove,
259
- onReject
381
+ onReject,
382
+ onGone
260
383
  }) {
261
384
  const {
262
385
  isDestructive,
@@ -264,6 +387,9 @@ function ConfirmCard({
264
387
  message,
265
388
  confirmLabel,
266
389
  cancelLabel,
390
+ confirmA11yLabel,
391
+ cancelA11yLabel,
392
+ expiredMessage,
267
393
  glyph,
268
394
  actionColor,
269
395
  cardBackground,
@@ -272,50 +398,91 @@ function ConfirmCard({
272
398
  cancelBackground,
273
399
  cancelTextColor
274
400
  } = deriveConfirmCardContent(action, palette, confirmStrings);
275
- return /* @__PURE__ */ React7__namespace.default.createElement(
401
+ const summaryRef = React8.useRef(null);
402
+ const expiresAt = chunkQAZ4TN3Z_js.confirmExpiresAt(action);
403
+ const [expired, setExpired] = React8.useState(() => expiresAt !== void 0 && expiresAt <= Date.now());
404
+ const onGoneRef = React8.useRef(onGone);
405
+ onGoneRef.current = onGone;
406
+ React8.useEffect(() => {
407
+ if (summaryRef.current) reactNative.AccessibilityInfo.sendAccessibilityEvent(summaryRef.current, "focus");
408
+ return () => onGoneRef.current?.();
409
+ }, []);
410
+ React8.useEffect(() => {
411
+ if (expiresAt === void 0 || expired) return;
412
+ const timer = setTimeout(() => setExpired(true), expiresAt - Date.now());
413
+ return () => clearTimeout(timer);
414
+ }, [expiresAt, expired]);
415
+ React8.useEffect(() => {
416
+ if (expired) reactNative.AccessibilityInfo.announceForAccessibility(expiredMessage);
417
+ }, [expired, expiredMessage]);
418
+ return /* @__PURE__ */ React8__namespace.default.createElement(
276
419
  reactNative.View,
277
420
  {
278
421
  style: [
279
422
  confirmCardStyles.card,
280
423
  { backgroundColor: cardBackground, borderColor: cardBorderColor }
281
424
  ],
282
- testID: "assistant-confirm-card"
425
+ testID: "assistant-confirm-card",
426
+ onAccessibilityEscape: () => onReject?.(action.id)
283
427
  },
284
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: confirmCardStyles.headerRow }, /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.glyph, { color: actionColor }] }, glyph), /* @__PURE__ */ React7__namespace.default.createElement(
428
+ /* @__PURE__ */ React8__namespace.default.createElement(
429
+ reactNative.View,
430
+ {
431
+ ref: summaryRef,
432
+ accessible: true,
433
+ accessibilityLabel: `${title}. ${message}`,
434
+ accessibilityLiveRegion: "polite"
435
+ },
436
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: confirmCardStyles.headerRow }, /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.glyph, { color: actionColor }] }, glyph), /* @__PURE__ */ React8__namespace.default.createElement(
437
+ reactNative.Text,
438
+ {
439
+ style: [
440
+ confirmCardStyles.title,
441
+ { color: isDestructive ? palette.error : palette.text, fontFamily }
442
+ ]
443
+ },
444
+ title
445
+ )),
446
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.message, { color: messageColor, fontFamily }] }, message)
447
+ ),
448
+ expired && /* @__PURE__ */ React8__namespace.default.createElement(
285
449
  reactNative.Text,
286
450
  {
287
- style: [
288
- confirmCardStyles.title,
289
- { color: isDestructive ? palette.error : palette.text, fontFamily }
290
- ]
451
+ style: [confirmCardStyles.expired, { color: palette.error, fontFamily }],
452
+ accessibilityLiveRegion: "assertive",
453
+ testID: "assistant-confirm-expired"
291
454
  },
292
- title
293
- )),
294
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.message, { color: messageColor, fontFamily }] }, message),
295
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: confirmCardStyles.buttons }, /* @__PURE__ */ React7__namespace.default.createElement(
455
+ expiredMessage
456
+ ),
457
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: confirmCardStyles.buttons }, /* @__PURE__ */ React8__namespace.default.createElement(
296
458
  reactNative.TouchableOpacity,
297
459
  {
298
460
  onPress: () => onReject?.(action.id),
299
461
  style: [confirmCardStyles.btn, { backgroundColor: cancelBackground }],
300
462
  activeOpacity: 0.7,
301
- accessibilityLabel: cancelLabel,
463
+ accessibilityRole: "button",
464
+ accessibilityLabel: cancelA11yLabel,
302
465
  testID: "assistant-confirm-reject"
303
466
  },
304
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.cancelText, { color: cancelTextColor, fontFamily }] }, cancelLabel)
305
- ), /* @__PURE__ */ React7__namespace.default.createElement(
467
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.cancelText, { color: cancelTextColor, fontFamily }] }, cancelLabel)
468
+ ), /* @__PURE__ */ React8__namespace.default.createElement(
306
469
  reactNative.TouchableOpacity,
307
470
  {
308
471
  onPress: () => onApprove?.(action.id),
472
+ disabled: expired,
309
473
  style: [
310
474
  confirmCardStyles.btn,
311
475
  confirmCardStyles.confirmBtn,
312
- { backgroundColor: actionColor }
476
+ { backgroundColor: actionColor },
477
+ expired && confirmCardStyles.disabledBtn
313
478
  ],
314
479
  activeOpacity: 0.7,
315
- accessibilityLabel: confirmLabel,
480
+ accessibilityRole: "button",
481
+ accessibilityState: { disabled: expired },
482
+ accessibilityLabel: confirmA11yLabel,
316
483
  testID: "assistant-confirm-approve"
317
484
  },
318
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.confirmText, { fontFamily }] }, confirmLabel)
485
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [confirmCardStyles.confirmText, { fontFamily }] }, confirmLabel)
319
486
  ))
320
487
  );
321
488
  }
@@ -349,18 +516,33 @@ var confirmCardStyles = reactNative.StyleSheet.create({
349
516
  // color set inline — theme-driven (textSecondary).
350
517
  marginBottom: 12
351
518
  },
519
+ // Wraps: on one line the two buttons ran off the LEFT edge at iOS AX5
520
+ // and Cancel was unreachable — on the one card that gates something
521
+ // irreversible.
352
522
  buttons: {
353
523
  flexDirection: "row",
524
+ flexWrap: "wrap",
354
525
  gap: 8,
355
526
  justifyContent: "flex-end"
356
527
  },
357
528
  btn: {
529
+ minHeight: MIN_TOUCH_TARGET,
530
+ maxWidth: "100%",
531
+ justifyContent: "center",
358
532
  paddingHorizontal: 14,
359
533
  paddingVertical: 8,
360
534
  borderRadius: 10,
361
535
  minWidth: 96,
362
536
  alignItems: "center"
363
537
  },
538
+ disabledBtn: {
539
+ opacity: 0.4
540
+ },
541
+ expired: {
542
+ fontSize: 13,
543
+ fontWeight: "600",
544
+ marginBottom: 12
545
+ },
364
546
  cancelText: {
365
547
  fontSize: 13,
366
548
  fontWeight: "600"
@@ -380,7 +562,11 @@ function StateIcon({
380
562
  tone,
381
563
  primaryColor
382
564
  }) {
383
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: [styles.iconCircle, { backgroundColor: tone.iconBg }] }, state === "running" ? /* @__PURE__ */ React7__namespace.default.createElement(reactNative.ActivityIndicator, { size: "small", color: primaryColor }) : /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [styles.iconGlyph, { color: tone.color }] }, iconGlyphFor(state)));
565
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: [styles.iconCircle, { backgroundColor: tone.iconBg }] }, state === "running" ? /* @__PURE__ */ React8__namespace.default.createElement(reactNative.ActivityIndicator, { size: "small", color: primaryColor }) : (
566
+ // Decorative, inside a fixed circle: capped so it cannot clip. The
567
+ // state is also in the row's accessibilityLabel.
568
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { maxFontSizeMultiplier: 1.3, style: [styles.iconGlyph, { color: tone.color }] }, iconGlyphFor(state))
569
+ ));
384
570
  }
385
571
  var styles = reactNative.StyleSheet.create({
386
572
  container: {
@@ -388,12 +574,26 @@ var styles = reactNative.StyleSheet.create({
388
574
  marginBottom: 8,
389
575
  paddingVertical: 4
390
576
  },
577
+ // Wraps so Approve/Reject drop below the label at large text sizes. On
578
+ // one line they squeezed the label to zero width (iOS AX5): the user was
579
+ // asked to approve an action they could not read.
391
580
  row: {
392
581
  flexDirection: "row",
582
+ flexWrap: "wrap",
583
+ gap: 8,
393
584
  alignItems: "center",
394
585
  paddingVertical: 6,
395
586
  paddingHorizontal: 4
396
587
  },
588
+ labelGroup: {
589
+ flexDirection: "row",
590
+ alignItems: "flex-start",
591
+ flexGrow: 1,
592
+ flexShrink: 1,
593
+ flexBasis: 0,
594
+ // What forces the wrap: the label keeps at least half the row.
595
+ minWidth: "50%"
596
+ },
397
597
  iconCircle: {
398
598
  width: 22,
399
599
  height: 22,
@@ -421,9 +621,11 @@ var styles = reactNative.StyleSheet.create({
421
621
  approvalButtons: {
422
622
  flexDirection: "row",
423
623
  gap: 6,
424
- marginLeft: 8
624
+ marginLeft: "auto"
425
625
  },
426
626
  btn: {
627
+ minHeight: MIN_TOUCH_TARGET,
628
+ justifyContent: "center",
427
629
  paddingHorizontal: 10,
428
630
  paddingVertical: 5,
429
631
  borderRadius: 8
@@ -471,7 +673,7 @@ function resolvePersonalization(props, remote) {
471
673
  };
472
674
  }
473
675
  function ChatIcon({ size = 24, color = "#ffffff" }) {
474
- return /* @__PURE__ */ React7__namespace.createElement(Svg__default.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React7__namespace.createElement(
676
+ return /* @__PURE__ */ React8__namespace.createElement(Svg__default.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React8__namespace.createElement(
475
677
  Svg.Path,
476
678
  {
477
679
  d: "M5 3.5h14a3 3 0 0 1 3 3v9a3 3 0 0 1-3 3h-7.4l-4.6 4v-4H5a3 3 0 0 1-3-3v-9a3 3 0 0 1 3-3z",
@@ -479,8 +681,524 @@ function ChatIcon({ size = 24, color = "#ffffff" }) {
479
681
  }
480
682
  ));
481
683
  }
684
+
685
+ // src/components/internalProps.ts
686
+ var APPILOTS_SKIP_PROPS = {
687
+ __appilotsSkip: true,
688
+ __appilotsInternal: true
689
+ };
690
+
691
+ // src/components/AgentPill.tsx
692
+ var PILL_MAX_FONT_SCALE = 1.5;
693
+ function toneFor(state, colors) {
694
+ switch (state) {
695
+ case "success":
696
+ return colors.success;
697
+ case "failed":
698
+ return colors.error;
699
+ default:
700
+ return colors.primary;
701
+ }
702
+ }
703
+ function AgentPill({
704
+ label,
705
+ state,
706
+ onExpand,
707
+ expandRef,
708
+ onStop,
709
+ position,
710
+ insets,
711
+ colors,
712
+ fontFamily,
713
+ strings
714
+ }) {
715
+ const atTop = position === "top-left" || position === "top-right";
716
+ const reduceMotion2 = useReduceMotion();
717
+ const enter = React8.useRef(new reactNative.Animated.Value(0)).current;
718
+ React8.useEffect(() => {
719
+ if (reduceMotion2) {
720
+ enter.setValue(1);
721
+ return;
722
+ }
723
+ reactNative.Animated.spring(enter, {
724
+ toValue: 1,
725
+ useNativeDriver: true,
726
+ tension: 70,
727
+ friction: 12
728
+ }).start();
729
+ }, [enter, reduceMotion2]);
730
+ const translateY = enter.interpolate({
731
+ inputRange: [0, 1],
732
+ outputRange: [atTop ? -80 : 80, 0]
733
+ });
734
+ const running = state === "running" || state === "pending";
735
+ return /* @__PURE__ */ React8__namespace.default.createElement(
736
+ reactNative.Animated.View,
737
+ {
738
+ ...APPILOTS_SKIP_PROPS,
739
+ pointerEvents: "box-none",
740
+ style: [
741
+ styles2.wrapper,
742
+ atTop ? { top: insets.top + 8 } : { bottom: insets.bottom + 8 },
743
+ { opacity: enter, transform: [{ translateY }] }
744
+ ]
745
+ },
746
+ /* @__PURE__ */ React8__namespace.default.createElement(
747
+ reactNative.TouchableOpacity,
748
+ {
749
+ ...APPILOTS_SKIP_PROPS,
750
+ ref: expandRef,
751
+ testID: "appilots-agent-pill",
752
+ accessibilityRole: "button",
753
+ accessibilityLabel: strings.expandA11y,
754
+ activeOpacity: 0.85,
755
+ onPress: onExpand,
756
+ style: [styles2.pill, { backgroundColor: colors.surface, borderColor: colors.border }]
757
+ },
758
+ running ? /* @__PURE__ */ React8__namespace.default.createElement(reactNative.ActivityIndicator, { size: "small", color: toneFor(state, colors) }) : /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: [styles2.dot, { backgroundColor: toneFor(state, colors) }] }),
759
+ /* @__PURE__ */ React8__namespace.default.createElement(
760
+ reactNative.Text,
761
+ {
762
+ testID: "appilots-agent-pill-label",
763
+ numberOfLines: 2,
764
+ maxFontSizeMultiplier: PILL_MAX_FONT_SCALE,
765
+ style: [styles2.label, { color: colors.text, fontFamily }]
766
+ },
767
+ label
768
+ ),
769
+ onStop ? /* @__PURE__ */ React8__namespace.default.createElement(
770
+ reactNative.TouchableOpacity,
771
+ {
772
+ ...APPILOTS_SKIP_PROPS,
773
+ testID: "appilots-agent-pill-stop",
774
+ accessibilityRole: "button",
775
+ accessibilityLabel: strings.stopA11y,
776
+ onPress: onStop,
777
+ hitSlop: { top: 12, bottom: 12, left: 12, right: 12 },
778
+ style: [styles2.stop, { borderColor: colors.border }]
779
+ },
780
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: [styles2.stopGlyph, { backgroundColor: colors.textSecondary }] })
781
+ ) : null
782
+ )
783
+ );
784
+ }
785
+ var styles2 = reactNative.StyleSheet.create({
786
+ // `box-none` above + `position: absolute` here is what lets touches
787
+ // outside the pill itself reach the app underneath.
788
+ wrapper: {
789
+ position: "absolute",
790
+ left: 12,
791
+ right: 12,
792
+ zIndex: 999,
793
+ alignItems: "center"
794
+ },
795
+ pill: {
796
+ flexDirection: "row",
797
+ alignItems: "center",
798
+ gap: 10,
799
+ maxWidth: "100%",
800
+ paddingLeft: 14,
801
+ paddingRight: 8,
802
+ paddingVertical: 10,
803
+ borderRadius: 24,
804
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
805
+ shadowColor: "#000",
806
+ shadowOffset: { width: 0, height: 2 },
807
+ shadowOpacity: 0.18,
808
+ shadowRadius: 8,
809
+ elevation: 8
810
+ },
811
+ dot: { width: 8, height: 8, borderRadius: 4 },
812
+ label: { flexShrink: 1, fontSize: 14, fontWeight: "500" },
813
+ stop: {
814
+ width: 26,
815
+ height: 26,
816
+ borderRadius: 13,
817
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
818
+ alignItems: "center",
819
+ justifyContent: "center"
820
+ },
821
+ stopGlyph: { width: 9, height: 9, borderRadius: 1.5 }
822
+ });
823
+ var PADDING = 6;
824
+ var CAPTION_HEIGHT = 28;
825
+ var CAPTION_GAP = 8;
826
+ function SpotlightOverlay({
827
+ rect,
828
+ seq,
829
+ label,
830
+ color,
831
+ captionBackground,
832
+ captionColor,
833
+ fontFamily,
834
+ window: win
835
+ }) {
836
+ const reduceMotion2 = useReduceMotion();
837
+ const pulse = React8.useRef(new reactNative.Animated.Value(reduceMotion2 ? 1 : 0)).current;
838
+ React8.useEffect(() => {
839
+ if (reduceMotion2) {
840
+ pulse.stopAnimation();
841
+ pulse.setValue(1);
842
+ return;
843
+ }
844
+ pulse.setValue(0);
845
+ reactNative.Animated.timing(pulse, {
846
+ toValue: 1,
847
+ duration: 220,
848
+ useNativeDriver: true
849
+ }).start();
850
+ }, [seq, pulse, reduceMotion2]);
851
+ if (!chunkQAZ4TN3Z_js.isRectOnScreen(rect, win)) return null;
852
+ const frame = {
853
+ left: rect.x - PADDING,
854
+ top: rect.y - PADDING,
855
+ width: rect.width + PADDING * 2,
856
+ height: rect.height + PADDING * 2
857
+ };
858
+ const above = frame.top - CAPTION_GAP - CAPTION_HEIGHT >= 0;
859
+ const captionTop = above ? frame.top - CAPTION_GAP - CAPTION_HEIGHT : frame.top + frame.height + CAPTION_GAP;
860
+ const captionFits = captionTop + CAPTION_HEIGHT <= win.height;
861
+ return /* @__PURE__ */ React8__namespace.default.createElement(
862
+ reactNative.View,
863
+ {
864
+ ...APPILOTS_SKIP_PROPS,
865
+ pointerEvents: "none",
866
+ style: reactNative.StyleSheet.absoluteFill,
867
+ testID: "appilots-spotlight"
868
+ },
869
+ /* @__PURE__ */ React8__namespace.default.createElement(
870
+ reactNative.Animated.View,
871
+ {
872
+ ...APPILOTS_SKIP_PROPS,
873
+ pointerEvents: "none",
874
+ style: [
875
+ styles3.ring,
876
+ frame,
877
+ { borderColor: color },
878
+ {
879
+ opacity: pulse,
880
+ // Settles inward: the ring arrives slightly large and snaps
881
+ // to the control, which reads as "this one" rather than as a
882
+ // box that was always there.
883
+ transform: [
884
+ {
885
+ scale: pulse.interpolate({ inputRange: [0, 1], outputRange: [1.08, 1] })
886
+ }
887
+ ]
888
+ }
889
+ ]
890
+ }
891
+ ),
892
+ label && captionFits ? /* @__PURE__ */ React8__namespace.default.createElement(
893
+ reactNative.Animated.View,
894
+ {
895
+ ...APPILOTS_SKIP_PROPS,
896
+ pointerEvents: "none",
897
+ style: [
898
+ styles3.caption,
899
+ {
900
+ top: captionTop,
901
+ // Clamped so a control at either edge does not push the
902
+ // caption off screen.
903
+ left: Math.max(8, Math.min(frame.left, win.width - 8)),
904
+ maxWidth: win.width - 16,
905
+ backgroundColor: captionBackground,
906
+ opacity: pulse
907
+ }
908
+ ]
909
+ },
910
+ /* @__PURE__ */ React8__namespace.default.createElement(
911
+ reactNative.Text,
912
+ {
913
+ testID: "appilots-spotlight-label",
914
+ numberOfLines: 1,
915
+ style: [styles3.captionText, { color: captionColor, fontFamily }]
916
+ },
917
+ label
918
+ )
919
+ ) : null
920
+ );
921
+ }
922
+ var styles3 = reactNative.StyleSheet.create({
923
+ ring: {
924
+ position: "absolute",
925
+ borderWidth: 2.5,
926
+ borderRadius: 10
927
+ },
928
+ caption: {
929
+ position: "absolute",
930
+ height: CAPTION_HEIGHT,
931
+ justifyContent: "center",
932
+ paddingHorizontal: 10,
933
+ borderRadius: 8
934
+ },
935
+ captionText: { fontSize: 13, fontWeight: "500" }
936
+ });
937
+ var NEVER = () => () => {
938
+ };
939
+ var NULL_TARGET = () => null;
940
+ function useSpotlight(enabled) {
941
+ const subscribe2 = React8.useCallback(
942
+ (onChange) => enabled ? chunkJGUDXRXN_js.subscribeSpotlight(onChange) : NEVER(),
943
+ [enabled]
944
+ );
945
+ return React8.useSyncExternalStore(subscribe2, enabled ? chunkJGUDXRXN_js.getSpotlightTarget : NULL_TARGET, NULL_TARGET);
946
+ }
947
+
948
+ // src/components/pillStatus.ts
949
+ function resolvePillStatus(actions, busy, strings) {
950
+ for (let i = actions.length - 1; i >= 0; i--) {
951
+ const action = actions[i];
952
+ if (action.status === "executing") return chunkQAZ4TN3Z_js.describeAction(action, strings.locale);
953
+ }
954
+ if (!busy) {
955
+ for (let i = actions.length - 1; i >= 0; i--) {
956
+ const action = actions[i];
957
+ if (action.status === "completed" || action.status === "failed") {
958
+ return chunkQAZ4TN3Z_js.describeAction(action, strings.locale);
959
+ }
960
+ }
961
+ return { label: strings.done, state: "success" };
962
+ }
963
+ return { label: strings.working, state: "running" };
964
+ }
965
+ var STREAMING_PREFIX = "streaming_";
966
+ function announce(message) {
967
+ if (reactNative.Platform.OS === "ios" && reactNative.AccessibilityInfo.announceForAccessibilityWithOptions) {
968
+ reactNative.AccessibilityInfo.announceForAccessibilityWithOptions(message, { queue: true });
969
+ } else {
970
+ reactNative.AccessibilityInfo.announceForAccessibility(message);
971
+ }
972
+ }
973
+ var speakable = (content) => content.replace(/[*`#]+/g, "").trim();
974
+ function useChatAnnouncements({
975
+ messages,
976
+ actions,
977
+ awaitingApproval,
978
+ acting,
979
+ locale,
980
+ strings
981
+ }) {
982
+ const seenMessages = React8.useRef(null);
983
+ if (!seenMessages.current) seenMessages.current = new Set(messages.map((m) => m.id));
984
+ const seenActions = React8.useRef(null);
985
+ if (!seenActions.current) seenActions.current = new Map(actions.map((a) => [a.id, a.status]));
986
+ const prev = React8.useRef({ awaitingApproval, acting });
987
+ const namedSinceSettle = React8.useRef(false);
988
+ const localeRef = React8.useRef(locale);
989
+ localeRef.current = locale;
990
+ React8.useEffect(
991
+ () => chunkJGUDXRXN_js.subscribeSpotlightAnnouncement((label, verb) => {
992
+ namedSinceSettle.current = true;
993
+ announce(targetAnnouncement(verb, label, localeRef.current));
994
+ }),
995
+ []
996
+ );
997
+ React8.useEffect(() => {
998
+ const out = [];
999
+ for (const message of messages) {
1000
+ if (message.role === "user" || message.id.startsWith(STREAMING_PREFIX)) continue;
1001
+ if (seenMessages.current.has(message.id)) continue;
1002
+ seenMessages.current.add(message.id);
1003
+ const text = speakable(message.content);
1004
+ if (text) out.push(text);
1005
+ }
1006
+ for (const action of actions) {
1007
+ if (action.type === "confirm") continue;
1008
+ if (seenActions.current.get(action.id) === action.status) continue;
1009
+ seenActions.current.set(action.id, action.status);
1010
+ const line = actionAnnouncement(action, locale, namedSinceSettle.current);
1011
+ if (action.status === "completed" || action.status === "failed") {
1012
+ namedSinceSettle.current = false;
1013
+ }
1014
+ if (line) out.push(line);
1015
+ }
1016
+ if (awaitingApproval && !prev.current.awaitingApproval) out.push(strings.a11yAwaitingApproval);
1017
+ if (prev.current.acting && !acting) out.push(strings.a11yTurnDone);
1018
+ prev.current = { awaitingApproval, acting };
1019
+ for (const line of out) announce(line);
1020
+ }, [messages, actions, awaitingApproval, acting, locale, strings]);
1021
+ }
1022
+ function useStillWorking(active, template) {
1023
+ const [seconds, setSeconds] = React8.useState(0);
1024
+ React8.useEffect(() => {
1025
+ setSeconds(0);
1026
+ if (!active) return;
1027
+ return chunkQAZ4TN3Z_js.startStillWorkingTimer((elapsed) => {
1028
+ setSeconds(elapsed);
1029
+ reactNative.AccessibilityInfo.announceForAccessibility(template.replace("{seconds}", String(elapsed)));
1030
+ });
1031
+ }, [active, template]);
1032
+ return seconds;
1033
+ }
1034
+ function useVoiceInput({
1035
+ host,
1036
+ locale,
1037
+ onTranscript
1038
+ }) {
1039
+ const [state, setState] = React8.useState("idle");
1040
+ const [partial, setPartial] = React8.useState("");
1041
+ const mounted = React8.useRef(true);
1042
+ React8.useEffect(() => {
1043
+ mounted.current = true;
1044
+ return () => {
1045
+ mounted.current = false;
1046
+ };
1047
+ }, []);
1048
+ const onTranscriptRef = React8.useRef(onTranscript);
1049
+ onTranscriptRef.current = onTranscript;
1050
+ const stateRef = React8.useRef("idle");
1051
+ stateRef.current = state;
1052
+ React8.useEffect(() => {
1053
+ return () => {
1054
+ if (stateRef.current === "listening" || stateRef.current === "starting") {
1055
+ void host?.cancel().catch(() => {
1056
+ });
1057
+ }
1058
+ };
1059
+ }, [host]);
1060
+ const start = React8.useCallback(() => {
1061
+ if (!host) return;
1062
+ if (state !== "idle" && state !== "error") return;
1063
+ setState("starting");
1064
+ setPartial("");
1065
+ host.start({ locale }).then(() => {
1066
+ if (!mounted.current) return;
1067
+ setState("listening");
1068
+ }).catch((err) => {
1069
+ chunkQAZ4TN3Z_js.appilotsDebugWarn("useVoiceInput: start failed", err);
1070
+ if (!mounted.current) return;
1071
+ setState("error");
1072
+ });
1073
+ }, [host, locale, state]);
1074
+ const stop = React8.useCallback(() => {
1075
+ if (!host) return;
1076
+ if (state !== "listening" && state !== "starting") return;
1077
+ setState("stopping");
1078
+ host.stop().then((text) => {
1079
+ if (!mounted.current) return;
1080
+ setState("idle");
1081
+ setPartial("");
1082
+ const trimmed = text?.trim();
1083
+ if (trimmed) onTranscriptRef.current(trimmed);
1084
+ }).catch((err) => {
1085
+ chunkQAZ4TN3Z_js.appilotsDebugWarn("useVoiceInput: stop failed", err);
1086
+ if (!mounted.current) return;
1087
+ setState("error");
1088
+ setPartial("");
1089
+ });
1090
+ }, [host, state]);
1091
+ const cancel = React8.useCallback(() => {
1092
+ if (!host) return;
1093
+ setPartial("");
1094
+ setState("idle");
1095
+ void host.cancel().catch((err) => chunkQAZ4TN3Z_js.appilotsDebugWarn("useVoiceInput: cancel failed", err));
1096
+ }, [host]);
1097
+ React8.useEffect(() => {
1098
+ if (!host?.onPartial) return;
1099
+ if (state !== "listening") return;
1100
+ const dispose = host.onPartial((text) => {
1101
+ if (mounted.current) setPartial(text);
1102
+ });
1103
+ return dispose;
1104
+ }, [host, state]);
1105
+ React8.useEffect(() => {
1106
+ if (!host?.onEnd) return;
1107
+ if (state !== "listening") return;
1108
+ return host.onEnd((error) => {
1109
+ if (!mounted.current) return;
1110
+ setPartial("");
1111
+ setState(error ? "error" : "idle");
1112
+ });
1113
+ }, [host, state]);
1114
+ return { state, partial, start, stop, cancel };
1115
+ }
1116
+
1117
+ // src/components/experience.ts
1118
+ var DEFAULT_EXPERIENCE = {
1119
+ presence: "sheet",
1120
+ spotlight: "off",
1121
+ control: "agent",
1122
+ entry: ["fab"],
1123
+ input: ["text"]
1124
+ };
1125
+ function uniq(values) {
1126
+ return values.filter((value, index) => values.indexOf(value) === index);
1127
+ }
1128
+ function resolveExperience(requested, caps) {
1129
+ const downgrades = [];
1130
+ let presence = requested?.presence ?? DEFAULT_EXPERIENCE.presence;
1131
+ let spotlight = requested?.spotlight ?? DEFAULT_EXPERIENCE.spotlight;
1132
+ const control = requested?.control ?? DEFAULT_EXPERIENCE.control;
1133
+ const entry = uniq(requested?.entry ?? DEFAULT_EXPERIENCE.entry);
1134
+ let input = uniq(requested?.input ?? DEFAULT_EXPERIENCE.input);
1135
+ if (spotlight !== "off" && !caps.geometry) {
1136
+ downgrades.push({
1137
+ field: "spotlight",
1138
+ from: spotlight,
1139
+ to: "off",
1140
+ reason: 'spotlight needs Fabric window geometry, which this app cannot report. Enable the new React Native architecture, or set spotlight:"off" to silence this.'
1141
+ });
1142
+ spotlight = "off";
1143
+ }
1144
+ if (spotlight !== "off" && presence === "sheet") {
1145
+ downgrades.push({
1146
+ field: "presence",
1147
+ from: "sheet",
1148
+ to: "pill",
1149
+ reason: 'spotlight draws on the app, which the sheet covers. Set presence:"pill" or "hidden" explicitly to silence this.'
1150
+ });
1151
+ presence = "pill";
1152
+ }
1153
+ if (control === "shared" && presence === "sheet") {
1154
+ downgrades.push({
1155
+ field: "presence",
1156
+ from: "sheet",
1157
+ to: "pill",
1158
+ reason: 'control:"shared" needs the app to be touchable, and the sheet is a native Modal that swallows every touch. Set presence:"pill" or "hidden" to silence this.'
1159
+ });
1160
+ presence = "pill";
1161
+ }
1162
+ if (input.includes("voice") && !caps.speech) {
1163
+ downgrades.push({
1164
+ field: "input",
1165
+ from: input.join("+"),
1166
+ to: input.filter((mode) => mode !== "voice").join("+") || "text",
1167
+ reason: 'input:"voice" needs a SpeechHost passed to <AppilotsChat speech={...} />. The SDK ships no speech engine of its own \u2014 see https://docs.appilots.com/docs/guides/voice-input.'
1168
+ });
1169
+ input = input.filter((mode) => mode !== "voice");
1170
+ }
1171
+ if (input.length === 0) input = ["text"];
1172
+ return {
1173
+ experience: { presence, spotlight, control, entry, input },
1174
+ downgrades
1175
+ };
1176
+ }
1177
+ function formatDowngrades(downgrades) {
1178
+ return downgrades.map(
1179
+ (d) => `[appilots] experience.${d.field}: "${d.from}" -> "${d.to}". ${d.reason}`
1180
+ );
1181
+ }
1182
+
1183
+ // src/components/presence.ts
1184
+ function resolveSurface(presence, activity) {
1185
+ if (presence === "sheet") return activity.open ? "sheet" : "none";
1186
+ if (activity.awaitingUser) return "sheet";
1187
+ if (activity.busy && (activity.acting || !activity.open)) return "pill";
1188
+ if (activity.hostModalOpen && !activity.explicitlyOpened && (activity.open || activity.unread))
1189
+ return "pill";
1190
+ if (activity.open) return "sheet";
1191
+ if (activity.unread) return "pill";
1192
+ return "none";
1193
+ }
1194
+ function shouldReopenOnTurnEnd(presence) {
1195
+ return presence === "pill";
1196
+ }
1197
+ function usesPill(presence) {
1198
+ return presence !== "sheet";
1199
+ }
482
1200
  function HeadsetIcon({ size = 18, color = "#ffffff" }) {
483
- return /* @__PURE__ */ React7__namespace.createElement(Svg__default.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React7__namespace.createElement(
1201
+ return /* @__PURE__ */ React8__namespace.createElement(Svg__default.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React8__namespace.createElement(
484
1202
  Svg.Path,
485
1203
  {
486
1204
  d: "M12 3a8 8 0 0 0-8 8v5.5A2.5 2.5 0 0 0 6.5 19H8a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H6v-1a6 6 0 0 1 12 0v1h-2a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h1.5a2.5 2.5 0 0 0 2.5-2.5V11a8 8 0 0 0-8-8z",
@@ -521,215 +1239,26 @@ function buildChatTimeline(messages, actions) {
521
1239
  }
522
1240
  return timeline;
523
1241
  }
524
-
525
- // src/components/markdownContent.ts
526
- var ORDERED_LINE = /^\s*(\d+)\.\s+(.+)$/;
527
- var BULLET_LINE = /^\s*[-*•]\s+(.+)$/;
528
- var HEADING_LINE = /^\s*(#{1,6})\s+(.+)$/;
529
- var FENCE_LINE = /^\s*```\s*([A-Za-z0-9+#_-]*)\s*$/;
530
- var INLINE_PATTERN = /\[([^\]\n]+)\]\((https?:\/\/[^\s)]+)\)|\*\*(.+?)\*\*|__(.+?)__|`([^`]+)`|\*(.+?)\*|_(.+?)_/g;
531
- var MIN_ENHANCE_LENGTH = 80;
532
- var SENTENCE_SPLIT = /[^.!?]+[.!?]+(?=\s+[A-ZÁÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕÇÑ¿¡"“]|$)|[^.!?]+$/g;
533
- var CAPABILITY_SENTENCE = /^((?:No aplicativo,?|In (?:this|the) app,?|En la aplicaci[oó]n,?|Dans l['’]application,?)?(?:\s+(?:voc[eê]|voce|you|tu|usted|puedes|puede|peux))?\s*(?:pode(?:m|r)?|can|could|puedes|puede|peux|peut))\s+(.+?)\.?\s*$/i;
534
- var INCLUDE_LIST_SENTENCE = /^(.+?)\s+(?:incluem|inclui|include|includes|incluye|incluyen|such as|for example|par exemple|por exemplo)\s+(.+?)\.?\s*$/i;
535
- function looksLikeMarkdown(content) {
536
- if (!content) return false;
537
- return /\*\*.+?\*\*/.test(content) || /__.+?__/.test(content) || /`[^`\n]+`/.test(content) || /^\s*[-*•]\s+/m.test(content) || /^\s*\d+\.\s+/m.test(content) || /^\s*#{1,6}\s+/m.test(content) || /^\s*```/m.test(content) || /\[[^\]\n]+\]\(https?:\/\/[^\s)]+\)/.test(content);
538
- }
539
- function splitEnumeration(text) {
540
- const trimmed = text.trim().replace(/\.\s*$/, "");
541
- if (!trimmed) return [];
542
- const commaParts = trimmed.split(",").map((part) => part.trim()).filter(Boolean);
543
- if (commaParts.length <= 1) {
544
- const conjParts = trimmed.split(/\s+(?:e|and|y|ou|or)\s+/i).map((part) => part.trim());
545
- return conjParts.filter(Boolean);
546
- }
547
- const last = commaParts[commaParts.length - 1];
548
- const conjMatch = last.match(/^(.+?)\s+(?:e|and|y|ou|or)\s+(.+)$/i);
549
- if (conjMatch) {
550
- commaParts[commaParts.length - 1] = conjMatch[1].trim();
551
- commaParts.push(conjMatch[2].trim());
552
- }
553
- return commaParts.filter(Boolean);
554
- }
555
- function splitSentences(text) {
556
- const matches = text.match(SENTENCE_SPLIT);
557
- if (!matches) return [text.trim()];
558
- return matches.map((part) => part.trim()).filter(Boolean);
559
- }
560
- function formatCapabilitySentence(sentence) {
561
- const match = CAPABILITY_SENTENCE.exec(sentence.trim());
562
- if (!match) return null;
563
- const items = splitEnumeration(match[2] ?? "");
564
- if (items.length < 3) return null;
565
- const intro = `${match[1].trim()}:`;
566
- return `${intro}
567
- ${items.map((item) => `- ${item}`).join("\n")}`;
568
- }
569
- function formatIncludeListSentence(sentence) {
570
- const match = INCLUDE_LIST_SENTENCE.exec(sentence.trim());
571
- if (!match) return null;
572
- const intro = match[1].trim().replace(/[,:]\s*$/, "");
573
- const items = splitEnumeration(match[2] ?? "");
574
- if (items.length < 2) return null;
575
- return `${intro}:
576
- ${items.map((item) => `- ${item}`).join("\n")}`;
577
- }
578
- function formatReadableSentence(sentence) {
579
- return formatCapabilitySentence(sentence) ?? formatIncludeListSentence(sentence) ?? sentence.trim();
580
- }
581
- function enhancePlainAssistantContent(content) {
582
- if (!content?.trim() || looksLikeMarkdown(content)) return content;
583
- const trimmed = content.trim();
584
- if (trimmed.length < MIN_ENHANCE_LENGTH) return content;
585
- const sentences = splitSentences(trimmed);
586
- if (sentences.length === 0) return content;
587
- const blocks = sentences.map(formatReadableSentence);
588
- const enhanced = blocks.join("\n\n");
589
- return enhanced || content;
590
- }
591
- function needsWideChatLayout(content) {
592
- if (!content?.trim()) return false;
593
- const prepared = enhancePlainAssistantContent(content);
594
- return looksLikeMarkdown(prepared) || /\n\n+/.test(prepared);
595
- }
596
- function parseMarkdownBlocks(content) {
597
- const lines = content.replace(/\r\n/g, "\n").split("\n");
598
- const blocks = [];
599
- let paragraph = [];
600
- let bulletItems = [];
601
- let orderedItems = [];
602
- let codeLines = null;
603
- let codeLanguage;
604
- const flushParagraph = () => {
605
- if (paragraph.length === 0) return;
606
- blocks.push({ kind: "paragraph", text: paragraph.join("\n") });
607
- paragraph = [];
608
- };
609
- const flushBullets = () => {
610
- if (bulletItems.length === 0) return;
611
- blocks.push({ kind: "bullet", items: bulletItems });
612
- bulletItems = [];
613
- };
614
- const flushOrdered = () => {
615
- if (orderedItems.length === 0) return;
616
- blocks.push({ kind: "ordered", items: orderedItems });
617
- orderedItems = [];
618
- };
619
- const flushLists = () => {
620
- flushBullets();
621
- flushOrdered();
622
- };
623
- const flushCode = () => {
624
- if (codeLines === null) return;
625
- blocks.push({
626
- kind: "codeblock",
627
- code: codeLines.join("\n"),
628
- ...codeLanguage ? { language: codeLanguage } : {}
629
- });
630
- codeLines = null;
631
- codeLanguage = void 0;
632
- };
633
- for (const line of lines) {
634
- if (codeLines !== null) {
635
- if (/^\s*```\s*$/.test(line)) {
636
- flushCode();
637
- } else {
638
- codeLines.push(line);
639
- }
640
- continue;
641
- }
642
- const fence = FENCE_LINE.exec(line);
643
- if (fence) {
644
- flushParagraph();
645
- flushLists();
646
- codeLines = [];
647
- codeLanguage = fence[1] || void 0;
648
- continue;
649
- }
650
- const trimmed = line.trim();
651
- if (!trimmed) {
652
- flushParagraph();
653
- flushLists();
654
- continue;
655
- }
656
- const heading = HEADING_LINE.exec(line);
657
- if (heading) {
658
- flushParagraph();
659
- flushLists();
660
- const level = Math.min(heading[1].length, 3);
661
- blocks.push({ kind: "heading", level, text: heading[2].trim() });
662
- continue;
663
- }
664
- const ordered = ORDERED_LINE.exec(line);
665
- if (ordered) {
666
- flushParagraph();
667
- flushBullets();
668
- orderedItems.push(ordered[2].trim());
669
- continue;
670
- }
671
- const bullet = BULLET_LINE.exec(line);
672
- if (bullet) {
673
- flushParagraph();
674
- flushOrdered();
675
- bulletItems.push(bullet[1].trim());
676
- continue;
677
- }
678
- flushLists();
679
- paragraph.push(line);
680
- }
681
- flushParagraph();
682
- flushLists();
683
- flushCode();
684
- return blocks.length > 0 ? blocks : [{ kind: "paragraph", text: content }];
685
- }
686
- function parseInlineMarkdown(text) {
687
- if (!text) return [{ kind: "text", value: "" }];
688
- const segments = [];
689
- let lastIndex = 0;
690
- INLINE_PATTERN.lastIndex = 0;
691
- for (let match = INLINE_PATTERN.exec(text); match; match = INLINE_PATTERN.exec(text)) {
692
- if (match.index > lastIndex) {
693
- segments.push({ kind: "text", value: text.slice(lastIndex, match.index) });
694
- }
695
- if (match[1] && match[2]) {
696
- segments.push({ kind: "link", value: match[1].trim(), href: match[2] });
697
- } else if (match[3] || match[4]) {
698
- segments.push({ kind: "bold", value: (match[3] ?? match[4]).trim() });
699
- } else if (match[5]) {
700
- segments.push({ kind: "code", value: match[5] });
701
- } else if (match[6] || match[7]) {
702
- segments.push({ kind: "italic", value: (match[6] ?? match[7]).trim() });
703
- }
704
- lastIndex = INLINE_PATTERN.lastIndex;
705
- }
706
- if (lastIndex < text.length) {
707
- segments.push({ kind: "text", value: text.slice(lastIndex) });
708
- }
709
- return segments.length > 0 ? segments : [{ kind: "text", value: text }];
710
- }
711
-
712
- // src/components/ChatMarkdown.tsx
713
1242
  function segmentKey(segment, index) {
714
1243
  return `${segment.kind}-${index}-${segment.value.slice(0, 12)}`;
715
1244
  }
716
1245
  function renderInlineSegments(text, theme, baseStyle) {
717
- const segments = parseInlineMarkdown(text);
1246
+ const segments = chunkQAZ4TN3Z_js.parseInlineMarkdown(text);
718
1247
  return segments.map((segment, index) => {
719
1248
  const key = segmentKey(segment, index);
720
1249
  switch (segment.kind) {
721
1250
  case "bold":
722
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { key, style: [baseStyle, styles2.bold] }, segment.value);
1251
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { key, style: [baseStyle, styles4.bold] }, segment.value);
723
1252
  case "italic":
724
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { key, style: [baseStyle, styles2.italic] }, segment.value);
1253
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { key, style: [baseStyle, styles4.italic] }, segment.value);
725
1254
  case "code":
726
- return /* @__PURE__ */ React7__namespace.default.createElement(
1255
+ return /* @__PURE__ */ React8__namespace.default.createElement(
727
1256
  reactNative.Text,
728
1257
  {
729
1258
  key,
730
1259
  style: [
731
1260
  baseStyle,
732
- styles2.code,
1261
+ styles4.code,
733
1262
  {
734
1263
  backgroundColor: theme.codeBackground ?? (theme.variant === "user" ? "rgba(255,255,255,0.22)" : "rgba(0,0,0,0.06)"),
735
1264
  color: theme.codeColor ?? theme.color
@@ -739,14 +1268,14 @@ function renderInlineSegments(text, theme, baseStyle) {
739
1268
  segment.value
740
1269
  );
741
1270
  case "link":
742
- return /* @__PURE__ */ React7__namespace.default.createElement(
1271
+ return /* @__PURE__ */ React8__namespace.default.createElement(
743
1272
  reactNative.Text,
744
1273
  {
745
1274
  key,
746
1275
  accessibilityRole: "link",
747
1276
  style: [
748
1277
  baseStyle,
749
- styles2.link,
1278
+ styles4.link,
750
1279
  {
751
1280
  color: theme.linkColor ?? (theme.variant === "user" ? theme.color : "#2563EB")
752
1281
  }
@@ -773,39 +1302,39 @@ function InlineMarkdown({
773
1302
  fontSize: theme.fontSize,
774
1303
  lineHeight: theme.lineHeight
775
1304
  };
776
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: baseStyle }, renderInlineSegments(text, theme, baseStyle));
1305
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: baseStyle }, renderInlineSegments(text, theme, baseStyle));
777
1306
  }
778
1307
  function ChatMarkdown({ content, theme, contentWidth }) {
779
- const prepared = enhancePlainAssistantContent(content);
1308
+ const prepared = chunkQAZ4TN3Z_js.enhancePlainAssistantContent(content);
780
1309
  const baseTextStyle = {
781
1310
  color: theme.color,
782
1311
  fontFamily: theme.fontFamily,
783
1312
  fontSize: theme.fontSize,
784
1313
  lineHeight: theme.lineHeight
785
1314
  };
786
- const rootStyle = contentWidth ? [styles2.root, { width: contentWidth }] : styles2.root;
787
- if (!looksLikeMarkdown(prepared)) {
1315
+ const rootStyle = contentWidth ? [styles4.root, { width: contentWidth }] : styles4.root;
1316
+ if (!chunkQAZ4TN3Z_js.looksLikeMarkdown(prepared)) {
788
1317
  const paragraphs = prepared.split(/\n\n+/).map((part) => part.trim()).filter(Boolean);
789
1318
  if (paragraphs.length > 1) {
790
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: rootStyle }, paragraphs.map((paragraph, index) => /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { key: `plain-p-${index}`, style: index > 0 ? styles2.blockGap : void 0 }, /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: baseTextStyle }, paragraph))));
1319
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: rootStyle }, paragraphs.map((paragraph, index) => /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { key: `plain-p-${index}`, style: index > 0 ? styles4.blockGap : void 0 }, /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: baseTextStyle }, paragraph))));
791
1320
  }
792
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: baseTextStyle }, prepared);
1321
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: baseTextStyle }, prepared);
793
1322
  }
794
- const blocks = parseMarkdownBlocks(prepared);
795
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: rootStyle }, blocks.map((block, blockIndex) => {
1323
+ const blocks = chunkQAZ4TN3Z_js.parseMarkdownBlocks(prepared);
1324
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: rootStyle }, blocks.map((block, blockIndex) => {
796
1325
  if (block.kind === "paragraph") {
797
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { key: `p-${blockIndex}`, style: blockIndex > 0 ? styles2.blockGap : void 0 }, /* @__PURE__ */ React7__namespace.default.createElement(InlineMarkdown, { text: block.text, theme }));
1326
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { key: `p-${blockIndex}`, style: blockIndex > 0 ? styles4.blockGap : void 0 }, /* @__PURE__ */ React8__namespace.default.createElement(InlineMarkdown, { text: block.text, theme }));
798
1327
  }
799
1328
  if (block.kind === "heading") {
800
1329
  const scale = block.level === 1 ? 1.25 : block.level === 2 ? 1.15 : 1.05;
801
1330
  const headingSize = Math.round((theme.fontSize ?? 15) * scale);
802
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { key: `h-${blockIndex}`, style: blockIndex > 0 ? styles2.blockGap : void 0 }, /* @__PURE__ */ React7__namespace.default.createElement(
1331
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { key: `h-${blockIndex}`, style: blockIndex > 0 ? styles4.blockGap : void 0 }, /* @__PURE__ */ React8__namespace.default.createElement(
803
1332
  reactNative.Text,
804
1333
  {
805
1334
  accessibilityRole: "header",
806
1335
  style: [
807
1336
  baseTextStyle,
808
- styles2.bold,
1337
+ styles4.bold,
809
1338
  { fontSize: headingSize, lineHeight: Math.round(headingSize * 1.35) }
810
1339
  ]
811
1340
  },
@@ -817,23 +1346,23 @@ function ChatMarkdown({ content, theme, contentWidth }) {
817
1346
  ));
818
1347
  }
819
1348
  if (block.kind === "codeblock") {
820
- return /* @__PURE__ */ React7__namespace.default.createElement(
1349
+ return /* @__PURE__ */ React8__namespace.default.createElement(
821
1350
  reactNative.View,
822
1351
  {
823
1352
  key: `code-${blockIndex}`,
824
1353
  style: [
825
- styles2.codeBlock,
826
- blockIndex > 0 ? styles2.blockGap : void 0,
1354
+ styles4.codeBlock,
1355
+ blockIndex > 0 ? styles4.blockGap : void 0,
827
1356
  {
828
1357
  backgroundColor: theme.codeBackground ?? (theme.variant === "user" ? "rgba(255,255,255,0.18)" : "rgba(0,0,0,0.055)")
829
1358
  }
830
1359
  ]
831
1360
  },
832
- /* @__PURE__ */ React7__namespace.default.createElement(
1361
+ /* @__PURE__ */ React8__namespace.default.createElement(
833
1362
  reactNative.Text,
834
1363
  {
835
1364
  style: [
836
- styles2.code,
1365
+ styles4.code,
837
1366
  {
838
1367
  color: theme.codeColor ?? theme.color,
839
1368
  fontSize: (theme.fontSize ?? 15) - 1,
@@ -846,28 +1375,28 @@ function ChatMarkdown({ content, theme, contentWidth }) {
846
1375
  );
847
1376
  }
848
1377
  if (block.kind === "bullet") {
849
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { key: `ul-${blockIndex}`, style: blockIndex > 0 ? styles2.blockGap : void 0 }, block.items.map((item, itemIndex) => /* @__PURE__ */ React7__namespace.default.createElement(
1378
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { key: `ul-${blockIndex}`, style: blockIndex > 0 ? styles4.blockGap : void 0 }, block.items.map((item, itemIndex) => /* @__PURE__ */ React8__namespace.default.createElement(
850
1379
  reactNative.Text,
851
1380
  {
852
1381
  key: `ul-${blockIndex}-${itemIndex}`,
853
- style: [baseTextStyle, itemIndex > 0 ? styles2.listItemGap : void 0]
1382
+ style: [baseTextStyle, itemIndex > 0 ? styles4.listItemGap : void 0]
854
1383
  },
855
1384
  "\u2022 ",
856
1385
  renderInlineSegments(item, theme, baseTextStyle)
857
1386
  )));
858
1387
  }
859
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { key: `ol-${blockIndex}`, style: blockIndex > 0 ? styles2.blockGap : void 0 }, block.items.map((item, itemIndex) => /* @__PURE__ */ React7__namespace.default.createElement(
1388
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { key: `ol-${blockIndex}`, style: blockIndex > 0 ? styles4.blockGap : void 0 }, block.items.map((item, itemIndex) => /* @__PURE__ */ React8__namespace.default.createElement(
860
1389
  reactNative.Text,
861
1390
  {
862
1391
  key: `ol-${blockIndex}-${itemIndex}`,
863
- style: [baseTextStyle, itemIndex > 0 ? styles2.listItemGap : void 0]
1392
+ style: [baseTextStyle, itemIndex > 0 ? styles4.listItemGap : void 0]
864
1393
  },
865
1394
  `${itemIndex + 1}. `,
866
1395
  renderInlineSegments(item, theme, baseTextStyle)
867
1396
  )));
868
1397
  }));
869
1398
  }
870
- var styles2 = reactNative.StyleSheet.create({
1399
+ var styles4 = reactNative.StyleSheet.create({
871
1400
  root: {
872
1401
  flexShrink: 1,
873
1402
  alignSelf: "stretch"
@@ -900,21 +1429,21 @@ var styles2 = reactNative.StyleSheet.create({
900
1429
  textDecorationLine: "underline"
901
1430
  }
902
1431
  });
903
- var ThemeContext = React7.createContext(chunkSUMIABJK_js.defaultLightTheme);
1432
+ var ThemeContext = React8.createContext(chunkQAZ4TN3Z_js.defaultLightTheme);
904
1433
  function AppilotsThemeProvider({
905
1434
  theme,
906
1435
  mode = "auto",
907
1436
  children
908
1437
  }) {
909
1438
  const systemScheme = reactNative.useColorScheme();
910
- const tokens = React7.useMemo(
911
- () => chunkSUMIABJK_js.mergeThemeTokens(chunkSUMIABJK_js.resolveBaseTheme(mode, systemScheme), theme ?? void 0),
1439
+ const tokens = React8.useMemo(
1440
+ () => chunkQAZ4TN3Z_js.mergeThemeTokens(chunkQAZ4TN3Z_js.resolveBaseTheme(mode, systemScheme), theme ?? void 0),
912
1441
  [mode, systemScheme, theme]
913
1442
  );
914
- return /* @__PURE__ */ React7__namespace.default.createElement(ThemeContext.Provider, { value: tokens }, children);
1443
+ return /* @__PURE__ */ React8__namespace.default.createElement(ThemeContext.Provider, { value: tokens }, children);
915
1444
  }
916
1445
  function useAppilotsTheme() {
917
- return React7.useContext(ThemeContext);
1446
+ return React8.useContext(ThemeContext);
918
1447
  }
919
1448
 
920
1449
  // src/theme/tailwindBridge.ts
@@ -1004,177 +1533,6 @@ var appilotsTheme = {
1004
1533
  fromTailwind: appilotsThemeFromTailwind
1005
1534
  };
1006
1535
 
1007
- // src/i18n/bundles/pt-BR.ts
1008
- var ptBR = {
1009
- chatTitle: "Assistente Appilots",
1010
- clearButton: "Limpar",
1011
- inputPlaceholder: "Digite uma mensagem...",
1012
- emptyTitle: "Como posso ajudar?",
1013
- emptySubtitle: "Navego, preencho formul\xE1rios e executo a\xE7\xF5es neste app.",
1014
- thinking: "Pensando...",
1015
- statusAnalyzing: "Analisando a tela...",
1016
- statusWaitingApp: "Aguardando o app responder...",
1017
- statusAdjusting: "Ajustando o plano...",
1018
- poweredBy: "Powered by Appilots",
1019
- approve: "Aprovar",
1020
- reject: "Rejeitar",
1021
- cancelledByUser: "Cancelado pelo usu\xE1rio",
1022
- confirmDestructiveTitle: "A\xE7\xE3o destrutiva",
1023
- confirmTitle: "Confirma\xE7\xE3o necess\xE1ria",
1024
- confirmMessage: 'Tem certeza que deseja "{action}"?',
1025
- confirmDestructiveApprove: "Sim, executar",
1026
- confirmApprove: "Confirmar",
1027
- confirmCancel: "Cancelar",
1028
- confirmThisAction: "esta a\xE7\xE3o",
1029
- unknownAction: "A\xE7\xE3o desconhecida",
1030
- somethingWentWrong: "Algo deu errado",
1031
- openChatA11y: "Abrir chat do assistente",
1032
- closeChatA11y: "Fechar chat do assistente",
1033
- stopGeneratingA11y: "Parar gera\xE7\xE3o",
1034
- talkToHumanA11y: "Falar com um atendente humano",
1035
- humanAgentLabel: "Atendente",
1036
- escalationRequested: "Certo! Chamei um atendente humano. Voc\xEA pode continuar usando o app normalmente enquanto isso.",
1037
- escalationConnected: "Um atendente entrou na conversa.",
1038
- escalationResolved: "O atendimento humano foi encerrado. Voltei a te ajudar por aqui.",
1039
- escalationOffer: "Se preferir, posso chamar uma pessoa para ajudar.",
1040
- escalationOfferChip: "Falar com um atendente",
1041
- escalationPendingBanner: "Aguardando um atendente...",
1042
- escalationActiveBanner: "Voc\xEA est\xE1 falando com um atendente"
1043
- };
1044
-
1045
- // src/i18n/bundles/en.ts
1046
- var en = {
1047
- chatTitle: "Appilots Assistant",
1048
- clearButton: "Clear",
1049
- inputPlaceholder: "Type a message...",
1050
- emptyTitle: "How can I help?",
1051
- emptySubtitle: "I navigate, fill forms, and run actions in this app.",
1052
- thinking: "Thinking...",
1053
- statusAnalyzing: "Reading the screen...",
1054
- statusWaitingApp: "Waiting for the app...",
1055
- statusAdjusting: "Adjusting the plan...",
1056
- poweredBy: "Powered by Appilots",
1057
- approve: "Approve",
1058
- reject: "Reject",
1059
- cancelledByUser: "Cancelled by user",
1060
- confirmDestructiveTitle: "Destructive action",
1061
- confirmTitle: "Confirmation needed",
1062
- confirmMessage: 'Are you sure you want to "{action}"?',
1063
- confirmDestructiveApprove: "Yes, do it",
1064
- confirmApprove: "Confirm",
1065
- confirmCancel: "Cancel",
1066
- confirmThisAction: "this action",
1067
- unknownAction: "Unknown action",
1068
- somethingWentWrong: "Something went wrong",
1069
- openChatA11y: "Open assistant chat",
1070
- closeChatA11y: "Close assistant chat",
1071
- stopGeneratingA11y: "Stop generating",
1072
- talkToHumanA11y: "Talk to a human agent",
1073
- humanAgentLabel: "Agent",
1074
- escalationRequested: "Done! I've called a human agent. You can keep using the app normally in the meantime.",
1075
- escalationConnected: "A human agent joined the conversation.",
1076
- escalationResolved: "The human handoff has ended. I'm back to help you here.",
1077
- escalationOffer: "If you prefer, I can bring in a person to help.",
1078
- escalationOfferChip: "Talk to a human",
1079
- escalationPendingBanner: "Waiting for a human agent...",
1080
- escalationActiveBanner: "You're talking to a human agent"
1081
- };
1082
-
1083
- // src/i18n/bundles/es.ts
1084
- var es = {
1085
- chatTitle: "Asistente Appilots",
1086
- clearButton: "Limpiar",
1087
- inputPlaceholder: "Escribe un mensaje...",
1088
- emptyTitle: "\xBFEn qu\xE9 puedo ayudarte?",
1089
- emptySubtitle: "Navego, relleno formularios y ejecuto acciones en esta app.",
1090
- thinking: "Pensando...",
1091
- statusAnalyzing: "Analizando la pantalla...",
1092
- statusWaitingApp: "Esperando a la app...",
1093
- statusAdjusting: "Ajustando el plan...",
1094
- poweredBy: "Hecho con Appilots",
1095
- approve: "Aprobar",
1096
- reject: "Rechazar",
1097
- cancelledByUser: "Cancelado por el usuario",
1098
- confirmDestructiveTitle: "Acci\xF3n destructiva",
1099
- confirmTitle: "Confirmaci\xF3n necesaria",
1100
- confirmMessage: '\xBFSeguro que quieres "{action}"?',
1101
- confirmDestructiveApprove: "S\xED, ejecutar",
1102
- confirmApprove: "Confirmar",
1103
- confirmCancel: "Cancelar",
1104
- confirmThisAction: "esta acci\xF3n",
1105
- unknownAction: "Acci\xF3n desconocida",
1106
- somethingWentWrong: "Algo sali\xF3 mal",
1107
- openChatA11y: "Abrir chat del asistente",
1108
- closeChatA11y: "Cerrar chat del asistente",
1109
- stopGeneratingA11y: "Detener generaci\xF3n",
1110
- talkToHumanA11y: "Hablar con un agente humano",
1111
- humanAgentLabel: "Agente",
1112
- escalationRequested: "\xA1Listo! Llam\xE9 a un agente humano. Mientras tanto puedes seguir usando la app con normalidad.",
1113
- escalationConnected: "Un agente humano se uni\xF3 a la conversaci\xF3n.",
1114
- escalationResolved: "La atenci\xF3n humana termin\xF3. Vuelvo a ayudarte por aqu\xED.",
1115
- escalationOffer: "Si prefieres, puedo llamar a una persona para ayudarte.",
1116
- escalationOfferChip: "Hablar con un agente",
1117
- escalationPendingBanner: "Esperando a un agente...",
1118
- escalationActiveBanner: "Est\xE1s hablando con un agente humano"
1119
- };
1120
- var BUNDLES = {
1121
- "pt-BR": ptBR,
1122
- en,
1123
- es
1124
- };
1125
- var DEFAULT_LOCALE = "en";
1126
- function detectDeviceLocale() {
1127
- try {
1128
- let raw;
1129
- if (reactNative.Platform.OS === "ios") {
1130
- const settings = reactNative.NativeModules?.SettingsManager?.settings;
1131
- raw = settings?.AppleLocale || (Array.isArray(settings?.AppleLanguages) ? settings?.AppleLanguages?.[0] : void 0);
1132
- } else if (reactNative.Platform.OS === "android") {
1133
- raw = reactNative.NativeModules?.I18nManager?.localeIdentifier;
1134
- }
1135
- if (!raw || typeof raw !== "string") return null;
1136
- const lower = raw.toLowerCase().replace("_", "-");
1137
- if (lower.startsWith("pt")) return "pt-BR";
1138
- if (lower.startsWith("es")) return "es";
1139
- if (lower.startsWith("en")) return "en";
1140
- return null;
1141
- } catch {
1142
- return null;
1143
- }
1144
- }
1145
- function resolveLocale(prop) {
1146
- if (prop && BUNDLES[prop]) return prop;
1147
- const detected = detectDeviceLocale();
1148
- if (detected && BUNDLES[detected]) return detected;
1149
- return DEFAULT_LOCALE;
1150
- }
1151
- var I18nContext = React7.createContext(null);
1152
- function AppilotsI18nProvider({
1153
- locale,
1154
- overrides,
1155
- children
1156
- }) {
1157
- const value = React7.useMemo(() => {
1158
- const resolved = resolveLocale(locale ?? null);
1159
- const merged = overrides ? { ...BUNDLES[resolved], ...overrides } : BUNDLES[resolved];
1160
- return {
1161
- locale: resolved,
1162
- strings: merged,
1163
- t: (key) => merged[key]
1164
- };
1165
- }, [locale, overrides]);
1166
- return /* @__PURE__ */ React7__namespace.default.createElement(I18nContext.Provider, { value }, children);
1167
- }
1168
- function useAppilotsI18n() {
1169
- const ctx = React7.useContext(I18nContext);
1170
- if (ctx) return ctx;
1171
- return {
1172
- locale: DEFAULT_LOCALE,
1173
- strings: BUNDLES[DEFAULT_LOCALE],
1174
- t: (key) => BUNDLES[DEFAULT_LOCALE][key]
1175
- };
1176
- }
1177
-
1178
1536
  // src/components/AppilotsChat.tsx
1179
1537
  function translateLegacyTheme(legacy) {
1180
1538
  const out = {};
@@ -1202,34 +1560,42 @@ function isImageSource(value) {
1202
1560
  return typeof value === "number" || /^https?:\/\//i.test(value.trim());
1203
1561
  }
1204
1562
  var { height: SCREEN_HEIGHT, width: SCREEN_WIDTH } = reactNative.Dimensions.get("window");
1563
+ var A11Y_FOCUS_DELAY_MS = 500;
1205
1564
  var CHAT_HORIZONTAL_PADDING = 16;
1206
1565
  var BUBBLE_HORIZONTAL_PADDING = 14;
1207
1566
  var ASSISTANT_CONTENT_WIDTH = SCREEN_WIDTH - CHAT_HORIZONTAL_PADDING * 2 - BUBBLE_HORIZONTAL_PADDING * 2;
1208
- var APPILOTS_SKIP_PROPS = {
1209
- __appilotsSkip: true,
1210
- __appilotsInternal: true
1211
- };
1567
+ var MIN_TOUCH_TARGET2 = 44;
1568
+ var LARGE_TEXT_FONT_SCALE = 1.6;
1569
+ var INPUT_MAX_HEIGHT = 120;
1212
1570
  function AppilotsChat(props) {
1213
- const { degraded } = chunkSUMIABJK_js.useAppilotsContext();
1571
+ const { degraded } = chunkQAZ4TN3Z_js.useAppilotsContext();
1214
1572
  if (degraded) return null;
1215
- return /* @__PURE__ */ React7__namespace.default.createElement(chunkSUMIABJK_js.AppilotsErrorBoundary, { surface: "chat", fallback: null }, /* @__PURE__ */ React7__namespace.default.createElement(AppilotsChatSurface, { ...props }));
1573
+ return /* @__PURE__ */ React8__namespace.default.createElement(chunkQAZ4TN3Z_js.AppilotsErrorBoundary, { surface: "chat", fallback: null }, /* @__PURE__ */ React8__namespace.default.createElement(AppilotsChatSurface, { ...props }));
1216
1574
  }
1217
1575
  function AppilotsChatSurface(props) {
1218
- const { remotePersonalization } = chunkSUMIABJK_js.useAppilotsContext();
1219
- const themeProp = React7.useMemo(() => {
1576
+ const [conversationLocale, setConversationLocale] = React8.useState(null);
1577
+ const { remotePersonalization } = chunkQAZ4TN3Z_js.useAppilotsContext();
1578
+ const themeProp = React8.useMemo(() => {
1220
1579
  if (!props.theme) return void 0;
1221
1580
  return isLegacyTheme(props.theme) ? translateLegacyTheme(props.theme) : props.theme;
1222
1581
  }, [props.theme]);
1223
- return /* @__PURE__ */ React7__namespace.default.createElement(
1582
+ return /* @__PURE__ */ React8__namespace.default.createElement(
1224
1583
  AppilotsThemeProvider,
1225
1584
  {
1226
1585
  theme: resolveTheme(themeProp, remotePersonalization),
1227
1586
  mode: resolveThemeMode(props.themeMode, remotePersonalization)
1228
1587
  },
1229
- /* @__PURE__ */ React7__namespace.default.createElement(AppilotsI18nProvider, { locale: resolveLocaleProp(props.locale, remotePersonalization) }, /* @__PURE__ */ React7__namespace.default.createElement(AppilotsChatInner, { ...props }))
1588
+ /* @__PURE__ */ React8__namespace.default.createElement(
1589
+ chunkJGUDXRXN_js.AppilotsI18nProvider,
1590
+ {
1591
+ locale: conversationLocale ?? resolveLocaleProp(props.locale, remotePersonalization)
1592
+ },
1593
+ /* @__PURE__ */ React8__namespace.default.createElement(AppilotsChatInner, { ...props, onReplyLocaleChange: setConversationLocale })
1594
+ )
1230
1595
  );
1231
1596
  }
1232
1597
  function AppilotsChatInner({
1598
+ onReplyLocaleChange,
1233
1599
  visible: controlledVisible,
1234
1600
  onClose,
1235
1601
  placeholder,
@@ -1245,20 +1611,28 @@ function AppilotsChatInner({
1245
1611
  triggerButton = "default",
1246
1612
  triggerIcon,
1247
1613
  triggerButtonColor: triggerButtonColorProp,
1248
- triggerButtonImage: triggerButtonImageProp
1614
+ triggerButtonImage: triggerButtonImageProp,
1615
+ experience: experienceProp,
1616
+ speech: speechProp
1249
1617
  }) {
1250
1618
  const theme = useAppilotsTheme();
1251
- const { strings, t } = useAppilotsI18n();
1619
+ const { strings, t, locale: resolvedLocale } = chunkJGUDXRXN_js.useAppilotsI18n();
1252
1620
  const {
1253
1621
  messages,
1622
+ mission,
1623
+ pauseMission,
1624
+ resumeMission,
1625
+ cancelMission,
1626
+ replyLocale,
1254
1627
  isLoading,
1255
1628
  loadingStatusKey,
1629
+ hasStartedActing,
1256
1630
  sendMessage,
1257
1631
  cancelMessage,
1258
1632
  clearMessages,
1259
1633
  escalation,
1260
1634
  requestHuman
1261
- } = chunkUFMTRGML_js.useAppilotsChat({
1635
+ } = chunkJGUDXRXN_js.useAppilotsChat({
1262
1636
  errorPrefix: t("somethingWentWrong"),
1263
1637
  escalationStrings: {
1264
1638
  requested: t("escalationRequested"),
@@ -1267,8 +1641,11 @@ function AppilotsChatInner({
1267
1641
  offer: t("escalationOffer")
1268
1642
  }
1269
1643
  });
1270
- const { pendingActions, executingActions, completedActions, approveAction, rejectAction } = chunkUFMTRGML_js.useAppilotsActions({ autoExecute });
1271
- const { emit, remotePersonalization } = chunkSUMIABJK_js.useAppilotsContext();
1644
+ React8.useEffect(() => {
1645
+ onReplyLocaleChange(replyLocale);
1646
+ }, [replyLocale, onReplyLocaleChange]);
1647
+ const { pendingActions, executingActions, completedActions, approveAction, rejectAction } = chunkJGUDXRXN_js.useAppilotsActions({ autoExecute });
1648
+ const { emit, remotePersonalization } = chunkQAZ4TN3Z_js.useAppilotsContext();
1272
1649
  const {
1273
1650
  headerTitle: resolvedTitle,
1274
1651
  assistantAvatar,
@@ -1292,37 +1669,130 @@ function AppilotsChatInner({
1292
1669
  );
1293
1670
  const allActions = [...pendingActions, ...executingActions, ...completedActions];
1294
1671
  const timeline = buildChatTimeline(messages, allActions);
1295
- const lastAssistantMessageId = React7__namespace.default.useMemo(() => {
1672
+ const lastAssistantMessageId = React8__namespace.default.useMemo(() => {
1296
1673
  for (let i = messages.length - 1; i >= 0; i--) {
1297
1674
  if (messages[i].role === "assistant") return messages[i].id;
1298
1675
  }
1299
1676
  return void 0;
1300
1677
  }, [messages]);
1301
1678
  const insets = useSafeAreaInsetsOrDefault();
1302
- const [internalVisible, setInternalVisible] = React7.useState(mode === "inline");
1303
- const [inputText, setInputText] = React7.useState("");
1304
- const flatListRef = React7.useRef(null);
1305
- const slideAnim = React7.useRef(new reactNative.Animated.Value(SCREEN_HEIGHT)).current;
1306
- const isVisible = mode === "inline" ? true : controlledVisible !== void 0 ? controlledVisible : internalVisible;
1307
- const showSuggestedPrompts = chunkUFMTRGML_js.shouldShowSuggestedPrompts({
1679
+ const { fontScale } = reactNative.useWindowDimensions();
1680
+ const [internalVisible, setInternalVisible] = React8.useState(mode === "inline");
1681
+ const [inputText, setInputText] = React8.useState("");
1682
+ const flatListRef = React8.useRef(null);
1683
+ const slideAnim = React8.useRef(new reactNative.Animated.Value(SCREEN_HEIGHT)).current;
1684
+ const wantsSheet = mode === "inline" ? true : controlledVisible !== void 0 ? controlledVisible : internalVisible;
1685
+ const speechHost = chunkQAZ4TN3Z_js.isSpeechHost(speechProp) ? speechProp : null;
1686
+ const hasGeometry = React8.useSyncExternalStore(
1687
+ chunkQAZ4TN3Z_js.subscribeGeometryHost,
1688
+ () => chunkQAZ4TN3Z_js.geometryAvailability() !== "unavailable",
1689
+ () => false
1690
+ );
1691
+ const capabilities = React8.useMemo(
1692
+ () => ({ geometry: hasGeometry, speech: speechHost !== null }),
1693
+ [hasGeometry, speechHost]
1694
+ );
1695
+ const { experience, downgrades } = React8.useMemo(
1696
+ () => resolveExperience(experienceProp, capabilities),
1697
+ [experienceProp, capabilities]
1698
+ );
1699
+ const presence = mode === "inline" ? "sheet" : experience.presence;
1700
+ React8.useEffect(() => {
1701
+ if (!__DEV__ || downgrades.length === 0) return;
1702
+ if (!chunkQAZ4TN3Z_js.isGeometryResolved()) return;
1703
+ for (const line of formatDowngrades(downgrades)) {
1704
+ console.warn(line);
1705
+ }
1706
+ }, [downgrades, hasGeometry]);
1707
+ const [unreadResult, setUnreadResult] = React8.useState(false);
1708
+ const [explicitlyOpened, setExplicitlyOpened] = React8.useState(false);
1709
+ const requireApproval = React8.useCallback(
1710
+ (action) => {
1711
+ if (action.status !== "pending") return false;
1712
+ if (action.type === "confirm") return true;
1713
+ return !autoExecute;
1714
+ },
1715
+ [autoExecute]
1716
+ );
1717
+ const awaitingApproval = pendingActions.some((action) => requireApproval(action));
1718
+ const awaitingUser = awaitingApproval || escalation?.status === "pending" || escalation?.status === "active";
1719
+ const busy = isLoading || executingActions.length > 0;
1720
+ const stillWorkingSeconds = useStillWorking(busy && !awaitingUser, strings.stillWorking);
1721
+ const acting = busy && hasStartedActing;
1722
+ useChatAnnouncements({
1723
+ messages,
1724
+ actions: allActions,
1725
+ awaitingApproval,
1726
+ acting,
1727
+ locale: resolvedLocale,
1728
+ strings
1729
+ });
1730
+ const hostModalOpen = useHostModalOpen(
1731
+ usesPill(presence) && (busy || wantsSheet || unreadResult)
1732
+ );
1733
+ const surface = resolveSurface(presence, {
1734
+ busy,
1735
+ acting,
1736
+ awaitingUser,
1737
+ open: wantsSheet,
1738
+ unread: unreadResult,
1739
+ hostModalOpen,
1740
+ explicitlyOpened
1741
+ });
1742
+ const isVisible = mode === "inline" ? true : surface === "sheet";
1743
+ const spotlight = useSpotlight(experience.spotlight !== "off");
1744
+ React8.useEffect(() => {
1745
+ chunkJGUDXRXN_js.setSpotlightMode(experience.spotlight);
1746
+ return () => chunkJGUDXRXN_js.setSpotlightMode("off");
1747
+ }, [experience.spotlight]);
1748
+ const { label: pillLabel, state: pillState } = surface === "pill" ? resolvePillStatus(allActions, busy, {
1749
+ working: strings.pillWorking,
1750
+ done: strings.pillDone,
1751
+ locale: resolvedLocale
1752
+ }) : { label: "", state: "pending" };
1753
+ const showSuggestedPrompts = chunkJGUDXRXN_js.shouldShowSuggestedPrompts({
1308
1754
  isVisible,
1309
1755
  messageCount: messages.length,
1310
1756
  inputText
1311
1757
  });
1312
- const { prompts: suggestedPrompts } = chunkUFMTRGML_js.useSuggestedPrompts({
1758
+ const { prompts: suggestedPrompts } = chunkJGUDXRXN_js.useSuggestedPrompts({
1313
1759
  enabled: showSuggestedPrompts,
1314
1760
  limit: 3
1315
1761
  });
1316
- const openChat = React7.useCallback(() => {
1762
+ const openChat = React8.useCallback(() => {
1763
+ setExplicitlyOpened(true);
1317
1764
  setInternalVisible(true);
1318
1765
  emit({ type: "chat:open", timestamp: Date.now(), data: {} });
1319
1766
  }, [emit]);
1320
- const closeChat = React7.useCallback(() => {
1767
+ const closeChat = React8.useCallback(() => {
1768
+ setExplicitlyOpened(false);
1321
1769
  setInternalVisible(false);
1322
1770
  onClose?.();
1323
1771
  emit({ type: "chat:close", timestamp: Date.now(), data: {} });
1324
1772
  }, [onClose, emit]);
1325
- React7.useEffect(() => {
1773
+ React8.useEffect(() => {
1774
+ if (acting) setExplicitlyOpened(false);
1775
+ if (presence === "hidden" && acting) setInternalVisible(false);
1776
+ }, [presence, acting]);
1777
+ const wasActingRef = React8.useRef(false);
1778
+ React8.useEffect(() => {
1779
+ if (!usesPill(presence)) {
1780
+ wasActingRef.current = acting;
1781
+ return;
1782
+ }
1783
+ if (acting) {
1784
+ wasActingRef.current = true;
1785
+ return;
1786
+ }
1787
+ if (!wasActingRef.current) return;
1788
+ wasActingRef.current = false;
1789
+ if (shouldReopenOnTurnEnd(presence)) setInternalVisible(true);
1790
+ else setUnreadResult(true);
1791
+ }, [acting, presence]);
1792
+ React8.useEffect(() => {
1793
+ if (surface === "sheet") setUnreadResult(false);
1794
+ }, [surface]);
1795
+ React8.useEffect(() => {
1326
1796
  if (mode === "inline") return;
1327
1797
  reactNative.Animated.spring(slideAnim, {
1328
1798
  toValue: isVisible ? 0 : SCREEN_HEIGHT,
@@ -1331,25 +1801,44 @@ function AppilotsChatInner({
1331
1801
  friction: 11
1332
1802
  }).start();
1333
1803
  }, [isVisible, slideAnim, mode]);
1334
- React7.useEffect(() => {
1804
+ const titleRef = React8.useRef(null);
1805
+ const launcherRef = React8.useRef(null);
1806
+ const pillRef = React8.useRef(null);
1807
+ const wasVisibleRef = React8.useRef(isVisible);
1808
+ React8.useEffect(() => {
1809
+ if (mode === "inline" || wasVisibleRef.current === isVisible) return;
1810
+ wasVisibleRef.current = isVisible;
1811
+ const timer = setTimeout(() => {
1812
+ const target = isVisible ? titleRef.current : pillRef.current ?? launcherRef.current;
1813
+ if (target) reactNative.AccessibilityInfo.sendAccessibilityEvent(target, "focus");
1814
+ }, A11Y_FOCUS_DELAY_MS);
1815
+ return () => clearTimeout(timer);
1816
+ }, [isVisible, mode]);
1817
+ React8.useEffect(() => {
1335
1818
  if (messages.length > 0) {
1336
1819
  setTimeout(() => flatListRef.current?.scrollToEnd({ animated: true }), 100);
1337
1820
  }
1338
1821
  }, [messages.length]);
1339
- const handleSend = React7.useCallback(() => {
1822
+ const voiceEnabled = experience.input.includes("voice");
1823
+ const voice = useVoiceInput({
1824
+ host: voiceEnabled ? speechHost : null,
1825
+ locale: resolvedLocale,
1826
+ onTranscript: sendMessage
1827
+ });
1828
+ const handleSend = React8.useCallback(() => {
1340
1829
  if (!inputText.trim()) return;
1341
1830
  sendMessage(inputText.trim());
1342
1831
  setInputText("");
1343
1832
  }, [inputText, sendMessage]);
1344
- const renderMessage = React7.useCallback(
1833
+ const renderMessage = React8.useCallback(
1345
1834
  ({ item }) => {
1346
1835
  if (item.role === "system") {
1347
1836
  const isOffer = item.metadata?.escalationOffer === true;
1348
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.systemMessageContainer }, /* @__PURE__ */ React7__namespace.default.createElement(
1837
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.systemMessageContainer }, /* @__PURE__ */ React8__namespace.default.createElement(
1349
1838
  reactNative.Text,
1350
1839
  {
1351
1840
  style: [
1352
- styles3.systemMessageText,
1841
+ styles5.systemMessageText,
1353
1842
  {
1354
1843
  color: theme.colors.textSecondary,
1355
1844
  fontFamily: theme.typography.fontFamily,
@@ -1358,13 +1847,13 @@ function AppilotsChatInner({
1358
1847
  ]
1359
1848
  },
1360
1849
  item.content
1361
- ), isOffer && !escalation && /* @__PURE__ */ React7__namespace.default.createElement(
1850
+ ), isOffer && !escalation && /* @__PURE__ */ React8__namespace.default.createElement(
1362
1851
  reactNative.TouchableOpacity,
1363
1852
  {
1364
1853
  ...APPILOTS_SKIP_PROPS,
1365
1854
  style: [
1366
- styles3.chip,
1367
- styles3.escalationOfferChip,
1855
+ styles5.chip,
1856
+ styles5.escalationOfferChip,
1368
1857
  {
1369
1858
  backgroundColor: theme.colors.surface,
1370
1859
  borderColor: theme.colors.border,
@@ -1377,12 +1866,12 @@ function AppilotsChatInner({
1377
1866
  accessibilityLabel: strings.talkToHumanA11y,
1378
1867
  testID: "escalation-offer-chip"
1379
1868
  },
1380
- /* @__PURE__ */ React7__namespace.default.createElement(HeadsetIcon, { size: 14, color: theme.colors.textSecondary }),
1381
- /* @__PURE__ */ React7__namespace.default.createElement(
1869
+ /* @__PURE__ */ React8__namespace.default.createElement(HeadsetIcon, { size: 14, color: theme.colors.textSecondary }),
1870
+ /* @__PURE__ */ React8__namespace.default.createElement(
1382
1871
  reactNative.Text,
1383
1872
  {
1384
1873
  style: [
1385
- styles3.chipText,
1874
+ styles5.chipText,
1386
1875
  {
1387
1876
  color: theme.colors.text,
1388
1877
  fontFamily: theme.typography.fontFamily,
@@ -1396,13 +1885,13 @@ function AppilotsChatInner({
1396
1885
  }
1397
1886
  const isUser = item.role === "user";
1398
1887
  const isHumanAgent = item.role === "human_agent";
1399
- const useWideAssistantLayout = !isUser && needsWideChatLayout(item.content);
1888
+ const useWideAssistantLayout = !isUser && chunkQAZ4TN3Z_js.needsWideChatLayout(item.content);
1400
1889
  if (isHumanAgent) {
1401
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.humanAgentContainer, testID: "human-agent-message" }, /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.humanAgentLabelRow }, /* @__PURE__ */ React7__namespace.default.createElement(HeadsetIcon, { size: 11, color: theme.colors.secondary }), /* @__PURE__ */ React7__namespace.default.createElement(
1890
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.humanAgentContainer, testID: "human-agent-message" }, /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.humanAgentLabelRow }, /* @__PURE__ */ React8__namespace.default.createElement(HeadsetIcon, { size: 11, color: theme.colors.secondary }), /* @__PURE__ */ React8__namespace.default.createElement(
1402
1891
  reactNative.Text,
1403
1892
  {
1404
1893
  style: [
1405
- styles3.humanAgentLabel,
1894
+ styles5.humanAgentLabel,
1406
1895
  {
1407
1896
  color: theme.colors.textSecondary,
1408
1897
  fontFamily: theme.typography.fontFamily
@@ -1410,17 +1899,17 @@ function AppilotsChatInner({
1410
1899
  ]
1411
1900
  },
1412
1901
  escalation?.operatorName ?? strings.humanAgentLabel
1413
- )), /* @__PURE__ */ React7__namespace.default.createElement(
1902
+ )), /* @__PURE__ */ React8__namespace.default.createElement(
1414
1903
  reactNative.View,
1415
1904
  {
1416
1905
  accessibilityLabel: item.content,
1417
1906
  style: [
1418
- styles3.messageBubble,
1419
- styles3.assistantBubble,
1907
+ styles5.messageBubble,
1908
+ styles5.assistantBubble,
1420
1909
  { backgroundColor: theme.colors.surface }
1421
1910
  ]
1422
1911
  },
1423
- /* @__PURE__ */ React7__namespace.default.createElement(
1912
+ /* @__PURE__ */ React8__namespace.default.createElement(
1424
1913
  ChatMarkdown,
1425
1914
  {
1426
1915
  content: item.content,
@@ -1435,21 +1924,21 @@ function AppilotsChatInner({
1435
1924
  )
1436
1925
  ));
1437
1926
  }
1438
- return /* @__PURE__ */ React7__namespace.default.createElement(
1927
+ return /* @__PURE__ */ React8__namespace.default.createElement(
1439
1928
  reactNative.View,
1440
1929
  {
1441
1930
  testID: isUser ? void 0 : item.id === lastAssistantMessageId ? "assistant-last-message" : "assistant-message",
1442
1931
  accessibilityLabel: isUser ? void 0 : item.content,
1443
1932
  style: [
1444
- styles3.messageBubble,
1445
- isUser ? [styles3.userBubble, { backgroundColor: theme.colors.primary }] : [
1446
- styles3.assistantBubble,
1447
- useWideAssistantLayout && styles3.assistantBubbleWide,
1933
+ styles5.messageBubble,
1934
+ isUser ? [styles5.userBubble, { backgroundColor: theme.colors.primary }] : [
1935
+ styles5.assistantBubble,
1936
+ useWideAssistantLayout && styles5.assistantBubbleWide,
1448
1937
  { backgroundColor: theme.colors.surface }
1449
1938
  ]
1450
1939
  ]
1451
1940
  },
1452
- /* @__PURE__ */ React7__namespace.default.createElement(
1941
+ /* @__PURE__ */ React8__namespace.default.createElement(
1453
1942
  ChatMarkdown,
1454
1943
  {
1455
1944
  content: item.content,
@@ -1467,19 +1956,16 @@ function AppilotsChatInner({
1467
1956
  },
1468
1957
  [theme, lastAssistantMessageId, escalation, requestHuman, strings]
1469
1958
  );
1470
- const requireApproval = React7.useCallback(
1471
- (action) => {
1472
- if (action.status !== "pending") return false;
1473
- if (action.type === "confirm") return true;
1474
- return !autoExecute;
1475
- },
1476
- [autoExecute]
1477
- );
1478
- const renderBreadcrumb = React7.useCallback(
1479
- (actions) => /* @__PURE__ */ React7__namespace.default.createElement(
1959
+ const composerRef = React8.useRef(null);
1960
+ const returnFocusToComposer = React8.useCallback(() => {
1961
+ if (composerRef.current) reactNative.AccessibilityInfo.sendAccessibilityEvent(composerRef.current, "focus");
1962
+ }, []);
1963
+ const renderBreadcrumb = React8.useCallback(
1964
+ (actions) => /* @__PURE__ */ React8__namespace.default.createElement(
1480
1965
  ActionBreadcrumb,
1481
1966
  {
1482
1967
  actions,
1968
+ locale: resolvedLocale,
1483
1969
  primaryColor: theme.colors.primary,
1484
1970
  textColor: theme.colors.text,
1485
1971
  fontFamily: theme.typography.fontFamily,
@@ -1490,7 +1976,8 @@ function AppilotsChatInner({
1490
1976
  confirmDestructiveApprove: strings.confirmDestructiveApprove,
1491
1977
  confirmApprove: strings.confirmApprove,
1492
1978
  confirmCancel: strings.confirmCancel,
1493
- confirmThisAction: strings.confirmThisAction
1979
+ confirmThisAction: strings.confirmThisAction,
1980
+ confirmExpired: strings.confirmExpired
1494
1981
  },
1495
1982
  palette: {
1496
1983
  textSecondary: theme.colors.textSecondary,
@@ -1502,7 +1989,8 @@ function AppilotsChatInner({
1502
1989
  },
1503
1990
  requireApprovalFor: requireApproval,
1504
1991
  onApprove: approveAction,
1505
- onReject: rejectAction
1992
+ onReject: rejectAction,
1993
+ onConfirmCardGone: returnFocusToComposer
1506
1994
  }
1507
1995
  ),
1508
1996
  [
@@ -1515,9 +2003,12 @@ function AppilotsChatInner({
1515
2003
  theme.colors.warning,
1516
2004
  theme.colors.error,
1517
2005
  theme.typography.fontFamily,
2006
+ strings,
2007
+ resolvedLocale,
1518
2008
  requireApproval,
1519
2009
  approveAction,
1520
- rejectAction
2010
+ rejectAction,
2011
+ returnFocusToComposer
1521
2012
  ]
1522
2013
  );
1523
2014
  const resolvedHeaderTitle = resolvedTitle ?? t("chatTitle");
@@ -1527,17 +2018,17 @@ function AppilotsChatInner({
1527
2018
  const showEmptySubtitle = resolvedEmptySubtitle.length > 0 && !(showSuggestedPrompts && suggestedPrompts.length > 0);
1528
2019
  const renderAvatar = () => {
1529
2020
  if (!assistantAvatar) {
1530
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: [styles3.headerDot, { backgroundColor: theme.colors.primary }] });
2021
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: [styles5.headerDot, { backgroundColor: theme.colors.primary }] });
1531
2022
  }
1532
2023
  if (typeof assistantAvatar === "string") {
1533
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Image, { source: { uri: assistantAvatar }, style: styles3.headerAvatar });
2024
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Image, { source: { uri: assistantAvatar }, style: styles5.headerAvatar });
1534
2025
  }
1535
2026
  if (typeof assistantAvatar === "number") {
1536
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Image, { source: assistantAvatar, style: styles3.headerAvatar });
2027
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Image, { source: assistantAvatar, style: styles5.headerAvatar });
1537
2028
  }
1538
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.headerAvatarSlot }, assistantAvatar);
2029
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.headerAvatarSlot }, assistantAvatar);
1539
2030
  };
1540
- const showTrigger = mode === "bubble" && !isVisible && controlledVisible === void 0 && triggerButton !== "none";
2031
+ const showTrigger = mode === "bubble" && surface === "none" && experience.entry.includes("fab") && controlledVisible === void 0 && triggerButton !== "none";
1541
2032
  const fabPositionStyle = (() => {
1542
2033
  switch (position) {
1543
2034
  case "bottom-left":
@@ -1551,15 +2042,16 @@ function AppilotsChatInner({
1551
2042
  return { bottom: 24, right: 24 };
1552
2043
  }
1553
2044
  })();
1554
- const chatSurface = /* @__PURE__ */ React7__namespace.default.createElement(
2045
+ const chatSurface = /* @__PURE__ */ React8__namespace.default.createElement(
1555
2046
  reactNative.View,
1556
2047
  {
1557
2048
  ...APPILOTS_SKIP_PROPS,
1558
2049
  style: [
1559
- styles3.chatContainer,
1560
- mode === "fullscreen" && styles3.chatContainerFullscreen,
1561
- mode === "sidebar" && styles3.chatContainerSidebar,
1562
- mode === "inline" && styles3.chatContainerInline,
2050
+ styles5.chatContainer,
2051
+ mode === "fullscreen" && styles5.chatContainerFullscreen,
2052
+ mode === "sidebar" && styles5.chatContainerSidebar,
2053
+ mode === "inline" && styles5.chatContainerInline,
2054
+ mode === "bubble" && fontScale >= LARGE_TEXT_FONT_SCALE && styles5.chatContainerFullscreen,
1563
2055
  {
1564
2056
  backgroundColor: theme.colors.background,
1565
2057
  borderTopLeftRadius: theme.radii.lg,
@@ -1567,11 +2059,13 @@ function AppilotsChatInner({
1567
2059
  }
1568
2060
  ]
1569
2061
  },
1570
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: [styles3.header, { borderBottomColor: theme.colors.border }] }, /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.headerLeft }, renderAvatar(), /* @__PURE__ */ React7__namespace.default.createElement(
2062
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: [styles5.header, { borderBottomColor: theme.colors.border }] }, /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.headerLeft }, renderAvatar(), /* @__PURE__ */ React8__namespace.default.createElement(
1571
2063
  reactNative.Text,
1572
2064
  {
2065
+ ref: titleRef,
2066
+ accessibilityRole: "header",
1573
2067
  style: [
1574
- styles3.headerTitle,
2068
+ styles5.headerTitle,
1575
2069
  {
1576
2070
  color: theme.colors.text,
1577
2071
  fontFamily: theme.typography.fontFamily,
@@ -1580,50 +2074,50 @@ function AppilotsChatInner({
1580
2074
  ]
1581
2075
  },
1582
2076
  resolvedHeaderTitle
1583
- )), /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.headerActions }, /* @__PURE__ */ React7__namespace.default.createElement(
2077
+ )), /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.headerActions }, /* @__PURE__ */ React8__namespace.default.createElement(
1584
2078
  reactNative.TouchableOpacity,
1585
2079
  {
1586
2080
  ...APPILOTS_SKIP_PROPS,
1587
2081
  onPress: () => requestHuman("user_requested"),
1588
- style: styles3.headerButton,
2082
+ style: styles5.headerButton,
1589
2083
  accessibilityRole: "button",
1590
2084
  accessibilityLabel: strings.talkToHumanA11y,
1591
2085
  testID: "escalation-header-button"
1592
2086
  },
1593
- /* @__PURE__ */ React7__namespace.default.createElement(
2087
+ /* @__PURE__ */ React8__namespace.default.createElement(
1594
2088
  HeadsetIcon,
1595
2089
  {
1596
2090
  size: 16,
1597
2091
  color: escalation ? theme.colors.primary : theme.colors.textSecondary
1598
2092
  }
1599
2093
  )
1600
- ), /* @__PURE__ */ React7__namespace.default.createElement(
2094
+ ), /* @__PURE__ */ React8__namespace.default.createElement(
1601
2095
  reactNative.TouchableOpacity,
1602
2096
  {
1603
2097
  ...APPILOTS_SKIP_PROPS,
1604
2098
  onPress: clearMessages,
1605
- style: styles3.headerButton,
2099
+ style: styles5.headerButton,
1606
2100
  accessibilityRole: "button",
1607
2101
  testID: "assistant-clear"
1608
2102
  },
1609
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [styles3.headerButtonText, { color: theme.colors.textSecondary }] }, strings.clearButton)
1610
- ), mode !== "inline" && /* @__PURE__ */ React7__namespace.default.createElement(
2103
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [styles5.headerButtonText, { color: theme.colors.textSecondary }] }, strings.clearButton)
2104
+ ), mode !== "inline" && /* @__PURE__ */ React8__namespace.default.createElement(
1611
2105
  reactNative.TouchableOpacity,
1612
2106
  {
1613
2107
  ...APPILOTS_SKIP_PROPS,
1614
2108
  onPress: closeChat,
1615
- style: styles3.closeButton,
2109
+ style: styles5.closeButton,
1616
2110
  accessibilityRole: "button",
1617
2111
  accessibilityLabel: strings.closeChatA11y,
1618
2112
  testID: "assistant-close"
1619
2113
  },
1620
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: [styles3.closeButtonText, { color: theme.colors.text }] }, "\u2715")
2114
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: [styles5.closeButtonText, { color: theme.colors.text }] }, "\u2715")
1621
2115
  ))),
1622
- escalation && /* @__PURE__ */ React7__namespace.default.createElement(
2116
+ escalation && /* @__PURE__ */ React8__namespace.default.createElement(
1623
2117
  reactNative.View,
1624
2118
  {
1625
2119
  style: [
1626
- styles3.escalationBanner,
2120
+ styles5.escalationBanner,
1627
2121
  {
1628
2122
  borderBottomColor: theme.colors.border,
1629
2123
  backgroundColor: theme.colors.primary + "0d"
@@ -1631,12 +2125,12 @@ function AppilotsChatInner({
1631
2125
  ],
1632
2126
  testID: "escalation-banner"
1633
2127
  },
1634
- /* @__PURE__ */ React7__namespace.default.createElement(HeadsetIcon, { size: 12, color: theme.colors.primary }),
1635
- /* @__PURE__ */ React7__namespace.default.createElement(
2128
+ /* @__PURE__ */ React8__namespace.default.createElement(HeadsetIcon, { size: 12, color: theme.colors.primary }),
2129
+ /* @__PURE__ */ React8__namespace.default.createElement(
1636
2130
  reactNative.Text,
1637
2131
  {
1638
2132
  style: [
1639
- styles3.escalationBannerText,
2133
+ styles5.escalationBannerText,
1640
2134
  {
1641
2135
  color: theme.colors.textSecondary,
1642
2136
  fontFamily: theme.typography.fontFamily,
@@ -1647,10 +2141,11 @@ function AppilotsChatInner({
1647
2141
  escalation.status === "pending" ? strings.escalationPendingBanner : strings.escalationActiveBanner
1648
2142
  )
1649
2143
  ),
1650
- /* @__PURE__ */ React7__namespace.default.createElement(
2144
+ /* @__PURE__ */ React8__namespace.default.createElement(
1651
2145
  reactNative.FlatList,
1652
2146
  {
1653
2147
  ...APPILOTS_SKIP_PROPS,
2148
+ testID: "assistant-transcript",
1654
2149
  ref: flatListRef,
1655
2150
  data: timeline,
1656
2151
  keyExtractor: (item) => item.type === "message" ? item.data.id : item.key,
@@ -1663,48 +2158,47 @@ function AppilotsChatInner({
1663
2158
  }
1664
2159
  return null;
1665
2160
  },
1666
- contentContainerStyle: styles3.messageList,
1667
- ListEmptyComponent: /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.emptyState }, emptyStateIcon && isImageSource(emptyStateIcon) ? /* @__PURE__ */ React7__namespace.default.createElement(
2161
+ contentContainerStyle: styles5.messageList,
2162
+ ListEmptyComponent: /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.emptyState }, emptyStateIcon && isImageSource(emptyStateIcon) ? /* @__PURE__ */ React8__namespace.default.createElement(
1668
2163
  reactNative.Image,
1669
2164
  {
1670
2165
  source: typeof emptyStateIcon === "string" ? { uri: emptyStateIcon } : emptyStateIcon,
1671
- style: styles3.emptyIconImage,
2166
+ style: styles5.emptyIconImage,
1672
2167
  resizeMode: "contain"
1673
2168
  }
1674
- ) : /* @__PURE__ */ React7__namespace.default.createElement(
2169
+ ) : /* @__PURE__ */ React8__namespace.default.createElement(
1675
2170
  reactNative.View,
1676
2171
  {
1677
- style: [styles3.emptyIconBadge, { backgroundColor: theme.colors.primary + "14" }]
2172
+ style: [styles5.emptyIconBadge, { backgroundColor: theme.colors.primary + "14" }]
1678
2173
  },
1679
- emptyStateIcon ? /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: styles3.emptyIconEmoji }, emptyStateIcon) : /* @__PURE__ */ React7__namespace.default.createElement(ChatIcon, { size: 30, color: theme.colors.primary })
1680
- ), /* @__PURE__ */ React7__namespace.default.createElement(
2174
+ emptyStateIcon ? /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: styles5.emptyIconEmoji }, emptyStateIcon) : /* @__PURE__ */ React8__namespace.default.createElement(ChatIcon, { size: 30, color: theme.colors.primary })
2175
+ ), /* @__PURE__ */ React8__namespace.default.createElement(
1681
2176
  reactNative.Text,
1682
2177
  {
1683
2178
  style: [
1684
- styles3.emptyTitle,
2179
+ styles5.emptyTitle,
1685
2180
  { color: theme.colors.text, fontFamily: theme.typography.fontFamily }
1686
2181
  ]
1687
2182
  },
1688
2183
  resolvedEmptyTitle
1689
- ), showEmptySubtitle && /* @__PURE__ */ React7__namespace.default.createElement(
2184
+ ), showEmptySubtitle && /* @__PURE__ */ React8__namespace.default.createElement(
1690
2185
  reactNative.Text,
1691
2186
  {
1692
2187
  style: [
1693
- styles3.emptySubtitle,
2188
+ styles5.emptySubtitle,
1694
2189
  {
1695
2190
  color: theme.colors.textSecondary,
1696
2191
  fontFamily: theme.typography.fontFamily
1697
2192
  }
1698
- ],
1699
- numberOfLines: 2
2193
+ ]
1700
2194
  },
1701
2195
  resolvedEmptySubtitle
1702
- ), showSuggestedPrompts && suggestedPrompts.length > 0 && /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.chipsContainer, testID: "assistant-suggested-prompts" }, suggestedPrompts.map((prompt) => /* @__PURE__ */ React7__namespace.default.createElement(
2196
+ ), showSuggestedPrompts && suggestedPrompts.length > 0 && /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.chipsContainer, testID: "assistant-suggested-prompts" }, suggestedPrompts.map((prompt) => /* @__PURE__ */ React8__namespace.default.createElement(
1703
2197
  reactNative.TouchableOpacity,
1704
2198
  {
1705
2199
  key: `${prompt.source}:${prompt.text}`,
1706
2200
  style: [
1707
- styles3.chip,
2201
+ styles5.chip,
1708
2202
  {
1709
2203
  backgroundColor: theme.colors.surface,
1710
2204
  borderColor: theme.colors.border,
@@ -1715,67 +2209,101 @@ function AppilotsChatInner({
1715
2209
  activeOpacity: 0.7,
1716
2210
  accessibilityLabel: `Suggested prompt: ${prompt.text}`
1717
2211
  },
1718
- /* @__PURE__ */ React7__namespace.default.createElement(
2212
+ /* @__PURE__ */ React8__namespace.default.createElement(
1719
2213
  reactNative.Text,
1720
2214
  {
1721
2215
  style: [
1722
- styles3.chipText,
2216
+ styles5.chipText,
1723
2217
  {
1724
2218
  color: theme.colors.buttonText,
1725
2219
  fontFamily: theme.typography.fontFamily,
1726
2220
  fontSize: theme.typography.fontSizeSm
1727
2221
  }
1728
- ],
1729
- numberOfLines: 1
2222
+ ]
1730
2223
  },
1731
2224
  prompt.text
1732
2225
  )
1733
2226
  )))),
1734
- ListFooterComponent: isLoading ? /* @__PURE__ */ React7__namespace.default.createElement(
2227
+ ListFooterComponent: isLoading ? /* @__PURE__ */ React8__namespace.default.createElement(
1735
2228
  reactNative.View,
1736
2229
  {
1737
2230
  style: [
1738
- styles3.messageBubble,
1739
- styles3.assistantBubble,
2231
+ styles5.messageBubble,
2232
+ styles5.assistantBubble,
1740
2233
  { backgroundColor: theme.colors.surface }
1741
2234
  ]
1742
2235
  },
1743
- /* @__PURE__ */ React7__namespace.default.createElement(
2236
+ /* @__PURE__ */ React8__namespace.default.createElement(
1744
2237
  reactNative.Text,
1745
2238
  {
1746
2239
  style: [
1747
- styles3.messageText,
2240
+ styles5.messageText,
1748
2241
  { color: theme.colors.textSecondary, fontFamily: theme.typography.fontFamily }
1749
2242
  ]
1750
2243
  },
1751
- strings[loadingStatusKey] ?? strings.thinking
2244
+ stillWorkingSeconds ? strings.stillWorking.replace("{seconds}", String(stillWorkingSeconds)) : strings[loadingStatusKey] ?? strings.thinking
1752
2245
  )
1753
2246
  ) : null
1754
2247
  }
1755
2248
  ),
1756
- /* @__PURE__ */ React7__namespace.default.createElement(
2249
+ mission && !["completed", "cancelled"].includes(mission.status) && /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: { padding: 12, gap: 8 }, testID: "appilots-mission-controls" }, /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: { color: theme.colors.text }, testID: "appilots-mission-progress" }, mission.progressText, mission.status === "paused" ? ` \xB7 ${strings.missionPaused}` : ""), /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.missionButtons }, mission.status === "running" ? /* @__PURE__ */ React8__namespace.default.createElement(
2250
+ reactNative.TouchableOpacity,
2251
+ {
2252
+ onPress: () => void pauseMission(),
2253
+ testID: "appilots-mission-pause",
2254
+ style: styles5.missionButton,
2255
+ accessibilityRole: "button"
2256
+ },
2257
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: { color: theme.colors.text } }, strings.missionPause)
2258
+ ) : mission.status !== "awaiting_approval" ? /* @__PURE__ */ React8__namespace.default.createElement(
2259
+ reactNative.TouchableOpacity,
2260
+ {
2261
+ onPress: () => void resumeMission(),
2262
+ disabled: isLoading,
2263
+ testID: "appilots-mission-resume",
2264
+ style: styles5.missionButton,
2265
+ accessibilityRole: "button"
2266
+ },
2267
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: { color: theme.colors.text } }, strings.missionResume)
2268
+ ) : null, /* @__PURE__ */ React8__namespace.default.createElement(
2269
+ reactNative.TouchableOpacity,
2270
+ {
2271
+ onPress: () => void cancelMission(),
2272
+ testID: "appilots-mission-cancel",
2273
+ style: styles5.missionButton,
2274
+ accessibilityRole: "button"
2275
+ },
2276
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: { color: theme.colors.text } }, strings.missionCancel)
2277
+ ))),
2278
+ /* @__PURE__ */ React8__namespace.default.createElement(
1757
2279
  reactNative.View,
1758
2280
  {
1759
2281
  style: [
1760
- styles3.inputContainer,
2282
+ styles5.inputContainer,
1761
2283
  {
1762
2284
  borderTopColor: theme.colors.border,
1763
2285
  paddingBottom: Math.max(insets.bottom, 10)
1764
2286
  }
1765
2287
  ]
1766
2288
  },
1767
- /* @__PURE__ */ React7__namespace.default.createElement(
2289
+ /* @__PURE__ */ React8__namespace.default.createElement(
1768
2290
  reactNative.TextInput,
1769
2291
  {
2292
+ ref: composerRef,
1770
2293
  style: [
1771
- styles3.input,
2294
+ styles5.input,
1772
2295
  {
1773
2296
  backgroundColor: theme.colors.surface,
1774
2297
  color: theme.colors.text,
1775
2298
  borderRadius: theme.radii.md,
1776
2299
  fontFamily: theme.typography.fontFamily,
1777
2300
  fontSize: theme.typography.fontSizeBase,
1778
- lineHeight: theme.typography.fontSizeBase * 1.35
2301
+ lineHeight: theme.typography.fontSizeBase * 1.35,
2302
+ // The 120pt cap is ~5 lines at default size and barely one at
2303
+ // iOS AX5, where even the placeholder was cut. It grows with
2304
+ // the text, but never past a quarter of the screen, so the
2305
+ // keyboard still leaves room for the transcript.
2306
+ maxHeight: Math.min(INPUT_MAX_HEIGHT * fontScale, SCREEN_HEIGHT * 0.25)
1779
2307
  }
1780
2308
  ],
1781
2309
  placeholder: resolvedPlaceholder,
@@ -1785,16 +2313,35 @@ function AppilotsChatInner({
1785
2313
  multiline: true,
1786
2314
  blurOnSubmit: false,
1787
2315
  scrollEnabled: true,
1788
- editable: !isLoading,
2316
+ editable: !isLoading && (!mission || ["completed", "cancelled"].includes(mission.status)),
1789
2317
  testID: "assistant-input",
1790
2318
  __appilotsInternal: true
1791
2319
  }
1792
2320
  ),
1793
- isLoading ? /* @__PURE__ */ React7__namespace.default.createElement(
2321
+ voiceEnabled && !isLoading ? /* @__PURE__ */ React8__namespace.default.createElement(
2322
+ reactNative.TouchableOpacity,
2323
+ {
2324
+ style: [
2325
+ styles5.sendButton,
2326
+ {
2327
+ backgroundColor: voice.state === "listening" || voice.state === "starting" ? theme.colors.error : theme.colors.primary + "40",
2328
+ borderRadius: theme.radii.md
2329
+ }
2330
+ ],
2331
+ onPressIn: voice.start,
2332
+ onPressOut: voice.stop,
2333
+ accessibilityRole: "button",
2334
+ accessibilityLabel: voice.state === "listening" ? strings.micStopA11y : strings.micStartA11y,
2335
+ testID: "appilots-mic-button",
2336
+ activeOpacity: 0.7
2337
+ },
2338
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: styles5.sendButtonText }, "\u25CF")
2339
+ ) : null,
2340
+ isLoading ? /* @__PURE__ */ React8__namespace.default.createElement(
1794
2341
  reactNative.TouchableOpacity,
1795
2342
  {
1796
2343
  style: [
1797
- styles3.sendButton,
2344
+ styles5.sendButton,
1798
2345
  {
1799
2346
  backgroundColor: theme.colors.primary,
1800
2347
  borderRadius: theme.radii.md
@@ -1806,31 +2353,31 @@ function AppilotsChatInner({
1806
2353
  testID: "appilots-stop-button",
1807
2354
  activeOpacity: 0.7
1808
2355
  },
1809
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: styles3.sendButtonText }, "\u25A0")
1810
- ) : /* @__PURE__ */ React7__namespace.default.createElement(
2356
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: styles5.sendButtonText }, "\u25A0")
2357
+ ) : /* @__PURE__ */ React8__namespace.default.createElement(
1811
2358
  reactNative.TouchableOpacity,
1812
2359
  {
1813
2360
  style: [
1814
- styles3.sendButton,
2361
+ styles5.sendButton,
1815
2362
  {
1816
2363
  backgroundColor: inputText.trim() ? theme.colors.primary : theme.colors.primary + "40",
1817
2364
  borderRadius: theme.radii.md
1818
2365
  }
1819
2366
  ],
1820
2367
  onPress: handleSend,
1821
- disabled: !inputText.trim(),
2368
+ disabled: !inputText.trim() || !!(mission && !["completed", "cancelled"].includes(mission.status)),
1822
2369
  activeOpacity: 0.7,
1823
2370
  accessibilityRole: "button",
1824
2371
  testID: "assistant-send"
1825
2372
  },
1826
- /* @__PURE__ */ React7__namespace.default.createElement(reactNative.Text, { style: styles3.sendButtonText }, "\u2191")
2373
+ /* @__PURE__ */ React8__namespace.default.createElement(reactNative.Text, { style: styles5.sendButtonText }, "\u2191")
1827
2374
  )
1828
2375
  ),
1829
- poweredByVisible && /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { style: styles3.poweredByContainer }, /* @__PURE__ */ React7__namespace.default.createElement(
2376
+ poweredByVisible && /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { style: styles5.poweredByContainer }, /* @__PURE__ */ React8__namespace.default.createElement(
1830
2377
  reactNative.Text,
1831
2378
  {
1832
2379
  style: [
1833
- styles3.poweredByText,
2380
+ styles5.poweredByText,
1834
2381
  {
1835
2382
  color: theme.colors.textSecondary,
1836
2383
  fontFamily: theme.typography.fontFamily,
@@ -1846,11 +2393,12 @@ function AppilotsChatInner({
1846
2393
  }
1847
2394
  const renderTrigger = () => {
1848
2395
  if (triggerButton === "none") return null;
1849
- if (triggerButton !== "default" && React7__namespace.default.isValidElement(triggerButton)) {
1850
- return /* @__PURE__ */ React7__namespace.default.createElement(reactNative.View, { ...APPILOTS_SKIP_PROPS, style: [styles3.fabWrapper, fabPositionStyle] }, /* @__PURE__ */ React7__namespace.default.createElement(
2396
+ if (triggerButton !== "default" && React8__namespace.default.isValidElement(triggerButton)) {
2397
+ return /* @__PURE__ */ React8__namespace.default.createElement(reactNative.View, { ...APPILOTS_SKIP_PROPS, style: [styles5.fabWrapper, fabPositionStyle] }, /* @__PURE__ */ React8__namespace.default.createElement(
1851
2398
  reactNative.TouchableOpacity,
1852
2399
  {
1853
2400
  ...APPILOTS_SKIP_PROPS,
2401
+ ref: launcherRef,
1854
2402
  onPress: openChat,
1855
2403
  activeOpacity: 0.8,
1856
2404
  accessibilityRole: "button",
@@ -1860,12 +2408,13 @@ function AppilotsChatInner({
1860
2408
  triggerButton
1861
2409
  ));
1862
2410
  }
1863
- return /* @__PURE__ */ React7__namespace.default.createElement(
2411
+ return /* @__PURE__ */ React8__namespace.default.createElement(
1864
2412
  reactNative.TouchableOpacity,
1865
2413
  {
1866
2414
  ...APPILOTS_SKIP_PROPS,
2415
+ ref: launcherRef,
1867
2416
  style: [
1868
- styles3.fab,
2417
+ styles5.fab,
1869
2418
  fabPositionStyle,
1870
2419
  { backgroundColor: triggerButtonColor ?? theme.colors.primary }
1871
2420
  ],
@@ -1875,55 +2424,116 @@ function AppilotsChatInner({
1875
2424
  accessibilityLabel: strings.openChatA11y,
1876
2425
  testID: "assistant-launcher"
1877
2426
  },
1878
- triggerIcon ?? (triggerButtonImage ? /* @__PURE__ */ React7__namespace.default.createElement(
2427
+ triggerIcon ?? (triggerButtonImage ? /* @__PURE__ */ React8__namespace.default.createElement(
1879
2428
  reactNative.Image,
1880
2429
  {
1881
2430
  source: typeof triggerButtonImage === "string" ? { uri: triggerButtonImage } : triggerButtonImage,
1882
- style: styles3.fabImage,
2431
+ style: styles5.fabImage,
1883
2432
  resizeMode: "contain"
1884
2433
  }
1885
- ) : /* @__PURE__ */ React7__namespace.default.createElement(ChatIcon, { size: 26, color: "#ffffff" }))
2434
+ ) : /* @__PURE__ */ React8__namespace.default.createElement(ChatIcon, { size: 26, color: "#ffffff" }))
1886
2435
  );
1887
2436
  };
1888
- return /* @__PURE__ */ React7__namespace.default.createElement(React7__namespace.default.Fragment, null, showTrigger && renderTrigger(), /* @__PURE__ */ React7__namespace.default.createElement(
1889
- reactNative.Modal,
2437
+ return /* @__PURE__ */ React8__namespace.default.createElement(React8__namespace.default.Fragment, null, showTrigger && renderTrigger(), spotlight && experience.spotlight !== "off" ? /* @__PURE__ */ React8__namespace.default.createElement(
2438
+ SpotlightOverlay,
2439
+ {
2440
+ rect: spotlight.rect,
2441
+ seq: spotlight.seq,
2442
+ label: spotlight.label,
2443
+ color: theme.colors.primary,
2444
+ captionBackground: theme.colors.surface,
2445
+ captionColor: theme.colors.text,
2446
+ fontFamily: theme.typography.fontFamily,
2447
+ window: { width: SCREEN_WIDTH, height: SCREEN_HEIGHT }
2448
+ }
2449
+ ) : null, surface === "pill" && /* @__PURE__ */ React8__namespace.default.createElement(
2450
+ AgentPill,
2451
+ {
2452
+ label: mission && !["completed", "cancelled"].includes(mission.status) ? mission.progressText : pillLabel,
2453
+ state: pillState,
2454
+ position,
2455
+ insets,
2456
+ fontFamily: theme.typography.fontFamily,
2457
+ colors: {
2458
+ surface: theme.colors.surface,
2459
+ text: theme.colors.text,
2460
+ textSecondary: theme.colors.textSecondary,
2461
+ primary: theme.colors.primary,
2462
+ border: theme.colors.border,
2463
+ success: theme.colors.success,
2464
+ error: theme.colors.error
2465
+ },
2466
+ strings: { expandA11y: strings.pillExpandA11y, stopA11y: strings.pillStopA11y },
2467
+ onExpand: openChat,
2468
+ expandRef: pillRef,
2469
+ onStop: busy ? cancelMessage : void 0
2470
+ }
2471
+ ), /* @__PURE__ */ React8__namespace.default.createElement(SheetHost, { useModal: presence === "sheet", visible: isVisible, onRequestClose: closeChat }, /* @__PURE__ */ React8__namespace.default.createElement(
2472
+ reactNative.Animated.View,
1890
2473
  {
1891
2474
  ...APPILOTS_SKIP_PROPS,
1892
- visible: isVisible,
1893
- transparent: true,
1894
- animationType: "none",
1895
- onRequestClose: closeChat
2475
+ pointerEvents: presence === "sheet" ? "auto" : "box-none",
2476
+ onAccessibilityEscape: closeChat,
2477
+ style: [
2478
+ mode === "fullscreen" ? styles5.modalContainerFullscreen : styles5.modalContainer,
2479
+ mode === "sidebar" && styles5.modalContainerSidebar,
2480
+ presence !== "sheet" && styles5.sheetContainerNoScrim,
2481
+ // Keeps the sheet out of the status bar / notch. It is padding
2482
+ // and not a margin so the scrim still covers the full screen.
2483
+ // Only reachable now that the sheet can grow to the top edge:
2484
+ // `fullscreen` and `sidebar` always could, and `bubble` does
2485
+ // whenever the keyboard shrinks it — without this, the header
2486
+ // renders under the clock.
2487
+ { paddingTop: insets.top },
2488
+ { transform: [{ translateY: slideAnim }] }
2489
+ ]
1896
2490
  },
1897
- /* @__PURE__ */ React7__namespace.default.createElement(
1898
- reactNative.Animated.View,
2491
+ /* @__PURE__ */ React8__namespace.default.createElement(
2492
+ reactNative.KeyboardAvoidingView,
1899
2493
  {
1900
- ...APPILOTS_SKIP_PROPS,
1901
- style: [
1902
- mode === "fullscreen" ? styles3.modalContainerFullscreen : styles3.modalContainer,
1903
- mode === "sidebar" && styles3.modalContainerSidebar,
1904
- // Keeps the sheet out of the status bar / notch. It is padding
1905
- // and not a margin so the scrim still covers the full screen.
1906
- // Only reachable now that the sheet can grow to the top edge:
1907
- // `fullscreen` and `sidebar` always could, and `bubble` does
1908
- // whenever the keyboard shrinks it — without this, the header
1909
- // renders under the clock.
1910
- { paddingTop: insets.top },
1911
- { transform: [{ translateY: slideAnim }] }
1912
- ]
2494
+ style: styles5.keyboardView,
2495
+ behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
2496
+ keyboardVerticalOffset: 0
1913
2497
  },
1914
- /* @__PURE__ */ React7__namespace.default.createElement(
1915
- reactNative.KeyboardAvoidingView,
1916
- {
1917
- style: styles3.keyboardView,
1918
- behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
1919
- keyboardVerticalOffset: 0
1920
- },
1921
- chatSurface
1922
- )
2498
+ chatSurface
1923
2499
  )
1924
- ));
2500
+ )));
1925
2501
  }
1926
- var styles3 = reactNative.StyleSheet.create({
2502
+ function SheetHost({
2503
+ useModal,
2504
+ visible,
2505
+ onRequestClose,
2506
+ children
2507
+ }) {
2508
+ if (useModal) {
2509
+ return /* @__PURE__ */ React8__namespace.default.createElement(
2510
+ reactNative.Modal,
2511
+ {
2512
+ ...APPILOTS_SKIP_PROPS,
2513
+ visible,
2514
+ transparent: true,
2515
+ animationType: "none",
2516
+ onRequestClose
2517
+ },
2518
+ children
2519
+ );
2520
+ }
2521
+ if (!visible) return null;
2522
+ return /* @__PURE__ */ React8__namespace.default.createElement(
2523
+ reactNative.View,
2524
+ {
2525
+ ...APPILOTS_SKIP_PROPS,
2526
+ pointerEvents: "box-none",
2527
+ accessibilityViewIsModal: true,
2528
+ style: [reactNative.StyleSheet.absoluteFill, styles5.sheetOverlay]
2529
+ },
2530
+ children
2531
+ );
2532
+ }
2533
+ var styles5 = reactNative.StyleSheet.create({
2534
+ // An explicitly opened chat must not mount underneath a sibling portal.
2535
+ // Automatic expansion is separately deferred while the host modal is open.
2536
+ sheetOverlay: { zIndex: 1e3, elevation: 7 },
1927
2537
  fab: {
1928
2538
  position: "absolute",
1929
2539
  width: 56,
@@ -1966,6 +2576,12 @@ var styles3 = reactNative.StyleSheet.create({
1966
2576
  flexDirection: "row",
1967
2577
  justifyContent: "flex-end"
1968
2578
  },
2579
+ // Non-modal presences drop the scrim entirely: dimming the app is
2580
+ // the opposite of the point, and a painted full-screen surface is
2581
+ // touch-opaque no matter what pointerEvents the parent asks for.
2582
+ sheetContainerNoScrim: {
2583
+ backgroundColor: "transparent"
2584
+ },
1969
2585
  keyboardView: {
1970
2586
  flex: 1,
1971
2587
  justifyContent: "flex-end"
@@ -2007,8 +2623,13 @@ var styles3 = reactNative.StyleSheet.create({
2007
2623
  maxHeight: "100%",
2008
2624
  flex: 1
2009
2625
  },
2626
+ // Wraps instead of squeezing: at large text sizes the title alone is
2627
+ // wider than the row, and without the wrap it pushed Clear and ✕ off the
2628
+ // right edge — the chat could not be closed (measured at iOS AX5).
2010
2629
  header: {
2011
2630
  flexDirection: "row",
2631
+ flexWrap: "wrap",
2632
+ rowGap: 4,
2012
2633
  alignItems: "center",
2013
2634
  justifyContent: "space-between",
2014
2635
  paddingHorizontal: 16,
@@ -2018,7 +2639,8 @@ var styles3 = reactNative.StyleSheet.create({
2018
2639
  headerLeft: {
2019
2640
  flexDirection: "row",
2020
2641
  alignItems: "center",
2021
- gap: 8
2642
+ gap: 8,
2643
+ flexShrink: 1
2022
2644
  },
2023
2645
  headerDot: {
2024
2646
  width: 8,
@@ -2037,24 +2659,30 @@ var styles3 = reactNative.StyleSheet.create({
2037
2659
  justifyContent: "center"
2038
2660
  },
2039
2661
  headerTitle: {
2040
- fontWeight: "600"
2662
+ fontWeight: "600",
2663
+ flexShrink: 1
2041
2664
  },
2042
2665
  headerActions: {
2043
2666
  flexDirection: "row",
2044
2667
  alignItems: "center",
2045
- gap: 12
2668
+ gap: 4,
2669
+ // Stays right-aligned when the header wraps it onto its own line.
2670
+ marginLeft: "auto"
2046
2671
  },
2047
2672
  headerButton: {
2673
+ minWidth: MIN_TOUCH_TARGET2,
2674
+ minHeight: MIN_TOUCH_TARGET2,
2048
2675
  paddingHorizontal: 8,
2049
- paddingVertical: 4
2676
+ alignItems: "center",
2677
+ justifyContent: "center"
2050
2678
  },
2051
2679
  headerButtonText: {
2052
2680
  fontSize: 13
2053
2681
  },
2054
2682
  closeButton: {
2055
- width: 28,
2056
- height: 28,
2057
- borderRadius: 14,
2683
+ minWidth: MIN_TOUCH_TARGET2,
2684
+ minHeight: MIN_TOUCH_TARGET2,
2685
+ borderRadius: MIN_TOUCH_TARGET2 / 2,
2058
2686
  alignItems: "center",
2059
2687
  justifyContent: "center"
2060
2688
  },
@@ -2136,6 +2764,8 @@ var styles3 = reactNative.StyleSheet.create({
2136
2764
  maxWidth: 320
2137
2765
  },
2138
2766
  chip: {
2767
+ minHeight: MIN_TOUCH_TARGET2,
2768
+ justifyContent: "center",
2139
2769
  paddingHorizontal: 16,
2140
2770
  paddingVertical: 10,
2141
2771
  borderWidth: 1,
@@ -2198,16 +2828,16 @@ var styles3 = reactNative.StyleSheet.create({
2198
2828
  },
2199
2829
  input: {
2200
2830
  flex: 1,
2201
- minHeight: 38,
2202
- maxHeight: 120,
2831
+ minHeight: MIN_TOUCH_TARGET2,
2832
+ maxHeight: INPUT_MAX_HEIGHT,
2203
2833
  paddingHorizontal: 16,
2204
2834
  paddingTop: reactNative.Platform.OS === "ios" ? 9 : 8,
2205
2835
  paddingBottom: reactNative.Platform.OS === "ios" ? 9 : 8,
2206
2836
  textAlignVertical: "top"
2207
2837
  },
2208
2838
  sendButton: {
2209
- width: 38,
2210
- height: 38,
2839
+ minWidth: MIN_TOUCH_TARGET2,
2840
+ minHeight: MIN_TOUCH_TARGET2,
2211
2841
  alignItems: "center",
2212
2842
  justifyContent: "center"
2213
2843
  },
@@ -2216,6 +2846,15 @@ var styles3 = reactNative.StyleSheet.create({
2216
2846
  fontSize: 18,
2217
2847
  fontWeight: "700"
2218
2848
  },
2849
+ missionButtons: {
2850
+ flexDirection: "row",
2851
+ flexWrap: "wrap",
2852
+ columnGap: 12
2853
+ },
2854
+ missionButton: {
2855
+ minHeight: MIN_TOUCH_TARGET2,
2856
+ justifyContent: "center"
2857
+ },
2219
2858
  poweredByContainer: {
2220
2859
  alignItems: "center",
2221
2860
  paddingVertical: 4
@@ -2230,6 +2869,11 @@ function ConfirmDialog(_props = {}) {
2230
2869
  return null;
2231
2870
  }
2232
2871
 
2872
+ // src/auto/appilotsListTotal.ts
2873
+ function appilotsListTotal(total) {
2874
+ return { appilotsTotalItemCount: total };
2875
+ }
2876
+
2233
2877
  // src/hoc/canHoldRef.ts
2234
2878
  var FORWARD_REF = /* @__PURE__ */ Symbol.for("react.forward_ref");
2235
2879
  var MEMO = /* @__PURE__ */ Symbol.for("react.memo");
@@ -2256,12 +2900,19 @@ function canHoldRef(type) {
2256
2900
  }
2257
2901
  }
2258
2902
 
2903
+ // src/hoc/withDeclaredIdentity.ts
2904
+ function withDeclaredIdentity(props, declaredId, enabled) {
2905
+ if (!enabled || !declaredId) return props;
2906
+ if (props.testID != null) return props;
2907
+ return { ...props, testID: declaredId };
2908
+ }
2909
+
2259
2910
  // src/hoc/createAppilotsInput.tsx
2260
2911
  function normalizeId(label) {
2261
2912
  return label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+(.)/g, (_, c) => c.toUpperCase());
2262
2913
  }
2263
2914
  function createAppilotsInput(WrappedComponent) {
2264
- const AppilotsInput = React7__namespace.default.forwardRef((props, ref) => {
2915
+ const AppilotsInput = React8__namespace.default.forwardRef((props, ref) => {
2265
2916
  const {
2266
2917
  appilotsId,
2267
2918
  appilotsScreen,
@@ -2273,17 +2924,17 @@ function createAppilotsInput(WrappedComponent) {
2273
2924
  ...rest
2274
2925
  } = props;
2275
2926
  const fieldId = appilotsId || (label ? normalizeId(label) : null);
2276
- const valueRef = React7.useRef(value ?? "");
2277
- const onChangeRef = React7.useRef(onChangeText);
2278
- const innerRef = React7.useRef(null);
2927
+ const valueRef = React8.useRef(value ?? "");
2928
+ const onChangeRef = React8.useRef(onChangeText);
2929
+ const innerRef = React8.useRef(null);
2279
2930
  valueRef.current = value ?? "";
2280
2931
  onChangeRef.current = onChangeText;
2281
- const getValue = React7.useCallback(() => valueRef.current, []);
2282
- const setValue = React7.useCallback((v) => onChangeRef.current?.(v), []);
2283
- const focus = React7.useCallback(() => {
2932
+ const getValue = React8.useCallback(() => valueRef.current, []);
2933
+ const setValue = React8.useCallback((v) => onChangeRef.current?.(v), []);
2934
+ const focus = React8.useCallback(() => {
2284
2935
  innerRef.current?.focus?.();
2285
2936
  }, []);
2286
- React7.useEffect(() => {
2937
+ React8.useEffect(() => {
2287
2938
  if (!fieldId || !appilotsEnabled) return;
2288
2939
  const entry = {
2289
2940
  kind: "field",
@@ -2294,9 +2945,9 @@ function createAppilotsInput(WrappedComponent) {
2294
2945
  label: label ?? fieldId,
2295
2946
  screen: appilotsScreen
2296
2947
  };
2297
- chunkSUMIABJK_js.componentRegistry.register(fieldId, entry);
2948
+ chunkQAZ4TN3Z_js.componentRegistry.register(fieldId, entry);
2298
2949
  return () => {
2299
- chunkSUMIABJK_js.componentRegistry.unregister(fieldId);
2950
+ chunkQAZ4TN3Z_js.componentRegistry.unregister(fieldId);
2300
2951
  };
2301
2952
  }, [
2302
2953
  fieldId,
@@ -2308,7 +2959,7 @@ function createAppilotsInput(WrappedComponent) {
2308
2959
  label,
2309
2960
  appilotsScreen
2310
2961
  ]);
2311
- const mergedRef = React7.useCallback(
2962
+ const mergedRef = React8.useCallback(
2312
2963
  (instance) => {
2313
2964
  innerRef.current = instance;
2314
2965
  if (typeof ref === "function") ref(instance);
@@ -2316,10 +2967,14 @@ function createAppilotsInput(WrappedComponent) {
2316
2967
  },
2317
2968
  [ref]
2318
2969
  );
2319
- return /* @__PURE__ */ React7__namespace.default.createElement(
2970
+ return /* @__PURE__ */ React8__namespace.default.createElement(
2320
2971
  WrappedComponent,
2321
2972
  {
2322
- ...{ label, value, onChangeText, ...rest },
2973
+ ...withDeclaredIdentity(
2974
+ { label, value, onChangeText, ...rest },
2975
+ fieldId,
2976
+ appilotsEnabled
2977
+ ),
2323
2978
  ...canHoldRef(WrappedComponent) ? { ref: mergedRef } : {}
2324
2979
  }
2325
2980
  );
@@ -2331,7 +2986,7 @@ function normalizeId2(label) {
2331
2986
  return label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+(.)/g, (_, c) => c.toUpperCase());
2332
2987
  }
2333
2988
  function createAppilotsButton(WrappedComponent) {
2334
- const AppilotsButton = React7__namespace.default.forwardRef((props, ref) => {
2989
+ const AppilotsButton = React8__namespace.default.forwardRef((props, ref) => {
2335
2990
  const {
2336
2991
  appilotsId,
2337
2992
  appilotsScreen,
@@ -2341,10 +2996,10 @@ function createAppilotsButton(WrappedComponent) {
2341
2996
  ...rest
2342
2997
  } = props;
2343
2998
  const targetId = appilotsId || (title ? normalizeId2(title) : null);
2344
- const onPressRef = React7.useRef(onPress);
2999
+ const onPressRef = React8.useRef(onPress);
2345
3000
  onPressRef.current = onPress;
2346
- const press = React7.useCallback(() => onPressRef.current?.(), []);
2347
- React7.useEffect(() => {
3001
+ const press = React8.useCallback(() => onPressRef.current?.(), []);
3002
+ React8.useEffect(() => {
2348
3003
  if (!targetId || !appilotsEnabled) return;
2349
3004
  const entry = {
2350
3005
  kind: "target",
@@ -2352,15 +3007,15 @@ function createAppilotsButton(WrappedComponent) {
2352
3007
  label: title ?? targetId,
2353
3008
  screen: appilotsScreen
2354
3009
  };
2355
- chunkSUMIABJK_js.componentRegistry.register(targetId, entry);
3010
+ chunkQAZ4TN3Z_js.componentRegistry.register(targetId, entry);
2356
3011
  return () => {
2357
- chunkSUMIABJK_js.componentRegistry.unregister(targetId);
3012
+ chunkQAZ4TN3Z_js.componentRegistry.unregister(targetId);
2358
3013
  };
2359
3014
  }, [targetId, appilotsEnabled, press, title, appilotsScreen]);
2360
- return /* @__PURE__ */ React7__namespace.default.createElement(
3015
+ return /* @__PURE__ */ React8__namespace.default.createElement(
2361
3016
  WrappedComponent,
2362
3017
  {
2363
- ...{ title, onPress, ...rest },
3018
+ ...withDeclaredIdentity({ title, onPress, ...rest }, targetId, appilotsEnabled),
2364
3019
  ...canHoldRef(WrappedComponent) ? { ref } : {}
2365
3020
  }
2366
3021
  );
@@ -2372,7 +3027,7 @@ function normalizeId3(label) {
2372
3027
  return label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+(.)/g, (_, c) => c.toUpperCase());
2373
3028
  }
2374
3029
  function createAppilotsSwitch(WrappedComponent) {
2375
- const AppilotsSwitch = React7__namespace.default.forwardRef((props, ref) => {
3030
+ const AppilotsSwitch = React8__namespace.default.forwardRef((props, ref) => {
2376
3031
  const {
2377
3032
  appilotsId,
2378
3033
  appilotsScreen,
@@ -2383,13 +3038,13 @@ function createAppilotsSwitch(WrappedComponent) {
2383
3038
  ...rest
2384
3039
  } = props;
2385
3040
  const toggleId = appilotsId || (label ? normalizeId3(label) : null);
2386
- const valueRef = React7.useRef(value ?? false);
2387
- const onChangeRef = React7.useRef(onValueChange);
3041
+ const valueRef = React8.useRef(value ?? false);
3042
+ const onChangeRef = React8.useRef(onValueChange);
2388
3043
  valueRef.current = value ?? false;
2389
3044
  onChangeRef.current = onValueChange;
2390
- const getValue = React7.useCallback(() => valueRef.current, []);
2391
- const setValue = React7.useCallback((v) => onChangeRef.current?.(v), []);
2392
- React7.useEffect(() => {
3045
+ const getValue = React8.useCallback(() => valueRef.current, []);
3046
+ const setValue = React8.useCallback((v) => onChangeRef.current?.(v), []);
3047
+ React8.useEffect(() => {
2393
3048
  if (!toggleId || !appilotsEnabled) return;
2394
3049
  const entry = {
2395
3050
  kind: "toggle",
@@ -2398,15 +3053,19 @@ function createAppilotsSwitch(WrappedComponent) {
2398
3053
  label: label ?? toggleId,
2399
3054
  screen: appilotsScreen
2400
3055
  };
2401
- chunkSUMIABJK_js.componentRegistry.register(toggleId, entry);
3056
+ chunkQAZ4TN3Z_js.componentRegistry.register(toggleId, entry);
2402
3057
  return () => {
2403
- chunkSUMIABJK_js.componentRegistry.unregister(toggleId);
3058
+ chunkQAZ4TN3Z_js.componentRegistry.unregister(toggleId);
2404
3059
  };
2405
3060
  }, [toggleId, appilotsEnabled, getValue, setValue, label, appilotsScreen]);
2406
- return /* @__PURE__ */ React7__namespace.default.createElement(
3061
+ return /* @__PURE__ */ React8__namespace.default.createElement(
2407
3062
  WrappedComponent,
2408
3063
  {
2409
- ...{ label, value, onValueChange, ...rest },
3064
+ ...withDeclaredIdentity(
3065
+ { label, value, onValueChange, ...rest },
3066
+ toggleId,
3067
+ appilotsEnabled
3068
+ ),
2410
3069
  ...canHoldRef(WrappedComponent) ? { ref } : {}
2411
3070
  }
2412
3071
  );
@@ -2417,193 +3076,256 @@ function createAppilotsSwitch(WrappedComponent) {
2417
3076
 
2418
3077
  Object.defineProperty(exports, "AppilotsNavigationContainer", {
2419
3078
  enumerable: true,
2420
- get: function () { return chunk5UVMNKPT_js.AppilotsNavigationContainer; }
3079
+ get: function () { return chunkGDCBLSYT_js.AppilotsNavigationContainer; }
3080
+ });
3081
+ Object.defineProperty(exports, "AppilotsI18nProvider", {
3082
+ enumerable: true,
3083
+ get: function () { return chunkJGUDXRXN_js.AppilotsI18nProvider; }
3084
+ });
3085
+ Object.defineProperty(exports, "REVEAL_MARGIN", {
3086
+ enumerable: true,
3087
+ get: function () { return chunkJGUDXRXN_js.REVEAL_MARGIN; }
3088
+ });
3089
+ Object.defineProperty(exports, "SPOTLIGHT_TTL_MS", {
3090
+ enumerable: true,
3091
+ get: function () { return chunkJGUDXRXN_js.SPOTLIGHT_TTL_MS; }
2421
3092
  });
2422
3093
  Object.defineProperty(exports, "appilotsSelfCheck", {
2423
3094
  enumerable: true,
2424
- get: function () { return chunkUFMTRGML_js.appilotsSelfCheck; }
3095
+ get: function () { return chunkJGUDXRXN_js.appilotsSelfCheck; }
2425
3096
  });
2426
3097
  Object.defineProperty(exports, "captureSnapshot", {
2427
3098
  enumerable: true,
2428
- get: function () { return chunkUFMTRGML_js.captureSnapshot; }
3099
+ get: function () { return chunkJGUDXRXN_js.captureSnapshot; }
3100
+ });
3101
+ Object.defineProperty(exports, "detectDeviceLocale", {
3102
+ enumerable: true,
3103
+ get: function () { return chunkJGUDXRXN_js.detectDeviceLocale; }
2429
3104
  });
2430
3105
  Object.defineProperty(exports, "executeAction", {
2431
3106
  enumerable: true,
2432
- get: function () { return chunkUFMTRGML_js.executeAction; }
3107
+ get: function () { return chunkJGUDXRXN_js.executeAction; }
3108
+ });
3109
+ Object.defineProperty(exports, "getSpotlightMode", {
3110
+ enumerable: true,
3111
+ get: function () { return chunkJGUDXRXN_js.getSpotlightMode; }
3112
+ });
3113
+ Object.defineProperty(exports, "getSpotlightTarget", {
3114
+ enumerable: true,
3115
+ get: function () { return chunkJGUDXRXN_js.getSpotlightTarget; }
3116
+ });
3117
+ Object.defineProperty(exports, "offsetToReveal", {
3118
+ enumerable: true,
3119
+ get: function () { return chunkJGUDXRXN_js.offsetToReveal; }
3120
+ });
3121
+ Object.defineProperty(exports, "resolveLocale", {
3122
+ enumerable: true,
3123
+ get: function () { return chunkJGUDXRXN_js.resolveLocale; }
3124
+ });
3125
+ Object.defineProperty(exports, "revealTarget", {
3126
+ enumerable: true,
3127
+ get: function () { return chunkJGUDXRXN_js.revealTarget; }
3128
+ });
3129
+ Object.defineProperty(exports, "setSpotlightMode", {
3130
+ enumerable: true,
3131
+ get: function () { return chunkJGUDXRXN_js.setSpotlightMode; }
3132
+ });
3133
+ Object.defineProperty(exports, "setSpotlightTarget", {
3134
+ enumerable: true,
3135
+ get: function () { return chunkJGUDXRXN_js.setSpotlightTarget; }
3136
+ });
3137
+ Object.defineProperty(exports, "subscribeSpotlight", {
3138
+ enumerable: true,
3139
+ get: function () { return chunkJGUDXRXN_js.subscribeSpotlight; }
2433
3140
  });
2434
3141
  Object.defineProperty(exports, "useAppilots", {
2435
3142
  enumerable: true,
2436
- get: function () { return chunkUFMTRGML_js.useAppilots; }
3143
+ get: function () { return chunkJGUDXRXN_js.useAppilots; }
2437
3144
  });
2438
3145
  Object.defineProperty(exports, "useAppilotsActions", {
2439
3146
  enumerable: true,
2440
- get: function () { return chunkUFMTRGML_js.useAppilotsActions; }
3147
+ get: function () { return chunkJGUDXRXN_js.useAppilotsActions; }
2441
3148
  });
2442
3149
  Object.defineProperty(exports, "useAppilotsChat", {
2443
3150
  enumerable: true,
2444
- get: function () { return chunkUFMTRGML_js.useAppilotsChat; }
3151
+ get: function () { return chunkJGUDXRXN_js.useAppilotsChat; }
2445
3152
  });
2446
3153
  Object.defineProperty(exports, "useAppilotsField", {
2447
3154
  enumerable: true,
2448
- get: function () { return chunkUFMTRGML_js.useAppilotsField; }
3155
+ get: function () { return chunkJGUDXRXN_js.useAppilotsField; }
3156
+ });
3157
+ Object.defineProperty(exports, "useAppilotsI18n", {
3158
+ enumerable: true,
3159
+ get: function () { return chunkJGUDXRXN_js.useAppilotsI18n; }
2449
3160
  });
2450
3161
  Object.defineProperty(exports, "useAppilotsNavigation", {
2451
3162
  enumerable: true,
2452
- get: function () { return chunkUFMTRGML_js.useAppilotsNavigation; }
3163
+ get: function () { return chunkJGUDXRXN_js.useAppilotsNavigation; }
2453
3164
  });
2454
3165
  Object.defineProperty(exports, "useAppilotsSlider", {
2455
3166
  enumerable: true,
2456
- get: function () { return chunkUFMTRGML_js.useAppilotsSlider; }
3167
+ get: function () { return chunkJGUDXRXN_js.useAppilotsSlider; }
2457
3168
  });
2458
3169
  Object.defineProperty(exports, "useAppilotsTarget", {
2459
3170
  enumerable: true,
2460
- get: function () { return chunkUFMTRGML_js.useAppilotsTarget; }
3171
+ get: function () { return chunkJGUDXRXN_js.useAppilotsTarget; }
2461
3172
  });
2462
3173
  Object.defineProperty(exports, "useAppilotsToggle", {
2463
3174
  enumerable: true,
2464
- get: function () { return chunkUFMTRGML_js.useAppilotsToggle; }
3175
+ get: function () { return chunkJGUDXRXN_js.useAppilotsToggle; }
2465
3176
  });
2466
3177
  Object.defineProperty(exports, "useSuggestedPrompts", {
2467
3178
  enumerable: true,
2468
- get: function () { return chunkUFMTRGML_js.useSuggestedPrompts; }
3179
+ get: function () { return chunkJGUDXRXN_js.useSuggestedPrompts; }
2469
3180
  });
2470
3181
  Object.defineProperty(exports, "AppilotsClient", {
2471
3182
  enumerable: true,
2472
- get: function () { return chunkSUMIABJK_js.AppilotsClient; }
3183
+ get: function () { return chunkQAZ4TN3Z_js.AppilotsClient; }
2473
3184
  });
2474
3185
  Object.defineProperty(exports, "AppilotsProvider", {
2475
3186
  enumerable: true,
2476
- get: function () { return chunkSUMIABJK_js.AppilotsProvider; }
3187
+ get: function () { return chunkQAZ4TN3Z_js.AppilotsProvider; }
2477
3188
  });
2478
3189
  Object.defineProperty(exports, "AppilotsRegistryProvider", {
2479
3190
  enumerable: true,
2480
- get: function () { return chunkSUMIABJK_js.AppilotsRegistryProvider; }
3191
+ get: function () { return chunkQAZ4TN3Z_js.AppilotsRegistryProvider; }
2481
3192
  });
2482
3193
  Object.defineProperty(exports, "RateLimitedError", {
2483
3194
  enumerable: true,
2484
- get: function () { return chunkSUMIABJK_js.RateLimitedError; }
3195
+ get: function () { return chunkQAZ4TN3Z_js.RateLimitedError; }
2485
3196
  });
2486
3197
  Object.defineProperty(exports, "SDK_VERSION", {
2487
3198
  enumerable: true,
2488
- get: function () { return chunkSUMIABJK_js.SDK_VERSION; }
3199
+ get: function () { return chunkQAZ4TN3Z_js.SDK_VERSION; }
2489
3200
  });
2490
3201
  Object.defineProperty(exports, "_patchJsxRuntimes", {
2491
3202
  enumerable: true,
2492
- get: function () { return chunkSUMIABJK_js._patchJsxRuntimes; }
3203
+ get: function () { return chunkQAZ4TN3Z_js._patchJsxRuntimes; }
2493
3204
  });
2494
3205
  Object.defineProperty(exports, "clearAppilotsDebugTraces", {
2495
3206
  enumerable: true,
2496
- get: function () { return chunkSUMIABJK_js.clearAppilotsDebugTraces; }
3207
+ get: function () { return chunkQAZ4TN3Z_js.clearAppilotsDebugTraces; }
2497
3208
  });
2498
3209
  Object.defineProperty(exports, "componentRegistry", {
2499
3210
  enumerable: true,
2500
- get: function () { return chunkSUMIABJK_js.componentRegistry; }
3211
+ get: function () { return chunkQAZ4TN3Z_js.componentRegistry; }
2501
3212
  });
2502
3213
  Object.defineProperty(exports, "createComponentRegistry", {
2503
3214
  enumerable: true,
2504
- get: function () { return chunkSUMIABJK_js.createComponentRegistry; }
3215
+ get: function () { return chunkQAZ4TN3Z_js.createComponentRegistry; }
2505
3216
  });
2506
3217
  Object.defineProperty(exports, "createElementRegistry", {
2507
3218
  enumerable: true,
2508
- get: function () { return chunkSUMIABJK_js.createElementRegistry; }
3219
+ get: function () { return chunkQAZ4TN3Z_js.createElementRegistry; }
2509
3220
  });
2510
3221
  Object.defineProperty(exports, "createListRegistry", {
2511
3222
  enumerable: true,
2512
- get: function () { return chunkSUMIABJK_js.createListRegistry; }
3223
+ get: function () { return chunkQAZ4TN3Z_js.createListRegistry; }
2513
3224
  });
2514
3225
  Object.defineProperty(exports, "defaultDarkTheme", {
2515
3226
  enumerable: true,
2516
- get: function () { return chunkSUMIABJK_js.defaultDarkTheme; }
3227
+ get: function () { return chunkQAZ4TN3Z_js.defaultDarkTheme; }
2517
3228
  });
2518
3229
  Object.defineProperty(exports, "defaultLightTheme", {
2519
3230
  enumerable: true,
2520
- get: function () { return chunkSUMIABJK_js.defaultLightTheme; }
3231
+ get: function () { return chunkQAZ4TN3Z_js.defaultLightTheme; }
2521
3232
  });
2522
3233
  Object.defineProperty(exports, "describeAction", {
2523
3234
  enumerable: true,
2524
- get: function () { return chunkSUMIABJK_js.describeAction; }
3235
+ get: function () { return chunkQAZ4TN3Z_js.describeAction; }
2525
3236
  });
2526
3237
  Object.defineProperty(exports, "elementRegistry", {
2527
3238
  enumerable: true,
2528
- get: function () { return chunkSUMIABJK_js.elementRegistry; }
3239
+ get: function () { return chunkQAZ4TN3Z_js.elementRegistry; }
2529
3240
  });
2530
3241
  Object.defineProperty(exports, "enableAppilotsAutoTracking", {
2531
3242
  enumerable: true,
2532
- get: function () { return chunkSUMIABJK_js.enableAppilotsAutoTracking; }
3243
+ get: function () { return chunkQAZ4TN3Z_js.enableAppilotsAutoTracking; }
2533
3244
  });
2534
3245
  Object.defineProperty(exports, "getAppilotsDebugTraces", {
2535
3246
  enumerable: true,
2536
- get: function () { return chunkSUMIABJK_js.getAppilotsDebugTraces; }
3247
+ get: function () { return chunkQAZ4TN3Z_js.getAppilotsDebugTraces; }
2537
3248
  });
2538
3249
  Object.defineProperty(exports, "getAutoTrackingState", {
2539
3250
  enumerable: true,
2540
- get: function () { return chunkSUMIABJK_js.getAutoTrackingState; }
3251
+ get: function () { return chunkQAZ4TN3Z_js.getAutoTrackingState; }
2541
3252
  });
2542
3253
  Object.defineProperty(exports, "getGlobalConfig", {
2543
3254
  enumerable: true,
2544
- get: function () { return chunkSUMIABJK_js.getGlobalConfig; }
3255
+ get: function () { return chunkQAZ4TN3Z_js.getGlobalConfig; }
2545
3256
  });
2546
3257
  Object.defineProperty(exports, "getIntrospectionDiagnostics", {
2547
3258
  enumerable: true,
2548
- get: function () { return chunkSUMIABJK_js.getIntrospectionDiagnostics; }
3259
+ get: function () { return chunkQAZ4TN3Z_js.getIntrospectionDiagnostics; }
2549
3260
  });
2550
3261
  Object.defineProperty(exports, "humanizeError", {
2551
3262
  enumerable: true,
2552
- get: function () { return chunkSUMIABJK_js.humanizeError; }
3263
+ get: function () { return chunkQAZ4TN3Z_js.humanizeError; }
2553
3264
  });
2554
3265
  Object.defineProperty(exports, "initAppilots", {
2555
3266
  enumerable: true,
2556
- get: function () { return chunkSUMIABJK_js.initAppilots; }
3267
+ get: function () { return chunkQAZ4TN3Z_js.initAppilots; }
2557
3268
  });
2558
3269
  Object.defineProperty(exports, "isAutoTrackingEnabled", {
2559
3270
  enumerable: true,
2560
- get: function () { return chunkSUMIABJK_js.isAutoTrackingEnabled; }
3271
+ get: function () { return chunkQAZ4TN3Z_js.isAutoTrackingEnabled; }
3272
+ });
3273
+ Object.defineProperty(exports, "isSpeechHost", {
3274
+ enumerable: true,
3275
+ get: function () { return chunkQAZ4TN3Z_js.isSpeechHost; }
2561
3276
  });
2562
3277
  Object.defineProperty(exports, "listRegistry", {
2563
3278
  enumerable: true,
2564
- get: function () { return chunkSUMIABJK_js.listRegistry; }
3279
+ get: function () { return chunkQAZ4TN3Z_js.listRegistry; }
2565
3280
  });
2566
3281
  Object.defineProperty(exports, "mergeThemeTokens", {
2567
3282
  enumerable: true,
2568
- get: function () { return chunkSUMIABJK_js.mergeThemeTokens; }
3283
+ get: function () { return chunkQAZ4TN3Z_js.mergeThemeTokens; }
2569
3284
  });
2570
3285
  Object.defineProperty(exports, "recordAppilotsDebugTrace", {
2571
3286
  enumerable: true,
2572
- get: function () { return chunkSUMIABJK_js.recordAppilotsDebugTrace; }
3287
+ get: function () { return chunkQAZ4TN3Z_js.recordAppilotsDebugTrace; }
2573
3288
  });
2574
3289
  Object.defineProperty(exports, "registerScreen", {
2575
3290
  enumerable: true,
2576
- get: function () { return chunkSUMIABJK_js.registerScreen; }
3291
+ get: function () { return chunkQAZ4TN3Z_js.registerScreen; }
2577
3292
  });
2578
3293
  Object.defineProperty(exports, "setCurrentScreen", {
2579
3294
  enumerable: true,
2580
- get: function () { return chunkSUMIABJK_js.setCurrentScreen; }
3295
+ get: function () { return chunkQAZ4TN3Z_js.setCurrentScreen; }
2581
3296
  });
2582
3297
  Object.defineProperty(exports, "subscribeAppilotsDebugTraces", {
2583
3298
  enumerable: true,
2584
- get: function () { return chunkSUMIABJK_js.subscribeAppilotsDebugTraces; }
3299
+ get: function () { return chunkQAZ4TN3Z_js.subscribeAppilotsDebugTraces; }
2585
3300
  });
2586
3301
  Object.defineProperty(exports, "useAppilotsContext", {
2587
3302
  enumerable: true,
2588
- get: function () { return chunkSUMIABJK_js.useAppilotsContext; }
3303
+ get: function () { return chunkQAZ4TN3Z_js.useAppilotsContext; }
2589
3304
  });
2590
3305
  Object.defineProperty(exports, "useResolvedRegistry", {
2591
3306
  enumerable: true,
2592
- get: function () { return chunkSUMIABJK_js.useResolvedRegistry; }
3307
+ get: function () { return chunkQAZ4TN3Z_js.useResolvedRegistry; }
2593
3308
  });
2594
3309
  exports.ActionBreadcrumb = ActionBreadcrumb;
3310
+ exports.AgentPill = AgentPill;
2595
3311
  exports.AppilotsChat = AppilotsChat;
2596
- exports.AppilotsI18nProvider = AppilotsI18nProvider;
2597
3312
  exports.AppilotsThemeProvider = AppilotsThemeProvider;
2598
3313
  exports.ChatIcon = ChatIcon;
2599
3314
  exports.ConfirmDialog = ConfirmDialog;
3315
+ exports.DEFAULT_EXPERIENCE = DEFAULT_EXPERIENCE;
2600
3316
  exports.HeadsetIcon = HeadsetIcon;
3317
+ exports.SpotlightOverlay = SpotlightOverlay;
3318
+ exports.appilotsListTotal = appilotsListTotal;
2601
3319
  exports.appilotsTheme = appilotsTheme;
2602
3320
  exports.appilotsThemeFromTailwind = appilotsThemeFromTailwind;
2603
3321
  exports.createAppilotsButton = createAppilotsButton;
2604
3322
  exports.createAppilotsInput = createAppilotsInput;
2605
3323
  exports.createAppilotsSwitch = createAppilotsSwitch;
2606
- exports.detectDeviceLocale = detectDeviceLocale;
2607
- exports.resolveLocale = resolveLocale;
2608
- exports.useAppilotsI18n = useAppilotsI18n;
3324
+ exports.formatDowngrades = formatDowngrades;
3325
+ exports.resolveExperience = resolveExperience;
3326
+ exports.resolvePillStatus = resolvePillStatus;
3327
+ exports.resolveSurface = resolveSurface;
3328
+ exports.shouldReopenOnTurnEnd = shouldReopenOnTurnEnd;
2609
3329
  exports.useAppilotsTheme = useAppilotsTheme;
3330
+ exports.useSpotlight = useSpotlight;
3331
+ exports.usesPill = usesPill;