@appilots/sdk 0.11.3 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkSUMIABJK_js = require('./chunk-SUMIABJK.js');
3
+ var chunkQAZ4TN3Z_js = require('./chunk-QAZ4TN3Z.js');
4
4
  var React = require('react');
5
5
  var reactNative = require('react-native');
6
6
 
@@ -8,6 +8,277 @@ 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
+ stillWorking: "Ainda trabalhando\u2026 {seconds} s",
23
+ poweredBy: "Powered by Appilots",
24
+ approve: "Aprovar",
25
+ reject: "Rejeitar",
26
+ cancelledByUser: "Cancelado pelo usu\xE1rio",
27
+ confirmDestructiveTitle: "A\xE7\xE3o destrutiva",
28
+ confirmTitle: "Confirma\xE7\xE3o necess\xE1ria",
29
+ confirmMessage: 'Tem certeza que deseja "{action}"?',
30
+ confirmDestructiveApprove: "Sim, executar",
31
+ confirmApprove: "Confirmar",
32
+ confirmCancel: "Cancelar",
33
+ confirmThisAction: "esta a\xE7\xE3o",
34
+ confirmExpired: "Esta confirma\xE7\xE3o expirou. Pe\xE7a de novo ao assistente para continuar.",
35
+ unknownAction: "A\xE7\xE3o desconhecida",
36
+ somethingWentWrong: "Algo deu errado",
37
+ openChatA11y: "Abrir chat do assistente",
38
+ closeChatA11y: "Fechar chat do assistente",
39
+ stopGeneratingA11y: "Parar gera\xE7\xE3o",
40
+ talkToHumanA11y: "Falar com um atendente humano",
41
+ humanAgentLabel: "Atendente",
42
+ escalationRequested: "Certo! Chamei um atendente humano. Voc\xEA pode continuar usando o app normalmente enquanto isso.",
43
+ escalationConnected: "Um atendente entrou na conversa.",
44
+ escalationResolved: "O atendimento humano foi encerrado. Voltei a te ajudar por aqui.",
45
+ escalationOffer: "Se preferir, posso chamar uma pessoa para ajudar.",
46
+ escalationOfferChip: "Falar com um atendente",
47
+ escalationPendingBanner: "Aguardando um atendente...",
48
+ escalationActiveBanner: "Voc\xEA est\xE1 falando com um atendente",
49
+ pillWorking: "Trabalhando...",
50
+ pillExpandA11y: "Abrir a conversa do assistente",
51
+ pillStopA11y: "Parar o assistente",
52
+ missionPause: "Pausar",
53
+ missionResume: "Retomar tarefa",
54
+ missionCancel: "Cancelar tarefa",
55
+ missionPaused: "Pausada",
56
+ pillDone: "Pronto \u2014 toque para ver",
57
+ a11yAwaitingApproval: "O assistente precisa da sua confirma\xE7\xE3o para continuar.",
58
+ a11yTurnDone: "O assistente terminou.",
59
+ micStartA11y: "Segurar para falar",
60
+ micStopA11y: "Soltar para enviar",
61
+ micListening: "Ouvindo..."
62
+ };
63
+
64
+ // src/i18n/bundles/en.ts
65
+ var en = {
66
+ chatTitle: "Appilots Assistant",
67
+ clearButton: "Clear",
68
+ inputPlaceholder: "Type a message...",
69
+ emptyTitle: "How can I help?",
70
+ emptySubtitle: "I navigate, fill forms, and run actions in this app.",
71
+ thinking: "Thinking...",
72
+ statusAnalyzing: "Reading the screen...",
73
+ statusWaitingApp: "Waiting for the app...",
74
+ statusAdjusting: "Adjusting the plan...",
75
+ stillWorking: "Still working\u2026 {seconds} s",
76
+ poweredBy: "Powered by Appilots",
77
+ approve: "Approve",
78
+ reject: "Reject",
79
+ cancelledByUser: "Cancelled by user",
80
+ confirmDestructiveTitle: "Destructive action",
81
+ confirmTitle: "Confirmation needed",
82
+ confirmMessage: 'Are you sure you want to "{action}"?',
83
+ confirmDestructiveApprove: "Yes, do it",
84
+ confirmApprove: "Confirm",
85
+ confirmCancel: "Cancel",
86
+ confirmThisAction: "this action",
87
+ confirmExpired: "This confirmation expired. Ask the assistant again to continue.",
88
+ unknownAction: "Unknown action",
89
+ somethingWentWrong: "Something went wrong",
90
+ openChatA11y: "Open assistant chat",
91
+ closeChatA11y: "Close assistant chat",
92
+ stopGeneratingA11y: "Stop generating",
93
+ talkToHumanA11y: "Talk to a human agent",
94
+ humanAgentLabel: "Agent",
95
+ escalationRequested: "Done! I've called a human agent. You can keep using the app normally in the meantime.",
96
+ escalationConnected: "A human agent joined the conversation.",
97
+ escalationResolved: "The human handoff has ended. I'm back to help you here.",
98
+ escalationOffer: "If you prefer, I can bring in a person to help.",
99
+ escalationOfferChip: "Talk to a human",
100
+ escalationPendingBanner: "Waiting for a human agent...",
101
+ escalationActiveBanner: "You're talking to a human agent",
102
+ pillWorking: "Working...",
103
+ pillExpandA11y: "Open the assistant conversation",
104
+ pillStopA11y: "Stop the assistant",
105
+ missionPause: "Pause",
106
+ missionResume: "Resume task",
107
+ missionCancel: "Cancel task",
108
+ missionPaused: "Paused",
109
+ pillDone: "Done \u2014 tap to read",
110
+ a11yAwaitingApproval: "The assistant needs your confirmation to continue.",
111
+ a11yTurnDone: "The assistant finished.",
112
+ micStartA11y: "Hold to talk",
113
+ micStopA11y: "Release to send",
114
+ micListening: "Listening..."
115
+ };
116
+
117
+ // src/i18n/bundles/es.ts
118
+ var es = {
119
+ chatTitle: "Asistente Appilots",
120
+ clearButton: "Limpiar",
121
+ inputPlaceholder: "Escribe un mensaje...",
122
+ emptyTitle: "\xBFEn qu\xE9 puedo ayudarte?",
123
+ emptySubtitle: "Navego, relleno formularios y ejecuto acciones en esta app.",
124
+ thinking: "Pensando...",
125
+ statusAnalyzing: "Analizando la pantalla...",
126
+ statusWaitingApp: "Esperando a la app...",
127
+ statusAdjusting: "Ajustando el plan...",
128
+ stillWorking: "Sigo trabajando\u2026 {seconds} s",
129
+ poweredBy: "Hecho con Appilots",
130
+ approve: "Aprobar",
131
+ reject: "Rechazar",
132
+ cancelledByUser: "Cancelado por el usuario",
133
+ confirmDestructiveTitle: "Acci\xF3n destructiva",
134
+ confirmTitle: "Confirmaci\xF3n necesaria",
135
+ confirmMessage: '\xBFSeguro que quieres "{action}"?',
136
+ confirmDestructiveApprove: "S\xED, ejecutar",
137
+ confirmApprove: "Confirmar",
138
+ confirmCancel: "Cancelar",
139
+ confirmThisAction: "esta acci\xF3n",
140
+ confirmExpired: "Esta confirmaci\xF3n expir\xF3. Pide de nuevo al asistente para continuar.",
141
+ unknownAction: "Acci\xF3n desconocida",
142
+ somethingWentWrong: "Algo sali\xF3 mal",
143
+ openChatA11y: "Abrir chat del asistente",
144
+ closeChatA11y: "Cerrar chat del asistente",
145
+ stopGeneratingA11y: "Detener generaci\xF3n",
146
+ talkToHumanA11y: "Hablar con un agente humano",
147
+ humanAgentLabel: "Agente",
148
+ escalationRequested: "\xA1Listo! Llam\xE9 a un agente humano. Mientras tanto puedes seguir usando la app con normalidad.",
149
+ escalationConnected: "Un agente humano se uni\xF3 a la conversaci\xF3n.",
150
+ escalationResolved: "La atenci\xF3n humana termin\xF3. Vuelvo a ayudarte por aqu\xED.",
151
+ escalationOffer: "Si prefieres, puedo llamar a una persona para ayudarte.",
152
+ escalationOfferChip: "Hablar con un agente",
153
+ escalationPendingBanner: "Esperando a un agente...",
154
+ escalationActiveBanner: "Est\xE1s hablando con un agente humano",
155
+ pillWorking: "Trabajando...",
156
+ pillExpandA11y: "Abrir la conversaci\xF3n del asistente",
157
+ pillStopA11y: "Detener el asistente",
158
+ missionPause: "Pausar",
159
+ missionResume: "Reanudar tarea",
160
+ missionCancel: "Cancelar tarea",
161
+ missionPaused: "Pausada",
162
+ pillDone: "Listo \u2014 toca para ver",
163
+ a11yAwaitingApproval: "El asistente necesita tu confirmaci\xF3n para continuar.",
164
+ a11yTurnDone: "El asistente termin\xF3.",
165
+ micStartA11y: "Mantener para hablar",
166
+ micStopA11y: "Soltar para enviar",
167
+ micListening: "Escuchando..."
168
+ };
169
+
170
+ // src/i18n/bundles/fr.ts
171
+ var fr = {
172
+ chatTitle: "Assistant Appilots",
173
+ clearButton: "Effacer",
174
+ inputPlaceholder: "\xC9crivez un message\u2026",
175
+ emptyTitle: "Comment puis-je vous aider ?",
176
+ emptySubtitle: "Je navigue, remplis les formulaires et effectue des actions dans cette application.",
177
+ thinking: "R\xE9flexion en cours\u2026",
178
+ statusAnalyzing: "Lecture de l\u2019\xE9cran\u2026",
179
+ statusWaitingApp: "En attente de l\u2019application\u2026",
180
+ statusAdjusting: "Ajustement du plan\u2026",
181
+ stillWorking: "Toujours en cours\u2026 {seconds} s",
182
+ poweredBy: "Propuls\xE9 par Appilots",
183
+ approve: "Approuver",
184
+ reject: "Refuser",
185
+ cancelledByUser: "Annul\xE9 par l\u2019utilisateur",
186
+ confirmDestructiveTitle: "Action destructive",
187
+ confirmTitle: "Confirmation requise",
188
+ confirmMessage: "Voulez-vous vraiment \xAB {action} \xBB ?",
189
+ confirmDestructiveApprove: "Oui, ex\xE9cuter",
190
+ confirmApprove: "Confirmer",
191
+ confirmCancel: "Annuler",
192
+ confirmThisAction: "cette action",
193
+ confirmExpired: "Cette confirmation a expir\xE9. Redemandez \xE0 l\u2019assistant pour continuer.",
194
+ unknownAction: "Action inconnue",
195
+ somethingWentWrong: "Une erreur est survenue",
196
+ openChatA11y: "Ouvrir la conversation avec l\u2019assistant",
197
+ closeChatA11y: "Fermer la conversation",
198
+ stopGeneratingA11y: "Arr\xEAter la g\xE9n\xE9ration",
199
+ talkToHumanA11y: "Parler \xE0 un conseiller",
200
+ humanAgentLabel: "Conseiller",
201
+ escalationRequested: "J\u2019ai contact\xE9 un conseiller. Vous pouvez continuer \xE0 utiliser l\u2019application en attendant.",
202
+ escalationConnected: "Un conseiller a rejoint la conversation.",
203
+ escalationResolved: "L\u2019intervention du conseiller est termin\xE9e. Je peux \xE0 nouveau vous aider.",
204
+ escalationOffer: "Si vous pr\xE9f\xE9rez, je peux faire appel \xE0 un conseiller.",
205
+ escalationOfferChip: "Parler \xE0 un conseiller",
206
+ escalationPendingBanner: "En attente d\u2019un conseiller\u2026",
207
+ escalationActiveBanner: "Vous discutez avec un conseiller",
208
+ pillWorking: "En cours\u2026",
209
+ pillExpandA11y: "Ouvrir la conversation avec l\u2019assistant",
210
+ pillStopA11y: "Arr\xEAter l\u2019assistant",
211
+ missionPause: "Mettre en pause",
212
+ missionResume: "Reprendre la t\xE2che",
213
+ missionCancel: "Annuler la t\xE2che",
214
+ missionPaused: "En pause",
215
+ pillDone: "Termin\xE9 \u2014 touchez pour lire",
216
+ a11yAwaitingApproval: "L\u2019assistant a besoin de votre confirmation pour continuer.",
217
+ a11yTurnDone: "L\u2019assistant a termin\xE9.",
218
+ micStartA11y: "Maintenez pour parler",
219
+ micStopA11y: "Rel\xE2chez pour envoyer",
220
+ micListening: "\xC9coute en cours\u2026"
221
+ };
222
+
223
+ // src/i18n/I18nProvider.tsx
224
+ var BUNDLES = {
225
+ "pt-BR": ptBR,
226
+ en,
227
+ es,
228
+ fr
229
+ };
230
+ var DEFAULT_LOCALE = "en";
231
+ function detectDeviceLocale() {
232
+ try {
233
+ let raw;
234
+ if (reactNative.Platform.OS === "ios") {
235
+ const manager = reactNative.NativeModules?.SettingsManager;
236
+ const settings = manager?.getConstants?.()?.settings ?? manager?.settings;
237
+ const languages = Array.isArray(settings?.AppleLanguages) ? settings.AppleLanguages : [];
238
+ for (const language of languages) {
239
+ const locale = chunkQAZ4TN3Z_js.normalizeAppilotsLocale(language);
240
+ if (locale) return locale;
241
+ }
242
+ raw = settings?.AppleLocale;
243
+ } else if (reactNative.Platform.OS === "android") {
244
+ const manager = reactNative.NativeModules?.I18nManager;
245
+ raw = manager?.getConstants?.()?.localeIdentifier ?? manager?.localeIdentifier;
246
+ }
247
+ if (!raw || typeof raw !== "string") return null;
248
+ return chunkQAZ4TN3Z_js.normalizeAppilotsLocale(raw) ?? null;
249
+ } catch {
250
+ return null;
251
+ }
252
+ }
253
+ function resolveLocale(prop) {
254
+ if (prop && BUNDLES[prop]) return prop;
255
+ const detected = detectDeviceLocale();
256
+ if (detected && BUNDLES[detected]) return detected;
257
+ return DEFAULT_LOCALE;
258
+ }
259
+ var I18nContext = React.createContext(null);
260
+ function AppilotsI18nProvider({ locale, overrides, children }) {
261
+ const value = React.useMemo(() => {
262
+ const resolved = resolveLocale(locale ?? null);
263
+ const merged = overrides ? { ...BUNDLES[resolved], ...overrides } : BUNDLES[resolved];
264
+ return {
265
+ locale: resolved,
266
+ strings: merged,
267
+ t: (key) => merged[key]
268
+ };
269
+ }, [locale, overrides]);
270
+ return /* @__PURE__ */ React__default.default.createElement(I18nContext.Provider, { value }, children);
271
+ }
272
+ function useAppilotsI18n() {
273
+ const ctx = React.useContext(I18nContext);
274
+ if (ctx) return ctx;
275
+ return {
276
+ locale: DEFAULT_LOCALE,
277
+ strings: BUNDLES[DEFAULT_LOCALE],
278
+ t: (key) => BUNDLES[DEFAULT_LOCALE][key]
279
+ };
280
+ }
281
+
11
282
  // src/introspection/captureSnapshot.ts
12
283
  function normalizeSliderKey(value) {
13
284
  return (value ?? "").toLowerCase().replace(/^slider[-_]/, "");
@@ -23,9 +294,9 @@ function fiberSliderMatches(fiber, registryId, registryLabel) {
23
294
  function reconcileSliders(snapshot) {
24
295
  const fiberSliders = snapshot.sliders;
25
296
  const out = [];
26
- for (const { id, kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
297
+ for (const { id, kind } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
27
298
  if (kind !== "slider") continue;
28
- const entry = chunkSUMIABJK_js.componentRegistry.getSlider(id);
299
+ const entry = chunkQAZ4TN3Z_js.componentRegistry.getSlider(id);
29
300
  if (!entry) continue;
30
301
  const fiber = fiberSliders.find((s) => fiberSliderMatches(s, id, entry.label));
31
302
  const visible = !!fiber || typeof entry.screen === "string" && entry.screen === snapshot.route;
@@ -53,7 +324,7 @@ function normalizeFieldKey(value) {
53
324
  }
54
325
  function canonicalizeRegisteredFields(snapshot) {
55
326
  const claimed = /* @__PURE__ */ new Set();
56
- for (const { id, kind, label } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
327
+ for (const { id, kind, label } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
57
328
  if (kind !== "field") continue;
58
329
  if (snapshot.inputs.some((input) => input.id === id)) continue;
59
330
  const registryLabel = (label ?? "").toLowerCase();
@@ -72,7 +343,7 @@ function canonicalizeRegisteredFields(snapshot) {
72
343
  }
73
344
  }
74
345
  function mergeRegisteredLists(snapshot) {
75
- const registered = chunkSUMIABJK_js.listRegistry.snapshot();
346
+ const registered = chunkQAZ4TN3Z_js.listRegistry.snapshot();
76
347
  if (registered.length === 0) return;
77
348
  const byId = /* @__PURE__ */ new Map();
78
349
  for (const list of snapshot.lists) {
@@ -80,20 +351,35 @@ function mergeRegisteredLists(snapshot) {
80
351
  }
81
352
  for (const entry of registered) {
82
353
  if (entry.kind === "scroll") continue;
354
+ const existing = byId.get(entry.id);
355
+ if (!existing && !(entry.screen && entry.screen === snapshot.route)) continue;
83
356
  const metrics = entry.getScrollMetrics?.();
84
357
  const scrollFacts = metrics ? {
85
358
  scrollOffsetY: Math.max(0, Math.round(metrics.offset)),
86
359
  canScrollUp: metrics.offset > 8,
87
360
  canScrollDown: metrics.offset + metrics.visibleLength < metrics.contentLength - 8
88
361
  } : void 0;
89
- const existing = byId.get(entry.id);
90
362
  if (existing) {
91
363
  existing.itemCount = existing.itemCount ?? entry.itemCount;
364
+ existing.totalItemCount = existing.totalItemCount ?? entry.totalItemCount;
92
365
  existing.refreshing = existing.refreshing ?? entry.refreshing;
93
366
  existing.empty = existing.empty ?? entry.empty;
94
367
  existing.label = existing.label ?? entry.label;
95
368
  existing.source = existing.source ?? "auto-tracked";
96
369
  existing.visibleItemCount = existing.items.length;
370
+ const viewport = entry.measureViewport?.();
371
+ if (viewport && viewport.width > 0 && viewport.height > 0) {
372
+ let measured = 0;
373
+ let inViewport = 0;
374
+ for (const item of existing.items) {
375
+ const rect = chunkQAZ4TN3Z_js.rectForNode(item);
376
+ if (!rect) continue;
377
+ measured++;
378
+ 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;
379
+ if (item.onScreen) inViewport++;
380
+ }
381
+ if (measured === existing.items.length) existing.viewportItemCount = inViewport;
382
+ }
97
383
  if (entry.dataPreview && entry.dataPreview.length > 0) {
98
384
  existing.dataPreview = entry.dataPreview;
99
385
  }
@@ -110,6 +396,7 @@ function mergeRegisteredLists(snapshot) {
110
396
  containerType: entry.component,
111
397
  source: "registry",
112
398
  itemCount: entry.itemCount,
399
+ totalItemCount: entry.totalItemCount,
113
400
  visibleItemCount: 0,
114
401
  refreshing: entry.refreshing,
115
402
  empty: entry.empty,
@@ -121,7 +408,7 @@ function mergeRegisteredLists(snapshot) {
121
408
  }
122
409
  }
123
410
  function mergeRegisteredScrollables(snapshot) {
124
- const registered = chunkSUMIABJK_js.listRegistry.snapshot().filter((e) => e.kind === "scroll");
411
+ const registered = chunkQAZ4TN3Z_js.listRegistry.snapshot().filter((e) => e.kind === "scroll");
125
412
  if (registered.length === 0) return;
126
413
  const listsById = /* @__PURE__ */ new Map();
127
414
  for (const list of snapshot.lists) {
@@ -154,7 +441,7 @@ function mergeRegisteredScrollables(snapshot) {
154
441
  if (out.length > 0) snapshot.scrollables = out;
155
442
  }
156
443
  function mergeNativeDialog(snapshot) {
157
- const dialog = chunkSUMIABJK_js.getOpenNativeDialog();
444
+ const dialog = chunkQAZ4TN3Z_js.getOpenNativeDialog();
158
445
  if (!dialog) return;
159
446
  snapshot.nativeDialog = {
160
447
  id: dialog.id,
@@ -169,21 +456,58 @@ function mergeNativeDialog(snapshot) {
169
456
  }
170
457
  var MIN_FIBERS_FOR_BLINDNESS = 200;
171
458
  function recordBlindWalk() {
172
- const walk = chunkSUMIABJK_js.getLastWalkDiagnostics();
459
+ const walk = chunkQAZ4TN3Z_js.getLastWalkDiagnostics();
173
460
  if (!walk) return;
174
461
  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);
462
+ if (chunkQAZ4TN3Z_js.totalDetectorHits(walk.detectors) > 0) return;
463
+ chunkQAZ4TN3Z_js.recordIntrospectionFailure("walk-recognized-nothing", null);
464
+ }
465
+ function mergeRegisteredFieldValues(snapshot) {
466
+ const present = new Set(snapshot.inputs.map((i) => normalizeFieldKey(i.id)));
467
+ const onScreenIds = [
468
+ ...snapshot.buttons.map((b) => (b.id ?? "").toLowerCase()),
469
+ ...snapshot.toggles.map((t) => (t.id ?? "").toLowerCase())
470
+ ].filter(Boolean);
471
+ const onScreenLabels = new Set(
472
+ [...snapshot.buttons.map((b) => b.label), ...snapshot.texts].filter((l) => !!l).map((l) => l.toLowerCase())
473
+ );
474
+ for (const { id, kind, screen, label } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
475
+ if (kind !== "field") continue;
476
+ const key = normalizeFieldKey(id);
477
+ if (!key || present.has(key)) continue;
478
+ const entry = chunkQAZ4TN3Z_js.componentRegistry.getField(id);
479
+ if (!entry) continue;
480
+ const fieldType = entry.fieldType ?? "";
481
+ if (fieldType === "text" || fieldType === "") continue;
482
+ const declaresRoute = typeof screen === "string" && screen === snapshot.route;
483
+ if (screen && !declaresRoute && !chunkQAZ4TN3Z_js.getActiveRouteNames().includes(screen)) continue;
484
+ const idEvidence = onScreenIds.some((candidate) => candidate.split(/[^a-z0-9]+/).includes(key));
485
+ const labelEvidence = !!entry.label && onScreenLabels.has(entry.label.toLowerCase());
486
+ if (!declaresRoute && !idEvidence && !labelEvidence) continue;
487
+ let value;
488
+ try {
489
+ value = String(entry.getValue() ?? "");
490
+ } catch {
491
+ continue;
492
+ }
493
+ snapshot.inputs.push({
494
+ id,
495
+ label: entry.label ?? label,
496
+ value,
497
+ type: fieldType
498
+ });
499
+ present.add(key);
500
+ }
177
501
  }
178
502
  function captureSnapshot() {
179
- const root = chunkSUMIABJK_js.getFiberRoot();
503
+ const root = chunkQAZ4TN3Z_js.getFiberRoot();
180
504
  if (!root) {
181
- chunkSUMIABJK_js.appilotsDebugWarn(
505
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
182
506
  "captureSnapshot: fiber root not captured yet. Ensure <AppilotsProvider> has rendered before calling this."
183
507
  );
184
- chunkSUMIABJK_js.recordIntrospectionFailure("never-mounted", null);
508
+ chunkQAZ4TN3Z_js.recordIntrospectionFailure("never-mounted", null);
185
509
  return {
186
- route: chunkSUMIABJK_js.getCurrentScreen(),
510
+ route: chunkQAZ4TN3Z_js.getCurrentScreen(),
187
511
  texts: [],
188
512
  inputs: [],
189
513
  buttons: [],
@@ -197,9 +521,9 @@ function captureSnapshot() {
197
521
  };
198
522
  }
199
523
  const start = Date.now();
200
- const snapshot = chunkSUMIABJK_js.walkFiber(root);
524
+ const snapshot = chunkQAZ4TN3Z_js.walkFiber(root);
201
525
  recordBlindWalk();
202
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
526
+ const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
203
527
  const deepestRoute = activePath[activePath.length - 1];
204
528
  if (deepestRoute) snapshot.route = deepestRoute;
205
529
  mergeRegisteredLists(snapshot);
@@ -207,15 +531,16 @@ function captureSnapshot() {
207
531
  mergeNativeDialog(snapshot);
208
532
  reconcileSliders(snapshot);
209
533
  canonicalizeRegisteredFields(snapshot);
210
- chunkSUMIABJK_js.clampSnapshotToWireLimits(snapshot);
211
- const entries = chunkSUMIABJK_js.deriveInteractionElements(snapshot, { rectOf: chunkSUMIABJK_js.rectForNode });
534
+ mergeRegisteredFieldValues(snapshot);
535
+ chunkQAZ4TN3Z_js.clampSnapshotToWireLimits(snapshot);
536
+ const entries = chunkQAZ4TN3Z_js.deriveInteractionElements(snapshot, { rectOf: chunkQAZ4TN3Z_js.rectForNode });
212
537
  const rectById = new Map(
213
538
  entries.flatMap((entry) => entry.rect ? [[entry.id, entry.rect]] : [])
214
539
  );
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(
540
+ snapshot.elements = entries.map(chunkQAZ4TN3Z_js.toWireElement);
541
+ snapshot.choiceGroups = chunkQAZ4TN3Z_js.attachElementIdsToChoiceGroups(snapshot.choiceGroups, snapshot.elements);
542
+ chunkQAZ4TN3Z_js.clampSnapshotToWireLimits(snapshot);
543
+ chunkQAZ4TN3Z_js.elementRegistry.replaceAll(
219
544
  snapshot.elements.map((element) => {
220
545
  const rect = rectById.get(element.id);
221
546
  return rect ? { ...element, rect } : element;
@@ -227,10 +552,10 @@ function captureSnapshot() {
227
552
  (acc, l) => acc + (typeof l.itemCount === "number" ? l.itemCount : 0),
228
553
  0
229
554
  );
230
- chunkSUMIABJK_js.appilotsDebugLog(
555
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
231
556
  `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
557
  );
233
- chunkSUMIABJK_js.appilotsDebugLog(
558
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
234
559
  `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
560
  );
236
561
  return snapshot;
@@ -241,10 +566,10 @@ function registryCounts() {
241
566
  toggles: 0,
242
567
  sliders: 0,
243
568
  targets: 0,
244
- lists: chunkSUMIABJK_js.listRegistry.snapshot().length,
245
- elements: chunkSUMIABJK_js.elementRegistry.size
569
+ lists: chunkQAZ4TN3Z_js.listRegistry.snapshot().length,
570
+ elements: chunkQAZ4TN3Z_js.elementRegistry.size
246
571
  };
247
- for (const { kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
572
+ for (const { kind } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
248
573
  if (kind === "field") counts.fields++;
249
574
  else if (kind === "toggle") counts.toggles++;
250
575
  else if (kind === "slider") counts.sliders++;
@@ -253,26 +578,26 @@ function registryCounts() {
253
578
  return counts;
254
579
  }
255
580
  function appilotsSelfCheck() {
256
- const root = chunkSUMIABJK_js.getFiberRoot();
581
+ const root = chunkQAZ4TN3Z_js.getFiberRoot();
257
582
  const start = Date.now();
258
- if (root) chunkSUMIABJK_js.walkFiber(root);
583
+ if (root) chunkQAZ4TN3Z_js.walkFiber(root);
259
584
  const elapsedMs = Date.now() - start;
260
- const walk = chunkSUMIABJK_js.getLastWalkDiagnostics();
585
+ const walk = chunkQAZ4TN3Z_js.getLastWalkDiagnostics();
261
586
  return {
262
- sdkVersion: chunkSUMIABJK_js.SDK_VERSION,
587
+ sdkVersion: chunkQAZ4TN3Z_js.SDK_VERSION,
263
588
  reactVersion: React__default.default.version ?? null,
264
- route: chunkSUMIABJK_js.getCurrentScreen() || null,
265
- introspection: chunkSUMIABJK_js.getIntrospectionDiagnostics(),
266
- autoTracking: chunkSUMIABJK_js.getAutoTrackingState(),
589
+ route: chunkQAZ4TN3Z_js.getCurrentScreen() || null,
590
+ introspection: chunkQAZ4TN3Z_js.getIntrospectionDiagnostics(),
591
+ autoTracking: chunkQAZ4TN3Z_js.getAutoTrackingState(),
267
592
  walk: {
268
593
  visitedFibers: root ? walk?.visitedFibers ?? 0 : 0,
269
594
  skippedHidden: root ? walk?.skippedHidden ?? 0 : 0,
270
595
  elapsedMs
271
596
  },
272
- detectors: root ? walk?.detectors ?? chunkSUMIABJK_js.emptyDetectorCounts() : chunkSUMIABJK_js.emptyDetectorCounts(),
597
+ detectors: root ? walk?.detectors ?? chunkQAZ4TN3Z_js.emptyDetectorCounts() : chunkQAZ4TN3Z_js.emptyDetectorCounts(),
273
598
  registry: registryCounts(),
274
- nameMangling: chunkSUMIABJK_js.getNameManglingProbe(),
275
- geometry: { availability: chunkSUMIABJK_js.geometryAvailability(), ...chunkSUMIABJK_js.geometryStats() }
599
+ nameMangling: chunkQAZ4TN3Z_js.getNameManglingProbe(),
600
+ geometry: { availability: chunkQAZ4TN3Z_js.geometryAvailability(), ...chunkQAZ4TN3Z_js.geometryStats() }
276
601
  };
277
602
  }
278
603
 
@@ -285,7 +610,7 @@ function declaredState(props) {
285
610
  return typeof checked === "boolean" ? checked : void 0;
286
611
  }
287
612
  function isReactNativeSwitch(fiber) {
288
- return chunkSUMIABJK_js.getTypeName(fiber?.type) === "Switch" || chunkSUMIABJK_js.getTypeName(fiber?.elementType) === "Switch";
613
+ return chunkQAZ4TN3Z_js.getTypeName(fiber?.type) === "Switch" || chunkQAZ4TN3Z_js.getTypeName(fiber?.elementType) === "Switch";
289
614
  }
290
615
  var SWITCH_FLIP_HANDLERS = ["onValueChange", "onChange", "onPress"];
291
616
  function flipSwitchFiber(fiber, next) {
@@ -309,6 +634,11 @@ function flipSwitchFiber(fiber, next) {
309
634
  return { ok: true, via: handler.via };
310
635
  }
311
636
 
637
+ // src/introspection/positionalIdentity.ts
638
+ function isPositionalControlId(value) {
639
+ return /^(?:list-\d+-item-\d+-)?(?:btn|input|slider|toggle)-\d+$/i.test(value.trim());
640
+ }
641
+
312
642
  // src/introspection/findInteractive.ts
313
643
  function getTypeName2(type) {
314
644
  if (!type) return null;
@@ -383,7 +713,7 @@ function shouldSkipSubtree2(fiber) {
383
713
  const typeName = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
384
714
  if (typeName && SELF_REFERENTIAL_COMPONENTS.has(typeName)) return true;
385
715
  if (isAppilotsSkipMarked(props)) return true;
386
- if (chunkSUMIABJK_js.isModalFiber(fiber) && props.visible === false) return true;
716
+ if (chunkQAZ4TN3Z_js.isModalFiber(fiber) && props.visible === false) return true;
387
717
  if (matchesName(fiber, "Screen") && props.activityState === 0) return true;
388
718
  const style = props.style;
389
719
  if (style) {
@@ -393,9 +723,17 @@ function shouldSkipSubtree2(fiber) {
393
723
  }
394
724
  return false;
395
725
  }
396
- var normalize = chunkSUMIABJK_js.foldForCompare;
726
+ function isSecureInput(props) {
727
+ return !!props.secureTextEntry || chunkQAZ4TN3Z_js.isAppilotsSensitiveMarked(props);
728
+ }
729
+ var normalize = chunkQAZ4TN3Z_js.foldForCompare;
397
730
  function scoreMatchDetail(fiber, queryNorm, queryRaw) {
398
731
  const props = fiber.memoizedProps ?? {};
732
+ if (chunkQAZ4TN3Z_js.isSourceControlId(queryRaw)) {
733
+ const matches = chunkQAZ4TN3Z_js.sourceControlId(fiber) === queryRaw;
734
+ const disabled = props.disabled === true || props.accessibilityState?.disabled === true;
735
+ return { score: matches ? disabled ? 60 : 120 : 0, named: matches, disabled };
736
+ }
399
737
  const candidates = [];
400
738
  if (typeof props.testID === "string") candidates.push({ val: props.testID, weight: 100 });
401
739
  if (typeof props.accessibilityLabel === "string")
@@ -409,16 +747,22 @@ function scoreMatchDetail(fiber, queryNorm, queryRaw) {
409
747
  if (childText) candidates.push({ val: childText, weight: 80 });
410
748
  }
411
749
  let best = 0;
750
+ let exact = false;
412
751
  for (const { val, weight } of candidates) {
413
752
  const vNorm = normalize(val);
414
753
  if (!vNorm) continue;
415
- if (val === queryRaw) best = Math.max(best, weight + 20);
416
- else if (vNorm === queryNorm) best = Math.max(best, weight + 10);
417
- else if (queryNorm && (vNorm.includes(queryNorm) || queryNorm.includes(vNorm)))
754
+ if (val === queryRaw) {
755
+ best = Math.max(best, weight + 20);
756
+ exact = true;
757
+ } else if (vNorm === queryNorm) {
758
+ best = Math.max(best, weight + 10);
759
+ exact = true;
760
+ } else if (!isPositionalControlId(queryRaw) && queryNorm && (vNorm.includes(queryNorm) || queryNorm.includes(vNorm)))
418
761
  best = Math.max(best, weight - 20);
419
762
  }
763
+ if (!exact && isSecureInput(props)) best = 0;
420
764
  const named = best >= IDENTITY_MATCH_SCORE;
421
- const disabledProp = props.disabled === true;
765
+ const disabledProp = props.disabled === true || props.editable === false || props.readOnly === true;
422
766
  const disabledA11y = typeof props.accessibilityState === "object" && props.accessibilityState !== null && props.accessibilityState.disabled === true;
423
767
  if (best > 0 && disabledProp) {
424
768
  best = Math.max(1, best - 60);
@@ -428,12 +772,18 @@ function scoreMatchDetail(fiber, queryNorm, queryRaw) {
428
772
  }
429
773
  return { score: best, named, disabled: disabledProp || disabledA11y };
430
774
  }
775
+ var inputIdentities = /* @__PURE__ */ new WeakMap();
431
776
  function wrapTextInput(fiber) {
777
+ const identity = inputIdentities.get(fiber) ?? (fiber.alternate && inputIdentities.get(fiber.alternate)) ?? {};
778
+ inputIdentities.set(fiber, identity);
779
+ if (fiber.alternate) inputIdentities.set(fiber.alternate, identity);
432
780
  const getProps = () => fiber.memoizedProps ?? {};
433
781
  return {
434
782
  kind: "field",
783
+ controlIdentity: identity,
435
784
  label: getProps().accessibilityLabel ?? getProps().label ?? getProps().placeholder ?? getProps().testID,
436
785
  getValue: () => getProps().value,
786
+ finishEditing: () => chunkQAZ4TN3Z_js.endTextInputEditing(getProps()),
437
787
  setValue: (value) => {
438
788
  const { onChangeText, onChange } = getProps();
439
789
  if (typeof onChangeText === "function") {
@@ -468,7 +818,7 @@ function wrapSwitch(fiber) {
468
818
  // `accessibilityRole="switch"`) has only the former, and reporting
469
819
  // `false` for a control that is on is worse than reporting nothing:
470
820
  // the caller inverts this to decide where to move.
471
- getValue: () => chunkSUMIABJK_js.switchValue(getProps()),
821
+ getValue: () => chunkQAZ4TN3Z_js.switchValue(getProps()),
472
822
  setValue: (value) => {
473
823
  const boolVal = typeof value === "boolean" ? value : value === "true" || value === true;
474
824
  const flipped = flipSwitchFiber(fiber, boolVal);
@@ -514,18 +864,18 @@ function describeCandidate(fiber, kind) {
514
864
  const props = fiber?.memoizedProps ?? {};
515
865
  return props.testID ?? props.accessibilityLabel ?? props.placeholder ?? (kind === "target" ? findChildText(fiber) : void 0);
516
866
  }
517
- function isDescendantOf(fiber, ancestor) {
867
+ function isDescendantOf(fiber, ancestor, parents) {
518
868
  if (!fiber || !ancestor) return false;
519
- let node = fiber.return;
520
- for (let depth = 0; node && depth < 200; depth++, node = node.return) {
869
+ let node = parents.get(fiber);
870
+ for (let depth = 0; node && depth < 200; depth++, node = parents.get(node)) {
521
871
  if (node === ancestor) return true;
522
872
  }
523
873
  return false;
524
874
  }
525
875
  function findInteractiveByIdentifier(query, options = {}) {
526
- const root = chunkSUMIABJK_js.getFiberRoot();
876
+ const root = chunkQAZ4TN3Z_js.getFiberRoot();
527
877
  if (!root) {
528
- chunkSUMIABJK_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
878
+ chunkQAZ4TN3Z_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
529
879
  return null;
530
880
  }
531
881
  const queryNorm = normalize(query);
@@ -538,18 +888,20 @@ function findInteractiveByIdentifier(query, options = {}) {
538
888
  let bestDisabled = false;
539
889
  let tied = [];
540
890
  const visited = /* @__PURE__ */ new WeakSet();
891
+ const parents = /* @__PURE__ */ new WeakMap();
541
892
  const stack = [];
542
- if (root.child) stack.push(root.child);
893
+ if (root.child) stack.push({ fiber: root.child, parent: root });
543
894
  while (stack.length > 0) {
544
- const fiber = stack.pop();
895
+ const { fiber, parent } = stack.pop();
545
896
  if (!fiber || visited.has(fiber)) continue;
546
897
  visited.add(fiber);
547
- if (fiber.sibling) stack.push(fiber.sibling);
898
+ parents.set(fiber, parent);
899
+ if (fiber.sibling) stack.push({ fiber: fiber.sibling, parent });
548
900
  if (shouldSkipSubtree2(fiber)) continue;
549
901
  const props = fiber.memoizedProps ?? {};
550
902
  let kind = null;
551
903
  if (matchesName(fiber, "TextInput")) kind = "field";
552
- else if (chunkSUMIABJK_js.isSwitchLike(fiber, props)) kind = "toggle";
904
+ else if (chunkQAZ4TN3Z_js.isSwitchLike(fiber, props)) kind = "toggle";
553
905
  else if (isPressableTarget(fiber)) kind = "target";
554
906
  if (kind && (!options.kind || options.kind === kind)) {
555
907
  const detail = scoreMatchDetail(fiber, queryNorm, queryRaw);
@@ -558,7 +910,7 @@ function findInteractiveByIdentifier(query, options = {}) {
558
910
  if (score > bestScore) tied = [{ fiber, kind }];
559
911
  else if (score === bestScore) tied.push({ fiber, kind });
560
912
  }
561
- const beatsBest = score > bestScore || score > 0 && score === bestScore && isDescendantOf(fiber, bestFiber);
913
+ const beatsBest = score > bestScore || score > 0 && score === bestScore && isDescendantOf(fiber, bestFiber, parents);
562
914
  if (beatsBest) {
563
915
  bestScore = score;
564
916
  bestFiber = fiber;
@@ -567,14 +919,18 @@ function findInteractiveByIdentifier(query, options = {}) {
567
919
  bestId = describeCandidate(fiber, kind);
568
920
  if (kind === "field") bestHandle = wrapTextInput(fiber);
569
921
  else if (kind === "toggle") bestHandle = wrapSwitch(fiber);
570
- else bestHandle = wrapTouchable(fiber, findChildText(fiber));
922
+ else if (chunkQAZ4TN3Z_js.isSourceControlId(queryRaw)) {
923
+ const bound = chunkQAZ4TN3Z_js.sourceControlTarget(fiber);
924
+ if (!bound || bound.disabled) bestHandle = null;
925
+ else bestHandle = wrapTouchable(bound.fiber, findChildText(fiber));
926
+ } else bestHandle = wrapTouchable(fiber, findChildText(fiber));
571
927
  }
572
928
  }
573
929
  if (kind === "toggle") continue;
574
- if (fiber.child) stack.push(fiber.child);
930
+ if (fiber.child) stack.push({ fiber: fiber.child, parent: fiber });
575
931
  }
576
932
  if (bestHandle && bestScore < (options.minScore ?? 0)) {
577
- chunkSUMIABJK_js.appilotsDebugLog(
933
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
578
934
  `findInteractiveByIdentifier: query="${query}" \u2192 best match scored ${bestScore}, below the requested floor of ${options.minScore} \u2014 refusing it`
579
935
  );
580
936
  return null;
@@ -582,23 +938,146 @@ function findInteractiveByIdentifier(query, options = {}) {
582
938
  if (bestHandle) {
583
939
  const independent = tied.filter(
584
940
  (candidate) => !tied.some(
585
- (other) => other.fiber !== candidate.fiber && isDescendantOf(other.fiber, candidate.fiber)
941
+ (other) => other.fiber !== candidate.fiber && isDescendantOf(other.fiber, candidate.fiber, parents)
586
942
  )
587
943
  );
588
944
  bestHandle.matchCount = independent.length;
589
945
  bestHandle.named = bestNamed;
590
946
  bestHandle.disabled = bestDisabled;
947
+ const measured = bestFiber;
948
+ bestHandle.measure = () => chunkQAZ4TN3Z_js.rectOfFiber(measured);
591
949
  const candidates = independent.map(({ fiber, kind }) => describeCandidate(fiber, kind)).filter((id) => typeof id === "string" && id.length > 0).slice(0, 8);
592
950
  if (candidates.length > 0) bestHandle.matchCandidates = candidates;
593
- chunkSUMIABJK_js.appilotsDebugLog(
951
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
594
952
  `findInteractiveByIdentifier: query="${query}" \u2192 kind=${bestHandle.kind} label="${bestHandle.label ?? bestId}" score=${bestScore} named=${bestNamed} disabled=${bestDisabled} tied=${independent.length}`
595
953
  );
596
954
  } else {
597
- chunkSUMIABJK_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
955
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
598
956
  }
599
957
  return bestHandle;
600
958
  }
601
959
 
960
+ // src/introspection/spotlightTarget.ts
961
+ var listeners = /* @__PURE__ */ new Set();
962
+ var announcementListeners = /* @__PURE__ */ new Set();
963
+ var current = null;
964
+ var seq = 0;
965
+ var expiry = null;
966
+ var SPOTLIGHT_TTL_MS = 1200;
967
+ var mode = "off";
968
+ function setSpotlightMode(next) {
969
+ mode = next;
970
+ }
971
+ function getSpotlightMode() {
972
+ return mode;
973
+ }
974
+ function emit() {
975
+ for (const listener of listeners) listener(current);
976
+ }
977
+ function setSpotlightTarget(rect, label, verb) {
978
+ if (label && verb) for (const listener of announcementListeners) listener(label, verb);
979
+ if (expiry) {
980
+ clearTimeout(expiry);
981
+ expiry = null;
982
+ }
983
+ if (!rect) {
984
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
985
+ `setSpotlightTarget: cleared${label ? ` (was about to mark "${label}")` : ""}`
986
+ );
987
+ if (current === null) return;
988
+ current = null;
989
+ emit();
990
+ return;
991
+ }
992
+ current = { rect, label, seq: ++seq };
993
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
994
+ `setSpotlightTarget: seq=${current.seq} label="${label ?? ""}" rect=${Math.round(rect.x)},${Math.round(rect.y)} ${Math.round(rect.width)}x${Math.round(rect.height)}`
995
+ );
996
+ emit();
997
+ expiry = setTimeout(() => {
998
+ expiry = null;
999
+ current = null;
1000
+ emit();
1001
+ }, SPOTLIGHT_TTL_MS);
1002
+ }
1003
+ function getSpotlightTarget() {
1004
+ return current;
1005
+ }
1006
+ function subscribeSpotlight(listener) {
1007
+ listeners.add(listener);
1008
+ return () => {
1009
+ listeners.delete(listener);
1010
+ };
1011
+ }
1012
+ function subscribeSpotlightAnnouncement(listener) {
1013
+ announcementListeners.add(listener);
1014
+ return () => {
1015
+ announcementListeners.delete(listener);
1016
+ };
1017
+ }
1018
+
1019
+ // src/introspection/scrollIntoView.ts
1020
+ var REVEAL_MARGIN = 24;
1021
+ function offsetToReveal({ rect, viewport, metrics }) {
1022
+ const maxOffset = Math.max(0, metrics.contentLength - metrics.visibleLength);
1023
+ const viewTop = viewport.top + REVEAL_MARGIN;
1024
+ const viewBottom = viewport.top + viewport.height - REVEAL_MARGIN;
1025
+ const tallerThanViewport = rect.height > viewport.height - REVEAL_MARGIN * 2;
1026
+ let delta;
1027
+ if (tallerThanViewport) {
1028
+ if (rect.y >= viewTop && rect.y <= viewBottom) return null;
1029
+ delta = rect.y - viewTop;
1030
+ } else if (rect.y < viewTop) {
1031
+ delta = rect.y - viewTop;
1032
+ } else if (rect.y + rect.height > viewBottom) {
1033
+ delta = rect.y + rect.height - viewBottom;
1034
+ } else {
1035
+ return null;
1036
+ }
1037
+ const target = clamp(metrics.offset + delta, 0, maxOffset);
1038
+ if (Math.abs(target - metrics.offset) < 1) return null;
1039
+ return target;
1040
+ }
1041
+ function clamp(value, min, max) {
1042
+ return Math.min(max, Math.max(min, value));
1043
+ }
1044
+
1045
+ // src/introspection/revealTarget.ts
1046
+ function revealTarget(rect) {
1047
+ const host = chunkQAZ4TN3Z_js.getGeometryHost();
1048
+ if (!host) return { rect, scrolled: false };
1049
+ if (chunkQAZ4TN3Z_js.isRectOnScreen(rect, host.window)) return { rect, scrolled: false };
1050
+ const scrollable = resolveScrollable();
1051
+ if (!scrollable) return { rect, scrolled: false };
1052
+ const metrics = scrollable.getScrollMetrics?.();
1053
+ if (!metrics) return { rect, scrolled: false };
1054
+ const box = scrollable.measureViewport?.();
1055
+ const viewport = box ? { top: box.y, height: box.height } : { top: 0, height: host.window.height };
1056
+ const target = offsetToReveal({ rect, viewport, metrics });
1057
+ if (target === null) return { rect, scrolled: false };
1058
+ const moved = scrollable.scrollToOffset?.(target) ?? false;
1059
+ if (!moved) {
1060
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`revealTarget: "${scrollable.id}" refused scrollToOffset(${target})`);
1061
+ return { rect, scrolled: false };
1062
+ }
1063
+ const delta = target - metrics.offset;
1064
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
1065
+ `revealTarget: scrolled "${scrollable.id}" by ${Math.round(delta)}px (${Math.round(metrics.offset)} \u2192 ${Math.round(target)})`
1066
+ );
1067
+ return { rect: { ...rect, y: rect.y - delta }, scrolled: true };
1068
+ }
1069
+ function resolveScrollable() {
1070
+ const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
1071
+ const candidates = chunkQAZ4TN3Z_js.listRegistry.snapshot().filter((entry) => entry.scrollToOffset && entry.getScrollMetrics).filter((entry) => !screen || !entry.screen || entry.screen === screen);
1072
+ if (candidates.length === 1) return candidates[0];
1073
+ if (candidates.length > 1) {
1074
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
1075
+ `revealTarget: ${candidates.length} scrollables on "${screen ?? "?"}" \u2014 cannot tell which holds the target, so not scrolling.`
1076
+ );
1077
+ }
1078
+ return null;
1079
+ }
1080
+
602
1081
  // src/executor/handlers/navigateHandler.ts
603
1082
  var _reportedMissingNavRef = false;
604
1083
  function reportMissingNavigationRef() {
@@ -641,43 +1120,52 @@ function screenExistsAnywhere(state, screenName) {
641
1120
  return false;
642
1121
  }
643
1122
  function safeNavigate(nav, screenName, params, path) {
1123
+ const state = nav.getState?.();
1124
+ const rootState = nav.getRootState?.() ?? state;
644
1125
  if (path && path.length > 0) {
1126
+ if (Array.isArray(rootState?.routeNames) && !screenExistsAnywhere(rootState, path[0]) && !state?.routeNames?.includes(path[0])) {
1127
+ if (state?.routeNames?.includes(screenName)) {
1128
+ nav.navigate(screenName, params);
1129
+ return;
1130
+ }
1131
+ throw new Error(
1132
+ `Route "${path[0]}" is not registered in any navigator. Cannot resolve the supplied path to "${screenName}".`
1133
+ );
1134
+ }
645
1135
  const { root, nestedParams } = buildNestedParams(path, screenName, params);
646
- chunkSUMIABJK_js.appilotsDebugLog(
1136
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
647
1137
  `safeNavigate: using path-based navigation \u2014 root="${root}", nested=${JSON.stringify(nestedParams)}`
648
1138
  );
649
1139
  nav.navigate(root, nestedParams);
650
1140
  return;
651
1141
  }
652
- const state = nav.getState?.();
653
1142
  if (state?.routeNames?.includes(screenName)) {
654
1143
  nav.navigate(screenName, params);
655
1144
  return;
656
1145
  }
657
- const rootState = nav.getRootState?.() ?? state;
658
1146
  if (!screenExistsAnywhere(rootState, screenName)) {
659
1147
  throw new Error(
660
1148
  `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
1149
  );
662
1150
  }
663
- chunkSUMIABJK_js.appilotsDebugLog(
1151
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
664
1152
  `safeNavigate: screen exists in nested navigator, attempting direct navigation to "${screenName}"`
665
1153
  );
666
1154
  nav.navigate(screenName, params);
667
1155
  }
668
1156
  function navigateHandler(payload, context) {
669
- chunkSUMIABJK_js.appilotsDebugLog(
1157
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
670
1158
  // Params carry record ids and, on some screens, the user's own
671
1159
  // 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)}`
1160
+ `navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${chunkQAZ4TN3Z_js.describeValue(payload.params)}`
673
1161
  );
674
1162
  const { navigationRef, permissions } = context;
675
1163
  const nav = navigationRef.current;
676
1164
  if (!permissions.canNavigate) {
677
1165
  return {
678
1166
  success: false,
679
- error: "Navigation is not permitted",
680
- diagnose: { category: "unknown", screen: payload.screenName }
1167
+ error: chunkQAZ4TN3Z_js.permissionDeniedMessage("Navigation", "canNavigate"),
1168
+ diagnose: { category: "unknown", screen: payload.screenName, recoverable: false }
681
1169
  };
682
1170
  }
683
1171
  const isGoBack = payload.navigationAction === "goBack";
@@ -762,12 +1250,12 @@ function navigateHandler(payload, context) {
762
1250
  diagnose: { category: "unknown", screen: payload.screenName }
763
1251
  };
764
1252
  }
765
- chunkSUMIABJK_js.appilotsDebugLog(
1253
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
766
1254
  `navigateHandler: navigation succeeded for "${payload.screenName}" (action="${payload.navigationAction}")`
767
1255
  );
768
1256
  return { success: true };
769
1257
  } catch (err) {
770
- chunkSUMIABJK_js.appilotsDebugWarn(
1258
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
771
1259
  `navigateHandler: navigation failed for "${payload.screenName}": ${err?.message}`
772
1260
  );
773
1261
  const msg = String(err?.message ?? "Navigation failed");
@@ -815,18 +1303,18 @@ function markedItemIndexFromFiber(fiber) {
815
1303
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
816
1304
  }
817
1305
  function normalize2(value) {
818
- return chunkSUMIABJK_js.foldForCompare(String(value ?? ""));
1306
+ return chunkQAZ4TN3Z_js.foldForCompare(String(value ?? ""));
819
1307
  }
820
1308
  function hasPressHandler2(fiber) {
821
1309
  const props = fiber?.memoizedProps ?? {};
822
1310
  return typeof props.onPress === "function" || typeof props.onPressIn === "function";
823
1311
  }
824
1312
  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);
1313
+ const typeName = chunkQAZ4TN3Z_js.getTypeName(fiber.type) ?? chunkQAZ4TN3Z_js.getTypeName(fiber.elementType) ?? "";
1314
+ return chunkQAZ4TN3Z_js.TOUCHABLE_NAMES.has(typeName) || hasPressHandler2(fiber);
827
1315
  }
828
1316
  function findListContainers(options = {}) {
829
- const root = chunkSUMIABJK_js.getFiberRoot();
1317
+ const root = chunkQAZ4TN3Z_js.getFiberRoot();
830
1318
  if (!root) return [];
831
1319
  const containers = [];
832
1320
  const visited = /* @__PURE__ */ new WeakSet();
@@ -837,17 +1325,17 @@ function findListContainers(options = {}) {
837
1325
  if (!fiber || visited.has(fiber)) continue;
838
1326
  visited.add(fiber);
839
1327
  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);
1328
+ if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
1329
+ if (chunkQAZ4TN3Z_js.isAlwaysListContainer(fiber) || chunkQAZ4TN3Z_js.isHeuristicListContainer(fiber)) {
1330
+ const minItems = chunkQAZ4TN3Z_js.isAlwaysListContainer(fiber) || options.allowSingleHeuristic ? 1 : 2;
1331
+ const items = chunkQAZ4TN3Z_js.findListItems(fiber, minItems);
844
1332
  if (items && items.length >= minItems) {
845
1333
  containers.push({
846
1334
  container: fiber,
847
1335
  items,
848
1336
  listId: listIdFromContainer(fiber),
849
1337
  listLabel: listLabelFromContainer(fiber),
850
- containerType: chunkSUMIABJK_js.getTypeName(fiber.type) ?? chunkSUMIABJK_js.getTypeName(fiber.elementType) ?? "List"
1338
+ containerType: chunkQAZ4TN3Z_js.getTypeName(fiber.type) ?? chunkQAZ4TN3Z_js.getTypeName(fiber.elementType) ?? "List"
851
1339
  });
852
1340
  continue;
853
1341
  }
@@ -866,7 +1354,7 @@ function findFirstTouchable(item) {
866
1354
  const { fiber, includeSibling } = stack.pop();
867
1355
  if (!fiber || visited.has(fiber)) continue;
868
1356
  visited.add(fiber);
869
- if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
1357
+ if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
870
1358
  if (isPressableFiber(fiber)) {
871
1359
  const props = fiber.memoizedProps ?? {};
872
1360
  if (typeof props.onPress === "function" || typeof props.onPressIn === "function") {
@@ -893,7 +1381,7 @@ function findTouchableFibers(item) {
893
1381
  const { fiber, includeSibling } = stack.pop();
894
1382
  if (!fiber || visited.has(fiber)) continue;
895
1383
  visited.add(fiber);
896
- if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
1384
+ if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
897
1385
  const props = fiber.memoizedProps ?? {};
898
1386
  if (isPressableFiber(fiber) && (typeof props.onPress === "function" || typeof props.onPressIn === "function")) {
899
1387
  found.push(fiber);
@@ -937,7 +1425,7 @@ function findFirstText(fiber) {
937
1425
  const node = stack.pop();
938
1426
  if (!node || visited.has(node)) continue;
939
1427
  visited.add(node);
940
- const typeName = chunkSUMIABJK_js.getTypeName(node.type) ?? chunkSUMIABJK_js.getTypeName(node.elementType) ?? "";
1428
+ const typeName = chunkQAZ4TN3Z_js.getTypeName(node.type) ?? chunkQAZ4TN3Z_js.getTypeName(node.elementType) ?? "";
941
1429
  if (typeName === "Text") {
942
1430
  const text = textFromChildren(node.memoizedProps?.children).trim();
943
1431
  if (text) return text;
@@ -956,7 +1444,7 @@ function collectTexts(fiber) {
956
1444
  const node = stack.pop();
957
1445
  if (!node || visited.has(node)) continue;
958
1446
  visited.add(node);
959
- const typeName = chunkSUMIABJK_js.getTypeName(node.type) ?? chunkSUMIABJK_js.getTypeName(node.elementType) ?? "";
1447
+ const typeName = chunkQAZ4TN3Z_js.getTypeName(node.type) ?? chunkQAZ4TN3Z_js.getTypeName(node.elementType) ?? "";
960
1448
  if (typeName === "Text") {
961
1449
  const text = textFromChildren(node.memoizedProps?.children).trim();
962
1450
  if (text) out.push(text);
@@ -968,10 +1456,10 @@ function collectTexts(fiber) {
968
1456
  }
969
1457
  function hasUsefulTouchableIdentity(fiber) {
970
1458
  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));
1459
+ if (chunkQAZ4TN3Z_js.isReferenceable(props.testID)) return true;
1460
+ if (chunkQAZ4TN3Z_js.isReferenceable(props.accessibilityLabel)) return true;
1461
+ if (chunkQAZ4TN3Z_js.isReferenceable(props.label)) return true;
1462
+ return chunkQAZ4TN3Z_js.isReferenceable(findFirstText(fiber));
975
1463
  }
976
1464
  function describeTouchable(fiber) {
977
1465
  const props = fiber?.memoizedProps ?? {};
@@ -982,10 +1470,10 @@ function describeTouchable(fiber) {
982
1470
  }
983
1471
  function touchableLooksDestructive(fiber) {
984
1472
  const descriptor = describeTouchable(fiber);
985
- if (descriptor && chunkSUMIABJK_js.looksDestructiveActionLabel(descriptor)) return true;
1473
+ if (descriptor && chunkQAZ4TN3Z_js.looksDestructiveActionLabel(descriptor)) return true;
986
1474
  const props = fiber?.memoizedProps ?? {};
987
1475
  const haystack = [props.testID, props.accessibilityLabel, props.accessibilityHint, props.label].filter((value) => typeof value === "string").join(" ");
988
- return chunkSUMIABJK_js.looksDestructiveActionLabel(haystack);
1476
+ return chunkQAZ4TN3Z_js.looksDestructiveActionLabel(haystack);
989
1477
  }
990
1478
  function describeItemCandidate(listIndex, zeroBasedIndex, item) {
991
1479
  const syntheticId = `list-${listIndex}-item-${zeroBasedIndex + 1}`;
@@ -1034,8 +1522,10 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
1034
1522
  (candidate) => candidate !== touchable && containsFiber(touchable, candidate)
1035
1523
  );
1036
1524
  if (primaryWrapsNestedTargets) {
1037
- chunkSUMIABJK_js.appilotsDebugLog(
1038
- `listItemDispatch: item "list-${listIndex}-item-${itemIndex}" has nested pressables; pressing outer row target`
1525
+ const outer = describeTouchable(touchable) ?? "?";
1526
+ const nested = safeIdentifiableTouchables.filter((candidate) => candidate !== touchable && containsFiber(touchable, candidate)).map((candidate) => describeTouchable(candidate) ?? "?").slice(0, 6);
1527
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
1528
+ `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
1529
  );
1040
1530
  } else {
1041
1531
  const candidates = safeIdentifiableTouchables.map(describeTouchable).filter((d) => !!d).slice(0, 8);
@@ -1069,14 +1559,14 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
1069
1559
  }
1070
1560
  return {
1071
1561
  ok: true,
1072
- containerType: chunkSUMIABJK_js.getTypeName(container.type) ?? chunkSUMIABJK_js.getTypeName(container.elementType) ?? list.containerType
1562
+ containerType: chunkQAZ4TN3Z_js.getTypeName(container.type) ?? chunkQAZ4TN3Z_js.getTypeName(container.elementType) ?? list.containerType
1073
1563
  };
1074
1564
  } catch (err) {
1075
1565
  return {
1076
1566
  ok: false,
1077
1567
  reason: "press-threw",
1078
1568
  error: err?.message ?? "press handler threw",
1079
- containerType: chunkSUMIABJK_js.getTypeName(container.type) ?? chunkSUMIABJK_js.getTypeName(container.elementType) ?? list.containerType
1569
+ containerType: chunkQAZ4TN3Z_js.getTypeName(container.type) ?? chunkQAZ4TN3Z_js.getTypeName(container.elementType) ?? list.containerType
1080
1570
  };
1081
1571
  }
1082
1572
  }
@@ -1102,10 +1592,12 @@ function scoreItemCandidate(item, zeroBasedIndex, locator) {
1102
1592
  if (locator.itemKey) {
1103
1593
  if (itemKey === locator.itemKey) score += 1e3;
1104
1594
  else if (itemKey && normalize2(itemKey) === normalize2(locator.itemKey)) score += 950;
1595
+ else return 0;
1105
1596
  }
1106
1597
  if (locator.reactKey) {
1107
1598
  if (reactKey === locator.reactKey) score += 900;
1108
1599
  else if (reactKey && normalize2(reactKey) === normalize2(locator.reactKey)) score += 850;
1600
+ else if (!locator.itemKey) return 0;
1109
1601
  }
1110
1602
  if (locator.itemIndex && zeroBasedIndex === locator.itemIndex - 1) score += 750;
1111
1603
  if (locator.itemIndex && markedIndex !== void 0 && (markedIndex === locator.itemIndex || markedIndex === locator.itemIndex - 1)) {
@@ -1132,7 +1624,7 @@ function candidateLists(containers, locator) {
1132
1624
  return containers.map((list, listIndex) => ({ list, listIndex }));
1133
1625
  }
1134
1626
  function pressListItemAtOrdinal(listIndex, itemIndex) {
1135
- if (!chunkSUMIABJK_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
1627
+ if (!chunkQAZ4TN3Z_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
1136
1628
  const containers = findListContainers({ allowSingleHeuristic: true });
1137
1629
  if (listIndex < 0 || listIndex >= containers.length) {
1138
1630
  return { ok: false, reason: "list-not-found" };
@@ -1146,7 +1638,7 @@ function pressListItemAtOrdinal(listIndex, itemIndex) {
1146
1638
  return pressResolvedListItem(list, items[zeroBased], listIndex, itemIndex);
1147
1639
  }
1148
1640
  function resolveListItemByIdentity(locator) {
1149
- if (!chunkSUMIABJK_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
1641
+ if (!chunkQAZ4TN3Z_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
1150
1642
  const parsed = locator.syntheticId ? parseSyntheticListItemId(locator.syntheticId) : null;
1151
1643
  const effective = parsed ? { ...locator, listIndex: parsed.listIndex, itemIndex: parsed.itemIndex } : locator;
1152
1644
  const containers = findListContainers({ allowSingleHeuristic: true });
@@ -1175,7 +1667,7 @@ function resolveListItemByIdentity(locator) {
1175
1667
  scoredCandidates.sort((a, b) => b.score - a.score);
1176
1668
  const best = scoredCandidates[0];
1177
1669
  const tiedCandidates = scoredCandidates.filter((c) => c.score === best.score);
1178
- if (tiedCandidates.length > 1 && best.score < 750) {
1670
+ if (tiedCandidates.length > 1 && (best.score < 750 || Boolean(effective.itemKey || effective.reactKey))) {
1179
1671
  const candidates = tiedCandidates.map((c) => describeItemCandidate(c.listIndex, c.itemIndex - 1, c.item)).slice(0, 8);
1180
1672
  return {
1181
1673
  ok: false,
@@ -1207,9 +1699,9 @@ function findSwitchFibers(item) {
1207
1699
  const { fiber, includeSibling } = stack.pop();
1208
1700
  if (!fiber || visited.has(fiber)) continue;
1209
1701
  visited.add(fiber);
1210
- if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
1702
+ if (chunkQAZ4TN3Z_js.shouldSkipSubtree(fiber)) continue;
1211
1703
  const props = fiber.memoizedProps ?? {};
1212
- if (chunkSUMIABJK_js.isSwitchLike(fiber, props)) {
1704
+ if (chunkQAZ4TN3Z_js.isSwitchLike(fiber, props)) {
1213
1705
  if (props.__appilotsInternal !== true) found.push(fiber);
1214
1706
  if (includeSibling && fiber.sibling) {
1215
1707
  stack.push({ fiber: fiber.sibling, includeSibling: true });
@@ -1243,11 +1735,11 @@ function toggleListItemByIdentity(locator, options) {
1243
1735
  }
1244
1736
  const target = switches[0];
1245
1737
  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 };
1738
+ const current2 = chunkQAZ4TN3Z_js.switchValue(props);
1739
+ if (options?.expected !== void 0 && current2 === options.expected) {
1740
+ return { ok: true, containerType: list.containerType, value: current2, noop: true };
1249
1741
  }
1250
- const flipped = flipSwitchFiber(target, !current);
1742
+ const flipped = flipSwitchFiber(target, !current2);
1251
1743
  if (!flipped.ok) {
1252
1744
  if (flipped.reason === "no-handler") {
1253
1745
  return {
@@ -1264,7 +1756,7 @@ function toggleListItemByIdentity(locator, options) {
1264
1756
  containerType: list.containerType
1265
1757
  };
1266
1758
  }
1267
- return { ok: true, containerType: list.containerType, value: !current };
1759
+ return { ok: true, containerType: list.containerType, value: !current2 };
1268
1760
  }
1269
1761
  function pressListItemByIdentity(locator) {
1270
1762
  const resolved = resolveListItemByIdentity(locator);
@@ -1282,7 +1774,7 @@ function screenDiagnose(targetId, category = "component-not-found") {
1282
1774
  return {
1283
1775
  category,
1284
1776
  targetId,
1285
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0
1777
+ screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0
1286
1778
  };
1287
1779
  }
1288
1780
  function isPressLike(action) {
@@ -1302,10 +1794,10 @@ function elementLookupKey(value) {
1302
1794
  return canonicalElementId(value).toLowerCase().replace(/[\s_]+/g, "-");
1303
1795
  }
1304
1796
  function findRegisteredElement(elementId) {
1305
- const direct = chunkSUMIABJK_js.elementRegistry.get(elementId) ?? chunkSUMIABJK_js.elementRegistry.get(canonicalElementId(elementId));
1797
+ const direct = chunkQAZ4TN3Z_js.elementRegistry.get(elementId) ?? chunkQAZ4TN3Z_js.elementRegistry.get(canonicalElementId(elementId));
1306
1798
  if (direct) return direct;
1307
1799
  const wanted = elementLookupKey(elementId);
1308
- return chunkSUMIABJK_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
1800
+ return chunkQAZ4TN3Z_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
1309
1801
  }
1310
1802
  function resolveInteractionElement(elementId) {
1311
1803
  return getLatestElement(elementId);
@@ -1425,7 +1917,7 @@ function dispatchIdentifiedToggle(targetId, action) {
1425
1917
  diagnose: { ...screenDiagnose(targetId, "unknown"), recoverable: true }
1426
1918
  };
1427
1919
  }
1428
- chunkSUMIABJK_js.appilotsDebugLog(
1920
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
1429
1921
  `elementDispatch: "${action}" on "${targetId}" names a switch \u2014 flipping it instead of pressing, so the verb cannot land on an ancestor`
1430
1922
  );
1431
1923
  try {
@@ -1459,6 +1951,13 @@ function dispatchFiberTarget(targetId, action) {
1459
1951
  diagnose: screenDiagnose(targetId)
1460
1952
  };
1461
1953
  }
1954
+ const measured = handle.measure?.() ?? null;
1955
+ const verb = action === "scroll" ? void 0 : action === "toggle" || action === "focus" ? action : "press";
1956
+ if (measured && getSpotlightMode() === "guided") {
1957
+ setSpotlightTarget(revealTarget(measured).rect, handle.label, verb);
1958
+ } else {
1959
+ setSpotlightTarget(measured, handle.label, verb);
1960
+ }
1462
1961
  try {
1463
1962
  if (isPressLike(action) && handle.kind === "target" && handle.press) {
1464
1963
  handle.press();
@@ -1509,6 +2008,13 @@ function dispatchLegacyTarget(targetId, registry, action) {
1509
2008
  };
1510
2009
  }
1511
2010
  function dispatchElement(element, registry, action) {
2011
+ if (element.dispatchable === false) {
2012
+ return {
2013
+ success: false,
2014
+ error: `Element "${element.id}" is observation-only and has no exact live control binding.`,
2015
+ diagnose: { ...screenDiagnose(element.id, "ambiguous-target"), recoverable: false }
2016
+ };
2017
+ }
1512
2018
  if (element.disabled === true) {
1513
2019
  return {
1514
2020
  success: false,
@@ -1527,6 +2033,13 @@ function dispatchElement(element, registry, action) {
1527
2033
  texts: element.texts
1528
2034
  });
1529
2035
  if (pressed.ok) return { success: true };
2036
+ if (!pressed.refusal && (element.listContext.itemKey || element.listContext.reactKey)) {
2037
+ return {
2038
+ success: false,
2039
+ error: pressed.error ?? `The observed list entity "${element.label ?? element.id}" could not be resolved. Reobserve; do not substitute its old position.`,
2040
+ diagnose: { ...screenDiagnose(element.id, "ambiguous-target"), recoverable: true }
2041
+ };
2042
+ }
1530
2043
  if (pressed.refusal) {
1531
2044
  return {
1532
2045
  success: false,
@@ -1634,7 +2147,7 @@ function dispatchToggleElement(element, registry) {
1634
2147
  }
1635
2148
  function dispatchStructuredElementId(identifier, action) {
1636
2149
  if (!isElementIdentifier(identifier) || !isPressLike(action)) return null;
1637
- const parsed = chunkSUMIABJK_js.parseStableElementId(identifier);
2150
+ const parsed = chunkQAZ4TN3Z_js.parseStableElementId(identifier);
1638
2151
  if (!parsed || parsed.role !== "option") return null;
1639
2152
  if (!parsed.itemKey && !parsed.listId) return null;
1640
2153
  const pressed = pressListItemByIdentity({
@@ -1644,7 +2157,7 @@ function dispatchStructuredElementId(identifier, action) {
1644
2157
  texts: parsed.itemKey ? [parsed.itemKey] : void 0
1645
2158
  });
1646
2159
  if (pressed.ok) {
1647
- chunkSUMIABJK_js.appilotsDebugLog(
2160
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
1648
2161
  `elementDispatch: resolved stale el id "${identifier}" via structural identity (listId="${parsed.listId}", itemKey="${parsed.itemKey}")`
1649
2162
  );
1650
2163
  return { success: true };
@@ -1675,20 +2188,20 @@ function normalize4(value) {
1675
2188
  return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
1676
2189
  }
1677
2190
  function resolveScreenForFormFields() {
1678
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
2191
+ const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
1679
2192
  for (let i = activePath.length - 1; i >= 0; i--) {
1680
2193
  const name = activePath[i];
1681
- const meta = name ? chunkSUMIABJK_js.getScreenMetadata(name) : void 0;
2194
+ const meta = name ? chunkQAZ4TN3Z_js.getScreenMetadata(name) : void 0;
1682
2195
  if (name && Array.isArray(meta?.fields) && meta.fields.length > 0) return name;
1683
2196
  }
1684
- return chunkSUMIABJK_js.getCurrentScreen();
2197
+ return chunkQAZ4TN3Z_js.getCurrentScreen();
1685
2198
  }
1686
2199
  function collectKnownFormFields(registry) {
1687
2200
  const registryFields = registry.snapshot().filter((entry) => entry.kind === "field" || entry.kind === "slider").map((entry) => ({ id: entry.id, label: entry.label }));
1688
2201
  if (registryFields.length >= 2) return registryFields;
1689
2202
  const screen = resolveScreenForFormFields();
1690
2203
  if (screen) {
1691
- const metaFields = chunkSUMIABJK_js.getScreenMetadata(screen)?.fields;
2204
+ const metaFields = chunkQAZ4TN3Z_js.getScreenMetadata(screen)?.fields;
1692
2205
  if (Array.isArray(metaFields) && metaFields.length > 0) {
1693
2206
  return metaFields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
1694
2207
  id: field.id,
@@ -1698,7 +2211,7 @@ function collectKnownFormFields(registry) {
1698
2211
  }));
1699
2212
  }
1700
2213
  }
1701
- for (const meta of chunkSUMIABJK_js.getAllScreens()) {
2214
+ for (const meta of chunkQAZ4TN3Z_js.getAllScreens()) {
1702
2215
  if (Array.isArray(meta.fields) && meta.fields.length > 0) {
1703
2216
  return meta.fields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
1704
2217
  id: field.id,
@@ -1710,19 +2223,9 @@ function collectKnownFormFields(registry) {
1710
2223
  }
1711
2224
  return registryFields;
1712
2225
  }
1713
- function isMisplacedFieldId(fieldId, knownIds) {
2226
+ function isMisplacedFieldId(fieldId) {
1714
2227
  const trimmed = fieldId.trim();
1715
- if (!trimmed) return true;
1716
- if (LIST_ORDINAL_RE.test(trimmed)) return true;
1717
- if (/^\d+$/.test(trimmed)) return true;
1718
- const normalized = normalize4(trimmed);
1719
- if (knownIds.has(normalized)) return false;
1720
- for (const known of knownIds) {
1721
- if (known.length >= 4 && (known.includes(normalized) || normalized.includes(known))) {
1722
- return false;
1723
- }
1724
- }
1725
- return true;
2228
+ return !trimmed || LIST_ORDINAL_RE.test(trimmed) || /^\d+$/.test(trimmed);
1726
2229
  }
1727
2230
  function valueMatchesOption(field, rawValue) {
1728
2231
  const value = normalize4(String(rawValue ?? ""));
@@ -1779,6 +2282,7 @@ function fieldTypeMatchesShape(field, shape) {
1779
2282
  function fieldAcceptsFreeText(field, shape) {
1780
2283
  const type = normalize4(field.type ?? "text");
1781
2284
  if (CHOICE_FIELD_TYPES.has(type)) return false;
2285
+ if (type === "password") return false;
1782
2286
  if (NUMERIC_FIELD_TYPES.has(type)) return shape === "number";
1783
2287
  if (DATE_FIELD_TYPES.has(type)) return shape === "date";
1784
2288
  if (EMAIL_FIELD_TYPES.has(type)) return shape === "email";
@@ -1799,19 +2303,18 @@ function inferFieldIdForValue(rawValue, fields, used) {
1799
2303
  function rewriteMisplacedFormFillFields(fields, registry) {
1800
2304
  const knownFields = collectKnownFormFields(registry);
1801
2305
  if (knownFields.length === 0) return fields;
1802
- const knownIds = new Set(knownFields.map((field) => normalize4(field.id)));
1803
- const needsRewrite = fields.some((field) => isMisplacedFieldId(field.fieldId, knownIds));
2306
+ const needsRewrite = fields.some((field) => isMisplacedFieldId(field.fieldId));
1804
2307
  if (!needsRewrite) return fields;
1805
2308
  const used = /* @__PURE__ */ new Set();
1806
2309
  return fields.map((field) => {
1807
- if (!isMisplacedFieldId(field.fieldId, knownIds)) {
2310
+ if (!isMisplacedFieldId(field.fieldId)) {
1808
2311
  used.add(field.fieldId);
1809
2312
  return field;
1810
2313
  }
1811
2314
  const inferred = inferFieldIdForValue(String(field.value ?? ""), knownFields, used);
1812
2315
  if (!inferred) return field;
1813
2316
  used.add(inferred);
1814
- chunkSUMIABJK_js.appilotsDebugWarn(
2317
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
1815
2318
  `formFieldRewrite: ${field.fieldId} \u2192 ${inferred} (value=${JSON.stringify(field.value)})`
1816
2319
  );
1817
2320
  return { ...field, fieldId: inferred };
@@ -1819,8 +2322,8 @@ function rewriteMisplacedFormFillFields(fields, registry) {
1819
2322
  }
1820
2323
 
1821
2324
  // 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;
2325
+ var FORM_VALIDATION_TEXT_RE2 = chunkQAZ4TN3Z_js.FORM_VALIDATION_TEXT_RE;
2326
+ var FORM_SUCCESS_TEXT_RE = chunkQAZ4TN3Z_js.FORM_WRITE_SUCCESS_TEXT_RE;
1824
2327
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1825
2328
  function inferValidationFieldId(message, inputs) {
1826
2329
  const haystack = normalizeText(message);
@@ -1844,12 +2347,18 @@ function normalizeText(value) {
1844
2347
  function containsWord(haystack, needle) {
1845
2348
  return ` ${haystack} `.includes(` ${needle} `);
1846
2349
  }
1847
- function readVisibleFormValidation(snap) {
2350
+ function readVisibleFormValidation(snap, beforeTexts) {
1848
2351
  if (!snap) return void 0;
2352
+ const invalid = snap.inputs?.find((input) => input.invalid === true);
2353
+ const hasSubmitControl = snap.buttons?.some(
2354
+ (button) => chunkQAZ4TN3Z_js.SUBMIT_CONTROL_RE.test(button.label ?? button.id ?? "")
2355
+ );
1849
2356
  for (const text of snap.texts ?? []) {
1850
- if (!text?.trim() || !FORM_VALIDATION_TEXT_RE2.test(text)) continue;
2357
+ if (!text?.trim() || !chunkQAZ4TN3Z_js.isVisibleValidationText(text, { invalid: !!invalid, hasSubmitControl, beforeTexts }))
2358
+ continue;
1851
2359
  return { fieldId: inferValidationFieldId(text, snap.inputs), message: text };
1852
2360
  }
2361
+ if (invalid) return { fieldId: invalid.id, message: "The app marks this field as invalid." };
1853
2362
  return void 0;
1854
2363
  }
1855
2364
  function readVisibleFormSuccess(snap) {
@@ -1857,20 +2366,23 @@ function readVisibleFormSuccess(snap) {
1857
2366
  return (snap.texts ?? []).find((text) => text?.trim() && FORM_SUCCESS_TEXT_RE.test(text));
1858
2367
  }
1859
2368
  function submitAsyncStillPending(submitTargetId) {
1860
- const probe = chunkSUMIABJK_js.probeLoadingState(submitTargetId ?? null, chunkSUMIABJK_js.getCurrentScreen());
2369
+ const probe = chunkQAZ4TN3Z_js.probeLoadingState(submitTargetId ?? null, chunkQAZ4TN3Z_js.getCurrentScreen());
1861
2370
  if (probe.loading) return true;
1862
2371
  if (submitTargetId && probe.pressedFound && probe.pressedDisabled) return true;
1863
2372
  return false;
1864
2373
  }
1865
- function evaluatePostSubmitSnapshot(snap, activePath) {
1866
- const validation = readVisibleFormValidation(snap);
2374
+ function evaluatePostSubmitSnapshot(snap, activePath, beforeTexts) {
2375
+ const validation = readVisibleFormValidation(snap, beforeTexts);
1867
2376
  if (validation) {
1868
2377
  return { status: "failure", fieldId: validation.fieldId, message: validation.message };
1869
2378
  }
1870
2379
  const successText = readVisibleFormSuccess(snap);
1871
2380
  if (successText) return { status: "success", message: successText };
1872
- if (!chunkSUMIABJK_js.snapshotShowsOpenCreateForm(snap, activePath)) {
1873
- return { status: "success" };
2381
+ if (!chunkQAZ4TN3Z_js.snapshotShowsOpenCreateForm(snap, activePath)) {
2382
+ return {
2383
+ status: "unverified",
2384
+ message: "The form closed without a visible success receipt. Inspect the resulting record before claiming the goal is complete."
2385
+ };
1874
2386
  }
1875
2387
  return void 0;
1876
2388
  }
@@ -1885,8 +2397,8 @@ async function waitForPostSubmitOutcome(options) {
1885
2397
  continue;
1886
2398
  }
1887
2399
  const snap2 = captureSnapshot();
1888
- const activePath2 = chunkSUMIABJK_js.getActiveRouteNames();
1889
- const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2);
2400
+ const activePath2 = chunkQAZ4TN3Z_js.getActiveRouteNames();
2401
+ const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2, options?.beforeTexts);
1890
2402
  if (outcome2) return outcome2;
1891
2403
  await sleep(pollMs);
1892
2404
  }
@@ -1897,8 +2409,8 @@ async function waitForPostSubmitOutcome(options) {
1897
2409
  };
1898
2410
  }
1899
2411
  const snap = captureSnapshot();
1900
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
1901
- const outcome = evaluatePostSubmitSnapshot(snap, activePath);
2412
+ const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
2413
+ const outcome = evaluatePostSubmitSnapshot(snap, activePath, options?.beforeTexts);
1902
2414
  if (outcome) return outcome;
1903
2415
  return {
1904
2416
  status: "failure",
@@ -1906,91 +2418,6 @@ async function waitForPostSubmitOutcome(options) {
1906
2418
  };
1907
2419
  }
1908
2420
 
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
2421
  // src/executor/handlers/uiInteractionHandler.ts
1995
2422
  function findSnapshotButton(targetId) {
1996
2423
  try {
@@ -2003,16 +2430,16 @@ function findSnapshotButton(targetId) {
2003
2430
  }
2004
2431
  }
2005
2432
  function buildUiDiagnose(targetId, cause) {
2006
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
2007
- const screen = activePath[activePath.length - 1] ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
2433
+ const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
2434
+ const screen = activePath[activePath.length - 1] ?? chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
2008
2435
  const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
2009
2436
  const diagnose = {
2010
2437
  category: cause === "not-found" ? "component-not-found" : cause === "disabled" ? "disabled" : "unknown",
2011
2438
  targetId,
2012
2439
  screen: screenPath
2013
2440
  };
2014
- if (chunkSUMIABJK_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
2015
- diagnose.visibleMessage = chunkSUMIABJK_js.OPTIONAL_STEP_AUTOMATION_HINT;
2441
+ if (chunkQAZ4TN3Z_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
2442
+ diagnose.visibleMessage = chunkQAZ4TN3Z_js.OPTIONAL_STEP_AUTOMATION_HINT;
2016
2443
  diagnose.recoverable = true;
2017
2444
  }
2018
2445
  return diagnose;
@@ -2063,6 +2490,7 @@ function stripComponentPrefix(componentId) {
2063
2490
  return null;
2064
2491
  }
2065
2492
  function resolveComponentId(componentId, registry, action) {
2493
+ if (chunkQAZ4TN3Z_js.isSourceControlId(componentId)) return componentId;
2066
2494
  if (registry.getTarget(componentId) || registry.getToggle(componentId) || registry.getField(componentId) || registry.getSlider(componentId)) {
2067
2495
  return componentId;
2068
2496
  }
@@ -2070,15 +2498,16 @@ function resolveComponentId(componentId, registry, action) {
2070
2498
  const snapshot = registry.snapshot();
2071
2499
  for (const comp of snapshot) {
2072
2500
  if (comp.id.toLowerCase() === lower) {
2073
- chunkSUMIABJK_js.appilotsDebugLog(
2501
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2074
2502
  `resolveComponentId: case-insensitive match "${componentId}" \u2192 "${comp.id}"`
2075
2503
  );
2076
2504
  return comp.id;
2077
2505
  }
2078
2506
  }
2079
- const currentScreen = chunkSUMIABJK_js.getCurrentScreen();
2507
+ if (isPositionalControlId(componentId)) return componentId;
2508
+ const currentScreen = chunkQAZ4TN3Z_js.getCurrentScreen();
2080
2509
  if (currentScreen) {
2081
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(currentScreen);
2510
+ const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(currentScreen);
2082
2511
  const actions = screenMeta?.actions;
2083
2512
  if (actions && Array.isArray(actions)) {
2084
2513
  const metaAction = actions.find(
@@ -2087,14 +2516,14 @@ function resolveComponentId(componentId, registry, action) {
2087
2516
  if (metaAction && typeof metaAction === "object" && metaAction.label) {
2088
2517
  const metaLabel = metaAction.label;
2089
2518
  const normalizedMetaLabel = metaLabel.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
2090
- chunkSUMIABJK_js.appilotsDebugLog(
2519
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2091
2520
  `resolveComponentId: found screen metadata for "${componentId}" \u2192 label="${metaLabel}"`
2092
2521
  );
2093
2522
  for (const comp of snapshot) {
2094
2523
  if (!comp.label) continue;
2095
2524
  const compLabel = comp.label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
2096
2525
  if (compLabel === normalizedMetaLabel || compLabel.includes(normalizedMetaLabel) || normalizedMetaLabel.includes(compLabel)) {
2097
- chunkSUMIABJK_js.appilotsDebugLog(
2526
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2098
2527
  `resolveComponentId: FOUND via metadata: "${componentId}" \u2192 "${comp.id}" (label="${comp.label}")`
2099
2528
  );
2100
2529
  return comp.id;
@@ -2109,9 +2538,9 @@ function resolveComponentId(componentId, registry, action) {
2109
2538
  label: c.label,
2110
2539
  kind: c.kind
2111
2540
  }));
2112
- const match = resolveTarget(componentId, candidates, { action });
2541
+ const match = chunkQAZ4TN3Z_js.resolveTarget(componentId, candidates, { action });
2113
2542
  if (match.status === "matched") {
2114
- chunkSUMIABJK_js.appilotsDebugLog(
2543
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2115
2544
  `resolveComponentId: matched "${componentId}" -> "${match.id}" (tier=${match.tier})`
2116
2545
  );
2117
2546
  return match.id;
@@ -2201,7 +2630,7 @@ function setValueHandler(rawComponentId, requested, registry) {
2201
2630
  try {
2202
2631
  slider.setValue(applied);
2203
2632
  if (applied !== requestedValue) {
2204
- chunkSUMIABJK_js.appilotsDebugLog(
2633
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2205
2634
  `uiInteractionHandler: set_value snapped ${requestedValue} \u2192 ${applied} for "${componentId}" (step=${step})`
2206
2635
  );
2207
2636
  }
@@ -2236,7 +2665,7 @@ function checkModalOcclusion(rawComponentId, action) {
2236
2665
  return null;
2237
2666
  }
2238
2667
  if (typeof rawComponentId !== "string" || rawComponentId.trim().length === 0) return null;
2239
- const dialog = chunkSUMIABJK_js.getOpenNativeDialog();
2668
+ const dialog = chunkQAZ4TN3Z_js.getOpenNativeDialog();
2240
2669
  if (dialog) {
2241
2670
  const needle = normalizeIdent(rawComponentId);
2242
2671
  if (dialog.buttons.some((b) => normalizeIdent(b.label) === needle)) return null;
@@ -2246,16 +2675,16 @@ function checkModalOcclusion(rawComponentId, action) {
2246
2675
  diagnose: {
2247
2676
  category: "ambiguous-target",
2248
2677
  targetId: rawComponentId,
2249
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
2678
+ screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
2250
2679
  candidates: dialog.buttons.map((b) => b.label).slice(0, 8)
2251
2680
  }
2252
2681
  };
2253
2682
  }
2254
- const fiberRoot = chunkSUMIABJK_js.getFiberRoot();
2683
+ const fiberRoot = chunkQAZ4TN3Z_js.getFiberRoot();
2255
2684
  if (!fiberRoot) return null;
2256
2685
  let snap;
2257
2686
  try {
2258
- snap = chunkSUMIABJK_js.walkFiber(fiberRoot);
2687
+ snap = chunkQAZ4TN3Z_js.walkFiber(fiberRoot);
2259
2688
  } catch {
2260
2689
  return null;
2261
2690
  }
@@ -2317,15 +2746,18 @@ function checkModalOcclusion(rawComponentId, action) {
2317
2746
  }
2318
2747
  function uiInteractionHandler(payload, context) {
2319
2748
  const { permissions } = context;
2320
- const registry = context.registry ?? chunkSUMIABJK_js.componentRegistry;
2749
+ const registry = context.registry ?? chunkQAZ4TN3Z_js.componentRegistry;
2321
2750
  if (!permissions.canInteractUI) {
2322
2751
  return {
2323
2752
  success: false,
2324
- error: "UI interaction is not permitted",
2325
- diagnose: buildUiDiagnose(
2326
- payload.componentId ?? payload.targetId ?? "",
2327
- "unknown"
2328
- )
2753
+ error: chunkQAZ4TN3Z_js.permissionDeniedMessage("UI interaction", "canInteractUI"),
2754
+ diagnose: {
2755
+ ...buildUiDiagnose(
2756
+ payload.componentId ?? payload.targetId ?? "",
2757
+ "unknown"
2758
+ ),
2759
+ recoverable: false
2760
+ }
2329
2761
  };
2330
2762
  }
2331
2763
  const { action } = payload;
@@ -2339,7 +2771,7 @@ function uiInteractionHandler(payload, context) {
2339
2771
  if (sliderId) {
2340
2772
  const smuggled = payload.value ?? payload.params?.value;
2341
2773
  if (smuggled !== void 0) {
2342
- chunkSUMIABJK_js.appilotsDebugLog(
2774
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2343
2775
  `uiInteractionHandler: "${actionStr}" on slider "${sliderId}" carried value=${JSON.stringify(smuggled)} \u2014 routing to set_value`
2344
2776
  );
2345
2777
  return setValueHandler(rawComponentId, smuggled, registry);
@@ -2350,23 +2782,23 @@ function uiInteractionHandler(payload, context) {
2350
2782
  diagnose: { ...buildUiDiagnose(sliderId, "unknown"), recoverable: true }
2351
2783
  };
2352
2784
  }
2353
- const openDialog = chunkSUMIABJK_js.getOpenNativeDialog();
2785
+ const openDialog = chunkQAZ4TN3Z_js.getOpenNativeDialog();
2354
2786
  const isPressVerb = actionStr === "press" || actionStr === "tap" || actionStr === "click";
2355
2787
  if (openDialog && isPressVerb) {
2356
2788
  const needle = normalizeIdent(rawComponentId);
2357
2789
  const button = openDialog.buttons.find((b) => normalizeIdent(b.label) === needle);
2358
2790
  if (button) {
2359
2791
  button.press();
2360
- chunkSUMIABJK_js.appilotsDebugLog(`uiInteractionHandler: pressed native dialog button "${button.label}"`);
2792
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`uiInteractionHandler: pressed native dialog button "${button.label}"`);
2361
2793
  return { success: true, effect: "changed" };
2362
2794
  }
2363
2795
  }
2364
2796
  if (!openDialog && isPressVerb) {
2365
- const answered = chunkSUMIABJK_js.getLastAnsweredNativeDialog();
2797
+ const answered = chunkQAZ4TN3Z_js.getLastAnsweredNativeDialog();
2366
2798
  const needle = normalizeIdent(rawComponentId);
2367
2799
  if (answered && needle) {
2368
2800
  if (answered.answeredWith && normalizeIdent(answered.answeredWith) === needle) {
2369
- chunkSUMIABJK_js.appilotsDebugLog(
2801
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2370
2802
  `uiInteractionHandler: native dialog button "${answered.answeredWith}" was already pressed and the dialog is closed \u2014 treating the repeat as done`
2371
2803
  );
2372
2804
  return { success: true, effect: "completed" };
@@ -2378,7 +2810,7 @@ function uiInteractionHandler(payload, context) {
2378
2810
  diagnose: {
2379
2811
  category: "component-not-found",
2380
2812
  targetId: rawComponentId,
2381
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
2813
+ screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
2382
2814
  recoverable: false
2383
2815
  }
2384
2816
  };
@@ -2387,7 +2819,7 @@ function uiInteractionHandler(payload, context) {
2387
2819
  }
2388
2820
  const occluded = checkModalOcclusion(rawComponentId, actionStr);
2389
2821
  if (occluded) {
2390
- chunkSUMIABJK_js.appilotsDebugLog(
2822
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2391
2823
  `uiInteractionHandler: blocked "${actionStr}" on "${rawComponentId}" \u2014 target is behind an open modal`
2392
2824
  );
2393
2825
  return occluded;
@@ -2395,7 +2827,7 @@ function uiInteractionHandler(payload, context) {
2395
2827
  if (typeof rawComponentId === "string" && rawComponentId.trim().toLowerCase().startsWith("el:")) {
2396
2828
  const result = dispatchElementOrTarget(rawComponentId, registry, actionStr);
2397
2829
  if (result.success) {
2398
- chunkSUMIABJK_js.appilotsDebugLog(
2830
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2399
2831
  `uiInteractionHandler: interaction element dispatch succeeded for "${rawComponentId}"`
2400
2832
  );
2401
2833
  }
@@ -2403,17 +2835,17 @@ function uiInteractionHandler(payload, context) {
2403
2835
  }
2404
2836
  const ordinal = parseSyntheticListItemId(rawComponentId);
2405
2837
  if (ordinal && (action === "press" || actionStr === "tap" || actionStr === "click" || actionStr === "longPress")) {
2406
- chunkSUMIABJK_js.appilotsDebugLog(
2838
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2407
2839
  `uiInteractionHandler: dispatching synthetic list ordinal \u2014 componentId="${rawComponentId}" list=${ordinal.listIndex} item=${ordinal.itemIndex}`
2408
2840
  );
2409
2841
  const result = pressListItemAtOrdinal(ordinal.listIndex, ordinal.itemIndex);
2410
2842
  if (result.ok) {
2411
- chunkSUMIABJK_js.appilotsDebugLog(
2843
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2412
2844
  `uiInteractionHandler: synthetic ordinal press succeeded (container=${result.containerType ?? "List"})`
2413
2845
  );
2414
2846
  return { success: true };
2415
2847
  }
2416
- const screen = chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
2848
+ const screen = chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
2417
2849
  if (result.reason === "list-not-found" || result.reason === "item-not-found") {
2418
2850
  return {
2419
2851
  success: false,
@@ -2454,7 +2886,7 @@ function uiInteractionHandler(payload, context) {
2454
2886
  };
2455
2887
  }
2456
2888
  const componentId = resolveComponentId(rawComponentId, registry, actionStr);
2457
- chunkSUMIABJK_js.appilotsDebugLog(
2889
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2458
2890
  `uiInteractionHandler: resolved componentId="${payload.componentId}" \u2192 "${componentId}"`
2459
2891
  );
2460
2892
  const target = registry.getTarget(componentId);
@@ -2507,7 +2939,7 @@ function uiInteractionHandler(payload, context) {
2507
2939
  return { success: false, error: err?.message ?? "Focus failed" };
2508
2940
  }
2509
2941
  }
2510
- chunkSUMIABJK_js.appilotsDebugLog(
2942
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2511
2943
  `uiInteractionHandler: registry miss for "${componentId}", falling back to fiber tree`
2512
2944
  );
2513
2945
  const namedToggle = dispatchIdentifiedToggle(componentId, actionStr);
@@ -2519,7 +2951,7 @@ function uiInteractionHandler(payload, context) {
2519
2951
  try {
2520
2952
  if (actionStr === "press" && handle.kind === "target" && handle.press) {
2521
2953
  handle.press();
2522
- chunkSUMIABJK_js.appilotsDebugLog(
2954
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
2523
2955
  `uiInteractionHandler: fiber fallback press succeeded for "${componentId}"`
2524
2956
  );
2525
2957
  return { success: true };
@@ -2555,6 +2987,28 @@ function uiInteractionHandler(payload, context) {
2555
2987
  };
2556
2988
  }
2557
2989
 
2990
+ // src/executor/completeTextEdit.ts
2991
+ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2992
+ async function completeTextEdit(fieldId, expected, registered, origin, resolveRegistered) {
2993
+ await sleep2(80);
2994
+ const current2 = findInteractiveByIdentifier(fieldId, { kind: "field" });
2995
+ if (origin?.controlIdentity && current2?.controlIdentity !== origin.controlIdentity) return false;
2996
+ if (registered && resolveRegistered && resolveRegistered() !== registered) return false;
2997
+ if (registered?.finishEditing) registered.finishEditing();
2998
+ else if (current2 && (current2.matchCount ?? 1) === 1 && !current2.disabled)
2999
+ current2.finishEditing?.();
3000
+ const started = Date.now();
3001
+ do {
3002
+ await sleep2(80);
3003
+ const live = findInteractiveByIdentifier(fieldId, { kind: "field" });
3004
+ if (origin?.controlIdentity && live?.controlIdentity !== origin.controlIdentity) return false;
3005
+ if (registered && resolveRegistered && resolveRegistered() !== registered) return false;
3006
+ const value = registered ? registered.getValue() : live?.getValue?.();
3007
+ if (value !== void 0 && value !== null && String(value) === String(expected)) return true;
3008
+ } while (Date.now() - started < 480);
3009
+ return false;
3010
+ }
3011
+
2558
3012
  // src/executor/formSubmitResolve.ts
2559
3013
  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
3014
  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 +3036,7 @@ function submitLabelHintsSubmit(label) {
2582
3036
  return SUBMIT_LABEL_HINT_RE.test(trimmed);
2583
3037
  }
2584
3038
  function screenDeclaresSubmitAction(screenName) {
2585
- const meta = chunkSUMIABJK_js.getScreenMetadata(screenName);
3039
+ const meta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
2586
3040
  return Array.isArray(meta?.actions) && meta.actions.some(
2587
3041
  (action) => typeof action === "object" && action !== null && action.type === "submit"
2588
3042
  );
@@ -2615,7 +3069,7 @@ function resolveFormScreensForSubmit(screen, activePath, registry) {
2615
3069
  } else {
2616
3070
  push(screen);
2617
3071
  }
2618
- push(chunkSUMIABJK_js.getCurrentScreen() ?? void 0);
3072
+ push(chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0);
2619
3073
  const withSubmit = [];
2620
3074
  const rest = [];
2621
3075
  for (const name of ordered) {
@@ -2633,7 +3087,7 @@ function collectSubmitTargetCandidates(screens, registry) {
2633
3087
  candidates.push(id);
2634
3088
  };
2635
3089
  for (const screenName of screens) {
2636
- const meta = chunkSUMIABJK_js.getScreenMetadata(screenName);
3090
+ const meta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
2637
3091
  const submitMeta = Array.isArray(meta?.actions) ? meta.actions.find(
2638
3092
  (action) => typeof action === "object" && action !== null && action.type === "submit"
2639
3093
  ) : void 0;
@@ -2677,8 +3131,8 @@ function readVisibleValidation(fieldId, label) {
2677
3131
  return void 0;
2678
3132
  }
2679
3133
  function resolveScreenContext() {
2680
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
2681
- const screen = activePath[activePath.length - 1] ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
3134
+ const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
3135
+ const screen = activePath[activePath.length - 1] ?? chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
2682
3136
  return { screen, activePath };
2683
3137
  }
2684
3138
  function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
@@ -2686,36 +3140,36 @@ function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
2686
3140
  if (!requested) return false;
2687
3141
  const meta = getMetadataField(fieldId, registry);
2688
3142
  const options = Array.isArray(meta?.options) ? meta.options : [];
2689
- const requestedNorm = chunkSUMIABJK_js.normalize3(requested);
2690
- const currentNorm = chunkSUMIABJK_js.normalize3(currentValue);
3143
+ const requestedNorm = chunkQAZ4TN3Z_js.normalize3(requested);
3144
+ const currentNorm = chunkQAZ4TN3Z_js.normalize3(currentValue);
2691
3145
  if (currentNorm === requestedNorm) return true;
2692
3146
  for (const option of options) {
2693
3147
  const value = typeof option?.value === "string" ? option.value : "";
2694
3148
  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;
3149
+ if (chunkQAZ4TN3Z_js.normalize3(value) === requestedNorm && chunkQAZ4TN3Z_js.normalize3(label) === currentNorm) return true;
3150
+ if (chunkQAZ4TN3Z_js.normalize3(label) === requestedNorm && chunkQAZ4TN3Z_js.normalize3(label) === currentNorm) return true;
3151
+ if (chunkQAZ4TN3Z_js.normalize3(value) === requestedNorm && chunkQAZ4TN3Z_js.normalize3(value) === currentNorm) return true;
2698
3152
  }
2699
3153
  return false;
2700
3154
  }
2701
3155
  function getMetadataField(fieldId, registry) {
2702
3156
  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);
3157
+ for (const name of chunkQAZ4TN3Z_js.getActiveRouteNames()) screens.add(name);
3158
+ const current2 = chunkQAZ4TN3Z_js.getCurrentScreen();
3159
+ if (current2) screens.add(current2);
2706
3160
  if (registry) {
2707
3161
  for (const comp of registry.snapshot()) {
2708
3162
  if (comp.kind === "field" && comp.screen) screens.add(comp.screen);
2709
3163
  }
2710
3164
  }
2711
- const needle = chunkSUMIABJK_js.normalize3(fieldId);
3165
+ const needle = chunkQAZ4TN3Z_js.normalize3(fieldId);
2712
3166
  for (const screenName of screens) {
2713
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(screenName);
3167
+ const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
2714
3168
  const fields = Array.isArray(screenMeta?.fields) ? screenMeta.fields : [];
2715
3169
  const match = fields.find((field) => {
2716
3170
  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) : "";
3171
+ const id = typeof field.id === "string" ? chunkQAZ4TN3Z_js.normalize3(field.id) : "";
3172
+ const label = typeof field.label === "string" ? chunkQAZ4TN3Z_js.normalize3(field.label) : "";
2719
3173
  return id === needle || label === needle;
2720
3174
  });
2721
3175
  if (match) return match;
@@ -2727,11 +3181,11 @@ function resolveSelectOption(fieldId, value, registry) {
2727
3181
  if (!requested) return void 0;
2728
3182
  const meta = getMetadataField(fieldId, registry);
2729
3183
  const options = Array.isArray(meta?.options) ? meta.options : [];
2730
- const requestedNorm = chunkSUMIABJK_js.normalize3(requested);
3184
+ const requestedNorm = chunkQAZ4TN3Z_js.normalize3(requested);
2731
3185
  for (const option of options) {
2732
3186
  const optionValue = typeof option?.value === "string" ? option.value : "";
2733
3187
  const optionLabel = typeof option?.label === "string" ? option.label : "";
2734
- if (chunkSUMIABJK_js.normalize3(optionValue) === requestedNorm || chunkSUMIABJK_js.normalize3(optionLabel) === requestedNorm) {
3188
+ if (chunkQAZ4TN3Z_js.normalize3(optionValue) === requestedNorm || chunkQAZ4TN3Z_js.normalize3(optionLabel) === requestedNorm) {
2735
3189
  return { value: optionValue, label: optionLabel };
2736
3190
  }
2737
3191
  }
@@ -2743,7 +3197,7 @@ async function tryOpenSelectModal(fieldId, registry) {
2743
3197
  if (!target) continue;
2744
3198
  try {
2745
3199
  target.press();
2746
- await sleep2(180);
3200
+ await sleep3(180);
2747
3201
  return true;
2748
3202
  } catch {
2749
3203
  }
@@ -2781,12 +3235,12 @@ async function tryPressSelectOption(fieldId, value, registry, options = {}) {
2781
3235
  return {
2782
3236
  success: false,
2783
3237
  error: `No pressable option found for select field "${fieldId}"`,
2784
- diagnose: { category: "component-not-found", fieldId, screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
3238
+ diagnose: { category: "component-not-found", fieldId, screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0 }
2785
3239
  };
2786
3240
  }
2787
3241
  function normalizeFieldType(type) {
2788
3242
  if (typeof type !== "string") return void 0;
2789
- const normalized = chunkSUMIABJK_js.normalize3(type);
3243
+ const normalized = chunkQAZ4TN3Z_js.normalize3(type);
2790
3244
  if (normalized === "select" || normalized === "picker" || normalized === "dropdown")
2791
3245
  return "select";
2792
3246
  if (normalized === "toggle" || normalized === "switch" || normalized === "checkbox")
@@ -2816,7 +3270,7 @@ function fieldCueTerms(fieldId, label) {
2816
3270
  );
2817
3271
  const terms = /* @__PURE__ */ new Set();
2818
3272
  for (const value of raw) {
2819
- const normalized = chunkSUMIABJK_js.normalize3(value);
3273
+ const normalized = chunkQAZ4TN3Z_js.normalize3(value);
2820
3274
  if (normalized.length >= 3 && normalized !== "id") terms.add(normalized);
2821
3275
  }
2822
3276
  return [...terms];
@@ -2824,17 +3278,17 @@ function fieldCueTerms(fieldId, label) {
2824
3278
  function snapshotHasFieldCue(snap, fieldId, label) {
2825
3279
  const terms = fieldCueTerms(fieldId, label);
2826
3280
  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);
3281
+ const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) => chunkQAZ4TN3Z_js.normalize3(text)).filter(Boolean);
2828
3282
  return visible.some((text) => terms.some((term) => text.includes(term) || term.includes(text)));
2829
3283
  }
2830
3284
  function scoreCandidateText(value, texts) {
2831
- const valueNorm = chunkSUMIABJK_js.normalize3(String(value ?? ""));
3285
+ const valueNorm = chunkQAZ4TN3Z_js.normalize3(String(value ?? ""));
2832
3286
  if (!valueNorm) return 0;
2833
3287
  let best = 0;
2834
3288
  for (const text of texts) {
2835
- const textNorm = chunkSUMIABJK_js.normalize3(text);
3289
+ const textNorm = chunkQAZ4TN3Z_js.normalize3(text);
2836
3290
  if (!textNorm) continue;
2837
- best = Math.max(best, chunkSUMIABJK_js.matchScore(valueNorm, textNorm));
3291
+ best = Math.max(best, chunkQAZ4TN3Z_js.matchScore(valueNorm, textNorm));
2838
3292
  }
2839
3293
  return best;
2840
3294
  }
@@ -2848,7 +3302,7 @@ function optionTexts(option) {
2848
3302
  function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue, registry) {
2849
3303
  const fieldLabel = getFieldLabel(fieldId, registry);
2850
3304
  const fieldCueVisible = snapshotHasFieldCue(snap, fieldId, fieldLabel);
2851
- const genericValue = chunkSUMIABJK_js.isGenericSelectValue(value);
3305
+ const genericValue = chunkQAZ4TN3Z_js.isGenericSelectValue(value);
2852
3306
  const candidates = [];
2853
3307
  let order = 0;
2854
3308
  const choiceGroups = snap.choiceGroups ?? [];
@@ -2860,7 +3314,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
2860
3314
  const groupCueScore = Math.max(
2861
3315
  globalCueScore,
2862
3316
  ...groupTexts.map((text) => {
2863
- const normalized = chunkSUMIABJK_js.normalize3(text);
3317
+ const normalized = chunkQAZ4TN3Z_js.normalize3(text);
2864
3318
  return fieldCueTerms(fieldId, fieldLabel).some(
2865
3319
  (term) => normalized.includes(term) || term.includes(normalized)
2866
3320
  ) ? 80 : 0;
@@ -2897,7 +3351,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
2897
3351
  const elementCueScore = Math.max(
2898
3352
  fieldCueVisible && elements.length <= 12 ? 50 : 0,
2899
3353
  ...cueTexts.map((text) => {
2900
- const normalized = chunkSUMIABJK_js.normalize3(text);
3354
+ const normalized = chunkQAZ4TN3Z_js.normalize3(text);
2901
3355
  return fieldTerms.some((term) => normalized.includes(term) || term.includes(normalized)) ? 80 : 0;
2902
3356
  })
2903
3357
  );
@@ -2955,7 +3409,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
2955
3409
  return {
2956
3410
  success: false,
2957
3411
  error: err?.message ?? "Could not capture visible choices",
2958
- diagnose: { category: "unknown", fieldId, screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
3412
+ diagnose: { category: "unknown", fieldId, screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0 }
2959
3413
  };
2960
3414
  }
2961
3415
  const candidates = buildChoiceCandidates(
@@ -2973,7 +3427,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
2973
3427
  diagnose: {
2974
3428
  category: "component-not-found",
2975
3429
  fieldId,
2976
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0
3430
+ screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0
2977
3431
  }
2978
3432
  };
2979
3433
  }
@@ -2987,7 +3441,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
2987
3441
  }
2988
3442
  function isContinuationButton(label) {
2989
3443
  if (!label) return false;
2990
- return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkSUMIABJK_js.normalize3(label));
3444
+ return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkQAZ4TN3Z_js.normalize3(label));
2991
3445
  }
2992
3446
  function pressContinuationButton(registry) {
2993
3447
  const snap = captureSnapshot();
@@ -3000,40 +3454,44 @@ function pressContinuationButton(registry) {
3000
3454
  return {
3001
3455
  success: false,
3002
3456
  error: "No enabled continuation button is visible",
3003
- diagnose: { category: "component-not-found", screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
3457
+ diagnose: { category: "component-not-found", screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0 }
3004
3458
  };
3005
3459
  }
3006
3460
  return pressTargetByIdOrLabel(id, registry);
3007
3461
  }
3008
3462
  function findField(fieldId, registry) {
3009
- chunkSUMIABJK_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
3463
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
3010
3464
  const exact = registry.getField(fieldId);
3011
3465
  if (exact) {
3012
- chunkSUMIABJK_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
3466
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
3013
3467
  return exact;
3014
3468
  }
3015
3469
  const lower = fieldId.toLowerCase();
3016
3470
  const snapshot = registry.snapshot();
3017
3471
  for (const comp of snapshot) {
3018
3472
  if (comp.kind === "field" && comp.id.toLowerCase() === lower) {
3019
- chunkSUMIABJK_js.appilotsDebugLog(
3473
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3020
3474
  `findField: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
3021
3475
  );
3022
3476
  return registry.getField(comp.id);
3023
3477
  }
3024
3478
  }
3025
- const currentScreenForTieBreak = chunkSUMIABJK_js.getCurrentScreen();
3026
- const needle = chunkSUMIABJK_js.normalize3(fieldId);
3479
+ if (findInteractiveByIdentifier(fieldId, { kind: "field", minScore: IDENTITY_MATCH_SCORE })) {
3480
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`findField: "${fieldId}" names a live input \u2014 not guessing in the registry`);
3481
+ return void 0;
3482
+ }
3483
+ const currentScreenForTieBreak = chunkQAZ4TN3Z_js.getCurrentScreen();
3484
+ const needle = chunkQAZ4TN3Z_js.normalize3(fieldId);
3027
3485
  let bestComp;
3028
3486
  let bestScore = 0;
3029
3487
  let bestOnCurrentScreen = false;
3030
3488
  for (const comp of snapshot) {
3031
3489
  if (comp.kind !== "field") continue;
3032
- const candidates = [chunkSUMIABJK_js.normalize3(comp.id)];
3033
- if (comp.label) candidates.push(chunkSUMIABJK_js.normalize3(comp.label));
3490
+ const candidates = [chunkQAZ4TN3Z_js.normalize3(comp.id)];
3491
+ if (comp.label) candidates.push(chunkQAZ4TN3Z_js.normalize3(comp.label));
3034
3492
  let candidateScore = 0;
3035
3493
  for (const cand of candidates) {
3036
- const s = chunkSUMIABJK_js.matchScore(needle, cand);
3494
+ const s = chunkQAZ4TN3Z_js.matchScore(needle, cand);
3037
3495
  if (s > candidateScore) candidateScore = s;
3038
3496
  }
3039
3497
  if (candidateScore === 0) continue;
@@ -3046,14 +3504,14 @@ function findField(fieldId, registry) {
3046
3504
  }
3047
3505
  }
3048
3506
  if (bestComp && bestScore >= 75) {
3049
- chunkSUMIABJK_js.appilotsDebugLog(
3507
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3050
3508
  `findField: scored match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
3051
3509
  );
3052
3510
  return registry.getField(bestComp.id);
3053
3511
  }
3054
- const currentScreen = chunkSUMIABJK_js.getCurrentScreen();
3512
+ const currentScreen = chunkQAZ4TN3Z_js.getCurrentScreen();
3055
3513
  if (currentScreen) {
3056
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(currentScreen);
3514
+ const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(currentScreen);
3057
3515
  const fields = screenMeta?.fields;
3058
3516
  if (fields && Array.isArray(fields)) {
3059
3517
  const metaField = fields.find(
@@ -3061,19 +3519,19 @@ function findField(fieldId, registry) {
3061
3519
  );
3062
3520
  if (metaField && typeof metaField === "object" && metaField.label) {
3063
3521
  const metaLabel = metaField.label;
3064
- const metaNeedle = chunkSUMIABJK_js.normalize3(metaLabel);
3522
+ const metaNeedle = chunkQAZ4TN3Z_js.normalize3(metaLabel);
3065
3523
  let mBest;
3066
3524
  let mBestScore = 0;
3067
3525
  for (const comp of snapshot) {
3068
3526
  if (comp.kind !== "field" || !comp.label) continue;
3069
- const score = chunkSUMIABJK_js.matchScore(metaNeedle, chunkSUMIABJK_js.normalize3(comp.label));
3527
+ const score = chunkQAZ4TN3Z_js.matchScore(metaNeedle, chunkQAZ4TN3Z_js.normalize3(comp.label));
3070
3528
  if (score > mBestScore) {
3071
3529
  mBestScore = score;
3072
3530
  mBest = comp;
3073
3531
  }
3074
3532
  }
3075
3533
  if (mBest && mBestScore >= 60) {
3076
- chunkSUMIABJK_js.appilotsDebugLog(
3534
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3077
3535
  `findField: FOUND via screen metadata translation: fieldId="${fieldId}" -> metaLabel="${metaLabel}" -> registered="${mBest.id}" (score=${mBestScore})`
3078
3536
  );
3079
3537
  return registry.getField(mBest.id);
@@ -3082,34 +3540,34 @@ function findField(fieldId, registry) {
3082
3540
  }
3083
3541
  }
3084
3542
  if (bestComp && bestScore >= 40) {
3085
- chunkSUMIABJK_js.appilotsDebugLog(
3543
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3086
3544
  `findField: weak substring match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
3087
3545
  );
3088
3546
  return registry.getField(bestComp.id);
3089
3547
  }
3090
- chunkSUMIABJK_js.appilotsDebugWarn(
3548
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
3091
3549
  `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
3550
  );
3093
3551
  return void 0;
3094
3552
  }
3095
3553
  function findToggle(fieldId, registry) {
3096
- chunkSUMIABJK_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
3554
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
3097
3555
  const exact = registry.getToggle(fieldId);
3098
3556
  if (exact) {
3099
- chunkSUMIABJK_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
3557
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
3100
3558
  return exact;
3101
3559
  }
3102
3560
  const lower = fieldId.toLowerCase();
3103
3561
  const snapshot = registry.snapshot();
3104
3562
  for (const comp of snapshot) {
3105
3563
  if (comp.kind === "toggle" && comp.id.toLowerCase() === lower) {
3106
- chunkSUMIABJK_js.appilotsDebugLog(
3564
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3107
3565
  `findToggle: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
3108
3566
  );
3109
3567
  return registry.getToggle(comp.id);
3110
3568
  }
3111
3569
  }
3112
- chunkSUMIABJK_js.appilotsDebugWarn(
3570
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
3113
3571
  `findToggle: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available toggles: ${snapshot.filter((c) => c.kind === "toggle").map((c) => `"${c.id}"`).join(", ") || "none"}`
3114
3572
  );
3115
3573
  return void 0;
@@ -3120,7 +3578,7 @@ function findSlider(fieldId, registry) {
3120
3578
  const lower = fieldId.toLowerCase();
3121
3579
  for (const comp of registry.snapshot()) {
3122
3580
  if (comp.kind === "slider" && comp.id.toLowerCase() === lower) {
3123
- chunkSUMIABJK_js.appilotsDebugLog(
3581
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3124
3582
  `findSlider: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
3125
3583
  );
3126
3584
  return registry.getSlider(comp.id);
@@ -3128,17 +3586,17 @@ function findSlider(fieldId, registry) {
3128
3586
  }
3129
3587
  return void 0;
3130
3588
  }
3131
- var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3589
+ var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3132
3590
  async function formFillHandler(payload, context) {
3133
3591
  const { permissions } = context;
3134
- const registry = context.registry ?? chunkSUMIABJK_js.componentRegistry;
3592
+ const registry = context.registry ?? chunkQAZ4TN3Z_js.componentRegistry;
3135
3593
  const { screen, activePath } = resolveScreenContext();
3136
3594
  const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
3137
3595
  if (!permissions.canFillForms) {
3138
3596
  return {
3139
3597
  success: false,
3140
- error: "Form filling is not permitted",
3141
- diagnose: { category: "unknown", screen: screenPath }
3598
+ error: chunkQAZ4TN3Z_js.permissionDeniedMessage("Form filling", "canFillForms"),
3599
+ diagnose: { category: "unknown", screen: screenPath, recoverable: false }
3142
3600
  };
3143
3601
  }
3144
3602
  if (!payload.fields || payload.fields.length === 0) {
@@ -3150,11 +3608,11 @@ async function formFillHandler(payload, context) {
3150
3608
  }
3151
3609
  const registrySnapshot = registry.snapshot();
3152
3610
  if (registrySnapshot.length === 0) {
3153
- chunkSUMIABJK_js.appilotsDebugWarn(
3611
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
3154
3612
  "formFillHandler: registry is EMPTY \u2014 auto-tracking may not be active. Ensure enableAppilotsAutoTracking() runs before components mount."
3155
3613
  );
3156
3614
  } else {
3157
- chunkSUMIABJK_js.appilotsDebugLog(
3615
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3158
3616
  `[Appilots formFillHandler] Registry has ${registrySnapshot.length} components:`,
3159
3617
  registrySnapshot.map((c) => `${c.kind}:${c.id}`).join(", ")
3160
3618
  );
@@ -3162,7 +3620,7 @@ async function formFillHandler(payload, context) {
3162
3620
  const fieldResults = [];
3163
3621
  let allSuccess = true;
3164
3622
  let selectedChoiceThisBatch = false;
3165
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
3623
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
3166
3624
  const availableFieldIds = () => registry.snapshot().filter((comp) => comp.kind === "field").map((comp) => `${comp.id}${comp.label ? ` (${comp.label})` : ""}`).slice(0, 8);
3167
3625
  const isElementIdField = (field) => typeof field.fieldId === "string" && field.fieldId.trim().toLowerCase().startsWith("el:");
3168
3626
  for (const field of payload.fields.filter(isElementIdField)) {
@@ -3189,20 +3647,57 @@ async function formFillHandler(payload, context) {
3189
3647
  const { fieldId, fieldType, value } = field;
3190
3648
  const effectiveFieldType = getEffectiveFieldType(fieldId, fieldType, registry);
3191
3649
  let selectFailure;
3192
- chunkSUMIABJK_js.appilotsDebugLog(
3193
- `formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkSUMIABJK_js.describeValue(value)}`
3650
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3651
+ `formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkQAZ4TN3Z_js.describeValue(value)}`
3194
3652
  );
3195
3653
  const fieldEntry = findField(fieldId, registry);
3196
3654
  if (fieldEntry) {
3197
3655
  try {
3198
- chunkSUMIABJK_js.appilotsDebugLog(
3656
+ const nativeField = findInteractiveByIdentifier(fieldId, { kind: "field" });
3657
+ if (nativeField?.disabled || (nativeField?.matchCount ?? 1) > 1) {
3658
+ fieldResults.push({
3659
+ fieldId,
3660
+ success: false,
3661
+ error: nativeField?.disabled ? "The field is disabled" : "The field identifier matches multiple controls",
3662
+ diagnose: {
3663
+ category: nativeField?.disabled ? "disabled" : "ambiguous-target",
3664
+ fieldId,
3665
+ screen: screenPath
3666
+ }
3667
+ });
3668
+ allSuccess = false;
3669
+ continue;
3670
+ }
3671
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3199
3672
  `formFillHandler: found field "${fieldId}" via registry, calling setValue(<${String(value).length} chars>)`
3200
3673
  );
3201
3674
  const beforeValue = effectiveFieldType === "date" ? fieldEntry.getValue?.() ?? "" : void 0;
3202
3675
  fieldEntry.focus?.();
3203
3676
  fieldEntry.setValue(String(value));
3677
+ if (effectiveFieldType === "text" || effectiveFieldType === "number") {
3678
+ if (!await completeTextEdit(
3679
+ fieldId,
3680
+ value,
3681
+ fieldEntry,
3682
+ nativeField,
3683
+ () => findField(fieldId, registry)
3684
+ )) {
3685
+ fieldResults.push({
3686
+ fieldId,
3687
+ success: false,
3688
+ error: "The field did not retain the requested value after editing ended. Inspect its current value before retrying.",
3689
+ diagnose: { category: "validation", fieldId, screen: screenPath }
3690
+ });
3691
+ allSuccess = false;
3692
+ continue;
3693
+ }
3694
+ }
3204
3695
  if (effectiveFieldType === "date") {
3205
- const afterValue = fieldEntry.getValue?.() ?? "";
3696
+ let afterValue = fieldEntry.getValue?.() ?? "";
3697
+ if (afterValue === beforeValue) {
3698
+ await sleep3(80);
3699
+ afterValue = fieldEntry.getValue?.() ?? "";
3700
+ }
3206
3701
  if (afterValue === beforeValue) {
3207
3702
  fieldResults.push({
3208
3703
  fieldId,
@@ -3222,11 +3717,11 @@ async function formFillHandler(payload, context) {
3222
3717
  if (effectiveFieldType === "select") {
3223
3718
  let after = fieldEntry.getValue?.() ?? "";
3224
3719
  if (!selectValueApplied(fieldId, value, after, registry)) {
3225
- await sleep2(80);
3720
+ await sleep3(80);
3226
3721
  after = fieldEntry.getValue?.() ?? "";
3227
3722
  }
3228
3723
  if (!selectValueApplied(fieldId, value, after, registry)) {
3229
- chunkSUMIABJK_js.appilotsDebugWarn(
3724
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
3230
3725
  `formFillHandler: select field "${fieldId}" setValue did not stick (wrote <${String(value).length} chars>, current is <${String(after ?? "").length} chars>), trying visible choice fallback`
3231
3726
  );
3232
3727
  const selectResult = await selectVisibleChoice(fieldId, value, registry, {
@@ -3343,7 +3838,7 @@ async function formFillHandler(payload, context) {
3343
3838
  if (!selectResult.success && selectedChoiceThisBatch) {
3344
3839
  const nextResult = pressContinuationButton(registry);
3345
3840
  if (nextResult.success) {
3346
- await sleep2(180);
3841
+ await sleep3(180);
3347
3842
  selectResult = await selectVisibleChoice(fieldId, value, registry, {
3348
3843
  allowFirstVisibleWhenNoCue: true
3349
3844
  });
@@ -3351,24 +3846,50 @@ async function formFillHandler(payload, context) {
3351
3846
  }
3352
3847
  if (selectResult.success) {
3353
3848
  selectedChoiceThisBatch = true;
3354
- chunkSUMIABJK_js.appilotsDebugLog(
3849
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3355
3850
  `formFillHandler: selected visible option for "${fieldId}"` + (selectResult.selectedLabel ? ` \u2192 "${selectResult.selectedLabel}"` : "")
3356
3851
  );
3357
- await sleep2(120);
3852
+ await sleep3(120);
3358
3853
  fieldResults.push({ fieldId, success: true });
3359
3854
  continue;
3360
3855
  }
3361
3856
  selectFailure = selectResult;
3362
3857
  }
3363
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
3858
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
3364
3859
  const handle = findInteractiveByIdentifier(fieldId, {
3365
3860
  kind: effectiveFieldType === "toggle" ? "toggle" : "field"
3366
3861
  });
3367
3862
  if (handle?.setValue) {
3368
3863
  try {
3864
+ if (handle.disabled || (handle.matchCount ?? 1) > 1) {
3865
+ fieldResults.push({
3866
+ fieldId,
3867
+ success: false,
3868
+ error: handle.disabled ? "The field is disabled" : "The field identifier matches multiple controls",
3869
+ diagnose: {
3870
+ category: handle.disabled ? "disabled" : "ambiguous-target",
3871
+ fieldId,
3872
+ screen: screenPath,
3873
+ candidates: handle.matchCandidates
3874
+ }
3875
+ });
3876
+ allSuccess = false;
3877
+ continue;
3878
+ }
3879
+ setSpotlightTarget(handle.measure?.() ?? null, handle.label, "fill");
3369
3880
  handle.focus?.();
3370
3881
  handle.setValue(value);
3371
- chunkSUMIABJK_js.appilotsDebugLog(
3882
+ if (handle.kind === "field" && !await completeTextEdit(fieldId, value, void 0, handle)) {
3883
+ fieldResults.push({
3884
+ fieldId,
3885
+ success: false,
3886
+ error: "The field did not retain the requested value after editing ended. Inspect its current value before retrying.",
3887
+ diagnose: { category: "validation", fieldId, screen: screenPath }
3888
+ });
3889
+ allSuccess = false;
3890
+ continue;
3891
+ }
3892
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3372
3893
  `formFillHandler: fiber fallback succeeded for "${fieldId}" \u2192 label="${handle.label}"`
3373
3894
  );
3374
3895
  fieldResults.push({ fieldId, success: true });
@@ -3415,14 +3936,15 @@ async function formFillHandler(payload, context) {
3415
3936
  }
3416
3937
  if (!allSuccess) {
3417
3938
  const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
3418
- chunkSUMIABJK_js.appilotsDebugWarn(
3939
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
3419
3940
  "formFillHandler: submitAfterFill=true requested but some fields failed; NOT submitting" + (failedIds.length > 0 ? ` (failed: ${failedIds.join(", ")})` : "")
3420
3941
  );
3421
3942
  } else {
3422
- await sleep2(120);
3943
+ await sleep3(120);
3423
3944
  if (!permissions.canSubmitForms) {
3424
3945
  return { success: false, error: "Form submission is not permitted", fieldResults };
3425
3946
  }
3947
+ const beforeSubmitTexts = captureSnapshot().texts;
3426
3948
  const submitResult = pressSubmitButton(
3427
3949
  {
3428
3950
  screen,
@@ -3433,7 +3955,7 @@ async function formFillHandler(payload, context) {
3433
3955
  registry
3434
3956
  );
3435
3957
  if (!submitResult.success) {
3436
- chunkSUMIABJK_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
3958
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
3437
3959
  return {
3438
3960
  success: false,
3439
3961
  error: submitResult.error,
@@ -3442,10 +3964,11 @@ async function formFillHandler(payload, context) {
3442
3964
  };
3443
3965
  }
3444
3966
  const postSubmit = await waitForPostSubmitOutcome({
3445
- submitTargetId: submitResult.pressedTargetId
3967
+ submitTargetId: submitResult.pressedTargetId,
3968
+ beforeTexts: beforeSubmitTexts
3446
3969
  });
3447
3970
  if (postSubmit.status === "pending") {
3448
- chunkSUMIABJK_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
3971
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
3449
3972
  return {
3450
3973
  success: false,
3451
3974
  error: postSubmit.message,
@@ -3454,7 +3977,7 @@ async function formFillHandler(payload, context) {
3454
3977
  };
3455
3978
  }
3456
3979
  if (postSubmit.status === "failure") {
3457
- chunkSUMIABJK_js.appilotsDebugWarn(
3980
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
3458
3981
  `formFillHandler: submit rejected by visible validation \u2014 ${postSubmit.message}`
3459
3982
  );
3460
3983
  return {
@@ -3469,7 +3992,10 @@ async function formFillHandler(payload, context) {
3469
3992
  }
3470
3993
  };
3471
3994
  }
3472
- chunkSUMIABJK_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
3995
+ if (postSubmit.status === "unverified") {
3996
+ return { success: true, fieldResults, effect: "unknown" };
3997
+ }
3998
+ chunkQAZ4TN3Z_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
3473
3999
  }
3474
4000
  }
3475
4001
  const aggregatedDiagnose = aggregateFieldDiagnoses(fieldResults, screenPath);
@@ -3481,17 +4007,17 @@ async function formFillHandler(payload, context) {
3481
4007
  };
3482
4008
  }
3483
4009
  function pressSubmitButton(context, registry) {
3484
- const activePath = context.activePath ?? chunkSUMIABJK_js.getActiveRouteNames();
4010
+ const activePath = context.activePath ?? chunkQAZ4TN3Z_js.getActiveRouteNames();
3485
4011
  const hintScreen = context.screen ?? context.screenPath;
3486
4012
  const formScreens = resolveFormScreensForSubmit(hintScreen, activePath, registry);
3487
- const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
4013
+ const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
3488
4014
  const candidates = collectSubmitTargetCandidates(formScreens, registry);
3489
4015
  for (const candidate of candidates) {
3490
4016
  const target = registry.getTarget(candidate);
3491
4017
  if (target) {
3492
4018
  try {
3493
4019
  target.press();
3494
- chunkSUMIABJK_js.appilotsDebugLog(
4020
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3495
4021
  `formFillHandler: submitAfterFill \u2014 pressed registry target "${candidate}"` + (resolvedScreen ? ` on screen "${resolvedScreen}"` : "")
3496
4022
  );
3497
4023
  return { success: true, pressedTargetId: candidate };
@@ -3505,7 +4031,7 @@ function pressSubmitButton(context, registry) {
3505
4031
  }
3506
4032
  }
3507
4033
  for (const screenName of formScreens) {
3508
- const screenMeta = chunkSUMIABJK_js.getScreenMetadata(screenName);
4034
+ const screenMeta = chunkQAZ4TN3Z_js.getScreenMetadata(screenName);
3509
4035
  const submitMeta = Array.isArray(screenMeta?.actions) ? screenMeta.actions.find(
3510
4036
  (action) => typeof action === "object" && action !== null && action.type === "submit"
3511
4037
  ) : void 0;
@@ -3516,7 +4042,7 @@ function pressSubmitButton(context, registry) {
3516
4042
  if (handle?.press) {
3517
4043
  try {
3518
4044
  handle.press();
3519
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
4045
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
3520
4046
  return { success: true, pressedTargetId: submitId ?? submitLabel };
3521
4047
  } catch (err) {
3522
4048
  return {
@@ -3538,7 +4064,7 @@ function pressSubmitButton(context, registry) {
3538
4064
  if (id) {
3539
4065
  const pressed = pressTargetByIdOrLabel(id, registry);
3540
4066
  if (pressed.success) {
3541
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
4067
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
3542
4068
  return { success: true, pressedTargetId: id };
3543
4069
  }
3544
4070
  }
@@ -3552,7 +4078,7 @@ function pressSubmitButton(context, registry) {
3552
4078
  if (target) {
3553
4079
  try {
3554
4080
  target.press();
3555
- chunkSUMIABJK_js.appilotsDebugLog(
4081
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3556
4082
  `formFillHandler: submitAfterFill \u2014 pressed by label heuristic "${comp.label}"`
3557
4083
  );
3558
4084
  return { success: true, pressedTargetId: comp.id };
@@ -3568,7 +4094,7 @@ function pressSubmitButton(context, registry) {
3568
4094
  for (const fieldId of [...context.filledFieldIds ?? []].reverse()) {
3569
4095
  const handle = findInteractiveByIdentifier(fieldId, { kind: "field" });
3570
4096
  if (handle?.submitFromKeyboard?.()) {
3571
- chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 return key on "${fieldId}"`);
4097
+ chunkQAZ4TN3Z_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 return key on "${fieldId}"`);
3572
4098
  return { success: true, pressedTargetId: fieldId };
3573
4099
  }
3574
4100
  }
@@ -3606,7 +4132,21 @@ function aggregateFieldDiagnoses(results, screen) {
3606
4132
  var FALLBACK_PAGE_PX = 600;
3607
4133
  var PAGE_FRACTION = 0.85;
3608
4134
  var POST_SCROLL_MOUNT_MS = 400;
3609
- var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
4135
+ var PAGINATION_MAX_WAIT_MS = 4e3;
4136
+ var PAGINATION_POLL_MS = 150;
4137
+ var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
4138
+ async function settleAfterScroll() {
4139
+ await sleep4(POST_SCROLL_MOUNT_MS);
4140
+ if (!chunkQAZ4TN3Z_js.probeLoadingState(void 0, chunkQAZ4TN3Z_js.getCurrentScreen()).loading) return;
4141
+ const deadline = Date.now() + PAGINATION_MAX_WAIT_MS;
4142
+ while (Date.now() < deadline) {
4143
+ await sleep4(PAGINATION_POLL_MS);
4144
+ if (!chunkQAZ4TN3Z_js.probeLoadingState(void 0, chunkQAZ4TN3Z_js.getCurrentScreen()).loading) {
4145
+ await sleep4(POST_SCROLL_MOUNT_MS);
4146
+ return;
4147
+ }
4148
+ }
4149
+ }
3610
4150
  function normalizeId2(value) {
3611
4151
  return String(value ?? "").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "");
3612
4152
  }
@@ -3614,12 +4154,12 @@ function buildDiagnose(category, targetId, candidates) {
3614
4154
  return {
3615
4155
  category,
3616
4156
  targetId,
3617
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
4157
+ screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
3618
4158
  ...candidates && candidates.length > 0 ? { candidates: candidates.slice(0, 8) } : {}
3619
4159
  };
3620
4160
  }
3621
4161
  function resolveListEntry(listId) {
3622
- const entries = chunkSUMIABJK_js.listRegistry.snapshot();
4162
+ const entries = chunkQAZ4TN3Z_js.listRegistry.snapshot();
3623
4163
  if (entries.length === 0) return {};
3624
4164
  if (listId) {
3625
4165
  const wanted = normalizeId2(listId);
@@ -3642,13 +4182,26 @@ function pageOffset(metrics, direction) {
3642
4182
  }
3643
4183
  return next;
3644
4184
  }
4185
+ async function finishScroll(entry, before) {
4186
+ await settleAfterScroll();
4187
+ const current2 = chunkQAZ4TN3Z_js.listRegistry.get(entry.id) ?? entry;
4188
+ const after = current2.getScrollMetrics?.();
4189
+ const grew = typeof entry.itemCount === "number" && typeof current2.itemCount === "number" && current2.itemCount > entry.itemCount;
4190
+ const moved = grew || !!(before && after && (Math.abs(after.offset - before.offset) > 2 || after.contentLength > before.contentLength + 2));
4191
+ const outcome = moved ? "moved" : before && after ? "no-progress" : "unverified";
4192
+ current2.exploration?.recordScroll(outcome);
4193
+ return {
4194
+ success: true,
4195
+ effect: moved ? "changed" : outcome === "no-progress" ? "none" : "unknown"
4196
+ };
4197
+ }
3645
4198
  async function scrollListHandler(payload, context) {
3646
4199
  const { permissions } = context;
3647
4200
  if (!permissions.canInteractUI) {
3648
4201
  return {
3649
4202
  success: false,
3650
- error: "UI interaction is not permitted",
3651
- diagnose: buildDiagnose("unknown", payload.listId)
4203
+ error: chunkQAZ4TN3Z_js.permissionDeniedMessage("UI interaction", "canInteractUI"),
4204
+ diagnose: { ...buildDiagnose("unknown", payload.listId), recoverable: false }
3652
4205
  };
3653
4206
  }
3654
4207
  const toIndex = typeof payload.toIndex === "number" ? payload.toIndex : void 0;
@@ -3676,6 +4229,15 @@ async function scrollListHandler(payload, context) {
3676
4229
  diagnose: buildDiagnose("component-not-found", payload.listId, candidates)
3677
4230
  };
3678
4231
  }
4232
+ const exploration = entry.exploration?.snapshot();
4233
+ if (exploration && (exploration.remainingScrollSteps === 0 || exploration.consecutiveNoProgress >= 2)) {
4234
+ return {
4235
+ success: false,
4236
+ effect: "none",
4237
+ 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.",
4238
+ diagnose: { ...buildDiagnose("validation", entry.id), recoverable: false }
4239
+ };
4240
+ }
3679
4241
  if (toIndex !== void 0) {
3680
4242
  if (entry.kind === "scroll") {
3681
4243
  return {
@@ -3691,17 +4253,16 @@ async function scrollListHandler(payload, context) {
3691
4253
  diagnose: buildDiagnose("validation", entry.id)
3692
4254
  };
3693
4255
  }
4256
+ const before = entry.getScrollMetrics?.();
3694
4257
  const zeroBased = toIndex - 1;
3695
4258
  if (entry.scrollToIndex?.(zeroBased)) {
3696
- await sleep3(POST_SCROLL_MOUNT_MS);
3697
- return { success: true };
4259
+ return finishScroll(entry, before);
3698
4260
  }
3699
4261
  const metrics2 = entry.getScrollMetrics?.();
3700
4262
  if (metrics2 && metrics2.contentLength > 0 && typeof entry.itemCount === "number" && entry.itemCount > 0) {
3701
4263
  const estimated = zeroBased / entry.itemCount * metrics2.contentLength;
3702
4264
  if (entry.scrollToOffset?.(Math.max(0, estimated))) {
3703
- await sleep3(POST_SCROLL_MOUNT_MS);
3704
- return { success: true };
4265
+ return finishScroll(entry, before);
3705
4266
  }
3706
4267
  }
3707
4268
  return {
@@ -3711,10 +4272,21 @@ async function scrollListHandler(payload, context) {
3711
4272
  };
3712
4273
  }
3713
4274
  const metrics = entry.getScrollMetrics?.();
4275
+ if (!metrics && exploration?.lastScroll === "unverified") {
4276
+ return {
4277
+ success: false,
4278
+ effect: "unknown",
4279
+ error: "Scroll offset is still unavailable after one probe. Cannot safely page again; do not infer the end or repeat the same absolute offset.",
4280
+ diagnose: { ...buildDiagnose("validation", entry.id), recoverable: false }
4281
+ };
4282
+ }
3714
4283
  const target = pageOffset(metrics, direction);
4284
+ if (metrics && Math.abs(target - metrics.offset) <= 2) {
4285
+ entry.exploration?.recordScroll("boundary");
4286
+ return { success: true, effect: "none" };
4287
+ }
3715
4288
  if (entry.scrollToOffset?.(target)) {
3716
- await sleep3(POST_SCROLL_MOUNT_MS);
3717
- return { success: true };
4289
+ return finishScroll(entry, metrics);
3718
4290
  }
3719
4291
  return {
3720
4292
  success: false,
@@ -3763,12 +4335,12 @@ function resolveActionHints(screen, pressedComponentId, actionPayload) {
3763
4335
  if (typeof declared === "number") return { asyncBudgetMs: declared };
3764
4336
  }
3765
4337
  if (!screen || !pressedComponentId) return void 0;
3766
- const meta = chunkSUMIABJK_js.getScreenMetadata(screen);
4338
+ const meta = chunkQAZ4TN3Z_js.getScreenMetadata(screen);
3767
4339
  const actions = meta?.actions;
3768
4340
  if (!actions || actions.length === 0) return void 0;
3769
4341
  for (const a of actions) {
3770
4342
  if (typeof a === "string") continue;
3771
- if (chunkSUMIABJK_js.idLooselyMatches(a.id, pressedComponentId)) {
4343
+ if (chunkQAZ4TN3Z_js.idLooselyMatches(a.id, pressedComponentId)) {
3772
4344
  const inferred = a.appilotsInferred;
3773
4345
  const declared = a.asyncBudgetMs;
3774
4346
  const hints = {
@@ -3798,12 +4370,12 @@ function hashFieldValue(value) {
3798
4370
  }
3799
4371
  return (hash >>> 0).toString(36);
3800
4372
  }
3801
- var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date"]);
4373
+ var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date", "number"]);
3802
4374
  function discreteFieldSignature() {
3803
4375
  const sigs = [];
3804
- for (const { id, kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
4376
+ for (const { id, kind } of chunkQAZ4TN3Z_js.componentRegistry.snapshot()) {
3805
4377
  if (kind !== "field") continue;
3806
- const entry = chunkSUMIABJK_js.componentRegistry.getField(id);
4378
+ const entry = chunkQAZ4TN3Z_js.componentRegistry.getField(id);
3807
4379
  if (!entry || !DISCRETE_FIELD_TYPES.has(entry.fieldType ?? "")) continue;
3808
4380
  try {
3809
4381
  sigs.push(`${id}:${hashFieldValue(String(entry.getValue() ?? ""))}`);
@@ -3812,35 +4384,46 @@ function discreteFieldSignature() {
3812
4384
  }
3813
4385
  return sigs.sort().join(",");
3814
4386
  }
3815
- async function waitForPostInteractionSettle(payload) {
4387
+ function capturePreInteractionBaseline(payload) {
3816
4388
  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 !== "";
4389
+ const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
4390
+ const probe = chunkQAZ4TN3Z_js.probeLoadingState(targetId || null, screen);
4391
+ return {
4392
+ fingerprint: probe.fingerprint,
4393
+ fields: discreteFieldSignature(),
4394
+ screen,
4395
+ readable: probe.fingerprint !== ""
4396
+ };
4397
+ }
4398
+ async function waitForPostInteractionSettle(payload, preBaseline) {
4399
+ const targetId = targetIdFromPayload(payload);
4400
+ const baseline = preBaseline ?? capturePreInteractionBaseline(payload);
4401
+ const fromScreen = baseline.screen;
4402
+ const baselineFields = baseline.fields;
4403
+ const readable = baseline.readable;
3821
4404
  await sleepMs(100);
3822
- const afterPress = chunkSUMIABJK_js.probeLoadingState(targetId || null, chunkSUMIABJK_js.getCurrentScreen());
4405
+ const afterPress = chunkQAZ4TN3Z_js.probeLoadingState(targetId || null, chunkQAZ4TN3Z_js.getCurrentScreen());
3823
4406
  const modalOrLoading = afterPress.modalOpen || afterPress.loading || afterPress.pressedDisabled;
3824
4407
  const fingerprintChanged = afterPress.fingerprint !== baseline.fingerprint;
3825
4408
  const verdict = () => {
3826
4409
  if (!readable) return { effect: "unknown" };
3827
- const settled = chunkSUMIABJK_js.probeLoadingState(targetId || null, chunkSUMIABJK_js.getCurrentScreen());
4410
+ const settled = chunkQAZ4TN3Z_js.probeLoadingState(targetId || null, chunkQAZ4TN3Z_js.getCurrentScreen());
3828
4411
  if (settled.fingerprint === "") return { effect: "unknown" };
3829
4412
  if (discreteFieldSignature() !== baselineFields) return { effect: "changed" };
3830
4413
  return { effect: settled.fingerprint !== baseline.fingerprint ? "changed" : "none" };
3831
4414
  };
3832
4415
  const declared = declaredBudgetMs(resolveActionHints(fromScreen, targetId || null, payload));
3833
- const capMs = declared ?? (chunkSUMIABJK_js.isListItemPressTarget(targetId) ? 5e3 : 1e4);
4416
+ const capMs = declared ?? (chunkQAZ4TN3Z_js.isListItemPressTarget(targetId) ? 5e3 : 1e4);
3834
4417
  if (modalOrLoading || fingerprintChanged) {
3835
- await chunkSUMIABJK_js.waitForLoadingSettle({
4418
+ await chunkQAZ4TN3Z_js.waitForLoadingSettle({
3836
4419
  pressedComponentId: targetId || null,
3837
4420
  fromScreen,
3838
4421
  maxMs: capMs
3839
4422
  });
3840
4423
  return verdict();
3841
4424
  }
3842
- if (chunkSUMIABJK_js.isListItemPressTarget(targetId)) {
3843
- await chunkSUMIABJK_js.waitForLoadingSettle({
4425
+ if (chunkQAZ4TN3Z_js.isListItemPressTarget(targetId)) {
4426
+ await chunkQAZ4TN3Z_js.waitForLoadingSettle({
3844
4427
  fromScreen,
3845
4428
  maxMs: 3e3
3846
4429
  });
@@ -3849,19 +4432,13 @@ async function waitForPostInteractionSettle(payload) {
3849
4432
  }
3850
4433
 
3851
4434
  // src/executor/ActionExecutor.ts
3852
- var DEFAULT_PERMISSIONS = {
3853
- canNavigate: true,
3854
- canFillForms: true,
3855
- canInteractUI: true,
3856
- canSubmitForms: true
3857
- };
3858
4435
  function validateActionPayload(action) {
3859
4436
  const invalid = (message, ids) => ({
3860
4437
  success: false,
3861
4438
  error: message,
3862
4439
  diagnose: {
3863
4440
  category: "validation",
3864
- screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
4441
+ screen: chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0,
3865
4442
  ...ids ?? {}
3866
4443
  }
3867
4444
  });
@@ -3922,10 +4499,10 @@ function isDestructivePayload(payload) {
3922
4499
  return !!params && typeof params === "object" && params.destructive === true;
3923
4500
  }
3924
4501
  async function executeAction(action, context) {
3925
- chunkSUMIABJK_js.appilotsDebugLog(
4502
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
3926
4503
  `executeAction called: type="${action.type}", id="${action.id}", payload=${JSON.stringify(action.payload)}`
3927
4504
  );
3928
- const permissions = context.permissions ?? DEFAULT_PERMISSIONS;
4505
+ const permissions = chunkQAZ4TN3Z_js.resolveAgentPermissions(context.permissions);
3929
4506
  context.emit({
3930
4507
  type: "agent:action:start",
3931
4508
  timestamp: Date.now(),
@@ -3951,7 +4528,7 @@ async function executeAction(action, context) {
3951
4528
  let result;
3952
4529
  const validationFailure = validateActionPayload(action);
3953
4530
  if (validationFailure) {
3954
- chunkSUMIABJK_js.appilotsDebugWarn(
4531
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
3955
4532
  `executeAction: payload validation failed for type="${action.type}" id="${action.id}": ${validationFailure.error}`
3956
4533
  );
3957
4534
  context.emit({
@@ -3978,17 +4555,18 @@ async function executeAction(action, context) {
3978
4555
  case "form_fill":
3979
4556
  result = await formFillHandler(action.payload, {
3980
4557
  permissions,
3981
- registry: context.registry ?? chunkSUMIABJK_js.getDefaultRegistry()
4558
+ registry: context.registry ?? chunkQAZ4TN3Z_js.getDefaultRegistry()
3982
4559
  });
3983
4560
  break;
3984
4561
  case "ui_interaction": {
3985
4562
  const payload = action.payload;
4563
+ const baseline = capturePreInteractionBaseline(payload);
3986
4564
  result = uiInteractionHandler(payload, {
3987
4565
  permissions,
3988
- registry: context.registry ?? chunkSUMIABJK_js.getDefaultRegistry()
4566
+ registry: context.registry ?? chunkQAZ4TN3Z_js.getDefaultRegistry()
3989
4567
  });
3990
4568
  if (result.success) {
3991
- const settle = await waitForPostInteractionSettle(payload);
4569
+ const settle = await waitForPostInteractionSettle(payload, baseline);
3992
4570
  result.effect = result.effect ?? effectFor(payload, settle.effect);
3993
4571
  }
3994
4572
  break;
@@ -4014,7 +4592,7 @@ async function executeAction(action, context) {
4014
4592
  };
4015
4593
  }
4016
4594
  } catch (err) {
4017
- chunkSUMIABJK_js.appilotsDebugWarn(
4595
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
4018
4596
  `executeAction: exception during action type="${action.type}" id="${action.id}": ${err?.message}`
4019
4597
  );
4020
4598
  result = {
@@ -4022,7 +4600,7 @@ async function executeAction(action, context) {
4022
4600
  error: err?.message ?? "Action execution failed unexpectedly"
4023
4601
  };
4024
4602
  }
4025
- chunkSUMIABJK_js.appilotsDebugLog(
4603
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
4026
4604
  `executeAction result: type="${action.type}", id="${action.id}", success=${result.success}, error=${result.error ?? "none"}`
4027
4605
  );
4028
4606
  context.emit({
@@ -4076,18 +4654,28 @@ var _patchedAlert = (title, message, buttons, options) => {
4076
4654
  return suppression.originalAlert(title, message, buttons, options);
4077
4655
  }
4078
4656
  suppression.consumed = true;
4079
- chunkSUMIABJK_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
4657
+ const report = (handlerCompleted) => suppression.onHandled?.({
4658
+ title: title.slice(0, 300),
4659
+ message: message?.slice(0, 1e3),
4660
+ buttonLabel: button.text?.slice(0, 160),
4661
+ handlerCompleted
4662
+ });
4663
+ chunkQAZ4TN3Z_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
4080
4664
  try {
4081
- suppression.pending = Promise.resolve(button.onPress()).then(() => void 0).catch((err) => reportHandlerFailure(err));
4665
+ suppression.pending = Promise.resolve(button.onPress()).then(() => report(true)).catch((err) => {
4666
+ reportHandlerFailure(err);
4667
+ report(false);
4668
+ });
4082
4669
  } catch (err) {
4083
4670
  reportHandlerFailure(err);
4084
4671
  suppression.pending = null;
4672
+ report(false);
4085
4673
  }
4086
4674
  };
4087
4675
  function reportHandlerFailure(err) {
4088
4676
  console.error("[Appilots] The app\u2019s Alert handler threw while being auto-confirmed", err);
4089
4677
  }
4090
- async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4678
+ async function runWithConfirmedDestructiveContext(enabled, host, fn, onHandled) {
4091
4679
  if (!enabled) return fn();
4092
4680
  if (_active) {
4093
4681
  _active.depth += 1;
@@ -4108,6 +4696,7 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4108
4696
  depth: 1,
4109
4697
  consumed: false,
4110
4698
  pending: null,
4699
+ onHandled,
4111
4700
  timer: null
4112
4701
  };
4113
4702
  _active = suppression;
@@ -4127,45 +4716,67 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4127
4716
  }
4128
4717
 
4129
4718
  // src/platform/reactNativeAdapter.ts
4130
- var deltaTracker = chunkSUMIABJK_js.createSnapshotDeltaTracker();
4719
+ var deltaTracker = chunkQAZ4TN3Z_js.createSnapshotDeltaTracker();
4131
4720
  function resolveScreenMetadata() {
4132
- const activePath = chunkSUMIABJK_js.getActiveRouteNames();
4721
+ const activePath = chunkQAZ4TN3Z_js.getActiveRouteNames();
4133
4722
  for (let i = activePath.length - 1; i >= 0; i--) {
4134
4723
  const name = activePath[i];
4135
- const meta = name ? chunkSUMIABJK_js.getScreenMetadata(name) : void 0;
4724
+ const meta = name ? chunkQAZ4TN3Z_js.getScreenMetadata(name) : void 0;
4136
4725
  if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
4137
4726
  return meta;
4138
4727
  }
4139
4728
  }
4140
- const screen = chunkSUMIABJK_js.getCurrentScreen();
4141
- return screen ? chunkSUMIABJK_js.getScreenMetadata(screen) : void 0;
4729
+ const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
4730
+ return screen ? chunkQAZ4TN3Z_js.getScreenMetadata(screen) : void 0;
4142
4731
  }
4143
4732
  function buildAgentContext(extras = {}) {
4144
- if (extras.newMission === true) deltaTracker.reset();
4733
+ if (extras.newMission === true) {
4734
+ deltaTracker.reset();
4735
+ for (const entry of chunkQAZ4TN3Z_js.listRegistry.snapshot()) entry.exploration?.reset();
4736
+ }
4145
4737
  const context = {};
4146
4738
  context.platform = "react-native";
4147
- const screen = chunkSUMIABJK_js.getCurrentScreen();
4739
+ context.missionProtocol = 1;
4740
+ context.deviceLocale = detectDeviceLocale() ?? "en";
4741
+ const screen = chunkQAZ4TN3Z_js.getCurrentScreen();
4148
4742
  if (screen) context.currentScreen = screen;
4149
- const navigationState = chunkSUMIABJK_js.getNavigationStateSnapshot();
4743
+ const navigationState = chunkQAZ4TN3Z_js.getNavigationStateSnapshot();
4150
4744
  if (navigationState) context.navigationState = navigationState;
4151
4745
  const screenMeta = resolveScreenMetadata();
4152
4746
  if (screenMeta) context.screenMetadata = screenMeta;
4153
4747
  try {
4154
4748
  const snapshot = captureSnapshot();
4749
+ for (const list of snapshot.lists) {
4750
+ const memory = list.id ? chunkQAZ4TN3Z_js.listRegistry.get(list.id)?.exploration : void 0;
4751
+ if (!memory) continue;
4752
+ memory.observe(list.items);
4753
+ list.exploration = memory.snapshot();
4754
+ }
4155
4755
  const delta = deltaTracker.observe(snapshot);
4156
4756
  if (delta) snapshot.delta = delta;
4157
4757
  context.snapshot = snapshot;
4158
4758
  } catch (err) {
4159
- chunkSUMIABJK_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
4759
+ chunkQAZ4TN3Z_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
4160
4760
  }
4161
- const registry = chunkSUMIABJK_js.componentRegistry.snapshot();
4761
+ const registry = chunkQAZ4TN3Z_js.componentRegistry.snapshot();
4162
4762
  const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
4163
4763
  if (filtered.length > 0) context.registeredComponents = filtered;
4164
- const registeredLists = chunkSUMIABJK_js.listRegistry.snapshot();
4764
+ const registeredLists = chunkQAZ4TN3Z_js.listRegistry.snapshot();
4165
4765
  if (registeredLists.length > 0) {
4166
- context.registeredLists = registeredLists.map(
4167
- ({ scrollToIndex, scrollToOffset, getScrollMetrics, dataPreview, ...rest }) => rest
4766
+ const snapshot = context.snapshot;
4767
+ const activeIds = new Set(
4768
+ [...snapshot?.lists ?? [], ...snapshot?.scrollables ?? []].map((l) => l.id)
4168
4769
  );
4770
+ context.registeredLists = registeredLists.filter((entry) => activeIds.has(entry.id)).map(({ id, kind, component, itemCount, totalItemCount, label, refreshing, empty }) => ({
4771
+ id,
4772
+ kind,
4773
+ component,
4774
+ itemCount,
4775
+ totalItemCount,
4776
+ label,
4777
+ refreshing,
4778
+ empty
4779
+ }));
4169
4780
  }
4170
4781
  if (extras.loadingPending === true) context.loadingPending = true;
4171
4782
  return context;
@@ -4175,30 +4786,31 @@ async function settleTurn(input) {
4175
4786
  let loadingPending = false;
4176
4787
  const { turnActions, pressedComponentId: pressedId, navigateTargetScreen } = input;
4177
4788
  const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
4789
+ const effectById = new Map(input.results.map((r) => [r.actionId, r.effect]));
4178
4790
  const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
4179
4791
  const pressedAction = turnActions.find(
4180
4792
  (a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
4181
4793
  );
4182
4794
  const hints = resolveActionHints(
4183
- chunkSUMIABJK_js.getCurrentScreen(),
4795
+ chunkQAZ4TN3Z_js.getCurrentScreen(),
4184
4796
  pressedId,
4185
4797
  pressedAction?.payload
4186
4798
  );
4187
4799
  const capSource = typeof hints?.asyncBudgetMs === "number" && hints.asyncBudgetMs > 0 ? " (app-declared)" : hints?.isAsyncTrigger ? " (mcp-inferred)" : "";
4188
4800
  if (input.hadNavigate) {
4189
- const settle = await chunkSUMIABJK_js.waitForScreenSettle({
4801
+ const settle = await chunkQAZ4TN3Z_js.waitForScreenSettle({
4190
4802
  expectingChange: true,
4191
4803
  fromScreen: input.preNavigateScreen ?? null,
4192
4804
  fromSignature: input.preNavigateSignature ?? null,
4193
4805
  targetScreen: navigateTargetScreen,
4194
4806
  maxMs: 3500
4195
4807
  });
4196
- chunkSUMIABJK_js.appilotsDebugLog(
4808
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
4197
4809
  `settleTurn: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
4198
4810
  );
4199
- const navigationMoved = settle.transitioned || chunkSUMIABJK_js.screenDepartedBaseline(input.preNavigateScreen ?? null, input.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkSUMIABJK_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
4811
+ const navigationMoved = settle.transitioned || chunkQAZ4TN3Z_js.screenDepartedBaseline(input.preNavigateScreen ?? null, input.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkQAZ4TN3Z_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
4200
4812
  if (!navigationMoved) {
4201
- chunkSUMIABJK_js.appilotsDebugWarn(
4813
+ chunkQAZ4TN3Z_js.appilotsDebugWarn(
4202
4814
  `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
4815
  );
4204
4816
  for (const [actionId, type] of typeById) {
@@ -4206,50 +4818,51 @@ async function settleTurn(input) {
4206
4818
  }
4207
4819
  }
4208
4820
  const postNavigateCapMs = resolvePostNavigateCapMs(hints);
4209
- const loadSettle = await chunkSUMIABJK_js.waitForLoadingSettle({
4821
+ const loadSettle = await chunkQAZ4TN3Z_js.waitForLoadingSettle({
4210
4822
  fromScreen: settle.screen ?? null,
4211
4823
  maxMs: postNavigateCapMs
4212
4824
  });
4213
- chunkSUMIABJK_js.appilotsDebugLog(
4825
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
4214
4826
  `settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${postNavigateCapMs}${capSource}`
4215
4827
  );
4216
4828
  if (loadSettle.loadingPending) loadingPending = true;
4217
4829
  } else {
4218
4830
  const settleCapMs = resolveSettleCapMs(hints);
4219
4831
  const busyMaxMs = resolveBusyCeilingMs(hints);
4220
- const loadSettle = await chunkSUMIABJK_js.waitForLoadingSettle({
4832
+ const loadSettle = await chunkQAZ4TN3Z_js.waitForLoadingSettle({
4221
4833
  pressedComponentId: pressedId,
4222
- fromScreen: chunkSUMIABJK_js.getCurrentScreen(),
4834
+ fromScreen: chunkQAZ4TN3Z_js.getCurrentScreen(),
4223
4835
  maxMs: settleCapMs,
4224
4836
  ...busyMaxMs !== void 0 ? { busyMaxMs } : {}
4225
4837
  });
4226
- chunkSUMIABJK_js.appilotsDebugLog(
4838
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
4227
4839
  `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
4840
  );
4229
4841
  if (loadSettle.loadingPending) loadingPending = true;
4230
4842
  const listPressActions = turnActions.filter((action) => {
4231
- const target = chunkSUMIABJK_js.actionPressTargetId(action);
4232
- return target ? chunkSUMIABJK_js.isListItemPressTarget(target) : false;
4843
+ const target = chunkQAZ4TN3Z_js.actionPressTargetId(action);
4844
+ return target ? chunkQAZ4TN3Z_js.isListItemPressTarget(target) : false;
4233
4845
  });
4234
4846
  if (listPressActions.length > 0) {
4235
- const baselineFingerprint = chunkSUMIABJK_js.probeLoadingState(pressedId, chunkSUMIABJK_js.getCurrentScreen()).fingerprint;
4236
- const postPressSettle = await chunkSUMIABJK_js.waitForScreenSettle({
4847
+ const baselineFingerprint = chunkQAZ4TN3Z_js.probeLoadingState(pressedId, chunkQAZ4TN3Z_js.getCurrentScreen()).fingerprint;
4848
+ const postPressSettle = await chunkQAZ4TN3Z_js.waitForScreenSettle({
4237
4849
  expectingChange: true,
4238
4850
  fromScreen: input.preNavigateScreen ?? null,
4239
4851
  fromSignature: input.preNavigateSignature ?? null,
4240
4852
  maxMs: 2500
4241
4853
  });
4242
- await chunkSUMIABJK_js.waitForLoadingSettle({
4854
+ await chunkQAZ4TN3Z_js.waitForLoadingSettle({
4243
4855
  pressedComponentId: pressedId,
4244
- fromScreen: chunkSUMIABJK_js.getCurrentScreen(),
4856
+ fromScreen: chunkQAZ4TN3Z_js.getCurrentScreen(),
4245
4857
  maxMs: 4e3
4246
4858
  });
4247
- const afterFingerprint = chunkSUMIABJK_js.probeLoadingState(pressedId, chunkSUMIABJK_js.getCurrentScreen()).fingerprint;
4248
- chunkSUMIABJK_js.appilotsDebugLog(
4859
+ const afterFingerprint = chunkQAZ4TN3Z_js.probeLoadingState(pressedId, chunkQAZ4TN3Z_js.getCurrentScreen()).fingerprint;
4860
+ chunkQAZ4TN3Z_js.appilotsDebugLog(
4249
4861
  `settleTurn: post-list-press settle \u2014 screen="${postPressSettle.screen}" transitioned=${postPressSettle.transitioned} timedOut=${postPressSettle.timedOut} waitedMs=${postPressSettle.waitedMs}`
4250
4862
  );
4251
4863
  if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
4252
4864
  for (const action of listPressActions) {
4865
+ if (effectById.get(action.id) === "changed") continue;
4253
4866
  if (successById.get(action.id)) {
4254
4867
  toolWithoutEffectIds.add(action.id);
4255
4868
  }
@@ -4261,46 +4874,68 @@ async function settleTurn(input) {
4261
4874
  }
4262
4875
  var reactNativeChatAdapter = {
4263
4876
  buildContext: buildAgentContext,
4264
- getCurrentScreen: chunkSUMIABJK_js.getCurrentScreen,
4265
- getCurrentScreenSignature: chunkSUMIABJK_js.getCurrentScreenSignature,
4877
+ getCurrentScreen: chunkQAZ4TN3Z_js.getCurrentScreen,
4878
+ getCurrentScreenSignature: chunkQAZ4TN3Z_js.getCurrentScreenSignature,
4266
4879
  settleTurn
4267
4880
  };
4268
4881
  function createReactNativeActionRunner(getOptions) {
4269
4882
  return {
4883
+ buildMissionContext: () => reactNativeChatAdapter.buildContext(),
4270
4884
  async execute(action, { confirmedDestructive }) {
4271
- const { permissions, emit, navigationRef, suppressNativeConfirm } = getOptions();
4272
- const navRef = navigationRef?.current ? navigationRef : { current: chunkSUMIABJK_js.getNavigationRef() };
4273
- return runWithConfirmedDestructiveContext(
4885
+ const { permissions, emit: emit2, navigationRef, suppressNativeConfirm } = getOptions();
4886
+ const navRef = navigationRef?.current ? navigationRef : { current: chunkQAZ4TN3Z_js.getNavigationRef() };
4887
+ let receipt;
4888
+ let terminal;
4889
+ const result = await runWithConfirmedDestructiveContext(
4274
4890
  confirmedDestructive && suppressNativeConfirm !== false,
4275
4891
  reactNative.Alert,
4276
4892
  () => executeAction(action, {
4277
4893
  navigationRef: navRef,
4278
4894
  permissions,
4279
- emit
4280
- })
4895
+ emit: (event) => {
4896
+ if (confirmedDestructive && (event.type === "agent:action:complete" || event.type === "agent:action:error"))
4897
+ terminal = event;
4898
+ else emit2(event);
4899
+ }
4900
+ }),
4901
+ (handled) => {
4902
+ receipt = handled;
4903
+ }
4281
4904
  );
4905
+ const failed = receipt?.handlerCompleted === false;
4906
+ if (terminal)
4907
+ emit2({
4908
+ ...terminal,
4909
+ type: failed ? "agent:action:error" : terminal.type,
4910
+ data: {
4911
+ ...terminal.data,
4912
+ ...receipt ? { nativeConfirmation: receipt } : {},
4913
+ ...failed ? { success: false, error: "Native confirmation callback failed" } : {}
4914
+ }
4915
+ });
4916
+ return failed ? { ...result, success: false, error: "Native confirmation callback failed" } : result;
4282
4917
  },
4283
- getCurrentScreen: chunkSUMIABJK_js.getCurrentScreen,
4284
- getCurrentScreenSignature: chunkSUMIABJK_js.getCurrentScreenSignature,
4918
+ getCurrentScreen: chunkQAZ4TN3Z_js.getCurrentScreen,
4919
+ getCurrentScreenSignature: chunkQAZ4TN3Z_js.getCurrentScreenSignature,
4285
4920
  getScreenActionsMetadata(screen) {
4286
- return chunkSUMIABJK_js.getScreenMetadata(screen)?.actions;
4921
+ return chunkQAZ4TN3Z_js.getScreenMetadata(screen)?.actions;
4287
4922
  },
4288
- waitForScreenSettle: chunkSUMIABJK_js.waitForScreenSettle
4923
+ waitForScreenSettle: chunkQAZ4TN3Z_js.waitForScreenSettle
4289
4924
  };
4290
4925
  }
4291
4926
 
4292
4927
  // src/hooks/useAppilotsChat.ts
4293
4928
  function useAppilotsChat(options = {}) {
4294
- const { client, emit, subscribe } = chunkSUMIABJK_js.useAppilotsContext();
4929
+ const { client, emit: emit2, subscribe } = chunkQAZ4TN3Z_js.useAppilotsContext();
4295
4930
  const machine = React.useMemo(
4296
- () => new chunkSUMIABJK_js.ChatSessionMachine(
4297
- { client, adapter: reactNativeChatAdapter, emit, warn: chunkSUMIABJK_js.appilotsDebugWarn },
4931
+ () => new chunkQAZ4TN3Z_js.ChatSessionMachine(
4932
+ { client, adapter: reactNativeChatAdapter, emit: emit2, warn: chunkQAZ4TN3Z_js.appilotsDebugWarn },
4298
4933
  options
4299
4934
  ),
4300
4935
  // A new machine per client/provider instance — options are pushed in
4301
4936
  // below so changing copy never resets the transcript.
4302
4937
  // eslint-disable-next-line react-hooks/exhaustive-deps
4303
- [client, emit]
4938
+ [client, emit2]
4304
4939
  );
4305
4940
  const optionsRef = React.useRef(options);
4306
4941
  optionsRef.current = options;
@@ -4308,6 +4943,14 @@ function useAppilotsChat(options = {}) {
4308
4943
  const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
4309
4944
  React.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
4310
4945
  React.useEffect(() => () => machine.dispose(), [machine]);
4946
+ React.useEffect(() => {
4947
+ void machine.restoreMission();
4948
+ const subscription = reactNative.AppState?.addEventListener?.("change", (next) => {
4949
+ if (next !== "active" && machine.getState().mission?.status === "running")
4950
+ void machine.pauseMission();
4951
+ });
4952
+ return () => subscription?.remove();
4953
+ }, [machine]);
4311
4954
  const requestHuman = React.useCallback(
4312
4955
  (reason) => machine.requestHuman(reason),
4313
4956
  [machine]
@@ -4317,7 +4960,13 @@ function useAppilotsChat(options = {}) {
4317
4960
  const clearMessages = React.useCallback(() => machine.clearMessages(), [machine]);
4318
4961
  const clearError = React.useCallback(() => machine.clearError(), [machine]);
4319
4962
  return {
4963
+ mission: state.mission,
4964
+ pauseMission: () => machine.pauseMission(),
4965
+ resumeMission: () => machine.resumeMission(),
4966
+ cancelMission: () => machine.cancelMission(),
4967
+ hasStartedActing: state.hasStartedActing,
4320
4968
  messages: state.messages,
4969
+ replyLocale: state.replyLocale,
4321
4970
  isLoading: state.isLoading,
4322
4971
  loadingStatusKey: state.loadingStatusKey,
4323
4972
  error: state.error,
@@ -4330,39 +4979,33 @@ function useAppilotsChat(options = {}) {
4330
4979
  clearError
4331
4980
  };
4332
4981
  }
4333
- var DEFAULT_PERMISSIONS2 = {
4334
- canNavigate: true,
4335
- canFillForms: true,
4336
- canInteractUI: true,
4337
- canSubmitForms: true
4338
- };
4339
4982
  function useAppilotsActions(options = {}) {
4340
- const { client, subscribe, config, emit } = chunkSUMIABJK_js.useAppilotsContext();
4983
+ const { client, subscribe, config, emit: emit2 } = chunkQAZ4TN3Z_js.useAppilotsContext();
4341
4984
  const { navigationRef, autoExecute = false } = options;
4342
4985
  const runnerOptionsRef = React.useRef({
4343
- permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
4344
- emit,
4986
+ permissions: chunkQAZ4TN3Z_js.resolveAgentPermissions(config.permissions),
4987
+ emit: emit2,
4345
4988
  navigationRef,
4346
4989
  suppressNativeConfirm: config.suppressNativeConfirm
4347
4990
  });
4348
4991
  runnerOptionsRef.current = {
4349
- permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
4350
- emit,
4992
+ permissions: chunkQAZ4TN3Z_js.resolveAgentPermissions(config.permissions),
4993
+ emit: emit2,
4351
4994
  navigationRef,
4352
4995
  suppressNativeConfirm: config.suppressNativeConfirm
4353
4996
  };
4354
4997
  const machine = React.useMemo(
4355
- () => new chunkSUMIABJK_js.ActionQueueMachine(
4998
+ () => new chunkQAZ4TN3Z_js.ActionQueueMachine(
4356
4999
  {
4357
5000
  client,
4358
5001
  adapter: createReactNativeActionRunner(() => runnerOptionsRef.current),
4359
- emit,
4360
- warn: chunkSUMIABJK_js.appilotsDebugWarn
5002
+ emit: emit2,
5003
+ warn: chunkQAZ4TN3Z_js.appilotsDebugWarn
4361
5004
  },
4362
5005
  { autoExecute }
4363
5006
  ),
4364
5007
  // eslint-disable-next-line react-hooks/exhaustive-deps
4365
- [client, emit]
5008
+ [client, emit2]
4366
5009
  );
4367
5010
  machine.setOptions({ autoExecute });
4368
5011
  const state = React.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
@@ -4414,7 +5057,7 @@ function shouldShowSuggestedPrompts(args) {
4414
5057
 
4415
5058
  // src/hooks/useSuggestedPrompts.ts
4416
5059
  function useSuggestedPrompts(options) {
4417
- const { client } = chunkSUMIABJK_js.useAppilotsContext();
5060
+ const { client } = chunkQAZ4TN3Z_js.useAppilotsContext();
4418
5061
  const { enabled, limit = 4 } = options;
4419
5062
  const [prompts, setPrompts] = React.useState([]);
4420
5063
  const [isLoading, setIsLoading] = React.useState(false);
@@ -4424,8 +5067,8 @@ function useSuggestedPrompts(options) {
4424
5067
  if (!enabled) return;
4425
5068
  const requestId = ++requestIdRef.current;
4426
5069
  let cancelled = false;
4427
- const screen = chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
4428
- const localDev = screen ? (chunkSUMIABJK_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
5070
+ const screen = chunkQAZ4TN3Z_js.getCurrentScreen() ?? void 0;
5071
+ const localDev = screen ? (chunkQAZ4TN3Z_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
4429
5072
  text,
4430
5073
  source: "dev-defined"
4431
5074
  })) : [];
@@ -4439,7 +5082,7 @@ function useSuggestedPrompts(options) {
4439
5082
  if (cancelled || requestIdRef.current !== requestId) return;
4440
5083
  setPrompts(mergePromptSources(localDev, data, limit));
4441
5084
  }).catch((err) => {
4442
- chunkSUMIABJK_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
5085
+ chunkQAZ4TN3Z_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
4443
5086
  }).finally(() => {
4444
5087
  if (cancelled || requestIdRef.current !== requestId) return;
4445
5088
  setIsLoading(false);
@@ -4450,11 +5093,11 @@ function useSuggestedPrompts(options) {
4450
5093
  }, [client, enabled, limit, refreshTick]);
4451
5094
  React.useEffect(() => {
4452
5095
  if (!enabled) return;
4453
- let lastScreen = chunkSUMIABJK_js.getCurrentScreen();
5096
+ let lastScreen = chunkQAZ4TN3Z_js.getCurrentScreen();
4454
5097
  const interval = setInterval(() => {
4455
- const current = chunkSUMIABJK_js.getCurrentScreen();
4456
- if (current !== lastScreen) {
4457
- lastScreen = current;
5098
+ const current2 = chunkQAZ4TN3Z_js.getCurrentScreen();
5099
+ if (current2 !== lastScreen) {
5100
+ lastScreen = current2;
4458
5101
  setRefreshTick((t) => t + 1);
4459
5102
  }
4460
5103
  }, 800);
@@ -4467,22 +5110,22 @@ function useSuggestedPrompts(options) {
4467
5110
  };
4468
5111
  }
4469
5112
  function useAppilotsNavigation() {
4470
- const { emit } = chunkSUMIABJK_js.useAppilotsContext();
5113
+ const { emit: emit2 } = chunkQAZ4TN3Z_js.useAppilotsContext();
4471
5114
  const [currentScreen, setCurrentScreenState] = React.useState(null);
4472
5115
  const [navigationHistory, setNavigationHistory] = React.useState([]);
4473
5116
  const navigationRef = React.useRef(null);
4474
5117
  const setCurrentScreen2 = React.useCallback(
4475
5118
  (screenName) => {
4476
5119
  setCurrentScreenState(screenName);
4477
- chunkSUMIABJK_js.setCurrentScreen(screenName);
5120
+ chunkQAZ4TN3Z_js.setCurrentScreen(screenName);
4478
5121
  setNavigationHistory((prev) => [...prev, screenName]);
4479
- emit({
5122
+ emit2({
4480
5123
  type: "navigation:change",
4481
5124
  timestamp: Date.now(),
4482
5125
  data: { screenName }
4483
5126
  });
4484
5127
  },
4485
- [emit]
5128
+ [emit2]
4486
5129
  );
4487
5130
  React.useEffect(() => {
4488
5131
  const nav = navigationRef.current;
@@ -4505,7 +5148,7 @@ function useAppilotsNavigation() {
4505
5148
 
4506
5149
  // src/hooks/useAppilots.ts
4507
5150
  function useAppilots() {
4508
- const { config, client } = chunkSUMIABJK_js.useAppilotsContext();
5151
+ const { config, client } = chunkQAZ4TN3Z_js.useAppilotsContext();
4509
5152
  const chat = useAppilotsChat();
4510
5153
  const navigation = useAppilotsNavigation();
4511
5154
  const actions = useAppilotsActions();
@@ -4532,9 +5175,14 @@ function useAppilots() {
4532
5175
  rejectAction: actions.rejectAction
4533
5176
  };
4534
5177
  }
5178
+ function useAppilotsElementProps(id) {
5179
+ return React.useMemo(() => ({ testID: id }), [id]);
5180
+ }
5181
+
5182
+ // src/hooks/useAppilotsField.ts
4535
5183
  function useAppilotsField(id, options) {
4536
5184
  const { value, onChangeText, ref, fieldType, label, screen } = options;
4537
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5185
+ const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
4538
5186
  const valueRef = React.useRef(value);
4539
5187
  const onChangeRef = React.useRef(onChangeText);
4540
5188
  valueRef.current = value;
@@ -4559,10 +5207,11 @@ function useAppilotsField(id, options) {
4559
5207
  registry.unregister(id);
4560
5208
  };
4561
5209
  }, [id, registry, getValue, setValue, focus, ref, fieldType, label, screen]);
5210
+ return useAppilotsElementProps(id);
4562
5211
  }
4563
5212
  function useAppilotsTarget(id, options) {
4564
5213
  const { onPress, onLongPress, onScrollTo, label, screen } = options;
4565
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5214
+ const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
4566
5215
  const onPressRef = React.useRef(onPress);
4567
5216
  const onLongPressRef = React.useRef(onLongPress);
4568
5217
  const onScrollToRef = React.useRef(onScrollTo);
@@ -4586,10 +5235,11 @@ function useAppilotsTarget(id, options) {
4586
5235
  registry.unregister(id);
4587
5236
  };
4588
5237
  }, [id, registry, press, longPress, scrollTo, onLongPress, onScrollTo, label, screen]);
5238
+ return useAppilotsElementProps(id);
4589
5239
  }
4590
5240
  function useAppilotsToggle(id, options) {
4591
5241
  const { value, onValueChange, label, screen } = options;
4592
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5242
+ const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
4593
5243
  const valueRef = React.useRef(value);
4594
5244
  const onChangeRef = React.useRef(onValueChange);
4595
5245
  valueRef.current = value;
@@ -4609,10 +5259,11 @@ function useAppilotsToggle(id, options) {
4609
5259
  registry.unregister(id);
4610
5260
  };
4611
5261
  }, [id, registry, getValue, setValue, label, screen]);
5262
+ return useAppilotsElementProps(id);
4612
5263
  }
4613
5264
  function useAppilotsSlider(id, options) {
4614
5265
  const { value, onValueChange, min, max, step, label, screen } = options;
4615
- const registry = chunkSUMIABJK_js.useResolvedRegistry();
5266
+ const registry = chunkQAZ4TN3Z_js.useResolvedRegistry();
4616
5267
  const valueRef = React.useRef(value);
4617
5268
  const onChangeRef = React.useRef(onValueChange);
4618
5269
  valueRef.current = value;
@@ -4635,16 +5286,31 @@ function useAppilotsSlider(id, options) {
4635
5286
  registry.unregister(id);
4636
5287
  };
4637
5288
  }, [id, registry, getValue, setValue, min, max, step, label, screen]);
5289
+ return useAppilotsElementProps(id);
4638
5290
  }
4639
5291
 
5292
+ exports.AppilotsI18nProvider = AppilotsI18nProvider;
5293
+ exports.REVEAL_MARGIN = REVEAL_MARGIN;
5294
+ exports.SPOTLIGHT_TTL_MS = SPOTLIGHT_TTL_MS;
4640
5295
  exports.appilotsSelfCheck = appilotsSelfCheck;
4641
5296
  exports.captureSnapshot = captureSnapshot;
5297
+ exports.detectDeviceLocale = detectDeviceLocale;
4642
5298
  exports.executeAction = executeAction;
5299
+ exports.getSpotlightMode = getSpotlightMode;
5300
+ exports.getSpotlightTarget = getSpotlightTarget;
5301
+ exports.offsetToReveal = offsetToReveal;
5302
+ exports.resolveLocale = resolveLocale;
5303
+ exports.revealTarget = revealTarget;
5304
+ exports.setSpotlightMode = setSpotlightMode;
5305
+ exports.setSpotlightTarget = setSpotlightTarget;
4643
5306
  exports.shouldShowSuggestedPrompts = shouldShowSuggestedPrompts;
5307
+ exports.subscribeSpotlight = subscribeSpotlight;
5308
+ exports.subscribeSpotlightAnnouncement = subscribeSpotlightAnnouncement;
4644
5309
  exports.useAppilots = useAppilots;
4645
5310
  exports.useAppilotsActions = useAppilotsActions;
4646
5311
  exports.useAppilotsChat = useAppilotsChat;
4647
5312
  exports.useAppilotsField = useAppilotsField;
5313
+ exports.useAppilotsI18n = useAppilotsI18n;
4648
5314
  exports.useAppilotsNavigation = useAppilotsNavigation;
4649
5315
  exports.useAppilotsSlider = useAppilotsSlider;
4650
5316
  exports.useAppilotsTarget = useAppilotsTarget;