@appilots/sdk 0.7.0 → 0.8.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.
@@ -76,7 +76,9 @@ var AppilotsClient = class {
76
76
  "Content-Type": "application/json",
77
77
  // Version telemetry: lets the server correlate behavior per SDK
78
78
  // release and pick the MCP doc matching this app build (B.4).
79
- "X-Appilots-Sdk-Version": SDK_VERSION,
79
+ // The platform SDK supplies its own published version; the
80
+ // client-core constant is only the fallback (see `sdkVersion`).
81
+ "X-Appilots-Sdk-Version": options.sdkVersion ?? SDK_VERSION,
80
82
  ...options.appVersion ? { "X-App-Version": options.appVersion } : {},
81
83
  ...options.mcpVersion ? { "X-Appilots-Mcp-Version": options.mcpVersion } : {},
82
84
  ...options.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {},
@@ -191,7 +193,8 @@ var AppilotsClient = class {
191
193
  introspectionFragment() {
192
194
  try {
193
195
  const report = this.introspectionReporter?.();
194
- if (!report || report.captured !== false) return {};
196
+ if (!report) return {};
197
+ if (report.captured !== false && !report.failureReason) return {};
195
198
  return { introspection: report };
196
199
  } catch {
197
200
  return {};
@@ -2842,6 +2845,114 @@ function attachElementIdsToChoiceGroups(choiceGroups, elements) {
2842
2845
  })
2843
2846
  }));
2844
2847
  }
2848
+ var WIRE_LIMITS = {
2849
+ route: 200,
2850
+ texts: 500,
2851
+ textLength: 2e3,
2852
+ inputs: 300,
2853
+ buttons: 300,
2854
+ toggles: 300,
2855
+ sliders: 100,
2856
+ lists: 100,
2857
+ listItems: 500,
2858
+ listDataPreview: 500,
2859
+ listDataPreviewTextLength: 500,
2860
+ choiceGroups: 100,
2861
+ choiceOptions: 200,
2862
+ elements: 1e3,
2863
+ elementTexts: 50,
2864
+ elementTextLength: 500,
2865
+ elementActions: 20,
2866
+ idLength: 160,
2867
+ labelLength: 300,
2868
+ valueLength: 4096,
2869
+ containerTypeLength: 60};
2870
+ var Cut = class {
2871
+ dropped = false;
2872
+ /** Cap an array's length, remembering whether entries were lost. */
2873
+ array(values, max) {
2874
+ if (!values || values.length <= max) return values;
2875
+ this.dropped = true;
2876
+ return values.slice(0, max);
2877
+ }
2878
+ string(value, max) {
2879
+ if (value === void 0 || value.length <= max) return value;
2880
+ this.dropped = true;
2881
+ return value.slice(0, max);
2882
+ }
2883
+ };
2884
+ function clampInput(cut, input) {
2885
+ input.id = cut.string(input.id, WIRE_LIMITS.idLength);
2886
+ input.label = cut.string(input.label, WIRE_LIMITS.labelLength);
2887
+ input.placeholder = cut.string(input.placeholder, WIRE_LIMITS.labelLength);
2888
+ input.value = cut.string(input.value, WIRE_LIMITS.valueLength);
2889
+ return input;
2890
+ }
2891
+ function clampList(cut, list) {
2892
+ list.id = cut.string(list.id, WIRE_LIMITS.idLength);
2893
+ list.containerType = cut.string(list.containerType, WIRE_LIMITS.containerTypeLength);
2894
+ list.label = cut.string(list.label, WIRE_LIMITS.labelLength);
2895
+ list.items = cut.array(list.items, WIRE_LIMITS.listItems) ?? [];
2896
+ if (list.dataPreview) {
2897
+ list.dataPreview = cut.array(list.dataPreview, WIRE_LIMITS.listDataPreview);
2898
+ for (const entry of list.dataPreview ?? []) {
2899
+ entry.key = cut.string(entry.key, WIRE_LIMITS.idLength);
2900
+ entry.text = cut.string(entry.text, WIRE_LIMITS.listDataPreviewTextLength);
2901
+ }
2902
+ }
2903
+ return list;
2904
+ }
2905
+ function clampChoiceGroup(cut, group) {
2906
+ group.id = cut.string(group.id, WIRE_LIMITS.idLength);
2907
+ group.label = cut.string(group.label, WIRE_LIMITS.labelLength);
2908
+ group.options = cut.array(group.options, WIRE_LIMITS.choiceOptions) ?? [];
2909
+ return group;
2910
+ }
2911
+ function clampSnapshotToWireLimits(snapshot) {
2912
+ const cut = new Cut();
2913
+ if (typeof snapshot.route === "string") {
2914
+ snapshot.route = cut.string(snapshot.route, WIRE_LIMITS.route);
2915
+ }
2916
+ snapshot.texts = (cut.array(snapshot.texts, WIRE_LIMITS.texts) ?? []).map(
2917
+ (text) => cut.string(text, WIRE_LIMITS.textLength)
2918
+ );
2919
+ snapshot.inputs = (cut.array(snapshot.inputs, WIRE_LIMITS.inputs) ?? []).map(
2920
+ (input) => clampInput(cut, input)
2921
+ );
2922
+ snapshot.buttons = (cut.array(snapshot.buttons, WIRE_LIMITS.buttons) ?? []).map((button) => {
2923
+ button.id = cut.string(button.id, WIRE_LIMITS.idLength);
2924
+ button.label = cut.string(button.label, WIRE_LIMITS.labelLength);
2925
+ return button;
2926
+ });
2927
+ snapshot.toggles = (cut.array(snapshot.toggles, WIRE_LIMITS.toggles) ?? []).map((toggle) => {
2928
+ toggle.id = cut.string(toggle.id, WIRE_LIMITS.idLength);
2929
+ toggle.label = cut.string(toggle.label, WIRE_LIMITS.labelLength);
2930
+ return toggle;
2931
+ });
2932
+ snapshot.sliders = (cut.array(snapshot.sliders, WIRE_LIMITS.sliders) ?? []).map((slider) => {
2933
+ slider.id = cut.string(slider.id, WIRE_LIMITS.idLength);
2934
+ slider.label = cut.string(slider.label, WIRE_LIMITS.labelLength);
2935
+ return slider;
2936
+ });
2937
+ snapshot.lists = (cut.array(snapshot.lists, WIRE_LIMITS.lists) ?? []).map(
2938
+ (list) => clampList(cut, list)
2939
+ );
2940
+ snapshot.choiceGroups = (cut.array(snapshot.choiceGroups, WIRE_LIMITS.choiceGroups) ?? []).map(
2941
+ (group) => clampChoiceGroup(cut, group)
2942
+ );
2943
+ snapshot.elements = (cut.array(snapshot.elements, WIRE_LIMITS.elements) ?? []).map((element) => {
2944
+ element.id = cut.string(element.id, WIRE_LIMITS.idLength);
2945
+ element.label = cut.string(element.label, WIRE_LIMITS.labelLength);
2946
+ element.targetId = cut.string(element.targetId, WIRE_LIMITS.idLength);
2947
+ element.texts = (cut.array(element.texts, WIRE_LIMITS.elementTexts) ?? []).map(
2948
+ (text) => cut.string(text, WIRE_LIMITS.elementTextLength)
2949
+ );
2950
+ element.actions = cut.array(element.actions, WIRE_LIMITS.elementActions) ?? [];
2951
+ return element;
2952
+ });
2953
+ if (cut.dropped) snapshot.truncated = true;
2954
+ return snapshot;
2955
+ }
2845
2956
 
2846
2957
  // src/registry/ComponentRegistry.ts
2847
2958
  var ComponentRegistryImpl = class {
@@ -3119,6 +3230,40 @@ function sectionListFlatIndex(sections, section, localIndex) {
3119
3230
  return base + localIndex;
3120
3231
  }
3121
3232
 
3233
+ // src/auto/interceptGuard.ts
3234
+ var _intercept = null;
3235
+ var _failures = 0;
3236
+ var INTERCEPT_FAILURE_LIMIT = 25;
3237
+ function setInterceptor(fn) {
3238
+ _intercept = fn;
3239
+ _failures = 0;
3240
+ }
3241
+ function isInterceptionActive() {
3242
+ return _intercept !== null;
3243
+ }
3244
+ function safeIntercept(type, props) {
3245
+ const intercept = _intercept;
3246
+ if (!intercept) return null;
3247
+ try {
3248
+ return intercept(type, props);
3249
+ } catch (err) {
3250
+ _failures += 1;
3251
+ if (_failures === 1) {
3252
+ console.error(
3253
+ "[Appilots] Auto-tracking failed to inspect an element and passed it through unchanged. Your app is unaffected; the agent may not see this component. This is an Appilots bug \u2014 please report it: https://github.com/Axtern-Labs/Appilots/issues",
3254
+ err
3255
+ );
3256
+ }
3257
+ if (_failures >= INTERCEPT_FAILURE_LIMIT) {
3258
+ _intercept = null;
3259
+ console.error(
3260
+ `[Appilots] Auto-tracking disabled after ${INTERCEPT_FAILURE_LIMIT} failures. The agent will only see components registered explicitly via registerScreen(). Your app is unaffected.`
3261
+ );
3262
+ }
3263
+ return null;
3264
+ }
3265
+ }
3266
+
3122
3267
  // src/auto/enableAutoTracking.tsx
3123
3268
  function extractId(props) {
3124
3269
  const raw = props?.testID ?? props?.nativeID ?? props?.id ?? props?.accessibilityLabel ?? props?.name ?? props?.placeholder ?? (typeof props?.autoComplete === "string" && props.autoComplete !== "off" ? props.autoComplete : void 0);
@@ -3577,15 +3722,15 @@ function enableAppilotsAutoTracking(options) {
3577
3722
  }
3578
3723
  return null;
3579
3724
  }
3725
+ setInterceptor(interceptType);
3580
3726
  React2.createElement = function(type, props, ...children) {
3581
- const replacement = interceptType(type, props);
3727
+ const replacement = safeIntercept(type, props);
3582
3728
  if (replacement) {
3583
3729
  return originalCreateElement(replacement.type, replacement.props, ...children);
3584
3730
  }
3585
3731
  return originalCreateElement(type, props, ...children);
3586
3732
  };
3587
3733
  console.log("[Appilots] Auto-tracking: React.createElement patched");
3588
- _interceptType = interceptType;
3589
3734
  try {
3590
3735
  const jsxRuntime = __require("react/jsx-runtime");
3591
3736
  if (jsxRuntime) {
@@ -3603,18 +3748,16 @@ function enableAppilotsAutoTracking(options) {
3603
3748
  console.log("[Appilots] Auto-tracking: react/jsx-dev-runtime not available internally (will be patched by metro shim)");
3604
3749
  }
3605
3750
  }
3606
- var _interceptType = null;
3607
3751
  var _jsxRuntimePatched = false;
3608
3752
  var _jsxDevRuntimePatched = false;
3609
3753
  function _patchJsxRuntimeModule(jsxRuntime) {
3610
- if (_jsxRuntimePatched || !_interceptType || !jsxRuntime) return;
3754
+ if (_jsxRuntimePatched || !isInterceptionActive() || !jsxRuntime) return;
3611
3755
  _jsxRuntimePatched = true;
3612
- const interceptType = _interceptType;
3613
3756
  const origJsx = jsxRuntime.jsx;
3614
3757
  const origJsxs = jsxRuntime.jsxs;
3615
3758
  if (origJsx) {
3616
3759
  jsxRuntime.jsx = function(type, props, key) {
3617
- const replacement = interceptType(type, props);
3760
+ const replacement = safeIntercept(type, props);
3618
3761
  if (replacement) {
3619
3762
  return origJsx(replacement.type, replacement.props, key);
3620
3763
  }
@@ -3624,7 +3767,7 @@ function _patchJsxRuntimeModule(jsxRuntime) {
3624
3767
  }
3625
3768
  if (origJsxs) {
3626
3769
  jsxRuntime.jsxs = function(type, props, key) {
3627
- const replacement = interceptType(type, props);
3770
+ const replacement = safeIntercept(type, props);
3628
3771
  if (replacement) {
3629
3772
  return origJsxs(replacement.type, replacement.props, key);
3630
3773
  }
@@ -3634,13 +3777,12 @@ function _patchJsxRuntimeModule(jsxRuntime) {
3634
3777
  }
3635
3778
  }
3636
3779
  function _patchJsxDevRuntimeModule(jsxDevRuntime) {
3637
- if (_jsxDevRuntimePatched || !_interceptType || !jsxDevRuntime) return;
3780
+ if (_jsxDevRuntimePatched || !isInterceptionActive() || !jsxDevRuntime) return;
3638
3781
  _jsxDevRuntimePatched = true;
3639
- const interceptType = _interceptType;
3640
3782
  if (jsxDevRuntime.jsxDEV) {
3641
3783
  const origJsxDEV = jsxDevRuntime.jsxDEV;
3642
3784
  jsxDevRuntime.jsxDEV = function(type, props, key, isStaticChildren, source, self) {
3643
- const replacement = interceptType(type, props);
3785
+ const replacement = safeIntercept(type, props);
3644
3786
  if (replacement) {
3645
3787
  return origJsxDEV(replacement.type, replacement.props, key, isStaticChildren, source, self);
3646
3788
  }
@@ -3650,7 +3792,7 @@ function _patchJsxDevRuntimeModule(jsxDevRuntime) {
3650
3792
  }
3651
3793
  }
3652
3794
  function _patchJsxRuntimes(jsxRuntime, jsxDevRuntime) {
3653
- if (!_interceptType) {
3795
+ if (!isInterceptionActive()) {
3654
3796
  console.warn("[Appilots] _patchJsxRuntimes called but auto-tracking is not enabled");
3655
3797
  return;
3656
3798
  }
@@ -3720,7 +3862,14 @@ function setFiberRoot(fiber) {
3720
3862
  _diagnostics.captured = true;
3721
3863
  }
3722
3864
  function getFiberRoot() {
3723
- return _fiberRoot;
3865
+ return resolveCurrentRoot(_fiberRoot);
3866
+ }
3867
+ function resolveCurrentRoot(fiber) {
3868
+ const current = fiber?.stateNode?.current;
3869
+ if (current && (current === fiber || current.alternate === fiber)) {
3870
+ return current;
3871
+ }
3872
+ return fiber;
3724
3873
  }
3725
3874
  function recordIntrospectionFailure(reason, reactVersion) {
3726
3875
  _diagnostics.failureCount += 1;
@@ -3729,6 +3878,13 @@ function recordIntrospectionFailure(reason, reactVersion) {
3729
3878
  _diagnostics.reactVersion = reactVersion;
3730
3879
  }
3731
3880
  }
3881
+ function recordRenderFailure(reactVersion) {
3882
+ _fiberRoot = null;
3883
+ _diagnostics.captured = false;
3884
+ _diagnostics.failureCount += 1;
3885
+ _diagnostics.failureReason = "render-crashed";
3886
+ _diagnostics.reactVersion = reactVersion;
3887
+ }
3732
3888
  function getIntrospectionDiagnostics() {
3733
3889
  return { ..._diagnostics };
3734
3890
  }
@@ -3740,6 +3896,9 @@ function typeName(fiber) {
3740
3896
  if (typeof t === "object") return t.displayName ?? t.render?.displayName ?? t.render?.name ?? "forwardRef/memo";
3741
3897
  return String(t);
3742
3898
  }
3899
+
3900
+ // src/version.ts
3901
+ var SDK_VERSION2 = "0.8.0";
3743
3902
  var FiberSentinel = class extends React2.Component {
3744
3903
  componentDidMount() {
3745
3904
  const fiber = this._reactInternals ?? this._reactInternalFiber ?? null;
@@ -3789,10 +3948,83 @@ function appilotsDebugWarn(...args) {
3789
3948
  if (!isDebugEnabled()) return;
3790
3949
  console.log("[Appilots]", ...args);
3791
3950
  }
3951
+ var AppilotsErrorBoundary = class extends React2.Component {
3952
+ state = { degraded: false, escalate: null };
3953
+ /**
3954
+ * Instance field rather than state: `componentDidCatch` needs to know
3955
+ * whether THIS is the first failure, and by the time it runs
3956
+ * `getDerivedStateFromError` has already flipped `state.degraded`.
3957
+ */
3958
+ hasDegradedOnce = false;
3959
+ static getDerivedStateFromError() {
3960
+ return { degraded: true };
3961
+ }
3962
+ componentDidCatch(error, info) {
3963
+ if (this.hasDegradedOnce) {
3964
+ this.setState({ escalate: error ?? new Error("Appilots: re-thrown host render error") });
3965
+ return;
3966
+ }
3967
+ this.hasDegradedOnce = true;
3968
+ console.error(
3969
+ `[Appilots] The Appilots ${this.props.surface} threw while rendering and has been disabled for the rest of this session. Your app keeps running \u2014 this is an Appilots bug, not a bug in your code. Please report it with the stack below: https://github.com/Axtern-Labs/Appilots/issues`,
3970
+ error
3971
+ );
3972
+ try {
3973
+ this.props.onError?.(error, info?.componentStack ?? null);
3974
+ } catch {
3975
+ }
3976
+ }
3977
+ render() {
3978
+ if (this.state.escalate !== null) throw this.state.escalate;
3979
+ if (this.state.degraded) return this.props.fallback;
3980
+ return this.props.children;
3981
+ }
3982
+ };
3792
3983
 
3793
3984
  // src/context/AppilotsProvider.tsx
3794
3985
  var AppilotsContext = createContext(null);
3795
- function AppilotsProvider({ config: configProp, children, client: externalClient }) {
3986
+ function createInertClient() {
3987
+ const unavailable = () => Promise.reject(
3988
+ new Error("Appilots is unavailable: the SDK degraded after a render error.")
3989
+ );
3990
+ return new Proxy({}, {
3991
+ get: (_target, prop) => {
3992
+ if (prop === "then" || typeof prop === "symbol") return void 0;
3993
+ return unavailable;
3994
+ }
3995
+ });
3996
+ }
3997
+ function createDegradedContext(config) {
3998
+ return {
3999
+ config: config ?? { projectId: "" },
4000
+ client: createInertClient(),
4001
+ subscribe: () => () => {
4002
+ },
4003
+ emit: () => {
4004
+ },
4005
+ remotePersonalization: null,
4006
+ degraded: true
4007
+ };
4008
+ }
4009
+ function AppilotsProvider({ config, children, client }) {
4010
+ return /* @__PURE__ */ React2.createElement(
4011
+ AppilotsErrorBoundary,
4012
+ {
4013
+ surface: "provider",
4014
+ onError: reportProviderRenderFailure,
4015
+ fallback: /* @__PURE__ */ React2.createElement(AppilotsContext.Provider, { value: createDegradedContext(config ?? null) }, children)
4016
+ },
4017
+ /* @__PURE__ */ React2.createElement(AppilotsProviderInner, { config, client }, children)
4018
+ );
4019
+ }
4020
+ function reportProviderRenderFailure() {
4021
+ recordRenderFailure(readReactVersion());
4022
+ }
4023
+ function readReactVersion() {
4024
+ const version = React2.version;
4025
+ return typeof version === "string" ? version : null;
4026
+ }
4027
+ function AppilotsProviderInner({ config: configProp, children, client: externalClient }) {
3796
4028
  console.log(`[Appilots] AppilotsProvider initializing \u2014 config source: ${configProp ? "prop" : "auto (globalThis.__APPILOTS_RC__)"}`);
3797
4029
  tryAutoConfig();
3798
4030
  const globalConfig = getGlobalConfig();
@@ -3805,7 +4037,8 @@ function AppilotsProvider({ config: configProp, children, client: externalClient
3805
4037
  debug: globalConfig.debug,
3806
4038
  appVersion: globalConfig.appVersion,
3807
4039
  mcpVersion: globalConfig.mcpVersion,
3808
- fetchPersonalization: globalConfig.fetchPersonalization
4040
+ fetchPersonalization: globalConfig.fetchPersonalization,
4041
+ suppressNativeConfirm: globalConfig.suppressNativeConfirm
3809
4042
  } : null);
3810
4043
  if (!config?.projectId) {
3811
4044
  throw new Error(
@@ -3844,6 +4077,9 @@ function AppilotsProvider({ config: configProp, children, client: externalClient
3844
4077
  debug: config.debug,
3845
4078
  appVersion: config.appVersion,
3846
4079
  mcpVersion: config.mcpVersion,
4080
+ // This package's published version, so the server knows which
4081
+ // SDK is actually in the field (issue #312).
4082
+ sdkVersion: SDK_VERSION2,
3847
4083
  user: config.user,
3848
4084
  // Only reports a FAILED reading; the happy path sends nothing.
3849
4085
  introspectionReporter: getIntrospectionDiagnostics
@@ -4386,4 +4622,4 @@ function clearScreenRegistry() {
4386
4622
  screenRegistry.clear();
4387
4623
  }
4388
4624
 
4389
- export { ActionQueueMachine, AppilotsClient, AppilotsProvider, AppilotsRegistryProvider, ChatSessionMachine, OPTIONAL_STEP_AUTOMATION_HINT, RateLimitedError, SDK_VERSION, _patchJsxRuntimes, actionPressTargetId, appilotsDebugLog, appilotsDebugWarn, attachElementIdsToChoiceGroups, clearAppilotsDebugTraces, clearScreenRegistry, componentRegistry, createComponentRegistry, createElementRegistry, createListRegistry, defaultDarkTheme, defaultLightTheme, deriveInteractionElements, describeAction, elementRegistry, enableAppilotsAutoTracking, getActiveRouteNames, getAllScreens, getAppilotsDebugTraces, getCurrentScreen, getCurrentScreenSignature, getDefaultRegistry, getFiberRoot, getGlobalConfig, getIntrospectionDiagnostics, getNavigationRef, getNavigationStateSnapshot, getScreenMetadata, humanizeError, idLooselyMatches, initAppilots, isAutoTrackingEnabled, isGenericSelectValue, isListItemPressTarget, isOptionalStepAutomationFailure, listRegistry, looksDestructiveActionLabel, matchScore, mergeThemeTokens, normalize3, parseStableElementId, probeLoadingState, recordAppilotsDebugTrace, recordIntrospectionFailure, registerScreen, resolveBaseTheme, routesBelongToSameFeature, screenDepartedBaseline, setCurrentScreen, setNavigationRef, snapshotShowsOpenCreateForm, subscribeAppilotsDebugTraces, useAppilotsContext, useResolvedRegistry, waitForLoadingSettle, waitForScreenSettle };
4625
+ export { ActionQueueMachine, AppilotsClient, AppilotsErrorBoundary, AppilotsProvider, AppilotsRegistryProvider, ChatSessionMachine, OPTIONAL_STEP_AUTOMATION_HINT, RateLimitedError, SDK_VERSION2 as SDK_VERSION, _patchJsxRuntimes, actionPressTargetId, appilotsDebugLog, appilotsDebugWarn, attachElementIdsToChoiceGroups, clampSnapshotToWireLimits, clearAppilotsDebugTraces, clearScreenRegistry, componentRegistry, createComponentRegistry, createElementRegistry, createListRegistry, defaultDarkTheme, defaultLightTheme, deriveInteractionElements, describeAction, elementRegistry, enableAppilotsAutoTracking, getActiveRouteNames, getAllScreens, getAppilotsDebugTraces, getCurrentScreen, getCurrentScreenSignature, getDefaultRegistry, getFiberRoot, getGlobalConfig, getIntrospectionDiagnostics, getNavigationRef, getNavigationStateSnapshot, getScreenMetadata, humanizeError, idLooselyMatches, initAppilots, isAutoTrackingEnabled, isGenericSelectValue, isListItemPressTarget, isOptionalStepAutomationFailure, listRegistry, looksDestructiveActionLabel, matchScore, mergeThemeTokens, normalize3, parseStableElementId, probeLoadingState, recordAppilotsDebugTrace, recordIntrospectionFailure, registerScreen, resolveBaseTheme, routesBelongToSameFeature, screenDepartedBaseline, setCurrentScreen, setNavigationRef, snapshotShowsOpenCreateForm, subscribeAppilotsDebugTraces, useAppilotsContext, useResolvedRegistry, waitForLoadingSettle, waitForScreenSettle };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkDZ7QRFHD_js = require('./chunk-DZ7QRFHD.js');
3
+ var chunkAYWMBMSN_js = require('./chunk-AYWMBMSN.js');
4
4
  var React = require('react');
5
5
 
6
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -15,11 +15,11 @@ function getActiveRouteName(state) {
15
15
  return route.name;
16
16
  }
17
17
  function AppilotsNavigationContainer({ children }) {
18
- const { emit } = chunkDZ7QRFHD_js.useAppilotsContext();
18
+ const { emit } = chunkAYWMBMSN_js.useAppilotsContext();
19
19
  const internalRef = React.useRef(null);
20
20
  const handleRef = React.useCallback((instance) => {
21
21
  internalRef.current = instance;
22
- chunkDZ7QRFHD_js.setNavigationRef(instance);
22
+ chunkAYWMBMSN_js.setNavigationRef(instance);
23
23
  const childRef = children.ref;
24
24
  if (typeof childRef === "function") childRef(instance);
25
25
  else if (childRef && typeof childRef === "object") childRef.current = instance;
@@ -32,7 +32,7 @@ function AppilotsNavigationContainer({ children }) {
32
32
  const routeName = getActiveRouteName(state);
33
33
  if (routeName) {
34
34
  console.log(`[Appilots] Screen changed \u2192 "${routeName}"`);
35
- chunkDZ7QRFHD_js.setCurrentScreen(routeName);
35
+ chunkAYWMBMSN_js.setCurrentScreen(routeName);
36
36
  emit({
37
37
  type: "navigation:change",
38
38
  timestamp: Date.now(),
@@ -48,7 +48,7 @@ function AppilotsNavigationContainer({ children }) {
48
48
  const route = internalRef.current?.getCurrentRoute?.();
49
49
  if (route?.name) {
50
50
  console.log(`[Appilots] Initial screen \u2192 "${route.name}"`);
51
- chunkDZ7QRFHD_js.setCurrentScreen(route.name);
51
+ chunkAYWMBMSN_js.setCurrentScreen(route.name);
52
52
  emit({
53
53
  type: "navigation:change",
54
54
  timestamp: Date.now(),
@@ -1,4 +1,4 @@
1
- import { getFiberRoot, recordIntrospectionFailure, getCurrentScreen, getActiveRouteNames, deriveInteractionElements, attachElementIdsToChoiceGroups, elementRegistry, appilotsDebugWarn, getDefaultRegistry, useAppilotsContext, ChatSessionMachine, getCurrentScreenSignature, ActionQueueMachine, getScreenMetadata, setCurrentScreen, useResolvedRegistry, listRegistry, componentRegistry, probeLoadingState, isListItemPressTarget, waitForLoadingSettle, appilotsDebugLog, waitForScreenSettle, screenDepartedBaseline, routesBelongToSameFeature, actionPressTargetId, getNavigationStateSnapshot, getNavigationRef, isOptionalStepAutomationFailure, OPTIONAL_STEP_AUTOMATION_HINT, normalize3, matchScore, idLooselyMatches, parseStableElementId, getAllScreens, snapshotShowsOpenCreateForm, looksDestructiveActionLabel, isGenericSelectValue } from './chunk-R4D34FEW.mjs';
1
+ import { getFiberRoot, recordIntrospectionFailure, getCurrentScreen, getActiveRouteNames, clampSnapshotToWireLimits, deriveInteractionElements, attachElementIdsToChoiceGroups, elementRegistry, appilotsDebugWarn, getDefaultRegistry, useAppilotsContext, ChatSessionMachine, getCurrentScreenSignature, ActionQueueMachine, getScreenMetadata, setCurrentScreen, useResolvedRegistry, listRegistry, componentRegistry, probeLoadingState, isListItemPressTarget, waitForLoadingSettle, appilotsDebugLog, waitForScreenSettle, screenDepartedBaseline, routesBelongToSameFeature, actionPressTargetId, getNavigationStateSnapshot, getNavigationRef, isOptionalStepAutomationFailure, OPTIONAL_STEP_AUTOMATION_HINT, normalize3, matchScore, idLooselyMatches, parseStableElementId, getAllScreens, snapshotShowsOpenCreateForm, looksDestructiveActionLabel, isGenericSelectValue } from './chunk-C2KVVJ5K.mjs';
2
2
  import { useMemo, useRef, useSyncExternalStore, useEffect, useCallback, useState } from 'react';
3
3
  import { Alert } from 'react-native';
4
4
 
@@ -770,11 +770,13 @@ function captureSnapshot() {
770
770
  if (deepestRoute) snapshot.route = deepestRoute;
771
771
  mergeRegisteredLists(snapshot);
772
772
  reconcileSliders(snapshot);
773
+ clampSnapshotToWireLimits(snapshot);
773
774
  snapshot.elements = deriveInteractionElements(snapshot);
774
775
  snapshot.choiceGroups = attachElementIdsToChoiceGroups(
775
776
  snapshot.choiceGroups,
776
777
  snapshot.elements
777
778
  );
779
+ clampSnapshotToWireLimits(snapshot);
778
780
  elementRegistry.replaceAll(snapshot.elements);
779
781
  const elapsed = Date.now() - start;
780
782
  const totalListItems = snapshot.lists.reduce(
@@ -786,7 +788,7 @@ function captureSnapshot() {
786
788
  0
787
789
  );
788
790
  console.log(
789
- `[Appilots] captureSnapshot: route="${snapshot.route}" texts=${snapshot.texts.length} inputs=${snapshot.inputs.length} buttons=${snapshot.buttons.length} toggles=${snapshot.toggles.length} sliders=${snapshot.sliders.length} loading=${snapshot.loading} modal=${snapshot.modalOpen} lists=${snapshot.lists.length}(visibleItems=${totalListItems}, dataItems=${totalListDataItems}) choices=${snapshot.choiceGroups.length} elements=${snapshot.elements.length} (walked ${snapshot.stats?.visitedFibers ?? 0} fibers, skipped ${snapshot.stats?.skippedHidden ?? 0} hidden, ${elapsed}ms)`
791
+ `[Appilots] captureSnapshot: route="${snapshot.route}" texts=${snapshot.texts.length} inputs=${snapshot.inputs.length} buttons=${snapshot.buttons.length} toggles=${snapshot.toggles.length} sliders=${snapshot.sliders.length} loading=${snapshot.loading} modal=${snapshot.modalOpen} lists=${snapshot.lists.length}(visibleItems=${totalListItems}, dataItems=${totalListDataItems}) choices=${snapshot.choiceGroups.length} elements=${snapshot.elements.length} ` + (snapshot.truncated ? "truncated=true " : "") + `(walked ${snapshot.stats?.visitedFibers ?? 0} fibers, skipped ${snapshot.stats?.skippedHidden ?? 0} hidden, ${elapsed}ms)`
790
792
  );
791
793
  console.log(
792
794
  `[Appilots] captureSnapshot detail: lists=[${snapshot.lists.map((l) => `${l.containerType}:${l.id ?? l.label ?? "?"}(${l.items.map((it) => it.texts[0] ?? it.buttons[0]?.id ?? "?").join("|")})`).join(", ")}] inputs=[${snapshot.inputs.map((i) => i.id ?? i.label ?? "?").slice(0, 12).join(", ")}] buttons=[${snapshot.buttons.map((b) => b.id ?? b.label ?? "?").slice(0, 15).join(", ")}]`
@@ -3963,6 +3965,95 @@ async function executeAction(action, context) {
3963
3965
  });
3964
3966
  return result;
3965
3967
  }
3968
+
3969
+ // src/platform/confirmedDestructiveAlert.ts
3970
+ var SUPPRESSION_WINDOW_MS = 1e3;
3971
+ var _active = null;
3972
+ function resolveConfirmButton(buttons) {
3973
+ if (!buttons || buttons.length === 0) return void 0;
3974
+ const destructive = buttons.find(
3975
+ (button) => button.style === "destructive" && typeof button.onPress === "function"
3976
+ );
3977
+ if (destructive) return destructive;
3978
+ return buttons.find(
3979
+ (button) => button.style !== "cancel" && typeof button.onPress === "function"
3980
+ );
3981
+ }
3982
+ function restore(suppression) {
3983
+ if (suppression.timer) {
3984
+ clearTimeout(suppression.timer);
3985
+ suppression.timer = null;
3986
+ }
3987
+ if (_active !== suppression) return;
3988
+ if (suppression.host.alert === _patchedAlert) {
3989
+ suppression.host.alert = suppression.originalAlert;
3990
+ }
3991
+ _active = null;
3992
+ }
3993
+ var _patchedAlert = (title, message, buttons, options) => {
3994
+ const suppression = _active;
3995
+ if (!suppression) return;
3996
+ if (suppression.consumed) {
3997
+ return suppression.originalAlert(title, message, buttons, options);
3998
+ }
3999
+ const button = resolveConfirmButton(buttons);
4000
+ if (!button?.onPress) {
4001
+ return suppression.originalAlert(title, message, buttons, options);
4002
+ }
4003
+ suppression.consumed = true;
4004
+ console.log(
4005
+ "[Appilots] Suppressing native Alert during already-confirmed destructive agent action"
4006
+ );
4007
+ try {
4008
+ suppression.pending = Promise.resolve(button.onPress()).then(() => void 0).catch((err) => reportHandlerFailure(err));
4009
+ } catch (err) {
4010
+ reportHandlerFailure(err);
4011
+ suppression.pending = null;
4012
+ }
4013
+ };
4014
+ function reportHandlerFailure(err) {
4015
+ console.error("[Appilots] The app\u2019s Alert handler threw while being auto-confirmed", err);
4016
+ }
4017
+ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4018
+ if (!enabled) return fn();
4019
+ if (_active) {
4020
+ _active.depth += 1;
4021
+ const joined = _active;
4022
+ try {
4023
+ return await fn();
4024
+ } finally {
4025
+ joined.depth -= 1;
4026
+ if (joined.depth === 0) {
4027
+ if (joined.pending) await joined.pending.catch(() => void 0);
4028
+ restore(joined);
4029
+ }
4030
+ }
4031
+ }
4032
+ const suppression = {
4033
+ host,
4034
+ originalAlert: host.alert,
4035
+ depth: 1,
4036
+ consumed: false,
4037
+ pending: null,
4038
+ timer: null
4039
+ };
4040
+ _active = suppression;
4041
+ host.alert = _patchedAlert;
4042
+ suppression.timer = setTimeout(() => {
4043
+ if (!suppression.consumed) restore(suppression);
4044
+ }, SUPPRESSION_WINDOW_MS);
4045
+ suppression.timer?.unref?.();
4046
+ try {
4047
+ const result = await fn();
4048
+ if (suppression.pending) await suppression.pending.catch(() => void 0);
4049
+ return result;
4050
+ } finally {
4051
+ suppression.depth -= 1;
4052
+ if (suppression.depth === 0) restore(suppression);
4053
+ }
4054
+ }
4055
+
4056
+ // src/platform/reactNativeAdapter.ts
3966
4057
  var POST_ACTION_LOADING_MAX_MS = 6e3;
3967
4058
  function resolveScreenMetadata() {
3968
4059
  const activePath = getActiveRouteNames();
@@ -4113,42 +4204,14 @@ var reactNativeChatAdapter = {
4113
4204
  getCurrentScreenSignature,
4114
4205
  settleTurn
4115
4206
  };
4116
- async function runWithConfirmedDestructiveContext(enabled, fn) {
4117
- if (!enabled) return fn();
4118
- const originalAlert = Alert.alert;
4119
- let consumed = false;
4120
- let alertWork = null;
4121
- Alert.alert = (title, message, buttons, options) => {
4122
- if (consumed) {
4123
- return originalAlert(title, message, buttons, options);
4124
- }
4125
- const destructive = buttons?.find((button) => button.style === "destructive");
4126
- const actionable = destructive ?? buttons?.find((button) => button.style !== "cancel" && typeof button.onPress === "function");
4127
- if (actionable?.onPress) {
4128
- consumed = true;
4129
- console.log(
4130
- "[Appilots] Suppressing native Alert during already-confirmed destructive agent action"
4131
- );
4132
- alertWork = Promise.resolve(actionable.onPress()).then(() => void 0);
4133
- return;
4134
- }
4135
- return originalAlert(title, message, buttons, options);
4136
- };
4137
- try {
4138
- const result = await fn();
4139
- if (alertWork) await alertWork;
4140
- return result;
4141
- } finally {
4142
- Alert.alert = originalAlert;
4143
- }
4144
- }
4145
4207
  function createReactNativeActionRunner(getOptions) {
4146
4208
  return {
4147
4209
  async execute(action, { confirmedDestructive }) {
4148
- const { permissions, emit, navigationRef } = getOptions();
4210
+ const { permissions, emit, navigationRef, suppressNativeConfirm } = getOptions();
4149
4211
  const navRef = navigationRef?.current ? navigationRef : { current: getNavigationRef() };
4150
4212
  return runWithConfirmedDestructiveContext(
4151
- confirmedDestructive,
4213
+ confirmedDestructive && suppressNativeConfirm !== false,
4214
+ Alert,
4152
4215
  () => executeAction(action, {
4153
4216
  navigationRef: navRef,
4154
4217
  permissions,
@@ -4218,12 +4281,14 @@ function useAppilotsActions(options = {}) {
4218
4281
  const runnerOptionsRef = useRef({
4219
4282
  permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
4220
4283
  emit,
4221
- navigationRef
4284
+ navigationRef,
4285
+ suppressNativeConfirm: config.suppressNativeConfirm
4222
4286
  });
4223
4287
  runnerOptionsRef.current = {
4224
4288
  permissions: config.permissions ?? DEFAULT_PERMISSIONS2,
4225
4289
  emit,
4226
- navigationRef
4290
+ navigationRef,
4291
+ suppressNativeConfirm: config.suppressNativeConfirm
4227
4292
  };
4228
4293
  const machine = useMemo(
4229
4294
  () => new ActionQueueMachine(