@appilots/sdk 0.11.0 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-meta.json +3 -3
- package/dist/{chunk-NA5H4IHH.mjs → chunk-2ZDELL54.mjs} +352 -114
- package/dist/{chunk-IZEWWAA7.js → chunk-5UVMNKPT.js} +8 -8
- package/dist/{chunk-3K7ORC4X.mjs → chunk-JKLE5SLN.mjs} +1 -1
- package/dist/{chunk-G6KI7KVH.mjs → chunk-ROXXCDIG.mjs} +299 -15
- package/dist/{chunk-55Y2AQE7.js → chunk-SUMIABJK.js} +299 -14
- package/dist/{chunk-2YPEQTL2.js → chunk-UFMTRGML.js} +622 -384
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +11 -11
- package/dist/hooks/index.mjs +2 -2
- package/dist/{index-BPZ0j71S.d.mts → index-BR-33WMN.d.mts} +112 -1
- package/dist/{index-BPZ0j71S.d.ts → index-BR-33WMN.d.ts} +112 -1
- package/dist/index.d.mts +28 -3
- package/dist/index.d.ts +28 -3
- package/dist/index.js +112 -82
- package/dist/index.mjs +45 -15
- package/dist/navigation/index.d.mts +42 -6
- package/dist/navigation/index.d.ts +42 -6
- package/dist/navigation/index.js +13 -13
- package/dist/navigation/index.mjs +2 -2
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkSUMIABJK_js = require('./chunk-SUMIABJK.js');
|
|
4
4
|
var React = require('react');
|
|
5
5
|
var reactNative = require('react-native');
|
|
6
6
|
|
|
@@ -23,9 +23,9 @@ function fiberSliderMatches(fiber, registryId, registryLabel) {
|
|
|
23
23
|
function reconcileSliders(snapshot) {
|
|
24
24
|
const fiberSliders = snapshot.sliders;
|
|
25
25
|
const out = [];
|
|
26
|
-
for (const { id, kind } of
|
|
26
|
+
for (const { id, kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
|
|
27
27
|
if (kind !== "slider") continue;
|
|
28
|
-
const entry =
|
|
28
|
+
const entry = chunkSUMIABJK_js.componentRegistry.getSlider(id);
|
|
29
29
|
if (!entry) continue;
|
|
30
30
|
const fiber = fiberSliders.find((s) => fiberSliderMatches(s, id, entry.label));
|
|
31
31
|
const visible = !!fiber || typeof entry.screen === "string" && entry.screen === snapshot.route;
|
|
@@ -53,7 +53,7 @@ function normalizeFieldKey(value) {
|
|
|
53
53
|
}
|
|
54
54
|
function canonicalizeRegisteredFields(snapshot) {
|
|
55
55
|
const claimed = /* @__PURE__ */ new Set();
|
|
56
|
-
for (const { id, kind, label } of
|
|
56
|
+
for (const { id, kind, label } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
|
|
57
57
|
if (kind !== "field") continue;
|
|
58
58
|
if (snapshot.inputs.some((input) => input.id === id)) continue;
|
|
59
59
|
const registryLabel = (label ?? "").toLowerCase();
|
|
@@ -72,7 +72,7 @@ function canonicalizeRegisteredFields(snapshot) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
function mergeRegisteredLists(snapshot) {
|
|
75
|
-
const registered =
|
|
75
|
+
const registered = chunkSUMIABJK_js.listRegistry.snapshot();
|
|
76
76
|
if (registered.length === 0) return;
|
|
77
77
|
const byId = /* @__PURE__ */ new Map();
|
|
78
78
|
for (const list of snapshot.lists) {
|
|
@@ -121,7 +121,7 @@ function mergeRegisteredLists(snapshot) {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
function mergeRegisteredScrollables(snapshot) {
|
|
124
|
-
const registered =
|
|
124
|
+
const registered = chunkSUMIABJK_js.listRegistry.snapshot().filter((e) => e.kind === "scroll");
|
|
125
125
|
if (registered.length === 0) return;
|
|
126
126
|
const listsById = /* @__PURE__ */ new Map();
|
|
127
127
|
for (const list of snapshot.lists) {
|
|
@@ -154,7 +154,7 @@ function mergeRegisteredScrollables(snapshot) {
|
|
|
154
154
|
if (out.length > 0) snapshot.scrollables = out;
|
|
155
155
|
}
|
|
156
156
|
function mergeNativeDialog(snapshot) {
|
|
157
|
-
const dialog =
|
|
157
|
+
const dialog = chunkSUMIABJK_js.getOpenNativeDialog();
|
|
158
158
|
if (!dialog) return;
|
|
159
159
|
snapshot.nativeDialog = {
|
|
160
160
|
id: dialog.id,
|
|
@@ -169,21 +169,21 @@ function mergeNativeDialog(snapshot) {
|
|
|
169
169
|
}
|
|
170
170
|
var MIN_FIBERS_FOR_BLINDNESS = 200;
|
|
171
171
|
function recordBlindWalk() {
|
|
172
|
-
const walk =
|
|
172
|
+
const walk = chunkSUMIABJK_js.getLastWalkDiagnostics();
|
|
173
173
|
if (!walk) return;
|
|
174
174
|
if (walk.visitedFibers < MIN_FIBERS_FOR_BLINDNESS) return;
|
|
175
|
-
if (
|
|
176
|
-
|
|
175
|
+
if (chunkSUMIABJK_js.totalDetectorHits(walk.detectors) > 0) return;
|
|
176
|
+
chunkSUMIABJK_js.recordIntrospectionFailure("walk-recognized-nothing", null);
|
|
177
177
|
}
|
|
178
178
|
function captureSnapshot() {
|
|
179
|
-
const root =
|
|
179
|
+
const root = chunkSUMIABJK_js.getFiberRoot();
|
|
180
180
|
if (!root) {
|
|
181
|
-
|
|
181
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
182
182
|
"captureSnapshot: fiber root not captured yet. Ensure <AppilotsProvider> has rendered before calling this."
|
|
183
183
|
);
|
|
184
|
-
|
|
184
|
+
chunkSUMIABJK_js.recordIntrospectionFailure("never-mounted", null);
|
|
185
185
|
return {
|
|
186
|
-
route:
|
|
186
|
+
route: chunkSUMIABJK_js.getCurrentScreen(),
|
|
187
187
|
texts: [],
|
|
188
188
|
inputs: [],
|
|
189
189
|
buttons: [],
|
|
@@ -197,9 +197,9 @@ function captureSnapshot() {
|
|
|
197
197
|
};
|
|
198
198
|
}
|
|
199
199
|
const start = Date.now();
|
|
200
|
-
const snapshot =
|
|
200
|
+
const snapshot = chunkSUMIABJK_js.walkFiber(root);
|
|
201
201
|
recordBlindWalk();
|
|
202
|
-
const activePath =
|
|
202
|
+
const activePath = chunkSUMIABJK_js.getActiveRouteNames();
|
|
203
203
|
const deepestRoute = activePath[activePath.length - 1];
|
|
204
204
|
if (deepestRoute) snapshot.route = deepestRoute;
|
|
205
205
|
mergeRegisteredLists(snapshot);
|
|
@@ -207,15 +207,15 @@ function captureSnapshot() {
|
|
|
207
207
|
mergeNativeDialog(snapshot);
|
|
208
208
|
reconcileSliders(snapshot);
|
|
209
209
|
canonicalizeRegisteredFields(snapshot);
|
|
210
|
-
|
|
211
|
-
const entries =
|
|
210
|
+
chunkSUMIABJK_js.clampSnapshotToWireLimits(snapshot);
|
|
211
|
+
const entries = chunkSUMIABJK_js.deriveInteractionElements(snapshot, { rectOf: chunkSUMIABJK_js.rectForNode });
|
|
212
212
|
const rectById = new Map(
|
|
213
213
|
entries.flatMap((entry) => entry.rect ? [[entry.id, entry.rect]] : [])
|
|
214
214
|
);
|
|
215
|
-
snapshot.elements = entries.map(
|
|
216
|
-
snapshot.choiceGroups =
|
|
217
|
-
|
|
218
|
-
|
|
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(
|
|
219
219
|
snapshot.elements.map((element) => {
|
|
220
220
|
const rect = rectById.get(element.id);
|
|
221
221
|
return rect ? { ...element, rect } : element;
|
|
@@ -227,10 +227,10 @@ function captureSnapshot() {
|
|
|
227
227
|
(acc, l) => acc + (typeof l.itemCount === "number" ? l.itemCount : 0),
|
|
228
228
|
0
|
|
229
229
|
);
|
|
230
|
-
|
|
230
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
231
231
|
`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
232
|
);
|
|
233
|
-
|
|
233
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
234
234
|
`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
235
|
);
|
|
236
236
|
return snapshot;
|
|
@@ -241,10 +241,10 @@ function registryCounts() {
|
|
|
241
241
|
toggles: 0,
|
|
242
242
|
sliders: 0,
|
|
243
243
|
targets: 0,
|
|
244
|
-
lists:
|
|
245
|
-
elements:
|
|
244
|
+
lists: chunkSUMIABJK_js.listRegistry.snapshot().length,
|
|
245
|
+
elements: chunkSUMIABJK_js.elementRegistry.size
|
|
246
246
|
};
|
|
247
|
-
for (const { kind } of
|
|
247
|
+
for (const { kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
|
|
248
248
|
if (kind === "field") counts.fields++;
|
|
249
249
|
else if (kind === "toggle") counts.toggles++;
|
|
250
250
|
else if (kind === "slider") counts.sliders++;
|
|
@@ -253,29 +253,62 @@ function registryCounts() {
|
|
|
253
253
|
return counts;
|
|
254
254
|
}
|
|
255
255
|
function appilotsSelfCheck() {
|
|
256
|
-
const root =
|
|
256
|
+
const root = chunkSUMIABJK_js.getFiberRoot();
|
|
257
257
|
const start = Date.now();
|
|
258
|
-
if (root)
|
|
258
|
+
if (root) chunkSUMIABJK_js.walkFiber(root);
|
|
259
259
|
const elapsedMs = Date.now() - start;
|
|
260
|
-
const walk =
|
|
260
|
+
const walk = chunkSUMIABJK_js.getLastWalkDiagnostics();
|
|
261
261
|
return {
|
|
262
|
-
sdkVersion:
|
|
262
|
+
sdkVersion: chunkSUMIABJK_js.SDK_VERSION,
|
|
263
263
|
reactVersion: React__default.default.version ?? null,
|
|
264
|
-
route:
|
|
265
|
-
introspection:
|
|
266
|
-
autoTracking:
|
|
264
|
+
route: chunkSUMIABJK_js.getCurrentScreen() || null,
|
|
265
|
+
introspection: chunkSUMIABJK_js.getIntrospectionDiagnostics(),
|
|
266
|
+
autoTracking: chunkSUMIABJK_js.getAutoTrackingState(),
|
|
267
267
|
walk: {
|
|
268
268
|
visitedFibers: root ? walk?.visitedFibers ?? 0 : 0,
|
|
269
269
|
skippedHidden: root ? walk?.skippedHidden ?? 0 : 0,
|
|
270
270
|
elapsedMs
|
|
271
271
|
},
|
|
272
|
-
detectors: root ? walk?.detectors ??
|
|
272
|
+
detectors: root ? walk?.detectors ?? chunkSUMIABJK_js.emptyDetectorCounts() : chunkSUMIABJK_js.emptyDetectorCounts(),
|
|
273
273
|
registry: registryCounts(),
|
|
274
|
-
nameMangling:
|
|
275
|
-
geometry: { availability:
|
|
274
|
+
nameMangling: chunkSUMIABJK_js.getNameManglingProbe(),
|
|
275
|
+
geometry: { availability: chunkSUMIABJK_js.geometryAvailability(), ...chunkSUMIABJK_js.geometryStats() }
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
// src/introspection/switchFlip.ts
|
|
280
|
+
function declaredState(props) {
|
|
281
|
+
if (typeof props?.value === "boolean") return props.value;
|
|
282
|
+
const aria = props?.["aria-checked"];
|
|
283
|
+
if (typeof aria === "boolean") return aria;
|
|
284
|
+
const checked = props?.accessibilityState?.checked;
|
|
285
|
+
return typeof checked === "boolean" ? checked : void 0;
|
|
286
|
+
}
|
|
287
|
+
function isReactNativeSwitch(fiber) {
|
|
288
|
+
return chunkSUMIABJK_js.getTypeName(fiber?.type) === "Switch" || chunkSUMIABJK_js.getTypeName(fiber?.elementType) === "Switch";
|
|
289
|
+
}
|
|
290
|
+
var SWITCH_FLIP_HANDLERS = ["onValueChange", "onChange", "onPress"];
|
|
291
|
+
function flipSwitchFiber(fiber, next) {
|
|
292
|
+
const props = fiber?.memoizedProps ?? {};
|
|
293
|
+
const onValueChange = props.onValueChange;
|
|
294
|
+
const onChange = props.onChange;
|
|
295
|
+
const onPress = props.onPress;
|
|
296
|
+
const handler = typeof onValueChange === "function" ? { fn: onValueChange, via: "onValueChange" } : typeof onChange === "function" ? { fn: onChange, via: "onChange" } : typeof onPress === "function" ? { fn: onPress, via: "onPress" } : null;
|
|
297
|
+
if (!handler) return { ok: false, reason: "no-handler" };
|
|
298
|
+
try {
|
|
299
|
+
if (handler.via === "onPress") {
|
|
300
|
+
if (declaredState(props) === next) return { ok: true, via: "onPress", noop: true };
|
|
301
|
+
handler.fn();
|
|
302
|
+
} else if (handler.via === "onChange") {
|
|
303
|
+
if (isReactNativeSwitch(fiber)) handler.fn({ nativeEvent: { value: next }, value: next });
|
|
304
|
+
else handler.fn(next);
|
|
305
|
+
} else handler.fn(next);
|
|
306
|
+
} catch (err) {
|
|
307
|
+
return { ok: false, reason: "threw", error: err?.message ?? "switch handler threw" };
|
|
308
|
+
}
|
|
309
|
+
return { ok: true, via: handler.via };
|
|
310
|
+
}
|
|
311
|
+
|
|
279
312
|
// src/introspection/findInteractive.ts
|
|
280
313
|
function getTypeName2(type) {
|
|
281
314
|
if (!type) return null;
|
|
@@ -350,7 +383,7 @@ function shouldSkipSubtree2(fiber) {
|
|
|
350
383
|
const typeName = getTypeName2(fiber.type) ?? getTypeName2(fiber.elementType);
|
|
351
384
|
if (typeName && SELF_REFERENTIAL_COMPONENTS.has(typeName)) return true;
|
|
352
385
|
if (isAppilotsSkipMarked(props)) return true;
|
|
353
|
-
if (
|
|
386
|
+
if (chunkSUMIABJK_js.isModalFiber(fiber) && props.visible === false) return true;
|
|
354
387
|
if (matchesName(fiber, "Screen") && props.activityState === 0) return true;
|
|
355
388
|
const style = props.style;
|
|
356
389
|
if (style) {
|
|
@@ -360,8 +393,8 @@ function shouldSkipSubtree2(fiber) {
|
|
|
360
393
|
}
|
|
361
394
|
return false;
|
|
362
395
|
}
|
|
363
|
-
var normalize =
|
|
364
|
-
function
|
|
396
|
+
var normalize = chunkSUMIABJK_js.foldForCompare;
|
|
397
|
+
function scoreMatchDetail(fiber, queryNorm, queryRaw) {
|
|
365
398
|
const props = fiber.memoizedProps ?? {};
|
|
366
399
|
const candidates = [];
|
|
367
400
|
if (typeof props.testID === "string") candidates.push({ val: props.testID, weight: 100 });
|
|
@@ -384,13 +417,16 @@ function scoreMatch(fiber, queryNorm, queryRaw) {
|
|
|
384
417
|
else if (queryNorm && (vNorm.includes(queryNorm) || queryNorm.includes(vNorm)))
|
|
385
418
|
best = Math.max(best, weight - 20);
|
|
386
419
|
}
|
|
387
|
-
|
|
420
|
+
const named = best >= IDENTITY_MATCH_SCORE;
|
|
421
|
+
const disabledProp = props.disabled === true;
|
|
422
|
+
const disabledA11y = typeof props.accessibilityState === "object" && props.accessibilityState !== null && props.accessibilityState.disabled === true;
|
|
423
|
+
if (best > 0 && disabledProp) {
|
|
388
424
|
best = Math.max(1, best - 60);
|
|
389
425
|
}
|
|
390
|
-
if (best > 0 &&
|
|
426
|
+
if (best > 0 && disabledA11y) {
|
|
391
427
|
best = Math.max(1, best - 60);
|
|
392
428
|
}
|
|
393
|
-
return best;
|
|
429
|
+
return { score: best, named, disabled: disabledProp || disabledA11y };
|
|
394
430
|
}
|
|
395
431
|
function wrapTextInput(fiber) {
|
|
396
432
|
const getProps = () => fiber.memoizedProps ?? {};
|
|
@@ -427,13 +463,31 @@ function wrapSwitch(fiber) {
|
|
|
427
463
|
return {
|
|
428
464
|
kind: "toggle",
|
|
429
465
|
label: getProps().accessibilityLabel ?? getProps().testID,
|
|
430
|
-
|
|
466
|
+
// `switchValue` reads `accessibilityState.checked` when there is no
|
|
467
|
+
// `value` prop. A CUSTOM switch (a Pressable with
|
|
468
|
+
// `accessibilityRole="switch"`) has only the former, and reporting
|
|
469
|
+
// `false` for a control that is on is worse than reporting nothing:
|
|
470
|
+
// the caller inverts this to decide where to move.
|
|
471
|
+
getValue: () => chunkSUMIABJK_js.switchValue(getProps()),
|
|
431
472
|
setValue: (value) => {
|
|
432
|
-
const { onValueChange, onChange } = getProps();
|
|
433
473
|
const boolVal = typeof value === "boolean" ? value : value === "true" || value === true;
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
474
|
+
const flipped = flipSwitchFiber(fiber, boolVal);
|
|
475
|
+
if (flipped.ok) return;
|
|
476
|
+
if (flipped.reason === "no-handler") {
|
|
477
|
+
throw new Error(`Switch exposes none of: ${SWITCH_FLIP_HANDLERS.join(", ")}`);
|
|
478
|
+
}
|
|
479
|
+
throw new Error(flipped.error);
|
|
480
|
+
},
|
|
481
|
+
// A custom switch is a `Pressable` underneath, so it may well declare
|
|
482
|
+
// its own long press (hold to configure, hold for a shortcut menu).
|
|
483
|
+
// Classifying it as a toggle took it out of the `kind: 'target'`
|
|
484
|
+
// lookup, and without this the long press would fall through to the
|
|
485
|
+
// best remaining candidate — the card that WRAPS it.
|
|
486
|
+
longPress: () => {
|
|
487
|
+
const { onLongPress } = getProps();
|
|
488
|
+
if (typeof onLongPress !== "function") return false;
|
|
489
|
+
onLongPress();
|
|
490
|
+
return true;
|
|
437
491
|
}
|
|
438
492
|
};
|
|
439
493
|
}
|
|
@@ -455,10 +509,23 @@ function wrapTouchable(fiber, label) {
|
|
|
455
509
|
}
|
|
456
510
|
};
|
|
457
511
|
}
|
|
512
|
+
var IDENTITY_MATCH_SCORE = 100;
|
|
513
|
+
function describeCandidate(fiber, kind) {
|
|
514
|
+
const props = fiber?.memoizedProps ?? {};
|
|
515
|
+
return props.testID ?? props.accessibilityLabel ?? props.placeholder ?? (kind === "target" ? findChildText(fiber) : void 0);
|
|
516
|
+
}
|
|
517
|
+
function isDescendantOf(fiber, ancestor) {
|
|
518
|
+
if (!fiber || !ancestor) return false;
|
|
519
|
+
let node = fiber.return;
|
|
520
|
+
for (let depth = 0; node && depth < 200; depth++, node = node.return) {
|
|
521
|
+
if (node === ancestor) return true;
|
|
522
|
+
}
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
458
525
|
function findInteractiveByIdentifier(query, options = {}) {
|
|
459
|
-
const root =
|
|
526
|
+
const root = chunkSUMIABJK_js.getFiberRoot();
|
|
460
527
|
if (!root) {
|
|
461
|
-
|
|
528
|
+
chunkSUMIABJK_js.appilotsDebugWarn("findInteractiveByIdentifier: fiber root not captured yet");
|
|
462
529
|
return null;
|
|
463
530
|
}
|
|
464
531
|
const queryNorm = normalize(query);
|
|
@@ -466,6 +533,10 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
466
533
|
let bestScore = 0;
|
|
467
534
|
let bestHandle = null;
|
|
468
535
|
let bestId;
|
|
536
|
+
let bestFiber = null;
|
|
537
|
+
let bestNamed = false;
|
|
538
|
+
let bestDisabled = false;
|
|
539
|
+
let tied = [];
|
|
469
540
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
470
541
|
const stack = [];
|
|
471
542
|
if (root.child) stack.push(root.child);
|
|
@@ -475,29 +546,55 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
475
546
|
visited.add(fiber);
|
|
476
547
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
477
548
|
if (shouldSkipSubtree2(fiber)) continue;
|
|
549
|
+
const props = fiber.memoizedProps ?? {};
|
|
478
550
|
let kind = null;
|
|
479
551
|
if (matchesName(fiber, "TextInput")) kind = "field";
|
|
480
|
-
else if (
|
|
552
|
+
else if (chunkSUMIABJK_js.isSwitchLike(fiber, props)) kind = "toggle";
|
|
481
553
|
else if (isPressableTarget(fiber)) kind = "target";
|
|
482
554
|
if (kind && (!options.kind || options.kind === kind)) {
|
|
483
|
-
const
|
|
484
|
-
|
|
555
|
+
const detail = scoreMatchDetail(fiber, queryNorm, queryRaw);
|
|
556
|
+
const score = detail.score;
|
|
557
|
+
if (score > 0) {
|
|
558
|
+
if (score > bestScore) tied = [{ fiber, kind }];
|
|
559
|
+
else if (score === bestScore) tied.push({ fiber, kind });
|
|
560
|
+
}
|
|
561
|
+
const beatsBest = score > bestScore || score > 0 && score === bestScore && isDescendantOf(fiber, bestFiber);
|
|
562
|
+
if (beatsBest) {
|
|
485
563
|
bestScore = score;
|
|
486
|
-
|
|
487
|
-
|
|
564
|
+
bestFiber = fiber;
|
|
565
|
+
bestNamed = detail.named;
|
|
566
|
+
bestDisabled = detail.disabled;
|
|
567
|
+
bestId = describeCandidate(fiber, kind);
|
|
488
568
|
if (kind === "field") bestHandle = wrapTextInput(fiber);
|
|
489
569
|
else if (kind === "toggle") bestHandle = wrapSwitch(fiber);
|
|
490
570
|
else bestHandle = wrapTouchable(fiber, findChildText(fiber));
|
|
491
571
|
}
|
|
492
572
|
}
|
|
573
|
+
if (kind === "toggle") continue;
|
|
493
574
|
if (fiber.child) stack.push(fiber.child);
|
|
494
575
|
}
|
|
576
|
+
if (bestHandle && bestScore < (options.minScore ?? 0)) {
|
|
577
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
578
|
+
`findInteractiveByIdentifier: query="${query}" \u2192 best match scored ${bestScore}, below the requested floor of ${options.minScore} \u2014 refusing it`
|
|
579
|
+
);
|
|
580
|
+
return null;
|
|
581
|
+
}
|
|
495
582
|
if (bestHandle) {
|
|
496
|
-
|
|
497
|
-
|
|
583
|
+
const independent = tied.filter(
|
|
584
|
+
(candidate) => !tied.some(
|
|
585
|
+
(other) => other.fiber !== candidate.fiber && isDescendantOf(other.fiber, candidate.fiber)
|
|
586
|
+
)
|
|
587
|
+
);
|
|
588
|
+
bestHandle.matchCount = independent.length;
|
|
589
|
+
bestHandle.named = bestNamed;
|
|
590
|
+
bestHandle.disabled = bestDisabled;
|
|
591
|
+
const candidates = independent.map(({ fiber, kind }) => describeCandidate(fiber, kind)).filter((id) => typeof id === "string" && id.length > 0).slice(0, 8);
|
|
592
|
+
if (candidates.length > 0) bestHandle.matchCandidates = candidates;
|
|
593
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
594
|
+
`findInteractiveByIdentifier: query="${query}" \u2192 kind=${bestHandle.kind} label="${bestHandle.label ?? bestId}" score=${bestScore} named=${bestNamed} disabled=${bestDisabled} tied=${independent.length}`
|
|
498
595
|
);
|
|
499
596
|
} else {
|
|
500
|
-
|
|
597
|
+
chunkSUMIABJK_js.appilotsDebugLog(`findInteractiveByIdentifier: query="${query}" \u2192 no match`);
|
|
501
598
|
}
|
|
502
599
|
return bestHandle;
|
|
503
600
|
}
|
|
@@ -546,7 +643,7 @@ function screenExistsAnywhere(state, screenName) {
|
|
|
546
643
|
function safeNavigate(nav, screenName, params, path) {
|
|
547
644
|
if (path && path.length > 0) {
|
|
548
645
|
const { root, nestedParams } = buildNestedParams(path, screenName, params);
|
|
549
|
-
|
|
646
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
550
647
|
`safeNavigate: using path-based navigation \u2014 root="${root}", nested=${JSON.stringify(nestedParams)}`
|
|
551
648
|
);
|
|
552
649
|
nav.navigate(root, nestedParams);
|
|
@@ -563,16 +660,16 @@ function safeNavigate(nav, screenName, params, path) {
|
|
|
563
660
|
`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.`
|
|
564
661
|
);
|
|
565
662
|
}
|
|
566
|
-
|
|
663
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
567
664
|
`safeNavigate: screen exists in nested navigator, attempting direct navigation to "${screenName}"`
|
|
568
665
|
);
|
|
569
666
|
nav.navigate(screenName, params);
|
|
570
667
|
}
|
|
571
668
|
function navigateHandler(payload, context) {
|
|
572
|
-
|
|
669
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
573
670
|
// Params carry record ids and, on some screens, the user's own
|
|
574
671
|
// data — the count answers "were params passed?" and nothing else.
|
|
575
|
-
`navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${
|
|
672
|
+
`navigateHandler called: screenName="${payload.screenName}" action="${payload.navigationAction}" params=${chunkSUMIABJK_js.describeValue(payload.params)}`
|
|
576
673
|
);
|
|
577
674
|
const { navigationRef, permissions } = context;
|
|
578
675
|
const nav = navigationRef.current;
|
|
@@ -665,12 +762,12 @@ function navigateHandler(payload, context) {
|
|
|
665
762
|
diagnose: { category: "unknown", screen: payload.screenName }
|
|
666
763
|
};
|
|
667
764
|
}
|
|
668
|
-
|
|
765
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
669
766
|
`navigateHandler: navigation succeeded for "${payload.screenName}" (action="${payload.navigationAction}")`
|
|
670
767
|
);
|
|
671
768
|
return { success: true };
|
|
672
769
|
} catch (err) {
|
|
673
|
-
|
|
770
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
674
771
|
`navigateHandler: navigation failed for "${payload.screenName}": ${err?.message}`
|
|
675
772
|
);
|
|
676
773
|
const msg = String(err?.message ?? "Navigation failed");
|
|
@@ -718,18 +815,18 @@ function markedItemIndexFromFiber(fiber) {
|
|
|
718
815
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
719
816
|
}
|
|
720
817
|
function normalize2(value) {
|
|
721
|
-
return
|
|
818
|
+
return chunkSUMIABJK_js.foldForCompare(String(value ?? ""));
|
|
722
819
|
}
|
|
723
820
|
function hasPressHandler2(fiber) {
|
|
724
821
|
const props = fiber?.memoizedProps ?? {};
|
|
725
822
|
return typeof props.onPress === "function" || typeof props.onPressIn === "function";
|
|
726
823
|
}
|
|
727
824
|
function isPressableFiber(fiber) {
|
|
728
|
-
const typeName =
|
|
729
|
-
return
|
|
825
|
+
const typeName = chunkSUMIABJK_js.getTypeName(fiber.type) ?? chunkSUMIABJK_js.getTypeName(fiber.elementType) ?? "";
|
|
826
|
+
return chunkSUMIABJK_js.TOUCHABLE_NAMES.has(typeName) || hasPressHandler2(fiber);
|
|
730
827
|
}
|
|
731
828
|
function findListContainers(options = {}) {
|
|
732
|
-
const root =
|
|
829
|
+
const root = chunkSUMIABJK_js.getFiberRoot();
|
|
733
830
|
if (!root) return [];
|
|
734
831
|
const containers = [];
|
|
735
832
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
@@ -740,17 +837,17 @@ function findListContainers(options = {}) {
|
|
|
740
837
|
if (!fiber || visited.has(fiber)) continue;
|
|
741
838
|
visited.add(fiber);
|
|
742
839
|
if (fiber.sibling) stack.push(fiber.sibling);
|
|
743
|
-
if (
|
|
744
|
-
if (
|
|
745
|
-
const minItems =
|
|
746
|
-
const items =
|
|
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);
|
|
747
844
|
if (items && items.length >= minItems) {
|
|
748
845
|
containers.push({
|
|
749
846
|
container: fiber,
|
|
750
847
|
items,
|
|
751
848
|
listId: listIdFromContainer(fiber),
|
|
752
849
|
listLabel: listLabelFromContainer(fiber),
|
|
753
|
-
containerType:
|
|
850
|
+
containerType: chunkSUMIABJK_js.getTypeName(fiber.type) ?? chunkSUMIABJK_js.getTypeName(fiber.elementType) ?? "List"
|
|
754
851
|
});
|
|
755
852
|
continue;
|
|
756
853
|
}
|
|
@@ -769,7 +866,7 @@ function findFirstTouchable(item) {
|
|
|
769
866
|
const { fiber, includeSibling } = stack.pop();
|
|
770
867
|
if (!fiber || visited.has(fiber)) continue;
|
|
771
868
|
visited.add(fiber);
|
|
772
|
-
if (
|
|
869
|
+
if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
|
|
773
870
|
if (isPressableFiber(fiber)) {
|
|
774
871
|
const props = fiber.memoizedProps ?? {};
|
|
775
872
|
if (typeof props.onPress === "function" || typeof props.onPressIn === "function") {
|
|
@@ -796,7 +893,7 @@ function findTouchableFibers(item) {
|
|
|
796
893
|
const { fiber, includeSibling } = stack.pop();
|
|
797
894
|
if (!fiber || visited.has(fiber)) continue;
|
|
798
895
|
visited.add(fiber);
|
|
799
|
-
if (
|
|
896
|
+
if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
|
|
800
897
|
const props = fiber.memoizedProps ?? {};
|
|
801
898
|
if (isPressableFiber(fiber) && (typeof props.onPress === "function" || typeof props.onPressIn === "function")) {
|
|
802
899
|
found.push(fiber);
|
|
@@ -840,7 +937,7 @@ function findFirstText(fiber) {
|
|
|
840
937
|
const node = stack.pop();
|
|
841
938
|
if (!node || visited.has(node)) continue;
|
|
842
939
|
visited.add(node);
|
|
843
|
-
const typeName =
|
|
940
|
+
const typeName = chunkSUMIABJK_js.getTypeName(node.type) ?? chunkSUMIABJK_js.getTypeName(node.elementType) ?? "";
|
|
844
941
|
if (typeName === "Text") {
|
|
845
942
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
846
943
|
if (text) return text;
|
|
@@ -859,7 +956,7 @@ function collectTexts(fiber) {
|
|
|
859
956
|
const node = stack.pop();
|
|
860
957
|
if (!node || visited.has(node)) continue;
|
|
861
958
|
visited.add(node);
|
|
862
|
-
const typeName =
|
|
959
|
+
const typeName = chunkSUMIABJK_js.getTypeName(node.type) ?? chunkSUMIABJK_js.getTypeName(node.elementType) ?? "";
|
|
863
960
|
if (typeName === "Text") {
|
|
864
961
|
const text = textFromChildren(node.memoizedProps?.children).trim();
|
|
865
962
|
if (text) out.push(text);
|
|
@@ -871,10 +968,10 @@ function collectTexts(fiber) {
|
|
|
871
968
|
}
|
|
872
969
|
function hasUsefulTouchableIdentity(fiber) {
|
|
873
970
|
const props = fiber?.memoizedProps ?? {};
|
|
874
|
-
if (
|
|
875
|
-
if (
|
|
876
|
-
if (
|
|
877
|
-
return
|
|
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));
|
|
878
975
|
}
|
|
879
976
|
function describeTouchable(fiber) {
|
|
880
977
|
const props = fiber?.memoizedProps ?? {};
|
|
@@ -885,10 +982,10 @@ function describeTouchable(fiber) {
|
|
|
885
982
|
}
|
|
886
983
|
function touchableLooksDestructive(fiber) {
|
|
887
984
|
const descriptor = describeTouchable(fiber);
|
|
888
|
-
if (descriptor &&
|
|
985
|
+
if (descriptor && chunkSUMIABJK_js.looksDestructiveActionLabel(descriptor)) return true;
|
|
889
986
|
const props = fiber?.memoizedProps ?? {};
|
|
890
987
|
const haystack = [props.testID, props.accessibilityLabel, props.accessibilityHint, props.label].filter((value) => typeof value === "string").join(" ");
|
|
891
|
-
return
|
|
988
|
+
return chunkSUMIABJK_js.looksDestructiveActionLabel(haystack);
|
|
892
989
|
}
|
|
893
990
|
function describeItemCandidate(listIndex, zeroBasedIndex, item) {
|
|
894
991
|
const syntheticId = `list-${listIndex}-item-${zeroBasedIndex + 1}`;
|
|
@@ -904,11 +1001,27 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
904
1001
|
const safeIdentifiableTouchables = identifiableTouchables.filter(
|
|
905
1002
|
(candidate) => !touchableLooksDestructive(candidate)
|
|
906
1003
|
);
|
|
1004
|
+
const rowSwitches = findSwitchFibers(itemFiber);
|
|
1005
|
+
if (rowSwitches.length > 0) {
|
|
1006
|
+
const switchCandidates = rowSwitches.map(
|
|
1007
|
+
(fiber, index) => describeTouchable(fiber) ?? `switch ${index + 1} of "list-${listIndex}-item-${itemIndex}" (role=toggle element)`
|
|
1008
|
+
);
|
|
1009
|
+
const pressCandidates = identifiableTouchables.map(describeTouchable).filter((d) => !!d);
|
|
1010
|
+
return {
|
|
1011
|
+
ok: false,
|
|
1012
|
+
reason: "ambiguous-touchables",
|
|
1013
|
+
refusal: "row-has-switch",
|
|
1014
|
+
error: `Item "list-${listIndex}-item-${itemIndex}" contains a switch, so pressing the row would activate the row itself and leave the switch untouched. To flip the switch, emit ui_interaction action="toggle" on the row's role=toggle element id from VISIBLE STATE` + (pressCandidates.length > 0 ? "; to activate the row instead, use a specific pressable id from the candidates." : "."),
|
|
1015
|
+
containerType: list.containerType,
|
|
1016
|
+
candidates: [...switchCandidates, ...pressCandidates].slice(0, 8)
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
907
1019
|
if (identifiableTouchables.length > 0 && safeIdentifiableTouchables.length === 0) {
|
|
908
1020
|
const candidates = identifiableTouchables.map(describeTouchable).filter((d) => !!d).slice(0, 8);
|
|
909
1021
|
return {
|
|
910
1022
|
ok: false,
|
|
911
1023
|
reason: "ambiguous-touchables",
|
|
1024
|
+
refusal: "destructive-only",
|
|
912
1025
|
error: `Item "list-${listIndex}-item-${itemIndex}" only exposes destructive controls. Use the specific button id from the row (for example the cancel button id) instead of pressing the list ordinal.`,
|
|
913
1026
|
containerType: list.containerType,
|
|
914
1027
|
candidates
|
|
@@ -921,7 +1034,7 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
921
1034
|
(candidate) => candidate !== touchable && containsFiber(touchable, candidate)
|
|
922
1035
|
);
|
|
923
1036
|
if (primaryWrapsNestedTargets) {
|
|
924
|
-
|
|
1037
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
925
1038
|
`listItemDispatch: item "list-${listIndex}-item-${itemIndex}" has nested pressables; pressing outer row target`
|
|
926
1039
|
);
|
|
927
1040
|
} else {
|
|
@@ -956,14 +1069,14 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
956
1069
|
}
|
|
957
1070
|
return {
|
|
958
1071
|
ok: true,
|
|
959
|
-
containerType:
|
|
1072
|
+
containerType: chunkSUMIABJK_js.getTypeName(container.type) ?? chunkSUMIABJK_js.getTypeName(container.elementType) ?? list.containerType
|
|
960
1073
|
};
|
|
961
1074
|
} catch (err) {
|
|
962
1075
|
return {
|
|
963
1076
|
ok: false,
|
|
964
1077
|
reason: "press-threw",
|
|
965
1078
|
error: err?.message ?? "press handler threw",
|
|
966
|
-
containerType:
|
|
1079
|
+
containerType: chunkSUMIABJK_js.getTypeName(container.type) ?? chunkSUMIABJK_js.getTypeName(container.elementType) ?? list.containerType
|
|
967
1080
|
};
|
|
968
1081
|
}
|
|
969
1082
|
}
|
|
@@ -1019,7 +1132,7 @@ function candidateLists(containers, locator) {
|
|
|
1019
1132
|
return containers.map((list, listIndex) => ({ list, listIndex }));
|
|
1020
1133
|
}
|
|
1021
1134
|
function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
1022
|
-
if (!
|
|
1135
|
+
if (!chunkSUMIABJK_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
|
|
1023
1136
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
1024
1137
|
if (listIndex < 0 || listIndex >= containers.length) {
|
|
1025
1138
|
return { ok: false, reason: "list-not-found" };
|
|
@@ -1033,7 +1146,7 @@ function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
|
1033
1146
|
return pressResolvedListItem(list, items[zeroBased], listIndex, itemIndex);
|
|
1034
1147
|
}
|
|
1035
1148
|
function resolveListItemByIdentity(locator) {
|
|
1036
|
-
if (!
|
|
1149
|
+
if (!chunkSUMIABJK_js.getFiberRoot()) return { ok: false, result: { ok: false, reason: "no-fiber-root" } };
|
|
1037
1150
|
const parsed = locator.syntheticId ? parseSyntheticListItemId(locator.syntheticId) : null;
|
|
1038
1151
|
const effective = parsed ? { ...locator, listIndex: parsed.listIndex, itemIndex: parsed.itemIndex } : locator;
|
|
1039
1152
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
@@ -1094,9 +1207,9 @@ function findSwitchFibers(item) {
|
|
|
1094
1207
|
const { fiber, includeSibling } = stack.pop();
|
|
1095
1208
|
if (!fiber || visited.has(fiber)) continue;
|
|
1096
1209
|
visited.add(fiber);
|
|
1097
|
-
if (
|
|
1210
|
+
if (chunkSUMIABJK_js.shouldSkipSubtree(fiber)) continue;
|
|
1098
1211
|
const props = fiber.memoizedProps ?? {};
|
|
1099
|
-
if (
|
|
1212
|
+
if (chunkSUMIABJK_js.isSwitchLike(fiber, props)) {
|
|
1100
1213
|
if (props.__appilotsInternal !== true) found.push(fiber);
|
|
1101
1214
|
if (includeSibling && fiber.sibling) {
|
|
1102
1215
|
stack.push({ fiber: fiber.sibling, includeSibling: true });
|
|
@@ -1130,26 +1243,24 @@ function toggleListItemByIdentity(locator, options) {
|
|
|
1130
1243
|
}
|
|
1131
1244
|
const target = switches[0];
|
|
1132
1245
|
const props = target?.memoizedProps ?? {};
|
|
1133
|
-
const current =
|
|
1246
|
+
const current = chunkSUMIABJK_js.switchValue(props);
|
|
1134
1247
|
if (options?.expected !== void 0 && current === options.expected) {
|
|
1135
|
-
return { ok: true, containerType: list.containerType, value: current };
|
|
1248
|
+
return { ok: true, containerType: list.containerType, value: current, noop: true };
|
|
1136
1249
|
}
|
|
1137
|
-
const
|
|
1138
|
-
if (
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
onValueChange(!current);
|
|
1148
|
-
} catch (err) {
|
|
1250
|
+
const flipped = flipSwitchFiber(target, !current);
|
|
1251
|
+
if (!flipped.ok) {
|
|
1252
|
+
if (flipped.reason === "no-handler") {
|
|
1253
|
+
return {
|
|
1254
|
+
ok: false,
|
|
1255
|
+
reason: "no-touchable",
|
|
1256
|
+
error: `The row has a switch but it exposes no handler that could flip it (looked for ${SWITCH_FLIP_HANDLERS.join(", ")}).`,
|
|
1257
|
+
containerType: list.containerType
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1149
1260
|
return {
|
|
1150
1261
|
ok: false,
|
|
1151
1262
|
reason: "press-threw",
|
|
1152
|
-
error:
|
|
1263
|
+
error: flipped.error,
|
|
1153
1264
|
containerType: list.containerType
|
|
1154
1265
|
};
|
|
1155
1266
|
}
|
|
@@ -1171,12 +1282,15 @@ function screenDiagnose(targetId, category = "component-not-found") {
|
|
|
1171
1282
|
return {
|
|
1172
1283
|
category,
|
|
1173
1284
|
targetId,
|
|
1174
|
-
screen:
|
|
1285
|
+
screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0
|
|
1175
1286
|
};
|
|
1176
1287
|
}
|
|
1177
1288
|
function isPressLike(action) {
|
|
1178
1289
|
return action === "press" || action === "tap" || action === "click" || action === "longPress";
|
|
1179
1290
|
}
|
|
1291
|
+
function isPlainPress(action) {
|
|
1292
|
+
return action === "press" || action === "tap" || action === "click";
|
|
1293
|
+
}
|
|
1180
1294
|
function isElementIdentifier(value) {
|
|
1181
1295
|
return value.trim().toLowerCase().startsWith("el:");
|
|
1182
1296
|
}
|
|
@@ -1188,10 +1302,10 @@ function elementLookupKey(value) {
|
|
|
1188
1302
|
return canonicalElementId(value).toLowerCase().replace(/[\s_]+/g, "-");
|
|
1189
1303
|
}
|
|
1190
1304
|
function findRegisteredElement(elementId) {
|
|
1191
|
-
const direct =
|
|
1305
|
+
const direct = chunkSUMIABJK_js.elementRegistry.get(elementId) ?? chunkSUMIABJK_js.elementRegistry.get(canonicalElementId(elementId));
|
|
1192
1306
|
if (direct) return direct;
|
|
1193
1307
|
const wanted = elementLookupKey(elementId);
|
|
1194
|
-
return
|
|
1308
|
+
return chunkSUMIABJK_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
|
|
1195
1309
|
}
|
|
1196
1310
|
function resolveInteractionElement(elementId) {
|
|
1197
1311
|
return getLatestElement(elementId);
|
|
@@ -1287,6 +1401,54 @@ function dispatchRegisteredTarget(targetId, registry, action) {
|
|
|
1287
1401
|
diagnose: screenDiagnose(targetId)
|
|
1288
1402
|
};
|
|
1289
1403
|
}
|
|
1404
|
+
function dispatchIdentifiedToggle(targetId, action) {
|
|
1405
|
+
if (!isPressLike(action)) return null;
|
|
1406
|
+
const winner = findInteractiveByIdentifier(targetId, { minScore: IDENTITY_MATCH_SCORE });
|
|
1407
|
+
if (winner) {
|
|
1408
|
+
if (winner.kind !== "toggle" || !winner.setValue) return null;
|
|
1409
|
+
if ((winner.matchCount ?? 1) > 1) {
|
|
1410
|
+
return {
|
|
1411
|
+
success: false,
|
|
1412
|
+
error: `"${targetId}" names ${winner.matchCount} controls on this screen \u2014 aim at one of the candidates instead`,
|
|
1413
|
+
diagnose: {
|
|
1414
|
+
...screenDiagnose(targetId, "ambiguous-target"),
|
|
1415
|
+
recoverable: true,
|
|
1416
|
+
...winner.matchCandidates && winner.matchCandidates.length > 0 ? { candidates: winner.matchCandidates } : {}
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
if (!isPlainPress(action)) {
|
|
1421
|
+
if (winner.longPress?.()) return { success: true };
|
|
1422
|
+
return {
|
|
1423
|
+
success: false,
|
|
1424
|
+
error: `"${targetId}" names a switch and it declares no long-press handler. Use action="toggle" to flip it.`,
|
|
1425
|
+
diagnose: { ...screenDiagnose(targetId, "unknown"), recoverable: true }
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
1429
|
+
`elementDispatch: "${action}" on "${targetId}" names a switch \u2014 flipping it instead of pressing, so the verb cannot land on an ancestor`
|
|
1430
|
+
);
|
|
1431
|
+
try {
|
|
1432
|
+
winner.setValue(!winner.getValue?.());
|
|
1433
|
+
return { success: true, effect: "changed" };
|
|
1434
|
+
} catch (err) {
|
|
1435
|
+
return {
|
|
1436
|
+
success: false,
|
|
1437
|
+
error: err?.message ?? `Could not flip the switch named "${targetId}"`,
|
|
1438
|
+
diagnose: screenDiagnose(targetId, "unknown")
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
const disabledToggle = findInteractiveByIdentifier(targetId, { kind: "toggle" });
|
|
1443
|
+
if (disabledToggle?.named && disabledToggle.disabled) {
|
|
1444
|
+
return {
|
|
1445
|
+
success: false,
|
|
1446
|
+
error: `The switch named "${targetId}" is currently disabled`,
|
|
1447
|
+
diagnose: screenDiagnose(targetId, "disabled")
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
return null;
|
|
1451
|
+
}
|
|
1290
1452
|
function dispatchFiberTarget(targetId, action) {
|
|
1291
1453
|
const kind = action === "toggle" ? "toggle" : action === "focus" ? "field" : "target";
|
|
1292
1454
|
const handle = findInteractiveByIdentifier(targetId, { kind });
|
|
@@ -1336,6 +1498,8 @@ function dispatchLegacyTarget(targetId, registry, action) {
|
|
|
1336
1498
|
}
|
|
1337
1499
|
const registered = dispatchRegisteredTarget(targetId, registry, action);
|
|
1338
1500
|
if (registered.success) return registered;
|
|
1501
|
+
const named = dispatchIdentifiedToggle(targetId, action);
|
|
1502
|
+
if (named) return named;
|
|
1339
1503
|
const fiber = dispatchFiberTarget(targetId, action);
|
|
1340
1504
|
if (fiber.success) return fiber;
|
|
1341
1505
|
return {
|
|
@@ -1352,6 +1516,9 @@ function dispatchElement(element, registry, action) {
|
|
|
1352
1516
|
diagnose: screenDiagnose(element.id, "disabled")
|
|
1353
1517
|
};
|
|
1354
1518
|
}
|
|
1519
|
+
if (element.role === "toggle" && (action === "toggle" || isPressLike(action))) {
|
|
1520
|
+
return dispatchToggleElement(element, registry);
|
|
1521
|
+
}
|
|
1355
1522
|
if (element.listContext && isPressLike(action)) {
|
|
1356
1523
|
const pressed = pressListItemByIdentity({
|
|
1357
1524
|
...element.listContext,
|
|
@@ -1360,6 +1527,18 @@ function dispatchElement(element, registry, action) {
|
|
|
1360
1527
|
texts: element.texts
|
|
1361
1528
|
});
|
|
1362
1529
|
if (pressed.ok) return { success: true };
|
|
1530
|
+
if (pressed.refusal) {
|
|
1531
|
+
return {
|
|
1532
|
+
success: false,
|
|
1533
|
+
error: pressed.error ?? `Could not press element "${element.id}" (${pressed.reason})`,
|
|
1534
|
+
diagnose: {
|
|
1535
|
+
...screenDiagnose(element.id),
|
|
1536
|
+
category: "ambiguous-target",
|
|
1537
|
+
recoverable: true,
|
|
1538
|
+
...pressed.candidates && pressed.candidates.length > 0 ? { candidates: pressed.candidates } : {}
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1363
1542
|
if (element.targetId && element.targetId !== element.id) {
|
|
1364
1543
|
const fallback = dispatchLegacyTarget(element.targetId, registry, action);
|
|
1365
1544
|
if (fallback.success) return fallback;
|
|
@@ -1391,50 +1570,6 @@ function dispatchElement(element, registry, action) {
|
|
|
1391
1570
|
diagnose: { ...screenDiagnose(element.id, "unknown"), recoverable: true }
|
|
1392
1571
|
};
|
|
1393
1572
|
}
|
|
1394
|
-
if (element.role === "toggle" && (action === "toggle" || isPressLike(action))) {
|
|
1395
|
-
if (element.listContext) {
|
|
1396
|
-
const toggled = toggleListItemByIdentity(
|
|
1397
|
-
{
|
|
1398
|
-
listIndex: element.listContext.listIndex,
|
|
1399
|
-
listId: element.listContext.listId,
|
|
1400
|
-
listLabel: element.listContext.listLabel,
|
|
1401
|
-
itemIndex: element.listContext.itemIndex,
|
|
1402
|
-
itemKey: element.listContext.itemKey,
|
|
1403
|
-
reactKey: element.listContext.reactKey,
|
|
1404
|
-
syntheticId: element.listContext.syntheticId,
|
|
1405
|
-
label: element.label,
|
|
1406
|
-
texts: element.texts
|
|
1407
|
-
},
|
|
1408
|
-
// The observation's `selected` is the state BEFORE this action.
|
|
1409
|
-
// Passing the desired end state makes the flip idempotent: a
|
|
1410
|
-
// retry or a recovery hop must not undo the work and call it
|
|
1411
|
-
// success. A toggle only knows how to invert, so without this the
|
|
1412
|
-
// second attempt silently returns the row to where it started.
|
|
1413
|
-
typeof element.selected === "boolean" ? { expected: !element.selected } : void 0
|
|
1414
|
-
);
|
|
1415
|
-
if (toggled.ok) {
|
|
1416
|
-
return {
|
|
1417
|
-
success: true,
|
|
1418
|
-
// Grounded: read back off the fiber after the handler ran, not
|
|
1419
|
-
// inferred from "the call did not throw".
|
|
1420
|
-
effect: "changed"
|
|
1421
|
-
};
|
|
1422
|
-
}
|
|
1423
|
-
return {
|
|
1424
|
-
success: false,
|
|
1425
|
-
error: toggled.error ?? `Could not flip the switch in row "${element.label ?? element.id}" (${toggled.reason})`,
|
|
1426
|
-
diagnose: {
|
|
1427
|
-
...screenDiagnose(
|
|
1428
|
-
element.id,
|
|
1429
|
-
toggled.reason === "ambiguous-touchables" || toggled.reason === "ambiguous-items" ? "ambiguous-target" : "component-not-found"
|
|
1430
|
-
),
|
|
1431
|
-
...toggled.candidates && toggled.candidates.length > 0 ? { candidates: toggled.candidates } : {}
|
|
1432
|
-
}
|
|
1433
|
-
};
|
|
1434
|
-
}
|
|
1435
|
-
const targetId = element.targetId ?? element.label ?? element.id;
|
|
1436
|
-
return dispatchLegacyTarget(targetId, registry, "toggle");
|
|
1437
|
-
}
|
|
1438
1573
|
if (element.role === "input" && (action === "focus" || isPressLike(action))) {
|
|
1439
1574
|
const targetId = element.targetId ?? element.label ?? element.id;
|
|
1440
1575
|
return dispatchLegacyTarget(targetId, registry, "focus");
|
|
@@ -1449,9 +1584,57 @@ function dispatchElement(element, registry, action) {
|
|
|
1449
1584
|
diagnose: screenDiagnose(element.id, "unknown")
|
|
1450
1585
|
};
|
|
1451
1586
|
}
|
|
1587
|
+
function dispatchToggleElement(element, registry) {
|
|
1588
|
+
if (element.listContext) {
|
|
1589
|
+
const toggled = toggleListItemByIdentity(
|
|
1590
|
+
{
|
|
1591
|
+
listIndex: element.listContext.listIndex,
|
|
1592
|
+
listId: element.listContext.listId,
|
|
1593
|
+
listLabel: element.listContext.listLabel,
|
|
1594
|
+
itemIndex: element.listContext.itemIndex,
|
|
1595
|
+
itemKey: element.listContext.itemKey,
|
|
1596
|
+
reactKey: element.listContext.reactKey,
|
|
1597
|
+
syntheticId: element.listContext.syntheticId,
|
|
1598
|
+
label: element.label,
|
|
1599
|
+
texts: element.texts
|
|
1600
|
+
},
|
|
1601
|
+
// The observation's `selected` is the state BEFORE this action.
|
|
1602
|
+
// Passing the desired end state makes the flip idempotent: a
|
|
1603
|
+
// retry or a recovery hop must not undo the work and call it
|
|
1604
|
+
// success. A toggle only knows how to invert, so without this the
|
|
1605
|
+
// second attempt silently returns the row to where it started.
|
|
1606
|
+
typeof element.selected === "boolean" ? { expected: !element.selected } : void 0
|
|
1607
|
+
);
|
|
1608
|
+
if (toggled.ok) {
|
|
1609
|
+
return {
|
|
1610
|
+
success: true,
|
|
1611
|
+
// Honest split (#504): a real flip is 'changed'; the idempotent
|
|
1612
|
+
// no-op — the switch already held the requested state, nothing
|
|
1613
|
+
// was touched — is 'completed' (goal state verified), NEVER
|
|
1614
|
+
// 'changed' (nothing changed this hop) and NEVER 'none' (which
|
|
1615
|
+
// would send recovery re-flipping a switch that is already
|
|
1616
|
+
// right).
|
|
1617
|
+
effect: toggled.noop ? "completed" : "changed"
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
return {
|
|
1621
|
+
success: false,
|
|
1622
|
+
error: toggled.error ?? `Could not flip the switch in row "${element.label ?? element.id}" (${toggled.reason})`,
|
|
1623
|
+
diagnose: {
|
|
1624
|
+
...screenDiagnose(
|
|
1625
|
+
element.id,
|
|
1626
|
+
toggled.reason === "ambiguous-touchables" || toggled.reason === "ambiguous-items" ? "ambiguous-target" : "component-not-found"
|
|
1627
|
+
),
|
|
1628
|
+
...toggled.candidates && toggled.candidates.length > 0 ? { candidates: toggled.candidates } : {}
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
const targetId = element.targetId ?? element.label ?? element.id;
|
|
1633
|
+
return dispatchLegacyTarget(targetId, registry, "toggle");
|
|
1634
|
+
}
|
|
1452
1635
|
function dispatchStructuredElementId(identifier, action) {
|
|
1453
1636
|
if (!isElementIdentifier(identifier) || !isPressLike(action)) return null;
|
|
1454
|
-
const parsed =
|
|
1637
|
+
const parsed = chunkSUMIABJK_js.parseStableElementId(identifier);
|
|
1455
1638
|
if (!parsed || parsed.role !== "option") return null;
|
|
1456
1639
|
if (!parsed.itemKey && !parsed.listId) return null;
|
|
1457
1640
|
const pressed = pressListItemByIdentity({
|
|
@@ -1461,7 +1644,7 @@ function dispatchStructuredElementId(identifier, action) {
|
|
|
1461
1644
|
texts: parsed.itemKey ? [parsed.itemKey] : void 0
|
|
1462
1645
|
});
|
|
1463
1646
|
if (pressed.ok) {
|
|
1464
|
-
|
|
1647
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
1465
1648
|
`elementDispatch: resolved stale el id "${identifier}" via structural identity (listId="${parsed.listId}", itemKey="${parsed.itemKey}")`
|
|
1466
1649
|
);
|
|
1467
1650
|
return { success: true };
|
|
@@ -1475,6 +1658,8 @@ function dispatchElementOrTarget(identifier, registry, action = "press") {
|
|
|
1475
1658
|
if (result.success) return result;
|
|
1476
1659
|
if (result.diagnose?.category === "disabled") return result;
|
|
1477
1660
|
if (element.role === "slider") return result;
|
|
1661
|
+
if (element.role === "toggle") return result;
|
|
1662
|
+
if (result.diagnose?.category === "ambiguous-target") return result;
|
|
1478
1663
|
}
|
|
1479
1664
|
const structured = dispatchStructuredElementId(identifier, action);
|
|
1480
1665
|
if (structured?.success) return structured;
|
|
@@ -1490,20 +1675,20 @@ function normalize4(value) {
|
|
|
1490
1675
|
return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
1491
1676
|
}
|
|
1492
1677
|
function resolveScreenForFormFields() {
|
|
1493
|
-
const activePath =
|
|
1678
|
+
const activePath = chunkSUMIABJK_js.getActiveRouteNames();
|
|
1494
1679
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
1495
1680
|
const name = activePath[i];
|
|
1496
|
-
const meta = name ?
|
|
1681
|
+
const meta = name ? chunkSUMIABJK_js.getScreenMetadata(name) : void 0;
|
|
1497
1682
|
if (name && Array.isArray(meta?.fields) && meta.fields.length > 0) return name;
|
|
1498
1683
|
}
|
|
1499
|
-
return
|
|
1684
|
+
return chunkSUMIABJK_js.getCurrentScreen();
|
|
1500
1685
|
}
|
|
1501
1686
|
function collectKnownFormFields(registry) {
|
|
1502
1687
|
const registryFields = registry.snapshot().filter((entry) => entry.kind === "field" || entry.kind === "slider").map((entry) => ({ id: entry.id, label: entry.label }));
|
|
1503
1688
|
if (registryFields.length >= 2) return registryFields;
|
|
1504
1689
|
const screen = resolveScreenForFormFields();
|
|
1505
1690
|
if (screen) {
|
|
1506
|
-
const metaFields =
|
|
1691
|
+
const metaFields = chunkSUMIABJK_js.getScreenMetadata(screen)?.fields;
|
|
1507
1692
|
if (Array.isArray(metaFields) && metaFields.length > 0) {
|
|
1508
1693
|
return metaFields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1509
1694
|
id: field.id,
|
|
@@ -1513,7 +1698,7 @@ function collectKnownFormFields(registry) {
|
|
|
1513
1698
|
}));
|
|
1514
1699
|
}
|
|
1515
1700
|
}
|
|
1516
|
-
for (const meta of
|
|
1701
|
+
for (const meta of chunkSUMIABJK_js.getAllScreens()) {
|
|
1517
1702
|
if (Array.isArray(meta.fields) && meta.fields.length > 0) {
|
|
1518
1703
|
return meta.fields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
1519
1704
|
id: field.id,
|
|
@@ -1626,7 +1811,7 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
1626
1811
|
const inferred = inferFieldIdForValue(String(field.value ?? ""), knownFields, used);
|
|
1627
1812
|
if (!inferred) return field;
|
|
1628
1813
|
used.add(inferred);
|
|
1629
|
-
|
|
1814
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
1630
1815
|
`formFieldRewrite: ${field.fieldId} \u2192 ${inferred} (value=${JSON.stringify(field.value)})`
|
|
1631
1816
|
);
|
|
1632
1817
|
return { ...field, fieldId: inferred };
|
|
@@ -1634,8 +1819,8 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
1634
1819
|
}
|
|
1635
1820
|
|
|
1636
1821
|
// src/executor/formValidation.ts
|
|
1637
|
-
var FORM_VALIDATION_TEXT_RE2 =
|
|
1638
|
-
var FORM_SUCCESS_TEXT_RE =
|
|
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;
|
|
1639
1824
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1640
1825
|
function inferValidationFieldId(message, inputs) {
|
|
1641
1826
|
const haystack = normalizeText(message);
|
|
@@ -1672,7 +1857,7 @@ function readVisibleFormSuccess(snap) {
|
|
|
1672
1857
|
return (snap.texts ?? []).find((text) => text?.trim() && FORM_SUCCESS_TEXT_RE.test(text));
|
|
1673
1858
|
}
|
|
1674
1859
|
function submitAsyncStillPending(submitTargetId) {
|
|
1675
|
-
const probe =
|
|
1860
|
+
const probe = chunkSUMIABJK_js.probeLoadingState(submitTargetId ?? null, chunkSUMIABJK_js.getCurrentScreen());
|
|
1676
1861
|
if (probe.loading) return true;
|
|
1677
1862
|
if (submitTargetId && probe.pressedFound && probe.pressedDisabled) return true;
|
|
1678
1863
|
return false;
|
|
@@ -1684,7 +1869,7 @@ function evaluatePostSubmitSnapshot(snap, activePath) {
|
|
|
1684
1869
|
}
|
|
1685
1870
|
const successText = readVisibleFormSuccess(snap);
|
|
1686
1871
|
if (successText) return { status: "success", message: successText };
|
|
1687
|
-
if (!
|
|
1872
|
+
if (!chunkSUMIABJK_js.snapshotShowsOpenCreateForm(snap, activePath)) {
|
|
1688
1873
|
return { status: "success" };
|
|
1689
1874
|
}
|
|
1690
1875
|
return void 0;
|
|
@@ -1700,7 +1885,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
1700
1885
|
continue;
|
|
1701
1886
|
}
|
|
1702
1887
|
const snap2 = captureSnapshot();
|
|
1703
|
-
const activePath2 =
|
|
1888
|
+
const activePath2 = chunkSUMIABJK_js.getActiveRouteNames();
|
|
1704
1889
|
const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2);
|
|
1705
1890
|
if (outcome2) return outcome2;
|
|
1706
1891
|
await sleep(pollMs);
|
|
@@ -1712,7 +1897,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
1712
1897
|
};
|
|
1713
1898
|
}
|
|
1714
1899
|
const snap = captureSnapshot();
|
|
1715
|
-
const activePath =
|
|
1900
|
+
const activePath = chunkSUMIABJK_js.getActiveRouteNames();
|
|
1716
1901
|
const outcome = evaluatePostSubmitSnapshot(snap, activePath);
|
|
1717
1902
|
if (outcome) return outcome;
|
|
1718
1903
|
return {
|
|
@@ -1818,16 +2003,16 @@ function findSnapshotButton(targetId) {
|
|
|
1818
2003
|
}
|
|
1819
2004
|
}
|
|
1820
2005
|
function buildUiDiagnose(targetId, cause) {
|
|
1821
|
-
const activePath =
|
|
1822
|
-
const screen = activePath[activePath.length - 1] ??
|
|
2006
|
+
const activePath = chunkSUMIABJK_js.getActiveRouteNames();
|
|
2007
|
+
const screen = activePath[activePath.length - 1] ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
|
|
1823
2008
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
1824
2009
|
const diagnose = {
|
|
1825
2010
|
category: cause === "not-found" ? "component-not-found" : cause === "disabled" ? "disabled" : "unknown",
|
|
1826
2011
|
targetId,
|
|
1827
2012
|
screen: screenPath
|
|
1828
2013
|
};
|
|
1829
|
-
if (
|
|
1830
|
-
diagnose.visibleMessage =
|
|
2014
|
+
if (chunkSUMIABJK_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
|
|
2015
|
+
diagnose.visibleMessage = chunkSUMIABJK_js.OPTIONAL_STEP_AUTOMATION_HINT;
|
|
1831
2016
|
diagnose.recoverable = true;
|
|
1832
2017
|
}
|
|
1833
2018
|
return diagnose;
|
|
@@ -1885,15 +2070,15 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
1885
2070
|
const snapshot = registry.snapshot();
|
|
1886
2071
|
for (const comp of snapshot) {
|
|
1887
2072
|
if (comp.id.toLowerCase() === lower) {
|
|
1888
|
-
|
|
2073
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
1889
2074
|
`resolveComponentId: case-insensitive match "${componentId}" \u2192 "${comp.id}"`
|
|
1890
2075
|
);
|
|
1891
2076
|
return comp.id;
|
|
1892
2077
|
}
|
|
1893
2078
|
}
|
|
1894
|
-
const currentScreen =
|
|
2079
|
+
const currentScreen = chunkSUMIABJK_js.getCurrentScreen();
|
|
1895
2080
|
if (currentScreen) {
|
|
1896
|
-
const screenMeta =
|
|
2081
|
+
const screenMeta = chunkSUMIABJK_js.getScreenMetadata(currentScreen);
|
|
1897
2082
|
const actions = screenMeta?.actions;
|
|
1898
2083
|
if (actions && Array.isArray(actions)) {
|
|
1899
2084
|
const metaAction = actions.find(
|
|
@@ -1902,14 +2087,14 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
1902
2087
|
if (metaAction && typeof metaAction === "object" && metaAction.label) {
|
|
1903
2088
|
const metaLabel = metaAction.label;
|
|
1904
2089
|
const normalizedMetaLabel = metaLabel.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
1905
|
-
|
|
2090
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
1906
2091
|
`resolveComponentId: found screen metadata for "${componentId}" \u2192 label="${metaLabel}"`
|
|
1907
2092
|
);
|
|
1908
2093
|
for (const comp of snapshot) {
|
|
1909
2094
|
if (!comp.label) continue;
|
|
1910
2095
|
const compLabel = comp.label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
1911
2096
|
if (compLabel === normalizedMetaLabel || compLabel.includes(normalizedMetaLabel) || normalizedMetaLabel.includes(compLabel)) {
|
|
1912
|
-
|
|
2097
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
1913
2098
|
`resolveComponentId: FOUND via metadata: "${componentId}" \u2192 "${comp.id}" (label="${comp.label}")`
|
|
1914
2099
|
);
|
|
1915
2100
|
return comp.id;
|
|
@@ -1926,7 +2111,7 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
1926
2111
|
}));
|
|
1927
2112
|
const match = resolveTarget(componentId, candidates, { action });
|
|
1928
2113
|
if (match.status === "matched") {
|
|
1929
|
-
|
|
2114
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
1930
2115
|
`resolveComponentId: matched "${componentId}" -> "${match.id}" (tier=${match.tier})`
|
|
1931
2116
|
);
|
|
1932
2117
|
return match.id;
|
|
@@ -2016,7 +2201,7 @@ function setValueHandler(rawComponentId, requested, registry) {
|
|
|
2016
2201
|
try {
|
|
2017
2202
|
slider.setValue(applied);
|
|
2018
2203
|
if (applied !== requestedValue) {
|
|
2019
|
-
|
|
2204
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2020
2205
|
`uiInteractionHandler: set_value snapped ${requestedValue} \u2192 ${applied} for "${componentId}" (step=${step})`
|
|
2021
2206
|
);
|
|
2022
2207
|
}
|
|
@@ -2051,7 +2236,7 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2051
2236
|
return null;
|
|
2052
2237
|
}
|
|
2053
2238
|
if (typeof rawComponentId !== "string" || rawComponentId.trim().length === 0) return null;
|
|
2054
|
-
const dialog =
|
|
2239
|
+
const dialog = chunkSUMIABJK_js.getOpenNativeDialog();
|
|
2055
2240
|
if (dialog) {
|
|
2056
2241
|
const needle = normalizeIdent(rawComponentId);
|
|
2057
2242
|
if (dialog.buttons.some((b) => normalizeIdent(b.label) === needle)) return null;
|
|
@@ -2061,16 +2246,16 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2061
2246
|
diagnose: {
|
|
2062
2247
|
category: "ambiguous-target",
|
|
2063
2248
|
targetId: rawComponentId,
|
|
2064
|
-
screen:
|
|
2249
|
+
screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
|
|
2065
2250
|
candidates: dialog.buttons.map((b) => b.label).slice(0, 8)
|
|
2066
2251
|
}
|
|
2067
2252
|
};
|
|
2068
2253
|
}
|
|
2069
|
-
const fiberRoot =
|
|
2254
|
+
const fiberRoot = chunkSUMIABJK_js.getFiberRoot();
|
|
2070
2255
|
if (!fiberRoot) return null;
|
|
2071
2256
|
let snap;
|
|
2072
2257
|
try {
|
|
2073
|
-
snap =
|
|
2258
|
+
snap = chunkSUMIABJK_js.walkFiber(fiberRoot);
|
|
2074
2259
|
} catch {
|
|
2075
2260
|
return null;
|
|
2076
2261
|
}
|
|
@@ -2132,7 +2317,7 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
2132
2317
|
}
|
|
2133
2318
|
function uiInteractionHandler(payload, context) {
|
|
2134
2319
|
const { permissions } = context;
|
|
2135
|
-
const registry = context.registry ??
|
|
2320
|
+
const registry = context.registry ?? chunkSUMIABJK_js.componentRegistry;
|
|
2136
2321
|
if (!permissions.canInteractUI) {
|
|
2137
2322
|
return {
|
|
2138
2323
|
success: false,
|
|
@@ -2154,7 +2339,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2154
2339
|
if (sliderId) {
|
|
2155
2340
|
const smuggled = payload.value ?? payload.params?.value;
|
|
2156
2341
|
if (smuggled !== void 0) {
|
|
2157
|
-
|
|
2342
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2158
2343
|
`uiInteractionHandler: "${actionStr}" on slider "${sliderId}" carried value=${JSON.stringify(smuggled)} \u2014 routing to set_value`
|
|
2159
2344
|
);
|
|
2160
2345
|
return setValueHandler(rawComponentId, smuggled, registry);
|
|
@@ -2165,23 +2350,23 @@ function uiInteractionHandler(payload, context) {
|
|
|
2165
2350
|
diagnose: { ...buildUiDiagnose(sliderId, "unknown"), recoverable: true }
|
|
2166
2351
|
};
|
|
2167
2352
|
}
|
|
2168
|
-
const openDialog =
|
|
2353
|
+
const openDialog = chunkSUMIABJK_js.getOpenNativeDialog();
|
|
2169
2354
|
const isPressVerb = actionStr === "press" || actionStr === "tap" || actionStr === "click";
|
|
2170
2355
|
if (openDialog && isPressVerb) {
|
|
2171
2356
|
const needle = normalizeIdent(rawComponentId);
|
|
2172
2357
|
const button = openDialog.buttons.find((b) => normalizeIdent(b.label) === needle);
|
|
2173
2358
|
if (button) {
|
|
2174
2359
|
button.press();
|
|
2175
|
-
|
|
2360
|
+
chunkSUMIABJK_js.appilotsDebugLog(`uiInteractionHandler: pressed native dialog button "${button.label}"`);
|
|
2176
2361
|
return { success: true, effect: "changed" };
|
|
2177
2362
|
}
|
|
2178
2363
|
}
|
|
2179
2364
|
if (!openDialog && isPressVerb) {
|
|
2180
|
-
const answered =
|
|
2365
|
+
const answered = chunkSUMIABJK_js.getLastAnsweredNativeDialog();
|
|
2181
2366
|
const needle = normalizeIdent(rawComponentId);
|
|
2182
2367
|
if (answered && needle) {
|
|
2183
2368
|
if (answered.answeredWith && normalizeIdent(answered.answeredWith) === needle) {
|
|
2184
|
-
|
|
2369
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2185
2370
|
`uiInteractionHandler: native dialog button "${answered.answeredWith}" was already pressed and the dialog is closed \u2014 treating the repeat as done`
|
|
2186
2371
|
);
|
|
2187
2372
|
return { success: true, effect: "completed" };
|
|
@@ -2193,7 +2378,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2193
2378
|
diagnose: {
|
|
2194
2379
|
category: "component-not-found",
|
|
2195
2380
|
targetId: rawComponentId,
|
|
2196
|
-
screen:
|
|
2381
|
+
screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
|
|
2197
2382
|
recoverable: false
|
|
2198
2383
|
}
|
|
2199
2384
|
};
|
|
@@ -2202,7 +2387,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2202
2387
|
}
|
|
2203
2388
|
const occluded = checkModalOcclusion(rawComponentId, actionStr);
|
|
2204
2389
|
if (occluded) {
|
|
2205
|
-
|
|
2390
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2206
2391
|
`uiInteractionHandler: blocked "${actionStr}" on "${rawComponentId}" \u2014 target is behind an open modal`
|
|
2207
2392
|
);
|
|
2208
2393
|
return occluded;
|
|
@@ -2210,26 +2395,25 @@ function uiInteractionHandler(payload, context) {
|
|
|
2210
2395
|
if (typeof rawComponentId === "string" && rawComponentId.trim().toLowerCase().startsWith("el:")) {
|
|
2211
2396
|
const result = dispatchElementOrTarget(rawComponentId, registry, actionStr);
|
|
2212
2397
|
if (result.success) {
|
|
2213
|
-
|
|
2398
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2214
2399
|
`uiInteractionHandler: interaction element dispatch succeeded for "${rawComponentId}"`
|
|
2215
2400
|
);
|
|
2216
|
-
return { success: true };
|
|
2217
2401
|
}
|
|
2218
2402
|
return result;
|
|
2219
2403
|
}
|
|
2220
2404
|
const ordinal = parseSyntheticListItemId(rawComponentId);
|
|
2221
2405
|
if (ordinal && (action === "press" || actionStr === "tap" || actionStr === "click" || actionStr === "longPress")) {
|
|
2222
|
-
|
|
2406
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2223
2407
|
`uiInteractionHandler: dispatching synthetic list ordinal \u2014 componentId="${rawComponentId}" list=${ordinal.listIndex} item=${ordinal.itemIndex}`
|
|
2224
2408
|
);
|
|
2225
2409
|
const result = pressListItemAtOrdinal(ordinal.listIndex, ordinal.itemIndex);
|
|
2226
2410
|
if (result.ok) {
|
|
2227
|
-
|
|
2411
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2228
2412
|
`uiInteractionHandler: synthetic ordinal press succeeded (container=${result.containerType ?? "List"})`
|
|
2229
2413
|
);
|
|
2230
2414
|
return { success: true };
|
|
2231
2415
|
}
|
|
2232
|
-
const screen =
|
|
2416
|
+
const screen = chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
|
|
2233
2417
|
if (result.reason === "list-not-found" || result.reason === "item-not-found") {
|
|
2234
2418
|
return {
|
|
2235
2419
|
success: false,
|
|
@@ -2245,12 +2429,12 @@ function uiInteractionHandler(payload, context) {
|
|
|
2245
2429
|
};
|
|
2246
2430
|
}
|
|
2247
2431
|
if (result.reason === "ambiguous-touchables") {
|
|
2248
|
-
const
|
|
2432
|
+
const namesConcreteChoice = result.refusal !== void 0 || /only exposes destructive controls|contains a switch/i.test(result.error ?? "");
|
|
2249
2433
|
return {
|
|
2250
2434
|
success: false,
|
|
2251
2435
|
error: result.error ?? `Synthetic list ordinal press failed (${result.reason ?? "unknown"})`,
|
|
2252
2436
|
diagnose: {
|
|
2253
|
-
category:
|
|
2437
|
+
category: namesConcreteChoice ? "ambiguous-target" : "unknown",
|
|
2254
2438
|
targetId: rawComponentId,
|
|
2255
2439
|
screen,
|
|
2256
2440
|
recoverable: true,
|
|
@@ -2270,7 +2454,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
2270
2454
|
};
|
|
2271
2455
|
}
|
|
2272
2456
|
const componentId = resolveComponentId(rawComponentId, registry, actionStr);
|
|
2273
|
-
|
|
2457
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2274
2458
|
`uiInteractionHandler: resolved componentId="${payload.componentId}" \u2192 "${componentId}"`
|
|
2275
2459
|
);
|
|
2276
2460
|
const target = registry.getTarget(componentId);
|
|
@@ -2323,9 +2507,11 @@ function uiInteractionHandler(payload, context) {
|
|
|
2323
2507
|
return { success: false, error: err?.message ?? "Focus failed" };
|
|
2324
2508
|
}
|
|
2325
2509
|
}
|
|
2326
|
-
|
|
2510
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2327
2511
|
`uiInteractionHandler: registry miss for "${componentId}", falling back to fiber tree`
|
|
2328
2512
|
);
|
|
2513
|
+
const namedToggle = dispatchIdentifiedToggle(componentId, actionStr);
|
|
2514
|
+
if (namedToggle) return namedToggle;
|
|
2329
2515
|
const handle = findInteractiveByIdentifier(componentId, {
|
|
2330
2516
|
kind: actionStr === "toggle" ? "toggle" : actionStr === "focus" ? "field" : "target"
|
|
2331
2517
|
});
|
|
@@ -2333,15 +2519,11 @@ function uiInteractionHandler(payload, context) {
|
|
|
2333
2519
|
try {
|
|
2334
2520
|
if (actionStr === "press" && handle.kind === "target" && handle.press) {
|
|
2335
2521
|
handle.press();
|
|
2336
|
-
|
|
2522
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2337
2523
|
`uiInteractionHandler: fiber fallback press succeeded for "${componentId}"`
|
|
2338
2524
|
);
|
|
2339
2525
|
return { success: true };
|
|
2340
2526
|
}
|
|
2341
|
-
if (actionStr === "press" && handle.kind === "toggle" && handle.setValue) {
|
|
2342
|
-
handle.setValue(!handle.getValue?.());
|
|
2343
|
-
return { success: true };
|
|
2344
|
-
}
|
|
2345
2527
|
if (actionStr === "toggle" && handle.kind === "toggle" && handle.setValue) {
|
|
2346
2528
|
handle.setValue(!handle.getValue?.());
|
|
2347
2529
|
return { success: true };
|
|
@@ -2400,7 +2582,7 @@ function submitLabelHintsSubmit(label) {
|
|
|
2400
2582
|
return SUBMIT_LABEL_HINT_RE.test(trimmed);
|
|
2401
2583
|
}
|
|
2402
2584
|
function screenDeclaresSubmitAction(screenName) {
|
|
2403
|
-
const meta =
|
|
2585
|
+
const meta = chunkSUMIABJK_js.getScreenMetadata(screenName);
|
|
2404
2586
|
return Array.isArray(meta?.actions) && meta.actions.some(
|
|
2405
2587
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2406
2588
|
);
|
|
@@ -2433,7 +2615,7 @@ function resolveFormScreensForSubmit(screen, activePath, registry) {
|
|
|
2433
2615
|
} else {
|
|
2434
2616
|
push(screen);
|
|
2435
2617
|
}
|
|
2436
|
-
push(
|
|
2618
|
+
push(chunkSUMIABJK_js.getCurrentScreen() ?? void 0);
|
|
2437
2619
|
const withSubmit = [];
|
|
2438
2620
|
const rest = [];
|
|
2439
2621
|
for (const name of ordered) {
|
|
@@ -2451,7 +2633,7 @@ function collectSubmitTargetCandidates(screens, registry) {
|
|
|
2451
2633
|
candidates.push(id);
|
|
2452
2634
|
};
|
|
2453
2635
|
for (const screenName of screens) {
|
|
2454
|
-
const meta =
|
|
2636
|
+
const meta = chunkSUMIABJK_js.getScreenMetadata(screenName);
|
|
2455
2637
|
const submitMeta = Array.isArray(meta?.actions) ? meta.actions.find(
|
|
2456
2638
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
2457
2639
|
) : void 0;
|
|
@@ -2495,8 +2677,8 @@ function readVisibleValidation(fieldId, label) {
|
|
|
2495
2677
|
return void 0;
|
|
2496
2678
|
}
|
|
2497
2679
|
function resolveScreenContext() {
|
|
2498
|
-
const activePath =
|
|
2499
|
-
const screen = activePath[activePath.length - 1] ??
|
|
2680
|
+
const activePath = chunkSUMIABJK_js.getActiveRouteNames();
|
|
2681
|
+
const screen = activePath[activePath.length - 1] ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
|
|
2500
2682
|
return { screen, activePath };
|
|
2501
2683
|
}
|
|
2502
2684
|
function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
@@ -2504,36 +2686,36 @@ function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
|
2504
2686
|
if (!requested) return false;
|
|
2505
2687
|
const meta = getMetadataField(fieldId, registry);
|
|
2506
2688
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2507
|
-
const requestedNorm =
|
|
2508
|
-
const currentNorm =
|
|
2689
|
+
const requestedNorm = chunkSUMIABJK_js.normalize3(requested);
|
|
2690
|
+
const currentNorm = chunkSUMIABJK_js.normalize3(currentValue);
|
|
2509
2691
|
if (currentNorm === requestedNorm) return true;
|
|
2510
2692
|
for (const option of options) {
|
|
2511
2693
|
const value = typeof option?.value === "string" ? option.value : "";
|
|
2512
2694
|
const label = typeof option?.label === "string" ? option.label : "";
|
|
2513
|
-
if (
|
|
2514
|
-
if (
|
|
2515
|
-
if (
|
|
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;
|
|
2516
2698
|
}
|
|
2517
2699
|
return false;
|
|
2518
2700
|
}
|
|
2519
2701
|
function getMetadataField(fieldId, registry) {
|
|
2520
2702
|
const screens = /* @__PURE__ */ new Set();
|
|
2521
|
-
for (const name of
|
|
2522
|
-
const current =
|
|
2703
|
+
for (const name of chunkSUMIABJK_js.getActiveRouteNames()) screens.add(name);
|
|
2704
|
+
const current = chunkSUMIABJK_js.getCurrentScreen();
|
|
2523
2705
|
if (current) screens.add(current);
|
|
2524
2706
|
if (registry) {
|
|
2525
2707
|
for (const comp of registry.snapshot()) {
|
|
2526
2708
|
if (comp.kind === "field" && comp.screen) screens.add(comp.screen);
|
|
2527
2709
|
}
|
|
2528
2710
|
}
|
|
2529
|
-
const needle =
|
|
2711
|
+
const needle = chunkSUMIABJK_js.normalize3(fieldId);
|
|
2530
2712
|
for (const screenName of screens) {
|
|
2531
|
-
const screenMeta =
|
|
2713
|
+
const screenMeta = chunkSUMIABJK_js.getScreenMetadata(screenName);
|
|
2532
2714
|
const fields = Array.isArray(screenMeta?.fields) ? screenMeta.fields : [];
|
|
2533
2715
|
const match = fields.find((field) => {
|
|
2534
2716
|
if (!field || typeof field !== "object") return false;
|
|
2535
|
-
const id = typeof field.id === "string" ?
|
|
2536
|
-
const label = typeof field.label === "string" ?
|
|
2717
|
+
const id = typeof field.id === "string" ? chunkSUMIABJK_js.normalize3(field.id) : "";
|
|
2718
|
+
const label = typeof field.label === "string" ? chunkSUMIABJK_js.normalize3(field.label) : "";
|
|
2537
2719
|
return id === needle || label === needle;
|
|
2538
2720
|
});
|
|
2539
2721
|
if (match) return match;
|
|
@@ -2545,11 +2727,11 @@ function resolveSelectOption(fieldId, value, registry) {
|
|
|
2545
2727
|
if (!requested) return void 0;
|
|
2546
2728
|
const meta = getMetadataField(fieldId, registry);
|
|
2547
2729
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
2548
|
-
const requestedNorm =
|
|
2730
|
+
const requestedNorm = chunkSUMIABJK_js.normalize3(requested);
|
|
2549
2731
|
for (const option of options) {
|
|
2550
2732
|
const optionValue = typeof option?.value === "string" ? option.value : "";
|
|
2551
2733
|
const optionLabel = typeof option?.label === "string" ? option.label : "";
|
|
2552
|
-
if (
|
|
2734
|
+
if (chunkSUMIABJK_js.normalize3(optionValue) === requestedNorm || chunkSUMIABJK_js.normalize3(optionLabel) === requestedNorm) {
|
|
2553
2735
|
return { value: optionValue, label: optionLabel };
|
|
2554
2736
|
}
|
|
2555
2737
|
}
|
|
@@ -2599,12 +2781,12 @@ async function tryPressSelectOption(fieldId, value, registry, options = {}) {
|
|
|
2599
2781
|
return {
|
|
2600
2782
|
success: false,
|
|
2601
2783
|
error: `No pressable option found for select field "${fieldId}"`,
|
|
2602
|
-
diagnose: { category: "component-not-found", fieldId, screen:
|
|
2784
|
+
diagnose: { category: "component-not-found", fieldId, screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
|
|
2603
2785
|
};
|
|
2604
2786
|
}
|
|
2605
2787
|
function normalizeFieldType(type) {
|
|
2606
2788
|
if (typeof type !== "string") return void 0;
|
|
2607
|
-
const normalized =
|
|
2789
|
+
const normalized = chunkSUMIABJK_js.normalize3(type);
|
|
2608
2790
|
if (normalized === "select" || normalized === "picker" || normalized === "dropdown")
|
|
2609
2791
|
return "select";
|
|
2610
2792
|
if (normalized === "toggle" || normalized === "switch" || normalized === "checkbox")
|
|
@@ -2634,7 +2816,7 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2634
2816
|
);
|
|
2635
2817
|
const terms = /* @__PURE__ */ new Set();
|
|
2636
2818
|
for (const value of raw) {
|
|
2637
|
-
const normalized =
|
|
2819
|
+
const normalized = chunkSUMIABJK_js.normalize3(value);
|
|
2638
2820
|
if (normalized.length >= 3 && normalized !== "id") terms.add(normalized);
|
|
2639
2821
|
}
|
|
2640
2822
|
return [...terms];
|
|
@@ -2642,17 +2824,17 @@ function fieldCueTerms(fieldId, label) {
|
|
|
2642
2824
|
function snapshotHasFieldCue(snap, fieldId, label) {
|
|
2643
2825
|
const terms = fieldCueTerms(fieldId, label);
|
|
2644
2826
|
if (terms.length === 0) return false;
|
|
2645
|
-
const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) =>
|
|
2827
|
+
const visible = [...snap.texts ?? [], ...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")].map((text) => chunkSUMIABJK_js.normalize3(text)).filter(Boolean);
|
|
2646
2828
|
return visible.some((text) => terms.some((term) => text.includes(term) || term.includes(text)));
|
|
2647
2829
|
}
|
|
2648
2830
|
function scoreCandidateText(value, texts) {
|
|
2649
|
-
const valueNorm =
|
|
2831
|
+
const valueNorm = chunkSUMIABJK_js.normalize3(String(value ?? ""));
|
|
2650
2832
|
if (!valueNorm) return 0;
|
|
2651
2833
|
let best = 0;
|
|
2652
2834
|
for (const text of texts) {
|
|
2653
|
-
const textNorm =
|
|
2835
|
+
const textNorm = chunkSUMIABJK_js.normalize3(text);
|
|
2654
2836
|
if (!textNorm) continue;
|
|
2655
|
-
best = Math.max(best,
|
|
2837
|
+
best = Math.max(best, chunkSUMIABJK_js.matchScore(valueNorm, textNorm));
|
|
2656
2838
|
}
|
|
2657
2839
|
return best;
|
|
2658
2840
|
}
|
|
@@ -2666,7 +2848,7 @@ function optionTexts(option) {
|
|
|
2666
2848
|
function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue, registry) {
|
|
2667
2849
|
const fieldLabel = getFieldLabel(fieldId, registry);
|
|
2668
2850
|
const fieldCueVisible = snapshotHasFieldCue(snap, fieldId, fieldLabel);
|
|
2669
|
-
const genericValue =
|
|
2851
|
+
const genericValue = chunkSUMIABJK_js.isGenericSelectValue(value);
|
|
2670
2852
|
const candidates = [];
|
|
2671
2853
|
let order = 0;
|
|
2672
2854
|
const choiceGroups = snap.choiceGroups ?? [];
|
|
@@ -2678,7 +2860,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2678
2860
|
const groupCueScore = Math.max(
|
|
2679
2861
|
globalCueScore,
|
|
2680
2862
|
...groupTexts.map((text) => {
|
|
2681
|
-
const normalized =
|
|
2863
|
+
const normalized = chunkSUMIABJK_js.normalize3(text);
|
|
2682
2864
|
return fieldCueTerms(fieldId, fieldLabel).some(
|
|
2683
2865
|
(term) => normalized.includes(term) || term.includes(normalized)
|
|
2684
2866
|
) ? 80 : 0;
|
|
@@ -2715,7 +2897,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
2715
2897
|
const elementCueScore = Math.max(
|
|
2716
2898
|
fieldCueVisible && elements.length <= 12 ? 50 : 0,
|
|
2717
2899
|
...cueTexts.map((text) => {
|
|
2718
|
-
const normalized =
|
|
2900
|
+
const normalized = chunkSUMIABJK_js.normalize3(text);
|
|
2719
2901
|
return fieldTerms.some((term) => normalized.includes(term) || term.includes(normalized)) ? 80 : 0;
|
|
2720
2902
|
})
|
|
2721
2903
|
);
|
|
@@ -2773,7 +2955,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
2773
2955
|
return {
|
|
2774
2956
|
success: false,
|
|
2775
2957
|
error: err?.message ?? "Could not capture visible choices",
|
|
2776
|
-
diagnose: { category: "unknown", fieldId, screen:
|
|
2958
|
+
diagnose: { category: "unknown", fieldId, screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
|
|
2777
2959
|
};
|
|
2778
2960
|
}
|
|
2779
2961
|
const candidates = buildChoiceCandidates(
|
|
@@ -2791,7 +2973,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
2791
2973
|
diagnose: {
|
|
2792
2974
|
category: "component-not-found",
|
|
2793
2975
|
fieldId,
|
|
2794
|
-
screen:
|
|
2976
|
+
screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0
|
|
2795
2977
|
}
|
|
2796
2978
|
};
|
|
2797
2979
|
}
|
|
@@ -2805,7 +2987,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
2805
2987
|
}
|
|
2806
2988
|
function isContinuationButton(label) {
|
|
2807
2989
|
if (!label) return false;
|
|
2808
|
-
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(
|
|
2990
|
+
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkSUMIABJK_js.normalize3(label));
|
|
2809
2991
|
}
|
|
2810
2992
|
function pressContinuationButton(registry) {
|
|
2811
2993
|
const snap = captureSnapshot();
|
|
@@ -2818,40 +3000,40 @@ function pressContinuationButton(registry) {
|
|
|
2818
3000
|
return {
|
|
2819
3001
|
success: false,
|
|
2820
3002
|
error: "No enabled continuation button is visible",
|
|
2821
|
-
diagnose: { category: "component-not-found", screen:
|
|
3003
|
+
diagnose: { category: "component-not-found", screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0 }
|
|
2822
3004
|
};
|
|
2823
3005
|
}
|
|
2824
3006
|
return pressTargetByIdOrLabel(id, registry);
|
|
2825
3007
|
}
|
|
2826
3008
|
function findField(fieldId, registry) {
|
|
2827
|
-
|
|
3009
|
+
chunkSUMIABJK_js.appilotsDebugLog(`findField: searching for fieldId="${fieldId}"`);
|
|
2828
3010
|
const exact = registry.getField(fieldId);
|
|
2829
3011
|
if (exact) {
|
|
2830
|
-
|
|
3012
|
+
chunkSUMIABJK_js.appilotsDebugLog(`findField: FOUND exact match for fieldId="${fieldId}"`);
|
|
2831
3013
|
return exact;
|
|
2832
3014
|
}
|
|
2833
3015
|
const lower = fieldId.toLowerCase();
|
|
2834
3016
|
const snapshot = registry.snapshot();
|
|
2835
3017
|
for (const comp of snapshot) {
|
|
2836
3018
|
if (comp.kind === "field" && comp.id.toLowerCase() === lower) {
|
|
2837
|
-
|
|
3019
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2838
3020
|
`findField: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2839
3021
|
);
|
|
2840
3022
|
return registry.getField(comp.id);
|
|
2841
3023
|
}
|
|
2842
3024
|
}
|
|
2843
|
-
const currentScreenForTieBreak =
|
|
2844
|
-
const needle =
|
|
3025
|
+
const currentScreenForTieBreak = chunkSUMIABJK_js.getCurrentScreen();
|
|
3026
|
+
const needle = chunkSUMIABJK_js.normalize3(fieldId);
|
|
2845
3027
|
let bestComp;
|
|
2846
3028
|
let bestScore = 0;
|
|
2847
3029
|
let bestOnCurrentScreen = false;
|
|
2848
3030
|
for (const comp of snapshot) {
|
|
2849
3031
|
if (comp.kind !== "field") continue;
|
|
2850
|
-
const candidates = [
|
|
2851
|
-
if (comp.label) candidates.push(
|
|
3032
|
+
const candidates = [chunkSUMIABJK_js.normalize3(comp.id)];
|
|
3033
|
+
if (comp.label) candidates.push(chunkSUMIABJK_js.normalize3(comp.label));
|
|
2852
3034
|
let candidateScore = 0;
|
|
2853
3035
|
for (const cand of candidates) {
|
|
2854
|
-
const s =
|
|
3036
|
+
const s = chunkSUMIABJK_js.matchScore(needle, cand);
|
|
2855
3037
|
if (s > candidateScore) candidateScore = s;
|
|
2856
3038
|
}
|
|
2857
3039
|
if (candidateScore === 0) continue;
|
|
@@ -2864,14 +3046,14 @@ function findField(fieldId, registry) {
|
|
|
2864
3046
|
}
|
|
2865
3047
|
}
|
|
2866
3048
|
if (bestComp && bestScore >= 75) {
|
|
2867
|
-
|
|
3049
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2868
3050
|
`findField: scored match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
2869
3051
|
);
|
|
2870
3052
|
return registry.getField(bestComp.id);
|
|
2871
3053
|
}
|
|
2872
|
-
const currentScreen =
|
|
3054
|
+
const currentScreen = chunkSUMIABJK_js.getCurrentScreen();
|
|
2873
3055
|
if (currentScreen) {
|
|
2874
|
-
const screenMeta =
|
|
3056
|
+
const screenMeta = chunkSUMIABJK_js.getScreenMetadata(currentScreen);
|
|
2875
3057
|
const fields = screenMeta?.fields;
|
|
2876
3058
|
if (fields && Array.isArray(fields)) {
|
|
2877
3059
|
const metaField = fields.find(
|
|
@@ -2879,19 +3061,19 @@ function findField(fieldId, registry) {
|
|
|
2879
3061
|
);
|
|
2880
3062
|
if (metaField && typeof metaField === "object" && metaField.label) {
|
|
2881
3063
|
const metaLabel = metaField.label;
|
|
2882
|
-
const metaNeedle =
|
|
3064
|
+
const metaNeedle = chunkSUMIABJK_js.normalize3(metaLabel);
|
|
2883
3065
|
let mBest;
|
|
2884
3066
|
let mBestScore = 0;
|
|
2885
3067
|
for (const comp of snapshot) {
|
|
2886
3068
|
if (comp.kind !== "field" || !comp.label) continue;
|
|
2887
|
-
const score =
|
|
3069
|
+
const score = chunkSUMIABJK_js.matchScore(metaNeedle, chunkSUMIABJK_js.normalize3(comp.label));
|
|
2888
3070
|
if (score > mBestScore) {
|
|
2889
3071
|
mBestScore = score;
|
|
2890
3072
|
mBest = comp;
|
|
2891
3073
|
}
|
|
2892
3074
|
}
|
|
2893
3075
|
if (mBest && mBestScore >= 60) {
|
|
2894
|
-
|
|
3076
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2895
3077
|
`findField: FOUND via screen metadata translation: fieldId="${fieldId}" -> metaLabel="${metaLabel}" -> registered="${mBest.id}" (score=${mBestScore})`
|
|
2896
3078
|
);
|
|
2897
3079
|
return registry.getField(mBest.id);
|
|
@@ -2900,34 +3082,34 @@ function findField(fieldId, registry) {
|
|
|
2900
3082
|
}
|
|
2901
3083
|
}
|
|
2902
3084
|
if (bestComp && bestScore >= 40) {
|
|
2903
|
-
|
|
3085
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2904
3086
|
`findField: weak substring match "${fieldId}" -> "${bestComp.id}" (label="${bestComp.label}", score=${bestScore})`
|
|
2905
3087
|
);
|
|
2906
3088
|
return registry.getField(bestComp.id);
|
|
2907
3089
|
}
|
|
2908
|
-
|
|
3090
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
2909
3091
|
`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"}`
|
|
2910
3092
|
);
|
|
2911
3093
|
return void 0;
|
|
2912
3094
|
}
|
|
2913
3095
|
function findToggle(fieldId, registry) {
|
|
2914
|
-
|
|
3096
|
+
chunkSUMIABJK_js.appilotsDebugLog(`findToggle: searching for fieldId="${fieldId}"`);
|
|
2915
3097
|
const exact = registry.getToggle(fieldId);
|
|
2916
3098
|
if (exact) {
|
|
2917
|
-
|
|
3099
|
+
chunkSUMIABJK_js.appilotsDebugLog(`findToggle: FOUND exact match for "${fieldId}"`);
|
|
2918
3100
|
return exact;
|
|
2919
3101
|
}
|
|
2920
3102
|
const lower = fieldId.toLowerCase();
|
|
2921
3103
|
const snapshot = registry.snapshot();
|
|
2922
3104
|
for (const comp of snapshot) {
|
|
2923
3105
|
if (comp.kind === "toggle" && comp.id.toLowerCase() === lower) {
|
|
2924
|
-
|
|
3106
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2925
3107
|
`findToggle: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2926
3108
|
);
|
|
2927
3109
|
return registry.getToggle(comp.id);
|
|
2928
3110
|
}
|
|
2929
3111
|
}
|
|
2930
|
-
|
|
3112
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
2931
3113
|
`findToggle: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available toggles: ${snapshot.filter((c) => c.kind === "toggle").map((c) => `"${c.id}"`).join(", ") || "none"}`
|
|
2932
3114
|
);
|
|
2933
3115
|
return void 0;
|
|
@@ -2938,7 +3120,7 @@ function findSlider(fieldId, registry) {
|
|
|
2938
3120
|
const lower = fieldId.toLowerCase();
|
|
2939
3121
|
for (const comp of registry.snapshot()) {
|
|
2940
3122
|
if (comp.kind === "slider" && comp.id.toLowerCase() === lower) {
|
|
2941
|
-
|
|
3123
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2942
3124
|
`findSlider: FOUND case-insensitive match: registered="${comp.id}" for searched="${fieldId}"`
|
|
2943
3125
|
);
|
|
2944
3126
|
return registry.getSlider(comp.id);
|
|
@@ -2949,7 +3131,7 @@ function findSlider(fieldId, registry) {
|
|
|
2949
3131
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2950
3132
|
async function formFillHandler(payload, context) {
|
|
2951
3133
|
const { permissions } = context;
|
|
2952
|
-
const registry = context.registry ??
|
|
3134
|
+
const registry = context.registry ?? chunkSUMIABJK_js.componentRegistry;
|
|
2953
3135
|
const { screen, activePath } = resolveScreenContext();
|
|
2954
3136
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
2955
3137
|
if (!permissions.canFillForms) {
|
|
@@ -2968,11 +3150,11 @@ async function formFillHandler(payload, context) {
|
|
|
2968
3150
|
}
|
|
2969
3151
|
const registrySnapshot = registry.snapshot();
|
|
2970
3152
|
if (registrySnapshot.length === 0) {
|
|
2971
|
-
|
|
3153
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
2972
3154
|
"formFillHandler: registry is EMPTY \u2014 auto-tracking may not be active. Ensure enableAppilotsAutoTracking() runs before components mount."
|
|
2973
3155
|
);
|
|
2974
3156
|
} else {
|
|
2975
|
-
|
|
3157
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
2976
3158
|
`[Appilots formFillHandler] Registry has ${registrySnapshot.length} components:`,
|
|
2977
3159
|
registrySnapshot.map((c) => `${c.kind}:${c.id}`).join(", ")
|
|
2978
3160
|
);
|
|
@@ -2980,7 +3162,7 @@ async function formFillHandler(payload, context) {
|
|
|
2980
3162
|
const fieldResults = [];
|
|
2981
3163
|
let allSuccess = true;
|
|
2982
3164
|
let selectedChoiceThisBatch = false;
|
|
2983
|
-
|
|
3165
|
+
chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: processing ${payload.fields.length} fields`);
|
|
2984
3166
|
const availableFieldIds = () => registry.snapshot().filter((comp) => comp.kind === "field").map((comp) => `${comp.id}${comp.label ? ` (${comp.label})` : ""}`).slice(0, 8);
|
|
2985
3167
|
const isElementIdField = (field) => typeof field.fieldId === "string" && field.fieldId.trim().toLowerCase().startsWith("el:");
|
|
2986
3168
|
for (const field of payload.fields.filter(isElementIdField)) {
|
|
@@ -3007,13 +3189,13 @@ async function formFillHandler(payload, context) {
|
|
|
3007
3189
|
const { fieldId, fieldType, value } = field;
|
|
3008
3190
|
const effectiveFieldType = getEffectiveFieldType(fieldId, fieldType, registry);
|
|
3009
3191
|
let selectFailure;
|
|
3010
|
-
|
|
3011
|
-
`formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${
|
|
3192
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3193
|
+
`formFillHandler: looking up fieldId="${fieldId}" fieldType="${fieldType}" effectiveFieldType="${effectiveFieldType}" value=${chunkSUMIABJK_js.describeValue(value)}`
|
|
3012
3194
|
);
|
|
3013
3195
|
const fieldEntry = findField(fieldId, registry);
|
|
3014
3196
|
if (fieldEntry) {
|
|
3015
3197
|
try {
|
|
3016
|
-
|
|
3198
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3017
3199
|
`formFillHandler: found field "${fieldId}" via registry, calling setValue(<${String(value).length} chars>)`
|
|
3018
3200
|
);
|
|
3019
3201
|
const beforeValue = effectiveFieldType === "date" ? fieldEntry.getValue?.() ?? "" : void 0;
|
|
@@ -3044,7 +3226,7 @@ async function formFillHandler(payload, context) {
|
|
|
3044
3226
|
after = fieldEntry.getValue?.() ?? "";
|
|
3045
3227
|
}
|
|
3046
3228
|
if (!selectValueApplied(fieldId, value, after, registry)) {
|
|
3047
|
-
|
|
3229
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
3048
3230
|
`formFillHandler: select field "${fieldId}" setValue did not stick (wrote <${String(value).length} chars>, current is <${String(after ?? "").length} chars>), trying visible choice fallback`
|
|
3049
3231
|
);
|
|
3050
3232
|
const selectResult = await selectVisibleChoice(fieldId, value, registry, {
|
|
@@ -3169,7 +3351,7 @@ async function formFillHandler(payload, context) {
|
|
|
3169
3351
|
}
|
|
3170
3352
|
if (selectResult.success) {
|
|
3171
3353
|
selectedChoiceThisBatch = true;
|
|
3172
|
-
|
|
3354
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3173
3355
|
`formFillHandler: selected visible option for "${fieldId}"` + (selectResult.selectedLabel ? ` \u2192 "${selectResult.selectedLabel}"` : "")
|
|
3174
3356
|
);
|
|
3175
3357
|
await sleep2(120);
|
|
@@ -3178,7 +3360,7 @@ async function formFillHandler(payload, context) {
|
|
|
3178
3360
|
}
|
|
3179
3361
|
selectFailure = selectResult;
|
|
3180
3362
|
}
|
|
3181
|
-
|
|
3363
|
+
chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: registry miss for "${fieldId}", falling back to fiber tree`);
|
|
3182
3364
|
const handle = findInteractiveByIdentifier(fieldId, {
|
|
3183
3365
|
kind: effectiveFieldType === "toggle" ? "toggle" : "field"
|
|
3184
3366
|
});
|
|
@@ -3186,7 +3368,7 @@ async function formFillHandler(payload, context) {
|
|
|
3186
3368
|
try {
|
|
3187
3369
|
handle.focus?.();
|
|
3188
3370
|
handle.setValue(value);
|
|
3189
|
-
|
|
3371
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3190
3372
|
`formFillHandler: fiber fallback succeeded for "${fieldId}" \u2192 label="${handle.label}"`
|
|
3191
3373
|
);
|
|
3192
3374
|
fieldResults.push({ fieldId, success: true });
|
|
@@ -3223,13 +3405,24 @@ async function formFillHandler(payload, context) {
|
|
|
3223
3405
|
allSuccess = false;
|
|
3224
3406
|
}
|
|
3225
3407
|
if (payload.submitAfterFill === true) {
|
|
3408
|
+
if (!permissions.canSubmitForms) {
|
|
3409
|
+
return {
|
|
3410
|
+
success: false,
|
|
3411
|
+
error: "Form submission is not permitted",
|
|
3412
|
+
fieldResults,
|
|
3413
|
+
diagnose: { category: "unknown", screen: screenPath }
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3226
3416
|
if (!allSuccess) {
|
|
3227
3417
|
const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
|
|
3228
|
-
|
|
3418
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
3229
3419
|
"formFillHandler: submitAfterFill=true requested but some fields failed; NOT submitting" + (failedIds.length > 0 ? ` (failed: ${failedIds.join(", ")})` : "")
|
|
3230
3420
|
);
|
|
3231
3421
|
} else {
|
|
3232
3422
|
await sleep2(120);
|
|
3423
|
+
if (!permissions.canSubmitForms) {
|
|
3424
|
+
return { success: false, error: "Form submission is not permitted", fieldResults };
|
|
3425
|
+
}
|
|
3233
3426
|
const submitResult = pressSubmitButton(
|
|
3234
3427
|
{
|
|
3235
3428
|
screen,
|
|
@@ -3240,7 +3433,7 @@ async function formFillHandler(payload, context) {
|
|
|
3240
3433
|
registry
|
|
3241
3434
|
);
|
|
3242
3435
|
if (!submitResult.success) {
|
|
3243
|
-
|
|
3436
|
+
chunkSUMIABJK_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
|
|
3244
3437
|
return {
|
|
3245
3438
|
success: false,
|
|
3246
3439
|
error: submitResult.error,
|
|
@@ -3252,7 +3445,7 @@ async function formFillHandler(payload, context) {
|
|
|
3252
3445
|
submitTargetId: submitResult.pressedTargetId
|
|
3253
3446
|
});
|
|
3254
3447
|
if (postSubmit.status === "pending") {
|
|
3255
|
-
|
|
3448
|
+
chunkSUMIABJK_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
|
|
3256
3449
|
return {
|
|
3257
3450
|
success: false,
|
|
3258
3451
|
error: postSubmit.message,
|
|
@@ -3261,7 +3454,7 @@ async function formFillHandler(payload, context) {
|
|
|
3261
3454
|
};
|
|
3262
3455
|
}
|
|
3263
3456
|
if (postSubmit.status === "failure") {
|
|
3264
|
-
|
|
3457
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
3265
3458
|
`formFillHandler: submit rejected by visible validation \u2014 ${postSubmit.message}`
|
|
3266
3459
|
);
|
|
3267
3460
|
return {
|
|
@@ -3276,7 +3469,7 @@ async function formFillHandler(payload, context) {
|
|
|
3276
3469
|
}
|
|
3277
3470
|
};
|
|
3278
3471
|
}
|
|
3279
|
-
|
|
3472
|
+
chunkSUMIABJK_js.appilotsDebugLog("formFillHandler: submitAfterFill \u2014 submit completed");
|
|
3280
3473
|
}
|
|
3281
3474
|
}
|
|
3282
3475
|
const aggregatedDiagnose = aggregateFieldDiagnoses(fieldResults, screenPath);
|
|
@@ -3288,17 +3481,17 @@ async function formFillHandler(payload, context) {
|
|
|
3288
3481
|
};
|
|
3289
3482
|
}
|
|
3290
3483
|
function pressSubmitButton(context, registry) {
|
|
3291
|
-
const activePath = context.activePath ??
|
|
3484
|
+
const activePath = context.activePath ?? chunkSUMIABJK_js.getActiveRouteNames();
|
|
3292
3485
|
const hintScreen = context.screen ?? context.screenPath;
|
|
3293
3486
|
const formScreens = resolveFormScreensForSubmit(hintScreen, activePath, registry);
|
|
3294
|
-
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ??
|
|
3487
|
+
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
|
|
3295
3488
|
const candidates = collectSubmitTargetCandidates(formScreens, registry);
|
|
3296
3489
|
for (const candidate of candidates) {
|
|
3297
3490
|
const target = registry.getTarget(candidate);
|
|
3298
3491
|
if (target) {
|
|
3299
3492
|
try {
|
|
3300
3493
|
target.press();
|
|
3301
|
-
|
|
3494
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3302
3495
|
`formFillHandler: submitAfterFill \u2014 pressed registry target "${candidate}"` + (resolvedScreen ? ` on screen "${resolvedScreen}"` : "")
|
|
3303
3496
|
);
|
|
3304
3497
|
return { success: true, pressedTargetId: candidate };
|
|
@@ -3312,7 +3505,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3312
3505
|
}
|
|
3313
3506
|
}
|
|
3314
3507
|
for (const screenName of formScreens) {
|
|
3315
|
-
const screenMeta =
|
|
3508
|
+
const screenMeta = chunkSUMIABJK_js.getScreenMetadata(screenName);
|
|
3316
3509
|
const submitMeta = Array.isArray(screenMeta?.actions) ? screenMeta.actions.find(
|
|
3317
3510
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
3318
3511
|
) : void 0;
|
|
@@ -3323,7 +3516,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3323
3516
|
if (handle?.press) {
|
|
3324
3517
|
try {
|
|
3325
3518
|
handle.press();
|
|
3326
|
-
|
|
3519
|
+
chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 fiber fallback "${submitLabel}"`);
|
|
3327
3520
|
return { success: true, pressedTargetId: submitId ?? submitLabel };
|
|
3328
3521
|
} catch (err) {
|
|
3329
3522
|
return {
|
|
@@ -3345,7 +3538,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3345
3538
|
if (id) {
|
|
3346
3539
|
const pressed = pressTargetByIdOrLabel(id, registry);
|
|
3347
3540
|
if (pressed.success) {
|
|
3348
|
-
|
|
3541
|
+
chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 pressed visible heuristic "${id}"`);
|
|
3349
3542
|
return { success: true, pressedTargetId: id };
|
|
3350
3543
|
}
|
|
3351
3544
|
}
|
|
@@ -3359,7 +3552,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3359
3552
|
if (target) {
|
|
3360
3553
|
try {
|
|
3361
3554
|
target.press();
|
|
3362
|
-
|
|
3555
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3363
3556
|
`formFillHandler: submitAfterFill \u2014 pressed by label heuristic "${comp.label}"`
|
|
3364
3557
|
);
|
|
3365
3558
|
return { success: true, pressedTargetId: comp.id };
|
|
@@ -3375,7 +3568,7 @@ function pressSubmitButton(context, registry) {
|
|
|
3375
3568
|
for (const fieldId of [...context.filledFieldIds ?? []].reverse()) {
|
|
3376
3569
|
const handle = findInteractiveByIdentifier(fieldId, { kind: "field" });
|
|
3377
3570
|
if (handle?.submitFromKeyboard?.()) {
|
|
3378
|
-
|
|
3571
|
+
chunkSUMIABJK_js.appilotsDebugLog(`formFillHandler: submitAfterFill \u2014 return key on "${fieldId}"`);
|
|
3379
3572
|
return { success: true, pressedTargetId: fieldId };
|
|
3380
3573
|
}
|
|
3381
3574
|
}
|
|
@@ -3421,12 +3614,12 @@ function buildDiagnose(category, targetId, candidates) {
|
|
|
3421
3614
|
return {
|
|
3422
3615
|
category,
|
|
3423
3616
|
targetId,
|
|
3424
|
-
screen:
|
|
3617
|
+
screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
|
|
3425
3618
|
...candidates && candidates.length > 0 ? { candidates: candidates.slice(0, 8) } : {}
|
|
3426
3619
|
};
|
|
3427
3620
|
}
|
|
3428
3621
|
function resolveListEntry(listId) {
|
|
3429
|
-
const entries =
|
|
3622
|
+
const entries = chunkSUMIABJK_js.listRegistry.snapshot();
|
|
3430
3623
|
if (entries.length === 0) return {};
|
|
3431
3624
|
if (listId) {
|
|
3432
3625
|
const wanted = normalizeId2(listId);
|
|
@@ -3535,6 +3728,59 @@ async function confirmHandler(_actionId, _payload) {
|
|
|
3535
3728
|
return { success: true, effect: "unknown" };
|
|
3536
3729
|
}
|
|
3537
3730
|
|
|
3731
|
+
// src/platform/asyncBudget.ts
|
|
3732
|
+
var POST_ACTION_LOADING_MAX_MS = 6e3;
|
|
3733
|
+
var INFERRED_ASYNC_LOADING_MAX_MS = 1e4;
|
|
3734
|
+
var POST_NAVIGATE_LOADING_MAX_MS = 3e3;
|
|
3735
|
+
var MAX_DECLARED_ASYNC_BUDGET_MS = 12e4;
|
|
3736
|
+
var ASYNC_BUSY_CEILING_MS = MAX_DECLARED_ASYNC_BUDGET_MS;
|
|
3737
|
+
function declaredBudgetMs(hints) {
|
|
3738
|
+
const declared = hints?.asyncBudgetMs;
|
|
3739
|
+
if (typeof declared !== "number" || !Number.isFinite(declared) || declared <= 0) return void 0;
|
|
3740
|
+
return Math.min(declared, MAX_DECLARED_ASYNC_BUDGET_MS);
|
|
3741
|
+
}
|
|
3742
|
+
function resolveSettleCapMs(hints) {
|
|
3743
|
+
const declared = declaredBudgetMs(hints);
|
|
3744
|
+
if (declared !== void 0) return declared;
|
|
3745
|
+
return hints?.isAsyncTrigger === true ? INFERRED_ASYNC_LOADING_MAX_MS : POST_ACTION_LOADING_MAX_MS;
|
|
3746
|
+
}
|
|
3747
|
+
function resolveBusyCeilingMs(hints) {
|
|
3748
|
+
return declaredBudgetMs(hints) === void 0 ? ASYNC_BUSY_CEILING_MS : void 0;
|
|
3749
|
+
}
|
|
3750
|
+
function resolvePostNavigateCapMs(hints) {
|
|
3751
|
+
return Math.max(POST_NAVIGATE_LOADING_MAX_MS, declaredBudgetMs(hints) ?? 0);
|
|
3752
|
+
}
|
|
3753
|
+
function resolveActionHints(screen, pressedComponentId, actionPayload) {
|
|
3754
|
+
if (actionPayload && typeof actionPayload === "object") {
|
|
3755
|
+
const payload = actionPayload;
|
|
3756
|
+
const inline = payload._appilotsInferred;
|
|
3757
|
+
const declared = payload._appilotsAsyncBudgetMs;
|
|
3758
|
+
if (inline && typeof inline === "object") {
|
|
3759
|
+
const hints = { ...inline };
|
|
3760
|
+
if (typeof declared === "number") hints.asyncBudgetMs = declared;
|
|
3761
|
+
return hints;
|
|
3762
|
+
}
|
|
3763
|
+
if (typeof declared === "number") return { asyncBudgetMs: declared };
|
|
3764
|
+
}
|
|
3765
|
+
if (!screen || !pressedComponentId) return void 0;
|
|
3766
|
+
const meta = chunkSUMIABJK_js.getScreenMetadata(screen);
|
|
3767
|
+
const actions = meta?.actions;
|
|
3768
|
+
if (!actions || actions.length === 0) return void 0;
|
|
3769
|
+
for (const a of actions) {
|
|
3770
|
+
if (typeof a === "string") continue;
|
|
3771
|
+
if (chunkSUMIABJK_js.idLooselyMatches(a.id, pressedComponentId)) {
|
|
3772
|
+
const inferred = a.appilotsInferred;
|
|
3773
|
+
const declared = a.asyncBudgetMs;
|
|
3774
|
+
const hints = {
|
|
3775
|
+
...inferred && typeof inferred === "object" ? inferred : {},
|
|
3776
|
+
...typeof declared === "number" ? { asyncBudgetMs: declared } : {}
|
|
3777
|
+
};
|
|
3778
|
+
return Object.keys(hints).length > 0 ? hints : void 0;
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
return void 0;
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3538
3784
|
// src/executor/postInteractionSettle.ts
|
|
3539
3785
|
var sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3540
3786
|
function targetIdFromPayload(payload) {
|
|
@@ -3555,9 +3801,9 @@ function hashFieldValue(value) {
|
|
|
3555
3801
|
var DISCRETE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "date"]);
|
|
3556
3802
|
function discreteFieldSignature() {
|
|
3557
3803
|
const sigs = [];
|
|
3558
|
-
for (const { id, kind } of
|
|
3804
|
+
for (const { id, kind } of chunkSUMIABJK_js.componentRegistry.snapshot()) {
|
|
3559
3805
|
if (kind !== "field") continue;
|
|
3560
|
-
const entry =
|
|
3806
|
+
const entry = chunkSUMIABJK_js.componentRegistry.getField(id);
|
|
3561
3807
|
if (!entry || !DISCRETE_FIELD_TYPES.has(entry.fieldType ?? "")) continue;
|
|
3562
3808
|
try {
|
|
3563
3809
|
sigs.push(`${id}:${hashFieldValue(String(entry.getValue() ?? ""))}`);
|
|
@@ -3568,32 +3814,33 @@ function discreteFieldSignature() {
|
|
|
3568
3814
|
}
|
|
3569
3815
|
async function waitForPostInteractionSettle(payload) {
|
|
3570
3816
|
const targetId = targetIdFromPayload(payload);
|
|
3571
|
-
const fromScreen =
|
|
3572
|
-
const baseline =
|
|
3817
|
+
const fromScreen = chunkSUMIABJK_js.getCurrentScreen();
|
|
3818
|
+
const baseline = chunkSUMIABJK_js.probeLoadingState(targetId || null, fromScreen);
|
|
3573
3819
|
const baselineFields = discreteFieldSignature();
|
|
3574
3820
|
const readable = baseline.fingerprint !== "";
|
|
3575
3821
|
await sleepMs(100);
|
|
3576
|
-
const afterPress =
|
|
3822
|
+
const afterPress = chunkSUMIABJK_js.probeLoadingState(targetId || null, chunkSUMIABJK_js.getCurrentScreen());
|
|
3577
3823
|
const modalOrLoading = afterPress.modalOpen || afterPress.loading || afterPress.pressedDisabled;
|
|
3578
3824
|
const fingerprintChanged = afterPress.fingerprint !== baseline.fingerprint;
|
|
3579
3825
|
const verdict = () => {
|
|
3580
3826
|
if (!readable) return { effect: "unknown" };
|
|
3581
|
-
const settled =
|
|
3827
|
+
const settled = chunkSUMIABJK_js.probeLoadingState(targetId || null, chunkSUMIABJK_js.getCurrentScreen());
|
|
3582
3828
|
if (settled.fingerprint === "") return { effect: "unknown" };
|
|
3583
3829
|
if (discreteFieldSignature() !== baselineFields) return { effect: "changed" };
|
|
3584
3830
|
return { effect: settled.fingerprint !== baseline.fingerprint ? "changed" : "none" };
|
|
3585
3831
|
};
|
|
3586
|
-
const
|
|
3832
|
+
const declared = declaredBudgetMs(resolveActionHints(fromScreen, targetId || null, payload));
|
|
3833
|
+
const capMs = declared ?? (chunkSUMIABJK_js.isListItemPressTarget(targetId) ? 5e3 : 1e4);
|
|
3587
3834
|
if (modalOrLoading || fingerprintChanged) {
|
|
3588
|
-
await
|
|
3835
|
+
await chunkSUMIABJK_js.waitForLoadingSettle({
|
|
3589
3836
|
pressedComponentId: targetId || null,
|
|
3590
3837
|
fromScreen,
|
|
3591
3838
|
maxMs: capMs
|
|
3592
3839
|
});
|
|
3593
3840
|
return verdict();
|
|
3594
3841
|
}
|
|
3595
|
-
if (
|
|
3596
|
-
await
|
|
3842
|
+
if (chunkSUMIABJK_js.isListItemPressTarget(targetId)) {
|
|
3843
|
+
await chunkSUMIABJK_js.waitForLoadingSettle({
|
|
3597
3844
|
fromScreen,
|
|
3598
3845
|
maxMs: 3e3
|
|
3599
3846
|
});
|
|
@@ -3614,7 +3861,7 @@ function validateActionPayload(action) {
|
|
|
3614
3861
|
error: message,
|
|
3615
3862
|
diagnose: {
|
|
3616
3863
|
category: "validation",
|
|
3617
|
-
screen:
|
|
3864
|
+
screen: chunkSUMIABJK_js.getCurrentScreen() ?? void 0,
|
|
3618
3865
|
...ids ?? {}
|
|
3619
3866
|
}
|
|
3620
3867
|
});
|
|
@@ -3675,7 +3922,7 @@ function isDestructivePayload(payload) {
|
|
|
3675
3922
|
return !!params && typeof params === "object" && params.destructive === true;
|
|
3676
3923
|
}
|
|
3677
3924
|
async function executeAction(action, context) {
|
|
3678
|
-
|
|
3925
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3679
3926
|
`executeAction called: type="${action.type}", id="${action.id}", payload=${JSON.stringify(action.payload)}`
|
|
3680
3927
|
);
|
|
3681
3928
|
const permissions = context.permissions ?? DEFAULT_PERMISSIONS;
|
|
@@ -3704,7 +3951,7 @@ async function executeAction(action, context) {
|
|
|
3704
3951
|
let result;
|
|
3705
3952
|
const validationFailure = validateActionPayload(action);
|
|
3706
3953
|
if (validationFailure) {
|
|
3707
|
-
|
|
3954
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
3708
3955
|
`executeAction: payload validation failed for type="${action.type}" id="${action.id}": ${validationFailure.error}`
|
|
3709
3956
|
);
|
|
3710
3957
|
context.emit({
|
|
@@ -3731,14 +3978,14 @@ async function executeAction(action, context) {
|
|
|
3731
3978
|
case "form_fill":
|
|
3732
3979
|
result = await formFillHandler(action.payload, {
|
|
3733
3980
|
permissions,
|
|
3734
|
-
registry: context.registry ??
|
|
3981
|
+
registry: context.registry ?? chunkSUMIABJK_js.getDefaultRegistry()
|
|
3735
3982
|
});
|
|
3736
3983
|
break;
|
|
3737
3984
|
case "ui_interaction": {
|
|
3738
3985
|
const payload = action.payload;
|
|
3739
3986
|
result = uiInteractionHandler(payload, {
|
|
3740
3987
|
permissions,
|
|
3741
|
-
registry: context.registry ??
|
|
3988
|
+
registry: context.registry ?? chunkSUMIABJK_js.getDefaultRegistry()
|
|
3742
3989
|
});
|
|
3743
3990
|
if (result.success) {
|
|
3744
3991
|
const settle = await waitForPostInteractionSettle(payload);
|
|
@@ -3767,7 +4014,7 @@ async function executeAction(action, context) {
|
|
|
3767
4014
|
};
|
|
3768
4015
|
}
|
|
3769
4016
|
} catch (err) {
|
|
3770
|
-
|
|
4017
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
3771
4018
|
`executeAction: exception during action type="${action.type}" id="${action.id}": ${err?.message}`
|
|
3772
4019
|
);
|
|
3773
4020
|
result = {
|
|
@@ -3775,7 +4022,7 @@ async function executeAction(action, context) {
|
|
|
3775
4022
|
error: err?.message ?? "Action execution failed unexpectedly"
|
|
3776
4023
|
};
|
|
3777
4024
|
}
|
|
3778
|
-
|
|
4025
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3779
4026
|
`executeAction result: type="${action.type}", id="${action.id}", success=${result.success}, error=${result.error ?? "none"}`
|
|
3780
4027
|
);
|
|
3781
4028
|
context.emit({
|
|
@@ -3829,7 +4076,7 @@ var _patchedAlert = (title, message, buttons, options) => {
|
|
|
3829
4076
|
return suppression.originalAlert(title, message, buttons, options);
|
|
3830
4077
|
}
|
|
3831
4078
|
suppression.consumed = true;
|
|
3832
|
-
|
|
4079
|
+
chunkSUMIABJK_js.appilotsDebugLog("Suppressing native Alert during already-confirmed destructive agent action");
|
|
3833
4080
|
try {
|
|
3834
4081
|
suppression.pending = Promise.resolve(button.onPress()).then(() => void 0).catch((err) => reportHandlerFailure(err));
|
|
3835
4082
|
} catch (err) {
|
|
@@ -3880,37 +4127,41 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
|
|
|
3880
4127
|
}
|
|
3881
4128
|
|
|
3882
4129
|
// src/platform/reactNativeAdapter.ts
|
|
3883
|
-
var
|
|
4130
|
+
var deltaTracker = chunkSUMIABJK_js.createSnapshotDeltaTracker();
|
|
3884
4131
|
function resolveScreenMetadata() {
|
|
3885
|
-
const activePath =
|
|
4132
|
+
const activePath = chunkSUMIABJK_js.getActiveRouteNames();
|
|
3886
4133
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
3887
4134
|
const name = activePath[i];
|
|
3888
|
-
const meta = name ?
|
|
4135
|
+
const meta = name ? chunkSUMIABJK_js.getScreenMetadata(name) : void 0;
|
|
3889
4136
|
if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
|
|
3890
4137
|
return meta;
|
|
3891
4138
|
}
|
|
3892
4139
|
}
|
|
3893
|
-
const screen =
|
|
3894
|
-
return screen ?
|
|
4140
|
+
const screen = chunkSUMIABJK_js.getCurrentScreen();
|
|
4141
|
+
return screen ? chunkSUMIABJK_js.getScreenMetadata(screen) : void 0;
|
|
3895
4142
|
}
|
|
3896
4143
|
function buildAgentContext(extras = {}) {
|
|
4144
|
+
if (extras.newMission === true) deltaTracker.reset();
|
|
3897
4145
|
const context = {};
|
|
3898
4146
|
context.platform = "react-native";
|
|
3899
|
-
const screen =
|
|
4147
|
+
const screen = chunkSUMIABJK_js.getCurrentScreen();
|
|
3900
4148
|
if (screen) context.currentScreen = screen;
|
|
3901
|
-
const navigationState =
|
|
4149
|
+
const navigationState = chunkSUMIABJK_js.getNavigationStateSnapshot();
|
|
3902
4150
|
if (navigationState) context.navigationState = navigationState;
|
|
3903
4151
|
const screenMeta = resolveScreenMetadata();
|
|
3904
4152
|
if (screenMeta) context.screenMetadata = screenMeta;
|
|
3905
4153
|
try {
|
|
3906
|
-
|
|
4154
|
+
const snapshot = captureSnapshot();
|
|
4155
|
+
const delta = deltaTracker.observe(snapshot);
|
|
4156
|
+
if (delta) snapshot.delta = delta;
|
|
4157
|
+
context.snapshot = snapshot;
|
|
3907
4158
|
} catch (err) {
|
|
3908
|
-
|
|
4159
|
+
chunkSUMIABJK_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
|
|
3909
4160
|
}
|
|
3910
|
-
const registry =
|
|
4161
|
+
const registry = chunkSUMIABJK_js.componentRegistry.snapshot();
|
|
3911
4162
|
const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
|
|
3912
4163
|
if (filtered.length > 0) context.registeredComponents = filtered;
|
|
3913
|
-
const registeredLists =
|
|
4164
|
+
const registeredLists = chunkSUMIABJK_js.listRegistry.snapshot();
|
|
3914
4165
|
if (registeredLists.length > 0) {
|
|
3915
4166
|
context.registeredLists = registeredLists.map(
|
|
3916
4167
|
({ scrollToIndex, scrollToOffset, getScrollMetrics, dataPreview, ...rest }) => rest
|
|
@@ -3919,95 +4170,82 @@ function buildAgentContext(extras = {}) {
|
|
|
3919
4170
|
if (extras.loadingPending === true) context.loadingPending = true;
|
|
3920
4171
|
return context;
|
|
3921
4172
|
}
|
|
3922
|
-
function resolveActionHints(screen, pressedComponentId, actionPayload) {
|
|
3923
|
-
if (actionPayload && typeof actionPayload === "object") {
|
|
3924
|
-
const inline = actionPayload._appilotsInferred;
|
|
3925
|
-
if (inline && typeof inline === "object") {
|
|
3926
|
-
return inline;
|
|
3927
|
-
}
|
|
3928
|
-
}
|
|
3929
|
-
if (!screen || !pressedComponentId) return void 0;
|
|
3930
|
-
const meta = chunk55Y2AQE7_js.getScreenMetadata(screen);
|
|
3931
|
-
const actions = meta?.actions;
|
|
3932
|
-
if (!actions || actions.length === 0) return void 0;
|
|
3933
|
-
for (const a of actions) {
|
|
3934
|
-
if (typeof a === "string") continue;
|
|
3935
|
-
if (chunk55Y2AQE7_js.idLooselyMatches(a.id, pressedComponentId)) {
|
|
3936
|
-
const inferred = a.appilotsInferred;
|
|
3937
|
-
if (inferred && typeof inferred === "object") return inferred;
|
|
3938
|
-
return void 0;
|
|
3939
|
-
}
|
|
3940
|
-
}
|
|
3941
|
-
return void 0;
|
|
3942
|
-
}
|
|
3943
4173
|
async function settleTurn(input) {
|
|
3944
4174
|
const toolWithoutEffectIds = /* @__PURE__ */ new Set();
|
|
3945
4175
|
let loadingPending = false;
|
|
3946
4176
|
const { turnActions, pressedComponentId: pressedId, navigateTargetScreen } = input;
|
|
3947
4177
|
const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
|
|
3948
4178
|
const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
|
|
4179
|
+
const pressedAction = turnActions.find(
|
|
4180
|
+
(a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
|
|
4181
|
+
);
|
|
4182
|
+
const hints = resolveActionHints(
|
|
4183
|
+
chunkSUMIABJK_js.getCurrentScreen(),
|
|
4184
|
+
pressedId,
|
|
4185
|
+
pressedAction?.payload
|
|
4186
|
+
);
|
|
4187
|
+
const capSource = typeof hints?.asyncBudgetMs === "number" && hints.asyncBudgetMs > 0 ? " (app-declared)" : hints?.isAsyncTrigger ? " (mcp-inferred)" : "";
|
|
3949
4188
|
if (input.hadNavigate) {
|
|
3950
|
-
const settle = await
|
|
4189
|
+
const settle = await chunkSUMIABJK_js.waitForScreenSettle({
|
|
3951
4190
|
expectingChange: true,
|
|
3952
4191
|
fromScreen: input.preNavigateScreen ?? null,
|
|
3953
4192
|
fromSignature: input.preNavigateSignature ?? null,
|
|
3954
4193
|
targetScreen: navigateTargetScreen,
|
|
3955
4194
|
maxMs: 3500
|
|
3956
4195
|
});
|
|
3957
|
-
|
|
4196
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
3958
4197
|
`settleTurn: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
3959
4198
|
);
|
|
3960
|
-
const navigationMoved = settle.transitioned ||
|
|
4199
|
+
const navigationMoved = settle.transitioned || chunkSUMIABJK_js.screenDepartedBaseline(input.preNavigateScreen ?? null, input.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkSUMIABJK_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
|
|
3961
4200
|
if (!navigationMoved) {
|
|
3962
|
-
|
|
4201
|
+
chunkSUMIABJK_js.appilotsDebugWarn(
|
|
3963
4202
|
`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.`
|
|
3964
4203
|
);
|
|
3965
4204
|
for (const [actionId, type] of typeById) {
|
|
3966
4205
|
if (type === "navigate") toolWithoutEffectIds.add(actionId);
|
|
3967
4206
|
}
|
|
3968
4207
|
}
|
|
3969
|
-
const
|
|
4208
|
+
const postNavigateCapMs = resolvePostNavigateCapMs(hints);
|
|
4209
|
+
const loadSettle = await chunkSUMIABJK_js.waitForLoadingSettle({
|
|
3970
4210
|
fromScreen: settle.screen ?? null,
|
|
3971
|
-
maxMs:
|
|
4211
|
+
maxMs: postNavigateCapMs
|
|
3972
4212
|
});
|
|
3973
|
-
|
|
3974
|
-
`settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs}`
|
|
4213
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
4214
|
+
`settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${postNavigateCapMs}${capSource}`
|
|
3975
4215
|
);
|
|
3976
4216
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
3977
4217
|
} else {
|
|
3978
|
-
const
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
const hints = resolveActionHints(chunk55Y2AQE7_js.getCurrentScreen(), pressedId, pressedAction?.payload);
|
|
3982
|
-
const settleCapMs = hints?.isAsyncTrigger === true ? 1e4 : POST_ACTION_LOADING_MAX_MS;
|
|
3983
|
-
const loadSettle = await chunk55Y2AQE7_js.waitForLoadingSettle({
|
|
4218
|
+
const settleCapMs = resolveSettleCapMs(hints);
|
|
4219
|
+
const busyMaxMs = resolveBusyCeilingMs(hints);
|
|
4220
|
+
const loadSettle = await chunkSUMIABJK_js.waitForLoadingSettle({
|
|
3984
4221
|
pressedComponentId: pressedId,
|
|
3985
|
-
fromScreen:
|
|
3986
|
-
maxMs: settleCapMs
|
|
4222
|
+
fromScreen: chunkSUMIABJK_js.getCurrentScreen(),
|
|
4223
|
+
maxMs: settleCapMs,
|
|
4224
|
+
...busyMaxMs !== void 0 ? { busyMaxMs } : {}
|
|
3987
4225
|
});
|
|
3988
|
-
|
|
3989
|
-
`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}${
|
|
4226
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
4227
|
+
`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}` : ""}`
|
|
3990
4228
|
);
|
|
3991
4229
|
if (loadSettle.loadingPending) loadingPending = true;
|
|
3992
4230
|
const listPressActions = turnActions.filter((action) => {
|
|
3993
|
-
const target =
|
|
3994
|
-
return target ?
|
|
4231
|
+
const target = chunkSUMIABJK_js.actionPressTargetId(action);
|
|
4232
|
+
return target ? chunkSUMIABJK_js.isListItemPressTarget(target) : false;
|
|
3995
4233
|
});
|
|
3996
4234
|
if (listPressActions.length > 0) {
|
|
3997
|
-
const baselineFingerprint =
|
|
3998
|
-
const postPressSettle = await
|
|
4235
|
+
const baselineFingerprint = chunkSUMIABJK_js.probeLoadingState(pressedId, chunkSUMIABJK_js.getCurrentScreen()).fingerprint;
|
|
4236
|
+
const postPressSettle = await chunkSUMIABJK_js.waitForScreenSettle({
|
|
3999
4237
|
expectingChange: true,
|
|
4000
4238
|
fromScreen: input.preNavigateScreen ?? null,
|
|
4001
4239
|
fromSignature: input.preNavigateSignature ?? null,
|
|
4002
4240
|
maxMs: 2500
|
|
4003
4241
|
});
|
|
4004
|
-
await
|
|
4242
|
+
await chunkSUMIABJK_js.waitForLoadingSettle({
|
|
4005
4243
|
pressedComponentId: pressedId,
|
|
4006
|
-
fromScreen:
|
|
4244
|
+
fromScreen: chunkSUMIABJK_js.getCurrentScreen(),
|
|
4007
4245
|
maxMs: 4e3
|
|
4008
4246
|
});
|
|
4009
|
-
const afterFingerprint =
|
|
4010
|
-
|
|
4247
|
+
const afterFingerprint = chunkSUMIABJK_js.probeLoadingState(pressedId, chunkSUMIABJK_js.getCurrentScreen()).fingerprint;
|
|
4248
|
+
chunkSUMIABJK_js.appilotsDebugLog(
|
|
4011
4249
|
`settleTurn: post-list-press settle \u2014 screen="${postPressSettle.screen}" transitioned=${postPressSettle.transitioned} timedOut=${postPressSettle.timedOut} waitedMs=${postPressSettle.waitedMs}`
|
|
4012
4250
|
);
|
|
4013
4251
|
if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
|
|
@@ -4023,15 +4261,15 @@ async function settleTurn(input) {
|
|
|
4023
4261
|
}
|
|
4024
4262
|
var reactNativeChatAdapter = {
|
|
4025
4263
|
buildContext: buildAgentContext,
|
|
4026
|
-
getCurrentScreen:
|
|
4027
|
-
getCurrentScreenSignature:
|
|
4264
|
+
getCurrentScreen: chunkSUMIABJK_js.getCurrentScreen,
|
|
4265
|
+
getCurrentScreenSignature: chunkSUMIABJK_js.getCurrentScreenSignature,
|
|
4028
4266
|
settleTurn
|
|
4029
4267
|
};
|
|
4030
4268
|
function createReactNativeActionRunner(getOptions) {
|
|
4031
4269
|
return {
|
|
4032
4270
|
async execute(action, { confirmedDestructive }) {
|
|
4033
4271
|
const { permissions, emit, navigationRef, suppressNativeConfirm } = getOptions();
|
|
4034
|
-
const navRef = navigationRef?.current ? navigationRef : { current:
|
|
4272
|
+
const navRef = navigationRef?.current ? navigationRef : { current: chunkSUMIABJK_js.getNavigationRef() };
|
|
4035
4273
|
return runWithConfirmedDestructiveContext(
|
|
4036
4274
|
confirmedDestructive && suppressNativeConfirm !== false,
|
|
4037
4275
|
reactNative.Alert,
|
|
@@ -4042,21 +4280,21 @@ function createReactNativeActionRunner(getOptions) {
|
|
|
4042
4280
|
})
|
|
4043
4281
|
);
|
|
4044
4282
|
},
|
|
4045
|
-
getCurrentScreen:
|
|
4046
|
-
getCurrentScreenSignature:
|
|
4283
|
+
getCurrentScreen: chunkSUMIABJK_js.getCurrentScreen,
|
|
4284
|
+
getCurrentScreenSignature: chunkSUMIABJK_js.getCurrentScreenSignature,
|
|
4047
4285
|
getScreenActionsMetadata(screen) {
|
|
4048
|
-
return
|
|
4286
|
+
return chunkSUMIABJK_js.getScreenMetadata(screen)?.actions;
|
|
4049
4287
|
},
|
|
4050
|
-
waitForScreenSettle:
|
|
4288
|
+
waitForScreenSettle: chunkSUMIABJK_js.waitForScreenSettle
|
|
4051
4289
|
};
|
|
4052
4290
|
}
|
|
4053
4291
|
|
|
4054
4292
|
// src/hooks/useAppilotsChat.ts
|
|
4055
4293
|
function useAppilotsChat(options = {}) {
|
|
4056
|
-
const { client, emit, subscribe } =
|
|
4294
|
+
const { client, emit, subscribe } = chunkSUMIABJK_js.useAppilotsContext();
|
|
4057
4295
|
const machine = React.useMemo(
|
|
4058
|
-
() => new
|
|
4059
|
-
{ client, adapter: reactNativeChatAdapter, emit, warn:
|
|
4296
|
+
() => new chunkSUMIABJK_js.ChatSessionMachine(
|
|
4297
|
+
{ client, adapter: reactNativeChatAdapter, emit, warn: chunkSUMIABJK_js.appilotsDebugWarn },
|
|
4060
4298
|
options
|
|
4061
4299
|
),
|
|
4062
4300
|
// A new machine per client/provider instance — options are pushed in
|
|
@@ -4099,7 +4337,7 @@ var DEFAULT_PERMISSIONS2 = {
|
|
|
4099
4337
|
canSubmitForms: true
|
|
4100
4338
|
};
|
|
4101
4339
|
function useAppilotsActions(options = {}) {
|
|
4102
|
-
const { client, subscribe, config, emit } =
|
|
4340
|
+
const { client, subscribe, config, emit } = chunkSUMIABJK_js.useAppilotsContext();
|
|
4103
4341
|
const { navigationRef, autoExecute = false } = options;
|
|
4104
4342
|
const runnerOptionsRef = React.useRef({
|
|
4105
4343
|
permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
|
|
@@ -4114,12 +4352,12 @@ function useAppilotsActions(options = {}) {
|
|
|
4114
4352
|
suppressNativeConfirm: config.suppressNativeConfirm
|
|
4115
4353
|
};
|
|
4116
4354
|
const machine = React.useMemo(
|
|
4117
|
-
() => new
|
|
4355
|
+
() => new chunkSUMIABJK_js.ActionQueueMachine(
|
|
4118
4356
|
{
|
|
4119
4357
|
client,
|
|
4120
4358
|
adapter: createReactNativeActionRunner(() => runnerOptionsRef.current),
|
|
4121
4359
|
emit,
|
|
4122
|
-
warn:
|
|
4360
|
+
warn: chunkSUMIABJK_js.appilotsDebugWarn
|
|
4123
4361
|
},
|
|
4124
4362
|
{ autoExecute }
|
|
4125
4363
|
),
|
|
@@ -4176,7 +4414,7 @@ function shouldShowSuggestedPrompts(args) {
|
|
|
4176
4414
|
|
|
4177
4415
|
// src/hooks/useSuggestedPrompts.ts
|
|
4178
4416
|
function useSuggestedPrompts(options) {
|
|
4179
|
-
const { client } =
|
|
4417
|
+
const { client } = chunkSUMIABJK_js.useAppilotsContext();
|
|
4180
4418
|
const { enabled, limit = 4 } = options;
|
|
4181
4419
|
const [prompts, setPrompts] = React.useState([]);
|
|
4182
4420
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
@@ -4186,8 +4424,8 @@ function useSuggestedPrompts(options) {
|
|
|
4186
4424
|
if (!enabled) return;
|
|
4187
4425
|
const requestId = ++requestIdRef.current;
|
|
4188
4426
|
let cancelled = false;
|
|
4189
|
-
const screen =
|
|
4190
|
-
const localDev = screen ? (
|
|
4427
|
+
const screen = chunkSUMIABJK_js.getCurrentScreen() ?? void 0;
|
|
4428
|
+
const localDev = screen ? (chunkSUMIABJK_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
|
|
4191
4429
|
text,
|
|
4192
4430
|
source: "dev-defined"
|
|
4193
4431
|
})) : [];
|
|
@@ -4201,7 +4439,7 @@ function useSuggestedPrompts(options) {
|
|
|
4201
4439
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4202
4440
|
setPrompts(mergePromptSources(localDev, data, limit));
|
|
4203
4441
|
}).catch((err) => {
|
|
4204
|
-
|
|
4442
|
+
chunkSUMIABJK_js.appilotsDebugWarn("useSuggestedPrompts: fetch failed", err);
|
|
4205
4443
|
}).finally(() => {
|
|
4206
4444
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
4207
4445
|
setIsLoading(false);
|
|
@@ -4212,9 +4450,9 @@ function useSuggestedPrompts(options) {
|
|
|
4212
4450
|
}, [client, enabled, limit, refreshTick]);
|
|
4213
4451
|
React.useEffect(() => {
|
|
4214
4452
|
if (!enabled) return;
|
|
4215
|
-
let lastScreen =
|
|
4453
|
+
let lastScreen = chunkSUMIABJK_js.getCurrentScreen();
|
|
4216
4454
|
const interval = setInterval(() => {
|
|
4217
|
-
const current =
|
|
4455
|
+
const current = chunkSUMIABJK_js.getCurrentScreen();
|
|
4218
4456
|
if (current !== lastScreen) {
|
|
4219
4457
|
lastScreen = current;
|
|
4220
4458
|
setRefreshTick((t) => t + 1);
|
|
@@ -4229,14 +4467,14 @@ function useSuggestedPrompts(options) {
|
|
|
4229
4467
|
};
|
|
4230
4468
|
}
|
|
4231
4469
|
function useAppilotsNavigation() {
|
|
4232
|
-
const { emit } =
|
|
4470
|
+
const { emit } = chunkSUMIABJK_js.useAppilotsContext();
|
|
4233
4471
|
const [currentScreen, setCurrentScreenState] = React.useState(null);
|
|
4234
4472
|
const [navigationHistory, setNavigationHistory] = React.useState([]);
|
|
4235
4473
|
const navigationRef = React.useRef(null);
|
|
4236
4474
|
const setCurrentScreen2 = React.useCallback(
|
|
4237
4475
|
(screenName) => {
|
|
4238
4476
|
setCurrentScreenState(screenName);
|
|
4239
|
-
|
|
4477
|
+
chunkSUMIABJK_js.setCurrentScreen(screenName);
|
|
4240
4478
|
setNavigationHistory((prev) => [...prev, screenName]);
|
|
4241
4479
|
emit({
|
|
4242
4480
|
type: "navigation:change",
|
|
@@ -4267,7 +4505,7 @@ function useAppilotsNavigation() {
|
|
|
4267
4505
|
|
|
4268
4506
|
// src/hooks/useAppilots.ts
|
|
4269
4507
|
function useAppilots() {
|
|
4270
|
-
const { config, client } =
|
|
4508
|
+
const { config, client } = chunkSUMIABJK_js.useAppilotsContext();
|
|
4271
4509
|
const chat = useAppilotsChat();
|
|
4272
4510
|
const navigation = useAppilotsNavigation();
|
|
4273
4511
|
const actions = useAppilotsActions();
|
|
@@ -4296,7 +4534,7 @@ function useAppilots() {
|
|
|
4296
4534
|
}
|
|
4297
4535
|
function useAppilotsField(id, options) {
|
|
4298
4536
|
const { value, onChangeText, ref, fieldType, label, screen } = options;
|
|
4299
|
-
const registry =
|
|
4537
|
+
const registry = chunkSUMIABJK_js.useResolvedRegistry();
|
|
4300
4538
|
const valueRef = React.useRef(value);
|
|
4301
4539
|
const onChangeRef = React.useRef(onChangeText);
|
|
4302
4540
|
valueRef.current = value;
|
|
@@ -4324,7 +4562,7 @@ function useAppilotsField(id, options) {
|
|
|
4324
4562
|
}
|
|
4325
4563
|
function useAppilotsTarget(id, options) {
|
|
4326
4564
|
const { onPress, onLongPress, onScrollTo, label, screen } = options;
|
|
4327
|
-
const registry =
|
|
4565
|
+
const registry = chunkSUMIABJK_js.useResolvedRegistry();
|
|
4328
4566
|
const onPressRef = React.useRef(onPress);
|
|
4329
4567
|
const onLongPressRef = React.useRef(onLongPress);
|
|
4330
4568
|
const onScrollToRef = React.useRef(onScrollTo);
|
|
@@ -4351,7 +4589,7 @@ function useAppilotsTarget(id, options) {
|
|
|
4351
4589
|
}
|
|
4352
4590
|
function useAppilotsToggle(id, options) {
|
|
4353
4591
|
const { value, onValueChange, label, screen } = options;
|
|
4354
|
-
const registry =
|
|
4592
|
+
const registry = chunkSUMIABJK_js.useResolvedRegistry();
|
|
4355
4593
|
const valueRef = React.useRef(value);
|
|
4356
4594
|
const onChangeRef = React.useRef(onValueChange);
|
|
4357
4595
|
valueRef.current = value;
|
|
@@ -4374,7 +4612,7 @@ function useAppilotsToggle(id, options) {
|
|
|
4374
4612
|
}
|
|
4375
4613
|
function useAppilotsSlider(id, options) {
|
|
4376
4614
|
const { value, onValueChange, min, max, step, label, screen } = options;
|
|
4377
|
-
const registry =
|
|
4615
|
+
const registry = chunkSUMIABJK_js.useResolvedRegistry();
|
|
4378
4616
|
const valueRef = React.useRef(value);
|
|
4379
4617
|
const onChangeRef = React.useRef(onValueChange);
|
|
4380
4618
|
valueRef.current = value;
|