@appilots/sdk 0.11.1 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  {
2
- "sourceHash": "6574aab0f4f8f43f",
3
- "gitSha": "cdbfa225c28ac0cf0bf495bb8a8ec0c55d4dc1d1",
4
- "builtAt": "2026-08-26T01:42:57.571Z"
2
+ "sourceHash": "d9adc8d175451d3a",
3
+ "gitSha": "9f1ad6d77e946ec908370319d90e8733cd4f1f31",
4
+ "builtAt": "2026-09-06T04:46:03.208Z"
5
5
  }
@@ -1,4 +1,4 @@
1
- import { getFiberRoot, appilotsDebugWarn, recordIntrospectionFailure, getCurrentScreen, walkFiber, getActiveRouteNames, clampSnapshotToWireLimits, deriveInteractionElements, rectForNode, toWireElement, attachElementIdsToChoiceGroups, elementRegistry, appilotsDebugLog, getLastWalkDiagnostics, SDK_VERSION, geometryStats, geometryAvailability, getNameManglingProbe, emptyDetectorCounts, getAutoTrackingState, getIntrospectionDiagnostics, getDefaultRegistry, useAppilotsContext, ChatSessionMachine, getCurrentScreenSignature, ActionQueueMachine, getScreenMetadata, setCurrentScreen, useResolvedRegistry, totalDetectorHits, listRegistry, getOpenNativeDialog, componentRegistry, getLastAnsweredNativeDialog, probeLoadingState, isListItemPressTarget, waitForLoadingSettle, describeValue, waitForScreenSettle, screenDepartedBaseline, routesBelongToSameFeature, actionPressTargetId, getNavigationStateSnapshot, getNavigationRef, isOptionalStepAutomationFailure, OPTIONAL_STEP_AUTOMATION_HINT, isSwitchLike, normalize3, matchScore, FORM_VALIDATION_TEXT_RE, idLooselyMatches, parseStableElementId, shouldSkipSubtree, isAlwaysListContainer, isHeuristicListContainer, findListItems, getTypeName, foldForCompare, isModalFiber, switchValue, getAllScreens, snapshotShowsOpenCreateForm, isReferenceable, looksDestructiveActionLabel, isGenericSelectValue, FORM_WRITE_SUCCESS_TEXT_RE, TOUCHABLE_NAMES } from './chunk-PQZ64CCE.mjs';
1
+ import { createSnapshotDeltaTracker, getFiberRoot, appilotsDebugWarn, recordIntrospectionFailure, getCurrentScreen, walkFiber, getActiveRouteNames, clampSnapshotToWireLimits, deriveInteractionElements, rectForNode, toWireElement, attachElementIdsToChoiceGroups, elementRegistry, appilotsDebugLog, getLastWalkDiagnostics, SDK_VERSION, geometryStats, geometryAvailability, getNameManglingProbe, emptyDetectorCounts, getAutoTrackingState, getIntrospectionDiagnostics, getDefaultRegistry, useAppilotsContext, ChatSessionMachine, getCurrentScreenSignature, ActionQueueMachine, getScreenMetadata, setCurrentScreen, useResolvedRegistry, totalDetectorHits, listRegistry, getOpenNativeDialog, componentRegistry, getLastAnsweredNativeDialog, probeLoadingState, isListItemPressTarget, waitForLoadingSettle, describeValue, waitForScreenSettle, screenDepartedBaseline, routesBelongToSameFeature, actionPressTargetId, getNavigationStateSnapshot, getNavigationRef, isOptionalStepAutomationFailure, OPTIONAL_STEP_AUTOMATION_HINT, isSwitchLike, idLooselyMatches, normalize3, matchScore, FORM_VALIDATION_TEXT_RE, parseStableElementId, shouldSkipSubtree, isAlwaysListContainer, isHeuristicListContainer, findListItems, getTypeName, foldForCompare, isModalFiber, switchValue, getAllScreens, snapshotShowsOpenCreateForm, isReferenceable, looksDestructiveActionLabel, isGenericSelectValue, FORM_WRITE_SUCCESS_TEXT_RE, TOUCHABLE_NAMES } from './chunk-ROXXCDIG.mjs';
2
2
  import React, { useMemo, useRef, useSyncExternalStore, useEffect, useCallback, useState } from 'react';
3
3
  import { Alert } from 'react-native';
4
4
 
@@ -3399,6 +3399,14 @@ async function formFillHandler(payload, context) {
3399
3399
  allSuccess = false;
3400
3400
  }
3401
3401
  if (payload.submitAfterFill === true) {
3402
+ if (!permissions.canSubmitForms) {
3403
+ return {
3404
+ success: false,
3405
+ error: "Form submission is not permitted",
3406
+ fieldResults,
3407
+ diagnose: { category: "unknown", screen: screenPath }
3408
+ };
3409
+ }
3402
3410
  if (!allSuccess) {
3403
3411
  const failedIds = fieldResults.filter((result) => !result.success).map((result) => result.fieldId);
3404
3412
  appilotsDebugWarn(
@@ -3406,6 +3414,9 @@ async function formFillHandler(payload, context) {
3406
3414
  );
3407
3415
  } else {
3408
3416
  await sleep2(120);
3417
+ if (!permissions.canSubmitForms) {
3418
+ return { success: false, error: "Form submission is not permitted", fieldResults };
3419
+ }
3409
3420
  const submitResult = pressSubmitButton(
3410
3421
  {
3411
3422
  screen,
@@ -3711,6 +3722,59 @@ async function confirmHandler(_actionId, _payload) {
3711
3722
  return { success: true, effect: "unknown" };
3712
3723
  }
3713
3724
 
3725
+ // src/platform/asyncBudget.ts
3726
+ var POST_ACTION_LOADING_MAX_MS = 6e3;
3727
+ var INFERRED_ASYNC_LOADING_MAX_MS = 1e4;
3728
+ var POST_NAVIGATE_LOADING_MAX_MS = 3e3;
3729
+ var MAX_DECLARED_ASYNC_BUDGET_MS = 12e4;
3730
+ var ASYNC_BUSY_CEILING_MS = MAX_DECLARED_ASYNC_BUDGET_MS;
3731
+ function declaredBudgetMs(hints) {
3732
+ const declared = hints?.asyncBudgetMs;
3733
+ if (typeof declared !== "number" || !Number.isFinite(declared) || declared <= 0) return void 0;
3734
+ return Math.min(declared, MAX_DECLARED_ASYNC_BUDGET_MS);
3735
+ }
3736
+ function resolveSettleCapMs(hints) {
3737
+ const declared = declaredBudgetMs(hints);
3738
+ if (declared !== void 0) return declared;
3739
+ return hints?.isAsyncTrigger === true ? INFERRED_ASYNC_LOADING_MAX_MS : POST_ACTION_LOADING_MAX_MS;
3740
+ }
3741
+ function resolveBusyCeilingMs(hints) {
3742
+ return declaredBudgetMs(hints) === void 0 ? ASYNC_BUSY_CEILING_MS : void 0;
3743
+ }
3744
+ function resolvePostNavigateCapMs(hints) {
3745
+ return Math.max(POST_NAVIGATE_LOADING_MAX_MS, declaredBudgetMs(hints) ?? 0);
3746
+ }
3747
+ function resolveActionHints(screen, pressedComponentId, actionPayload) {
3748
+ if (actionPayload && typeof actionPayload === "object") {
3749
+ const payload = actionPayload;
3750
+ const inline = payload._appilotsInferred;
3751
+ const declared = payload._appilotsAsyncBudgetMs;
3752
+ if (inline && typeof inline === "object") {
3753
+ const hints = { ...inline };
3754
+ if (typeof declared === "number") hints.asyncBudgetMs = declared;
3755
+ return hints;
3756
+ }
3757
+ if (typeof declared === "number") return { asyncBudgetMs: declared };
3758
+ }
3759
+ if (!screen || !pressedComponentId) return void 0;
3760
+ const meta = getScreenMetadata(screen);
3761
+ const actions = meta?.actions;
3762
+ if (!actions || actions.length === 0) return void 0;
3763
+ for (const a of actions) {
3764
+ if (typeof a === "string") continue;
3765
+ if (idLooselyMatches(a.id, pressedComponentId)) {
3766
+ const inferred = a.appilotsInferred;
3767
+ const declared = a.asyncBudgetMs;
3768
+ const hints = {
3769
+ ...inferred && typeof inferred === "object" ? inferred : {},
3770
+ ...typeof declared === "number" ? { asyncBudgetMs: declared } : {}
3771
+ };
3772
+ return Object.keys(hints).length > 0 ? hints : void 0;
3773
+ }
3774
+ }
3775
+ return void 0;
3776
+ }
3777
+
3714
3778
  // src/executor/postInteractionSettle.ts
3715
3779
  var sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3716
3780
  function targetIdFromPayload(payload) {
@@ -3759,7 +3823,8 @@ async function waitForPostInteractionSettle(payload) {
3759
3823
  if (discreteFieldSignature() !== baselineFields) return { effect: "changed" };
3760
3824
  return { effect: settled.fingerprint !== baseline.fingerprint ? "changed" : "none" };
3761
3825
  };
3762
- const capMs = isListItemPressTarget(targetId) ? 5e3 : 1e4;
3826
+ const declared = declaredBudgetMs(resolveActionHints(fromScreen, targetId || null, payload));
3827
+ const capMs = declared ?? (isListItemPressTarget(targetId) ? 5e3 : 1e4);
3763
3828
  if (modalOrLoading || fingerprintChanged) {
3764
3829
  await waitForLoadingSettle({
3765
3830
  pressedComponentId: targetId || null,
@@ -4056,7 +4121,7 @@ async function runWithConfirmedDestructiveContext(enabled, host, fn) {
4056
4121
  }
4057
4122
 
4058
4123
  // src/platform/reactNativeAdapter.ts
4059
- var POST_ACTION_LOADING_MAX_MS = 6e3;
4124
+ var deltaTracker = createSnapshotDeltaTracker();
4060
4125
  function resolveScreenMetadata() {
4061
4126
  const activePath = getActiveRouteNames();
4062
4127
  for (let i = activePath.length - 1; i >= 0; i--) {
@@ -4070,6 +4135,7 @@ function resolveScreenMetadata() {
4070
4135
  return screen ? getScreenMetadata(screen) : void 0;
4071
4136
  }
4072
4137
  function buildAgentContext(extras = {}) {
4138
+ if (extras.newMission === true) deltaTracker.reset();
4073
4139
  const context = {};
4074
4140
  context.platform = "react-native";
4075
4141
  const screen = getCurrentScreen();
@@ -4079,7 +4145,10 @@ function buildAgentContext(extras = {}) {
4079
4145
  const screenMeta = resolveScreenMetadata();
4080
4146
  if (screenMeta) context.screenMetadata = screenMeta;
4081
4147
  try {
4082
- context.snapshot = captureSnapshot();
4148
+ const snapshot = captureSnapshot();
4149
+ const delta = deltaTracker.observe(snapshot);
4150
+ if (delta) snapshot.delta = delta;
4151
+ context.snapshot = snapshot;
4083
4152
  } catch (err) {
4084
4153
  appilotsDebugWarn("buildAgentContext: captureSnapshot failed", err);
4085
4154
  }
@@ -4095,33 +4164,21 @@ function buildAgentContext(extras = {}) {
4095
4164
  if (extras.loadingPending === true) context.loadingPending = true;
4096
4165
  return context;
4097
4166
  }
4098
- function resolveActionHints(screen, pressedComponentId, actionPayload) {
4099
- if (actionPayload && typeof actionPayload === "object") {
4100
- const inline = actionPayload._appilotsInferred;
4101
- if (inline && typeof inline === "object") {
4102
- return inline;
4103
- }
4104
- }
4105
- if (!screen || !pressedComponentId) return void 0;
4106
- const meta = getScreenMetadata(screen);
4107
- const actions = meta?.actions;
4108
- if (!actions || actions.length === 0) return void 0;
4109
- for (const a of actions) {
4110
- if (typeof a === "string") continue;
4111
- if (idLooselyMatches(a.id, pressedComponentId)) {
4112
- const inferred = a.appilotsInferred;
4113
- if (inferred && typeof inferred === "object") return inferred;
4114
- return void 0;
4115
- }
4116
- }
4117
- return void 0;
4118
- }
4119
4167
  async function settleTurn(input) {
4120
4168
  const toolWithoutEffectIds = /* @__PURE__ */ new Set();
4121
4169
  let loadingPending = false;
4122
4170
  const { turnActions, pressedComponentId: pressedId, navigateTargetScreen } = input;
4123
4171
  const successById = new Map(input.results.map((r) => [r.actionId, r.success]));
4124
4172
  const typeById = new Map(input.results.map((r) => [r.actionId, r.type]));
4173
+ const pressedAction = turnActions.find(
4174
+ (a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
4175
+ );
4176
+ const hints = resolveActionHints(
4177
+ getCurrentScreen(),
4178
+ pressedId,
4179
+ pressedAction?.payload
4180
+ );
4181
+ const capSource = typeof hints?.asyncBudgetMs === "number" && hints.asyncBudgetMs > 0 ? " (app-declared)" : hints?.isAsyncTrigger ? " (mcp-inferred)" : "";
4125
4182
  if (input.hadNavigate) {
4126
4183
  const settle = await waitForScreenSettle({
4127
4184
  expectingChange: true,
@@ -4142,27 +4199,26 @@ async function settleTurn(input) {
4142
4199
  if (type === "navigate") toolWithoutEffectIds.add(actionId);
4143
4200
  }
4144
4201
  }
4202
+ const postNavigateCapMs = resolvePostNavigateCapMs(hints);
4145
4203
  const loadSettle = await waitForLoadingSettle({
4146
4204
  fromScreen: settle.screen ?? null,
4147
- maxMs: 3e3
4205
+ maxMs: postNavigateCapMs
4148
4206
  });
4149
4207
  appilotsDebugLog(
4150
- `settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs}`
4208
+ `settleTurn: post-navigate loading settle \u2014 settled=${loadSettle.settled} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${postNavigateCapMs}${capSource}`
4151
4209
  );
4152
4210
  if (loadSettle.loadingPending) loadingPending = true;
4153
4211
  } else {
4154
- const pressedAction = turnActions.find(
4155
- (a) => a.type === "ui_interaction" && a.payload?.componentId === pressedId
4156
- );
4157
- const hints = resolveActionHints(getCurrentScreen(), pressedId, pressedAction?.payload);
4158
- const settleCapMs = hints?.isAsyncTrigger === true ? 1e4 : POST_ACTION_LOADING_MAX_MS;
4212
+ const settleCapMs = resolveSettleCapMs(hints);
4213
+ const busyMaxMs = resolveBusyCeilingMs(hints);
4159
4214
  const loadSettle = await waitForLoadingSettle({
4160
4215
  pressedComponentId: pressedId,
4161
4216
  fromScreen: getCurrentScreen(),
4162
- maxMs: settleCapMs
4217
+ maxMs: settleCapMs,
4218
+ ...busyMaxMs !== void 0 ? { busyMaxMs } : {}
4163
4219
  });
4164
4220
  appilotsDebugLog(
4165
- `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)" : ""}`
4221
+ `settleTurn: post-action loading settle \u2014 pressedId="${pressedId ?? ""}" settled=${loadSettle.settled} transitioned=${loadSettle.transitioned} loadingPending=${loadSettle.loadingPending} probes=${loadSettle.probeCount} waitedMs=${loadSettle.waitedMs} cap=${settleCapMs}${capSource}${busyMaxMs !== void 0 ? ` busyCap=${busyMaxMs}` : ""}`
4166
4222
  );
4167
4223
  if (loadSettle.loadingPending) loadingPending = true;
4168
4224
  const listPressActions = turnActions.filter((action) => {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkKZ2BLMS4_js = require('./chunk-KZ2BLMS4.js');
3
+ var chunkSUMIABJK_js = require('./chunk-SUMIABJK.js');
4
4
  var React = require('react');
5
5
 
6
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -15,17 +15,17 @@ function getActiveRouteName(state) {
15
15
  return route.name;
16
16
  }
17
17
  function AppilotsNavigationContainer({ children }) {
18
- const { emit } = chunkKZ2BLMS4_js.useAppilotsContext();
18
+ const { emit } = chunkSUMIABJK_js.useAppilotsContext();
19
19
  const internalRef = React.useRef(null);
20
20
  const handleRef = React.useCallback(
21
21
  (instance) => {
22
22
  internalRef.current = instance;
23
- chunkKZ2BLMS4_js.setNavigationRef(instance);
23
+ chunkSUMIABJK_js.setNavigationRef(instance);
24
24
  const childRef = children.ref;
25
25
  if (typeof childRef === "function") childRef(instance);
26
26
  else if (childRef && typeof childRef === "object") childRef.current = instance;
27
27
  if (instance) {
28
- chunkKZ2BLMS4_js.appilotsDebugLog("NavigationContainer ref captured");
28
+ chunkSUMIABJK_js.appilotsDebugLog("NavigationContainer ref captured");
29
29
  }
30
30
  },
31
31
  [children]
@@ -34,8 +34,8 @@ function AppilotsNavigationContainer({ children }) {
34
34
  (state) => {
35
35
  const routeName = getActiveRouteName(state);
36
36
  if (routeName) {
37
- chunkKZ2BLMS4_js.appilotsDebugLog(`Screen changed \u2192 "${routeName}"`);
38
- chunkKZ2BLMS4_js.setCurrentScreen(routeName);
37
+ chunkSUMIABJK_js.appilotsDebugLog(`Screen changed \u2192 "${routeName}"`);
38
+ chunkSUMIABJK_js.setCurrentScreen(routeName);
39
39
  emit({
40
40
  type: "navigation:change",
41
41
  timestamp: Date.now(),
@@ -50,8 +50,8 @@ function AppilotsNavigationContainer({ children }) {
50
50
  const timer = setTimeout(() => {
51
51
  const route = internalRef.current?.getCurrentRoute?.();
52
52
  if (route?.name) {
53
- chunkKZ2BLMS4_js.appilotsDebugLog(`Initial screen \u2192 "${route.name}"`);
54
- chunkKZ2BLMS4_js.setCurrentScreen(route.name);
53
+ chunkSUMIABJK_js.appilotsDebugLog(`Initial screen \u2192 "${route.name}"`);
54
+ chunkSUMIABJK_js.setCurrentScreen(route.name);
55
55
  emit({
56
56
  type: "navigation:change",
57
57
  timestamp: Date.now(),
@@ -1,4 +1,4 @@
1
- import { useAppilotsContext, setNavigationRef, appilotsDebugLog, setCurrentScreen } from './chunk-PQZ64CCE.mjs';
1
+ import { useAppilotsContext, setNavigationRef, appilotsDebugLog, setCurrentScreen } from './chunk-ROXXCDIG.mjs';
2
2
  import React, { useRef, useCallback, useEffect } from 'react';
3
3
 
4
4
  function getActiveRouteName(state) {