@appilots/sdk 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-BKFO4DHW.mjs → chunk-42WI3UDB.mjs} +322 -1479
- package/dist/{chunk-N2I3CA7Q.js → chunk-CHY5D2PV.js} +5 -5
- package/dist/{chunk-DUSYQXAQ.mjs → chunk-GEKCGVJN.mjs} +1 -1
- package/dist/{chunk-QMSMXTED.mjs → chunk-JBOLV5AM.mjs} +1435 -51
- package/dist/{chunk-MCY5YFYD.js → chunk-V3TUIIT2.js} +1442 -57
- package/dist/{chunk-XNKPS7W3.js → chunk-Y7EA6R2G.js} +394 -1551
- package/dist/hooks/index.d.mts +1 -2
- package/dist/hooks/index.d.ts +1 -2
- package/dist/hooks/index.js +11 -11
- package/dist/hooks/index.mjs +2 -2
- package/dist/index-Cb0D6uKH.d.mts +1543 -0
- package/dist/index-Cb0D6uKH.d.ts +1543 -0
- package/dist/index.d.mts +5 -282
- package/dist/index.d.ts +5 -282
- package/dist/index.js +65 -65
- package/dist/index.mjs +5 -5
- package/dist/navigation/index.js +13 -13
- package/dist/navigation/index.mjs +2 -2
- package/hooks/package.json +9 -0
- package/metro.d.ts +49 -0
- package/metro.js +0 -37
- package/navigation/package.json +9 -0
- package/package.json +31 -12
- package/dist/index-BYVRBzjJ.d.mts +0 -619
- package/dist/index-BYVRBzjJ.d.ts +0 -619
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkV3TUIIT2_js = require('./chunk-V3TUIIT2.js');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var reactNative = require('react-native');
|
|
6
6
|
|
|
@@ -495,7 +495,7 @@ function walkSubtree(root, detectLists, startInModal = false) {
|
|
|
495
495
|
}
|
|
496
496
|
function walkFiber(root) {
|
|
497
497
|
const snapshot = {
|
|
498
|
-
route:
|
|
498
|
+
route: chunkV3TUIIT2_js.getCurrentScreen(),
|
|
499
499
|
texts: [],
|
|
500
500
|
inputs: [],
|
|
501
501
|
buttons: [],
|
|
@@ -656,225 +656,6 @@ function normalizeLabel(label) {
|
|
|
656
656
|
return label.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+(.)/g, (_, c) => c.toUpperCase()).replace(/\s+/g, "");
|
|
657
657
|
}
|
|
658
658
|
|
|
659
|
-
// src/introspection/interactionGraph.ts
|
|
660
|
-
function normalizePart(value) {
|
|
661
|
-
return String(value ?? "").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
662
|
-
}
|
|
663
|
-
function hashString(value) {
|
|
664
|
-
let hash = 2166136261;
|
|
665
|
-
for (let i = 0; i < value.length; i++) {
|
|
666
|
-
hash ^= value.charCodeAt(i);
|
|
667
|
-
hash = Math.imul(hash, 16777619);
|
|
668
|
-
}
|
|
669
|
-
return (hash >>> 0).toString(36);
|
|
670
|
-
}
|
|
671
|
-
function stableElementId(parts) {
|
|
672
|
-
const raw = parts.filter((p) => p !== void 0 && String(p).length > 0).join("|");
|
|
673
|
-
const readable = parts.map(normalizePart).filter(Boolean).join(":").slice(0, 120);
|
|
674
|
-
return `el:${readable}:${hashString(raw)}`;
|
|
675
|
-
}
|
|
676
|
-
function parseStableElementId(id) {
|
|
677
|
-
if (typeof id !== "string") return null;
|
|
678
|
-
const trimmed = id.trim();
|
|
679
|
-
if (!/^el:/i.test(trimmed)) return null;
|
|
680
|
-
const parts = trimmed.split(":");
|
|
681
|
-
if (parts.length < 3) return null;
|
|
682
|
-
const hash = parts[parts.length - 1];
|
|
683
|
-
const segments = parts.slice(1, -1);
|
|
684
|
-
if (segments.length === 0) return null;
|
|
685
|
-
const role = segments[0];
|
|
686
|
-
const result = { role, segments, hash };
|
|
687
|
-
if (role === "option" && segments.length >= 4) {
|
|
688
|
-
result.listId = segments[segments.length - 2];
|
|
689
|
-
result.itemKey = segments[segments.length - 1];
|
|
690
|
-
}
|
|
691
|
-
return result;
|
|
692
|
-
}
|
|
693
|
-
function uniqueTexts(texts) {
|
|
694
|
-
const seen = /* @__PURE__ */ new Set();
|
|
695
|
-
const out = [];
|
|
696
|
-
for (const text of texts) {
|
|
697
|
-
const t = typeof text === "string" ? text.trim() : "";
|
|
698
|
-
if (!t || seen.has(t)) continue;
|
|
699
|
-
seen.add(t);
|
|
700
|
-
out.push(t);
|
|
701
|
-
}
|
|
702
|
-
return out;
|
|
703
|
-
}
|
|
704
|
-
function labelForListItem(item) {
|
|
705
|
-
return uniqueTexts([
|
|
706
|
-
...item.texts ?? [],
|
|
707
|
-
...(item.buttons ?? []).map((button) => button.label ?? button.id)
|
|
708
|
-
]).slice(0, 2).join(" \xB7 ") || void 0;
|
|
709
|
-
}
|
|
710
|
-
function listItemElement(route, list, item) {
|
|
711
|
-
const texts = uniqueTexts([
|
|
712
|
-
...item.texts ?? [],
|
|
713
|
-
...(item.buttons ?? []).map((button) => button.label ?? button.id)
|
|
714
|
-
]);
|
|
715
|
-
const label = labelForListItem(item);
|
|
716
|
-
const key = item.itemKey ?? item.reactKey ?? label ?? item.syntheticId;
|
|
717
|
-
const id = stableElementId([
|
|
718
|
-
"option",
|
|
719
|
-
route ?? "unknown",
|
|
720
|
-
list.id ?? list.label ?? `list-${list.index}`,
|
|
721
|
-
key
|
|
722
|
-
]);
|
|
723
|
-
const inModal = (item.buttons ?? []).some((button) => button.inModal) || (item.inputs ?? []).some((input) => input.inModal) || (item.toggles ?? []).some((toggle) => toggle.inModal);
|
|
724
|
-
return {
|
|
725
|
-
id,
|
|
726
|
-
role: "option",
|
|
727
|
-
label,
|
|
728
|
-
texts,
|
|
729
|
-
actions: ["press"],
|
|
730
|
-
disabled: false,
|
|
731
|
-
source: "list",
|
|
732
|
-
targetId: item.syntheticId,
|
|
733
|
-
...inModal ? { inModal: true } : {},
|
|
734
|
-
listContext: {
|
|
735
|
-
listIndex: list.index,
|
|
736
|
-
listId: list.id,
|
|
737
|
-
listLabel: list.label,
|
|
738
|
-
itemIndex: item.index,
|
|
739
|
-
itemKey: item.itemKey,
|
|
740
|
-
reactKey: item.reactKey,
|
|
741
|
-
syntheticId: item.syntheticId
|
|
742
|
-
}
|
|
743
|
-
};
|
|
744
|
-
}
|
|
745
|
-
function buttonElement(route, button, index) {
|
|
746
|
-
const label = button.label ?? button.id;
|
|
747
|
-
const id = stableElementId([
|
|
748
|
-
"button",
|
|
749
|
-
route ?? "unknown",
|
|
750
|
-
button.id ?? label ?? `button-${index}`
|
|
751
|
-
]);
|
|
752
|
-
return {
|
|
753
|
-
id,
|
|
754
|
-
role: "button",
|
|
755
|
-
label,
|
|
756
|
-
texts: uniqueTexts([label]),
|
|
757
|
-
actions: ["press"],
|
|
758
|
-
disabled: button.disabled,
|
|
759
|
-
selected: button.selected,
|
|
760
|
-
source: "button",
|
|
761
|
-
targetId: button.id ?? button.label,
|
|
762
|
-
...button.inModal ? { inModal: true } : {}
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
function inputElement(route, input, index) {
|
|
766
|
-
const label = input.label ?? input.placeholder ?? input.id;
|
|
767
|
-
const id = stableElementId([
|
|
768
|
-
"input",
|
|
769
|
-
route ?? "unknown",
|
|
770
|
-
input.id ?? label ?? `input-${index}`
|
|
771
|
-
]);
|
|
772
|
-
return {
|
|
773
|
-
id,
|
|
774
|
-
role: "input",
|
|
775
|
-
label,
|
|
776
|
-
texts: uniqueTexts([label, input.placeholder]),
|
|
777
|
-
actions: ["focus", "setValue"],
|
|
778
|
-
disabled: input.editable === false,
|
|
779
|
-
source: "input",
|
|
780
|
-
targetId: input.id ?? input.label ?? input.placeholder,
|
|
781
|
-
...input.inModal ? { inModal: true } : {}
|
|
782
|
-
};
|
|
783
|
-
}
|
|
784
|
-
function toggleElement(route, toggle, index) {
|
|
785
|
-
const label = toggle.label ?? toggle.id;
|
|
786
|
-
const id = stableElementId([
|
|
787
|
-
"toggle",
|
|
788
|
-
route ?? "unknown",
|
|
789
|
-
toggle.id ?? label ?? `toggle-${index}`
|
|
790
|
-
]);
|
|
791
|
-
return {
|
|
792
|
-
id,
|
|
793
|
-
role: "toggle",
|
|
794
|
-
label,
|
|
795
|
-
texts: uniqueTexts([label]),
|
|
796
|
-
actions: ["toggle", "press"],
|
|
797
|
-
selected: toggle.value,
|
|
798
|
-
source: "toggle",
|
|
799
|
-
targetId: toggle.id ?? toggle.label,
|
|
800
|
-
...toggle.inModal ? { inModal: true } : {}
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
function sliderElement(route, slider, index) {
|
|
804
|
-
const label = slider.label ?? slider.id;
|
|
805
|
-
const id = stableElementId([
|
|
806
|
-
"slider",
|
|
807
|
-
route ?? "unknown",
|
|
808
|
-
slider.id ?? label ?? `slider-${index}`
|
|
809
|
-
]);
|
|
810
|
-
return {
|
|
811
|
-
id,
|
|
812
|
-
role: "slider",
|
|
813
|
-
label,
|
|
814
|
-
texts: uniqueTexts([label]),
|
|
815
|
-
actions: ["setValue"],
|
|
816
|
-
disabled: slider.disabled,
|
|
817
|
-
source: "slider",
|
|
818
|
-
targetId: slider.id ?? slider.label,
|
|
819
|
-
...slider.inModal ? { inModal: true } : {}
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
function deriveInteractionElements(snapshot) {
|
|
823
|
-
const elements = [];
|
|
824
|
-
const seen = /* @__PURE__ */ new Set();
|
|
825
|
-
const push = (element) => {
|
|
826
|
-
if (!element.id || seen.has(element.id)) return;
|
|
827
|
-
seen.add(element.id);
|
|
828
|
-
elements.push(element);
|
|
829
|
-
};
|
|
830
|
-
for (const list of snapshot.lists ?? []) {
|
|
831
|
-
for (const item of list.items ?? []) {
|
|
832
|
-
push(listItemElement(snapshot.route, list, item));
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
for (const [index, button] of (snapshot.buttons ?? []).entries()) {
|
|
836
|
-
push(buttonElement(snapshot.route, button, index));
|
|
837
|
-
}
|
|
838
|
-
for (const [index, input] of (snapshot.inputs ?? []).entries()) {
|
|
839
|
-
push(inputElement(snapshot.route, input, index));
|
|
840
|
-
}
|
|
841
|
-
for (const [index, toggle] of (snapshot.toggles ?? []).entries()) {
|
|
842
|
-
push(toggleElement(snapshot.route, toggle, index));
|
|
843
|
-
}
|
|
844
|
-
for (const [index, slider] of (snapshot.sliders ?? []).entries()) {
|
|
845
|
-
push(sliderElement(snapshot.route, slider, index));
|
|
846
|
-
}
|
|
847
|
-
return elements;
|
|
848
|
-
}
|
|
849
|
-
function findElementForChoice(elements, option) {
|
|
850
|
-
if (option.targetId) {
|
|
851
|
-
const byTarget = elements.find((element) => element.targetId === option.targetId);
|
|
852
|
-
if (byTarget) return byTarget;
|
|
853
|
-
}
|
|
854
|
-
const optionLabel = normalizePart(option.label ?? option.texts?.join(" "));
|
|
855
|
-
if (!optionLabel) return void 0;
|
|
856
|
-
return elements.find((element) => {
|
|
857
|
-
if (element.role !== "option" && element.role !== "button") return false;
|
|
858
|
-
const label = normalizePart(element.label ?? element.texts.join(" "));
|
|
859
|
-
return label === optionLabel || label.includes(optionLabel) || optionLabel.includes(label);
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
function attachElementIdsToChoiceGroups(choiceGroups, elements) {
|
|
863
|
-
return choiceGroups.map((group) => ({
|
|
864
|
-
...group,
|
|
865
|
-
options: group.options.map((option) => {
|
|
866
|
-
const element = findElementForChoice(elements, option);
|
|
867
|
-
if (!element) return option;
|
|
868
|
-
const handle = element.listContext?.syntheticId ?? element.id;
|
|
869
|
-
return {
|
|
870
|
-
...option,
|
|
871
|
-
syntheticId: handle,
|
|
872
|
-
targetId: handle
|
|
873
|
-
};
|
|
874
|
-
})
|
|
875
|
-
}));
|
|
876
|
-
}
|
|
877
|
-
|
|
878
659
|
// src/introspection/captureSnapshot.ts
|
|
879
660
|
function normalizeSliderKey(value) {
|
|
880
661
|
return (value ?? "").toLowerCase().replace(/^slider[-_]/, "");
|
|
@@ -890,9 +671,9 @@ function fiberSliderMatches(fiber, registryId, registryLabel) {
|
|
|
890
671
|
function reconcileSliders(snapshot) {
|
|
891
672
|
const fiberSliders = snapshot.sliders;
|
|
892
673
|
const out = [];
|
|
893
|
-
for (const { id, kind } of
|
|
674
|
+
for (const { id, kind } of chunkV3TUIIT2_js.componentRegistry.snapshot()) {
|
|
894
675
|
if (kind !== "slider") continue;
|
|
895
|
-
const entry =
|
|
676
|
+
const entry = chunkV3TUIIT2_js.componentRegistry.getSlider(id);
|
|
896
677
|
if (!entry) continue;
|
|
897
678
|
const fiber = fiberSliders.find((s) => fiberSliderMatches(s, id, entry.label));
|
|
898
679
|
const visible = !!fiber || typeof entry.screen === "string" && entry.screen === snapshot.route;
|
|
@@ -916,7 +697,7 @@ function reconcileSliders(snapshot) {
|
|
|
916
697
|
snapshot.sliders = out;
|
|
917
698
|
}
|
|
918
699
|
function mergeRegisteredLists(snapshot) {
|
|
919
|
-
const registered =
|
|
700
|
+
const registered = chunkV3TUIIT2_js.listRegistry.snapshot();
|
|
920
701
|
if (registered.length === 0) return;
|
|
921
702
|
const byId = /* @__PURE__ */ new Map();
|
|
922
703
|
for (const list of snapshot.lists) {
|
|
@@ -964,13 +745,13 @@ function mergeRegisteredLists(snapshot) {
|
|
|
964
745
|
}
|
|
965
746
|
}
|
|
966
747
|
function captureSnapshot() {
|
|
967
|
-
const root =
|
|
748
|
+
const root = chunkV3TUIIT2_js.getFiberRoot();
|
|
968
749
|
if (!root) {
|
|
969
750
|
console.warn(
|
|
970
751
|
"[Appilots] captureSnapshot: fiber root not captured yet. Ensure <AppilotsProvider> has rendered before calling this."
|
|
971
752
|
);
|
|
972
753
|
return {
|
|
973
|
-
route:
|
|
754
|
+
route: chunkV3TUIIT2_js.getCurrentScreen(),
|
|
974
755
|
texts: [],
|
|
975
756
|
inputs: [],
|
|
976
757
|
buttons: [],
|
|
@@ -985,17 +766,17 @@ function captureSnapshot() {
|
|
|
985
766
|
}
|
|
986
767
|
const start = Date.now();
|
|
987
768
|
const snapshot = walkFiber(root);
|
|
988
|
-
const activePath =
|
|
769
|
+
const activePath = chunkV3TUIIT2_js.getActiveRouteNames();
|
|
989
770
|
const deepestRoute = activePath[activePath.length - 1];
|
|
990
771
|
if (deepestRoute) snapshot.route = deepestRoute;
|
|
991
772
|
mergeRegisteredLists(snapshot);
|
|
992
773
|
reconcileSliders(snapshot);
|
|
993
|
-
snapshot.elements = deriveInteractionElements(snapshot);
|
|
994
|
-
snapshot.choiceGroups = attachElementIdsToChoiceGroups(
|
|
774
|
+
snapshot.elements = chunkV3TUIIT2_js.deriveInteractionElements(snapshot);
|
|
775
|
+
snapshot.choiceGroups = chunkV3TUIIT2_js.attachElementIdsToChoiceGroups(
|
|
995
776
|
snapshot.choiceGroups,
|
|
996
777
|
snapshot.elements
|
|
997
778
|
);
|
|
998
|
-
|
|
779
|
+
chunkV3TUIIT2_js.elementRegistry.replaceAll(snapshot.elements);
|
|
999
780
|
const elapsed = Date.now() - start;
|
|
1000
781
|
const totalListItems = snapshot.lists.reduce(
|
|
1001
782
|
(acc, l) => acc + l.items.length,
|
|
@@ -1188,7 +969,7 @@ function wrapTouchable(fiber, label) {
|
|
|
1188
969
|
};
|
|
1189
970
|
}
|
|
1190
971
|
function findInteractiveByIdentifier(query, options = {}) {
|
|
1191
|
-
const root =
|
|
972
|
+
const root = chunkV3TUIIT2_js.getFiberRoot();
|
|
1192
973
|
if (!root) {
|
|
1193
974
|
console.warn("[Appilots] findInteractiveByIdentifier: fiber root not captured yet");
|
|
1194
975
|
return null;
|
|
@@ -1234,820 +1015,6 @@ function findInteractiveByIdentifier(query, options = {}) {
|
|
|
1234
1015
|
return bestHandle;
|
|
1235
1016
|
}
|
|
1236
1017
|
|
|
1237
|
-
// src/hooks/visibleMessages.ts
|
|
1238
|
-
var INTERNAL_MARKER_RE = /^\[(?:Permission policy notice|Recovery exhausted|User rejected the proposed action)[^\]]*\]:\s*/i;
|
|
1239
|
-
var TECHNICAL_TRACE_RE = /(^|\n)\s*(?:Results:|[-*]\s*[✓✗]\s+|(?:press|click|tap|navigate|form_fill|ui_interaction|scroll_list)\b|(?:Cliquei|Clicked)\s+em\s+(?:el:|list-\d+-item-\d+|[A-Za-z]+:))/i;
|
|
1240
|
-
var TECHNICAL_SELECTOR_RE = /\b(?:el:[^\s]+|list-\d+-item-\d+|[A-Za-z][\w-]*:(?!\/\/)[^\s]+|(?:testID|test-id|accessibilityId|accessibility-id)[:=_-][^\s]+)/i;
|
|
1241
|
-
function sanitizeVisibleAssistantContent(content) {
|
|
1242
|
-
return content.split("\n").map((line) => line.replace(INTERNAL_MARKER_RE, "").trimEnd()).filter((line) => !INTERNAL_MARKER_RE.test(line)).join("\n").trim();
|
|
1243
|
-
}
|
|
1244
|
-
function humanizeAssistantFallback(content) {
|
|
1245
|
-
let text = sanitizeVisibleAssistantContent(content).replace(/\blist-\d+-item-\d+\b/gi, "o item da lista").replace(/\bel:[^\s".]+/gi, "o elemento").replace(
|
|
1246
|
-
/"\s*(?:press|click|tap|navigate|form_fill|ui_interaction|scroll_list)\s+on\s+[^"]+"/gi,
|
|
1247
|
-
'"a a\xE7\xE3o solicitada"'
|
|
1248
|
-
).replace(/\bsubscription-cancel-[^\s"]+/gi, "cancelamento de assinatura").trim();
|
|
1249
|
-
if (text.length < 16) return null;
|
|
1250
|
-
const probe = {
|
|
1251
|
-
role: "assistant",
|
|
1252
|
-
content: text};
|
|
1253
|
-
if (isInternalTraceMessage(probe)) return null;
|
|
1254
|
-
return text;
|
|
1255
|
-
}
|
|
1256
|
-
function isInternalTraceMessage(message) {
|
|
1257
|
-
if (message.role !== "assistant") return false;
|
|
1258
|
-
const content = message.content.trim();
|
|
1259
|
-
if (!content) return true;
|
|
1260
|
-
return TECHNICAL_TRACE_RE.test(content) || TECHNICAL_SELECTOR_RE.test(content);
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
// src/executor/formWriteEffect.ts
|
|
1264
|
-
var CREATE_FORM_ROUTE_RE = /vehiclecreate|subscriptioncreate|vehicleedit|subscriptionedit|maintenancecreate|create|cadastr|register|novo|edit/i;
|
|
1265
|
-
var SUBMIT_BUTTON_RE = /cadastrar|registrar|salvar|submit|register|guardar|enviar|confirmar|save/i;
|
|
1266
|
-
var FORM_VALIDATION_TEXT_RE = /(inv[aá]lid|obrigat[oó]ri|required|invalid|j[aá]\s+existe|already\s+exists|duplicad|formato|format|too\s+short|muito\s+curto|n[aã]o\s+(?:foi|pode)|must\s+be|deve\s+ser|selecione|escolha|select\s+(?:the|a|o|an))/i;
|
|
1267
|
-
function normalize3(value) {
|
|
1268
|
-
return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
|
|
1269
|
-
}
|
|
1270
|
-
function routeHintsCreateForm(routeNames) {
|
|
1271
|
-
return routeNames.some((name) => CREATE_FORM_ROUTE_RE.test(normalize3(name)));
|
|
1272
|
-
}
|
|
1273
|
-
function snapshotHasSubmitControl(snap) {
|
|
1274
|
-
return (snap.buttons ?? []).some(
|
|
1275
|
-
(btn) => SUBMIT_BUTTON_RE.test(normalize3(`${btn.label ?? btn.id ?? ""}`))
|
|
1276
|
-
);
|
|
1277
|
-
}
|
|
1278
|
-
function snapshotHasVisibleSubmitButton(snap) {
|
|
1279
|
-
return (snap.buttons ?? []).some(
|
|
1280
|
-
(btn) => !btn.disabled && SUBMIT_BUTTON_RE.test(normalize3(`${btn.label ?? btn.id ?? ""}`))
|
|
1281
|
-
);
|
|
1282
|
-
}
|
|
1283
|
-
function snapshotHasVisibleValidation(snap) {
|
|
1284
|
-
return (snap.texts ?? []).some((text) => typeof text === "string" && FORM_VALIDATION_TEXT_RE.test(text));
|
|
1285
|
-
}
|
|
1286
|
-
function snapshotShowsOpenCreateForm(snap, activePath = []) {
|
|
1287
|
-
if (!snap) return false;
|
|
1288
|
-
const routeNames = [
|
|
1289
|
-
...typeof snap.route === "string" && snap.route ? [snap.route] : [],
|
|
1290
|
-
...activePath
|
|
1291
|
-
];
|
|
1292
|
-
const hasFormInputs = (snap.inputs?.length ?? 0) > 0;
|
|
1293
|
-
const hasValidation = snapshotHasVisibleValidation(snap);
|
|
1294
|
-
const hasFormContext = routeHintsCreateForm(routeNames) || hasFormInputs || hasValidation;
|
|
1295
|
-
if (!hasFormContext) return false;
|
|
1296
|
-
if (snap.loading === true) return true;
|
|
1297
|
-
if (snapshotHasVisibleSubmitButton(snap)) return true;
|
|
1298
|
-
if (snapshotHasSubmitControl(snap) && hasFormInputs) return true;
|
|
1299
|
-
if (hasValidation) return true;
|
|
1300
|
-
return false;
|
|
1301
|
-
}
|
|
1302
|
-
function formFillLackedWriteEffect(action, snap, activePath = []) {
|
|
1303
|
-
if (action.type !== "form_fill") return false;
|
|
1304
|
-
if (!snapshotShowsOpenCreateForm(snap, activePath)) return false;
|
|
1305
|
-
const payload = action.payload;
|
|
1306
|
-
if (payload?.submitAfterFill === true) return true;
|
|
1307
|
-
return Array.isArray(payload?.fields) && payload.fields.length > 0;
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
// src/hooks/useAppilotsChat.ts
|
|
1311
|
-
var ESCALATION_RECONNECT_MAX_MS = 3e4;
|
|
1312
|
-
function resolveScreenMetadata() {
|
|
1313
|
-
const activePath = chunkMCY5YFYD_js.getActiveRouteNames();
|
|
1314
|
-
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
1315
|
-
const name = activePath[i];
|
|
1316
|
-
const meta = name ? chunkMCY5YFYD_js.getScreenMetadata(name) : void 0;
|
|
1317
|
-
if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
|
|
1318
|
-
return meta;
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
const screen = chunkMCY5YFYD_js.getCurrentScreen();
|
|
1322
|
-
return screen ? chunkMCY5YFYD_js.getScreenMetadata(screen) : void 0;
|
|
1323
|
-
}
|
|
1324
|
-
function buildAgentContext(extras = {}) {
|
|
1325
|
-
const context = {};
|
|
1326
|
-
context.platform = "react-native";
|
|
1327
|
-
const screen = chunkMCY5YFYD_js.getCurrentScreen();
|
|
1328
|
-
if (screen) context.currentScreen = screen;
|
|
1329
|
-
const navigationState = chunkMCY5YFYD_js.getNavigationStateSnapshot();
|
|
1330
|
-
if (navigationState) context.navigationState = navigationState;
|
|
1331
|
-
const screenMeta = resolveScreenMetadata();
|
|
1332
|
-
if (screenMeta) context.screenMetadata = screenMeta;
|
|
1333
|
-
try {
|
|
1334
|
-
context.snapshot = captureSnapshot();
|
|
1335
|
-
} catch (err) {
|
|
1336
|
-
chunkMCY5YFYD_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
|
|
1337
|
-
}
|
|
1338
|
-
const registry = chunkMCY5YFYD_js.componentRegistry.snapshot();
|
|
1339
|
-
const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
|
|
1340
|
-
if (filtered.length > 0) context.registeredComponents = filtered;
|
|
1341
|
-
const registeredLists = chunkMCY5YFYD_js.listRegistry.snapshot();
|
|
1342
|
-
if (registeredLists.length > 0) {
|
|
1343
|
-
context.registeredLists = registeredLists.map(
|
|
1344
|
-
({ scrollToIndex, scrollToOffset, getScrollMetrics, dataPreview, ...rest }) => rest
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
if (extras.loadingPending === true) context.loadingPending = true;
|
|
1348
|
-
return context;
|
|
1349
|
-
}
|
|
1350
|
-
function extractPressedComponentId(actions) {
|
|
1351
|
-
for (let i = actions.length - 1; i >= 0; i--) {
|
|
1352
|
-
const a = actions[i];
|
|
1353
|
-
if (!a || a.type !== "ui_interaction") continue;
|
|
1354
|
-
const p = a.payload;
|
|
1355
|
-
const interaction = p?.action ?? "press";
|
|
1356
|
-
if (interaction !== "press" && interaction !== "longPress") continue;
|
|
1357
|
-
const id = p?.componentId;
|
|
1358
|
-
if (typeof id === "string" && id.length > 0) return id;
|
|
1359
|
-
}
|
|
1360
|
-
return null;
|
|
1361
|
-
}
|
|
1362
|
-
function extractNavigateTargetScreen(actions) {
|
|
1363
|
-
for (let i = actions.length - 1; i >= 0; i--) {
|
|
1364
|
-
const a = actions[i];
|
|
1365
|
-
if (!a || a.type !== "navigate") continue;
|
|
1366
|
-
const screenName = a.payload?.screenName;
|
|
1367
|
-
if (typeof screenName === "string" && screenName.length > 0) return screenName;
|
|
1368
|
-
}
|
|
1369
|
-
return null;
|
|
1370
|
-
}
|
|
1371
|
-
function idLooselyMatches(candidate, target) {
|
|
1372
|
-
if (!candidate || !target) return false;
|
|
1373
|
-
if (candidate === target) return true;
|
|
1374
|
-
const c = candidate.toLowerCase();
|
|
1375
|
-
const t = target.toLowerCase();
|
|
1376
|
-
if (c === t) return true;
|
|
1377
|
-
return c.endsWith(`-${t}`) || c.endsWith(`_${t}`) || t.endsWith(`-${c}`) || t.endsWith(`_${c}`);
|
|
1378
|
-
}
|
|
1379
|
-
function resolveActionHints(screen, pressedComponentId, actionPayload) {
|
|
1380
|
-
if (actionPayload && typeof actionPayload === "object") {
|
|
1381
|
-
const inline = actionPayload._appilotsInferred;
|
|
1382
|
-
if (inline && typeof inline === "object") {
|
|
1383
|
-
return inline;
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
if (!screen || !pressedComponentId) return void 0;
|
|
1387
|
-
const meta = chunkMCY5YFYD_js.getScreenMetadata(screen);
|
|
1388
|
-
const actions = meta?.actions;
|
|
1389
|
-
if (!actions || actions.length === 0) return void 0;
|
|
1390
|
-
for (const a of actions) {
|
|
1391
|
-
if (typeof a === "string") continue;
|
|
1392
|
-
if (idLooselyMatches(a.id, pressedComponentId)) {
|
|
1393
|
-
const inferred = a.appilotsInferred;
|
|
1394
|
-
if (inferred && typeof inferred === "object") return inferred;
|
|
1395
|
-
return void 0;
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
return void 0;
|
|
1399
|
-
}
|
|
1400
|
-
function summarizeAction(action) {
|
|
1401
|
-
const p = action.payload;
|
|
1402
|
-
switch (action.type) {
|
|
1403
|
-
case "navigate":
|
|
1404
|
-
return `navigate to ${p?.screenName ?? "?"}`;
|
|
1405
|
-
case "form_fill": {
|
|
1406
|
-
const fields = p?.fields ?? [];
|
|
1407
|
-
if (fields.length === 0) return "form_fill (no fields)";
|
|
1408
|
-
const parts = fields.slice(0, 3).map((f) => `${f.fieldId}=${JSON.stringify(f.value)}`);
|
|
1409
|
-
const extra = fields.length > 3 ? ` +${fields.length - 3} more` : "";
|
|
1410
|
-
return `form_fill ${parts.join(", ")}${extra}`;
|
|
1411
|
-
}
|
|
1412
|
-
case "ui_interaction":
|
|
1413
|
-
return `${p?.action ?? "press"} on ${p?.componentId ?? "?"}`;
|
|
1414
|
-
case "scroll_list": {
|
|
1415
|
-
const target = typeof p?.toIndex === "number" ? `to item #${p.toIndex}` : p?.direction ?? "down";
|
|
1416
|
-
return `scroll_list ${p?.listId ? `"${p.listId}" ` : ""}${target}`;
|
|
1417
|
-
}
|
|
1418
|
-
case "confirm":
|
|
1419
|
-
return `confirm: ${p?.message ?? p?.title ?? ""}`;
|
|
1420
|
-
default:
|
|
1421
|
-
return action.type;
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
var MAX_RECOVERY_ATTEMPTS_PER_ACTION = 2;
|
|
1425
|
-
var POST_ACTION_LOADING_MAX_MS = 6e3;
|
|
1426
|
-
function useAppilotsChat(options = {}) {
|
|
1427
|
-
const { client, emit, subscribe } = chunkMCY5YFYD_js.useAppilotsContext();
|
|
1428
|
-
const errorPrefix = options.errorPrefix ?? "Algo deu errado";
|
|
1429
|
-
const streamingEnabled = options.streaming !== false;
|
|
1430
|
-
const abortRef = react.useRef(null);
|
|
1431
|
-
const [messages, setMessages] = react.useState([]);
|
|
1432
|
-
const [pendingActions, setPendingActions] = react.useState([]);
|
|
1433
|
-
const [isLoading, setIsLoading] = react.useState(false);
|
|
1434
|
-
const [loadingStatusKey, setLoadingStatusKey] = react.useState("thinking");
|
|
1435
|
-
const [error, setError] = react.useState(null);
|
|
1436
|
-
const messageIdCounter = react.useRef(0);
|
|
1437
|
-
const [escalation, setEscalation] = react.useState(null);
|
|
1438
|
-
const escalationRef = react.useRef(null);
|
|
1439
|
-
escalationRef.current = escalation;
|
|
1440
|
-
const [escalationStreamEpoch, setEscalationStreamEpoch] = react.useState(0);
|
|
1441
|
-
const escalationReconnectAttemptRef = react.useRef(0);
|
|
1442
|
-
const escalationReconnectTimerRef = react.useRef(null);
|
|
1443
|
-
const escalationSinceRef = react.useRef(void 0);
|
|
1444
|
-
const seenHumanMessageIdsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
1445
|
-
const escalationStrings = options.escalationStrings;
|
|
1446
|
-
const currentTurnRef = react.useRef(null);
|
|
1447
|
-
const continuationInFlightRef = react.useRef(false);
|
|
1448
|
-
const recoveryCountByFingerprintRef = react.useRef(/* @__PURE__ */ new Map());
|
|
1449
|
-
const pendingActionsRef = react.useRef([]);
|
|
1450
|
-
pendingActionsRef.current = pendingActions;
|
|
1451
|
-
const messagesRef = react.useRef([]);
|
|
1452
|
-
messagesRef.current = messages;
|
|
1453
|
-
const addAssistantMessage = react.useCallback((message) => {
|
|
1454
|
-
const visibleContent = message.role === "assistant" ? sanitizeVisibleAssistantContent(message.content) : message.content;
|
|
1455
|
-
const candidate = { ...message, content: visibleContent };
|
|
1456
|
-
if (isInternalTraceMessage(candidate)) {
|
|
1457
|
-
chunkMCY5YFYD_js.recordAppilotsDebugTrace({
|
|
1458
|
-
type: "agent:trace",
|
|
1459
|
-
timestamp: Date.now(),
|
|
1460
|
-
messageId: candidate.id,
|
|
1461
|
-
summary: "Suppressed internal assistant trace from visible chat",
|
|
1462
|
-
data: { role: candidate.role, content: message.content }
|
|
1463
|
-
});
|
|
1464
|
-
const fallback = humanizeAssistantFallback(message.content);
|
|
1465
|
-
if (fallback) {
|
|
1466
|
-
setMessages((prev) => [...prev, { ...candidate, content: fallback }]);
|
|
1467
|
-
}
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
setMessages((prev) => [...prev, candidate]);
|
|
1471
|
-
}, []);
|
|
1472
|
-
const appendLocalSystemMessage = react.useCallback(
|
|
1473
|
-
(content, metadata) => {
|
|
1474
|
-
if (!content) return;
|
|
1475
|
-
setMessages((prev) => [
|
|
1476
|
-
...prev,
|
|
1477
|
-
{
|
|
1478
|
-
id: `system_${++messageIdCounter.current}`,
|
|
1479
|
-
role: "system",
|
|
1480
|
-
content,
|
|
1481
|
-
timestamp: Date.now(),
|
|
1482
|
-
...metadata ? { metadata } : {}
|
|
1483
|
-
}
|
|
1484
|
-
]);
|
|
1485
|
-
},
|
|
1486
|
-
[]
|
|
1487
|
-
);
|
|
1488
|
-
const requestHuman = react.useCallback(
|
|
1489
|
-
async (reason = "user_requested") => {
|
|
1490
|
-
if (escalationRef.current) return;
|
|
1491
|
-
try {
|
|
1492
|
-
const lastError = messagesRef.current.slice().reverse().find((m) => m.role === "assistant" && m.id.startsWith("error_"));
|
|
1493
|
-
const result = await client.requestEscalation(reason, lastError?.content);
|
|
1494
|
-
setEscalation({ id: result.escalationId, status: result.status });
|
|
1495
|
-
escalationReconnectAttemptRef.current = 0;
|
|
1496
|
-
appendLocalSystemMessage(escalationStrings?.requested ?? "");
|
|
1497
|
-
emit({
|
|
1498
|
-
type: "chat:escalation:start",
|
|
1499
|
-
timestamp: Date.now(),
|
|
1500
|
-
data: { escalationId: result.escalationId, reason }
|
|
1501
|
-
});
|
|
1502
|
-
} catch (err) {
|
|
1503
|
-
setError(err instanceof Error ? err.message : "Failed to request a human");
|
|
1504
|
-
}
|
|
1505
|
-
},
|
|
1506
|
-
[client, emit, appendLocalSystemMessage, escalationStrings]
|
|
1507
|
-
);
|
|
1508
|
-
react.useEffect(() => {
|
|
1509
|
-
if (!escalation?.id) return;
|
|
1510
|
-
const escalationId = escalation.id;
|
|
1511
|
-
const close = client.openEscalationStream(escalationId, {
|
|
1512
|
-
since: escalationSinceRef.current,
|
|
1513
|
-
onHumanMessage: (message) => {
|
|
1514
|
-
escalationReconnectAttemptRef.current = 0;
|
|
1515
|
-
if (seenHumanMessageIdsRef.current.has(message.id)) return;
|
|
1516
|
-
seenHumanMessageIdsRef.current.add(message.id);
|
|
1517
|
-
escalationSinceRef.current = message.createdAt;
|
|
1518
|
-
setMessages((prev) => [
|
|
1519
|
-
...prev,
|
|
1520
|
-
{
|
|
1521
|
-
id: message.id,
|
|
1522
|
-
role: "human_agent",
|
|
1523
|
-
content: message.content,
|
|
1524
|
-
timestamp: Date.now()
|
|
1525
|
-
}
|
|
1526
|
-
]);
|
|
1527
|
-
emit({
|
|
1528
|
-
type: "chat:escalation:message",
|
|
1529
|
-
timestamp: Date.now(),
|
|
1530
|
-
data: { escalationId, messageId: message.id }
|
|
1531
|
-
});
|
|
1532
|
-
},
|
|
1533
|
-
onStatus: (status, operatorName) => {
|
|
1534
|
-
escalationReconnectAttemptRef.current = 0;
|
|
1535
|
-
if (status === "active") {
|
|
1536
|
-
setEscalation((prev) => {
|
|
1537
|
-
if (!prev || prev.id !== escalationId) return prev;
|
|
1538
|
-
if (prev.status === "active") return prev;
|
|
1539
|
-
appendLocalSystemMessage(escalationStrings?.connected ?? "");
|
|
1540
|
-
return { ...prev, status: "active", operatorName };
|
|
1541
|
-
});
|
|
1542
|
-
} else if (status === "resolved") {
|
|
1543
|
-
appendLocalSystemMessage(escalationStrings?.resolved ?? "");
|
|
1544
|
-
setEscalation(null);
|
|
1545
|
-
emit({
|
|
1546
|
-
type: "chat:escalation:end",
|
|
1547
|
-
timestamp: Date.now(),
|
|
1548
|
-
data: { escalationId }
|
|
1549
|
-
});
|
|
1550
|
-
}
|
|
1551
|
-
},
|
|
1552
|
-
onClose: () => {
|
|
1553
|
-
if (!escalationRef.current || escalationRef.current.id !== escalationId) return;
|
|
1554
|
-
const attempt = ++escalationReconnectAttemptRef.current;
|
|
1555
|
-
const delay = Math.min(
|
|
1556
|
-
ESCALATION_RECONNECT_MAX_MS,
|
|
1557
|
-
1e3 * 2 ** Math.min(attempt, 5)
|
|
1558
|
-
);
|
|
1559
|
-
escalationReconnectTimerRef.current = setTimeout(() => {
|
|
1560
|
-
setEscalationStreamEpoch((n) => n + 1);
|
|
1561
|
-
}, delay);
|
|
1562
|
-
}
|
|
1563
|
-
});
|
|
1564
|
-
return () => {
|
|
1565
|
-
if (escalationReconnectTimerRef.current) {
|
|
1566
|
-
clearTimeout(escalationReconnectTimerRef.current);
|
|
1567
|
-
escalationReconnectTimerRef.current = null;
|
|
1568
|
-
}
|
|
1569
|
-
close();
|
|
1570
|
-
};
|
|
1571
|
-
}, [client, emit, appendLocalSystemMessage, escalationStrings, escalation?.id, escalationStreamEpoch]);
|
|
1572
|
-
const sendEscalationMessage = react.useCallback(
|
|
1573
|
-
async (content) => {
|
|
1574
|
-
const current = escalationRef.current;
|
|
1575
|
-
if (!current) return;
|
|
1576
|
-
const userMessage = {
|
|
1577
|
-
id: `local_${++messageIdCounter.current}`,
|
|
1578
|
-
role: "user",
|
|
1579
|
-
content,
|
|
1580
|
-
timestamp: Date.now()
|
|
1581
|
-
};
|
|
1582
|
-
setMessages((prev) => [...prev, userMessage]);
|
|
1583
|
-
try {
|
|
1584
|
-
await client.sendEscalationMessage(current.id, content);
|
|
1585
|
-
} catch (err) {
|
|
1586
|
-
setError(err instanceof Error ? err.message : "Failed to send message");
|
|
1587
|
-
}
|
|
1588
|
-
},
|
|
1589
|
-
[client]
|
|
1590
|
-
);
|
|
1591
|
-
const beginTurn = react.useCallback(
|
|
1592
|
-
(assistantMessageId, actions, hop) => {
|
|
1593
|
-
if (!actions || actions.length === 0) {
|
|
1594
|
-
currentTurnRef.current = null;
|
|
1595
|
-
return;
|
|
1596
|
-
}
|
|
1597
|
-
const stamped = actions.map((a) => ({ ...a, messageId: assistantMessageId }));
|
|
1598
|
-
setPendingActions((prev) => [...prev, ...stamped]);
|
|
1599
|
-
const turn = {
|
|
1600
|
-
messageId: assistantMessageId,
|
|
1601
|
-
actionIds: new Set(stamped.map((a) => a.id)),
|
|
1602
|
-
results: /* @__PURE__ */ new Map(),
|
|
1603
|
-
reportedIds: /* @__PURE__ */ new Set(),
|
|
1604
|
-
hop,
|
|
1605
|
-
hadNavigate: stamped.some((a) => a.type === "navigate"),
|
|
1606
|
-
// Snapshot the current screen NOW, before any navigate
|
|
1607
|
-
// dispatches. waitForScreenSettle will use this as the
|
|
1608
|
-
// baseline to detect that the navigate completed.
|
|
1609
|
-
preNavigateScreen: chunkMCY5YFYD_js.getCurrentScreen(),
|
|
1610
|
-
// Full route+params signature — lets settle detect navigate
|
|
1611
|
-
// to the same route name with different params.
|
|
1612
|
-
preNavigateSignature: chunkMCY5YFYD_js.getCurrentScreenSignature()
|
|
1613
|
-
};
|
|
1614
|
-
const originScreen = chunkMCY5YFYD_js.getCurrentScreen() ?? void 0;
|
|
1615
|
-
for (const a of stamped) {
|
|
1616
|
-
turn.results.set(a.id, {
|
|
1617
|
-
type: a.type,
|
|
1618
|
-
success: false,
|
|
1619
|
-
summary: summarizeAction(a),
|
|
1620
|
-
fingerprint: chunkMCY5YFYD_js.fingerprintAction(a, originScreen)
|
|
1621
|
-
});
|
|
1622
|
-
}
|
|
1623
|
-
currentTurnRef.current = turn;
|
|
1624
|
-
for (const action of stamped) {
|
|
1625
|
-
emit({
|
|
1626
|
-
type: "agent:action:start",
|
|
1627
|
-
timestamp: Date.now(),
|
|
1628
|
-
data: { action }
|
|
1629
|
-
});
|
|
1630
|
-
}
|
|
1631
|
-
if (chunkMCY5YFYD_js.turnHasConfirmActions(stamped)) {
|
|
1632
|
-
setIsLoading(false);
|
|
1633
|
-
setLoadingStatusKey("thinking");
|
|
1634
|
-
}
|
|
1635
|
-
},
|
|
1636
|
-
[emit]
|
|
1637
|
-
);
|
|
1638
|
-
const registerSynthesizedTurnAction = react.useCallback((action) => {
|
|
1639
|
-
const turn = currentTurnRef.current;
|
|
1640
|
-
if (!turn || turn.actionIds.has(action.id)) return;
|
|
1641
|
-
const stamped = { ...action, messageId: turn.messageId };
|
|
1642
|
-
turn.actionIds.add(stamped.id);
|
|
1643
|
-
turn.results.set(stamped.id, {
|
|
1644
|
-
type: stamped.type,
|
|
1645
|
-
success: false,
|
|
1646
|
-
summary: summarizeAction(stamped),
|
|
1647
|
-
fingerprint: chunkMCY5YFYD_js.fingerprintAction(stamped, chunkMCY5YFYD_js.getCurrentScreen() ?? void 0)
|
|
1648
|
-
});
|
|
1649
|
-
setPendingActions((prev) => {
|
|
1650
|
-
if (prev.some((candidate) => candidate.id === stamped.id)) return prev;
|
|
1651
|
-
return [...prev, stamped];
|
|
1652
|
-
});
|
|
1653
|
-
if (stamped.type === "confirm") {
|
|
1654
|
-
setIsLoading(false);
|
|
1655
|
-
setLoadingStatusKey("thinking");
|
|
1656
|
-
}
|
|
1657
|
-
}, []);
|
|
1658
|
-
const runContinuation = react.useCallback(
|
|
1659
|
-
async (turn) => {
|
|
1660
|
-
if (continuationInFlightRef.current) return;
|
|
1661
|
-
continuationInFlightRef.current = true;
|
|
1662
|
-
try {
|
|
1663
|
-
setIsLoading(true);
|
|
1664
|
-
setLoadingStatusKey("statusWaitingApp");
|
|
1665
|
-
const toolWithoutEffectIds = /* @__PURE__ */ new Set();
|
|
1666
|
-
let loadingPending = false;
|
|
1667
|
-
const turnActions = pendingActionsRef.current.filter(
|
|
1668
|
-
(a) => turn.actionIds.has(a.id)
|
|
1669
|
-
);
|
|
1670
|
-
const pressedId = extractPressedComponentId(turnActions);
|
|
1671
|
-
const navigateTargetScreen = extractNavigateTargetScreen(turnActions);
|
|
1672
|
-
if (turn.hadNavigate) {
|
|
1673
|
-
const settle = await chunkMCY5YFYD_js.waitForScreenSettle({
|
|
1674
|
-
expectingChange: true,
|
|
1675
|
-
fromScreen: turn.preNavigateScreen ?? null,
|
|
1676
|
-
fromSignature: turn.preNavigateSignature ?? null,
|
|
1677
|
-
targetScreen: navigateTargetScreen,
|
|
1678
|
-
maxMs: 3500
|
|
1679
|
-
});
|
|
1680
|
-
console.log(
|
|
1681
|
-
`[Appilots] runContinuation: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
1682
|
-
);
|
|
1683
|
-
const navigationMoved = settle.transitioned || chunkMCY5YFYD_js.screenDepartedBaseline(turn.preNavigateScreen ?? null, turn.preNavigateSignature ?? null) || !!navigateTargetScreen && !!settle.screen && chunkMCY5YFYD_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
|
|
1684
|
-
if (!navigationMoved) {
|
|
1685
|
-
chunkMCY5YFYD_js.appilotsDebugWarn(
|
|
1686
|
-
`tool-without-effect: navigate emitted but screen did not change (stayed at "${turn.preNavigateScreen ?? "unknown"}", waitedMs=${settle.waitedMs}). Likely causes: target screenName missing from MCP doc, nested-nav path absent, or React Navigation rejected the route.`
|
|
1687
|
-
);
|
|
1688
|
-
for (const actionId of turn.actionIds) {
|
|
1689
|
-
const r = turn.results.get(actionId);
|
|
1690
|
-
if (r && r.type === "navigate") {
|
|
1691
|
-
toolWithoutEffectIds.add(actionId);
|
|
1692
|
-
}
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
const loadSettle = await chunkMCY5YFYD_js.waitForLoadingSettle({
|
|
1696
|
-
fromScreen: settle.screen ?? null,
|
|
1697
|
-
maxMs: 3e3
|
|
1698
|
-
});
|
|
1699
|
-
console.log(
|
|
1700
|
-
`[Appilots] runContinuation: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs}`
|
|
1701
|
-
);
|
|
1702
|
-
if (loadSettle.loadingPending) loadingPending = true;
|
|
1703
|
-
} else {
|
|
1704
|
-
const pressedAction = turnActions.find(
|
|
1705
|
-
(a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
|
|
1706
|
-
);
|
|
1707
|
-
const hints = resolveActionHints(
|
|
1708
|
-
chunkMCY5YFYD_js.getCurrentScreen(),
|
|
1709
|
-
pressedId,
|
|
1710
|
-
pressedAction?.payload
|
|
1711
|
-
);
|
|
1712
|
-
const settleCapMs = hints?.isAsyncTrigger === true ? 1e4 : POST_ACTION_LOADING_MAX_MS;
|
|
1713
|
-
const loadSettle = await chunkMCY5YFYD_js.waitForLoadingSettle({
|
|
1714
|
-
pressedComponentId: pressedId,
|
|
1715
|
-
fromScreen: chunkMCY5YFYD_js.getCurrentScreen(),
|
|
1716
|
-
maxMs: settleCapMs
|
|
1717
|
-
});
|
|
1718
|
-
console.log(
|
|
1719
|
-
`[Appilots] runContinuation: post-action loading settle \u2014 pressedId="${pressedId ?? ""}" settled=${loadSettle.settled} transitioned=${loadSettle.transitioned} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${settleCapMs}${hints?.isAsyncTrigger ? " (mcp-inferred)" : ""}`
|
|
1720
|
-
);
|
|
1721
|
-
if (loadSettle.loadingPending) loadingPending = true;
|
|
1722
|
-
const listPressActions = turnActions.filter((action) => {
|
|
1723
|
-
const target = chunkMCY5YFYD_js.actionPressTargetId(action);
|
|
1724
|
-
return target ? chunkMCY5YFYD_js.isListItemPressTarget(target) : false;
|
|
1725
|
-
});
|
|
1726
|
-
if (listPressActions.length > 0) {
|
|
1727
|
-
const baselineFingerprint = chunkMCY5YFYD_js.probeLoadingState(
|
|
1728
|
-
pressedId,
|
|
1729
|
-
chunkMCY5YFYD_js.getCurrentScreen()
|
|
1730
|
-
).fingerprint;
|
|
1731
|
-
const postPressSettle = await chunkMCY5YFYD_js.waitForScreenSettle({
|
|
1732
|
-
expectingChange: true,
|
|
1733
|
-
fromScreen: turn.preNavigateScreen ?? null,
|
|
1734
|
-
fromSignature: turn.preNavigateSignature ?? null,
|
|
1735
|
-
maxMs: 2500
|
|
1736
|
-
});
|
|
1737
|
-
await chunkMCY5YFYD_js.waitForLoadingSettle({
|
|
1738
|
-
pressedComponentId: pressedId,
|
|
1739
|
-
fromScreen: chunkMCY5YFYD_js.getCurrentScreen(),
|
|
1740
|
-
maxMs: 4e3
|
|
1741
|
-
});
|
|
1742
|
-
const afterFingerprint = chunkMCY5YFYD_js.probeLoadingState(
|
|
1743
|
-
pressedId,
|
|
1744
|
-
chunkMCY5YFYD_js.getCurrentScreen()
|
|
1745
|
-
).fingerprint;
|
|
1746
|
-
console.log(
|
|
1747
|
-
`[Appilots] runContinuation: post-list-press settle \u2014 screen="${postPressSettle.screen}" transitioned=${postPressSettle.transitioned} timedOut=${postPressSettle.timedOut} waitedMs=${postPressSettle.waitedMs}`
|
|
1748
|
-
);
|
|
1749
|
-
if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
|
|
1750
|
-
for (const action of listPressActions) {
|
|
1751
|
-
const result = turn.results.get(action.id);
|
|
1752
|
-
if (result?.success) {
|
|
1753
|
-
toolWithoutEffectIds.add(action.id);
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
const context = buildAgentContext({ loadingPending });
|
|
1760
|
-
const snap = context.snapshot;
|
|
1761
|
-
const activePath = context.navigationState?.activePath ?? [];
|
|
1762
|
-
for (const action of turnActions) {
|
|
1763
|
-
const result = turn.results.get(action.id);
|
|
1764
|
-
if (result?.success && formFillLackedWriteEffect(action, snap, activePath)) {
|
|
1765
|
-
toolWithoutEffectIds.add(action.id);
|
|
1766
|
-
chunkMCY5YFYD_js.appilotsDebugWarn(
|
|
1767
|
-
`tool-without-effect: form_fill succeeded but create form is still open (actionId="${action.id}")`
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
const results = Array.from(turn.actionIds).map((actionId) => {
|
|
1772
|
-
const r = turn.results.get(actionId);
|
|
1773
|
-
if (!r) {
|
|
1774
|
-
return {
|
|
1775
|
-
actionId,
|
|
1776
|
-
type: "unknown",
|
|
1777
|
-
success: false,
|
|
1778
|
-
error: "no result reported",
|
|
1779
|
-
summary: actionId,
|
|
1780
|
-
diagnose: void 0,
|
|
1781
|
-
recoveryAttempt: 0,
|
|
1782
|
-
recoveryExhausted: false,
|
|
1783
|
-
toolWithoutEffect: false,
|
|
1784
|
-
effect: "unknown"
|
|
1785
|
-
};
|
|
1786
|
-
}
|
|
1787
|
-
const hasToolWithoutEffect = toolWithoutEffectIds.has(actionId);
|
|
1788
|
-
let recoveryAttempt = 0;
|
|
1789
|
-
let recoveryExhausted = false;
|
|
1790
|
-
if (!r.success || hasToolWithoutEffect) {
|
|
1791
|
-
const counts = recoveryCountByFingerprintRef.current;
|
|
1792
|
-
const previous = counts.get(r.fingerprint) ?? 0;
|
|
1793
|
-
const next = previous + 1;
|
|
1794
|
-
counts.set(r.fingerprint, next);
|
|
1795
|
-
recoveryAttempt = next;
|
|
1796
|
-
recoveryExhausted = next >= MAX_RECOVERY_ATTEMPTS_PER_ACTION;
|
|
1797
|
-
}
|
|
1798
|
-
return {
|
|
1799
|
-
actionId,
|
|
1800
|
-
type: r.type,
|
|
1801
|
-
success: r.success,
|
|
1802
|
-
error: r.error,
|
|
1803
|
-
summary: r.summary,
|
|
1804
|
-
diagnose: r.diagnose,
|
|
1805
|
-
recoveryAttempt,
|
|
1806
|
-
recoveryExhausted,
|
|
1807
|
-
toolWithoutEffect: hasToolWithoutEffect,
|
|
1808
|
-
effect: hasToolWithoutEffect ? "none" : r.effect,
|
|
1809
|
-
userVisibleStatusKey: r.userVisibleStatusKey
|
|
1810
|
-
};
|
|
1811
|
-
});
|
|
1812
|
-
const exhausted = results.filter((r) => r.recoveryExhausted);
|
|
1813
|
-
setLoadingStatusKey(
|
|
1814
|
-
results.some((r) => !r.success || r.toolWithoutEffect) ? "statusAdjusting" : "statusAnalyzing"
|
|
1815
|
-
);
|
|
1816
|
-
console.log(
|
|
1817
|
-
`[Appilots] useAppilotsChat: running continuation hop=${turn.hop} (${results.filter((r) => r.success).length}/${results.length} succeeded` + (exhausted.length > 0 ? `, ${exhausted.length} recovery-exhausted` : "") + ")"
|
|
1818
|
-
);
|
|
1819
|
-
const response = await client.continueAgent(results, context, turn.hop);
|
|
1820
|
-
addAssistantMessage(response.message);
|
|
1821
|
-
emit({
|
|
1822
|
-
type: "agent:message",
|
|
1823
|
-
timestamp: Date.now(),
|
|
1824
|
-
data: { message: response.message, usage: response.usage }
|
|
1825
|
-
});
|
|
1826
|
-
if (response.isDone || !response.actions || response.actions.length === 0) {
|
|
1827
|
-
currentTurnRef.current = null;
|
|
1828
|
-
setIsLoading(false);
|
|
1829
|
-
setLoadingStatusKey("thinking");
|
|
1830
|
-
return;
|
|
1831
|
-
}
|
|
1832
|
-
beginTurn(response.message.id, response.actions, response.hop);
|
|
1833
|
-
} catch (err) {
|
|
1834
|
-
const raw = err instanceof Error ? err.message : "Continuation failed";
|
|
1835
|
-
chunkMCY5YFYD_js.appilotsDebugWarn("useAppilotsChat: continuation failed \u2014", raw);
|
|
1836
|
-
const recentUserTexts = messagesRef.current.filter((m) => m.role === "user").slice(-4).map((m) => m.content);
|
|
1837
|
-
const friendly = chunkMCY5YFYD_js.buildContinuationFailureMessage(raw, recentUserTexts);
|
|
1838
|
-
addAssistantMessage({
|
|
1839
|
-
id: `error_${++messageIdCounter.current}`,
|
|
1840
|
-
role: "assistant",
|
|
1841
|
-
content: friendly,
|
|
1842
|
-
timestamp: Date.now()
|
|
1843
|
-
});
|
|
1844
|
-
if (!escalationRef.current && escalationStrings?.offer) {
|
|
1845
|
-
appendLocalSystemMessage(escalationStrings.offer, { escalationOffer: true });
|
|
1846
|
-
}
|
|
1847
|
-
if (turn) {
|
|
1848
|
-
setPendingActions(
|
|
1849
|
-
(prev) => prev.map(
|
|
1850
|
-
(a) => turn.actionIds.has(a.id) && (a.status === "pending" || a.status === "executing") ? { ...a, status: "failed", error: friendly } : a
|
|
1851
|
-
)
|
|
1852
|
-
);
|
|
1853
|
-
for (const actionId of turn.actionIds) {
|
|
1854
|
-
if (turn.reportedIds.has(actionId)) continue;
|
|
1855
|
-
emit({
|
|
1856
|
-
type: "agent:action:error",
|
|
1857
|
-
timestamp: Date.now(),
|
|
1858
|
-
data: { actionId, error: friendly, abandoned: true }
|
|
1859
|
-
});
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
currentTurnRef.current = null;
|
|
1863
|
-
setIsLoading(false);
|
|
1864
|
-
setLoadingStatusKey("thinking");
|
|
1865
|
-
} finally {
|
|
1866
|
-
continuationInFlightRef.current = false;
|
|
1867
|
-
}
|
|
1868
|
-
},
|
|
1869
|
-
[client, emit, addAssistantMessage, beginTurn]
|
|
1870
|
-
);
|
|
1871
|
-
react.useEffect(() => {
|
|
1872
|
-
return subscribe((event) => {
|
|
1873
|
-
if (event.type === "agent:action:start") {
|
|
1874
|
-
const action = event.data?.action;
|
|
1875
|
-
if (!action?.id || action.type !== "confirm") return;
|
|
1876
|
-
const injectedBy = action.payload?.injectedBy;
|
|
1877
|
-
if (injectedBy !== "sdk-local") return;
|
|
1878
|
-
registerSynthesizedTurnAction(action);
|
|
1879
|
-
return;
|
|
1880
|
-
}
|
|
1881
|
-
if (event.type !== "agent:action:complete" && event.type !== "agent:action:error") return;
|
|
1882
|
-
const turn = currentTurnRef.current;
|
|
1883
|
-
if (!turn) return;
|
|
1884
|
-
const actionId = event.data?.actionId;
|
|
1885
|
-
if (!actionId || !turn.actionIds.has(actionId)) return;
|
|
1886
|
-
if (turn.reportedIds.has(actionId)) return;
|
|
1887
|
-
const success = event.type === "agent:action:complete";
|
|
1888
|
-
const errorMsg = event.data?.error || void 0;
|
|
1889
|
-
const diagnose = event.data?.diagnose;
|
|
1890
|
-
const effect = event.data?.effect;
|
|
1891
|
-
const userVisibleStatusKey = event.data?.userVisibleStatusKey;
|
|
1892
|
-
const existing = turn.results.get(actionId);
|
|
1893
|
-
if (existing) {
|
|
1894
|
-
existing.success = success;
|
|
1895
|
-
existing.error = errorMsg;
|
|
1896
|
-
existing.diagnose = diagnose;
|
|
1897
|
-
existing.effect = effect;
|
|
1898
|
-
existing.userVisibleStatusKey = userVisibleStatusKey;
|
|
1899
|
-
}
|
|
1900
|
-
turn.reportedIds.add(actionId);
|
|
1901
|
-
if (turn.reportedIds.size >= turn.actionIds.size) {
|
|
1902
|
-
void runContinuation(turn);
|
|
1903
|
-
}
|
|
1904
|
-
});
|
|
1905
|
-
}, [subscribe, runContinuation, registerSynthesizedTurnAction]);
|
|
1906
|
-
const sendMessage = react.useCallback(
|
|
1907
|
-
async (content) => {
|
|
1908
|
-
if (!content.trim() || isLoading) return;
|
|
1909
|
-
if (escalationRef.current) {
|
|
1910
|
-
await sendEscalationMessage(content.trim());
|
|
1911
|
-
return;
|
|
1912
|
-
}
|
|
1913
|
-
setError(null);
|
|
1914
|
-
setIsLoading(true);
|
|
1915
|
-
setLoadingStatusKey("statusAnalyzing");
|
|
1916
|
-
currentTurnRef.current = null;
|
|
1917
|
-
recoveryCountByFingerprintRef.current = /* @__PURE__ */ new Map();
|
|
1918
|
-
const userMessage = {
|
|
1919
|
-
id: `local_${++messageIdCounter.current}`,
|
|
1920
|
-
role: "user",
|
|
1921
|
-
content: content.trim(),
|
|
1922
|
-
timestamp: Date.now()
|
|
1923
|
-
};
|
|
1924
|
-
setMessages((prev) => [...prev, userMessage]);
|
|
1925
|
-
const streamingId = `streaming_${++messageIdCounter.current}`;
|
|
1926
|
-
let streamedVisible = false;
|
|
1927
|
-
const removeStreamingPlaceholder = () => {
|
|
1928
|
-
if (!streamedVisible) return;
|
|
1929
|
-
streamedVisible = false;
|
|
1930
|
-
setMessages((prev) => prev.filter((m) => m.id !== streamingId));
|
|
1931
|
-
};
|
|
1932
|
-
const abortController = new AbortController();
|
|
1933
|
-
abortRef.current = abortController;
|
|
1934
|
-
try {
|
|
1935
|
-
const context = buildAgentContext();
|
|
1936
|
-
console.log(
|
|
1937
|
-
`[Appilots] useAppilotsChat sendMessage: context \u2014 currentScreen="${context.currentScreen ?? "unknown"}", snapshot={texts:${context.snapshot?.texts?.length ?? 0}, inputs:${context.snapshot?.inputs?.length ?? 0}, buttons:${context.snapshot?.buttons?.length ?? 0}, elements:${context.snapshot?.elements?.length ?? 0}, lists:${context.snapshot?.lists?.length ?? 0}, listItems:${(context.snapshot?.lists ?? []).reduce((acc, l) => acc + (l.items?.length ?? 0), 0)}, choiceGroups:${context.snapshot?.choiceGroups?.length ?? 0}}`
|
|
1938
|
-
);
|
|
1939
|
-
let response;
|
|
1940
|
-
if (streamingEnabled) {
|
|
1941
|
-
try {
|
|
1942
|
-
response = await client.sendMessageStream(content.trim(), context, {
|
|
1943
|
-
signal: abortController.signal,
|
|
1944
|
-
onTextDelta: (_chunk, fullText) => {
|
|
1945
|
-
const visible = sanitizeVisibleAssistantContent(fullText);
|
|
1946
|
-
if (!streamedVisible) {
|
|
1947
|
-
streamedVisible = true;
|
|
1948
|
-
setMessages((prev) => [
|
|
1949
|
-
...prev,
|
|
1950
|
-
{ id: streamingId, role: "assistant", content: visible, timestamp: Date.now() }
|
|
1951
|
-
]);
|
|
1952
|
-
} else {
|
|
1953
|
-
setMessages(
|
|
1954
|
-
(prev) => prev.map((m) => m.id === streamingId ? { ...m, content: visible } : m)
|
|
1955
|
-
);
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
});
|
|
1959
|
-
} catch (err) {
|
|
1960
|
-
if (err instanceof chunkMCY5YFYD_js.StreamTransportError) {
|
|
1961
|
-
console.warn(`[Appilots] streaming unavailable, falling back to JSON: ${err.message}`);
|
|
1962
|
-
response = await client.sendMessage(content.trim(), context);
|
|
1963
|
-
} else {
|
|
1964
|
-
throw err;
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
|
-
} else {
|
|
1968
|
-
response = await client.sendMessage(content.trim(), context);
|
|
1969
|
-
}
|
|
1970
|
-
console.log(
|
|
1971
|
-
`[Appilots] useAppilotsChat sendMessage: response received \u2014 actions=${response.actions?.length ?? 0}, hasSummary=${!!response.summaryMessage}`
|
|
1972
|
-
);
|
|
1973
|
-
removeStreamingPlaceholder();
|
|
1974
|
-
addAssistantMessage(response.message);
|
|
1975
|
-
beginTurn(response.message.id, response.actions, 1);
|
|
1976
|
-
if (response.summaryMessage) {
|
|
1977
|
-
addAssistantMessage(response.summaryMessage);
|
|
1978
|
-
}
|
|
1979
|
-
emit({
|
|
1980
|
-
type: "agent:message",
|
|
1981
|
-
timestamp: Date.now(),
|
|
1982
|
-
data: { message: response.message, usage: response.usage }
|
|
1983
|
-
});
|
|
1984
|
-
if (!response.actions || response.actions.length === 0) {
|
|
1985
|
-
setIsLoading(false);
|
|
1986
|
-
setLoadingStatusKey("thinking");
|
|
1987
|
-
}
|
|
1988
|
-
} catch (err) {
|
|
1989
|
-
if (err instanceof chunkMCY5YFYD_js.StreamAbortError || err instanceof Error && err.name === "AbortError") {
|
|
1990
|
-
setIsLoading(false);
|
|
1991
|
-
setLoadingStatusKey("thinking");
|
|
1992
|
-
return;
|
|
1993
|
-
}
|
|
1994
|
-
removeStreamingPlaceholder();
|
|
1995
|
-
const errorMessage = err instanceof Error ? err.message : "Failed to send message";
|
|
1996
|
-
setError(errorMessage);
|
|
1997
|
-
const errorMsg = {
|
|
1998
|
-
id: `error_${++messageIdCounter.current}`,
|
|
1999
|
-
role: "assistant",
|
|
2000
|
-
content: `${errorPrefix}: ${errorMessage}`,
|
|
2001
|
-
timestamp: Date.now()
|
|
2002
|
-
};
|
|
2003
|
-
addAssistantMessage(errorMsg);
|
|
2004
|
-
setIsLoading(false);
|
|
2005
|
-
setLoadingStatusKey("thinking");
|
|
2006
|
-
} finally {
|
|
2007
|
-
if (abortRef.current === abortController) {
|
|
2008
|
-
abortRef.current = null;
|
|
2009
|
-
}
|
|
2010
|
-
}
|
|
2011
|
-
},
|
|
2012
|
-
[client, emit, isLoading, addAssistantMessage, beginTurn, errorPrefix, streamingEnabled]
|
|
2013
|
-
);
|
|
2014
|
-
const cancelMessage = react.useCallback(() => {
|
|
2015
|
-
abortRef.current?.abort();
|
|
2016
|
-
}, []);
|
|
2017
|
-
const clearMessages = react.useCallback(() => {
|
|
2018
|
-
setMessages([]);
|
|
2019
|
-
setPendingActions([]);
|
|
2020
|
-
setError(null);
|
|
2021
|
-
setIsLoading(false);
|
|
2022
|
-
setLoadingStatusKey("thinking");
|
|
2023
|
-
currentTurnRef.current = null;
|
|
2024
|
-
continuationInFlightRef.current = false;
|
|
2025
|
-
recoveryCountByFingerprintRef.current = /* @__PURE__ */ new Map();
|
|
2026
|
-
if (escalationRef.current) {
|
|
2027
|
-
void client.abandonEscalation(escalationRef.current.id);
|
|
2028
|
-
}
|
|
2029
|
-
setEscalation(null);
|
|
2030
|
-
escalationSinceRef.current = void 0;
|
|
2031
|
-
seenHumanMessageIdsRef.current = /* @__PURE__ */ new Set();
|
|
2032
|
-
escalationReconnectAttemptRef.current = 0;
|
|
2033
|
-
client.destroySession();
|
|
2034
|
-
}, [client]);
|
|
2035
|
-
const clearError = react.useCallback(() => setError(null), []);
|
|
2036
|
-
return {
|
|
2037
|
-
messages,
|
|
2038
|
-
isLoading,
|
|
2039
|
-
loadingStatusKey,
|
|
2040
|
-
error,
|
|
2041
|
-
pendingActions,
|
|
2042
|
-
escalation,
|
|
2043
|
-
requestHuman,
|
|
2044
|
-
sendMessage,
|
|
2045
|
-
cancelMessage,
|
|
2046
|
-
clearMessages,
|
|
2047
|
-
clearError
|
|
2048
|
-
};
|
|
2049
|
-
}
|
|
2050
|
-
|
|
2051
1018
|
// src/executor/handlers/navigateHandler.ts
|
|
2052
1019
|
function categorizeNavigationError(message) {
|
|
2053
1020
|
if (/screen named|was not handled by any navigator|no route|not found|not registered in any navigator|couldn'?t find a route|route .* (?:doesn'?t|does not) exist/i.test(
|
|
@@ -2231,7 +1198,7 @@ function markedItemIndexFromFiber(fiber) {
|
|
|
2231
1198
|
const value = fiber?.memoizedProps?.__appilotsItemIndex;
|
|
2232
1199
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2233
1200
|
}
|
|
2234
|
-
function
|
|
1201
|
+
function normalize2(value) {
|
|
2235
1202
|
return String(value ?? "").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "");
|
|
2236
1203
|
}
|
|
2237
1204
|
function hasPressHandler3(fiber) {
|
|
@@ -2243,7 +1210,7 @@ function isPressableFiber(fiber) {
|
|
|
2243
1210
|
return TOUCHABLE_NAMES.has(typeName) || hasPressHandler3(fiber);
|
|
2244
1211
|
}
|
|
2245
1212
|
function findListContainers(options = {}) {
|
|
2246
|
-
const root =
|
|
1213
|
+
const root = chunkV3TUIIT2_js.getFiberRoot();
|
|
2247
1214
|
if (!root) return [];
|
|
2248
1215
|
const containers = [];
|
|
2249
1216
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
@@ -2402,7 +1369,7 @@ function describeTouchable(fiber) {
|
|
|
2402
1369
|
}
|
|
2403
1370
|
function touchableLooksDestructive(fiber) {
|
|
2404
1371
|
const descriptor = describeTouchable(fiber);
|
|
2405
|
-
if (descriptor &&
|
|
1372
|
+
if (descriptor && chunkV3TUIIT2_js.looksDestructiveActionLabel(descriptor)) return true;
|
|
2406
1373
|
const props = fiber?.memoizedProps ?? {};
|
|
2407
1374
|
const haystack = [
|
|
2408
1375
|
props.testID,
|
|
@@ -2410,7 +1377,7 @@ function touchableLooksDestructive(fiber) {
|
|
|
2410
1377
|
props.accessibilityHint,
|
|
2411
1378
|
props.label
|
|
2412
1379
|
].filter((value) => typeof value === "string").join(" ");
|
|
2413
|
-
return
|
|
1380
|
+
return chunkV3TUIIT2_js.looksDestructiveActionLabel(haystack);
|
|
2414
1381
|
}
|
|
2415
1382
|
function describeItemCandidate(listIndex, zeroBasedIndex, item) {
|
|
2416
1383
|
const syntheticId = `list-${listIndex}-item-${zeroBasedIndex + 1}`;
|
|
@@ -2490,9 +1457,9 @@ function pressResolvedListItem(list, itemFiber, listIndex, itemIndex) {
|
|
|
2490
1457
|
}
|
|
2491
1458
|
}
|
|
2492
1459
|
function itemTextScore(item, locator) {
|
|
2493
|
-
const needles = [locator.label, ...locator.texts ?? []].map(
|
|
1460
|
+
const needles = [locator.label, ...locator.texts ?? []].map(normalize2).filter((text) => text.length >= 2);
|
|
2494
1461
|
if (needles.length === 0) return 0;
|
|
2495
|
-
const haystack = collectTexts(item).map(
|
|
1462
|
+
const haystack = collectTexts(item).map(normalize2).filter(Boolean);
|
|
2496
1463
|
if (haystack.length === 0) return 0;
|
|
2497
1464
|
let score = 0;
|
|
2498
1465
|
for (const needle of needles) {
|
|
@@ -2510,11 +1477,11 @@ function scoreItemCandidate(item, zeroBasedIndex, locator) {
|
|
|
2510
1477
|
const markedIndex = markedItemIndexFromFiber(item);
|
|
2511
1478
|
if (locator.itemKey) {
|
|
2512
1479
|
if (itemKey === locator.itemKey) score += 1e3;
|
|
2513
|
-
else if (itemKey &&
|
|
1480
|
+
else if (itemKey && normalize2(itemKey) === normalize2(locator.itemKey)) score += 950;
|
|
2514
1481
|
}
|
|
2515
1482
|
if (locator.reactKey) {
|
|
2516
1483
|
if (reactKey === locator.reactKey) score += 900;
|
|
2517
|
-
else if (reactKey &&
|
|
1484
|
+
else if (reactKey && normalize2(reactKey) === normalize2(locator.reactKey)) score += 850;
|
|
2518
1485
|
}
|
|
2519
1486
|
if (locator.itemIndex && zeroBasedIndex === locator.itemIndex - 1) score += 750;
|
|
2520
1487
|
if (locator.itemIndex && markedIndex !== void 0 && (markedIndex === locator.itemIndex || markedIndex === locator.itemIndex - 1)) {
|
|
@@ -2525,8 +1492,8 @@ function scoreItemCandidate(item, zeroBasedIndex, locator) {
|
|
|
2525
1492
|
}
|
|
2526
1493
|
function candidateLists(containers, locator) {
|
|
2527
1494
|
if (locator.listId) {
|
|
2528
|
-
const normalizedId =
|
|
2529
|
-
const matches = containers.map((list, listIndex) => ({ list, listIndex })).filter(({ list }) =>
|
|
1495
|
+
const normalizedId = normalize2(locator.listId);
|
|
1496
|
+
const matches = containers.map((list, listIndex) => ({ list, listIndex })).filter(({ list }) => normalize2(list.listId) === normalizedId);
|
|
2530
1497
|
if (matches.length > 0) return matches;
|
|
2531
1498
|
}
|
|
2532
1499
|
if (typeof locator.listIndex === "number") {
|
|
@@ -2534,14 +1501,14 @@ function candidateLists(containers, locator) {
|
|
|
2534
1501
|
return list ? [{ list, listIndex: locator.listIndex }] : [];
|
|
2535
1502
|
}
|
|
2536
1503
|
if (locator.listLabel) {
|
|
2537
|
-
const normalizedLabel =
|
|
2538
|
-
const matches = containers.map((list, listIndex) => ({ list, listIndex })).filter(({ list }) =>
|
|
1504
|
+
const normalizedLabel = normalize2(locator.listLabel);
|
|
1505
|
+
const matches = containers.map((list, listIndex) => ({ list, listIndex })).filter(({ list }) => normalize2(list.listLabel).includes(normalizedLabel));
|
|
2539
1506
|
if (matches.length > 0) return matches;
|
|
2540
1507
|
}
|
|
2541
1508
|
return containers.map((list, listIndex) => ({ list, listIndex }));
|
|
2542
1509
|
}
|
|
2543
1510
|
function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
2544
|
-
if (!
|
|
1511
|
+
if (!chunkV3TUIIT2_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
|
|
2545
1512
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
2546
1513
|
if (listIndex < 0 || listIndex >= containers.length) {
|
|
2547
1514
|
return { ok: false, reason: "list-not-found" };
|
|
@@ -2555,7 +1522,7 @@ function pressListItemAtOrdinal(listIndex, itemIndex) {
|
|
|
2555
1522
|
return pressResolvedListItem(list, items[zeroBased], listIndex, itemIndex);
|
|
2556
1523
|
}
|
|
2557
1524
|
function pressListItemByIdentity(locator) {
|
|
2558
|
-
if (!
|
|
1525
|
+
if (!chunkV3TUIIT2_js.getFiberRoot()) return { ok: false, reason: "no-fiber-root" };
|
|
2559
1526
|
const parsed = locator.syntheticId ? parseSyntheticListItemId(locator.syntheticId) : null;
|
|
2560
1527
|
const effective = parsed ? { ...locator, listIndex: parsed.listIndex, itemIndex: parsed.itemIndex } : locator;
|
|
2561
1528
|
const containers = findListContainers({ allowSingleHeuristic: true });
|
|
@@ -2595,7 +1562,7 @@ function screenDiagnose(targetId, category = "component-not-found") {
|
|
|
2595
1562
|
return {
|
|
2596
1563
|
category,
|
|
2597
1564
|
targetId,
|
|
2598
|
-
screen:
|
|
1565
|
+
screen: chunkV3TUIIT2_js.getCurrentScreen() ?? void 0
|
|
2599
1566
|
};
|
|
2600
1567
|
}
|
|
2601
1568
|
function isPressLike(action) {
|
|
@@ -2612,10 +1579,10 @@ function elementLookupKey(value) {
|
|
|
2612
1579
|
return canonicalElementId(value).toLowerCase().replace(/[\s_]+/g, "-");
|
|
2613
1580
|
}
|
|
2614
1581
|
function findRegisteredElement(elementId) {
|
|
2615
|
-
const direct =
|
|
1582
|
+
const direct = chunkV3TUIIT2_js.elementRegistry.get(elementId) ?? chunkV3TUIIT2_js.elementRegistry.get(canonicalElementId(elementId));
|
|
2616
1583
|
if (direct) return direct;
|
|
2617
1584
|
const wanted = elementLookupKey(elementId);
|
|
2618
|
-
return
|
|
1585
|
+
return chunkV3TUIIT2_js.elementRegistry.snapshot().find((element) => elementLookupKey(element.id) === wanted);
|
|
2619
1586
|
}
|
|
2620
1587
|
function resolveInteractionElement(elementId) {
|
|
2621
1588
|
return getLatestElement(elementId);
|
|
@@ -2835,7 +1802,7 @@ function dispatchElement(element, registry, action) {
|
|
|
2835
1802
|
}
|
|
2836
1803
|
function dispatchStructuredElementId(identifier, action) {
|
|
2837
1804
|
if (!isElementIdentifier(identifier) || !isPressLike(action)) return null;
|
|
2838
|
-
const parsed = parseStableElementId(identifier);
|
|
1805
|
+
const parsed = chunkV3TUIIT2_js.parseStableElementId(identifier);
|
|
2839
1806
|
if (!parsed || parsed.role !== "option") return null;
|
|
2840
1807
|
if (!parsed.itemKey && !parsed.listId) return null;
|
|
2841
1808
|
const pressed = pressListItemByIdentity({
|
|
@@ -2871,24 +1838,24 @@ function pressElementOrTarget(identifier, registry) {
|
|
|
2871
1838
|
// src/executor/formFieldRewrite.ts
|
|
2872
1839
|
var LIST_ORDINAL_RE = /^list-\d+-item-\d+$/i;
|
|
2873
1840
|
var PLATE_RE = /^[A-Z]{3}-?\d[A-Z0-9]\d{2}$/i;
|
|
2874
|
-
function
|
|
1841
|
+
function normalize4(value) {
|
|
2875
1842
|
return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]/g, "");
|
|
2876
1843
|
}
|
|
2877
1844
|
function resolveScreenForFormFields() {
|
|
2878
|
-
const activePath =
|
|
1845
|
+
const activePath = chunkV3TUIIT2_js.getActiveRouteNames();
|
|
2879
1846
|
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
2880
1847
|
const name = activePath[i];
|
|
2881
|
-
const meta = name ?
|
|
1848
|
+
const meta = name ? chunkV3TUIIT2_js.getScreenMetadata(name) : void 0;
|
|
2882
1849
|
if (name && Array.isArray(meta?.fields) && meta.fields.length > 0) return name;
|
|
2883
1850
|
}
|
|
2884
|
-
return
|
|
1851
|
+
return chunkV3TUIIT2_js.getCurrentScreen();
|
|
2885
1852
|
}
|
|
2886
1853
|
function collectKnownFormFields(registry) {
|
|
2887
1854
|
const registryFields = registry.snapshot().filter((entry) => entry.kind === "field" || entry.kind === "slider").map((entry) => ({ id: entry.id, label: entry.label }));
|
|
2888
1855
|
if (registryFields.length >= 2) return registryFields;
|
|
2889
1856
|
const screen = resolveScreenForFormFields();
|
|
2890
1857
|
if (screen) {
|
|
2891
|
-
const metaFields =
|
|
1858
|
+
const metaFields = chunkV3TUIIT2_js.getScreenMetadata(screen)?.fields;
|
|
2892
1859
|
if (Array.isArray(metaFields) && metaFields.length > 0) {
|
|
2893
1860
|
return metaFields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
2894
1861
|
id: field.id,
|
|
@@ -2898,7 +1865,7 @@ function collectKnownFormFields(registry) {
|
|
|
2898
1865
|
}));
|
|
2899
1866
|
}
|
|
2900
1867
|
}
|
|
2901
|
-
for (const meta of
|
|
1868
|
+
for (const meta of chunkV3TUIIT2_js.getAllScreens()) {
|
|
2902
1869
|
if (Array.isArray(meta.fields) && meta.fields.length > 0) {
|
|
2903
1870
|
return meta.fields.filter((field) => !!field && typeof field.id === "string").map((field) => ({
|
|
2904
1871
|
id: field.id,
|
|
@@ -2911,14 +1878,14 @@ function collectKnownFormFields(registry) {
|
|
|
2911
1878
|
return registryFields;
|
|
2912
1879
|
}
|
|
2913
1880
|
function fieldHaystack(field) {
|
|
2914
|
-
return
|
|
1881
|
+
return normalize4(`${field.id} ${field.label ?? ""}`);
|
|
2915
1882
|
}
|
|
2916
1883
|
function isMisplacedFieldId(fieldId, knownIds) {
|
|
2917
1884
|
const trimmed = fieldId.trim();
|
|
2918
1885
|
if (!trimmed) return true;
|
|
2919
1886
|
if (LIST_ORDINAL_RE.test(trimmed)) return true;
|
|
2920
1887
|
if (/^\d+$/.test(trimmed)) return true;
|
|
2921
|
-
const normalized =
|
|
1888
|
+
const normalized = normalize4(trimmed);
|
|
2922
1889
|
if (knownIds.has(normalized)) return false;
|
|
2923
1890
|
for (const known of knownIds) {
|
|
2924
1891
|
if (known.length >= 4 && (known.includes(normalized) || normalized.includes(known))) {
|
|
@@ -2928,18 +1895,18 @@ function isMisplacedFieldId(fieldId, knownIds) {
|
|
|
2928
1895
|
return true;
|
|
2929
1896
|
}
|
|
2930
1897
|
function valueMatchesOption(field, rawValue) {
|
|
2931
|
-
const value =
|
|
1898
|
+
const value = normalize4(String(rawValue ?? ""));
|
|
2932
1899
|
if (!value || !Array.isArray(field.options)) return false;
|
|
2933
1900
|
return field.options.some((option) => {
|
|
2934
|
-
const label =
|
|
2935
|
-
const optionValue =
|
|
1901
|
+
const label = normalize4(option.label ?? "");
|
|
1902
|
+
const optionValue = normalize4(option.value ?? "");
|
|
2936
1903
|
return label === value || optionValue === value || value.includes(label) || value.includes(optionValue);
|
|
2937
1904
|
});
|
|
2938
1905
|
}
|
|
2939
1906
|
function inferFieldIdForValue(rawValue, fields, used) {
|
|
2940
1907
|
const value = String(rawValue ?? "").trim();
|
|
2941
1908
|
if (!value) return void 0;
|
|
2942
|
-
const normalizedValue =
|
|
1909
|
+
const normalizedValue = normalize4(value);
|
|
2943
1910
|
for (const field of fields) {
|
|
2944
1911
|
if (used.has(field.id)) continue;
|
|
2945
1912
|
if (valueMatchesOption(field, value)) return field.id;
|
|
@@ -2976,7 +1943,7 @@ function inferFieldIdForValue(rawValue, fields, used) {
|
|
|
2976
1943
|
}
|
|
2977
1944
|
const nextText = fields.find((field) => {
|
|
2978
1945
|
if (used.has(field.id)) return false;
|
|
2979
|
-
const type =
|
|
1946
|
+
const type = normalize4(field.type ?? "text");
|
|
2980
1947
|
return type === "text" || type === "input" || type === "number" || type === "";
|
|
2981
1948
|
});
|
|
2982
1949
|
return nextText?.id;
|
|
@@ -2984,7 +1951,7 @@ function inferFieldIdForValue(rawValue, fields, used) {
|
|
|
2984
1951
|
function rewriteMisplacedFormFillFields(fields, registry) {
|
|
2985
1952
|
const knownFields = collectKnownFormFields(registry);
|
|
2986
1953
|
if (knownFields.length === 0) return fields;
|
|
2987
|
-
const knownIds = new Set(knownFields.map((field) =>
|
|
1954
|
+
const knownIds = new Set(knownFields.map((field) => normalize4(field.id)));
|
|
2988
1955
|
const needsRewrite = fields.some((field) => isMisplacedFieldId(field.fieldId, knownIds));
|
|
2989
1956
|
if (!needsRewrite) return fields;
|
|
2990
1957
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -2996,7 +1963,7 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
2996
1963
|
const inferred = inferFieldIdForValue(String(field.value ?? ""), knownFields, used);
|
|
2997
1964
|
if (!inferred) return field;
|
|
2998
1965
|
used.add(inferred);
|
|
2999
|
-
|
|
1966
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
3000
1967
|
`formFieldRewrite: ${field.fieldId} \u2192 ${inferred} (value=${JSON.stringify(field.value)})`
|
|
3001
1968
|
);
|
|
3002
1969
|
return { ...field, fieldId: inferred };
|
|
@@ -3004,7 +1971,7 @@ function rewriteMisplacedFormFillFields(fields, registry) {
|
|
|
3004
1971
|
}
|
|
3005
1972
|
|
|
3006
1973
|
// src/executor/formValidation.ts
|
|
3007
|
-
var
|
|
1974
|
+
var FORM_VALIDATION_TEXT_RE = /(inv[aá]lid|obrigat[oó]ri|required|invalid|j[aá]\s+existe|already\s+exists|duplicad|formato|format|too\s+short|muito\s+curto|n[aã]o\s+(?:foi|pode)|must\s+be|deve\s+ser|selecione|escolha|select\s+(?:the|a|o|an))/i;
|
|
3008
1975
|
var FORM_SUCCESS_TEXT_RE = /\b(cadastrad[oa]s?\s+com\s+sucesso|registrad[oa]s?\s+com\s+sucesso|salv[oa]\s+com\s+sucesso|foi\s+cadastrad[oa]|foi\s+registrad[oa]|foi\s+salv[oa]|successfully\s+(?:registered|saved|created)|(?:has\s+been|was)\s+(?:registered|saved|created))\b/i;
|
|
3009
1976
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3010
1977
|
var FIELD_HINTS = [
|
|
@@ -3024,7 +1991,7 @@ function inferValidationFieldId(message) {
|
|
|
3024
1991
|
function readVisibleFormValidation(snap) {
|
|
3025
1992
|
if (!snap) return void 0;
|
|
3026
1993
|
for (const text of snap.texts ?? []) {
|
|
3027
|
-
if (!text?.trim() || !
|
|
1994
|
+
if (!text?.trim() || !FORM_VALIDATION_TEXT_RE.test(text)) continue;
|
|
3028
1995
|
return { fieldId: inferValidationFieldId(text), message: text };
|
|
3029
1996
|
}
|
|
3030
1997
|
return void 0;
|
|
@@ -3034,7 +2001,7 @@ function readVisibleFormSuccess(snap) {
|
|
|
3034
2001
|
return (snap.texts ?? []).find((text) => text?.trim() && FORM_SUCCESS_TEXT_RE.test(text));
|
|
3035
2002
|
}
|
|
3036
2003
|
function submitAsyncStillPending(submitTargetId) {
|
|
3037
|
-
const probe =
|
|
2004
|
+
const probe = chunkV3TUIIT2_js.probeLoadingState(submitTargetId ?? null, chunkV3TUIIT2_js.getCurrentScreen());
|
|
3038
2005
|
if (probe.loading) return true;
|
|
3039
2006
|
if (submitTargetId && probe.pressedFound && probe.pressedDisabled) return true;
|
|
3040
2007
|
return false;
|
|
@@ -3046,7 +2013,7 @@ function evaluatePostSubmitSnapshot(snap, activePath) {
|
|
|
3046
2013
|
}
|
|
3047
2014
|
const successText = readVisibleFormSuccess(snap);
|
|
3048
2015
|
if (successText) return { status: "success", message: successText };
|
|
3049
|
-
if (!snapshotShowsOpenCreateForm(snap, activePath)) {
|
|
2016
|
+
if (!chunkV3TUIIT2_js.snapshotShowsOpenCreateForm(snap, activePath)) {
|
|
3050
2017
|
return { status: "success" };
|
|
3051
2018
|
}
|
|
3052
2019
|
return void 0;
|
|
@@ -3062,7 +2029,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
3062
2029
|
continue;
|
|
3063
2030
|
}
|
|
3064
2031
|
const snap2 = captureSnapshot();
|
|
3065
|
-
const activePath2 =
|
|
2032
|
+
const activePath2 = chunkV3TUIIT2_js.getActiveRouteNames();
|
|
3066
2033
|
const outcome2 = evaluatePostSubmitSnapshot(snap2, activePath2);
|
|
3067
2034
|
if (outcome2) return outcome2;
|
|
3068
2035
|
await sleep(pollMs);
|
|
@@ -3074,7 +2041,7 @@ async function waitForPostSubmitOutcome(options) {
|
|
|
3074
2041
|
};
|
|
3075
2042
|
}
|
|
3076
2043
|
const snap = captureSnapshot();
|
|
3077
|
-
const activePath =
|
|
2044
|
+
const activePath = chunkV3TUIIT2_js.getActiveRouteNames();
|
|
3078
2045
|
const outcome = evaluatePostSubmitSnapshot(snap, activePath);
|
|
3079
2046
|
if (outcome) return outcome;
|
|
3080
2047
|
return {
|
|
@@ -3180,16 +2147,16 @@ function findSnapshotButton(targetId) {
|
|
|
3180
2147
|
}
|
|
3181
2148
|
}
|
|
3182
2149
|
function buildUiDiagnose(targetId, cause) {
|
|
3183
|
-
const activePath =
|
|
3184
|
-
const screen = activePath[activePath.length - 1] ??
|
|
2150
|
+
const activePath = chunkV3TUIIT2_js.getActiveRouteNames();
|
|
2151
|
+
const screen = activePath[activePath.length - 1] ?? chunkV3TUIIT2_js.getCurrentScreen() ?? void 0;
|
|
3185
2152
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
3186
2153
|
const diagnose = {
|
|
3187
2154
|
category: cause === "not-found" ? "component-not-found" : cause === "disabled" ? "disabled" : "unknown",
|
|
3188
2155
|
targetId,
|
|
3189
2156
|
screen: screenPath
|
|
3190
2157
|
};
|
|
3191
|
-
if (
|
|
3192
|
-
diagnose.visibleMessage =
|
|
2158
|
+
if (chunkV3TUIIT2_js.isOptionalStepAutomationFailure(targetId, screenPath, activePath)) {
|
|
2159
|
+
diagnose.visibleMessage = chunkV3TUIIT2_js.OPTIONAL_STEP_AUTOMATION_HINT;
|
|
3193
2160
|
diagnose.recoverable = true;
|
|
3194
2161
|
}
|
|
3195
2162
|
return diagnose;
|
|
@@ -3251,9 +2218,9 @@ function resolveComponentId(componentId, registry, action) {
|
|
|
3251
2218
|
return comp.id;
|
|
3252
2219
|
}
|
|
3253
2220
|
}
|
|
3254
|
-
const currentScreen =
|
|
2221
|
+
const currentScreen = chunkV3TUIIT2_js.getCurrentScreen();
|
|
3255
2222
|
if (currentScreen) {
|
|
3256
|
-
const screenMeta =
|
|
2223
|
+
const screenMeta = chunkV3TUIIT2_js.getScreenMetadata(currentScreen);
|
|
3257
2224
|
const actions = screenMeta?.actions;
|
|
3258
2225
|
if (actions && Array.isArray(actions)) {
|
|
3259
2226
|
const metaAction = actions.find(
|
|
@@ -3407,7 +2374,7 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
3407
2374
|
return null;
|
|
3408
2375
|
}
|
|
3409
2376
|
if (typeof rawComponentId !== "string" || rawComponentId.trim().length === 0) return null;
|
|
3410
|
-
const fiberRoot =
|
|
2377
|
+
const fiberRoot = chunkV3TUIIT2_js.getFiberRoot();
|
|
3411
2378
|
if (!fiberRoot) return null;
|
|
3412
2379
|
let snap;
|
|
3413
2380
|
try {
|
|
@@ -3470,7 +2437,7 @@ function checkModalOcclusion(rawComponentId, action) {
|
|
|
3470
2437
|
}
|
|
3471
2438
|
function uiInteractionHandler(payload, context) {
|
|
3472
2439
|
const { permissions } = context;
|
|
3473
|
-
const registry = context.registry ??
|
|
2440
|
+
const registry = context.registry ?? chunkV3TUIIT2_js.componentRegistry;
|
|
3474
2441
|
if (!permissions.canInteractUI) {
|
|
3475
2442
|
return {
|
|
3476
2443
|
success: false,
|
|
@@ -3529,7 +2496,7 @@ function uiInteractionHandler(payload, context) {
|
|
|
3529
2496
|
);
|
|
3530
2497
|
return { success: true };
|
|
3531
2498
|
}
|
|
3532
|
-
const screen =
|
|
2499
|
+
const screen = chunkV3TUIIT2_js.getCurrentScreen() ?? void 0;
|
|
3533
2500
|
if (result.reason === "list-not-found" || result.reason === "item-not-found") {
|
|
3534
2501
|
return {
|
|
3535
2502
|
success: false,
|
|
@@ -3670,18 +2637,18 @@ function uiInteractionHandler(payload, context) {
|
|
|
3670
2637
|
// src/executor/formSubmitResolve.ts
|
|
3671
2638
|
var SUBMIT_LABEL_HINT_RE = /\b(submit|save|send|continue|next|sign\s*in|log\s*in|register|salvar|enviar|entrar|cadastrar|continuar|proximo|próximo|avancar|avançar|confirmar|guardar|registrarse|iniciar\s+sesi[óo]n|enregistrer|envoyer|valider|soumettre|confirmer|se\s+connecter|s['e]\s*inscrire)\b/i;
|
|
3672
2639
|
var AGENT_CHROME_TARGET_RE = /\b(fechar|close|dismiss|cancelar|cancel|limpar|clear|chat\s+do\s+assistente|assistant\s+chat)\b/i;
|
|
3673
|
-
function
|
|
2640
|
+
function normalize5(value) {
|
|
3674
2641
|
return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
|
|
3675
2642
|
}
|
|
3676
2643
|
function isAgentChromeTarget(id, label) {
|
|
3677
|
-
const hay =
|
|
2644
|
+
const hay = normalize5(`${id ?? ""} ${label ?? ""}`);
|
|
3678
2645
|
return AGENT_CHROME_TARGET_RE.test(hay);
|
|
3679
2646
|
}
|
|
3680
2647
|
function isSubmitLikeTarget(id, label) {
|
|
3681
2648
|
if (!id && !label) return false;
|
|
3682
2649
|
if (isAgentChromeTarget(id, label)) return false;
|
|
3683
|
-
const idNorm =
|
|
3684
|
-
|
|
2650
|
+
const idNorm = normalize5(id ?? "");
|
|
2651
|
+
normalize5(label ?? "");
|
|
3685
2652
|
if (/^submit[-_]/i.test(id ?? "")) return true;
|
|
3686
2653
|
if (submitLabelHintsSubmit(label ?? "")) return true;
|
|
3687
2654
|
if (submitLabelHintsSubmit(id ?? "")) return true;
|
|
@@ -3694,7 +2661,7 @@ function submitLabelHintsSubmit(label) {
|
|
|
3694
2661
|
return SUBMIT_LABEL_HINT_RE.test(trimmed);
|
|
3695
2662
|
}
|
|
3696
2663
|
function screenDeclaresSubmitAction(screenName) {
|
|
3697
|
-
const meta =
|
|
2664
|
+
const meta = chunkV3TUIIT2_js.getScreenMetadata(screenName);
|
|
3698
2665
|
return Array.isArray(meta?.actions) && meta.actions.some(
|
|
3699
2666
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
3700
2667
|
);
|
|
@@ -3727,7 +2694,7 @@ function resolveFormScreensForSubmit(screen, activePath, registry) {
|
|
|
3727
2694
|
} else {
|
|
3728
2695
|
push(screen);
|
|
3729
2696
|
}
|
|
3730
|
-
push(
|
|
2697
|
+
push(chunkV3TUIIT2_js.getCurrentScreen() ?? void 0);
|
|
3731
2698
|
const withSubmit = [];
|
|
3732
2699
|
const rest = [];
|
|
3733
2700
|
for (const name of ordered) {
|
|
@@ -3745,7 +2712,7 @@ function collectSubmitTargetCandidates(screens, registry) {
|
|
|
3745
2712
|
candidates.push(id);
|
|
3746
2713
|
};
|
|
3747
2714
|
for (const screenName of screens) {
|
|
3748
|
-
const meta =
|
|
2715
|
+
const meta = chunkV3TUIIT2_js.getScreenMetadata(screenName);
|
|
3749
2716
|
const submitMeta = Array.isArray(meta?.actions) ? meta.actions.find(
|
|
3750
2717
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
3751
2718
|
) : void 0;
|
|
@@ -3780,7 +2747,7 @@ function readVisibleValidation(fieldId, label) {
|
|
|
3780
2747
|
);
|
|
3781
2748
|
for (const text of texts) {
|
|
3782
2749
|
const lower = text.toLowerCase();
|
|
3783
|
-
if (
|
|
2750
|
+
if (FORM_VALIDATION_TEXT_RE.test(lower)) {
|
|
3784
2751
|
for (const needle of needles) {
|
|
3785
2752
|
if (lower.includes(needle.toLowerCase())) return text;
|
|
3786
2753
|
}
|
|
@@ -3791,8 +2758,8 @@ function readVisibleValidation(fieldId, label) {
|
|
|
3791
2758
|
return void 0;
|
|
3792
2759
|
}
|
|
3793
2760
|
function resolveScreenContext() {
|
|
3794
|
-
const activePath =
|
|
3795
|
-
const screen = activePath[activePath.length - 1] ??
|
|
2761
|
+
const activePath = chunkV3TUIIT2_js.getActiveRouteNames();
|
|
2762
|
+
const screen = activePath[activePath.length - 1] ?? chunkV3TUIIT2_js.getCurrentScreen() ?? void 0;
|
|
3796
2763
|
return { screen, activePath };
|
|
3797
2764
|
}
|
|
3798
2765
|
function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
@@ -3800,36 +2767,36 @@ function selectValueApplied(fieldId, requestedValue, currentValue, registry) {
|
|
|
3800
2767
|
if (!requested) return false;
|
|
3801
2768
|
const meta = getMetadataField(fieldId, registry);
|
|
3802
2769
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
3803
|
-
const requestedNorm =
|
|
3804
|
-
const currentNorm =
|
|
2770
|
+
const requestedNorm = chunkV3TUIIT2_js.normalize3(requested);
|
|
2771
|
+
const currentNorm = chunkV3TUIIT2_js.normalize3(currentValue);
|
|
3805
2772
|
if (currentNorm === requestedNorm) return true;
|
|
3806
2773
|
for (const option of options) {
|
|
3807
2774
|
const value = typeof option?.value === "string" ? option.value : "";
|
|
3808
2775
|
const label = typeof option?.label === "string" ? option.label : "";
|
|
3809
|
-
if (
|
|
3810
|
-
if (
|
|
3811
|
-
if (
|
|
2776
|
+
if (chunkV3TUIIT2_js.normalize3(value) === requestedNorm && chunkV3TUIIT2_js.normalize3(label) === currentNorm) return true;
|
|
2777
|
+
if (chunkV3TUIIT2_js.normalize3(label) === requestedNorm && chunkV3TUIIT2_js.normalize3(label) === currentNorm) return true;
|
|
2778
|
+
if (chunkV3TUIIT2_js.normalize3(value) === requestedNorm && chunkV3TUIIT2_js.normalize3(value) === currentNorm) return true;
|
|
3812
2779
|
}
|
|
3813
2780
|
return false;
|
|
3814
2781
|
}
|
|
3815
2782
|
function getMetadataField(fieldId, registry) {
|
|
3816
2783
|
const screens = /* @__PURE__ */ new Set();
|
|
3817
|
-
for (const name of
|
|
3818
|
-
const current =
|
|
2784
|
+
for (const name of chunkV3TUIIT2_js.getActiveRouteNames()) screens.add(name);
|
|
2785
|
+
const current = chunkV3TUIIT2_js.getCurrentScreen();
|
|
3819
2786
|
if (current) screens.add(current);
|
|
3820
2787
|
if (registry) {
|
|
3821
2788
|
for (const comp of registry.snapshot()) {
|
|
3822
2789
|
if (comp.kind === "field" && comp.screen) screens.add(comp.screen);
|
|
3823
2790
|
}
|
|
3824
2791
|
}
|
|
3825
|
-
const needle =
|
|
2792
|
+
const needle = chunkV3TUIIT2_js.normalize3(fieldId);
|
|
3826
2793
|
for (const screenName of screens) {
|
|
3827
|
-
const screenMeta =
|
|
2794
|
+
const screenMeta = chunkV3TUIIT2_js.getScreenMetadata(screenName);
|
|
3828
2795
|
const fields = Array.isArray(screenMeta?.fields) ? screenMeta.fields : [];
|
|
3829
2796
|
const match = fields.find((field) => {
|
|
3830
2797
|
if (!field || typeof field !== "object") return false;
|
|
3831
|
-
const id = typeof field.id === "string" ?
|
|
3832
|
-
const label = typeof field.label === "string" ?
|
|
2798
|
+
const id = typeof field.id === "string" ? chunkV3TUIIT2_js.normalize3(field.id) : "";
|
|
2799
|
+
const label = typeof field.label === "string" ? chunkV3TUIIT2_js.normalize3(field.label) : "";
|
|
3833
2800
|
return id === needle || label === needle;
|
|
3834
2801
|
});
|
|
3835
2802
|
if (match) return match;
|
|
@@ -3841,11 +2808,11 @@ function resolveSelectOption(fieldId, value, registry) {
|
|
|
3841
2808
|
if (!requested) return void 0;
|
|
3842
2809
|
const meta = getMetadataField(fieldId, registry);
|
|
3843
2810
|
const options = Array.isArray(meta?.options) ? meta.options : [];
|
|
3844
|
-
const requestedNorm =
|
|
2811
|
+
const requestedNorm = chunkV3TUIIT2_js.normalize3(requested);
|
|
3845
2812
|
for (const option of options) {
|
|
3846
2813
|
const optionValue = typeof option?.value === "string" ? option.value : "";
|
|
3847
2814
|
const optionLabel = typeof option?.label === "string" ? option.label : "";
|
|
3848
|
-
if (
|
|
2815
|
+
if (chunkV3TUIIT2_js.normalize3(optionValue) === requestedNorm || chunkV3TUIIT2_js.normalize3(optionLabel) === requestedNorm) {
|
|
3849
2816
|
return { value: optionValue, label: optionLabel };
|
|
3850
2817
|
}
|
|
3851
2818
|
}
|
|
@@ -3895,12 +2862,12 @@ async function tryPressSelectOption(fieldId, value, registry, options = {}) {
|
|
|
3895
2862
|
return {
|
|
3896
2863
|
success: false,
|
|
3897
2864
|
error: `No pressable option found for select field "${fieldId}"`,
|
|
3898
|
-
diagnose: { category: "component-not-found", fieldId, screen:
|
|
2865
|
+
diagnose: { category: "component-not-found", fieldId, screen: chunkV3TUIIT2_js.getCurrentScreen() ?? void 0 }
|
|
3899
2866
|
};
|
|
3900
2867
|
}
|
|
3901
2868
|
function normalizeFieldType(type) {
|
|
3902
2869
|
if (typeof type !== "string") return void 0;
|
|
3903
|
-
const normalized =
|
|
2870
|
+
const normalized = chunkV3TUIIT2_js.normalize3(type);
|
|
3904
2871
|
if (normalized === "select" || normalized === "picker" || normalized === "dropdown") return "select";
|
|
3905
2872
|
if (normalized === "toggle" || normalized === "switch" || normalized === "checkbox") return "toggle";
|
|
3906
2873
|
if (normalized === "date") return "date";
|
|
@@ -3928,7 +2895,7 @@ function fieldCueTerms(fieldId, label) {
|
|
|
3928
2895
|
);
|
|
3929
2896
|
const terms = /* @__PURE__ */ new Set();
|
|
3930
2897
|
for (const value of raw) {
|
|
3931
|
-
const normalized =
|
|
2898
|
+
const normalized = chunkV3TUIIT2_js.normalize3(value);
|
|
3932
2899
|
if (normalized.length >= 3 && normalized !== "id") terms.add(normalized);
|
|
3933
2900
|
}
|
|
3934
2901
|
return [...terms];
|
|
@@ -3939,17 +2906,17 @@ function snapshotHasFieldCue(snap, fieldId, label) {
|
|
|
3939
2906
|
const visible = [
|
|
3940
2907
|
...snap.texts ?? [],
|
|
3941
2908
|
...(snap.buttons ?? []).map((b) => b.label ?? b.id ?? "")
|
|
3942
|
-
].map((text) =>
|
|
2909
|
+
].map((text) => chunkV3TUIIT2_js.normalize3(text)).filter(Boolean);
|
|
3943
2910
|
return visible.some((text) => terms.some((term) => text.includes(term) || term.includes(text)));
|
|
3944
2911
|
}
|
|
3945
2912
|
function scoreCandidateText(value, texts) {
|
|
3946
|
-
const valueNorm =
|
|
2913
|
+
const valueNorm = chunkV3TUIIT2_js.normalize3(String(value ?? ""));
|
|
3947
2914
|
if (!valueNorm) return 0;
|
|
3948
2915
|
let best = 0;
|
|
3949
2916
|
for (const text of texts) {
|
|
3950
|
-
const textNorm =
|
|
2917
|
+
const textNorm = chunkV3TUIIT2_js.normalize3(text);
|
|
3951
2918
|
if (!textNorm) continue;
|
|
3952
|
-
best = Math.max(best,
|
|
2919
|
+
best = Math.max(best, chunkV3TUIIT2_js.matchScore(valueNorm, textNorm));
|
|
3953
2920
|
}
|
|
3954
2921
|
return best;
|
|
3955
2922
|
}
|
|
@@ -3963,7 +2930,7 @@ function optionTexts(option) {
|
|
|
3963
2930
|
function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue, registry) {
|
|
3964
2931
|
const fieldLabel = getFieldLabel(fieldId, registry);
|
|
3965
2932
|
const fieldCueVisible = snapshotHasFieldCue(snap, fieldId, fieldLabel);
|
|
3966
|
-
const genericValue =
|
|
2933
|
+
const genericValue = chunkV3TUIIT2_js.isGenericSelectValue(value);
|
|
3967
2934
|
const candidates = [];
|
|
3968
2935
|
let order = 0;
|
|
3969
2936
|
const choiceGroups = snap.choiceGroups ?? [];
|
|
@@ -3975,7 +2942,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
3975
2942
|
const groupCueScore = Math.max(
|
|
3976
2943
|
globalCueScore,
|
|
3977
2944
|
...groupTexts.map((text) => {
|
|
3978
|
-
const normalized =
|
|
2945
|
+
const normalized = chunkV3TUIIT2_js.normalize3(text);
|
|
3979
2946
|
return fieldCueTerms(fieldId, fieldLabel).some(
|
|
3980
2947
|
(term) => normalized.includes(term) || term.includes(normalized)
|
|
3981
2948
|
) ? 80 : 0;
|
|
@@ -4012,7 +2979,7 @@ function buildChoiceCandidates(snap, fieldId, value, allowFirstVisibleWhenNoCue,
|
|
|
4012
2979
|
const elementCueScore = Math.max(
|
|
4013
2980
|
fieldCueVisible && elements.length <= 12 ? 50 : 0,
|
|
4014
2981
|
...cueTexts.map((text) => {
|
|
4015
|
-
const normalized =
|
|
2982
|
+
const normalized = chunkV3TUIIT2_js.normalize3(text);
|
|
4016
2983
|
return fieldTerms.some(
|
|
4017
2984
|
(term) => normalized.includes(term) || term.includes(normalized)
|
|
4018
2985
|
) ? 80 : 0;
|
|
@@ -4072,7 +3039,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
4072
3039
|
return {
|
|
4073
3040
|
success: false,
|
|
4074
3041
|
error: err?.message ?? "Could not capture visible choices",
|
|
4075
|
-
diagnose: { category: "unknown", fieldId, screen:
|
|
3042
|
+
diagnose: { category: "unknown", fieldId, screen: chunkV3TUIIT2_js.getCurrentScreen() ?? void 0 }
|
|
4076
3043
|
};
|
|
4077
3044
|
}
|
|
4078
3045
|
const candidates = buildChoiceCandidates(
|
|
@@ -4087,7 +3054,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
4087
3054
|
return {
|
|
4088
3055
|
success: false,
|
|
4089
3056
|
error: `No visible option found for select field "${fieldId}"`,
|
|
4090
|
-
diagnose: { category: "component-not-found", fieldId, screen:
|
|
3057
|
+
diagnose: { category: "component-not-found", fieldId, screen: chunkV3TUIIT2_js.getCurrentScreen() ?? void 0 }
|
|
4091
3058
|
};
|
|
4092
3059
|
}
|
|
4093
3060
|
const pressed = pressTargetByIdOrLabel(candidate.targetId, registry);
|
|
@@ -4100,7 +3067,7 @@ async function selectVisibleChoiceAsync(fieldId, value, registry, options) {
|
|
|
4100
3067
|
}
|
|
4101
3068
|
function isContinuationButton(label) {
|
|
4102
3069
|
if (!label) return false;
|
|
4103
|
-
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(
|
|
3070
|
+
return /^(next|continue|proximo|prox|continuar|avancar|avançar)$/i.test(chunkV3TUIIT2_js.normalize3(label));
|
|
4104
3071
|
}
|
|
4105
3072
|
function pressContinuationButton(registry) {
|
|
4106
3073
|
const snap = captureSnapshot();
|
|
@@ -4113,7 +3080,7 @@ function pressContinuationButton(registry) {
|
|
|
4113
3080
|
return {
|
|
4114
3081
|
success: false,
|
|
4115
3082
|
error: "No enabled continuation button is visible",
|
|
4116
|
-
diagnose: { category: "component-not-found", screen:
|
|
3083
|
+
diagnose: { category: "component-not-found", screen: chunkV3TUIIT2_js.getCurrentScreen() ?? void 0 }
|
|
4117
3084
|
};
|
|
4118
3085
|
}
|
|
4119
3086
|
return pressTargetByIdOrLabel(id, registry);
|
|
@@ -4133,18 +3100,18 @@ function findField(fieldId, registry) {
|
|
|
4133
3100
|
return registry.getField(comp.id);
|
|
4134
3101
|
}
|
|
4135
3102
|
}
|
|
4136
|
-
const currentScreenForTieBreak =
|
|
4137
|
-
const needle =
|
|
3103
|
+
const currentScreenForTieBreak = chunkV3TUIIT2_js.getCurrentScreen();
|
|
3104
|
+
const needle = chunkV3TUIIT2_js.normalize3(fieldId);
|
|
4138
3105
|
let bestComp;
|
|
4139
3106
|
let bestScore = 0;
|
|
4140
3107
|
let bestOnCurrentScreen = false;
|
|
4141
3108
|
for (const comp of snapshot) {
|
|
4142
3109
|
if (comp.kind !== "field") continue;
|
|
4143
|
-
const candidates = [
|
|
4144
|
-
if (comp.label) candidates.push(
|
|
3110
|
+
const candidates = [chunkV3TUIIT2_js.normalize3(comp.id)];
|
|
3111
|
+
if (comp.label) candidates.push(chunkV3TUIIT2_js.normalize3(comp.label));
|
|
4145
3112
|
let candidateScore = 0;
|
|
4146
3113
|
for (const cand of candidates) {
|
|
4147
|
-
const s =
|
|
3114
|
+
const s = chunkV3TUIIT2_js.matchScore(needle, cand);
|
|
4148
3115
|
if (s > candidateScore) candidateScore = s;
|
|
4149
3116
|
}
|
|
4150
3117
|
if (candidateScore === 0) continue;
|
|
@@ -4162,9 +3129,9 @@ function findField(fieldId, registry) {
|
|
|
4162
3129
|
);
|
|
4163
3130
|
return registry.getField(bestComp.id);
|
|
4164
3131
|
}
|
|
4165
|
-
const currentScreen =
|
|
3132
|
+
const currentScreen = chunkV3TUIIT2_js.getCurrentScreen();
|
|
4166
3133
|
if (currentScreen) {
|
|
4167
|
-
const screenMeta =
|
|
3134
|
+
const screenMeta = chunkV3TUIIT2_js.getScreenMetadata(currentScreen);
|
|
4168
3135
|
const fields = screenMeta?.fields;
|
|
4169
3136
|
if (fields && Array.isArray(fields)) {
|
|
4170
3137
|
const metaField = fields.find(
|
|
@@ -4172,12 +3139,12 @@ function findField(fieldId, registry) {
|
|
|
4172
3139
|
);
|
|
4173
3140
|
if (metaField && typeof metaField === "object" && metaField.label) {
|
|
4174
3141
|
const metaLabel = metaField.label;
|
|
4175
|
-
const metaNeedle =
|
|
3142
|
+
const metaNeedle = chunkV3TUIIT2_js.normalize3(metaLabel);
|
|
4176
3143
|
let mBest;
|
|
4177
3144
|
let mBestScore = 0;
|
|
4178
3145
|
for (const comp of snapshot) {
|
|
4179
3146
|
if (comp.kind !== "field" || !comp.label) continue;
|
|
4180
|
-
const score =
|
|
3147
|
+
const score = chunkV3TUIIT2_js.matchScore(metaNeedle, chunkV3TUIIT2_js.normalize3(comp.label));
|
|
4181
3148
|
if (score > mBestScore) {
|
|
4182
3149
|
mBestScore = score;
|
|
4183
3150
|
mBest = comp;
|
|
@@ -4198,7 +3165,7 @@ function findField(fieldId, registry) {
|
|
|
4198
3165
|
);
|
|
4199
3166
|
return registry.getField(bestComp.id);
|
|
4200
3167
|
}
|
|
4201
|
-
|
|
3168
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4202
3169
|
`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"}`
|
|
4203
3170
|
);
|
|
4204
3171
|
return void 0;
|
|
@@ -4218,7 +3185,7 @@ function findToggle(fieldId, registry) {
|
|
|
4218
3185
|
return registry.getToggle(comp.id);
|
|
4219
3186
|
}
|
|
4220
3187
|
}
|
|
4221
|
-
|
|
3188
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4222
3189
|
`findToggle: NOT FOUND \u2014 fieldId="${fieldId}" not in registry. Available toggles: ${snapshot.filter((c) => c.kind === "toggle").map((c) => `"${c.id}"`).join(", ") || "none"}`
|
|
4223
3190
|
);
|
|
4224
3191
|
return void 0;
|
|
@@ -4238,7 +3205,7 @@ function findSlider(fieldId, registry) {
|
|
|
4238
3205
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
4239
3206
|
async function formFillHandler(payload, context) {
|
|
4240
3207
|
const { permissions } = context;
|
|
4241
|
-
const registry = context.registry ??
|
|
3208
|
+
const registry = context.registry ?? chunkV3TUIIT2_js.componentRegistry;
|
|
4242
3209
|
const { screen, activePath } = resolveScreenContext();
|
|
4243
3210
|
const screenPath = activePath.length > 1 ? activePath.join("/") : screen;
|
|
4244
3211
|
if (!permissions.canFillForms) {
|
|
@@ -4257,7 +3224,7 @@ async function formFillHandler(payload, context) {
|
|
|
4257
3224
|
}
|
|
4258
3225
|
const registrySnapshot = registry.snapshot();
|
|
4259
3226
|
if (registrySnapshot.length === 0) {
|
|
4260
|
-
|
|
3227
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4261
3228
|
"formFillHandler: registry is EMPTY \u2014 auto-tracking may not be active. Ensure enableAppilotsAutoTracking() runs before components mount."
|
|
4262
3229
|
);
|
|
4263
3230
|
} else {
|
|
@@ -4331,7 +3298,7 @@ async function formFillHandler(payload, context) {
|
|
|
4331
3298
|
after = fieldEntry.getValue?.() ?? "";
|
|
4332
3299
|
}
|
|
4333
3300
|
if (!selectValueApplied(fieldId, value, after, registry)) {
|
|
4334
|
-
|
|
3301
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4335
3302
|
`formFillHandler: select field "${fieldId}" setValue("${value}") did not stick (current="${after}"), trying visible choice fallback`
|
|
4336
3303
|
);
|
|
4337
3304
|
const selectResult = await selectVisibleChoice(fieldId, value, registry, {
|
|
@@ -4504,14 +3471,14 @@ async function formFillHandler(payload, context) {
|
|
|
4504
3471
|
if (payload.submitAfterFill === true) {
|
|
4505
3472
|
if (!allSuccess) {
|
|
4506
3473
|
const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
|
|
4507
|
-
|
|
3474
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4508
3475
|
"formFillHandler: submitAfterFill=true requested but some fields failed; NOT submitting" + (failedIds.length > 0 ? ` (failed: ${failedIds.join(", ")})` : "")
|
|
4509
3476
|
);
|
|
4510
3477
|
} else {
|
|
4511
3478
|
await sleep2(120);
|
|
4512
3479
|
const submitResult = pressSubmitButton({ screen, screenPath, activePath }, registry);
|
|
4513
3480
|
if (!submitResult.success) {
|
|
4514
|
-
|
|
3481
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(`formFillHandler: submitAfterFill failed \u2014 ${submitResult.error}`);
|
|
4515
3482
|
return {
|
|
4516
3483
|
success: false,
|
|
4517
3484
|
error: submitResult.error,
|
|
@@ -4523,7 +3490,7 @@ async function formFillHandler(payload, context) {
|
|
|
4523
3490
|
submitTargetId: submitResult.pressedTargetId
|
|
4524
3491
|
});
|
|
4525
3492
|
if (postSubmit.status === "pending") {
|
|
4526
|
-
|
|
3493
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(`formFillHandler: submit still pending \u2014 ${postSubmit.message}`);
|
|
4527
3494
|
return {
|
|
4528
3495
|
success: false,
|
|
4529
3496
|
error: postSubmit.message,
|
|
@@ -4532,7 +3499,7 @@ async function formFillHandler(payload, context) {
|
|
|
4532
3499
|
};
|
|
4533
3500
|
}
|
|
4534
3501
|
if (postSubmit.status === "failure") {
|
|
4535
|
-
|
|
3502
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4536
3503
|
`formFillHandler: submit rejected by visible validation \u2014 ${postSubmit.message}`
|
|
4537
3504
|
);
|
|
4538
3505
|
return {
|
|
@@ -4559,10 +3526,10 @@ async function formFillHandler(payload, context) {
|
|
|
4559
3526
|
};
|
|
4560
3527
|
}
|
|
4561
3528
|
function pressSubmitButton(context, registry) {
|
|
4562
|
-
const activePath = context.activePath ??
|
|
3529
|
+
const activePath = context.activePath ?? chunkV3TUIIT2_js.getActiveRouteNames();
|
|
4563
3530
|
const hintScreen = context.screen ?? context.screenPath;
|
|
4564
3531
|
const formScreens = resolveFormScreensForSubmit(hintScreen, activePath, registry);
|
|
4565
|
-
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ??
|
|
3532
|
+
const resolvedScreen = formScreens.find((name) => screenDeclaresSubmit(name)) ?? formScreens[0] ?? hintScreen ?? chunkV3TUIIT2_js.getCurrentScreen() ?? void 0;
|
|
4566
3533
|
const candidates = collectSubmitTargetCandidates(formScreens, registry);
|
|
4567
3534
|
for (const candidate of candidates) {
|
|
4568
3535
|
const target = registry.getTarget(candidate);
|
|
@@ -4583,7 +3550,7 @@ function pressSubmitButton(context, registry) {
|
|
|
4583
3550
|
}
|
|
4584
3551
|
}
|
|
4585
3552
|
for (const screenName of formScreens) {
|
|
4586
|
-
const screenMeta =
|
|
3553
|
+
const screenMeta = chunkV3TUIIT2_js.getScreenMetadata(screenName);
|
|
4587
3554
|
const submitMeta = Array.isArray(screenMeta?.actions) ? screenMeta.actions.find(
|
|
4588
3555
|
(action) => typeof action === "object" && action !== null && action.type === "submit"
|
|
4589
3556
|
) : void 0;
|
|
@@ -4689,12 +3656,12 @@ function buildDiagnose(category, targetId, candidates) {
|
|
|
4689
3656
|
return {
|
|
4690
3657
|
category,
|
|
4691
3658
|
targetId,
|
|
4692
|
-
screen:
|
|
3659
|
+
screen: chunkV3TUIIT2_js.getCurrentScreen() ?? void 0,
|
|
4693
3660
|
...candidates && candidates.length > 0 ? { candidates: candidates.slice(0, 8) } : {}
|
|
4694
3661
|
};
|
|
4695
3662
|
}
|
|
4696
3663
|
function resolveListEntry(listId) {
|
|
4697
|
-
const entries =
|
|
3664
|
+
const entries = chunkV3TUIIT2_js.listRegistry.snapshot();
|
|
4698
3665
|
if (entries.length === 0) return {};
|
|
4699
3666
|
if (listId) {
|
|
4700
3667
|
const wanted = normalizeId2(listId);
|
|
@@ -4805,23 +3772,23 @@ function targetIdFromPayload(payload) {
|
|
|
4805
3772
|
}
|
|
4806
3773
|
async function waitForPostInteractionSettle(payload) {
|
|
4807
3774
|
const targetId = targetIdFromPayload(payload);
|
|
4808
|
-
const fromScreen =
|
|
4809
|
-
const baseline =
|
|
3775
|
+
const fromScreen = chunkV3TUIIT2_js.getCurrentScreen();
|
|
3776
|
+
const baseline = chunkV3TUIIT2_js.probeLoadingState(targetId || null, fromScreen);
|
|
4810
3777
|
await sleepMs(100);
|
|
4811
|
-
const afterPress =
|
|
3778
|
+
const afterPress = chunkV3TUIIT2_js.probeLoadingState(targetId || null, chunkV3TUIIT2_js.getCurrentScreen());
|
|
4812
3779
|
const modalOrLoading = afterPress.modalOpen || afterPress.loading || afterPress.pressedDisabled;
|
|
4813
3780
|
const fingerprintChanged = afterPress.fingerprint !== baseline.fingerprint;
|
|
4814
|
-
const capMs =
|
|
3781
|
+
const capMs = chunkV3TUIIT2_js.isListItemPressTarget(targetId) ? 5e3 : 1e4;
|
|
4815
3782
|
if (modalOrLoading || fingerprintChanged) {
|
|
4816
|
-
await
|
|
3783
|
+
await chunkV3TUIIT2_js.waitForLoadingSettle({
|
|
4817
3784
|
pressedComponentId: targetId || null,
|
|
4818
3785
|
fromScreen,
|
|
4819
3786
|
maxMs: capMs
|
|
4820
3787
|
});
|
|
4821
3788
|
return;
|
|
4822
3789
|
}
|
|
4823
|
-
if (
|
|
4824
|
-
await
|
|
3790
|
+
if (chunkV3TUIIT2_js.isListItemPressTarget(targetId)) {
|
|
3791
|
+
await chunkV3TUIIT2_js.waitForLoadingSettle({
|
|
4825
3792
|
fromScreen,
|
|
4826
3793
|
maxMs: 3e3
|
|
4827
3794
|
});
|
|
@@ -4841,7 +3808,7 @@ function validateActionPayload(action) {
|
|
|
4841
3808
|
error: message,
|
|
4842
3809
|
diagnose: {
|
|
4843
3810
|
category: "validation",
|
|
4844
|
-
screen:
|
|
3811
|
+
screen: chunkV3TUIIT2_js.getCurrentScreen() ?? void 0,
|
|
4845
3812
|
...ids ?? {}
|
|
4846
3813
|
}
|
|
4847
3814
|
});
|
|
@@ -4908,7 +3875,7 @@ async function executeAction(action, context) {
|
|
|
4908
3875
|
let result;
|
|
4909
3876
|
const validationFailure = validateActionPayload(action);
|
|
4910
3877
|
if (validationFailure) {
|
|
4911
|
-
|
|
3878
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4912
3879
|
`executeAction: payload validation failed for type="${action.type}" id="${action.id}": ${validationFailure.error}`
|
|
4913
3880
|
);
|
|
4914
3881
|
context.emit({
|
|
@@ -4935,13 +3902,13 @@ async function executeAction(action, context) {
|
|
|
4935
3902
|
case "form_fill":
|
|
4936
3903
|
result = await formFillHandler(action.payload, {
|
|
4937
3904
|
permissions,
|
|
4938
|
-
registry: context.registry ??
|
|
3905
|
+
registry: context.registry ?? chunkV3TUIIT2_js.getDefaultRegistry()
|
|
4939
3906
|
});
|
|
4940
3907
|
break;
|
|
4941
3908
|
case "ui_interaction":
|
|
4942
3909
|
result = uiInteractionHandler(action.payload, {
|
|
4943
3910
|
permissions,
|
|
4944
|
-
registry: context.registry ??
|
|
3911
|
+
registry: context.registry ?? chunkV3TUIIT2_js.getDefaultRegistry()
|
|
4945
3912
|
});
|
|
4946
3913
|
if (result.success) {
|
|
4947
3914
|
await waitForPostInteractionSettle(action.payload);
|
|
@@ -4971,7 +3938,7 @@ async function executeAction(action, context) {
|
|
|
4971
3938
|
};
|
|
4972
3939
|
}
|
|
4973
3940
|
} catch (err) {
|
|
4974
|
-
|
|
3941
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4975
3942
|
`executeAction: exception during action type="${action.type}" id="${action.id}": ${err?.message}`
|
|
4976
3943
|
);
|
|
4977
3944
|
result = {
|
|
@@ -4995,79 +3962,156 @@ async function executeAction(action, context) {
|
|
|
4995
3962
|
});
|
|
4996
3963
|
return result;
|
|
4997
3964
|
}
|
|
4998
|
-
var
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
}
|
|
5007
|
-
|
|
5008
|
-
|
|
3965
|
+
var POST_ACTION_LOADING_MAX_MS = 6e3;
|
|
3966
|
+
function resolveScreenMetadata() {
|
|
3967
|
+
const activePath = chunkV3TUIIT2_js.getActiveRouteNames();
|
|
3968
|
+
for (let i = activePath.length - 1; i >= 0; i--) {
|
|
3969
|
+
const name = activePath[i];
|
|
3970
|
+
const meta = name ? chunkV3TUIIT2_js.getScreenMetadata(name) : void 0;
|
|
3971
|
+
if (meta && (Array.isArray(meta.fields) && meta.fields.length > 0 || Array.isArray(meta.actions) && meta.actions.length > 0)) {
|
|
3972
|
+
return meta;
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
const screen = chunkV3TUIIT2_js.getCurrentScreen();
|
|
3976
|
+
return screen ? chunkV3TUIIT2_js.getScreenMetadata(screen) : void 0;
|
|
5009
3977
|
}
|
|
5010
|
-
function
|
|
5011
|
-
|
|
5012
|
-
|
|
3978
|
+
function buildAgentContext(extras = {}) {
|
|
3979
|
+
const context = {};
|
|
3980
|
+
context.platform = "react-native";
|
|
3981
|
+
const screen = chunkV3TUIIT2_js.getCurrentScreen();
|
|
3982
|
+
if (screen) context.currentScreen = screen;
|
|
3983
|
+
const navigationState = chunkV3TUIIT2_js.getNavigationStateSnapshot();
|
|
3984
|
+
if (navigationState) context.navigationState = navigationState;
|
|
3985
|
+
const screenMeta = resolveScreenMetadata();
|
|
3986
|
+
if (screenMeta) context.screenMetadata = screenMeta;
|
|
3987
|
+
try {
|
|
3988
|
+
context.snapshot = captureSnapshot();
|
|
3989
|
+
} catch (err) {
|
|
3990
|
+
chunkV3TUIIT2_js.appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
|
|
3991
|
+
}
|
|
3992
|
+
const registry = chunkV3TUIIT2_js.componentRegistry.snapshot();
|
|
3993
|
+
const filtered = screen ? registry.filter((c) => !c.screen || c.screen === screen) : registry;
|
|
3994
|
+
if (filtered.length > 0) context.registeredComponents = filtered;
|
|
3995
|
+
const registeredLists = chunkV3TUIIT2_js.listRegistry.snapshot();
|
|
3996
|
+
if (registeredLists.length > 0) {
|
|
3997
|
+
context.registeredLists = registeredLists.map(
|
|
3998
|
+
({ scrollToIndex, scrollToOffset, getScrollMetrics, dataPreview, ...rest }) => rest
|
|
3999
|
+
);
|
|
5013
4000
|
}
|
|
5014
|
-
|
|
4001
|
+
if (extras.loadingPending === true) context.loadingPending = true;
|
|
4002
|
+
return context;
|
|
5015
4003
|
}
|
|
5016
|
-
function
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
source: "action-policy"
|
|
5023
|
-
};
|
|
4004
|
+
function resolveActionHints(screen, pressedComponentId, actionPayload) {
|
|
4005
|
+
if (actionPayload && typeof actionPayload === "object") {
|
|
4006
|
+
const inline = actionPayload._appilotsInferred;
|
|
4007
|
+
if (inline && typeof inline === "object") {
|
|
4008
|
+
return inline;
|
|
4009
|
+
}
|
|
5024
4010
|
}
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
4011
|
+
if (!screen || !pressedComponentId) return void 0;
|
|
4012
|
+
const meta = chunkV3TUIIT2_js.getScreenMetadata(screen);
|
|
4013
|
+
const actions = meta?.actions;
|
|
4014
|
+
if (!actions || actions.length === 0) return void 0;
|
|
4015
|
+
for (const a of actions) {
|
|
4016
|
+
if (typeof a === "string") continue;
|
|
4017
|
+
if (chunkV3TUIIT2_js.idLooselyMatches(a.id, pressedComponentId)) {
|
|
4018
|
+
const inferred = a.appilotsInferred;
|
|
4019
|
+
if (inferred && typeof inferred === "object") return inferred;
|
|
4020
|
+
return void 0;
|
|
5034
4021
|
}
|
|
5035
4022
|
}
|
|
5036
|
-
return
|
|
5037
|
-
}
|
|
5038
|
-
function isConfirmGateFor(confirm, target) {
|
|
5039
|
-
if (confirm.type !== "confirm") return false;
|
|
5040
|
-
const payload = readPayload(confirm);
|
|
5041
|
-
const injectedBy = payload.injectedBy;
|
|
5042
|
-
return payload.gatedActionId === target.id && (injectedBy === "permissions" || injectedBy === "sdk-local");
|
|
5043
|
-
}
|
|
5044
|
-
function toDestructiveConfirmPayload(confirm, policy, fallbackLabel) {
|
|
5045
|
-
const payload = readPayload(confirm);
|
|
5046
|
-
const existingDescription = typeof payload.actionDescription === "string" && payload.actionDescription ? payload.actionDescription : void 0;
|
|
5047
|
-
const labelText = policy.label ?? existingDescription ?? fallbackLabel ?? "esta a\xE7\xE3o";
|
|
5048
|
-
return {
|
|
5049
|
-
...payload,
|
|
5050
|
-
title: "A\xE7\xE3o destrutiva",
|
|
5051
|
-
message: `Tem certeza que deseja "${labelText}"?`,
|
|
5052
|
-
actionDescription: labelText,
|
|
5053
|
-
severity: "danger",
|
|
5054
|
-
destructive: true,
|
|
5055
|
-
confirmLabel: typeof payload.confirmLabel === "string" && payload.confirmLabel ? payload.confirmLabel : "Sim, executar",
|
|
5056
|
-
cancelLabel: typeof payload.cancelLabel === "string" && payload.cancelLabel ? payload.cancelLabel : "Cancelar"
|
|
5057
|
-
};
|
|
5058
|
-
}
|
|
5059
|
-
function confirmNeedsDestructiveUpgrade(confirm) {
|
|
5060
|
-
const payload = readPayload(confirm);
|
|
5061
|
-
return confirm.destructive !== true || payload.destructive !== true || payload.severity !== "danger";
|
|
4023
|
+
return void 0;
|
|
5062
4024
|
}
|
|
5063
|
-
function
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
4025
|
+
async function settleTurn(input) {
|
|
4026
|
+
const toolWithoutEffectIds = /* @__PURE__ */ new Set();
|
|
4027
|
+
let loadingPending = false;
|
|
4028
|
+
const { turnActions, pressedComponentId: pressedId, navigateTargetScreen } = input;
|
|
4029
|
+
const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
|
|
4030
|
+
const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
|
|
4031
|
+
if (input.hadNavigate) {
|
|
4032
|
+
const settle = await chunkV3TUIIT2_js.waitForScreenSettle({
|
|
4033
|
+
expectingChange: true,
|
|
4034
|
+
fromScreen: input.preNavigateScreen ?? null,
|
|
4035
|
+
fromSignature: input.preNavigateSignature ?? null,
|
|
4036
|
+
targetScreen: navigateTargetScreen,
|
|
4037
|
+
maxMs: 3500
|
|
4038
|
+
});
|
|
4039
|
+
console.log(
|
|
4040
|
+
`[Appilots] settleTurn: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
4041
|
+
);
|
|
4042
|
+
const navigationMoved = settle.transitioned || chunkV3TUIIT2_js.screenDepartedBaseline(
|
|
4043
|
+
input.preNavigateScreen ?? null,
|
|
4044
|
+
input.preNavigateSignature ?? null
|
|
4045
|
+
) || !!navigateTargetScreen && !!settle.screen && chunkV3TUIIT2_js.routesBelongToSameFeature(settle.screen, navigateTargetScreen);
|
|
4046
|
+
if (!navigationMoved) {
|
|
4047
|
+
chunkV3TUIIT2_js.appilotsDebugWarn(
|
|
4048
|
+
`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.`
|
|
4049
|
+
);
|
|
4050
|
+
for (const [actionId, type] of typeById) {
|
|
4051
|
+
if (type === "navigate") toolWithoutEffectIds.add(actionId);
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
const loadSettle = await chunkV3TUIIT2_js.waitForLoadingSettle({
|
|
4055
|
+
fromScreen: settle.screen ?? null,
|
|
4056
|
+
maxMs: 3e3
|
|
4057
|
+
});
|
|
4058
|
+
console.log(
|
|
4059
|
+
`[Appilots] settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs}`
|
|
4060
|
+
);
|
|
4061
|
+
if (loadSettle.loadingPending) loadingPending = true;
|
|
4062
|
+
} else {
|
|
4063
|
+
const pressedAction = turnActions.find(
|
|
4064
|
+
(a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
|
|
4065
|
+
);
|
|
4066
|
+
const hints = resolveActionHints(chunkV3TUIIT2_js.getCurrentScreen(), pressedId, pressedAction?.payload);
|
|
4067
|
+
const settleCapMs = hints?.isAsyncTrigger === true ? 1e4 : POST_ACTION_LOADING_MAX_MS;
|
|
4068
|
+
const loadSettle = await chunkV3TUIIT2_js.waitForLoadingSettle({
|
|
4069
|
+
pressedComponentId: pressedId,
|
|
4070
|
+
fromScreen: chunkV3TUIIT2_js.getCurrentScreen(),
|
|
4071
|
+
maxMs: settleCapMs
|
|
4072
|
+
});
|
|
4073
|
+
console.log(
|
|
4074
|
+
`[Appilots] 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}${hints?.isAsyncTrigger ? " (mcp-inferred)" : ""}`
|
|
4075
|
+
);
|
|
4076
|
+
if (loadSettle.loadingPending) loadingPending = true;
|
|
4077
|
+
const listPressActions = turnActions.filter((action) => {
|
|
4078
|
+
const target = chunkV3TUIIT2_js.actionPressTargetId(action);
|
|
4079
|
+
return target ? chunkV3TUIIT2_js.isListItemPressTarget(target) : false;
|
|
4080
|
+
});
|
|
4081
|
+
if (listPressActions.length > 0) {
|
|
4082
|
+
const baselineFingerprint = chunkV3TUIIT2_js.probeLoadingState(pressedId, chunkV3TUIIT2_js.getCurrentScreen()).fingerprint;
|
|
4083
|
+
const postPressSettle = await chunkV3TUIIT2_js.waitForScreenSettle({
|
|
4084
|
+
expectingChange: true,
|
|
4085
|
+
fromScreen: input.preNavigateScreen ?? null,
|
|
4086
|
+
fromSignature: input.preNavigateSignature ?? null,
|
|
4087
|
+
maxMs: 2500
|
|
4088
|
+
});
|
|
4089
|
+
await chunkV3TUIIT2_js.waitForLoadingSettle({
|
|
4090
|
+
pressedComponentId: pressedId,
|
|
4091
|
+
fromScreen: chunkV3TUIIT2_js.getCurrentScreen(),
|
|
4092
|
+
maxMs: 4e3
|
|
4093
|
+
});
|
|
4094
|
+
const afterFingerprint = chunkV3TUIIT2_js.probeLoadingState(pressedId, chunkV3TUIIT2_js.getCurrentScreen()).fingerprint;
|
|
4095
|
+
console.log(
|
|
4096
|
+
`[Appilots] settleTurn: post-list-press settle \u2014 screen="${postPressSettle.screen}" transitioned=${postPressSettle.transitioned} timedOut=${postPressSettle.timedOut} waitedMs=${postPressSettle.waitedMs}`
|
|
4097
|
+
);
|
|
4098
|
+
if (!postPressSettle.transitioned && baselineFingerprint === afterFingerprint) {
|
|
4099
|
+
for (const action of listPressActions) {
|
|
4100
|
+
if (successById.get(action.id)) {
|
|
4101
|
+
toolWithoutEffectIds.add(action.id);
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
return { loadingPending, toolWithoutEffectIds };
|
|
5070
4108
|
}
|
|
4109
|
+
var reactNativeChatAdapter = {
|
|
4110
|
+
buildContext: buildAgentContext,
|
|
4111
|
+
getCurrentScreen: chunkV3TUIIT2_js.getCurrentScreen,
|
|
4112
|
+
getCurrentScreenSignature: chunkV3TUIIT2_js.getCurrentScreenSignature,
|
|
4113
|
+
settleTurn
|
|
4114
|
+
};
|
|
5071
4115
|
async function runWithConfirmedDestructiveContext(enabled, fn) {
|
|
5072
4116
|
if (!enabled) return fn();
|
|
5073
4117
|
const originalAlert = reactNative.Alert.alert;
|
|
@@ -5097,321 +4141,120 @@ async function runWithConfirmedDestructiveContext(enabled, fn) {
|
|
|
5097
4141
|
reactNative.Alert.alert = originalAlert;
|
|
5098
4142
|
}
|
|
5099
4143
|
}
|
|
5100
|
-
function
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
if (!action?.id) return;
|
|
5113
|
-
console.log(
|
|
5114
|
-
`[Appilots] useAppilotsActions: received agent:action:start event, action id="${action.id}", type="${action.type}"`
|
|
5115
|
-
);
|
|
5116
|
-
setActions((prev) => {
|
|
5117
|
-
if (prev.some((a) => a.id === action.id)) return prev;
|
|
5118
|
-
return [...prev, action];
|
|
5119
|
-
});
|
|
5120
|
-
}
|
|
5121
|
-
});
|
|
5122
|
-
return unsubscribe;
|
|
5123
|
-
}, [subscribe]);
|
|
5124
|
-
const processedRef = react.useRef(/* @__PURE__ */ new Set());
|
|
5125
|
-
react.useEffect(() => {
|
|
5126
|
-
if (!autoExecute) return;
|
|
5127
|
-
const pending = actions.filter(
|
|
5128
|
-
(a) => a.status === "pending" && !processedRef.current.has(a.id)
|
|
5129
|
-
);
|
|
5130
|
-
console.log(`[Appilots] useAppilotsActions: autoExecute check \u2014 ${pending.length} pending action(s) to process`);
|
|
5131
|
-
const findGatingConfirm = (target) => {
|
|
5132
|
-
return actions.find((a) => {
|
|
5133
|
-
if (a.type !== "confirm") return false;
|
|
5134
|
-
const payload = a.payload;
|
|
5135
|
-
const injectedBy = payload?.injectedBy;
|
|
5136
|
-
return payload?.gatedActionId === target.id && (injectedBy === "permissions" || injectedBy === "sdk-local");
|
|
5137
|
-
});
|
|
5138
|
-
};
|
|
5139
|
-
const ensureLocalConfirmIfNeeded = (target) => {
|
|
5140
|
-
if (target.type !== "ui_interaction") return false;
|
|
5141
|
-
const payload = target.payload;
|
|
5142
|
-
const componentId = typeof payload?.componentId === "string" && payload.componentId || typeof payload?.targetId === "string" && payload.targetId || "";
|
|
5143
|
-
let policy = payloadRequiresConfirmation(target);
|
|
5144
|
-
if (!policy.required && componentId) {
|
|
5145
|
-
const screen = chunkMCY5YFYD_js.getCurrentScreen();
|
|
5146
|
-
const meta = screen ? chunkMCY5YFYD_js.getScreenMetadata(screen) : void 0;
|
|
5147
|
-
const actionsMeta = meta?.actions;
|
|
5148
|
-
if (actionsMeta && Array.isArray(actionsMeta)) {
|
|
5149
|
-
const match = actionsMeta.find((a) => {
|
|
5150
|
-
if (typeof a === "string") return false;
|
|
5151
|
-
return chunkMCY5YFYD_js.metadataMatchesComponentId(a.id, componentId);
|
|
5152
|
-
});
|
|
5153
|
-
if (match && typeof match !== "string") {
|
|
5154
|
-
policy = actionMetadataRequiresConfirmation(match);
|
|
5155
|
-
}
|
|
5156
|
-
}
|
|
5157
|
-
}
|
|
5158
|
-
const existingGate = findGatingConfirm(target);
|
|
5159
|
-
if (existingGate) {
|
|
5160
|
-
if (policy.required && confirmNeedsDestructiveUpgrade(existingGate)) {
|
|
5161
|
-
setActions(
|
|
5162
|
-
(prev) => prev.map(
|
|
5163
|
-
(a) => a.id === existingGate.id ? {
|
|
5164
|
-
...a,
|
|
5165
|
-
destructive: true,
|
|
5166
|
-
payload: toDestructiveConfirmPayload(
|
|
5167
|
-
a,
|
|
5168
|
-
policy,
|
|
5169
|
-
componentId || target.id
|
|
5170
|
-
)
|
|
5171
|
-
} : a
|
|
5172
|
-
)
|
|
5173
|
-
);
|
|
5174
|
-
}
|
|
5175
|
-
return false;
|
|
5176
|
-
}
|
|
5177
|
-
if (!policy.required) return false;
|
|
5178
|
-
const confirmId = `confirm-local-${target.id}`;
|
|
5179
|
-
setActions((prev) => {
|
|
5180
|
-
const existingGate2 = prev.some((a) => {
|
|
5181
|
-
if (a.type !== "confirm") return false;
|
|
5182
|
-
const p = a.payload;
|
|
5183
|
-
if (!p || p.gatedActionId !== target.id) return false;
|
|
5184
|
-
return p.injectedBy === "permissions" || p.injectedBy === "sdk-local";
|
|
5185
|
-
});
|
|
5186
|
-
if (existingGate2) {
|
|
5187
|
-
const gateToUpgrade = prev.find(
|
|
5188
|
-
(a) => isConfirmGateFor(a, target) && confirmNeedsDestructiveUpgrade(a)
|
|
5189
|
-
);
|
|
5190
|
-
if (!gateToUpgrade) return prev;
|
|
5191
|
-
return prev.map(
|
|
5192
|
-
(a) => a.id === gateToUpgrade.id ? {
|
|
5193
|
-
...a,
|
|
5194
|
-
destructive: true,
|
|
5195
|
-
payload: toDestructiveConfirmPayload(
|
|
5196
|
-
a,
|
|
5197
|
-
policy,
|
|
5198
|
-
componentId || target.id
|
|
5199
|
-
)
|
|
5200
|
-
} : a
|
|
5201
|
-
);
|
|
5202
|
-
}
|
|
5203
|
-
if (prev.some((a) => a.id === confirmId)) return prev;
|
|
5204
|
-
console.log(
|
|
5205
|
-
`[Appilots] useAppilotsActions: action "${componentId || target.id}" requires confirmation (${policy.source ?? "local-policy"}) \u2014 synthesising local confirm (id="${confirmId}")`
|
|
5206
|
-
);
|
|
5207
|
-
const synth = {
|
|
5208
|
-
id: confirmId,
|
|
5209
|
-
type: "confirm",
|
|
5210
|
-
payload: toDestructiveConfirmPayload(
|
|
5211
|
-
{
|
|
5212
|
-
payload: {
|
|
5213
|
-
gatedActionId: target.id,
|
|
5214
|
-
gatedActionType: target.type,
|
|
5215
|
-
injectedBy: "sdk-local"
|
|
5216
|
-
},
|
|
5217
|
-
messageId: target.messageId
|
|
5218
|
-
},
|
|
5219
|
-
policy,
|
|
5220
|
-
componentId || "esta a\xE7\xE3o"
|
|
5221
|
-
),
|
|
5222
|
-
status: "pending",
|
|
5223
|
-
messageId: target.messageId
|
|
5224
|
-
};
|
|
5225
|
-
emit({
|
|
5226
|
-
type: "agent:action:start",
|
|
5227
|
-
timestamp: Date.now(),
|
|
5228
|
-
data: { action: synth }
|
|
5229
|
-
});
|
|
5230
|
-
const idx = prev.findIndex((a) => a.id === target.id);
|
|
5231
|
-
if (idx < 0) return [...prev, synth];
|
|
5232
|
-
return [...prev.slice(0, idx), synth, ...prev.slice(idx)];
|
|
5233
|
-
});
|
|
5234
|
-
return true;
|
|
5235
|
-
};
|
|
5236
|
-
const executeSequentially = async () => {
|
|
5237
|
-
let lastWasNavigate = false;
|
|
5238
|
-
let preNavScreen = null;
|
|
5239
|
-
let preNavSignature = null;
|
|
5240
|
-
for (const action of pending) {
|
|
5241
|
-
if (action.type === "confirm") {
|
|
5242
|
-
continue;
|
|
5243
|
-
}
|
|
5244
|
-
if (ensureLocalConfirmIfNeeded(action)) {
|
|
5245
|
-
continue;
|
|
5246
|
-
}
|
|
5247
|
-
const gate = findGatingConfirm(action);
|
|
5248
|
-
if (gate) {
|
|
5249
|
-
if (gate.status === "pending" || gate.status === "executing") {
|
|
5250
|
-
console.log(
|
|
5251
|
-
`[Appilots] useAppilotsActions: action id="${action.id}" is gated by confirm id="${gate.id}" (status=${gate.status}); waiting for user decision`
|
|
5252
|
-
);
|
|
5253
|
-
continue;
|
|
5254
|
-
}
|
|
5255
|
-
if (gate.status === "failed") {
|
|
5256
|
-
console.log(
|
|
5257
|
-
`[Appilots] useAppilotsActions: confirm id="${gate.id}" was rejected; skipping gated action id="${action.id}"`
|
|
5258
|
-
);
|
|
5259
|
-
processedRef.current.add(action.id);
|
|
5260
|
-
setActions(
|
|
5261
|
-
(prev) => prev.map(
|
|
5262
|
-
(a) => a.id === action.id ? { ...a, status: "failed", error: "Confirm canceled by user" } : a
|
|
5263
|
-
)
|
|
5264
|
-
);
|
|
5265
|
-
try {
|
|
5266
|
-
await client.completeAction(action.id, false, "Confirm canceled by user");
|
|
5267
|
-
} catch {
|
|
5268
|
-
}
|
|
5269
|
-
emit({
|
|
5270
|
-
type: "agent:action:error",
|
|
5271
|
-
timestamp: Date.now(),
|
|
5272
|
-
data: {
|
|
5273
|
-
actionId: action.id,
|
|
5274
|
-
actionType: action.type,
|
|
5275
|
-
success: false,
|
|
5276
|
-
error: "Confirm canceled by user"
|
|
5277
|
-
}
|
|
5278
|
-
});
|
|
5279
|
-
continue;
|
|
5280
|
-
}
|
|
5281
|
-
}
|
|
5282
|
-
if (lastWasNavigate) {
|
|
5283
|
-
const settle = await chunkMCY5YFYD_js.waitForScreenSettle({
|
|
5284
|
-
expectingChange: true,
|
|
5285
|
-
fromScreen: preNavScreen,
|
|
5286
|
-
fromSignature: preNavSignature,
|
|
5287
|
-
maxMs: 3500
|
|
5288
|
-
});
|
|
5289
|
-
console.log(
|
|
5290
|
-
`[Appilots] useAppilotsActions: post-navigate settle done \u2014 screen="${settle.screen}" transitioned=${settle.transitioned} timedOut=${settle.timedOut} waitedMs=${settle.waitedMs}`
|
|
5291
|
-
);
|
|
5292
|
-
}
|
|
5293
|
-
console.log(`[Appilots] useAppilotsActions: auto-executing action id="${action.id}" type="${action.type}"`);
|
|
5294
|
-
processedRef.current.add(action.id);
|
|
5295
|
-
if (action.type === "navigate") {
|
|
5296
|
-
preNavScreen = chunkMCY5YFYD_js.getCurrentScreen();
|
|
5297
|
-
preNavSignature = chunkMCY5YFYD_js.getCurrentScreenSignature();
|
|
5298
|
-
}
|
|
5299
|
-
const succeeded = await approveActionImpl(action.id);
|
|
5300
|
-
if (!succeeded) {
|
|
5301
|
-
chunkMCY5YFYD_js.appilotsDebugWarn(
|
|
5302
|
-
`useAppilotsActions: stopping current action batch after failed action id="${action.id}"`
|
|
5303
|
-
);
|
|
5304
|
-
break;
|
|
5305
|
-
}
|
|
5306
|
-
lastWasNavigate = action.type === "navigate";
|
|
5307
|
-
}
|
|
5308
|
-
};
|
|
5309
|
-
void executeSequentially();
|
|
5310
|
-
}, [actions, autoExecute]);
|
|
5311
|
-
const approveActionImpl = react.useCallback(
|
|
5312
|
-
async (actionId) => {
|
|
5313
|
-
const action = actionsRef.current.find((a) => a.id === actionId);
|
|
5314
|
-
if (!action) return false;
|
|
5315
|
-
console.log(`[Appilots] useAppilotsActions: action status transition: pending \u2192 executing (id="${actionId}", type="${action.type}")`);
|
|
5316
|
-
setActions(
|
|
5317
|
-
(prev) => prev.map((a) => a.id === actionId ? { ...a, status: "executing" } : a)
|
|
4144
|
+
function createReactNativeActionRunner(getOptions) {
|
|
4145
|
+
return {
|
|
4146
|
+
async execute(action, { confirmedDestructive }) {
|
|
4147
|
+
const { permissions, emit, navigationRef } = getOptions();
|
|
4148
|
+
const navRef = navigationRef?.current ? navigationRef : { current: chunkV3TUIIT2_js.getNavigationRef() };
|
|
4149
|
+
return runWithConfirmedDestructiveContext(
|
|
4150
|
+
confirmedDestructive,
|
|
4151
|
+
() => executeAction(action, {
|
|
4152
|
+
navigationRef: navRef,
|
|
4153
|
+
permissions,
|
|
4154
|
+
emit
|
|
4155
|
+
})
|
|
5318
4156
|
);
|
|
5319
|
-
try {
|
|
5320
|
-
const navRef = navRefStable.current?.current ? navRefStable.current : { current: chunkMCY5YFYD_js.getNavigationRef() };
|
|
5321
|
-
const confirmedDestructive = actionHasCompletedConfirmGate(
|
|
5322
|
-
action,
|
|
5323
|
-
actionsRef.current
|
|
5324
|
-
);
|
|
5325
|
-
const result = await runWithConfirmedDestructiveContext(
|
|
5326
|
-
confirmedDestructive,
|
|
5327
|
-
() => executeAction(
|
|
5328
|
-
{ ...action, status: "executing" },
|
|
5329
|
-
{
|
|
5330
|
-
navigationRef: navRef,
|
|
5331
|
-
permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
|
|
5332
|
-
emit
|
|
5333
|
-
}
|
|
5334
|
-
)
|
|
5335
|
-
);
|
|
5336
|
-
if (result.success) {
|
|
5337
|
-
console.log(`[Appilots] useAppilotsActions: action status transition: executing \u2192 completed (id="${actionId}", type="${action.type}")`);
|
|
5338
|
-
setActions(
|
|
5339
|
-
(prev) => prev.map((a) => a.id === actionId ? { ...a, status: "completed" } : a)
|
|
5340
|
-
);
|
|
5341
|
-
try {
|
|
5342
|
-
await client.completeAction(actionId, true);
|
|
5343
|
-
} catch {
|
|
5344
|
-
}
|
|
5345
|
-
return true;
|
|
5346
|
-
} else {
|
|
5347
|
-
chunkMCY5YFYD_js.appilotsDebugWarn(
|
|
5348
|
-
`useAppilotsActions: action status transition: executing \u2192 failed (id="${actionId}", type="${action.type}", error="${result.error}")`
|
|
5349
|
-
);
|
|
5350
|
-
setActions(
|
|
5351
|
-
(prev) => prev.map(
|
|
5352
|
-
(a) => a.id === actionId ? { ...a, status: "failed", error: result.error } : a
|
|
5353
|
-
)
|
|
5354
|
-
);
|
|
5355
|
-
try {
|
|
5356
|
-
await client.completeAction(
|
|
5357
|
-
actionId,
|
|
5358
|
-
false,
|
|
5359
|
-
result.error,
|
|
5360
|
-
result.diagnose
|
|
5361
|
-
);
|
|
5362
|
-
} catch {
|
|
5363
|
-
}
|
|
5364
|
-
return false;
|
|
5365
|
-
}
|
|
5366
|
-
} catch (err) {
|
|
5367
|
-
const errorMsg = err instanceof Error ? err.message : "Action failed";
|
|
5368
|
-
chunkMCY5YFYD_js.appilotsDebugWarn(
|
|
5369
|
-
`useAppilotsActions: action status transition: executing \u2192 failed (exception) (id="${actionId}", error="${errorMsg}")`
|
|
5370
|
-
);
|
|
5371
|
-
setActions(
|
|
5372
|
-
(prev) => prev.map(
|
|
5373
|
-
(a) => a.id === actionId ? { ...a, status: "failed", error: errorMsg } : a
|
|
5374
|
-
)
|
|
5375
|
-
);
|
|
5376
|
-
try {
|
|
5377
|
-
await client.completeAction(actionId, false, errorMsg);
|
|
5378
|
-
} catch {
|
|
5379
|
-
}
|
|
5380
|
-
return false;
|
|
5381
|
-
}
|
|
5382
4157
|
},
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
setActions(
|
|
5388
|
-
(prev) => prev.map(
|
|
5389
|
-
(a) => a.id === actionId ? { ...a, status: "failed", error: "Rejected by user" } : a
|
|
5390
|
-
)
|
|
5391
|
-
);
|
|
5392
|
-
const action = actionsRef.current.find((a) => a.id === actionId);
|
|
5393
|
-
emit({
|
|
5394
|
-
type: "agent:action:error",
|
|
5395
|
-
timestamp: Date.now(),
|
|
5396
|
-
data: {
|
|
5397
|
-
actionId,
|
|
5398
|
-
actionType: action?.type,
|
|
5399
|
-
success: false,
|
|
5400
|
-
error: "Rejected by user"
|
|
5401
|
-
}
|
|
5402
|
-
});
|
|
5403
|
-
try {
|
|
5404
|
-
await client.completeAction(actionId, false, "Rejected by user");
|
|
5405
|
-
} catch {
|
|
5406
|
-
}
|
|
4158
|
+
getCurrentScreen: chunkV3TUIIT2_js.getCurrentScreen,
|
|
4159
|
+
getCurrentScreenSignature: chunkV3TUIIT2_js.getCurrentScreenSignature,
|
|
4160
|
+
getScreenActionsMetadata(screen) {
|
|
4161
|
+
return chunkV3TUIIT2_js.getScreenMetadata(screen)?.actions;
|
|
5407
4162
|
},
|
|
4163
|
+
waitForScreenSettle: chunkV3TUIIT2_js.waitForScreenSettle
|
|
4164
|
+
};
|
|
4165
|
+
}
|
|
4166
|
+
|
|
4167
|
+
// src/hooks/useAppilotsChat.ts
|
|
4168
|
+
function useAppilotsChat(options = {}) {
|
|
4169
|
+
const { client, emit, subscribe } = chunkV3TUIIT2_js.useAppilotsContext();
|
|
4170
|
+
const machine = react.useMemo(
|
|
4171
|
+
() => new chunkV3TUIIT2_js.ChatSessionMachine(
|
|
4172
|
+
{ client, adapter: reactNativeChatAdapter, emit, warn: chunkV3TUIIT2_js.appilotsDebugWarn },
|
|
4173
|
+
options
|
|
4174
|
+
),
|
|
4175
|
+
// A new machine per client/provider instance — options are pushed in
|
|
4176
|
+
// below so changing copy never resets the transcript.
|
|
4177
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4178
|
+
[client, emit]
|
|
4179
|
+
);
|
|
4180
|
+
const optionsRef = react.useRef(options);
|
|
4181
|
+
optionsRef.current = options;
|
|
4182
|
+
machine.setOptions(options);
|
|
4183
|
+
const state = react.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
|
|
4184
|
+
react.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
|
|
4185
|
+
react.useEffect(() => () => machine.dispose(), [machine]);
|
|
4186
|
+
const requestHuman = react.useCallback(
|
|
4187
|
+
(reason) => machine.requestHuman(reason),
|
|
4188
|
+
[machine]
|
|
4189
|
+
);
|
|
4190
|
+
const sendMessage = react.useCallback((content) => machine.sendMessage(content), [machine]);
|
|
4191
|
+
const cancelMessage = react.useCallback(() => machine.cancelMessage(), [machine]);
|
|
4192
|
+
const clearMessages = react.useCallback(() => machine.clearMessages(), [machine]);
|
|
4193
|
+
const clearError = react.useCallback(() => machine.clearError(), [machine]);
|
|
4194
|
+
return {
|
|
4195
|
+
messages: state.messages,
|
|
4196
|
+
isLoading: state.isLoading,
|
|
4197
|
+
loadingStatusKey: state.loadingStatusKey,
|
|
4198
|
+
error: state.error,
|
|
4199
|
+
pendingActions: state.pendingActions,
|
|
4200
|
+
escalation: state.escalation,
|
|
4201
|
+
requestHuman,
|
|
4202
|
+
sendMessage,
|
|
4203
|
+
cancelMessage,
|
|
4204
|
+
clearMessages,
|
|
4205
|
+
clearError
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4208
|
+
var DEFAULT_PERMISSIONS2 = {
|
|
4209
|
+
canNavigate: true,
|
|
4210
|
+
canFillForms: true,
|
|
4211
|
+
canInteractUI: true,
|
|
4212
|
+
canSubmitForms: true
|
|
4213
|
+
};
|
|
4214
|
+
function useAppilotsActions(options = {}) {
|
|
4215
|
+
const { client, subscribe, config, emit } = chunkV3TUIIT2_js.useAppilotsContext();
|
|
4216
|
+
const { navigationRef, autoExecute = false } = options;
|
|
4217
|
+
const runnerOptionsRef = react.useRef({
|
|
4218
|
+
permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
|
|
4219
|
+
emit,
|
|
4220
|
+
navigationRef
|
|
4221
|
+
});
|
|
4222
|
+
runnerOptionsRef.current = {
|
|
4223
|
+
permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
|
|
4224
|
+
emit,
|
|
4225
|
+
navigationRef
|
|
4226
|
+
};
|
|
4227
|
+
const machine = react.useMemo(
|
|
4228
|
+
() => new chunkV3TUIIT2_js.ActionQueueMachine(
|
|
4229
|
+
{
|
|
4230
|
+
client,
|
|
4231
|
+
adapter: createReactNativeActionRunner(() => runnerOptionsRef.current),
|
|
4232
|
+
emit,
|
|
4233
|
+
warn: chunkV3TUIIT2_js.appilotsDebugWarn
|
|
4234
|
+
},
|
|
4235
|
+
{ autoExecute }
|
|
4236
|
+
),
|
|
4237
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5408
4238
|
[client, emit]
|
|
5409
4239
|
);
|
|
4240
|
+
machine.setOptions({ autoExecute });
|
|
4241
|
+
const state = react.useSyncExternalStore(machine.subscribeState, machine.getState, machine.getState);
|
|
4242
|
+
react.useEffect(() => subscribe(machine.handleEvent), [subscribe, machine]);
|
|
4243
|
+
react.useEffect(() => {
|
|
4244
|
+
if (autoExecute) machine.scheduleDrain();
|
|
4245
|
+
}, [autoExecute, machine, state.actions]);
|
|
4246
|
+
const approveAction = react.useCallback(
|
|
4247
|
+
(actionId) => machine.approveAction(actionId),
|
|
4248
|
+
[machine]
|
|
4249
|
+
);
|
|
4250
|
+
const rejectAction = react.useCallback((actionId) => machine.rejectAction(actionId), [machine]);
|
|
5410
4251
|
return {
|
|
5411
|
-
pendingActions: actions.filter((a) => a.status === "pending"),
|
|
5412
|
-
executingActions: actions.filter((a) => a.status === "executing"),
|
|
5413
|
-
completedActions: actions.filter(
|
|
5414
|
-
|
|
4252
|
+
pendingActions: state.actions.filter((a) => a.status === "pending"),
|
|
4253
|
+
executingActions: state.actions.filter((a) => a.status === "executing"),
|
|
4254
|
+
completedActions: state.actions.filter(
|
|
4255
|
+
(a) => a.status === "completed" || a.status === "failed"
|
|
4256
|
+
),
|
|
4257
|
+
approveAction,
|
|
5415
4258
|
rejectAction
|
|
5416
4259
|
};
|
|
5417
4260
|
}
|
|
@@ -5444,7 +4287,7 @@ function shouldShowSuggestedPrompts(args) {
|
|
|
5444
4287
|
|
|
5445
4288
|
// src/hooks/useSuggestedPrompts.ts
|
|
5446
4289
|
function useSuggestedPrompts(options) {
|
|
5447
|
-
const { client } =
|
|
4290
|
+
const { client } = chunkV3TUIIT2_js.useAppilotsContext();
|
|
5448
4291
|
const { enabled, limit = 4 } = options;
|
|
5449
4292
|
const [prompts, setPrompts] = react.useState([]);
|
|
5450
4293
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
@@ -5454,8 +4297,8 @@ function useSuggestedPrompts(options) {
|
|
|
5454
4297
|
if (!enabled) return;
|
|
5455
4298
|
const requestId = ++requestIdRef.current;
|
|
5456
4299
|
let cancelled = false;
|
|
5457
|
-
const screen =
|
|
5458
|
-
const localDev = screen ? (
|
|
4300
|
+
const screen = chunkV3TUIIT2_js.getCurrentScreen() ?? void 0;
|
|
4301
|
+
const localDev = screen ? (chunkV3TUIIT2_js.getScreenMetadata(screen)?.suggestedPrompts ?? []).map((text) => ({
|
|
5459
4302
|
text,
|
|
5460
4303
|
source: "dev-defined"
|
|
5461
4304
|
})) : [];
|
|
@@ -5480,9 +4323,9 @@ function useSuggestedPrompts(options) {
|
|
|
5480
4323
|
}, [client, enabled, limit, refreshTick]);
|
|
5481
4324
|
react.useEffect(() => {
|
|
5482
4325
|
if (!enabled) return;
|
|
5483
|
-
let lastScreen =
|
|
4326
|
+
let lastScreen = chunkV3TUIIT2_js.getCurrentScreen();
|
|
5484
4327
|
const interval = setInterval(() => {
|
|
5485
|
-
const current =
|
|
4328
|
+
const current = chunkV3TUIIT2_js.getCurrentScreen();
|
|
5486
4329
|
if (current !== lastScreen) {
|
|
5487
4330
|
lastScreen = current;
|
|
5488
4331
|
setRefreshTick((t) => t + 1);
|
|
@@ -5497,14 +4340,14 @@ function useSuggestedPrompts(options) {
|
|
|
5497
4340
|
};
|
|
5498
4341
|
}
|
|
5499
4342
|
function useAppilotsNavigation() {
|
|
5500
|
-
const { emit } =
|
|
4343
|
+
const { emit } = chunkV3TUIIT2_js.useAppilotsContext();
|
|
5501
4344
|
const [currentScreen, setCurrentScreenState] = react.useState(null);
|
|
5502
4345
|
const [navigationHistory, setNavigationHistory] = react.useState([]);
|
|
5503
4346
|
const navigationRef = react.useRef(null);
|
|
5504
4347
|
const setCurrentScreen2 = react.useCallback(
|
|
5505
4348
|
(screenName) => {
|
|
5506
4349
|
setCurrentScreenState(screenName);
|
|
5507
|
-
|
|
4350
|
+
chunkV3TUIIT2_js.setCurrentScreen(screenName);
|
|
5508
4351
|
setNavigationHistory((prev) => [...prev, screenName]);
|
|
5509
4352
|
emit({
|
|
5510
4353
|
type: "navigation:change",
|
|
@@ -5535,7 +4378,7 @@ function useAppilotsNavigation() {
|
|
|
5535
4378
|
|
|
5536
4379
|
// src/hooks/useAppilots.ts
|
|
5537
4380
|
function useAppilots() {
|
|
5538
|
-
const { config, client } =
|
|
4381
|
+
const { config, client } = chunkV3TUIIT2_js.useAppilotsContext();
|
|
5539
4382
|
const chat = useAppilotsChat();
|
|
5540
4383
|
const navigation = useAppilotsNavigation();
|
|
5541
4384
|
const actions = useAppilotsActions();
|
|
@@ -5564,7 +4407,7 @@ function useAppilots() {
|
|
|
5564
4407
|
}
|
|
5565
4408
|
function useAppilotsField(id, options) {
|
|
5566
4409
|
const { value, onChangeText, ref, fieldType, label, screen } = options;
|
|
5567
|
-
const registry =
|
|
4410
|
+
const registry = chunkV3TUIIT2_js.useResolvedRegistry();
|
|
5568
4411
|
const valueRef = react.useRef(value);
|
|
5569
4412
|
const onChangeRef = react.useRef(onChangeText);
|
|
5570
4413
|
valueRef.current = value;
|
|
@@ -5592,7 +4435,7 @@ function useAppilotsField(id, options) {
|
|
|
5592
4435
|
}
|
|
5593
4436
|
function useAppilotsTarget(id, options) {
|
|
5594
4437
|
const { onPress, onLongPress, onScrollTo, label, screen } = options;
|
|
5595
|
-
const registry =
|
|
4438
|
+
const registry = chunkV3TUIIT2_js.useResolvedRegistry();
|
|
5596
4439
|
const onPressRef = react.useRef(onPress);
|
|
5597
4440
|
const onLongPressRef = react.useRef(onLongPress);
|
|
5598
4441
|
const onScrollToRef = react.useRef(onScrollTo);
|
|
@@ -5619,7 +4462,7 @@ function useAppilotsTarget(id, options) {
|
|
|
5619
4462
|
}
|
|
5620
4463
|
function useAppilotsToggle(id, options) {
|
|
5621
4464
|
const { value, onValueChange, label, screen } = options;
|
|
5622
|
-
const registry =
|
|
4465
|
+
const registry = chunkV3TUIIT2_js.useResolvedRegistry();
|
|
5623
4466
|
const valueRef = react.useRef(value);
|
|
5624
4467
|
const onChangeRef = react.useRef(onValueChange);
|
|
5625
4468
|
valueRef.current = value;
|
|
@@ -5642,7 +4485,7 @@ function useAppilotsToggle(id, options) {
|
|
|
5642
4485
|
}
|
|
5643
4486
|
function useAppilotsSlider(id, options) {
|
|
5644
4487
|
const { value, onValueChange, min, max, step, label, screen } = options;
|
|
5645
|
-
const registry =
|
|
4488
|
+
const registry = chunkV3TUIIT2_js.useResolvedRegistry();
|
|
5646
4489
|
const valueRef = react.useRef(value);
|
|
5647
4490
|
const onChangeRef = react.useRef(onValueChange);
|
|
5648
4491
|
valueRef.current = value;
|