@appilots/sdk 0.11.3 → 0.13.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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkSUMIABJK_js = require('./chunk-SUMIABJK.js');
3
+ var chunkUZ2D4BVX_js = require('./chunk-UZ2D4BVX.js');
4
4
  var React = require('react');
5
5
  var reactNative = require('react-native');
6
6
 
@@ -8,6 +8,261 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
8
 
9
9
  var React__default = /*#__PURE__*/_interopDefault(React);
10
10
 
11
+ // src/i18n/bundles/pt-BR.ts
12
+ var ptBR = {
13
+ chatTitle: "Assistente Appilots",
14
+ clearButton: "Limpar",
15
+ inputPlaceholder: "Digite uma mensagem...",
16
+ emptyTitle: "Como posso ajudar?",
17
+ emptySubtitle: "Navego, preencho formul\xE1rios e executo a\xE7\xF5es neste app.",
18
+ thinking: "Pensando...",
19
+ statusAnalyzing: "Analisando a tela...",
20
+ statusWaitingApp: "Aguardando o app responder...",
21
+ statusAdjusting: "Ajustando o plano...",
22
+ poweredBy: "Powered by Appilots",
23
+ approve: "Aprovar",
24
+ reject: "Rejeitar",
25
+ cancelledByUser: "Cancelado pelo usu\xE1rio",
26
+ confirmDestructiveTitle: "A\xE7\xE3o destrutiva",
27
+ confirmTitle: "Confirma\xE7\xE3o necess\xE1ria",
28
+ confirmMessage: 'Tem certeza que deseja "{action}"?',
29
+ confirmDestructiveApprove: "Sim, executar",
30
+ confirmApprove: "Confirmar",
31
+ confirmCancel: "Cancelar",
32
+ confirmThisAction: "esta a\xE7\xE3o",
33
+ unknownAction: "A\xE7\xE3o desconhecida",
34
+ somethingWentWrong: "Algo deu errado",
35
+ openChatA11y: "Abrir chat do assistente",
36
+ closeChatA11y: "Fechar chat do assistente",
37
+ stopGeneratingA11y: "Parar gera\xE7\xE3o",
38
+ talkToHumanA11y: "Falar com um atendente humano",
39
+ humanAgentLabel: "Atendente",
40
+ escalationRequested: "Certo! Chamei um atendente humano. Voc\xEA pode continuar usando o app normalmente enquanto isso.",
41
+ escalationConnected: "Um atendente entrou na conversa.",
42
+ escalationResolved: "O atendimento humano foi encerrado. Voltei a te ajudar por aqui.",
43
+ escalationOffer: "Se preferir, posso chamar uma pessoa para ajudar.",
44
+ escalationOfferChip: "Falar com um atendente",
45
+ escalationPendingBanner: "Aguardando um atendente...",
46
+ escalationActiveBanner: "Voc\xEA est\xE1 falando com um atendente",
47
+ pillWorking: "Trabalhando...",
48
+ pillExpandA11y: "Abrir a conversa do assistente",
49
+ pillStopA11y: "Parar o assistente",
50
+ missionPause: "Pausar",
51
+ missionResume: "Retomar tarefa",
52
+ missionCancel: "Cancelar tarefa",
53
+ missionPaused: "Pausada",
54
+ pillDone: "Pronto \u2014 toque para ver",
55
+ micStartA11y: "Segurar para falar",
56
+ micStopA11y: "Soltar para enviar",
57
+ micListening: "Ouvindo..."
58
+ };
59
+
60
+ // src/i18n/bundles/en.ts
61
+ var en = {
62
+ chatTitle: "Appilots Assistant",
63
+ clearButton: "Clear",
64
+ inputPlaceholder: "Type a message...",
65
+ emptyTitle: "How can I help?",
66
+ emptySubtitle: "I navigate, fill forms, and run actions in this app.",
67
+ thinking: "Thinking...",
68
+ statusAnalyzing: "Reading the screen...",
69
+ statusWaitingApp: "Waiting for the app...",
70
+ statusAdjusting: "Adjusting the plan...",
71
+ poweredBy: "Powered by Appilots",
72
+ approve: "Approve",
73
+ reject: "Reject",
74
+ cancelledByUser: "Cancelled by user",
75
+ confirmDestructiveTitle: "Destructive action",
76
+ confirmTitle: "Confirmation needed",
77
+ confirmMessage: 'Are you sure you want to "{action}"?',
78
+ confirmDestructiveApprove: "Yes, do it",
79
+ confirmApprove: "Confirm",
80
+ confirmCancel: "Cancel",
81
+ confirmThisAction: "this action",
82
+ unknownAction: "Unknown action",
83
+ somethingWentWrong: "Something went wrong",
84
+ openChatA11y: "Open assistant chat",
85
+ closeChatA11y: "Close assistant chat",
86
+ stopGeneratingA11y: "Stop generating",
87
+ talkToHumanA11y: "Talk to a human agent",
88
+ humanAgentLabel: "Agent",
89
+ escalationRequested: "Done! I've called a human agent. You can keep using the app normally in the meantime.",
90
+ escalationConnected: "A human agent joined the conversation.",
91
+ escalationResolved: "The human handoff has ended. I'm back to help you here.",
92
+ escalationOffer: "If you prefer, I can bring in a person to help.",
93
+ escalationOfferChip: "Talk to a human",
94
+ escalationPendingBanner: "Waiting for a human agent...",
95
+ escalationActiveBanner: "You're talking to a human agent",
96
+ pillWorking: "Working...",
97
+ pillExpandA11y: "Open the assistant conversation",
98
+ pillStopA11y: "Stop the assistant",
99
+ missionPause: "Pause",
100
+ missionResume: "Resume task",
101
+ missionCancel: "Cancel task",
102
+ missionPaused: "Paused",
103
+ pillDone: "Done \u2014 tap to read",
104
+ micStartA11y: "Hold to talk",
105
+ micStopA11y: "Release to send",
106
+ micListening: "Listening..."
107
+ };
108
+
109
+ // src/i18n/bundles/es.ts
110
+ var es = {
111
+ chatTitle: "Asistente Appilots",
112
+ clearButton: "Limpiar",
113
+ inputPlaceholder: "Escribe un mensaje...",
114
+ emptyTitle: "\xBFEn qu\xE9 puedo ayudarte?",
115
+ emptySubtitle: "Navego, relleno formularios y ejecuto acciones en esta app.",
116
+ thinking: "Pensando...",
117
+ statusAnalyzing: "Analizando la pantalla...",
118
+ statusWaitingApp: "Esperando a la app...",
119
+ statusAdjusting: "Ajustando el plan...",
120
+ poweredBy: "Hecho con Appilots",
121
+ approve: "Aprobar",
122
+ reject: "Rechazar",
123
+ cancelledByUser: "Cancelado por el usuario",
124
+ confirmDestructiveTitle: "Acci\xF3n destructiva",
125
+ confirmTitle: "Confirmaci\xF3n necesaria",
126
+ confirmMessage: '\xBFSeguro que quieres "{action}"?',
127
+ confirmDestructiveApprove: "S\xED, ejecutar",
128
+ confirmApprove: "Confirmar",
129
+ confirmCancel: "Cancelar",
130
+ confirmThisAction: "esta acci\xF3n",
131
+ unknownAction: "Acci\xF3n desconocida",
132
+ somethingWentWrong: "Algo sali\xF3 mal",
133
+ openChatA11y: "Abrir chat del asistente",
134
+ closeChatA11y: "Cerrar chat del asistente",
135
+ stopGeneratingA11y: "Detener generaci\xF3n",
136
+ talkToHumanA11y: "Hablar con un agente humano",
137
+ humanAgentLabel: "Agente",
138
+ escalationRequested: "\xA1Listo! Llam\xE9 a un agente humano. Mientras tanto puedes seguir usando la app con normalidad.",
139
+ escalationConnected: "Un agente humano se uni\xF3 a la conversaci\xF3n.",
140
+ escalationResolved: "La atenci\xF3n humana termin\xF3. Vuelvo a ayudarte por aqu\xED.",
141
+ escalationOffer: "Si prefieres, puedo llamar a una persona para ayudarte.",
142
+ escalationOfferChip: "Hablar con un agente",
143
+ escalationPendingBanner: "Esperando a un agente...",
144
+ escalationActiveBanner: "Est\xE1s hablando con un agente humano",
145
+ pillWorking: "Trabajando...",
146
+ pillExpandA11y: "Abrir la conversaci\xF3n del asistente",
147
+ pillStopA11y: "Detener el asistente",
148
+ missionPause: "Pausar",
149
+ missionResume: "Reanudar tarea",
150
+ missionCancel: "Cancelar tarea",
151
+ missionPaused: "Pausada",
152
+ pillDone: "Listo \u2014 toca para ver",
153
+ micStartA11y: "Mantener para hablar",
154
+ micStopA11y: "Soltar para enviar",
155
+ micListening: "Escuchando..."
156
+ };
157
+
158
+ // src/i18n/bundles/fr.ts
159
+ var fr = {
160
+ chatTitle: "Assistant Appilots",
161
+ clearButton: "Effacer",
162
+ inputPlaceholder: "\xC9crivez un message\u2026",
163
+ emptyTitle: "Comment puis-je vous aider ?",
164
+ emptySubtitle: "Je navigue, remplis les formulaires et effectue des actions dans cette application.",
165
+ thinking: "R\xE9flexion en cours\u2026",
166
+ statusAnalyzing: "Lecture de l\u2019\xE9cran\u2026",
167
+ statusWaitingApp: "En attente de l\u2019application\u2026",
168
+ statusAdjusting: "Ajustement du plan\u2026",
169
+ poweredBy: "Propuls\xE9 par Appilots",
170
+ approve: "Approuver",
171
+ reject: "Refuser",
172
+ cancelledByUser: "Annul\xE9 par l\u2019utilisateur",
173
+ confirmDestructiveTitle: "Action destructive",
174
+ confirmTitle: "Confirmation requise",
175
+ confirmMessage: "Voulez-vous vraiment \xAB {action} \xBB ?",
176
+ confirmDestructiveApprove: "Oui, ex\xE9cuter",
177
+ confirmApprove: "Confirmer",
178
+ confirmCancel: "Annuler",
179
+ confirmThisAction: "cette action",
180
+ unknownAction: "Action inconnue",
181
+ somethingWentWrong: "Une erreur est survenue",
182
+ openChatA11y: "Ouvrir la conversation avec l\u2019assistant",
183
+ closeChatA11y: "Fermer la conversation",
184
+ stopGeneratingA11y: "Arr\xEAter la g\xE9n\xE9ration",
185
+ talkToHumanA11y: "Parler \xE0 un conseiller",
186
+ humanAgentLabel: "Conseiller",
187
+ escalationRequested: "J\u2019ai contact\xE9 un conseiller. Vous pouvez continuer \xE0 utiliser l\u2019application en attendant.",
188
+ escalationConnected: "Un conseiller a rejoint la conversation.",
189
+ escalationResolved: "L\u2019intervention du conseiller est termin\xE9e. Je peux \xE0 nouveau vous aider.",
190
+ escalationOffer: "Si vous pr\xE9f\xE9rez, je peux faire appel \xE0 un conseiller.",
191
+ escalationOfferChip: "Parler \xE0 un conseiller",
192
+ escalationPendingBanner: "En attente d\u2019un conseiller\u2026",
193
+ escalationActiveBanner: "Vous discutez avec un conseiller",
194
+ pillWorking: "En cours\u2026",
195
+ pillExpandA11y: "Ouvrir la conversation avec l\u2019assistant",
196
+ pillStopA11y: "Arr\xEAter l\u2019assistant",
197
+ missionPause: "Mettre en pause",
198
+ missionResume: "Reprendre la t\xE2che",
199
+ missionCancel: "Annuler la t\xE2che",
200
+ missionPaused: "En pause",
201
+ pillDone: "Termin\xE9 \u2014 touchez pour lire",
202
+ micStartA11y: "Maintenez pour parler",
203
+ micStopA11y: "Rel\xE2chez pour envoyer",
204
+ micListening: "\xC9coute en cours\u2026"
205
+ };
206
+
207
+ // src/i18n/I18nProvider.tsx
208
+ var BUNDLES = {
209
+ "pt-BR": ptBR,
210
+ en,
211
+ es,
212
+ fr
213
+ };
214
+ var DEFAULT_LOCALE = "en";
215
+ function detectDeviceLocale() {
216
+ try {
217
+ let raw;
218
+ if (reactNative.Platform.OS === "ios") {
219
+ const manager = reactNative.NativeModules?.SettingsManager;
220
+ const settings = manager?.getConstants?.()?.settings ?? manager?.settings;
221
+ const languages = Array.isArray(settings?.AppleLanguages) ? settings.AppleLanguages : [];
222
+ for (const language of languages) {
223
+ const locale = chunkUZ2D4BVX_js.normalizeAppilotsLocale(language);
224
+ if (locale) return locale;
225
+ }
226
+ raw = settings?.AppleLocale;
227
+ } else if (reactNative.Platform.OS === "android") {
228
+ const manager = reactNative.NativeModules?.I18nManager;
229
+ raw = manager?.getConstants?.()?.localeIdentifier ?? manager?.localeIdentifier;
230
+ }
231
+ if (!raw || typeof raw !== "string") return null;
232
+ return chunkUZ2D4BVX_js.normalizeAppilotsLocale(raw) ?? null;
233
+ } catch {
234
+ return null;
235
+ }
236
+ }
237
+ function resolveLocale(prop) {
238
+ if (prop && BUNDLES[prop]) return prop;
239
+ const detected = detectDeviceLocale();
240
+ if (detected && BUNDLES[detected]) return detected;
241
+ return DEFAULT_LOCALE;
242
+ }
243
+ var I18nContext = React.createContext(null);
244
+ function AppilotsI18nProvider({ locale, overrides, children }) {
245
+ const value = React.useMemo(() => {
246
+ const resolved = resolveLocale(locale ?? null);
247
+ const merged = overrides ? { ...BUNDLES[resolved], ...overrides } : BUNDLES[resolved];
248
+ return {
249
+ locale: resolved,
250
+ strings: merged,
251
+ t: (key) => merged[key]
252
+ };
253
+ }, [locale, overrides]);
254
+ return /* @__PURE__ */ React__default.default.createElement(I18nContext.Provider, { value }, children);
255
+ }
256
+ function useAppilotsI18n() {
257
+ const ctx = React.useContext(I18nContext);
258
+ if (ctx) return ctx;
259
+ return {
260
+ locale: DEFAULT_LOCALE,
261
+ strings: BUNDLES[DEFAULT_LOCALE],
262
+ t: (key) => BUNDLES[DEFAULT_LOCALE][key]
263
+ };
264
+ }
265
+
11
266
  // src/introspection/captureSnapshot.ts
12
267
  function normalizeSliderKey(value) {
13
268
  return (value ?? "").toLowerCase().replace(/^slider[-_]/, "");
@@ -23,9 +278,9 @@ function fiberSliderMatches(fiber, registryId, registryLabel) {
23
278
  function reconcileSliders(snapshot) {
24
279
  const fiberSliders = snapshot.sliders;
25
280
  const out = [];
26
- for (const { id, kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
281
+ for (const { id, kind } of chunkUZ2D4BVX_js.componentRegistry.snapshot()) {
27
282
  if (kind !== "slider") continue;
28
- const entry = chunkSUMIABJK_js.componentRegistry.getSlider(id);
283
+ const entry = chunkUZ2D4BVX_js.componentRegistry.getSlider(id);
29
284
  if (!entry) continue;
30
285
  const fiber = fiberSliders.find((s) => fiberSliderMatches(s, id, entry.label));
31
286
  const visible = !!fiber || typeof entry.screen === "string" && entry.screen === snapshot.route;
@@ -53,7 +308,7 @@ function normalizeFieldKey(value) {
53
308
  }
54
309
  function canonicalizeRegisteredFields(snapshot) {
55
310
  const claimed = /* @__PURE__ */ new Set();
56
- for (const { id, kind, label } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
311
+ for (const { id, kind, label } of chunkUZ2D4BVX_js.componentRegistry.snapshot()) {
57
312
  if (kind !== "field") continue;
58
313
  if (snapshot.inputs.some((input) => input.id === id)) continue;
59
314
  const registryLabel = (label ?? "").toLowerCase();
@@ -72,7 +327,7 @@ function canonicalizeRegisteredFields(snapshot) {
72
327
  }
73
328
  }
74
329
  function mergeRegisteredLists(snapshot) {
75
- const registered = chunkSUMIABJK_js.listRegistry.snapshot();
330
+ const registered = chunkUZ2D4BVX_js.listRegistry.snapshot();
76
331
  if (registered.length === 0) return;
77
332
  const byId = /* @__PURE__ */ new Map();
78
333
  for (const list of snapshot.lists) {
@@ -80,20 +335,35 @@ function mergeRegisteredLists(snapshot) {
80
335
  }
81
336
  for (const entry of registered) {
82
337
  if (entry.kind === "scroll") continue;
338
+ const existing = byId.get(entry.id);
339
+ if (!existing && !(entry.screen && entry.screen === snapshot.route)) continue;
83
340
  const metrics = entry.getScrollMetrics?.();
84
341
  const scrollFacts = metrics ? {
85
342
  scrollOffsetY: Math.max(0, Math.round(metrics.offset)),
86
343
  canScrollUp: metrics.offset > 8,
87
344
  canScrollDown: metrics.offset + metrics.visibleLength < metrics.contentLength - 8
88
345
  } : void 0;
89
- const existing = byId.get(entry.id);
90
346
  if (existing) {
91
347
  existing.itemCount = existing.itemCount ?? entry.itemCount;
348
+ existing.totalItemCount = existing.totalItemCount ?? entry.totalItemCount;
92
349
  existing.refreshing = existing.refreshing ?? entry.refreshing;
93
350
  existing.empty = existing.empty ?? entry.empty;
94
351
  existing.label = existing.label ?? entry.label;
95
352
  existing.source = existing.source ?? "auto-tracked";
96
353
  existing.visibleItemCount = existing.items.length;
354
+ const viewport = entry.measureViewport?.();
355
+ if (viewport && viewport.width > 0 && viewport.height > 0) {
356
+ let measured = 0;
357
+ let inViewport = 0;
358
+ for (const item of existing.items) {
359
+ const rect = chunkUZ2D4BVX_js.rectForNode(item);
360
+ if (!rect) continue;
361
+ measured++;
362
+ item.onScreen = rect.width > 0 && rect.height > 0 && rect.x < viewport.x + viewport.width && rect.x + rect.width > viewport.x && rect.y < viewport.y + viewport.height && rect.y + rect.height > viewport.y;
363
+ if (item.onScreen) inViewport++;
364
+ }
365
+ if (measured === existing.items.length) existing.viewportItemCount = inViewport;
366
+ }
97
367
  if (entry.dataPreview && entry.dataPreview.length > 0) {
98
368
  existing.dataPreview = entry.dataPreview;
99
369
  }
@@ -110,6 +380,7 @@ function mergeRegisteredLists(snapshot) {
110
380
  containerType: entry.component,
111
381
  source: "registry",
112
382
  itemCount: entry.itemCount,
383
+ totalItemCount: entry.totalItemCount,
113
384
  visibleItemCount: 0,
114
385
  refreshing: entry.refreshing,
115
386
  empty: entry.empty,
@@ -121,7 +392,7 @@ function mergeRegisteredLists(snapshot) {
121
392
  }
122
393
  }
123
394
  function mergeRegisteredScrollables(snapshot) {
124
- const registered = chunkSUMIABJK_js.listRegistry.snapshot().filter((e) => e.kind === "scroll");
395
+ const registered = chunkUZ2D4BVX_js.listRegistry.snapshot().filter((e) => e.kind === "scroll");
125
396
  if (registered.length === 0) return;
126
397
  const listsById = /* @__PURE__ */ new Map();
127
398
  for (const list of snapshot.lists) {
@@ -154,7 +425,7 @@ function mergeRegisteredScrollables(snapshot) {
154
425
  if (out.length > 0) snapshot.scrollables = out;
155
426
  }
156
427
  function mergeNativeDialog(snapshot) {
157
- const dialog = chunkSUMIABJK_js.getOpenNativeDialog();
428
+ const dialog = chunkUZ2D4BVX_js.getOpenNativeDialog();
158
429
  if (!dialog) return;
159
430
  snapshot.nativeDialog = {
160
431
  id: dialog.id,
@@ -169,21 +440,58 @@ function mergeNativeDialog(snapshot) {
169
440
  }
170
441
  var MIN_FIBERS_FOR_BLINDNESS = 200;
171
442
  function recordBlindWalk() {
172
- const walk = chunkSUMIABJK_js.getLastWalkDiagnostics();
443
+ const walk = chunkUZ2D4BVX_js.getLastWalkDiagnostics();
173
444
  if (!walk) return;
174
445
  if (walk.visitedFibers < MIN_FIBERS_FOR_BLINDNESS) return;
175
- if (chunkSUMIABJK_js.totalDetectorHits(walk.detectors) > 0) return;
176
- chunkSUMIABJK_js.recordIntrospectionFailure("walk-recognized-nothing", null);
446
+ if (chunkUZ2D4BVX_js.totalDetectorHits(walk.detectors) > 0) return;
447
+ chunkUZ2D4BVX_js.recordIntrospectionFailure("walk-recognized-nothing", null);
448
+ }
449
+ function mergeRegisteredFieldValues(snapshot) {
450
+ const present = new Set(snapshot.inputs.map((i) => normalizeFieldKey(i.id)));
451
+ const onScreenIds = [
452
+ ...snapshot.buttons.map((b) => (b.id ?? "").toLowerCase()),
453
+ ...snapshot.toggles.map((t) => (t.id ?? "").toLowerCase())
454
+ ].filter(Boolean);
455
+ const onScreenLabels = new Set(
456
+ [...snapshot.buttons.map((b) => b.label), ...snapshot.texts].filter((l) => !!l).map((l) => l.toLowerCase())
457
+ );
458
+ for (const { id, kind, screen, label } of chunkUZ2D4BVX_js.componentRegistry.snapshot()) {
459
+ if (kind !== "field") continue;
460
+ const key = normalizeFieldKey(id);
461
+ if (!key || present.has(key)) continue;
462
+ const entry = chunkUZ2D4BVX_js.componentRegistry.getField(id);
463
+ if (!entry) continue;
464
+ const fieldType = entry.fieldType ?? "";
465
+ if (fieldType === "text" || fieldType === "") continue;
466
+ const declaresRoute = typeof screen === "string" && screen === snapshot.route;
467
+ if (screen && !declaresRoute && !chunkUZ2D4BVX_js.getActiveRouteNames().includes(screen)) continue;
468
+ const idEvidence = onScreenIds.some((candidate) => candidate.split(/[^a-z0-9]+/).includes(key));
469
+ const labelEvidence = !!entry.label && onScreenLabels.has(entry.label.toLowerCase());
470
+ if (!declaresRoute && !idEvidence && !labelEvidence) continue;
471
+ let value;
472
+ try {
473
+ value = String(entry.getValue() ?? "");
474
+ } catch {
475
+ continue;
476
+ }
477
+ snapshot.inputs.push({
478
+ id,
479
+ label: entry.label ?? label,
480
+ value,
481
+ type: fieldType
482
+ });
483
+ present.add(key);
484
+ }
177
485
  }
178
486
  function captureSnapshot() {
179
- const root = chunkSUMIABJK_js.getFiberRoot();
487
+ const root = chunkUZ2D4BVX_js.getFiberRoot();
180
488
  if (!root) {
181
- chunkSUMIABJK_js.appilotsDebugWarn(
489
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
182
490
  "captureSnapshot: fiber root not captured yet. Ensure <AppilotsProvider> has rendered before calling this."
183
491
  );
184
- chunkSUMIABJK_js.recordIntrospectionFailure("never-mounted", null);
492
+ chunkUZ2D4BVX_js.recordIntrospectionFailure("never-mounted", null);
185
493
  return {
186
- route: chunkSUMIABJK_js.getCurrentScreen(),
494
+ route: chunkUZ2D4BVX_js.getCurrentScreen(),
187
495
  texts: [],
188
496
  inputs: [],
189
497
  buttons: [],
@@ -197,9 +505,9 @@ function captureSnapshot() {
197
505
  };
198
506
  }
199
507
  const start = Date.now();
200
- const snapshot = chunkSUMIABJK_js.walkFiber(root);
508
+ const snapshot = chunkUZ2D4BVX_js.walkFiber(root);
201
509
  recordBlindWalk();
202
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
510
+ const activePath = chunkUZ2D4BVX_js.getActiveRouteNames();
203
511
  const deepestRoute = activePath[activePath.length - 1];
204
512
  if (deepestRoute) snapshot.route = deepestRoute;
205
513
  mergeRegisteredLists(snapshot);
@@ -207,15 +515,16 @@ function captureSnapshot() {
207
515
  mergeNativeDialog(snapshot);
208
516
  reconcileSliders(snapshot);
209
517
  canonicalizeRegisteredFields(snapshot);
210
- chunkSUMIABJK_js.clampSnapshotToWireLimits(snapshot);
211
- const entries = chunkSUMIABJK_js.deriveInteractionElements(snapshot, { rectOf: chunkSUMIABJK_js.rectForNode });
518
+ mergeRegisteredFieldValues(snapshot);
519
+ chunkUZ2D4BVX_js.clampSnapshotToWireLimits(snapshot);
520
+ const entries = chunkUZ2D4BVX_js.deriveInteractionElements(snapshot, { rectOf: chunkUZ2D4BVX_js.rectForNode });
212
521
  const rectById = new Map(
213
522
  entries.flatMap((entry) => entry.rect ? [[entry.id, entry.rect]] : [])
214
523
  );
215
- snapshot.elements = entries.map(chunkSUMIABJK_js.toWireElement);
216
- snapshot.choiceGroups = chunkSUMIABJK_js.attachElementIdsToChoiceGroups(snapshot.choiceGroups, snapshot.elements);
217
- chunkSUMIABJK_js.clampSnapshotToWireLimits(snapshot);
218
- chunkSUMIABJK_js.elementRegistry.replaceAll(
524
+ snapshot.elements = entries.map(chunkUZ2D4BVX_js.toWireElement);
525
+ snapshot.choiceGroups = chunkUZ2D4BVX_js.attachElementIdsToChoiceGroups(snapshot.choiceGroups, snapshot.elements);
526
+ chunkUZ2D4BVX_js.clampSnapshotToWireLimits(snapshot);
527
+ chunkUZ2D4BVX_js.elementRegistry.replaceAll(
219
528
  snapshot.elements.map((element) => {
220
529
  const rect = rectById.get(element.id);
221
530
  return rect ? { ...element, rect } : element;
@@ -227,10 +536,10 @@ function captureSnapshot() {
227
536
  (acc, l) => acc + (typeof l.itemCount === "number" ? l.itemCount : 0),
228
537
  0
229
538
  );
230
- chunkSUMIABJK_js.appilotsDebugLog(
539
+ chunkUZ2D4BVX_js.appilotsDebugLog(
231
540
  `captureSnapshot: route="${snapshot.route}" texts=${snapshot.texts.length} inputs=${snapshot.inputs.length} buttons=${snapshot.buttons.length} toggles=${snapshot.toggles.length} sliders=${snapshot.sliders.length} loading=${snapshot.loading} modal=${snapshot.modalOpen} lists=${snapshot.lists.length}(visibleItems=${totalListItems}, dataItems=${totalListDataItems}) choices=${snapshot.choiceGroups.length} elements=${snapshot.elements.length} ` + (snapshot.truncated ? "truncated=true " : "") + `(walked ${snapshot.stats?.visitedFibers ?? 0} fibers, skipped ${snapshot.stats?.skippedHidden ?? 0} hidden, ${elapsed}ms)`
232
541
  );
233
- chunkSUMIABJK_js.appilotsDebugLog(
542
+ chunkUZ2D4BVX_js.appilotsDebugLog(
234
543
  `captureSnapshot detail: lists=[${snapshot.lists.map((l) => `${l.containerType}:${l.id ?? l.label ?? "?"}(rows=${l.items.length})`).join(", ")}] inputs=[${snapshot.inputs.map((i) => i.id ?? i.label ?? "?").slice(0, 12).join(", ")}] buttons=[${snapshot.buttons.map((b) => b.id ?? b.label ?? "?").slice(0, 15).join(", ")}]`
235
544
  );
236
545
  return snapshot;
@@ -241,10 +550,10 @@ function registryCounts() {
241
550
  toggles: 0,
242
551
  sliders: 0,
243
552
  targets: 0,
244
- lists: chunkSUMIABJK_js.listRegistry.snapshot().length,
245
- elements: chunkSUMIABJK_js.elementRegistry.size
553
+ lists: chunkUZ2D4BVX_js.listRegistry.snapshot().length,
554
+ elements: chunkUZ2D4BVX_js.elementRegistry.size
246
555
  };
247
- for (const { kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
556
+ for (const { kind } of chunkUZ2D4BVX_js.componentRegistry.snapshot()) {
248
557
  if (kind === "field") counts.fields++;
249
558
  else if (kind === "toggle") counts.toggles++;
250
559
  else if (kind === "slider") counts.sliders++;
@@ -253,26 +562,26 @@ function registryCounts() {
253
562
  return counts;
254
563
  }
255
564
  function appilotsSelfCheck() {
256
- const root = chunkSUMIABJK_js.getFiberRoot();
565
+ const root = chunkUZ2D4BVX_js.getFiberRoot();
257
566
  const start = Date.now();
258
- if (root) chunkSUMIABJK_js.walkFiber(root);
567
+ if (root) chunkUZ2D4BVX_js.walkFiber(root);
259
568
  const elapsedMs = Date.now() - start;
260
- const walk = chunkSUMIABJK_js.getLastWalkDiagnostics();
569
+ const walk = chunkUZ2D4BVX_js.getLastWalkDiagnostics();
261
570
  return {
262
- sdkVersion: chunkSUMIABJK_js.SDK_VERSION,
571
+ sdkVersion: chunkUZ2D4BVX_js.SDK_VERSION,
263
572
  reactVersion: React__default.default.version ?? null,
264
- route: chunkSUMIABJK_js.getCurrentScreen() || null,
265
- introspection: chunkSUMIABJK_js.getIntrospectionDiagnostics(),
266
- autoTracking: chunkSUMIABJK_js.getAutoTrackingState(),
573
+ route: chunkUZ2D4BVX_js.getCurrentScreen() || null,
574
+ introspection: chunkUZ2D4BVX_js.getIntrospectionDiagnostics(),
575
+ autoTracking: chunkUZ2D4BVX_js.getAutoTrackingState(),
267
576
  walk: {
268
577
  visitedFibers: root ? walk?.visitedFibers ?? 0 : 0,
269
578
  skippedHidden: root ? walk?.skippedHidden ?? 0 : 0,
270
579
  elapsedMs
271
580
  },
272
- detectors: root ? walk?.detectors ?? chunkSUMIABJK_js.emptyDetectorCounts() : chunkSUMIABJK_js.emptyDetectorCounts(),
581
+ detectors: root ? walk?.detectors ?? chunkUZ2D4BVX_js.emptyDetectorCounts() : chunkUZ2D4BVX_js.emptyDetectorCounts(),
273
582
  registry: registryCounts(),
274
- nameMangling: chunkSUMIABJK_js.getNameManglingProbe(),
275
- geometry: { availability: chunkSUMIABJK_js.geometryAvailability(), ...chunkSUMIABJK_js.geometryStats() }
583
+ nameMangling: chunkUZ2D4BVX_js.getNameManglingProbe(),
584
+ geometry: { availability: chunkUZ2D4BVX_js.geometryAvailability(), ...chunkUZ2D4BVX_js.geometryStats() }
276
585
  };
277
586
  }
278
587
 
@@ -285,7 +594,7 @@ function declaredState(props) {
285
594
  return typeof checked === "boolean" ? checked : void 0;
286
595
  }
287
596
  function isReactNativeSwitch(fiber) {
288
- return chunkSUMIABJK_js.getTypeName(fiber?.type) === "Switch" || chunkSUMIABJK_js.getTypeName(fiber?.elementType) === "Switch";
597
+ return chunkUZ2D4BVX_js.getTypeName(fiber?.type) === "Switch" || chunkUZ2D4BVX_js.getTypeName(fiber?.elementType) === "Switch";
289
598
  }
290
599
  var SWITCH_FLIP_HANDLERS = ["onValueChange", "onChange", "onPress"];
291
600
  function flipSwitchFiber(fiber, next) {
@@ -309,6 +618,11 @@ function flipSwitchFiber(fiber, next) {
309
618
  return { ok: true, via: handler.via };
310
619
  }
311
620
 
621
+ // src/introspection/positionalIdentity.ts
622
+ function isPositionalControlId(value) {
623
+ return /^(?:list-\d+-item-\d+-)?(?:btn|input|slider|toggle)-\d+$/i.test(value.trim());
624
+ }
625
+
312
626
  // src/introspection/findInteractive.ts
313
627
  function getTypeName2(type) {
314
628
  if (!type) return null;
@@ -383,7 +697,7 @@ function shouldSkipSubtree2(fiber) {
383
697
  const typeName = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
384
698
  if (typeName && SELF_REFERENTIAL_COMPONENTS.has(typeName)) return true;
385
699
  if (isAppilotsSkipMarked(props)) return true;
386
- if (chunkSUMIABJK_js.isModalFiber(fiber) && props.visible === false) return true;
700
+ if (chunkUZ2D4BVX_js.isModalFiber(fiber) && props.visible === false) return true;
387
701
  if (matchesName(fiber, "Screen") && props.activityState === 0) return true;
388
702
  const style = props.style;
389
703
  if (style) {
@@ -393,9 +707,14 @@ function shouldSkipSubtree2(fiber) {
393
707
  }
394
708
  return false;
395
709
  }
396
- var normalize = chunkSUMIABJK_js.foldForCompare;
710
+ var normalize = chunkUZ2D4BVX_js.foldForCompare;
397
711
  function scoreMatchDetail(fiber, queryNorm, queryRaw) {
398
712
  const props = fiber.memoizedProps ?? {};
713
+ if (chunkUZ2D4BVX_js.isSourceControlId(queryRaw)) {
714
+ const matches = chunkUZ2D4BVX_js.sourceControlId(fiber) === queryRaw;
715
+ const disabled = props.disabled === true || props.accessibilityState?.disabled === true;
716
+ return { score: matches ? disabled ? 60 : 120 : 0, named: matches, disabled };
717
+ }
399
718
  const candidates = [];
400
719
  if (typeof props.testID === "string") candidates.push({ val: props.testID, weight: 100 });
401
720
  if (typeof props.accessibilityLabel === "string")
@@ -414,11 +733,11 @@ function scoreMatchDetail(fiber, queryNorm, queryRaw) {
414
733
  if (!vNorm) continue;
415
734
  if (val === queryRaw) best = Math.max(best, weight + 20);
416
735
  else if (vNorm === queryNorm) best = Math.max(best, weight + 10);
417
- else if (queryNorm && (vNorm.includes(queryNorm) || queryNorm.includes(vNorm)))
736
+ else if (!isPositionalControlId(queryRaw) && queryNorm && (vNorm.includes(queryNorm) || queryNorm.includes(vNorm)))
418
737
  best = Math.max(best, weight - 20);
419
738
  }
420
739
  const named = best >= IDENTITY_MATCH_SCORE;
421
- const disabledProp = props.disabled === true;
740
+ const disabledProp = props.disabled === true || props.editable === false || props.readOnly === true;
422
741
  const disabledA11y = typeof props.accessibilityState === "object" && props.accessibilityState !== null && props.accessibilityState.disabled === true;
423
742
  if (best > 0 && disabledProp) {
424
743
  best = Math.max(1, best - 60);
@@ -428,12 +747,18 @@ function scoreMatchDetail(fiber, queryNorm, queryRaw) {
428
747
  }
429
748
  return { score: best, named, disabled: disabledProp || disabledA11y };
430
749
  }
750
+ var inputIdentities = /* @__PURE__ */ new WeakMap();
431
751
  function wrapTextInput(fiber) {
752
+ const identity = inputIdentities.get(fiber) ?? (fiber.alternate && inputIdentities.get(fiber.alternate)) ?? {};
753
+ inputIdentities.set(fiber, identity);
754
+ if (fiber.alternate) inputIdentities.set(fiber.alternate, identity);
432
755
  const getProps = () => fiber.memoizedProps ?? {};
433
756
  return {
434
757
  kind: "field",
758
+ controlIdentity: identity,
435
759
  label: getProps().accessibilityLabel ?? getProps().label ?? getProps().placeholder ?? getProps().testID,
436
760
  getValue: () => getProps().value,
761
+ finishEditing: () => chunkUZ2D4BVX_js.endTextInputEditing(getProps()),
437
762
  setValue: (value) => {
438
763
  const { onChangeText, onChange } = getProps();
439
764
  if (typeof onChangeText === "function") {
@@ -468,7 +793,7 @@ function wrapSwitch(fiber) {
468
793
  // `accessibilityRole="switch"`) has only the former, and reporting
469
794
  // `false` for a control that is on is worse than reporting nothing:
470
795
  // the caller inverts this to decide where to move.
471
- getValue: () => chunkSUMIABJK_js.switchValue(getProps()),
796
+ getValue: () => chunkUZ2D4BVX_js.switchValue(getProps()),
472
797
  setValue: (value) => {
473
798
  const boolVal = typeof value === "boolean" ? value : value === "true" || value === true;
474
799
  const flipped = flipSwitchFiber(fiber, boolVal);
@@ -514,18 +839,18 @@ function describeCandidate(fiber, kind) {
514
839
  const props = fiber?.memoizedProps ?? {};
515
840
  return props.testID ?? props.accessibilityLabel ?? props.placeholder ?? (kind === "target" ? findChildText(fiber) : void 0);
516
841
  }
517
- function isDescendantOf(fiber, ancestor) {
842
+ function isDescendantOf(fiber, ancestor, parents) {
518
843
  if (!fiber || !ancestor) return false;
519
- let node = fiber.return;
520
- for (let depth = 0; node && depth < 200; depth++, node = node.return) {
844
+ let node = parents.get(fiber);
845
+ for (let depth = 0; node && depth < 200; depth++, node = parents.get(node)) {
521
846
  if (node === ancestor) return true;
522
847
  }
523
848
  return false;
524
849
  }
525
850
  function findInteractiveByIdentifier(query, options = {}) {
526
- const root = chunkSUMIABJK_js.getFiberRoot();
851
+ const root = chunkUZ2D4BVX_js.getFiberRoot();
527
852
  if (!root) {
528
- chunkSUMIABJK_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
853
+ chunkUZ2D4BVX_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
529
854
  return null;
530
855
  }
531
856
  const queryNorm = normalize(query);
@@ -538,18 +863,20 @@ function findInteractiveByIdentifier(query, options = {}) {
538
863
  let bestDisabled = false;
539
864
  let tied = [];
540
865
  const visited = /* @__PURE__ */ new WeakSet();
866
+ const parents = /* @__PURE__ */ new WeakMap();
541
867
  const stack = [];
542
- if (root.child) stack.push(root.child);
868
+ if (root.child) stack.push({ fiber: root.child, parent: root });
543
869
  while (stack.length > 0) {
544
- const fiber = stack.pop();
870
+ const { fiber, parent } = stack.pop();
545
871
  if (!fiber || visited.has(fiber)) continue;
546
872
  visited.add(fiber);
547
- if (fiber.sibling) stack.push(fiber.sibling);
873
+ parents.set(fiber, parent);
874
+ if (fiber.sibling) stack.push({ fiber: fiber.sibling, parent });
548
875
  if (shouldSkipSubtree2(fiber)) continue;
549
876
  const props = fiber.memoizedProps ?? {};
550
877
  let kind = null;
551
878
  if (matchesName(fiber, "TextInput")) kind = "field";
552
- else if (chunkSUMIABJK_js.isSwitchLike(fiber, props)) kind = "toggle";
879
+ else if (chunkUZ2D4BVX_js.isSwitchLike(fiber, props)) kind = "toggle";
553
880
  else if (isPressableTarget(fiber)) kind = "target";
554
881
  if (kind && (!options.kind || options.kind === kind)) {
555
882
  const detail = scoreMatchDetail(fiber, queryNorm, queryRaw);
@@ -558,7 +885,7 @@ function findInteractiveByIdentifier(query, options = {}) {
558
885
  if (score > bestScore) tied = [{ fiber, kind }];
559
886
  else if (score === bestScore) tied.push({ fiber, kind });
560
887
  }
561
- const beatsBest = score > bestScore || score > 0 && score === bestScore && isDescendantOf(fiber, bestFiber);
888
+ const beatsBest = score > bestScore || score > 0 && score === bestScore && isDescendantOf(fiber, bestFiber, parents);
562
889
  if (beatsBest) {
563
890
  bestScore = score;
564
891
  bestFiber = fiber;
@@ -567,14 +894,18 @@ function findInteractiveByIdentifier(query, options = {}) {
567
894
  bestId = describeCandidate(fiber, kind);
568
895
  if (kind === "field") bestHandle = wrapTextInput(fiber);
569
896
  else if (kind === "toggle") bestHandle = wrapSwitch(fiber);
570
- else bestHandle = wrapTouchable(fiber, findChildText(fiber));
897
+ else if (chunkUZ2D4BVX_js.isSourceControlId(queryRaw)) {
898
+ const bound = chunkUZ2D4BVX_js.sourceControlTarget(fiber);
899
+ if (!bound || bound.disabled) bestHandle = null;
900
+ else bestHandle = wrapTouchable(bound.fiber, findChildText(fiber));
901
+ } else bestHandle = wrapTouchable(fiber, findChildText(fiber));
571
902
  }
572
903
  }
573
904
  if (kind === "toggle") continue;
574
- if (fiber.child) stack.push(fiber.child);
905
+ if (fiber.child) stack.push({ fiber: fiber.child, parent: fiber });
575
906
  }
576
907
  if (bestHandle && bestScore < (options.minScore ?? 0)) {
577
- chunkSUMIABJK_js.appilotsDebugLog(
908
+ chunkUZ2D4BVX_js.appilotsDebugLog(
578
909
  `findInteractiveByIdentifier: query="${query}" \u2192 best match scored ${bestScore}, below the requested floor of ${options.minScore} \u2014 refusing it`
579
910
  );
580
911
  return null;
@@ -582,23 +913,138 @@ function findInteractiveByIdentifier(query, options = {}) {
582
913
  if (bestHandle) {
583
914
  const independent = tied.filter(
584
915
  (candidate) => !tied.some(
585
- (other) => other.fiber !== candidate.fiber && isDescendantOf(other.fiber, candidate.fiber)
916
+ (other) => other.fiber !== candidate.fiber && isDescendantOf(other.fiber, candidate.fiber, parents)
586
917
  )
587
918
  );
588
919
  bestHandle.matchCount = independent.length;
589
920
  bestHandle.named = bestNamed;
590
921
  bestHandle.disabled = bestDisabled;
922
+ const measured = bestFiber;
923
+ bestHandle.measure = () => chunkUZ2D4BVX_js.rectOfFiber(measured);
591
924
  const candidates = independent.map(({ fiber, kind }) => describeCandidate(fiber, kind)).filter((id) => typeof id === "string" && id.length > 0).slice(0, 8);
592
925
  if (candidates.length > 0) bestHandle.matchCandidates = candidates;
593
- chunkSUMIABJK_js.appilotsDebugLog(
926
+ chunkUZ2D4BVX_js.appilotsDebugLog(
594
927
  `findInteractiveByIdentifier: query="${query}" \u2192 kind=${bestHandle.kind} label="${bestHandle.label ?? bestId}" score=${bestScore} named=${bestNamed} disabled=${bestDisabled} tied=${independent.length}`
595
928
  );
596
929
  } else {
597
- chunkSUMIABJK_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
930
+ chunkUZ2D4BVX_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
598
931
  }
599
932
  return bestHandle;
600
933
  }
601
934
 
935
+ // src/introspection/spotlightTarget.ts
936
+ var listeners = /* @__PURE__ */ new Set();
937
+ var current = null;
938
+ var seq = 0;
939
+ var expiry = null;
940
+ var SPOTLIGHT_TTL_MS = 1200;
941
+ var mode = "off";
942
+ function setSpotlightMode(next) {
943
+ mode = next;
944
+ }
945
+ function getSpotlightMode() {
946
+ return mode;
947
+ }
948
+ function emit() {
949
+ for (const listener of listeners) listener(current);
950
+ }
951
+ function setSpotlightTarget(rect, label) {
952
+ if (expiry) {
953
+ clearTimeout(expiry);
954
+ expiry = null;
955
+ }
956
+ if (!rect) {
957
+ chunkUZ2D4BVX_js.appilotsDebugLog(
958
+ `setSpotlightTarget: cleared${label ? ` (was about to mark "${label}")` : ""}`
959
+ );
960
+ if (current === null) return;
961
+ current = null;
962
+ emit();
963
+ return;
964
+ }
965
+ current = { rect, label, seq: ++seq };
966
+ chunkUZ2D4BVX_js.appilotsDebugLog(
967
+ `setSpotlightTarget: seq=${current.seq} label="${label ?? ""}" rect=${Math.round(rect.x)},${Math.round(rect.y)} ${Math.round(rect.width)}x${Math.round(rect.height)}`
968
+ );
969
+ emit();
970
+ expiry = setTimeout(() => {
971
+ expiry = null;
972
+ current = null;
973
+ emit();
974
+ }, SPOTLIGHT_TTL_MS);
975
+ }
976
+ function getSpotlightTarget() {
977
+ return current;
978
+ }
979
+ function subscribeSpotlight(listener) {
980
+ listeners.add(listener);
981
+ return () => {
982
+ listeners.delete(listener);
983
+ };
984
+ }
985
+
986
+ // src/introspection/scrollIntoView.ts
987
+ var REVEAL_MARGIN = 24;
988
+ function offsetToReveal({ rect, viewport, metrics }) {
989
+ const maxOffset = Math.max(0, metrics.contentLength - metrics.visibleLength);
990
+ const viewTop = viewport.top + REVEAL_MARGIN;
991
+ const viewBottom = viewport.top + viewport.height - REVEAL_MARGIN;
992
+ const tallerThanViewport = rect.height > viewport.height - REVEAL_MARGIN * 2;
993
+ let delta;
994
+ if (tallerThanViewport) {
995
+ if (rect.y >= viewTop && rect.y <= viewBottom) return null;
996
+ delta = rect.y - viewTop;
997
+ } else if (rect.y < viewTop) {
998
+ delta = rect.y - viewTop;
999
+ } else if (rect.y + rect.height > viewBottom) {
1000
+ delta = rect.y + rect.height - viewBottom;
1001
+ } else {
1002
+ return null;
1003
+ }
1004
+ const target = clamp(metrics.offset + delta, 0, maxOffset);
1005
+ if (Math.abs(target - metrics.offset) < 1) return null;
1006
+ return target;
1007
+ }
1008
+ function clamp(value, min, max) {
1009
+ return Math.min(max, Math.max(min, value));
1010
+ }
1011
+
1012
+ // src/introspection/revealTarget.ts
1013
+ function revealTarget(rect) {
1014
+ const host = chunkUZ2D4BVX_js.getGeometryHost();
1015
+ if (!host) return { rect, scrolled: false };
1016
+ if (chunkUZ2D4BVX_js.isRectOnScreen(rect, host.window)) return { rect, scrolled: false };
1017
+ const scrollable = resolveScrollable();
1018
+ if (!scrollable) return { rect, scrolled: false };
1019
+ const metrics = scrollable.getScrollMetrics?.();
1020
+ if (!metrics) return { rect, scrolled: false };
1021
+ const box = scrollable.measureViewport?.();
1022
+ const viewport = box ? { top: box.y, height: box.height } : { top: 0, height: host.window.height };
1023
+ const target = offsetToReveal({ rect, viewport, metrics });
1024
+ if (target === null) return { rect, scrolled: false };
1025
+ const moved = scrollable.scrollToOffset?.(target) ?? false;
1026
+ if (!moved) {
1027
+ chunkUZ2D4BVX_js.appilotsDebugLog(`revealTarget: "${scrollable.id}" refused scrollToOffset(${target})`);
1028
+ return { rect, scrolled: false };
1029
+ }
1030
+ const delta = target - metrics.offset;
1031
+ chunkUZ2D4BVX_js.appilotsDebugLog(
1032
+ `revealTarget: scrolled "${scrollable.id}" by ${Math.round(delta)}px (${Math.round(metrics.offset)} \u2192 ${Math.round(target)})`
1033
+ );
1034
+ return { rect: { ...rect, y: rect.y - delta }, scrolled: true };
1035
+ }
1036
+ function resolveScrollable() {
1037
+ const screen = chunkUZ2D4BVX_js.getCurrentScreen();
1038
+ const candidates = chunkUZ2D4BVX_js.listRegistry.snapshot().filter((entry) => entry.scrollToOffset && entry.getScrollMetrics).filter((entry) => !screen || !entry.screen || entry.screen === screen);
1039
+ if (candidates.length === 1) return candidates[0];
1040
+ if (candidates.length > 1) {
1041
+ chunkUZ2D4BVX_js.appilotsDebugLog(
1042
+ `revealTarget: ${candidates.length} scrollables on "${screen ?? "?"}" \u2014 cannot tell which holds the target, so not scrolling.`
1043
+ );
1044
+ }
1045
+ return null;
1046
+ }
1047
+
602
1048
  // src/executor/handlers/navigateHandler.ts
603
1049
  var _reportedMissingNavRef = false;
604
1050
  function reportMissingNavigationRef() {
@@ -641,43 +1087,52 @@ function screenExistsAnywhere(state, screenName) {
641
1087
  return false;
642
1088
  }
643
1089
  function safeNavigate(nav, screenName, params, path) {
1090
+ const state = nav.getState?.();
1091
+ const rootState = nav.getRootState?.() ?? state;
644
1092
  if (path && path.length > 0) {
1093
+ if (Array.isArray(rootState?.routeNames) && !screenExistsAnywhere(rootState, path[0]) && !state?.routeNames?.includes(path[0])) {
1094
+ if (state?.routeNames?.includes(screenName)) {
1095
+ nav.navigate(screenName, params);
1096
+ return;
1097
+ }
1098
+ throw new Error(
1099
+ `Route "${path[0]}" is not registered in any navigator. Cannot resolve the supplied path to "${screenName}".`
1100
+ );
1101
+ }
645
1102
  const { root, nestedParams } = buildNestedParams(path, screenName, params);
646
- chunkSUMIABJK_js.appilotsDebugLog(
1103
+ chunkUZ2D4BVX_js.appilotsDebugLog(
647
1104
  `safeNavigate: using path-based navigation \u2014 root="${root}", nested=${JSON.stringify(nestedParams)}`
648
1105
  );
649
1106
  nav.navigate(root, nestedParams);
650
1107
  return;
651
1108
  }
652
- const state = nav.getState?.();
653
1109
  if (state?.routeNames?.includes(screenName)) {
654
1110
  nav.navigate(screenName, params);
655
1111
  return;
656
1112
  }
657
- const rootState = nav.getRootState?.() ?? state;
658
1113
  if (!screenExistsAnywhere(rootState, screenName)) {
659
1114
  throw new Error(
660
1115
  `Screen "${screenName}" is not registered in any navigator. The screen may have been removed, may live inside a flow that is not currently mounted (e.g. Auth stack after login), or the MCP doc is stale.`
661
1116
  );
662
1117
  }
663
- chunkSUMIABJK_js.appilotsDebugLog(
1118
+ chunkUZ2D4BVX_js.appilotsDebugLog(
664
1119
  `safeNavigate: screen exists in nested navigator, attempting direct navigation to "${screenName}"`
665
1120
  );
666
1121
  nav.navigate(screenName, params);
667
1122
  }
668
1123
  function navigateHandler(payload, context) {
669
- chunkSUMIABJK_js.appilotsDebugLog(
1124
+ chunkUZ2D4BVX_js.appilotsDebugLog(
670
1125
  // Params carry record ids and, on some screens, the user's own
671
1126
  // data — the count answers "were params passed?" and nothing else.
672
- `navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${chunkSUMIABJK_js.describeValue(payload.params)}`
1127
+ `navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${chunkUZ2D4BVX_js.describeValue(payload.params)}`
673
1128
  );
674
1129
  const { navigationRef, permissions } = context;
675
1130
  const nav = navigationRef.current;
676
1131
  if (!permissions.canNavigate) {
677
1132
  return {
678
1133
  success: false,
679
- error: "Navigation is not permitted",
680
- diagnose: { category: "unknown", screen: payload.screenName }
1134
+ error: chunkUZ2D4BVX_js.permissionDeniedMessage("Navigation", "canNavigate"),
1135
+ diagnose: { category: "unknown", screen: payload.screenName, recoverable: false }
681
1136
  };
682
1137
  }
683
1138
  const isGoBack = payload.navigationAction === "goBack";
@@ -762,12 +1217,12 @@ function navigateHandler(payload, context) {
762
1217
  diagnose: { category: "unknown", screen: payload.screenName }
763
1218
  };
764
1219
  }
765
- chunkSUMIABJK_js.appilotsDebugLog(
1220
+ chunkUZ2D4BVX_js.appilotsDebugLog(
766
1221
  `navigateHandler: navigation succeeded for "${payload.screenName}" (action="${payload.navigationAction}")`
767
1222
  );
768
1223
  return { success: true };
769
1224
  } catch (err) {
770
- chunkSUMIABJK_js.appilotsDebugWarn(
1225
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
771
1226
  `navigateHandler: navigation failed for "${payload.screenName}": ${err?.message}`
772
1227
  );
773
1228
  const msg = String(err?.message ?? "Navigation failed");
@@ -815,18 +1270,18 @@ function markedItemIndexFromFiber(fiber) {
815
1270
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
816
1271
  }
817
1272
  function normalize2(value) {
818
- return chunkSUMIABJK_js.foldForCompare(String(value ?? ""));
1273
+ return chunkUZ2D4BVX_js.foldForCompare(String(value ?? ""));
819
1274
  }
820
1275
  function hasPressHandler2(fiber) {
821
1276
  const props = fiber?.memoizedProps ?? {};
822
1277
  return typeof props.onPress === "function" || typeof props.onPressIn === "function";
823
1278
  }
824
1279
  function isPressableFiber(fiber) {
825
- const typeName = chunkSUMIABJK_js.getTypeName(fiber.type) ?? chunkSUMIABJK_js.getTypeName(fiber.elementType) ?? "";
826
- return chunkSUMIABJK_js.TOUCHABLE_NAMES.has(typeName) || hasPressHandler2(fiber);
1280
+ const typeName = chunkUZ2D4BVX_js.getTypeName(fiber.type) ?? chunkUZ2D4BVX_js.getTypeName(fiber.elementType) ?? "";
1281
+ return chunkUZ2D4BVX_js.TOUCHABLE_NAMES.has(typeName) || hasPressHandler2(fiber);
827
1282
  }
828
1283
  function findListContainers(options = {}) {
829
- const root = chunkSUMIABJK_js.getFiberRoot();
1284
+ const root = chunkUZ2D4BVX_js.getFiberRoot();
830
1285
  if (!root) return [];
831
1286
  const containers = [];
832
1287
  const visited = /* @__PURE__ */ new WeakSet();
@@ -837,17 +1292,17 @@ function findListContainers(options = {}) {
837
1292
  if (!fiber || visited.has(fiber)) continue;
838
1293
  visited.add(fiber);
839
1294
  if (fiber.sibling) stack.push(fiber.sibling);
840
- if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
841
- if (chunkSUMIABJK_js.isAlwaysListContainer(fiber) || chunkSUMIABJK_js.isHeuristicListContainer(fiber)) {
842
- const minItems = chunkSUMIABJK_js.isAlwaysListContainer(fiber) || options.allowSingleHeuristic ? 1 : 2;
843
- const items = chunkSUMIABJK_js.findListItems(fiber, minItems);
1295
+ if (chunkUZ2D4BVX_js.shouldSkipSubtree(fiber)) continue;
1296
+ if (chunkUZ2D4BVX_js.isAlwaysListContainer(fiber) || chunkUZ2D4BVX_js.isHeuristicListContainer(fiber)) {
1297
+ const minItems = chunkUZ2D4BVX_js.isAlwaysListContainer(fiber) || options.allowSingleHeuristic ? 1 : 2;
1298
+ const items = chunkUZ2D4BVX_js.findListItems(fiber, minItems);
844
1299
  if (items && items.length >= minItems) {
845
1300
  containers.push({
846
1301
  container: fiber,
847
1302
  items,
848
1303
  listId: listIdFromContainer(fiber),
849
1304
  listLabel: listLabelFromContainer(fiber),
850
- containerType: chunkSUMIABJK_js.getTypeName(fiber.type) ?? chunkSUMIABJK_js.getTypeName(fiber.elementType) ?? "List"
1305
+ containerType: chunkUZ2D4BVX_js.getTypeName(fiber.type) ?? chunkUZ2D4BVX_js.getTypeName(fiber.elementType) ?? "List"
851
1306
  });
852
1307
  continue;
853
1308
  }
@@ -866,7 +1321,7 @@ function findFirstTouchable(item) {
866
1321
  const { fiber, includeSibling } = stack.pop();
867
1322
  if (!fiber || visited.has(fiber)) continue;
868
1323
  visited.add(fiber);
869
- if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
1324
+ if (chunkUZ2D4BVX_js.shouldSkipSubtree(fiber)) continue;
870
1325
  if (isPressableFiber(fiber)) {
871
1326
  const props = fiber.memoizedProps ?? {};
872
1327
  if (typeof props.onPress === "function" || typeof props.onPressIn === "function") {
@@ -893,7 +1348,7 @@ function findTouchableFibers(item) {
893
1348
  const { fiber, includeSibling } = stack.pop();
894
1349
  if (!fiber || visited.has(fiber)) continue;
895
1350
  visited.add(fiber);
896
- if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
1351
+ if (chunkUZ2D4BVX_js.shouldSkipSubtree(fiber)) continue;
897
1352
  const props = fiber.memoizedProps ?? {};
898
1353
  if (isPressableFiber(fiber) && (typeof props.onPress === "function" || typeof props.onPressIn === "function")) {
899
1354
  found.push(fiber);
@@ -937,7 +1392,7 @@ function findFirstText(fiber) {
937
1392
  const node = stack.pop();
938
1393
  if (!node || visited.has(node)) continue;
939
1394
  visited.add(node);
940
- const typeName = chunkSUMIABJK_js.getTypeName(node.type) ?? chunkSUMIABJK_js.getTypeName(node.elementType) ?? "";
1395
+ const typeName = chunkUZ2D4BVX_js.getTypeName(node.type) ?? chunkUZ2D4BVX_js.getTypeName(node.elementType) ?? "";
941
1396
  if (typeName === "Text") {
942
1397
  const text = textFromChildren(node.memoizedProps?.children).trim();
943
1398
  if (text) return text;
@@ -956,7 +1411,7 @@ function collectTexts(fiber) {
956
1411
  const node = stack.pop();
957
1412
  if (!node || visited.has(node)) continue;
958
1413
  visited.add(node);
959
- const typeName = chunkSUMIABJK_js.getTypeName(node.type) ?? chunkSUMIABJK_js.getTypeName(node.elementType) ?? "";
1414
+ const typeName = chunkUZ2D4BVX_js.getTypeName(node.type) ?? chunkUZ2D4BVX_js.getTypeName(node.elementType) ?? "";
960
1415
  if (typeName === "Text") {
961
1416
  const text = textFromChildren(node.memoizedProps?.children).trim();
962
1417
  if (text) out.push(text);
@@ -968,10 +1423,10 @@ function collectTexts(fiber) {
968
1423
  }
969
1424
  function hasUsefulTouchableIdentity(fiber) {
970
1425
  const props = fiber?.memoizedProps ?? {};
971
- if (chunkSUMIABJK_js.isReferenceable(props.testID)) return true;
972
- if (chunkSUMIABJK_js.isReferenceable(props.accessibilityLabel)) return true;
973
- if (chunkSUMIABJK_js.isReferenceable(props.label)) return true;
974
- return chunkSUMIABJK_js.isReferenceable(findFirstText(fiber));
1426
+ if (chunkUZ2D4BVX_js.isReferenceable(props.testID)) return true;
1427
+ if (chunkUZ2D4BVX_js.isReferenceable(props.accessibilityLabel)) return true;
1428
+ if (chunkUZ2D4BVX_js.isReferenceable(props.label)) return true;
1429
+ return chunkUZ2D4BVX_js.isReferenceable(findFirstText(fiber));
975
1430
  }
976
1431
  function describeTouchable(fiber) {
977
1432
  const props = fiber?.memoizedProps ?? {};
@@ -982,10 +1437,10 @@ function describeTouchable(fiber) {
982
1437
  }
983
1438
  function touchableLooksDestructive(fiber) {
984
1439
  const descriptor = describeTouchable(fiber);
985
- if (descriptor && chunkSUMIABJK_js.looksDestructiveActionLabel(descriptor)) return true;
1440
+ if (descriptor && chunkUZ2D4BVX_js.looksDestructiveActionLabel(descriptor)) return true;
986
1441
  const props = fiber?.memoizedProps ?? {};
987
1442
  const haystack = [props.testID, props.accessibilityLabel, props.accessibilityHint, props.label].filter((value) => typeof value === "string").join(" ");
988
- return chunkSUMIABJK_js.looksDestructiveActionLabel(haystack);
1443
+ return chunkUZ2D4BVX_js.looksDestructiveActionLabel(haystack);
989
1444
  }
990
1445
  function describeItemCandidate(listIndex, zeroBasedIndex, item) {
991
1446
  const syntheticId = `list-${listIndex}-item-${zeroBasedIndex + 1}`;
@@ -1034,8 +1489,10 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
1034
1489
  (candidate) => candidate !== touchable && containsFiber(touchable, candidate)
1035
1490
  );
1036
1491
  if (primaryWrapsNestedTargets) {
1037
- chunkSUMIABJK_js.appilotsDebugLog(
1038
- `listItemDispatch: item "list-${listIndex}-item-${itemIndex}" has nested pressables; pressing outer row target`
1492
+ const outer = describeTouchable(touchable) ?? "?";
1493
+ const nested = safeIdentifiableTouchables.filter((candidate) => candidate !== touchable && containsFiber(touchable, candidate)).map((candidate) => describeTouchable(candidate) ?? "?").slice(0, 6);
1494
+ chunkUZ2D4BVX_js.appilotsDebugLog(
1495
+ `listItemDispatch: item "list-${listIndex}-item-${itemIndex}" has nested pressables; pressing outer row target [outer=${outer}] [nested=${nested.join(", ")}] [outerHasOnPress=${typeof touchable?.memoizedProps?.onPress === "function"}]`
1039
1496
  );
1040
1497
  } else {
1041
1498
  const candidates = safeIdentifiableTouchables.map(describeTouchable).filter((d) => !!d).slice(0, 8);
@@ -1069,14 +1526,14 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
1069
1526
  }
1070
1527
  return {
1071
1528
  ok: true,
1072
- containerType: chunkSUMIABJK_js.getTypeName(container.type) ?? chunkSUMIABJK_js.getTypeName(container.elementType) ?? list.containerType
1529
+ containerType: chunkUZ2D4BVX_js.getTypeName(container.type) ?? chunkUZ2D4BVX_js.getTypeName(container.elementType) ?? list.containerType
1073
1530
  };
1074
1531
  } catch (err) {
1075
1532
  return {
1076
1533
  ok: false,
1077
1534
  reason: "press-threw",
1078
1535
  error: err?.message ?? "press handler threw",
1079
- containerType: chunkSUMIABJK_js.getTypeName(container.type) ?? chunkSUMIABJK_js.getTypeName(container.elementType) ?? list.containerType
1536
+ containerType: chunkUZ2D4BVX_js.getTypeName(container.type) ?? chunkUZ2D4BVX_js.getTypeName(container.elementType) ?? list.containerType
1080
1537
  };
1081
1538
  }
1082
1539
  }
@@ -1102,10 +1559,12 @@ function scoreItemCandidate(item, zeroBasedIndex, locator) {
1102
1559
  if (locator.itemKey) {
1103
1560
  if (itemKey === locator.itemKey) score += 1e3;
1104
1561
  else if (itemKey && normalize2(itemKey) === normalize2(locator.itemKey)) score += 950;
1562
+ else return 0;
1105
1563
  }
1106
1564
  if (locator.reactKey) {
1107
1565
  if (reactKey === locator.reactKey) score += 900;
1108
1566
  else if (reactKey && normalize2(reactKey) === normalize2(locator.reactKey)) score += 850;
1567
+ else if (!locator.itemKey) return 0;
1109
1568
  }
1110
1569
  if (locator.itemIndex && zeroBasedIndex === locator.itemIndex - 1) score += 750;
1111
1570
  if (locator.itemIndex && markedIndex !== void 0 && (markedIndex === locator.itemIndex || markedIndex === locator.itemIndex - 1)) {
@@ -1132,7 +1591,7 @@ function candidateLists(containers, locator) {
1132
1591
  return containers.map((list, listIndex) => ({ list, listIndex }));
1133
1592
  }
1134
1593
  function pressListItemAtOrdinal(listIndex, itemIndex) {
1135
- if (!chunkSUMIABJK_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
1594
+ if (!chunkUZ2D4BVX_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
1136
1595
  const containers = findListContainers({ allowSingleHeuristic: true });
1137
1596
  if (listIndex < 0 || listIndex >= containers.length) {
1138
1597
  return { ok: false, reason: "list-not-found" };
@@ -1146,7 +1605,7 @@ function pressListItemAtOrdinal(listIndex, itemIndex) {
1146
1605
  return pressResolvedListItem(list, items[zeroBased], listIndex, itemIndex);
1147
1606
  }
1148
1607
  function resolveListItemByIdentity(locator) {
1149
- if (!chunkSUMIABJK_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
1608
+ if (!chunkUZ2D4BVX_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
1150
1609
  const parsed = locator.syntheticId ? parseSyntheticListItemId(locator.syntheticId) : null;
1151
1610
  const effective = parsed ? { ...locator, listIndex: parsed.listIndex, itemIndex: parsed.itemIndex } : locator;
1152
1611
  const containers = findListContainers({ allowSingleHeuristic: true });
@@ -1175,7 +1634,7 @@ function resolveListItemByIdentity(locator) {
1175
1634
  scoredCandidates.sort((a, b) => b.score - a.score);
1176
1635
  const best = scoredCandidates[0];
1177
1636
  const tiedCandidates = scoredCandidates.filter((c) => c.score === best.score);
1178
- if (tiedCandidates.length > 1 && best.score < 750) {
1637
+ if (tiedCandidates.length > 1 && (best.score < 750 || Boolean(effective.itemKey || effective.reactKey))) {
1179
1638
  const candidates = tiedCandidates.map((c) => describeItemCandidate(c.listIndex, c.itemIndex - 1, c.item)).slice(0, 8);
1180
1639
  return {
1181
1640
  ok: false,
@@ -1207,9 +1666,9 @@ function findSwitchFibers(item) {
1207
1666
  const { fiber, includeSibling } = stack.pop();
1208
1667
  if (!fiber || visited.has(fiber)) continue;
1209
1668
  visited.add(fiber);
1210
- if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
1669
+ if (chunkUZ2D4BVX_js.shouldSkipSubtree(fiber)) continue;
1211
1670
  const props = fiber.memoizedProps ?? {};
1212
- if (chunkSUMIABJK_js.isSwitchLike(fiber, props)) {
1671
+ if (chunkUZ2D4BVX_js.isSwitchLike(fiber, props)) {
1213
1672
  if (props.__appilotsInternal !== true) found.push(fiber);
1214
1673
  if (includeSibling && fiber.sibling) {
1215
1674
  stack.push({ fiber: fiber.sibling, includeSibling: true });
@@ -1243,11 +1702,11 @@ function toggleListItemByIdentity(locator, options) {
1243
1702
  }
1244
1703
  const target = switches[0];
1245
1704
  const props = target?.memoizedProps ?? {};
1246
- const current = chunkSUMIABJK_js.switchValue(props);
1247
- if (options?.expected !== void 0 && current === options.expected) {
1248
- return { ok: true, containerType: list.containerType, value: current, noop: true };
1705
+ const current2 = chunkUZ2D4BVX_js.switchValue(props);
1706
+ if (options?.expected !== void 0 && current2 === options.expected) {
1707
+ return { ok: true, containerType: list.containerType, value: current2, noop: true };
1249
1708
  }
1250
- const flipped = flipSwitchFiber(target, !current);
1709
+ const flipped = flipSwitchFiber(target, !current2);
1251
1710
  if (!flipped.ok) {
1252
1711
  if (flipped.reason === "no-handler") {
1253
1712
  return {
@@ -1264,7 +1723,7 @@ function toggleListItemByIdentity(locator, options) {
1264
1723
  containerType: list.containerType
1265
1724
  };
1266
1725
  }
1267
- return { ok: true, containerType: list.containerType, value: !current };
1726
+ return { ok: true, containerType: list.containerType, value: !current2 };
1268
1727
  }
1269
1728
  function pressListItemByIdentity(locator) {
1270
1729
  const resolved = resolveListItemByIdentity(locator);
@@ -1282,7 +1741,7 @@ function screenDiagnose(targetId, category = "component-not-found") {
1282
1741
  return {
1283
1742
  category,
1284
1743
  targetId,
1285
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0
1744
+ screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0
1286
1745
  };
1287
1746
  }
1288
1747
  function isPressLike(action) {
@@ -1302,10 +1761,10 @@ function elementLookupKey(value) {
1302
1761
  return canonicalElementId(value).toLowerCase().replace(/[\s_]+/g, "-");
1303
1762
  }
1304
1763
  function findRegisteredElement(elementId) {
1305
- const direct = chunkSUMIABJK_js.elementRegistry.get(elementId) ?? chunkSUMIABJK_js.elementRegistry.get(canonicalElementId(elementId));
1764
+ const direct = chunkUZ2D4BVX_js.elementRegistry.get(elementId) ?? chunkUZ2D4BVX_js.elementRegistry.get(canonicalElementId(elementId));
1306
1765
  if (direct) return direct;
1307
1766
  const wanted = elementLookupKey(elementId);
1308
- return chunkSUMIABJK_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
1767
+ return chunkUZ2D4BVX_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
1309
1768
  }
1310
1769
  function resolveInteractionElement(elementId) {
1311
1770
  return getLatestElement(elementId);
@@ -1425,7 +1884,7 @@ function dispatchIdentifiedToggle(targetId, action) {
1425
1884
  diagnose: { ...screenDiagnose(targetId, "unknown"), recoverable: true }
1426
1885
  };
1427
1886
  }
1428
- chunkSUMIABJK_js.appilotsDebugLog(
1887
+ chunkUZ2D4BVX_js.appilotsDebugLog(
1429
1888
  `elementDispatch: "${action}" on "${targetId}" names a switch \u2014 flipping it instead of pressing, so the verb cannot land on an ancestor`
1430
1889
  );
1431
1890
  try {
@@ -1459,6 +1918,12 @@ function dispatchFiberTarget(targetId, action) {
1459
1918
  diagnose: screenDiagnose(targetId)
1460
1919
  };
1461
1920
  }
1921
+ const measured = handle.measure?.() ?? null;
1922
+ if (measured && getSpotlightMode() === "guided") {
1923
+ setSpotlightTarget(revealTarget(measured).rect, handle.label);
1924
+ } else {
1925
+ setSpotlightTarget(measured, handle.label);
1926
+ }
1462
1927
  try {
1463
1928
  if (isPressLike(action) && handle.kind === "target" && handle.press) {
1464
1929
  handle.press();
@@ -1509,6 +1974,13 @@ function dispatchLegacyTarget(targetId, registry, action) {
1509
1974
  };
1510
1975
  }
1511
1976
  function dispatchElement(element, registry, action) {
1977
+ if (element.dispatchable === false) {
1978
+ return {
1979
+ success: false,
1980
+ error: `Element "${element.id}" is observation-only and has no exact live control binding.`,
1981
+ diagnose: { ...screenDiagnose(element.id, "ambiguous-target"), recoverable: false }
1982
+ };
1983
+ }
1512
1984
  if (element.disabled === true) {
1513
1985
  return {
1514
1986
  success: false,
@@ -1527,6 +1999,13 @@ function dispatchElement(element, registry, action) {
1527
1999
  texts: element.texts
1528
2000
  });
1529
2001
  if (pressed.ok) return { success: true };
2002
+ if (!pressed.refusal && (element.listContext.itemKey || element.listContext.reactKey)) {
2003
+ return {
2004
+ success: false,
2005
+ error: pressed.error ?? `The observed list entity "${element.label ?? element.id}" could not be resolved. Reobserve; do not substitute its old position.`,
2006
+ diagnose: { ...screenDiagnose(element.id, "ambiguous-target"), recoverable: true }
2007
+ };
2008
+ }
1530
2009
  if (pressed.refusal) {
1531
2010
  return {
1532
2011
  success: false,
@@ -1634,7 +2113,7 @@ function dispatchToggleElement(element, registry) {
1634
2113
  }
1635
2114
  function dispatchStructuredElementId(identifier, action) {
1636
2115
  if (!isElementIdentifier(identifier) || !isPressLike(action)) return null;
1637
- const parsed = chunkSUMIABJK_js.parseStableElementId(identifier);
2116
+ const parsed = chunkUZ2D4BVX_js.parseStableElementId(identifier);
1638
2117
  if (!parsed || parsed.role !== "option") return null;
1639
2118
  if (!parsed.itemKey && !parsed.listId) return null;
1640
2119
  const pressed = pressListItemByIdentity({
@@ -1644,7 +2123,7 @@ function dispatchStructuredElementId(identifier, action) {
1644
2123
  texts: parsed.itemKey ? [parsed.itemKey] : void 0
1645
2124
  });
1646
2125
  if (pressed.ok) {
1647
- chunkSUMIABJK_js.appilotsDebugLog(
2126
+ chunkUZ2D4BVX_js.appilotsDebugLog(
1648
2127
  `elementDispatch: resolved stale el id "${identifier}" via structural identity (listId="${parsed.listId}", itemKey="${parsed.itemKey}")`
1649
2128
  );
1650
2129
  return { success: true };
@@ -1675,20 +2154,20 @@ function normalize4(value) {
1675
2154
  return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
1676
2155
  }
1677
2156
  function resolveScreenForFormFields() {
1678
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
2157
+ const activePath = chunkUZ2D4BVX_js.getActiveRouteNames();
1679
2158
  for (let i = activePath.length - 1; i >= 0; i--) {
1680
2159
  const name = activePath[i];
1681
- const meta = name ? chunkSUMIABJK_js.getScreenMetadata(name) : void 0;
2160
+ const meta = name ? chunkUZ2D4BVX_js.getScreenMetadata(name) : void 0;
1682
2161
  if (name && Array.isArray(meta?.fields) && meta.fields.length > 0) return name;
1683
2162
  }
1684
- return chunkSUMIABJK_js.getCurrentScreen();
2163
+ return chunkUZ2D4BVX_js.getCurrentScreen();
1685
2164
  }
1686
2165
  function collectKnownFormFields(registry) {
1687
2166
  const registryFields = registry.snapshot().filter((entry) => entry.kind === "field" || entry.kind === "slider").map((entry) => ({ id: entry.id, label: entry.label }));
1688
2167
  if (registryFields.length >= 2) return registryFields;
1689
2168
  const screen = resolveScreenForFormFields();
1690
2169
  if (screen) {
1691
- const metaFields = chunkSUMIABJK_js.getScreenMetadata(screen)?.fields;
2170
+ const metaFields = chunkUZ2D4BVX_js.getScreenMetadata(screen)?.fields;
1692
2171
  if (Array.isArray(metaFields) && metaFields.length > 0) {
1693
2172
  return metaFields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
1694
2173
  id: field.id,
@@ -1698,7 +2177,7 @@ function collectKnownFormFields(registry) {
1698
2177
  }));
1699
2178
  }
1700
2179
  }
1701
- for (const meta of chunkSUMIABJK_js.getAllScreens()) {
2180
+ for (const meta of chunkUZ2D4BVX_js.getAllScreens()) {
1702
2181
  if (Array.isArray(meta.fields) && meta.fields.length > 0) {
1703
2182
  return meta.fields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
1704
2183
  id: field.id,
@@ -1811,7 +2290,7 @@ function rewriteMisplacedFormFillFields(fields, registry) {
1811
2290
  const inferred = inferFieldIdForValue(String(field.value ?? ""), knownFields, used);
1812
2291
  if (!inferred) return field;
1813
2292
  used.add(inferred);
1814
- chunkSUMIABJK_js.appilotsDebugWarn(
2293
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
1815
2294
  `formFieldRewrite: ${field.fieldId} \u2192 ${inferred} (value=${JSON.stringify(field.value)})`
1816
2295
  );
1817
2296
  return { ...field, fieldId: inferred };
@@ -1819,8 +2298,8 @@ function rewriteMisplacedFormFillFields(fields, registry) {
1819
2298
  }
1820
2299
 
1821
2300
  // src/executor/formValidation.ts
1822
- var FORM_VALIDATION_TEXT_RE2 = chunkSUMIABJK_js.FORM_VALIDATION_TEXT_RE;
1823
- var FORM_SUCCESS_TEXT_RE = chunkSUMIABJK_js.FORM_WRITE_SUCCESS_TEXT_RE;
2301
+ var FORM_VALIDATION_TEXT_RE2 = chunkUZ2D4BVX_js.FORM_VALIDATION_TEXT_RE;
2302
+ var FORM_SUCCESS_TEXT_RE = chunkUZ2D4BVX_js.FORM_WRITE_SUCCESS_TEXT_RE;
1824
2303
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1825
2304
  function inferValidationFieldId(message, inputs) {
1826
2305
  const haystack = normalizeText(message);
@@ -1844,12 +2323,18 @@ function normalizeText(value) {
1844
2323
  function containsWord(haystack, needle) {
1845
2324
  return ` ${haystack} `.includes(` ${needle} `);
1846
2325
  }
1847
- function readVisibleFormValidation(snap) {
2326
+ function readVisibleFormValidation(snap, beforeTexts) {
1848
2327
  if (!snap) return void 0;
2328
+ const invalid = snap.inputs?.find((input) => input.invalid === true);
2329
+ const hasSubmitControl = snap.buttons?.some(
2330
+ (button) => chunkUZ2D4BVX_js.SUBMIT_CONTROL_RE.test(button.label ?? button.id ?? "")
2331
+ );
1849
2332
  for (const text of snap.texts ?? []) {
1850
- if (!text?.trim() || !FORM_VALIDATION_TEXT_RE2.test(text)) continue;
2333
+ if (!text?.trim() || !chunkUZ2D4BVX_js.isVisibleValidationText(text, { invalid: !!invalid, hasSubmitControl, beforeTexts }))
2334
+ continue;
1851
2335
  return { fieldId: inferValidationFieldId(text, snap.inputs), message: text };
1852
2336
  }
2337
+ if (invalid) return { fieldId: invalid.id, message: "The app marks this field as invalid." };
1853
2338
  return void 0;
1854
2339
  }
1855
2340
  function readVisibleFormSuccess(snap) {
@@ -1857,20 +2342,23 @@ function readVisibleFormSuccess(snap) {
1857
2342
  return (snap.texts ?? []).find((text) => text?.trim() && FORM_SUCCESS_TEXT_RE.test(text));
1858
2343
  }
1859
2344
  function submitAsyncStillPending(submitTargetId) {
1860
- const probe = chunkSUMIABJK_js.probeLoadingState(submitTargetId ?? null, chunkSUMIABJK_js.getCurrentScreen());
2345
+ const probe = chunkUZ2D4BVX_js.probeLoadingState(submitTargetId ?? null, chunkUZ2D4BVX_js.getCurrentScreen());
1861
2346
  if (probe.loading) return true;
1862
2347
  if (submitTargetId && probe.pressedFound && probe.pressedDisabled) return true;
1863
2348
  return false;
1864
2349
  }
1865
- function evaluatePostSubmitSnapshot(snap, activePath) {
1866
- const validation = readVisibleFormValidation(snap);
2350
+ function evaluatePostSubmitSnapshot(snap, activePath, beforeTexts) {
2351
+ const validation = readVisibleFormValidation(snap, beforeTexts);
1867
2352
  if (validation) {
1868
2353
  return { status: "failure", fieldId: validation.fieldId, message: validation.message };
1869
2354
  }
1870
2355
  const successText = readVisibleFormSuccess(snap);
1871
2356
  if (successText) return { status: "success", message: successText };
1872
- if (!chunkSUMIABJK_js.snapshotShowsOpenCreateForm(snap, activePath)) {
1873
- return { status: "success" };
2357
+ if (!chunkUZ2D4BVX_js.snapshotShowsOpenCreateForm(snap, activePath)) {
2358
+ return {
2359
+ status: "unverified",
2360
+ message: "The form closed without a visible success receipt. Inspect the resulting record before claiming the goal is complete."
2361
+ };
1874
2362
  }
1875
2363
  return void 0;
1876
2364
  }
@@ -1885,8 +2373,8 @@ async function waitForPostSubmitOutcome(options) {
1885
2373
  continue;
1886
2374
  }
1887
2375
  const snap2 = captureSnapshot();
1888
- const activePath2 = chunkSUMIABJK_js.getActiveRouteNames();
1889
- const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2);
2376
+ const activePath2 = chunkUZ2D4BVX_js.getActiveRouteNames();
2377
+ const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2, options?.beforeTexts);
1890
2378
  if (outcome2) return outcome2;
1891
2379
  await sleep(pollMs);
1892
2380
  }
@@ -1897,8 +2385,8 @@ async function waitForPostSubmitOutcome(options) {
1897
2385
  };
1898
2386
  }
1899
2387
  const snap = captureSnapshot();
1900
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
1901
- const outcome = evaluatePostSubmitSnapshot(snap, activePath);
2388
+ const activePath = chunkUZ2D4BVX_js.getActiveRouteNames();
2389
+ const outcome = evaluatePostSubmitSnapshot(snap, activePath, options?.beforeTexts);
1902
2390
  if (outcome) return outcome;
1903
2391
  return {
1904
2392
  status: "failure",
@@ -1906,91 +2394,6 @@ async function waitForPostSubmitOutcome(options) {
1906
2394
  };
1907
2395
  }
1908
2396
 
1909
- // ../shared/dist/chunk-ERITSWKE.mjs
1910
- var DEFAULT_FUZZY_FLOOR = 4;
1911
- function normalizeId(value) {
1912
- return String(value ?? "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]/g, "");
1913
- }
1914
- var KIND_PREFIX_WORDS = "button|switch|toggle|input|field|link|btn|slider";
1915
- var KEBAB_SNAKE_PREFIX_RE = new RegExp(`^(?:${KIND_PREFIX_WORDS})[-_]`, "i");
1916
- var CAMEL_PREFIX_RE = new RegExp(`^(?:${KIND_PREFIX_WORDS})(?=[A-Z])`, "");
1917
- function stripKindPrefix(id) {
1918
- const raw = String(id ?? "");
1919
- if (KEBAB_SNAKE_PREFIX_RE.test(raw)) return raw.replace(KEBAB_SNAKE_PREFIX_RE, "");
1920
- if (CAMEL_PREFIX_RE.test(raw)) return raw.replace(CAMEL_PREFIX_RE, "");
1921
- return raw;
1922
- }
1923
- function actionAllowsKind(action, kind) {
1924
- if (!action || !kind) return true;
1925
- switch (action) {
1926
- case "press":
1927
- case "longPress":
1928
- return kind !== "field" && kind !== "input" && kind !== "slider";
1929
- case "set_value":
1930
- return kind === "slider" || kind === "field" || kind === "input";
1931
- case "focus":
1932
- return kind === "field" || kind === "input";
1933
- case "toggle":
1934
- return kind === "toggle";
1935
- default:
1936
- return true;
1937
- }
1938
- }
1939
- function distinctIds(candidates) {
1940
- return [...new Set(candidates.map((c) => c.id))];
1941
- }
1942
- function resolveTarget(requested, candidates, opts = {}) {
1943
- const floor = opts.fuzzyFloor ?? DEFAULT_FUZZY_FLOOR;
1944
- const nReq = normalizeId(requested);
1945
- if (!nReq || candidates.length === 0) {
1946
- return { status: "unverified", reason: "not-found" };
1947
- }
1948
- for (const c of candidates) {
1949
- if (normalizeId(c.id) === nReq) {
1950
- return { status: "matched", id: c.id, tier: "exact" };
1951
- }
1952
- }
1953
- const labelExact = distinctIds(
1954
- candidates.filter((c) => c.label && normalizeId(c.label) === nReq)
1955
- );
1956
- if (labelExact.length === 1) return { status: "matched", id: labelExact[0], tier: "exact" };
1957
- if (labelExact.length > 1) return { status: "unverified", reason: "ambiguous" };
1958
- const nReqStripped = normalizeId(stripKindPrefix(requested));
1959
- for (const c of candidates) {
1960
- const nId = normalizeId(c.id);
1961
- const nIdStripped = normalizeId(stripKindPrefix(c.id));
1962
- if (nReqStripped && (nReqStripped === nId || nReqStripped === nIdStripped) || nIdStripped && nIdStripped === nReq) {
1963
- return { status: "matched", id: c.id, tier: "prefix" };
1964
- }
1965
- }
1966
- if (opts.destructive) {
1967
- return { status: "unverified", reason: "destructive-inexact" };
1968
- }
1969
- if (nReq.length < floor) {
1970
- return { status: "unverified", reason: "not-found" };
1971
- }
1972
- const fuzzy = candidates.filter((c) => {
1973
- for (const s of [c.id, c.label]) {
1974
- if (!s) continue;
1975
- const ns = normalizeId(s);
1976
- if (ns.length >= floor && (ns.includes(nReq) || nReq.includes(ns))) return true;
1977
- }
1978
- return false;
1979
- });
1980
- if (fuzzy.length === 0) {
1981
- return { status: "unverified", reason: "not-found" };
1982
- }
1983
- const typed = fuzzy.filter((c) => actionAllowsKind(opts.action, c.kind));
1984
- if (typed.length === 0) {
1985
- return { status: "unverified", reason: "type-mismatch" };
1986
- }
1987
- const ids = distinctIds(typed);
1988
- if (ids.length > 1) {
1989
- return { status: "unverified", reason: "ambiguous" };
1990
- }
1991
- return { status: "matched", id: ids[0], tier: "fuzzy" };
1992
- }
1993
-
1994
2397
  // src/executor/handlers/uiInteractionHandler.ts
1995
2398
  function findSnapshotButton(targetId) {
1996
2399
  try {
@@ -2003,16 +2406,16 @@ function findSnapshotButton(targetId) {
2003
2406
  }
2004
2407
  }
2005
2408
  function buildUiDiagnose(targetId, cause) {
2006
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
2007
- const screen = activePath[activePath.length - 1] ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
2409
+ const activePath = chunkUZ2D4BVX_js.getActiveRouteNames();
2410
+ const screen = activePath[activePath.length - 1] ?? chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0;
2008
2411
  const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
2009
2412
  const diagnose = {
2010
2413
  category: cause === "not-found" ? "component-not-found" : cause === "disabled" ? "disabled" : "unknown",
2011
2414
  targetId,
2012
2415
  screen: screenPath
2013
2416
  };
2014
- if (chunkSUMIABJK_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
2015
- diagnose.visibleMessage = chunkSUMIABJK_js.OPTIONAL_STEP_AUTOMATION_HINT;
2417
+ if (chunkUZ2D4BVX_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
2418
+ diagnose.visibleMessage = chunkUZ2D4BVX_js.OPTIONAL_STEP_AUTOMATION_HINT;
2016
2419
  diagnose.recoverable = true;
2017
2420
  }
2018
2421
  return diagnose;
@@ -2063,6 +2466,7 @@ function stripComponentPrefix(componentId) {
2063
2466
  return null;
2064
2467
  }
2065
2468
  function resolveComponentId(componentId, registry, action) {
2469
+ if (chunkUZ2D4BVX_js.isSourceControlId(componentId)) return componentId;
2066
2470
  if (registry.getTarget(componentId) || registry.getToggle(componentId) || registry.getField(componentId) || registry.getSlider(componentId)) {
2067
2471
  return componentId;
2068
2472
  }
@@ -2070,15 +2474,16 @@ function resolveComponentId(componentId, registry, action) {
2070
2474
  const snapshot = registry.snapshot();
2071
2475
  for (const comp of snapshot) {
2072
2476
  if (comp.id.toLowerCase() === lower) {
2073
- chunkSUMIABJK_js.appilotsDebugLog(
2477
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2074
2478
  `resolveComponentId: case-insensitive match "${componentId}" \u2192 "${comp.id}"`
2075
2479
  );
2076
2480
  return comp.id;
2077
2481
  }
2078
2482
  }
2079
- const currentScreen = chunkSUMIABJK_js.getCurrentScreen();
2483
+ if (isPositionalControlId(componentId)) return componentId;
2484
+ const currentScreen = chunkUZ2D4BVX_js.getCurrentScreen();
2080
2485
  if (currentScreen) {
2081
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(currentScreen);
2486
+ const screenMeta = chunkUZ2D4BVX_js.getScreenMetadata(currentScreen);
2082
2487
  const actions = screenMeta?.actions;
2083
2488
  if (actions && Array.isArray(actions)) {
2084
2489
  const metaAction = actions.find(
@@ -2087,14 +2492,14 @@ function resolveComponentId(componentId, registry, action) {
2087
2492
  if (metaAction && typeof metaAction === "object" && metaAction.label) {
2088
2493
  const metaLabel = metaAction.label;
2089
2494
  const normalizedMetaLabel = metaLabel.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
2090
- chunkSUMIABJK_js.appilotsDebugLog(
2495
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2091
2496
  `resolveComponentId: found screen metadata for "${componentId}" \u2192 label="${metaLabel}"`
2092
2497
  );
2093
2498
  for (const comp of snapshot) {
2094
2499
  if (!comp.label) continue;
2095
2500
  const compLabel = comp.label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
2096
2501
  if (compLabel === normalizedMetaLabel || compLabel.includes(normalizedMetaLabel) || normalizedMetaLabel.includes(compLabel)) {
2097
- chunkSUMIABJK_js.appilotsDebugLog(
2502
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2098
2503
  `resolveComponentId: FOUND via metadata: "${componentId}" \u2192 "${comp.id}" (label="${comp.label}")`
2099
2504
  );
2100
2505
  return comp.id;
@@ -2109,9 +2514,9 @@ function resolveComponentId(componentId, registry, action) {
2109
2514
  label: c.label,
2110
2515
  kind: c.kind
2111
2516
  }));
2112
- const match = resolveTarget(componentId, candidates, { action });
2517
+ const match = chunkUZ2D4BVX_js.resolveTarget(componentId, candidates, { action });
2113
2518
  if (match.status === "matched") {
2114
- chunkSUMIABJK_js.appilotsDebugLog(
2519
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2115
2520
  `resolveComponentId: matched "${componentId}" -> "${match.id}" (tier=${match.tier})`
2116
2521
  );
2117
2522
  return match.id;
@@ -2201,7 +2606,7 @@ function setValueHandler(rawComponentId, requested, registry) {
2201
2606
  try {
2202
2607
  slider.setValue(applied);
2203
2608
  if (applied !== requestedValue) {
2204
- chunkSUMIABJK_js.appilotsDebugLog(
2609
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2205
2610
  `uiInteractionHandler: set_value snapped ${requestedValue} \u2192 ${applied} for "${componentId}" (step=${step})`
2206
2611
  );
2207
2612
  }
@@ -2236,7 +2641,7 @@ function checkModalOcclusion(rawComponentId, action) {
2236
2641
  return null;
2237
2642
  }
2238
2643
  if (typeof rawComponentId !== "string" || rawComponentId.trim().length === 0) return null;
2239
- const dialog = chunkSUMIABJK_js.getOpenNativeDialog();
2644
+ const dialog = chunkUZ2D4BVX_js.getOpenNativeDialog();
2240
2645
  if (dialog) {
2241
2646
  const needle = normalizeIdent(rawComponentId);
2242
2647
  if (dialog.buttons.some((b) => normalizeIdent(b.label) === needle)) return null;
@@ -2246,16 +2651,16 @@ function checkModalOcclusion(rawComponentId, action) {
2246
2651
  diagnose: {
2247
2652
  category: "ambiguous-target",
2248
2653
  targetId: rawComponentId,
2249
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
2654
+ screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0,
2250
2655
  candidates: dialog.buttons.map((b) => b.label).slice(0, 8)
2251
2656
  }
2252
2657
  };
2253
2658
  }
2254
- const fiberRoot = chunkSUMIABJK_js.getFiberRoot();
2659
+ const fiberRoot = chunkUZ2D4BVX_js.getFiberRoot();
2255
2660
  if (!fiberRoot) return null;
2256
2661
  let snap;
2257
2662
  try {
2258
- snap = chunkSUMIABJK_js.walkFiber(fiberRoot);
2663
+ snap = chunkUZ2D4BVX_js.walkFiber(fiberRoot);
2259
2664
  } catch {
2260
2665
  return null;
2261
2666
  }
@@ -2317,15 +2722,18 @@ function checkModalOcclusion(rawComponentId, action) {
2317
2722
  }
2318
2723
  function uiInteractionHandler(payload, context) {
2319
2724
  const { permissions } = context;
2320
- const registry = context.registry ?? chunkSUMIABJK_js.componentRegistry;
2725
+ const registry = context.registry ?? chunkUZ2D4BVX_js.componentRegistry;
2321
2726
  if (!permissions.canInteractUI) {
2322
2727
  return {
2323
2728
  success: false,
2324
- error: "UI interaction is not permitted",
2325
- diagnose: buildUiDiagnose(
2326
- payload.componentId ?? payload.targetId ?? "",
2327
- "unknown"
2328
- )
2729
+ error: chunkUZ2D4BVX_js.permissionDeniedMessage("UI interaction", "canInteractUI"),
2730
+ diagnose: {
2731
+ ...buildUiDiagnose(
2732
+ payload.componentId ?? payload.targetId ?? "",
2733
+ "unknown"
2734
+ ),
2735
+ recoverable: false
2736
+ }
2329
2737
  };
2330
2738
  }
2331
2739
  const { action } = payload;
@@ -2339,7 +2747,7 @@ function uiInteractionHandler(payload, context) {
2339
2747
  if (sliderId) {
2340
2748
  const smuggled = payload.value ?? payload.params?.value;
2341
2749
  if (smuggled !== void 0) {
2342
- chunkSUMIABJK_js.appilotsDebugLog(
2750
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2343
2751
  `uiInteractionHandler: "${actionStr}" on slider "${sliderId}" carried value=${JSON.stringify(smuggled)} \u2014 routing to set_value`
2344
2752
  );
2345
2753
  return setValueHandler(rawComponentId, smuggled, registry);
@@ -2350,23 +2758,23 @@ function uiInteractionHandler(payload, context) {
2350
2758
  diagnose: { ...buildUiDiagnose(sliderId, "unknown"), recoverable: true }
2351
2759
  };
2352
2760
  }
2353
- const openDialog = chunkSUMIABJK_js.getOpenNativeDialog();
2761
+ const openDialog = chunkUZ2D4BVX_js.getOpenNativeDialog();
2354
2762
  const isPressVerb = actionStr === "press" || actionStr === "tap" || actionStr === "click";
2355
2763
  if (openDialog && isPressVerb) {
2356
2764
  const needle = normalizeIdent(rawComponentId);
2357
2765
  const button = openDialog.buttons.find((b) => normalizeIdent(b.label) === needle);
2358
2766
  if (button) {
2359
2767
  button.press();
2360
- chunkSUMIABJK_js.appilotsDebugLog(`uiInteractionHandler: pressed native dialog button "${button.label}"`);
2768
+ chunkUZ2D4BVX_js.appilotsDebugLog(`uiInteractionHandler: pressed native dialog button "${button.label}"`);
2361
2769
  return { success: true, effect: "changed" };
2362
2770
  }
2363
2771
  }
2364
2772
  if (!openDialog && isPressVerb) {
2365
- const answered = chunkSUMIABJK_js.getLastAnsweredNativeDialog();
2773
+ const answered = chunkUZ2D4BVX_js.getLastAnsweredNativeDialog();
2366
2774
  const needle = normalizeIdent(rawComponentId);
2367
2775
  if (answered && needle) {
2368
2776
  if (answered.answeredWith && normalizeIdent(answered.answeredWith) === needle) {
2369
- chunkSUMIABJK_js.appilotsDebugLog(
2777
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2370
2778
  `uiInteractionHandler: native dialog button "${answered.answeredWith}" was already pressed and the dialog is closed \u2014 treating the repeat as done`
2371
2779
  );
2372
2780
  return { success: true, effect: "completed" };
@@ -2378,7 +2786,7 @@ function uiInteractionHandler(payload, context) {
2378
2786
  diagnose: {
2379
2787
  category: "component-not-found",
2380
2788
  targetId: rawComponentId,
2381
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
2789
+ screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0,
2382
2790
  recoverable: false
2383
2791
  }
2384
2792
  };
@@ -2387,7 +2795,7 @@ function uiInteractionHandler(payload, context) {
2387
2795
  }
2388
2796
  const occluded = checkModalOcclusion(rawComponentId, actionStr);
2389
2797
  if (occluded) {
2390
- chunkSUMIABJK_js.appilotsDebugLog(
2798
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2391
2799
  `uiInteractionHandler: blocked "${actionStr}" on "${rawComponentId}" \u2014 target is behind an open modal`
2392
2800
  );
2393
2801
  return occluded;
@@ -2395,7 +2803,7 @@ function uiInteractionHandler(payload, context) {
2395
2803
  if (typeof rawComponentId === "string" && rawComponentId.trim().toLowerCase().startsWith("el:")) {
2396
2804
  const result = dispatchElementOrTarget(rawComponentId, registry, actionStr);
2397
2805
  if (result.success) {
2398
- chunkSUMIABJK_js.appilotsDebugLog(
2806
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2399
2807
  `uiInteractionHandler: interaction element dispatch succeeded for "${rawComponentId}"`
2400
2808
  );
2401
2809
  }
@@ -2403,17 +2811,17 @@ function uiInteractionHandler(payload, context) {
2403
2811
  }
2404
2812
  const ordinal = parseSyntheticListItemId(rawComponentId);
2405
2813
  if (ordinal && (action === "press" || actionStr === "tap" || actionStr === "click" || actionStr === "longPress")) {
2406
- chunkSUMIABJK_js.appilotsDebugLog(
2814
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2407
2815
  `uiInteractionHandler: dispatching synthetic list ordinal \u2014 componentId="${rawComponentId}" list=${ordinal.listIndex} item=${ordinal.itemIndex}`
2408
2816
  );
2409
2817
  const result = pressListItemAtOrdinal(ordinal.listIndex, ordinal.itemIndex);
2410
2818
  if (result.ok) {
2411
- chunkSUMIABJK_js.appilotsDebugLog(
2819
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2412
2820
  `uiInteractionHandler: synthetic ordinal press succeeded (container=${result.containerType ?? "List"})`
2413
2821
  );
2414
2822
  return { success: true };
2415
2823
  }
2416
- const screen = chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
2824
+ const screen = chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0;
2417
2825
  if (result.reason === "list-not-found" || result.reason === "item-not-found") {
2418
2826
  return {
2419
2827
  success: false,
@@ -2454,7 +2862,7 @@ function uiInteractionHandler(payload, context) {
2454
2862
  };
2455
2863
  }
2456
2864
  const componentId = resolveComponentId(rawComponentId, registry, actionStr);
2457
- chunkSUMIABJK_js.appilotsDebugLog(
2865
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2458
2866
  `uiInteractionHandler: resolved componentId="${payload.componentId}" \u2192 "${componentId}"`
2459
2867
  );
2460
2868
  const target = registry.getTarget(componentId);
@@ -2507,7 +2915,7 @@ function uiInteractionHandler(payload, context) {
2507
2915
  return { success: false, error: err?.message ?? "Focus failed" };
2508
2916
  }
2509
2917
  }
2510
- chunkSUMIABJK_js.appilotsDebugLog(
2918
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2511
2919
  `uiInteractionHandler: registry miss for "${componentId}", falling back to fiber tree`
2512
2920
  );
2513
2921
  const namedToggle = dispatchIdentifiedToggle(componentId, actionStr);
@@ -2519,7 +2927,7 @@ function uiInteractionHandler(payload, context) {
2519
2927
  try {
2520
2928
  if (actionStr === "press" && handle.kind === "target" && handle.press) {
2521
2929
  handle.press();
2522
- chunkSUMIABJK_js.appilotsDebugLog(
2930
+ chunkUZ2D4BVX_js.appilotsDebugLog(
2523
2931
  `uiInteractionHandler: fiber fallback press succeeded for "${componentId}"`
2524
2932
  );
2525
2933
  return { success: true };
@@ -2555,6 +2963,28 @@ function uiInteractionHandler(payload, context) {
2555
2963
  };
2556
2964
  }
2557
2965
 
2966
+ // src/executor/completeTextEdit.ts
2967
+ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2968
+ async function completeTextEdit(fieldId, expected, registered, origin, resolveRegistered) {
2969
+ await sleep2(80);
2970
+ const current2 = findInteractiveByIdentifier(fieldId, { kind: "field" });
2971
+ if (origin?.controlIdentity && current2?.controlIdentity !== origin.controlIdentity) return false;
2972
+ if (registered && resolveRegistered && resolveRegistered() !== registered) return false;
2973
+ if (registered?.finishEditing) registered.finishEditing();
2974
+ else if (current2 && (current2.matchCount ?? 1) === 1 && !current2.disabled)
2975
+ current2.finishEditing?.();
2976
+ const started = Date.now();
2977
+ do {
2978
+ await sleep2(80);
2979
+ const live = findInteractiveByIdentifier(fieldId, { kind: "field" });
2980
+ if (origin?.controlIdentity && live?.controlIdentity !== origin.controlIdentity) return false;
2981
+ if (registered && resolveRegistered && resolveRegistered() !== registered) return false;
2982
+ const value = registered ? registered.getValue() : live?.getValue?.();
2983
+ if (value !== void 0 && value !== null && String(value) === String(expected)) return true;
2984
+ } while (Date.now() - started < 480);
2985
+ return false;
2986
+ }
2987
+
2558
2988
  // src/executor/formSubmitResolve.ts
2559
2989
  var SUBMIT_LABEL_HINT_RE = /\b(submit|save|send|continue|next|sign\s*in|log\s*in|register|salvar|enviar|entrar|cadastrar|continuar|proximo|próximo|avancar|avançar|confirmar|guardar|registrarse|iniciar\s+sesi[óo]n|enregistrer|envoyer|valider|soumettre|confirmer|se\s+connecter|s['e]\s*inscrire)\b/i;
2560
2990
  var AGENT_CHROME_TARGET_RE = /\b(fechar|close|dismiss|cancelar|cancel|limpar|clear|chat\s+do\s+assistente|assistant\s+chat)\b/i;
@@ -2582,7 +3012,7 @@ function submitLabelHintsSubmit(label) {
2582
3012
  return SUBMIT_LABEL_HINT_RE.test(trimmed);
2583
3013
  }
2584
3014
  function screenDeclaresSubmitAction(screenName) {
2585
- const meta = chunkSUMIABJK_js.getScreenMetadata(screenName);
3015
+ const meta = chunkUZ2D4BVX_js.getScreenMetadata(screenName);
2586
3016
  return Array.isArray(meta?.actions) && meta.actions.some(
2587
3017
  (action) => typeof action === "object" && action !== null && action.type === "submit"
2588
3018
  );
@@ -2615,7 +3045,7 @@ function resolveFormScreensForSubmit(screen, activePath, registry) {
2615
3045
  } else {
2616
3046
  push(screen);
2617
3047
  }
2618
- push(chunkSUMIABJK_js.getCurrentScreen() ?? void 0);
3048
+ push(chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0);
2619
3049
  const withSubmit = [];
2620
3050
  const rest = [];
2621
3051
  for (const name of ordered) {
@@ -2633,7 +3063,7 @@ function collectSubmitTargetCandidates(screens, registry) {
2633
3063
  candidates.push(id);
2634
3064
  };
2635
3065
  for (const screenName of screens) {
2636
- const meta = chunkSUMIABJK_js.getScreenMetadata(screenName);
3066
+ const meta = chunkUZ2D4BVX_js.getScreenMetadata(screenName);
2637
3067
  const submitMeta = Array.isArray(meta?.actions) ? meta.actions.find(
2638
3068
  (action) => typeof action === "object" && action !== null && action.type === "submit"
2639
3069
  ) : void 0;
@@ -2677,8 +3107,8 @@ function readVisibleValidation(fieldId, label) {
2677
3107
  return void 0;
2678
3108
  }
2679
3109
  function resolveScreenContext() {
2680
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
2681
- const screen = activePath[activePath.length - 1] ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
3110
+ const activePath = chunkUZ2D4BVX_js.getActiveRouteNames();
3111
+ const screen = activePath[activePath.length - 1] ?? chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0;
2682
3112
  return { screen, activePath };
2683
3113
  }
2684
3114
  function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
@@ -2686,36 +3116,36 @@ function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
2686
3116
  if (!requested) return false;
2687
3117
  const meta = getMetadataField(fieldId, registry);
2688
3118
  const options = Array.isArray(meta?.options) ? meta.options : [];
2689
- const requestedNorm = chunkSUMIABJK_js.normalize3(requested);
2690
- const currentNorm = chunkSUMIABJK_js.normalize3(currentValue);
3119
+ const requestedNorm = chunkUZ2D4BVX_js.normalize3(requested);
3120
+ const currentNorm = chunkUZ2D4BVX_js.normalize3(currentValue);
2691
3121
  if (currentNorm === requestedNorm) return true;
2692
3122
  for (const option of options) {
2693
3123
  const value = typeof option?.value === "string" ? option.value : "";
2694
3124
  const label = typeof option?.label === "string" ? option.label : "";
2695
- if (chunkSUMIABJK_js.normalize3(value) === requestedNorm && chunkSUMIABJK_js.normalize3(label) === currentNorm) return true;
2696
- if (chunkSUMIABJK_js.normalize3(label) === requestedNorm && chunkSUMIABJK_js.normalize3(label) === currentNorm) return true;
2697
- if (chunkSUMIABJK_js.normalize3(value) === requestedNorm && chunkSUMIABJK_js.normalize3(value) === currentNorm) return true;
3125
+ if (chunkUZ2D4BVX_js.normalize3(value) === requestedNorm && chunkUZ2D4BVX_js.normalize3(label) === currentNorm) return true;
3126
+ if (chunkUZ2D4BVX_js.normalize3(label) === requestedNorm && chunkUZ2D4BVX_js.normalize3(label) === currentNorm) return true;
3127
+ if (chunkUZ2D4BVX_js.normalize3(value) === requestedNorm && chunkUZ2D4BVX_js.normalize3(value) === currentNorm) return true;
2698
3128
  }
2699
3129
  return false;
2700
3130
  }
2701
3131
  function getMetadataField(fieldId, registry) {
2702
3132
  const screens = /* @__PURE__ */ new Set();
2703
- for (const name of chunkSUMIABJK_js.getActiveRouteNames()) screens.add(name);
2704
- const current = chunkSUMIABJK_js.getCurrentScreen();
2705
- if (current) screens.add(current);
3133
+ for (const name of chunkUZ2D4BVX_js.getActiveRouteNames()) screens.add(name);
3134
+ const current2 = chunkUZ2D4BVX_js.getCurrentScreen();
3135
+ if (current2) screens.add(current2);
2706
3136
  if (registry) {
2707
3137
  for (const comp of registry.snapshot()) {
2708
3138
  if (comp.kind === "field" && comp.screen) screens.add(comp.screen);
2709
3139
  }
2710
3140
  }
2711
- const needle = chunkSUMIABJK_js.normalize3(fieldId);
3141
+ const needle = chunkUZ2D4BVX_js.normalize3(fieldId);
2712
3142
  for (const screenName of screens) {
2713
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(screenName);
3143
+ const screenMeta = chunkUZ2D4BVX_js.getScreenMetadata(screenName);
2714
3144
  const fields = Array.isArray(screenMeta?.fields) ? screenMeta.fields : [];
2715
3145
  const match = fields.find((field) => {
2716
3146
  if (!field || typeof field !== "object") return false;
2717
- const id = typeof field.id === "string" ? chunkSUMIABJK_js.normalize3(field.id) : "";
2718
- const label = typeof field.label === "string" ? chunkSUMIABJK_js.normalize3(field.label) : "";
3147
+ const id = typeof field.id === "string" ? chunkUZ2D4BVX_js.normalize3(field.id) : "";
3148
+ const label = typeof field.label === "string" ? chunkUZ2D4BVX_js.normalize3(field.label) : "";
2719
3149
  return id === needle || label === needle;
2720
3150
  });
2721
3151
  if (match) return match;
@@ -2727,11 +3157,11 @@ function resolveSelectOption(fieldId, value, registry) {
2727
3157
  if (!requested) return void 0;
2728
3158
  const meta = getMetadataField(fieldId, registry);
2729
3159
  const options = Array.isArray(meta?.options) ? meta.options : [];
2730
- const requestedNorm = chunkSUMIABJK_js.normalize3(requested);
3160
+ const requestedNorm = chunkUZ2D4BVX_js.normalize3(requested);
2731
3161
  for (const option of options) {
2732
3162
  const optionValue = typeof option?.value === "string" ? option.value : "";
2733
3163
  const optionLabel = typeof option?.label === "string" ? option.label : "";
2734
- if (chunkSUMIABJK_js.normalize3(optionValue) === requestedNorm || chunkSUMIABJK_js.normalize3(optionLabel) === requestedNorm) {
3164
+ if (chunkUZ2D4BVX_js.normalize3(optionValue) === requestedNorm || chunkUZ2D4BVX_js.normalize3(optionLabel) === requestedNorm) {
2735
3165
  return { value: optionValue, label: optionLabel };
2736
3166
  }
2737
3167
  }
@@ -2743,7 +3173,7 @@ async function tryOpenSelectModal(fieldId, registry) {
2743
3173
  if (!target) continue;
2744
3174
  try {
2745
3175
  target.press();
2746
- await sleep2(180);
3176
+ await sleep3(180);
2747
3177
  return true;
2748
3178
  } catch {
2749
3179
  }
@@ -2781,12 +3211,12 @@ async function tryPressSelectOption(fieldId, value, registry, options = {}) {
2781
3211
  return {
2782
3212
  success: false,
2783
3213
  error: `No pressable option found for select field "${fieldId}"`,
2784
- diagnose: { category: "component-not-found", fieldId, screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
3214
+ diagnose: { category: "component-not-found", fieldId, screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0 }
2785
3215
  };
2786
3216
  }
2787
3217
  function normalizeFieldType(type) {
2788
3218
  if (typeof type !== "string") return void 0;
2789
- const normalized = chunkSUMIABJK_js.normalize3(type);
3219
+ const normalized = chunkUZ2D4BVX_js.normalize3(type);
2790
3220
  if (normalized === "select" || normalized === "picker" || normalized === "dropdown")
2791
3221
  return "select";
2792
3222
  if (normalized === "toggle" || normalized === "switch" || normalized === "checkbox")
@@ -2816,7 +3246,7 @@ function fieldCueTerms(fieldId, label) {
2816
3246
  );
2817
3247
  const terms = /* @__PURE__ */ new Set();
2818
3248
  for (const value of raw) {
2819
- const normalized = chunkSUMIABJK_js.normalize3(value);
3249
+ const normalized = chunkUZ2D4BVX_js.normalize3(value);
2820
3250
  if (normalized.length >= 3 && normalized !== "id") terms.add(normalized);
2821
3251
  }
2822
3252
  return [...terms];
@@ -2824,17 +3254,17 @@ function fieldCueTerms(fieldId, label) {
2824
3254
  function snapshotHasFieldCue(snap, fieldId, label) {
2825
3255
  const terms = fieldCueTerms(fieldId, label);
2826
3256
  if (terms.length === 0) return false;
2827
- const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) => chunkSUMIABJK_js.normalize3(text)).filter(Boolean);
3257
+ const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) => chunkUZ2D4BVX_js.normalize3(text)).filter(Boolean);
2828
3258
  return visible.some((text) => terms.some((term) => text.includes(term) || term.includes(text)));
2829
3259
  }
2830
3260
  function scoreCandidateText(value, texts) {
2831
- const valueNorm = chunkSUMIABJK_js.normalize3(String(value ?? ""));
3261
+ const valueNorm = chunkUZ2D4BVX_js.normalize3(String(value ?? ""));
2832
3262
  if (!valueNorm) return 0;
2833
3263
  let best = 0;
2834
3264
  for (const text of texts) {
2835
- const textNorm = chunkSUMIABJK_js.normalize3(text);
3265
+ const textNorm = chunkUZ2D4BVX_js.normalize3(text);
2836
3266
  if (!textNorm) continue;
2837
- best = Math.max(best, chunkSUMIABJK_js.matchScore(valueNorm, textNorm));
3267
+ best = Math.max(best, chunkUZ2D4BVX_js.matchScore(valueNorm, textNorm));
2838
3268
  }
2839
3269
  return best;
2840
3270
  }
@@ -2848,7 +3278,7 @@ function optionTexts(option) {
2848
3278
  function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue, registry) {
2849
3279
  const fieldLabel = getFieldLabel(fieldId, registry);
2850
3280
  const fieldCueVisible = snapshotHasFieldCue(snap, fieldId, fieldLabel);
2851
- const genericValue = chunkSUMIABJK_js.isGenericSelectValue(value);
3281
+ const genericValue = chunkUZ2D4BVX_js.isGenericSelectValue(value);
2852
3282
  const candidates = [];
2853
3283
  let order = 0;
2854
3284
  const choiceGroups = snap.choiceGroups ?? [];
@@ -2860,7 +3290,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
2860
3290
  const groupCueScore = Math.max(
2861
3291
  globalCueScore,
2862
3292
  ...groupTexts.map((text) => {
2863
- const normalized = chunkSUMIABJK_js.normalize3(text);
3293
+ const normalized = chunkUZ2D4BVX_js.normalize3(text);
2864
3294
  return fieldCueTerms(fieldId, fieldLabel).some(
2865
3295
  (term) => normalized.includes(term) || term.includes(normalized)
2866
3296
  ) ? 80 : 0;
@@ -2897,7 +3327,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
2897
3327
  const elementCueScore = Math.max(
2898
3328
  fieldCueVisible && elements.length <= 12 ? 50 : 0,
2899
3329
  ...cueTexts.map((text) => {
2900
- const normalized = chunkSUMIABJK_js.normalize3(text);
3330
+ const normalized = chunkUZ2D4BVX_js.normalize3(text);
2901
3331
  return fieldTerms.some((term) => normalized.includes(term) || term.includes(normalized)) ? 80 : 0;
2902
3332
  })
2903
3333
  );
@@ -2955,7 +3385,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
2955
3385
  return {
2956
3386
  success: false,
2957
3387
  error: err?.message ?? "Could not capture visible choices",
2958
- diagnose: { category: "unknown", fieldId, screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
3388
+ diagnose: { category: "unknown", fieldId, screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0 }
2959
3389
  };
2960
3390
  }
2961
3391
  const candidates = buildChoiceCandidates(
@@ -2973,7 +3403,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
2973
3403
  diagnose: {
2974
3404
  category: "component-not-found",
2975
3405
  fieldId,
2976
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0
3406
+ screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0
2977
3407
  }
2978
3408
  };
2979
3409
  }
@@ -2987,7 +3417,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
2987
3417
  }
2988
3418
  function isContinuationButton(label) {
2989
3419
  if (!label) return false;
2990
- return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkSUMIABJK_js.normalize3(label));
3420
+ return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkUZ2D4BVX_js.normalize3(label));
2991
3421
  }
2992
3422
  function pressContinuationButton(registry) {
2993
3423
  const snap = captureSnapshot();
@@ -3000,40 +3430,40 @@ function pressContinuationButton(registry) {
3000
3430
  return {
3001
3431
  success: false,
3002
3432
  error: "No enabled continuation button is visible",
3003
- diagnose: { category: "component-not-found", screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
3433
+ diagnose: { category: "component-not-found", screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0 }
3004
3434
  };
3005
3435
  }
3006
3436
  return pressTargetByIdOrLabel(id, registry);
3007
3437
  }
3008
3438
  function findField(fieldId, registry) {
3009
- chunkSUMIABJK_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
3439
+ chunkUZ2D4BVX_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
3010
3440
  const exact = registry.getField(fieldId);
3011
3441
  if (exact) {
3012
- chunkSUMIABJK_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
3442
+ chunkUZ2D4BVX_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
3013
3443
  return exact;
3014
3444
  }
3015
3445
  const lower = fieldId.toLowerCase();
3016
3446
  const snapshot = registry.snapshot();
3017
3447
  for (const comp of snapshot) {
3018
3448
  if (comp.kind === "field" && comp.id.toLowerCase() === lower) {
3019
- chunkSUMIABJK_js.appilotsDebugLog(
3449
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3020
3450
  `findField: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
3021
3451
  );
3022
3452
  return registry.getField(comp.id);
3023
3453
  }
3024
3454
  }
3025
- const currentScreenForTieBreak = chunkSUMIABJK_js.getCurrentScreen();
3026
- const needle = chunkSUMIABJK_js.normalize3(fieldId);
3455
+ const currentScreenForTieBreak = chunkUZ2D4BVX_js.getCurrentScreen();
3456
+ const needle = chunkUZ2D4BVX_js.normalize3(fieldId);
3027
3457
  let bestComp;
3028
3458
  let bestScore = 0;
3029
3459
  let bestOnCurrentScreen = false;
3030
3460
  for (const comp of snapshot) {
3031
3461
  if (comp.kind !== "field") continue;
3032
- const candidates = [chunkSUMIABJK_js.normalize3(comp.id)];
3033
- if (comp.label) candidates.push(chunkSUMIABJK_js.normalize3(comp.label));
3462
+ const candidates = [chunkUZ2D4BVX_js.normalize3(comp.id)];
3463
+ if (comp.label) candidates.push(chunkUZ2D4BVX_js.normalize3(comp.label));
3034
3464
  let candidateScore = 0;
3035
3465
  for (const cand of candidates) {
3036
- const s = chunkSUMIABJK_js.matchScore(needle, cand);
3466
+ const s = chunkUZ2D4BVX_js.matchScore(needle, cand);
3037
3467
  if (s > candidateScore) candidateScore = s;
3038
3468
  }
3039
3469
  if (candidateScore === 0) continue;
@@ -3046,14 +3476,14 @@ function findField(fieldId, registry) {
3046
3476
  }
3047
3477
  }
3048
3478
  if (bestComp && bestScore >= 75) {
3049
- chunkSUMIABJK_js.appilotsDebugLog(
3479
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3050
3480
  `findField: scored match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
3051
3481
  );
3052
3482
  return registry.getField(bestComp.id);
3053
3483
  }
3054
- const currentScreen = chunkSUMIABJK_js.getCurrentScreen();
3484
+ const currentScreen = chunkUZ2D4BVX_js.getCurrentScreen();
3055
3485
  if (currentScreen) {
3056
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(currentScreen);
3486
+ const screenMeta = chunkUZ2D4BVX_js.getScreenMetadata(currentScreen);
3057
3487
  const fields = screenMeta?.fields;
3058
3488
  if (fields && Array.isArray(fields)) {
3059
3489
  const metaField = fields.find(
@@ -3061,19 +3491,19 @@ function findField(fieldId, registry) {
3061
3491
  );
3062
3492
  if (metaField && typeof metaField === "object" && metaField.label) {
3063
3493
  const metaLabel = metaField.label;
3064
- const metaNeedle = chunkSUMIABJK_js.normalize3(metaLabel);
3494
+ const metaNeedle = chunkUZ2D4BVX_js.normalize3(metaLabel);
3065
3495
  let mBest;
3066
3496
  let mBestScore = 0;
3067
3497
  for (const comp of snapshot) {
3068
3498
  if (comp.kind !== "field" || !comp.label) continue;
3069
- const score = chunkSUMIABJK_js.matchScore(metaNeedle, chunkSUMIABJK_js.normalize3(comp.label));
3499
+ const score = chunkUZ2D4BVX_js.matchScore(metaNeedle, chunkUZ2D4BVX_js.normalize3(comp.label));
3070
3500
  if (score > mBestScore) {
3071
3501
  mBestScore = score;
3072
3502
  mBest = comp;
3073
3503
  }
3074
3504
  }
3075
3505
  if (mBest && mBestScore >= 60) {
3076
- chunkSUMIABJK_js.appilotsDebugLog(
3506
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3077
3507
  `findField: FOUND via screen metadata translation: fieldId="${fieldId}" -> metaLabel="${metaLabel}" -> registered="${mBest.id}" (score=${mBestScore})`
3078
3508
  );
3079
3509
  return registry.getField(mBest.id);
@@ -3082,34 +3512,34 @@ function findField(fieldId, registry) {
3082
3512
  }
3083
3513
  }
3084
3514
  if (bestComp && bestScore >= 40) {
3085
- chunkSUMIABJK_js.appilotsDebugLog(
3515
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3086
3516
  `findField: weak substring match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
3087
3517
  );
3088
3518
  return registry.getField(bestComp.id);
3089
3519
  }
3090
- chunkSUMIABJK_js.appilotsDebugWarn(
3520
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
3091
3521
  `findField: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available fields: ${snapshot.filter((c) => c.kind === "field").map((c) => `"${c.id}" (label: ${c.label})`).join(", ") || "none"}`
3092
3522
  );
3093
3523
  return void 0;
3094
3524
  }
3095
3525
  function findToggle(fieldId, registry) {
3096
- chunkSUMIABJK_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
3526
+ chunkUZ2D4BVX_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
3097
3527
  const exact = registry.getToggle(fieldId);
3098
3528
  if (exact) {
3099
- chunkSUMIABJK_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
3529
+ chunkUZ2D4BVX_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
3100
3530
  return exact;
3101
3531
  }
3102
3532
  const lower = fieldId.toLowerCase();
3103
3533
  const snapshot = registry.snapshot();
3104
3534
  for (const comp of snapshot) {
3105
3535
  if (comp.kind === "toggle" && comp.id.toLowerCase() === lower) {
3106
- chunkSUMIABJK_js.appilotsDebugLog(
3536
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3107
3537
  `findToggle: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
3108
3538
  );
3109
3539
  return registry.getToggle(comp.id);
3110
3540
  }
3111
3541
  }
3112
- chunkSUMIABJK_js.appilotsDebugWarn(
3542
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
3113
3543
  `findToggle: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available toggles: ${snapshot.filter((c) => c.kind === "toggle").map((c) => `"${c.id}"`).join(", ") || "none"}`
3114
3544
  );
3115
3545
  return void 0;
@@ -3120,7 +3550,7 @@ function findSlider(fieldId, registry) {
3120
3550
  const lower = fieldId.toLowerCase();
3121
3551
  for (const comp of registry.snapshot()) {
3122
3552
  if (comp.kind === "slider" && comp.id.toLowerCase() === lower) {
3123
- chunkSUMIABJK_js.appilotsDebugLog(
3553
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3124
3554
  `findSlider: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
3125
3555
  );
3126
3556
  return registry.getSlider(comp.id);
@@ -3128,17 +3558,17 @@ function findSlider(fieldId, registry) {
3128
3558
  }
3129
3559
  return void 0;
3130
3560
  }
3131
- var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3561
+ var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3132
3562
  async function formFillHandler(payload, context) {
3133
3563
  const { permissions } = context;
3134
- const registry = context.registry ?? chunkSUMIABJK_js.componentRegistry;
3564
+ const registry = context.registry ?? chunkUZ2D4BVX_js.componentRegistry;
3135
3565
  const { screen, activePath } = resolveScreenContext();
3136
3566
  const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
3137
3567
  if (!permissions.canFillForms) {
3138
3568
  return {
3139
3569
  success: false,
3140
- error: "Form filling is not permitted",
3141
- diagnose: { category: "unknown", screen: screenPath }
3570
+ error: chunkUZ2D4BVX_js.permissionDeniedMessage("Form filling", "canFillForms"),
3571
+ diagnose: { category: "unknown", screen: screenPath, recoverable: false }
3142
3572
  };
3143
3573
  }
3144
3574
  if (!payload.fields || payload.fields.length === 0) {
@@ -3150,11 +3580,11 @@ async function formFillHandler(payload, context) {
3150
3580
  }
3151
3581
  const registrySnapshot = registry.snapshot();
3152
3582
  if (registrySnapshot.length === 0) {
3153
- chunkSUMIABJK_js.appilotsDebugWarn(
3583
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
3154
3584
  "formFillHandler: registry is EMPTY \u2014 auto-tracking may not be active. Ensure enableAppilotsAutoTracking() runs before components mount."
3155
3585
  );
3156
3586
  } else {
3157
- chunkSUMIABJK_js.appilotsDebugLog(
3587
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3158
3588
  `[Appilots formFillHandler] Registry has ${registrySnapshot.length} components:`,
3159
3589
  registrySnapshot.map((c) => `${c.kind}:${c.id}`).join(", ")
3160
3590
  );
@@ -3162,7 +3592,7 @@ async function formFillHandler(payload, context) {
3162
3592
  const fieldResults = [];
3163
3593
  let allSuccess = true;
3164
3594
  let selectedChoiceThisBatch = false;
3165
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
3595
+ chunkUZ2D4BVX_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
3166
3596
  const availableFieldIds = () => registry.snapshot().filter((comp) => comp.kind === "field").map((comp) => `${comp.id}${comp.label ? ` (${comp.label})` : ""}`).slice(0, 8);
3167
3597
  const isElementIdField = (field) => typeof field.fieldId === "string" && field.fieldId.trim().toLowerCase().startsWith("el:");
3168
3598
  for (const field of payload.fields.filter(isElementIdField)) {
@@ -3189,20 +3619,57 @@ async function formFillHandler(payload, context) {
3189
3619
  const { fieldId, fieldType, value } = field;
3190
3620
  const effectiveFieldType = getEffectiveFieldType(fieldId, fieldType, registry);
3191
3621
  let selectFailure;
3192
- chunkSUMIABJK_js.appilotsDebugLog(
3193
- `formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkSUMIABJK_js.describeValue(value)}`
3622
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3623
+ `formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkUZ2D4BVX_js.describeValue(value)}`
3194
3624
  );
3195
3625
  const fieldEntry = findField(fieldId, registry);
3196
3626
  if (fieldEntry) {
3197
3627
  try {
3198
- chunkSUMIABJK_js.appilotsDebugLog(
3628
+ const nativeField = findInteractiveByIdentifier(fieldId, { kind: "field" });
3629
+ if (nativeField?.disabled || (nativeField?.matchCount ?? 1) > 1) {
3630
+ fieldResults.push({
3631
+ fieldId,
3632
+ success: false,
3633
+ error: nativeField?.disabled ? "The field is disabled" : "The field identifier matches multiple controls",
3634
+ diagnose: {
3635
+ category: nativeField?.disabled ? "disabled" : "ambiguous-target",
3636
+ fieldId,
3637
+ screen: screenPath
3638
+ }
3639
+ });
3640
+ allSuccess = false;
3641
+ continue;
3642
+ }
3643
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3199
3644
  `formFillHandler: found field "${fieldId}" via registry, calling setValue(<${String(value).length} chars>)`
3200
3645
  );
3201
3646
  const beforeValue = effectiveFieldType === "date" ? fieldEntry.getValue?.() ?? "" : void 0;
3202
3647
  fieldEntry.focus?.();
3203
3648
  fieldEntry.setValue(String(value));
3649
+ if (effectiveFieldType === "text" || effectiveFieldType === "number") {
3650
+ if (!await completeTextEdit(
3651
+ fieldId,
3652
+ value,
3653
+ fieldEntry,
3654
+ nativeField,
3655
+ () => findField(fieldId, registry)
3656
+ )) {
3657
+ fieldResults.push({
3658
+ fieldId,
3659
+ success: false,
3660
+ error: "The field did not retain the requested value after editing ended. Inspect its current value before retrying.",
3661
+ diagnose: { category: "validation", fieldId, screen: screenPath }
3662
+ });
3663
+ allSuccess = false;
3664
+ continue;
3665
+ }
3666
+ }
3204
3667
  if (effectiveFieldType === "date") {
3205
- const afterValue = fieldEntry.getValue?.() ?? "";
3668
+ let afterValue = fieldEntry.getValue?.() ?? "";
3669
+ if (afterValue === beforeValue) {
3670
+ await sleep3(80);
3671
+ afterValue = fieldEntry.getValue?.() ?? "";
3672
+ }
3206
3673
  if (afterValue === beforeValue) {
3207
3674
  fieldResults.push({
3208
3675
  fieldId,
@@ -3222,11 +3689,11 @@ async function formFillHandler(payload, context) {
3222
3689
  if (effectiveFieldType === "select") {
3223
3690
  let after = fieldEntry.getValue?.() ?? "";
3224
3691
  if (!selectValueApplied(fieldId, value, after, registry)) {
3225
- await sleep2(80);
3692
+ await sleep3(80);
3226
3693
  after = fieldEntry.getValue?.() ?? "";
3227
3694
  }
3228
3695
  if (!selectValueApplied(fieldId, value, after, registry)) {
3229
- chunkSUMIABJK_js.appilotsDebugWarn(
3696
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
3230
3697
  `formFillHandler: select field "${fieldId}" setValue did not stick (wrote <${String(value).length} chars>, current is <${String(after ?? "").length} chars>), trying visible choice fallback`
3231
3698
  );
3232
3699
  const selectResult = await selectVisibleChoice(fieldId, value, registry, {
@@ -3343,7 +3810,7 @@ async function formFillHandler(payload, context) {
3343
3810
  if (!selectResult.success && selectedChoiceThisBatch) {
3344
3811
  const nextResult = pressContinuationButton(registry);
3345
3812
  if (nextResult.success) {
3346
- await sleep2(180);
3813
+ await sleep3(180);
3347
3814
  selectResult = await selectVisibleChoice(fieldId, value, registry, {
3348
3815
  allowFirstVisibleWhenNoCue: true
3349
3816
  });
@@ -3351,24 +3818,50 @@ async function formFillHandler(payload, context) {
3351
3818
  }
3352
3819
  if (selectResult.success) {
3353
3820
  selectedChoiceThisBatch = true;
3354
- chunkSUMIABJK_js.appilotsDebugLog(
3821
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3355
3822
  `formFillHandler: selected visible option for "${fieldId}"` + (selectResult.selectedLabel ? ` \u2192 "${selectResult.selectedLabel}"` : "")
3356
3823
  );
3357
- await sleep2(120);
3824
+ await sleep3(120);
3358
3825
  fieldResults.push({ fieldId, success: true });
3359
3826
  continue;
3360
3827
  }
3361
3828
  selectFailure = selectResult;
3362
3829
  }
3363
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
3830
+ chunkUZ2D4BVX_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
3364
3831
  const handle = findInteractiveByIdentifier(fieldId, {
3365
3832
  kind: effectiveFieldType === "toggle" ? "toggle" : "field"
3366
3833
  });
3367
3834
  if (handle?.setValue) {
3368
3835
  try {
3836
+ if (handle.disabled || (handle.matchCount ?? 1) > 1) {
3837
+ fieldResults.push({
3838
+ fieldId,
3839
+ success: false,
3840
+ error: handle.disabled ? "The field is disabled" : "The field identifier matches multiple controls",
3841
+ diagnose: {
3842
+ category: handle.disabled ? "disabled" : "ambiguous-target",
3843
+ fieldId,
3844
+ screen: screenPath,
3845
+ candidates: handle.matchCandidates
3846
+ }
3847
+ });
3848
+ allSuccess = false;
3849
+ continue;
3850
+ }
3851
+ setSpotlightTarget(handle.measure?.() ?? null, handle.label);
3369
3852
  handle.focus?.();
3370
3853
  handle.setValue(value);
3371
- chunkSUMIABJK_js.appilotsDebugLog(
3854
+ if (handle.kind === "field" && !await completeTextEdit(fieldId, value, void 0, handle)) {
3855
+ fieldResults.push({
3856
+ fieldId,
3857
+ success: false,
3858
+ error: "The field did not retain the requested value after editing ended. Inspect its current value before retrying.",
3859
+ diagnose: { category: "validation", fieldId, screen: screenPath }
3860
+ });
3861
+ allSuccess = false;
3862
+ continue;
3863
+ }
3864
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3372
3865
  `formFillHandler: fiber fallback succeeded for "${fieldId}" \u2192 label="${handle.label}"`
3373
3866
  );
3374
3867
  fieldResults.push({ fieldId, success: true });
@@ -3415,14 +3908,15 @@ async function formFillHandler(payload, context) {
3415
3908
  }
3416
3909
  if (!allSuccess) {
3417
3910
  const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
3418
- chunkSUMIABJK_js.appilotsDebugWarn(
3911
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
3419
3912
  "formFillHandler: submitAfterFill=true requested but some fields failed; NOT submitting" + (failedIds.length > 0 ? ` (failed: ${failedIds.join(", ")})` : "")
3420
3913
  );
3421
3914
  } else {
3422
- await sleep2(120);
3915
+ await sleep3(120);
3423
3916
  if (!permissions.canSubmitForms) {
3424
3917
  return { success: false, error: "Form submission is not permitted", fieldResults };
3425
3918
  }
3919
+ const beforeSubmitTexts = captureSnapshot().texts;
3426
3920
  const submitResult = pressSubmitButton(
3427
3921
  {
3428
3922
  screen,
@@ -3433,7 +3927,7 @@ async function formFillHandler(payload, context) {
3433
3927
  registry
3434
3928
  );
3435
3929
  if (!submitResult.success) {
3436
- chunkSUMIABJK_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
3930
+ chunkUZ2D4BVX_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
3437
3931
  return {
3438
3932
  success: false,
3439
3933
  error: submitResult.error,
@@ -3442,10 +3936,11 @@ async function formFillHandler(payload, context) {
3442
3936
  };
3443
3937
  }
3444
3938
  const postSubmit = await waitForPostSubmitOutcome({
3445
- submitTargetId: submitResult.pressedTargetId
3939
+ submitTargetId: submitResult.pressedTargetId,
3940
+ beforeTexts: beforeSubmitTexts
3446
3941
  });
3447
3942
  if (postSubmit.status === "pending") {
3448
- chunkSUMIABJK_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
3943
+ chunkUZ2D4BVX_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
3449
3944
  return {
3450
3945
  success: false,
3451
3946
  error: postSubmit.message,
@@ -3454,7 +3949,7 @@ async function formFillHandler(payload, context) {
3454
3949
  };
3455
3950
  }
3456
3951
  if (postSubmit.status === "failure") {
3457
- chunkSUMIABJK_js.appilotsDebugWarn(
3952
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
3458
3953
  `formFillHandler: submit rejected by visible validation \u2014 ${postSubmit.message}`
3459
3954
  );
3460
3955
  return {
@@ -3469,7 +3964,10 @@ async function formFillHandler(payload, context) {
3469
3964
  }
3470
3965
  };
3471
3966
  }
3472
- chunkSUMIABJK_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
3967
+ if (postSubmit.status === "unverified") {
3968
+ return { success: true, fieldResults, effect: "unknown" };
3969
+ }
3970
+ chunkUZ2D4BVX_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
3473
3971
  }
3474
3972
  }
3475
3973
  const aggregatedDiagnose = aggregateFieldDiagnoses(fieldResults, screenPath);
@@ -3481,17 +3979,17 @@ async function formFillHandler(payload, context) {
3481
3979
  };
3482
3980
  }
3483
3981
  function pressSubmitButton(context, registry) {
3484
- const activePath = context.activePath ?? chunkSUMIABJK_js.getActiveRouteNames();
3982
+ const activePath = context.activePath ?? chunkUZ2D4BVX_js.getActiveRouteNames();
3485
3983
  const hintScreen = context.screen ?? context.screenPath;
3486
3984
  const formScreens = resolveFormScreensForSubmit(hintScreen, activePath, registry);
3487
- const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
3985
+ const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0;
3488
3986
  const candidates = collectSubmitTargetCandidates(formScreens, registry);
3489
3987
  for (const candidate of candidates) {
3490
3988
  const target = registry.getTarget(candidate);
3491
3989
  if (target) {
3492
3990
  try {
3493
3991
  target.press();
3494
- chunkSUMIABJK_js.appilotsDebugLog(
3992
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3495
3993
  `formFillHandler: submitAfterFill \u2014 pressed registry target "${candidate}"` + (resolvedScreen ? ` on screen "${resolvedScreen}"` : "")
3496
3994
  );
3497
3995
  return { success: true, pressedTargetId: candidate };
@@ -3505,7 +4003,7 @@ function pressSubmitButton(context, registry) {
3505
4003
  }
3506
4004
  }
3507
4005
  for (const screenName of formScreens) {
3508
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(screenName);
4006
+ const screenMeta = chunkUZ2D4BVX_js.getScreenMetadata(screenName);
3509
4007
  const submitMeta = Array.isArray(screenMeta?.actions) ? screenMeta.actions.find(
3510
4008
  (action) => typeof action === "object" && action !== null && action.type === "submit"
3511
4009
  ) : void 0;
@@ -3516,7 +4014,7 @@ function pressSubmitButton(context, registry) {
3516
4014
  if (handle?.press) {
3517
4015
  try {
3518
4016
  handle.press();
3519
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
4017
+ chunkUZ2D4BVX_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
3520
4018
  return { success: true, pressedTargetId: submitId ?? submitLabel };
3521
4019
  } catch (err) {
3522
4020
  return {
@@ -3538,7 +4036,7 @@ function pressSubmitButton(context, registry) {
3538
4036
  if (id) {
3539
4037
  const pressed = pressTargetByIdOrLabel(id, registry);
3540
4038
  if (pressed.success) {
3541
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
4039
+ chunkUZ2D4BVX_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
3542
4040
  return { success: true, pressedTargetId: id };
3543
4041
  }
3544
4042
  }
@@ -3552,7 +4050,7 @@ function pressSubmitButton(context, registry) {
3552
4050
  if (target) {
3553
4051
  try {
3554
4052
  target.press();
3555
- chunkSUMIABJK_js.appilotsDebugLog(
4053
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3556
4054
  `formFillHandler: submitAfterFill \u2014 pressed by label heuristic "${comp.label}"`
3557
4055
  );
3558
4056
  return { success: true, pressedTargetId: comp.id };
@@ -3568,7 +4066,7 @@ function pressSubmitButton(context, registry) {
3568
4066
  for (const fieldId of [...context.filledFieldIds ?? []].reverse()) {
3569
4067
  const handle = findInteractiveByIdentifier(fieldId, { kind: "field" });
3570
4068
  if (handle?.submitFromKeyboard?.()) {
3571
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 return key on "${fieldId}"`);
4069
+ chunkUZ2D4BVX_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 return key on "${fieldId}"`);
3572
4070
  return { success: true, pressedTargetId: fieldId };
3573
4071
  }
3574
4072
  }
@@ -3606,7 +4104,21 @@ function aggregateFieldDiagnoses(results, screen) {
3606
4104
  var FALLBACK_PAGE_PX = 600;
3607
4105
  var PAGE_FRACTION = 0.85;
3608
4106
  var POST_SCROLL_MOUNT_MS = 400;
3609
- var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
4107
+ var PAGINATION_MAX_WAIT_MS = 4e3;
4108
+ var PAGINATION_POLL_MS = 150;
4109
+ var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
4110
+ async function settleAfterScroll() {
4111
+ await sleep4(POST_SCROLL_MOUNT_MS);
4112
+ if (!chunkUZ2D4BVX_js.probeLoadingState(void 0, chunkUZ2D4BVX_js.getCurrentScreen()).loading) return;
4113
+ const deadline = Date.now() + PAGINATION_MAX_WAIT_MS;
4114
+ while (Date.now() < deadline) {
4115
+ await sleep4(PAGINATION_POLL_MS);
4116
+ if (!chunkUZ2D4BVX_js.probeLoadingState(void 0, chunkUZ2D4BVX_js.getCurrentScreen()).loading) {
4117
+ await sleep4(POST_SCROLL_MOUNT_MS);
4118
+ return;
4119
+ }
4120
+ }
4121
+ }
3610
4122
  function normalizeId2(value) {
3611
4123
  return String(value ?? "").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "");
3612
4124
  }
@@ -3614,12 +4126,12 @@ function buildDiagnose(category, targetId, candidates) {
3614
4126
  return {
3615
4127
  category,
3616
4128
  targetId,
3617
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
4129
+ screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0,
3618
4130
  ...candidates && candidates.length > 0 ? { candidates: candidates.slice(0, 8) } : {}
3619
4131
  };
3620
4132
  }
3621
4133
  function resolveListEntry(listId) {
3622
- const entries = chunkSUMIABJK_js.listRegistry.snapshot();
4134
+ const entries = chunkUZ2D4BVX_js.listRegistry.snapshot();
3623
4135
  if (entries.length === 0) return {};
3624
4136
  if (listId) {
3625
4137
  const wanted = normalizeId2(listId);
@@ -3642,13 +4154,26 @@ function pageOffset(metrics, direction) {
3642
4154
  }
3643
4155
  return next;
3644
4156
  }
4157
+ async function finishScroll(entry, before) {
4158
+ await settleAfterScroll();
4159
+ const current2 = chunkUZ2D4BVX_js.listRegistry.get(entry.id) ?? entry;
4160
+ const after = current2.getScrollMetrics?.();
4161
+ const grew = typeof entry.itemCount === "number" && typeof current2.itemCount === "number" && current2.itemCount > entry.itemCount;
4162
+ const moved = grew || !!(before && after && (Math.abs(after.offset - before.offset) > 2 || after.contentLength > before.contentLength + 2));
4163
+ const outcome = moved ? "moved" : before && after ? "no-progress" : "unverified";
4164
+ current2.exploration?.recordScroll(outcome);
4165
+ return {
4166
+ success: true,
4167
+ effect: moved ? "changed" : outcome === "no-progress" ? "none" : "unknown"
4168
+ };
4169
+ }
3645
4170
  async function scrollListHandler(payload, context) {
3646
4171
  const { permissions } = context;
3647
4172
  if (!permissions.canInteractUI) {
3648
4173
  return {
3649
4174
  success: false,
3650
- error: "UI interaction is not permitted",
3651
- diagnose: buildDiagnose("unknown", payload.listId)
4175
+ error: chunkUZ2D4BVX_js.permissionDeniedMessage("UI interaction", "canInteractUI"),
4176
+ diagnose: { ...buildDiagnose("unknown", payload.listId), recoverable: false }
3652
4177
  };
3653
4178
  }
3654
4179
  const toIndex = typeof payload.toIndex === "number" ? payload.toIndex : void 0;
@@ -3676,6 +4201,15 @@ async function scrollListHandler(payload, context) {
3676
4201
  diagnose: buildDiagnose("component-not-found", payload.listId, candidates)
3677
4202
  };
3678
4203
  }
4204
+ const exploration = entry.exploration?.snapshot();
4205
+ if (exploration && (exploration.remainingScrollSteps === 0 || exploration.consecutiveNoProgress >= 2)) {
4206
+ return {
4207
+ success: false,
4208
+ effect: "none",
4209
+ error: "List exploration stopped: scroll budget exhausted or repeated no progress. Use the current loaded count/coverage and report any remaining uncertainty; do not repeat this scroll.",
4210
+ diagnose: { ...buildDiagnose("validation", entry.id), recoverable: false }
4211
+ };
4212
+ }
3679
4213
  if (toIndex !== void 0) {
3680
4214
  if (entry.kind === "scroll") {
3681
4215
  return {
@@ -3691,17 +4225,16 @@ async function scrollListHandler(payload, context) {
3691
4225
  diagnose: buildDiagnose("validation", entry.id)
3692
4226
  };
3693
4227
  }
4228
+ const before = entry.getScrollMetrics?.();
3694
4229
  const zeroBased = toIndex - 1;
3695
4230
  if (entry.scrollToIndex?.(zeroBased)) {
3696
- await sleep3(POST_SCROLL_MOUNT_MS);
3697
- return { success: true };
4231
+ return finishScroll(entry, before);
3698
4232
  }
3699
4233
  const metrics2 = entry.getScrollMetrics?.();
3700
4234
  if (metrics2 && metrics2.contentLength > 0 && typeof entry.itemCount === "number" && entry.itemCount > 0) {
3701
4235
  const estimated = zeroBased / entry.itemCount * metrics2.contentLength;
3702
4236
  if (entry.scrollToOffset?.(Math.max(0, estimated))) {
3703
- await sleep3(POST_SCROLL_MOUNT_MS);
3704
- return { success: true };
4237
+ return finishScroll(entry, before);
3705
4238
  }
3706
4239
  }
3707
4240
  return {
@@ -3711,10 +4244,21 @@ async function scrollListHandler(payload, context) {
3711
4244
  };
3712
4245
  }
3713
4246
  const metrics = entry.getScrollMetrics?.();
4247
+ if (!metrics && exploration?.lastScroll === "unverified") {
4248
+ return {
4249
+ success: false,
4250
+ effect: "unknown",
4251
+ error: "Scroll offset is still unavailable after one probe. Cannot safely page again; do not infer the end or repeat the same absolute offset.",
4252
+ diagnose: { ...buildDiagnose("validation", entry.id), recoverable: false }
4253
+ };
4254
+ }
3714
4255
  const target = pageOffset(metrics, direction);
4256
+ if (metrics && Math.abs(target - metrics.offset) <= 2) {
4257
+ entry.exploration?.recordScroll("boundary");
4258
+ return { success: true, effect: "none" };
4259
+ }
3715
4260
  if (entry.scrollToOffset?.(target)) {
3716
- await sleep3(POST_SCROLL_MOUNT_MS);
3717
- return { success: true };
4261
+ return finishScroll(entry, metrics);
3718
4262
  }
3719
4263
  return {
3720
4264
  success: false,
@@ -3763,12 +4307,12 @@ function resolveActionHints(screen, pressedComponentId, actionPayload) {
3763
4307
  if (typeof declared === "number") return { asyncBudgetMs: declared };
3764
4308
  }
3765
4309
  if (!screen || !pressedComponentId) return void 0;
3766
- const meta = chunkSUMIABJK_js.getScreenMetadata(screen);
4310
+ const meta = chunkUZ2D4BVX_js.getScreenMetadata(screen);
3767
4311
  const actions = meta?.actions;
3768
4312
  if (!actions || actions.length === 0) return void 0;
3769
4313
  for (const a of actions) {
3770
4314
  if (typeof a === "string") continue;
3771
- if (chunkSUMIABJK_js.idLooselyMatches(a.id, pressedComponentId)) {
4315
+ if (chunkUZ2D4BVX_js.idLooselyMatches(a.id, pressedComponentId)) {
3772
4316
  const inferred = a.appilotsInferred;
3773
4317
  const declared = a.asyncBudgetMs;
3774
4318
  const hints = {
@@ -3798,12 +4342,12 @@ function hashFieldValue(value) {
3798
4342
  }
3799
4343
  return (hash >>> 0).toString(36);
3800
4344
  }
3801
- var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date"]);
4345
+ var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date", "number"]);
3802
4346
  function discreteFieldSignature() {
3803
4347
  const sigs = [];
3804
- for (const { id, kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
4348
+ for (const { id, kind } of chunkUZ2D4BVX_js.componentRegistry.snapshot()) {
3805
4349
  if (kind !== "field") continue;
3806
- const entry = chunkSUMIABJK_js.componentRegistry.getField(id);
4350
+ const entry = chunkUZ2D4BVX_js.componentRegistry.getField(id);
3807
4351
  if (!entry || !DISCRETE_FIELD_TYPES.has(entry.fieldType ?? "")) continue;
3808
4352
  try {
3809
4353
  sigs.push(`${id}:${hashFieldValue(String(entry.getValue() ?? ""))}`);
@@ -3812,35 +4356,46 @@ function discreteFieldSignature() {
3812
4356
  }
3813
4357
  return sigs.sort().join(",");
3814
4358
  }
3815
- async function waitForPostInteractionSettle(payload) {
4359
+ function capturePreInteractionBaseline(payload) {
4360
+ const targetId = targetIdFromPayload(payload);
4361
+ const screen = chunkUZ2D4BVX_js.getCurrentScreen();
4362
+ const probe = chunkUZ2D4BVX_js.probeLoadingState(targetId || null, screen);
4363
+ return {
4364
+ fingerprint: probe.fingerprint,
4365
+ fields: discreteFieldSignature(),
4366
+ screen,
4367
+ readable: probe.fingerprint !== ""
4368
+ };
4369
+ }
4370
+ async function waitForPostInteractionSettle(payload, preBaseline) {
3816
4371
  const targetId = targetIdFromPayload(payload);
3817
- const fromScreen = chunkSUMIABJK_js.getCurrentScreen();
3818
- const baseline = chunkSUMIABJK_js.probeLoadingState(targetId || null, fromScreen);
3819
- const baselineFields = discreteFieldSignature();
3820
- const readable = baseline.fingerprint !== "";
4372
+ const baseline = preBaseline ?? capturePreInteractionBaseline(payload);
4373
+ const fromScreen = baseline.screen;
4374
+ const baselineFields = baseline.fields;
4375
+ const readable = baseline.readable;
3821
4376
  await sleepMs(100);
3822
- const afterPress = chunkSUMIABJK_js.probeLoadingState(targetId || null, chunkSUMIABJK_js.getCurrentScreen());
4377
+ const afterPress = chunkUZ2D4BVX_js.probeLoadingState(targetId || null, chunkUZ2D4BVX_js.getCurrentScreen());
3823
4378
  const modalOrLoading = afterPress.modalOpen || afterPress.loading || afterPress.pressedDisabled;
3824
4379
  const fingerprintChanged = afterPress.fingerprint !== baseline.fingerprint;
3825
4380
  const verdict = () => {
3826
4381
  if (!readable) return { effect: "unknown" };
3827
- const settled = chunkSUMIABJK_js.probeLoadingState(targetId || null, chunkSUMIABJK_js.getCurrentScreen());
4382
+ const settled = chunkUZ2D4BVX_js.probeLoadingState(targetId || null, chunkUZ2D4BVX_js.getCurrentScreen());
3828
4383
  if (settled.fingerprint === "") return { effect: "unknown" };
3829
4384
  if (discreteFieldSignature() !== baselineFields) return { effect: "changed" };
3830
4385
  return { effect: settled.fingerprint !== baseline.fingerprint ? "changed" : "none" };
3831
4386
  };
3832
4387
  const declared = declaredBudgetMs(resolveActionHints(fromScreen, targetId || null, payload));
3833
- const capMs = declared ?? (chunkSUMIABJK_js.isListItemPressTarget(targetId) ? 5e3 : 1e4);
4388
+ const capMs = declared ?? (chunkUZ2D4BVX_js.isListItemPressTarget(targetId) ? 5e3 : 1e4);
3834
4389
  if (modalOrLoading || fingerprintChanged) {
3835
- await chunkSUMIABJK_js.waitForLoadingSettle({
4390
+ await chunkUZ2D4BVX_js.waitForLoadingSettle({
3836
4391
  pressedComponentId: targetId || null,
3837
4392
  fromScreen,
3838
4393
  maxMs: capMs
3839
4394
  });
3840
4395
  return verdict();
3841
4396
  }
3842
- if (chunkSUMIABJK_js.isListItemPressTarget(targetId)) {
3843
- await chunkSUMIABJK_js.waitForLoadingSettle({
4397
+ if (chunkUZ2D4BVX_js.isListItemPressTarget(targetId)) {
4398
+ await chunkUZ2D4BVX_js.waitForLoadingSettle({
3844
4399
  fromScreen,
3845
4400
  maxMs: 3e3
3846
4401
  });
@@ -3849,19 +4404,13 @@ async function waitForPostInteractionSettle(payload) {
3849
4404
  }
3850
4405
 
3851
4406
  // src/executor/ActionExecutor.ts
3852
- var DEFAULT_PERMISSIONS = {
3853
- canNavigate: true,
3854
- canFillForms: true,
3855
- canInteractUI: true,
3856
- canSubmitForms: true
3857
- };
3858
4407
  function validateActionPayload(action) {
3859
4408
  const invalid = (message, ids) => ({
3860
4409
  success: false,
3861
4410
  error: message,
3862
4411
  diagnose: {
3863
4412
  category: "validation",
3864
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
4413
+ screen: chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0,
3865
4414
  ...ids ?? {}
3866
4415
  }
3867
4416
  });
@@ -3922,10 +4471,10 @@ function isDestructivePayload(payload) {
3922
4471
  return !!params && typeof params === "object" && params.destructive === true;
3923
4472
  }
3924
4473
  async function executeAction(action, context) {
3925
- chunkSUMIABJK_js.appilotsDebugLog(
4474
+ chunkUZ2D4BVX_js.appilotsDebugLog(
3926
4475
  `executeAction called: type="${action.type}", id="${action.id}", payload=${JSON.stringify(action.payload)}`
3927
4476
  );
3928
- const permissions = context.permissions ?? DEFAULT_PERMISSIONS;
4477
+ const permissions = chunkUZ2D4BVX_js.resolveAgentPermissions(context.permissions);
3929
4478
  context.emit({
3930
4479
  type: "agent:action:start",
3931
4480
  timestamp: Date.now(),
@@ -3951,7 +4500,7 @@ async function executeAction(action, context) {
3951
4500
  let result;
3952
4501
  const validationFailure = validateActionPayload(action);
3953
4502
  if (validationFailure) {
3954
- chunkSUMIABJK_js.appilotsDebugWarn(
4503
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
3955
4504
  `executeAction: payload validation failed for type="${action.type}" id="${action.id}": ${validationFailure.error}`
3956
4505
  );
3957
4506
  context.emit({
@@ -3978,17 +4527,18 @@ async function executeAction(action, context) {
3978
4527
  case "form_fill":
3979
4528
  result = await formFillHandler(action.payload, {
3980
4529
  permissions,
3981
- registry: context.registry ?? chunkSUMIABJK_js.getDefaultRegistry()
4530
+ registry: context.registry ?? chunkUZ2D4BVX_js.getDefaultRegistry()
3982
4531
  });
3983
4532
  break;
3984
4533
  case "ui_interaction": {
3985
4534
  const payload = action.payload;
4535
+ const baseline = capturePreInteractionBaseline(payload);
3986
4536
  result = uiInteractionHandler(payload, {
3987
4537
  permissions,
3988
- registry: context.registry ?? chunkSUMIABJK_js.getDefaultRegistry()
4538
+ registry: context.registry ?? chunkUZ2D4BVX_js.getDefaultRegistry()
3989
4539
  });
3990
4540
  if (result.success) {
3991
- const settle = await waitForPostInteractionSettle(payload);
4541
+ const settle = await waitForPostInteractionSettle(payload, baseline);
3992
4542
  result.effect = result.effect ?? effectFor(payload, settle.effect);
3993
4543
  }
3994
4544
  break;
@@ -4014,7 +4564,7 @@ async function executeAction(action, context) {
4014
4564
  };
4015
4565
  }
4016
4566
  } catch (err) {
4017
- chunkSUMIABJK_js.appilotsDebugWarn(
4567
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
4018
4568
  `executeAction: exception during action type="${action.type}" id="${action.id}": ${err?.message}`
4019
4569
  );
4020
4570
  result = {
@@ -4022,7 +4572,7 @@ async function executeAction(action, context) {
4022
4572
  error: err?.message ?? "Action execution failed unexpectedly"
4023
4573
  };
4024
4574
  }
4025
- chunkSUMIABJK_js.appilotsDebugLog(
4575
+ chunkUZ2D4BVX_js.appilotsDebugLog(
4026
4576
  `executeAction result: type="${action.type}", id="${action.id}", success=${result.success}, error=${result.error ?? "none"}`
4027
4577
  );
4028
4578
  context.emit({
@@ -4076,18 +4626,28 @@ var _patchedAlert = (title, message, buttons, options) => {
4076
4626
  return suppression.originalAlert(title, message, buttons, options);
4077
4627
  }
4078
4628
  suppression.consumed = true;
4079
- chunkSUMIABJK_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
4629
+ const report = (handlerCompleted) => suppression.onHandled?.({
4630
+ title: title.slice(0, 300),
4631
+ message: message?.slice(0, 1e3),
4632
+ buttonLabel: button.text?.slice(0, 160),
4633
+ handlerCompleted
4634
+ });
4635
+ chunkUZ2D4BVX_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
4080
4636
  try {
4081
- suppression.pending = Promise.resolve(button.onPress()).then(() => void 0).catch((err) => reportHandlerFailure(err));
4637
+ suppression.pending = Promise.resolve(button.onPress()).then(() => report(true)).catch((err) => {
4638
+ reportHandlerFailure(err);
4639
+ report(false);
4640
+ });
4082
4641
  } catch (err) {
4083
4642
  reportHandlerFailure(err);
4084
4643
  suppression.pending = null;
4644
+ report(false);
4085
4645
  }
4086
4646
  };
4087
4647
  function reportHandlerFailure(err) {
4088
4648
  console.error("[Appilots] The app\u2019s Alert handler threw while being auto-confirmed", err);
4089
4649
  }
4090
- async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4650
+ async function runWithConfirmedDestructiveContext(enabled, host, fn, onHandled) {
4091
4651
  if (!enabled) return fn();
4092
4652
  if (_active) {
4093
4653
  _active.depth += 1;
@@ -4108,6 +4668,7 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4108
4668
  depth: 1,
4109
4669
  consumed: false,
4110
4670
  pending: null,
4671
+ onHandled,
4111
4672
  timer: null
4112
4673
  };
4113
4674
  _active = suppression;
@@ -4127,45 +4688,67 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4127
4688
  }
4128
4689
 
4129
4690
  // src/platform/reactNativeAdapter.ts
4130
- var deltaTracker = chunkSUMIABJK_js.createSnapshotDeltaTracker();
4691
+ var deltaTracker = chunkUZ2D4BVX_js.createSnapshotDeltaTracker();
4131
4692
  function resolveScreenMetadata() {
4132
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
4693
+ const activePath = chunkUZ2D4BVX_js.getActiveRouteNames();
4133
4694
  for (let i = activePath.length - 1; i >= 0; i--) {
4134
4695
  const name = activePath[i];
4135
- const meta = name ? chunkSUMIABJK_js.getScreenMetadata(name) : void 0;
4696
+ const meta = name ? chunkUZ2D4BVX_js.getScreenMetadata(name) : void 0;
4136
4697
  if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
4137
4698
  return meta;
4138
4699
  }
4139
4700
  }
4140
- const screen = chunkSUMIABJK_js.getCurrentScreen();
4141
- return screen ? chunkSUMIABJK_js.getScreenMetadata(screen) : void 0;
4701
+ const screen = chunkUZ2D4BVX_js.getCurrentScreen();
4702
+ return screen ? chunkUZ2D4BVX_js.getScreenMetadata(screen) : void 0;
4142
4703
  }
4143
4704
  function buildAgentContext(extras = {}) {
4144
- if (extras.newMission === true) deltaTracker.reset();
4705
+ if (extras.newMission === true) {
4706
+ deltaTracker.reset();
4707
+ for (const entry of chunkUZ2D4BVX_js.listRegistry.snapshot()) entry.exploration?.reset();
4708
+ }
4145
4709
  const context = {};
4146
4710
  context.platform = "react-native";
4147
- const screen = chunkSUMIABJK_js.getCurrentScreen();
4711
+ context.missionProtocol = 1;
4712
+ context.deviceLocale = detectDeviceLocale() ?? "en";
4713
+ const screen = chunkUZ2D4BVX_js.getCurrentScreen();
4148
4714
  if (screen) context.currentScreen = screen;
4149
- const navigationState = chunkSUMIABJK_js.getNavigationStateSnapshot();
4715
+ const navigationState = chunkUZ2D4BVX_js.getNavigationStateSnapshot();
4150
4716
  if (navigationState) context.navigationState = navigationState;
4151
4717
  const screenMeta = resolveScreenMetadata();
4152
4718
  if (screenMeta) context.screenMetadata = screenMeta;
4153
4719
  try {
4154
4720
  const snapshot = captureSnapshot();
4721
+ for (const list of snapshot.lists) {
4722
+ const memory = list.id ? chunkUZ2D4BVX_js.listRegistry.get(list.id)?.exploration : void 0;
4723
+ if (!memory) continue;
4724
+ memory.observe(list.items);
4725
+ list.exploration = memory.snapshot();
4726
+ }
4155
4727
  const delta = deltaTracker.observe(snapshot);
4156
4728
  if (delta) snapshot.delta = delta;
4157
4729
  context.snapshot = snapshot;
4158
4730
  } catch (err) {
4159
- chunkSUMIABJK_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
4731
+ chunkUZ2D4BVX_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
4160
4732
  }
4161
- const registry = chunkSUMIABJK_js.componentRegistry.snapshot();
4733
+ const registry = chunkUZ2D4BVX_js.componentRegistry.snapshot();
4162
4734
  const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
4163
4735
  if (filtered.length > 0) context.registeredComponents = filtered;
4164
- const registeredLists = chunkSUMIABJK_js.listRegistry.snapshot();
4736
+ const registeredLists = chunkUZ2D4BVX_js.listRegistry.snapshot();
4165
4737
  if (registeredLists.length > 0) {
4166
- context.registeredLists = registeredLists.map(
4167
- ({ scrollToIndex, scrollToOffset, getScrollMetrics, dataPreview, ...rest }) => rest
4738
+ const snapshot = context.snapshot;
4739
+ const activeIds = new Set(
4740
+ [...snapshot?.lists ?? [], ...snapshot?.scrollables ?? []].map((l) => l.id)
4168
4741
  );
4742
+ context.registeredLists = registeredLists.filter((entry) => activeIds.has(entry.id)).map(({ id, kind, component, itemCount, totalItemCount, label, refreshing, empty }) => ({
4743
+ id,
4744
+ kind,
4745
+ component,
4746
+ itemCount,
4747
+ totalItemCount,
4748
+ label,
4749
+ refreshing,
4750
+ empty
4751
+ }));
4169
4752
  }
4170
4753
  if (extras.loadingPending === true) context.loadingPending = true;
4171
4754
  return context;
@@ -4175,30 +4758,31 @@ async function settleTurn(input) {
4175
4758
  let loadingPending = false;
4176
4759
  const { turnActions, pressedComponentId: pressedId, navigateTargetScreen } = input;
4177
4760
  const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
4761
+ const effectById = new Map(input.results.map((r) => [r.actionId, r.effect]));
4178
4762
  const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
4179
4763
  const pressedAction = turnActions.find(
4180
4764
  (a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
4181
4765
  );
4182
4766
  const hints = resolveActionHints(
4183
- chunkSUMIABJK_js.getCurrentScreen(),
4767
+ chunkUZ2D4BVX_js.getCurrentScreen(),
4184
4768
  pressedId,
4185
4769
  pressedAction?.payload
4186
4770
  );
4187
4771
  const capSource = typeof hints?.asyncBudgetMs === "number" && hints.asyncBudgetMs > 0 ? " (app-declared)" : hints?.isAsyncTrigger ? " (mcp-inferred)" : "";
4188
4772
  if (input.hadNavigate) {
4189
- const settle = await chunkSUMIABJK_js.waitForScreenSettle({
4773
+ const settle = await chunkUZ2D4BVX_js.waitForScreenSettle({
4190
4774
  expectingChange: true,
4191
4775
  fromScreen: input.preNavigateScreen ?? null,
4192
4776
  fromSignature: input.preNavigateSignature ?? null,
4193
4777
  targetScreen: navigateTargetScreen,
4194
4778
  maxMs: 3500
4195
4779
  });
4196
- chunkSUMIABJK_js.appilotsDebugLog(
4780
+ chunkUZ2D4BVX_js.appilotsDebugLog(
4197
4781
  `settleTurn: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
4198
4782
  );
4199
- const navigationMoved = settle.transitioned || chunkSUMIABJK_js.screenDepartedBaseline(input.preNavigateScreen ?? null, input.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkSUMIABJK_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
4783
+ const navigationMoved = settle.transitioned || chunkUZ2D4BVX_js.screenDepartedBaseline(input.preNavigateScreen ?? null, input.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkUZ2D4BVX_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
4200
4784
  if (!navigationMoved) {
4201
- chunkSUMIABJK_js.appilotsDebugWarn(
4785
+ chunkUZ2D4BVX_js.appilotsDebugWarn(
4202
4786
  `tool-without-effect: navigate emitted but screen did not change (stayed at "${input.preNavigateScreen ?? "unknown"}", waitedMs=${settle.waitedMs}). Likely causes: target screenName missing from MCP doc, nested-nav path absent, or React Navigation rejected the route.`
4203
4787
  );
4204
4788
  for (const [actionId, type] of typeById) {
@@ -4206,50 +4790,51 @@ async function settleTurn(input) {
4206
4790
  }
4207
4791
  }
4208
4792
  const postNavigateCapMs = resolvePostNavigateCapMs(hints);
4209
- const loadSettle = await chunkSUMIABJK_js.waitForLoadingSettle({
4793
+ const loadSettle = await chunkUZ2D4BVX_js.waitForLoadingSettle({
4210
4794
  fromScreen: settle.screen ?? null,
4211
4795
  maxMs: postNavigateCapMs
4212
4796
  });
4213
- chunkSUMIABJK_js.appilotsDebugLog(
4797
+ chunkUZ2D4BVX_js.appilotsDebugLog(
4214
4798
  `settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${postNavigateCapMs}${capSource}`
4215
4799
  );
4216
4800
  if (loadSettle.loadingPending) loadingPending = true;
4217
4801
  } else {
4218
4802
  const settleCapMs = resolveSettleCapMs(hints);
4219
4803
  const busyMaxMs = resolveBusyCeilingMs(hints);
4220
- const loadSettle = await chunkSUMIABJK_js.waitForLoadingSettle({
4804
+ const loadSettle = await chunkUZ2D4BVX_js.waitForLoadingSettle({
4221
4805
  pressedComponentId: pressedId,
4222
- fromScreen: chunkSUMIABJK_js.getCurrentScreen(),
4806
+ fromScreen: chunkUZ2D4BVX_js.getCurrentScreen(),
4223
4807
  maxMs: settleCapMs,
4224
4808
  ...busyMaxMs !== void 0 ? { busyMaxMs } : {}
4225
4809
  });
4226
- chunkSUMIABJK_js.appilotsDebugLog(
4810
+ chunkUZ2D4BVX_js.appilotsDebugLog(
4227
4811
  `settleTurn: post-action loading settle \u2014 pressedId="${pressedId ?? ""}" settled=${loadSettle.settled} transitioned=${loadSettle.transitioned} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${settleCapMs}${capSource}${busyMaxMs !== void 0 ? ` busyCap=${busyMaxMs}` : ""}`
4228
4812
  );
4229
4813
  if (loadSettle.loadingPending) loadingPending = true;
4230
4814
  const listPressActions = turnActions.filter((action) => {
4231
- const target = chunkSUMIABJK_js.actionPressTargetId(action);
4232
- return target ? chunkSUMIABJK_js.isListItemPressTarget(target) : false;
4815
+ const target = chunkUZ2D4BVX_js.actionPressTargetId(action);
4816
+ return target ? chunkUZ2D4BVX_js.isListItemPressTarget(target) : false;
4233
4817
  });
4234
4818
  if (listPressActions.length > 0) {
4235
- const baselineFingerprint = chunkSUMIABJK_js.probeLoadingState(pressedId, chunkSUMIABJK_js.getCurrentScreen()).fingerprint;
4236
- const postPressSettle = await chunkSUMIABJK_js.waitForScreenSettle({
4819
+ const baselineFingerprint = chunkUZ2D4BVX_js.probeLoadingState(pressedId, chunkUZ2D4BVX_js.getCurrentScreen()).fingerprint;
4820
+ const postPressSettle = await chunkUZ2D4BVX_js.waitForScreenSettle({
4237
4821
  expectingChange: true,
4238
4822
  fromScreen: input.preNavigateScreen ?? null,
4239
4823
  fromSignature: input.preNavigateSignature ?? null,
4240
4824
  maxMs: 2500
4241
4825
  });
4242
- await chunkSUMIABJK_js.waitForLoadingSettle({
4826
+ await chunkUZ2D4BVX_js.waitForLoadingSettle({
4243
4827
  pressedComponentId: pressedId,
4244
- fromScreen: chunkSUMIABJK_js.getCurrentScreen(),
4828
+ fromScreen: chunkUZ2D4BVX_js.getCurrentScreen(),
4245
4829
  maxMs: 4e3
4246
4830
  });
4247
- const afterFingerprint = chunkSUMIABJK_js.probeLoadingState(pressedId, chunkSUMIABJK_js.getCurrentScreen()).fingerprint;
4248
- chunkSUMIABJK_js.appilotsDebugLog(
4831
+ const afterFingerprint = chunkUZ2D4BVX_js.probeLoadingState(pressedId, chunkUZ2D4BVX_js.getCurrentScreen()).fingerprint;
4832
+ chunkUZ2D4BVX_js.appilotsDebugLog(
4249
4833
  `settleTurn: post-list-press settle \u2014 screen="${postPressSettle.screen}" transitioned=${postPressSettle.transitioned} timedOut=${postPressSettle.timedOut} waitedMs=${postPressSettle.waitedMs}`
4250
4834
  );
4251
4835
  if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
4252
4836
  for (const action of listPressActions) {
4837
+ if (effectById.get(action.id) === "changed") continue;
4253
4838
  if (successById.get(action.id)) {
4254
4839
  toolWithoutEffectIds.add(action.id);
4255
4840
  }
@@ -4261,46 +4846,68 @@ async function settleTurn(input) {
4261
4846
  }
4262
4847
  var reactNativeChatAdapter = {
4263
4848
  buildContext: buildAgentContext,
4264
- getCurrentScreen: chunkSUMIABJK_js.getCurrentScreen,
4265
- getCurrentScreenSignature: chunkSUMIABJK_js.getCurrentScreenSignature,
4849
+ getCurrentScreen: chunkUZ2D4BVX_js.getCurrentScreen,
4850
+ getCurrentScreenSignature: chunkUZ2D4BVX_js.getCurrentScreenSignature,
4266
4851
  settleTurn
4267
4852
  };
4268
4853
  function createReactNativeActionRunner(getOptions) {
4269
4854
  return {
4855
+ buildMissionContext: () => reactNativeChatAdapter.buildContext(),
4270
4856
  async execute(action, { confirmedDestructive }) {
4271
- const { permissions, emit, navigationRef, suppressNativeConfirm } = getOptions();
4272
- const navRef = navigationRef?.current ? navigationRef : { current: chunkSUMIABJK_js.getNavigationRef() };
4273
- return runWithConfirmedDestructiveContext(
4857
+ const { permissions, emit: emit2, navigationRef, suppressNativeConfirm } = getOptions();
4858
+ const navRef = navigationRef?.current ? navigationRef : { current: chunkUZ2D4BVX_js.getNavigationRef() };
4859
+ let receipt;
4860
+ let terminal;
4861
+ const result = await runWithConfirmedDestructiveContext(
4274
4862
  confirmedDestructive && suppressNativeConfirm !== false,
4275
4863
  reactNative.Alert,
4276
4864
  () => executeAction(action, {
4277
4865
  navigationRef: navRef,
4278
4866
  permissions,
4279
- emit
4280
- })
4867
+ emit: (event) => {
4868
+ if (confirmedDestructive && (event.type === "agent:action:complete" || event.type === "agent:action:error"))
4869
+ terminal = event;
4870
+ else emit2(event);
4871
+ }
4872
+ }),
4873
+ (handled) => {
4874
+ receipt = handled;
4875
+ }
4281
4876
  );
4877
+ const failed = receipt?.handlerCompleted === false;
4878
+ if (terminal)
4879
+ emit2({
4880
+ ...terminal,
4881
+ type: failed ? "agent:action:error" : terminal.type,
4882
+ data: {
4883
+ ...terminal.data,
4884
+ ...receipt ? { nativeConfirmation: receipt } : {},
4885
+ ...failed ? { success: false, error: "Native confirmation callback failed" } : {}
4886
+ }
4887
+ });
4888
+ return failed ? { ...result, success: false, error: "Native confirmation callback failed" } : result;
4282
4889
  },
4283
- getCurrentScreen: chunkSUMIABJK_js.getCurrentScreen,
4284
- getCurrentScreenSignature: chunkSUMIABJK_js.getCurrentScreenSignature,
4890
+ getCurrentScreen: chunkUZ2D4BVX_js.getCurrentScreen,
4891
+ getCurrentScreenSignature: chunkUZ2D4BVX_js.getCurrentScreenSignature,
4285
4892
  getScreenActionsMetadata(screen) {
4286
- return chunkSUMIABJK_js.getScreenMetadata(screen)?.actions;
4893
+ return chunkUZ2D4BVX_js.getScreenMetadata(screen)?.actions;
4287
4894
  },
4288
- waitForScreenSettle: chunkSUMIABJK_js.waitForScreenSettle
4895
+ waitForScreenSettle: chunkUZ2D4BVX_js.waitForScreenSettle
4289
4896
  };
4290
4897
  }
4291
4898
 
4292
4899
  // src/hooks/useAppilotsChat.ts
4293
4900
  function useAppilotsChat(options = {}) {
4294
- const { client, emit, subscribe } = chunkSUMIABJK_js.useAppilotsContext();
4901
+ const { client, emit: emit2, subscribe } = chunkUZ2D4BVX_js.useAppilotsContext();
4295
4902
  const machine = React.useMemo(
4296
- () => new chunkSUMIABJK_js.ChatSessionMachine(
4297
- { client, adapter: reactNativeChatAdapter, emit, warn: chunkSUMIABJK_js.appilotsDebugWarn },
4903
+ () => new chunkUZ2D4BVX_js.ChatSessionMachine(
4904
+ { client, adapter: reactNativeChatAdapter, emit: emit2, warn: chunkUZ2D4BVX_js.appilotsDebugWarn },
4298
4905
  options
4299
4906
  ),
4300
4907
  // A new machine per client/provider instance — options are pushed in
4301
4908
  // below so changing copy never resets the transcript.
4302
4909
  // eslint-disable-next-line react-hooks/exhaustive-deps
4303
- [client, emit]
4910
+ [client, emit2]
4304
4911
  );
4305
4912
  const optionsRef = React.useRef(options);
4306
4913
  optionsRef.current = options;
@@ -4308,6 +4915,14 @@ function useAppilotsChat(options = {}) {
4308
4915
  const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
4309
4916
  React.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
4310
4917
  React.useEffect(() => () => machine.dispose(), [machine]);
4918
+ React.useEffect(() => {
4919
+ void machine.restoreMission();
4920
+ const subscription = reactNative.AppState?.addEventListener?.("change", (next) => {
4921
+ if (next !== "active" && machine.getState().mission?.status === "running")
4922
+ void machine.pauseMission();
4923
+ });
4924
+ return () => subscription?.remove();
4925
+ }, [machine]);
4311
4926
  const requestHuman = React.useCallback(
4312
4927
  (reason) => machine.requestHuman(reason),
4313
4928
  [machine]
@@ -4317,7 +4932,13 @@ function useAppilotsChat(options = {}) {
4317
4932
  const clearMessages = React.useCallback(() => machine.clearMessages(), [machine]);
4318
4933
  const clearError = React.useCallback(() => machine.clearError(), [machine]);
4319
4934
  return {
4935
+ mission: state.mission,
4936
+ pauseMission: () => machine.pauseMission(),
4937
+ resumeMission: () => machine.resumeMission(),
4938
+ cancelMission: () => machine.cancelMission(),
4939
+ hasStartedActing: state.hasStartedActing,
4320
4940
  messages: state.messages,
4941
+ replyLocale: state.replyLocale,
4321
4942
  isLoading: state.isLoading,
4322
4943
  loadingStatusKey: state.loadingStatusKey,
4323
4944
  error: state.error,
@@ -4330,39 +4951,33 @@ function useAppilotsChat(options = {}) {
4330
4951
  clearError
4331
4952
  };
4332
4953
  }
4333
- var DEFAULT_PERMISSIONS2 = {
4334
- canNavigate: true,
4335
- canFillForms: true,
4336
- canInteractUI: true,
4337
- canSubmitForms: true
4338
- };
4339
4954
  function useAppilotsActions(options = {}) {
4340
- const { client, subscribe, config, emit } = chunkSUMIABJK_js.useAppilotsContext();
4955
+ const { client, subscribe, config, emit: emit2 } = chunkUZ2D4BVX_js.useAppilotsContext();
4341
4956
  const { navigationRef, autoExecute = false } = options;
4342
4957
  const runnerOptionsRef = React.useRef({
4343
- permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
4344
- emit,
4958
+ permissions: chunkUZ2D4BVX_js.resolveAgentPermissions(config.permissions),
4959
+ emit: emit2,
4345
4960
  navigationRef,
4346
4961
  suppressNativeConfirm: config.suppressNativeConfirm
4347
4962
  });
4348
4963
  runnerOptionsRef.current = {
4349
- permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
4350
- emit,
4964
+ permissions: chunkUZ2D4BVX_js.resolveAgentPermissions(config.permissions),
4965
+ emit: emit2,
4351
4966
  navigationRef,
4352
4967
  suppressNativeConfirm: config.suppressNativeConfirm
4353
4968
  };
4354
4969
  const machine = React.useMemo(
4355
- () => new chunkSUMIABJK_js.ActionQueueMachine(
4970
+ () => new chunkUZ2D4BVX_js.ActionQueueMachine(
4356
4971
  {
4357
4972
  client,
4358
4973
  adapter: createReactNativeActionRunner(() => runnerOptionsRef.current),
4359
- emit,
4360
- warn: chunkSUMIABJK_js.appilotsDebugWarn
4974
+ emit: emit2,
4975
+ warn: chunkUZ2D4BVX_js.appilotsDebugWarn
4361
4976
  },
4362
4977
  { autoExecute }
4363
4978
  ),
4364
4979
  // eslint-disable-next-line react-hooks/exhaustive-deps
4365
- [client, emit]
4980
+ [client, emit2]
4366
4981
  );
4367
4982
  machine.setOptions({ autoExecute });
4368
4983
  const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
@@ -4414,7 +5029,7 @@ function shouldShowSuggestedPrompts(args) {
4414
5029
 
4415
5030
  // src/hooks/useSuggestedPrompts.ts
4416
5031
  function useSuggestedPrompts(options) {
4417
- const { client } = chunkSUMIABJK_js.useAppilotsContext();
5032
+ const { client } = chunkUZ2D4BVX_js.useAppilotsContext();
4418
5033
  const { enabled, limit = 4 } = options;
4419
5034
  const [prompts, setPrompts] = React.useState([]);
4420
5035
  const [isLoading, setIsLoading] = React.useState(false);
@@ -4424,8 +5039,8 @@ function useSuggestedPrompts(options) {
4424
5039
  if (!enabled) return;
4425
5040
  const requestId = ++requestIdRef.current;
4426
5041
  let cancelled = false;
4427
- const screen = chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
4428
- const localDev = screen ? (chunkSUMIABJK_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
5042
+ const screen = chunkUZ2D4BVX_js.getCurrentScreen() ?? void 0;
5043
+ const localDev = screen ? (chunkUZ2D4BVX_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
4429
5044
  text,
4430
5045
  source: "dev-defined"
4431
5046
  })) : [];
@@ -4439,7 +5054,7 @@ function useSuggestedPrompts(options) {
4439
5054
  if (cancelled || requestIdRef.current !== requestId) return;
4440
5055
  setPrompts(mergePromptSources(localDev, data, limit));
4441
5056
  }).catch((err) => {
4442
- chunkSUMIABJK_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
5057
+ chunkUZ2D4BVX_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
4443
5058
  }).finally(() => {
4444
5059
  if (cancelled || requestIdRef.current !== requestId) return;
4445
5060
  setIsLoading(false);
@@ -4450,11 +5065,11 @@ function useSuggestedPrompts(options) {
4450
5065
  }, [client, enabled, limit, refreshTick]);
4451
5066
  React.useEffect(() => {
4452
5067
  if (!enabled) return;
4453
- let lastScreen = chunkSUMIABJK_js.getCurrentScreen();
5068
+ let lastScreen = chunkUZ2D4BVX_js.getCurrentScreen();
4454
5069
  const interval = setInterval(() => {
4455
- const current = chunkSUMIABJK_js.getCurrentScreen();
4456
- if (current !== lastScreen) {
4457
- lastScreen = current;
5070
+ const current2 = chunkUZ2D4BVX_js.getCurrentScreen();
5071
+ if (current2 !== lastScreen) {
5072
+ lastScreen = current2;
4458
5073
  setRefreshTick((t) => t + 1);
4459
5074
  }
4460
5075
  }, 800);
@@ -4467,22 +5082,22 @@ function useSuggestedPrompts(options) {
4467
5082
  };
4468
5083
  }
4469
5084
  function useAppilotsNavigation() {
4470
- const { emit } = chunkSUMIABJK_js.useAppilotsContext();
5085
+ const { emit: emit2 } = chunkUZ2D4BVX_js.useAppilotsContext();
4471
5086
  const [currentScreen, setCurrentScreenState] = React.useState(null);
4472
5087
  const [navigationHistory, setNavigationHistory] = React.useState([]);
4473
5088
  const navigationRef = React.useRef(null);
4474
5089
  const setCurrentScreen2 = React.useCallback(
4475
5090
  (screenName) => {
4476
5091
  setCurrentScreenState(screenName);
4477
- chunkSUMIABJK_js.setCurrentScreen(screenName);
5092
+ chunkUZ2D4BVX_js.setCurrentScreen(screenName);
4478
5093
  setNavigationHistory((prev) => [...prev, screenName]);
4479
- emit({
5094
+ emit2({
4480
5095
  type: "navigation:change",
4481
5096
  timestamp: Date.now(),
4482
5097
  data: { screenName }
4483
5098
  });
4484
5099
  },
4485
- [emit]
5100
+ [emit2]
4486
5101
  );
4487
5102
  React.useEffect(() => {
4488
5103
  const nav = navigationRef.current;
@@ -4505,7 +5120,7 @@ function useAppilotsNavigation() {
4505
5120
 
4506
5121
  // src/hooks/useAppilots.ts
4507
5122
  function useAppilots() {
4508
- const { config, client } = chunkSUMIABJK_js.useAppilotsContext();
5123
+ const { config, client } = chunkUZ2D4BVX_js.useAppilotsContext();
4509
5124
  const chat = useAppilotsChat();
4510
5125
  const navigation = useAppilotsNavigation();
4511
5126
  const actions = useAppilotsActions();
@@ -4532,9 +5147,14 @@ function useAppilots() {
4532
5147
  rejectAction: actions.rejectAction
4533
5148
  };
4534
5149
  }
5150
+ function useAppilotsElementProps(id) {
5151
+ return React.useMemo(() => ({ testID: id }), [id]);
5152
+ }
5153
+
5154
+ // src/hooks/useAppilotsField.ts
4535
5155
  function useAppilotsField(id, options) {
4536
5156
  const { value, onChangeText, ref, fieldType, label, screen } = options;
4537
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5157
+ const registry = chunkUZ2D4BVX_js.useResolvedRegistry();
4538
5158
  const valueRef = React.useRef(value);
4539
5159
  const onChangeRef = React.useRef(onChangeText);
4540
5160
  valueRef.current = value;
@@ -4559,10 +5179,11 @@ function useAppilotsField(id, options) {
4559
5179
  registry.unregister(id);
4560
5180
  };
4561
5181
  }, [id, registry, getValue, setValue, focus, ref, fieldType, label, screen]);
5182
+ return useAppilotsElementProps(id);
4562
5183
  }
4563
5184
  function useAppilotsTarget(id, options) {
4564
5185
  const { onPress, onLongPress, onScrollTo, label, screen } = options;
4565
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5186
+ const registry = chunkUZ2D4BVX_js.useResolvedRegistry();
4566
5187
  const onPressRef = React.useRef(onPress);
4567
5188
  const onLongPressRef = React.useRef(onLongPress);
4568
5189
  const onScrollToRef = React.useRef(onScrollTo);
@@ -4586,10 +5207,11 @@ function useAppilotsTarget(id, options) {
4586
5207
  registry.unregister(id);
4587
5208
  };
4588
5209
  }, [id, registry, press, longPress, scrollTo, onLongPress, onScrollTo, label, screen]);
5210
+ return useAppilotsElementProps(id);
4589
5211
  }
4590
5212
  function useAppilotsToggle(id, options) {
4591
5213
  const { value, onValueChange, label, screen } = options;
4592
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5214
+ const registry = chunkUZ2D4BVX_js.useResolvedRegistry();
4593
5215
  const valueRef = React.useRef(value);
4594
5216
  const onChangeRef = React.useRef(onValueChange);
4595
5217
  valueRef.current = value;
@@ -4609,10 +5231,11 @@ function useAppilotsToggle(id, options) {
4609
5231
  registry.unregister(id);
4610
5232
  };
4611
5233
  }, [id, registry, getValue, setValue, label, screen]);
5234
+ return useAppilotsElementProps(id);
4612
5235
  }
4613
5236
  function useAppilotsSlider(id, options) {
4614
5237
  const { value, onValueChange, min, max, step, label, screen } = options;
4615
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5238
+ const registry = chunkUZ2D4BVX_js.useResolvedRegistry();
4616
5239
  const valueRef = React.useRef(value);
4617
5240
  const onChangeRef = React.useRef(onValueChange);
4618
5241
  valueRef.current = value;
@@ -4635,16 +5258,30 @@ function useAppilotsSlider(id, options) {
4635
5258
  registry.unregister(id);
4636
5259
  };
4637
5260
  }, [id, registry, getValue, setValue, min, max, step, label, screen]);
5261
+ return useAppilotsElementProps(id);
4638
5262
  }
4639
5263
 
5264
+ exports.AppilotsI18nProvider = AppilotsI18nProvider;
5265
+ exports.REVEAL_MARGIN = REVEAL_MARGIN;
5266
+ exports.SPOTLIGHT_TTL_MS = SPOTLIGHT_TTL_MS;
4640
5267
  exports.appilotsSelfCheck = appilotsSelfCheck;
4641
5268
  exports.captureSnapshot = captureSnapshot;
5269
+ exports.detectDeviceLocale = detectDeviceLocale;
4642
5270
  exports.executeAction = executeAction;
5271
+ exports.getSpotlightMode = getSpotlightMode;
5272
+ exports.getSpotlightTarget = getSpotlightTarget;
5273
+ exports.offsetToReveal = offsetToReveal;
5274
+ exports.resolveLocale = resolveLocale;
5275
+ exports.revealTarget = revealTarget;
5276
+ exports.setSpotlightMode = setSpotlightMode;
5277
+ exports.setSpotlightTarget = setSpotlightTarget;
4643
5278
  exports.shouldShowSuggestedPrompts = shouldShowSuggestedPrompts;
5279
+ exports.subscribeSpotlight = subscribeSpotlight;
4644
5280
  exports.useAppilots = useAppilots;
4645
5281
  exports.useAppilotsActions = useAppilotsActions;
4646
5282
  exports.useAppilotsChat = useAppilotsChat;
4647
5283
  exports.useAppilotsField = useAppilotsField;
5284
+ exports.useAppilotsI18n = useAppilotsI18n;
4648
5285
  exports.useAppilotsNavigation = useAppilotsNavigation;
4649
5286
  exports.useAppilotsSlider = useAppilotsSlider;
4650
5287
  exports.useAppilotsTarget = useAppilotsTarget;