@swmansion/argent 0.25.1-next.30 → 0.25.1-next.32

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/cli-cmds.mjs CHANGED
@@ -21857,7 +21857,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
21857
21857
  var SESSION_ID2 = randomUUID5();
21858
21858
  function readCliVersion() {
21859
21859
  if (true) {
21860
- return "0.25.1-next.30";
21860
+ return "0.25.1-next.32";
21861
21861
  }
21862
21862
  return "0.0.0";
21863
21863
  }
@@ -16710,7 +16710,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
16710
16710
  var SESSION_ID = randomUUID4();
16711
16711
  function readCliVersion() {
16712
16712
  if (true) {
16713
- return "0.25.1-next.30";
16713
+ return "0.25.1-next.32";
16714
16714
  }
16715
16715
  return "0.0.0";
16716
16716
  }
@@ -94704,7 +94704,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
94704
94704
  var SESSION_ID = (0, import_node_crypto3.randomUUID)();
94705
94705
  function readCliVersion() {
94706
94706
  if (true) {
94707
- return "0.25.1-next.30";
94707
+ return "0.25.1-next.32";
94708
94708
  }
94709
94709
  return "0.0.0";
94710
94710
  }
@@ -125765,7 +125765,7 @@ init_adb();
125765
125765
 
125766
125766
  // ../tool-server/src/utils/poll-describe-tree.ts
125767
125767
  async function pollDescribeTree(args) {
125768
- const { fetchTree: fetchTree2, timeoutMs, pollIntervalMs, signal, onSample } = args;
125768
+ const { fetchTree, timeoutMs, pollIntervalMs, signal, onSample } = args;
125769
125769
  const start2 = Date.now();
125770
125770
  const deadline = start2 + timeoutMs;
125771
125771
  let polls = 0;
@@ -125784,7 +125784,7 @@ async function pollDescribeTree(args) {
125784
125784
  for (; ; ) {
125785
125785
  if (signal?.aborted) return outcome(void 0, true);
125786
125786
  const remaining = Math.max(0, deadline - Date.now());
125787
- const settled = await settleWithin(fetchTree2(), remaining, signal);
125787
+ const settled = await settleWithin(fetchTree(), remaining, signal);
125788
125788
  polls += 1;
125789
125789
  if (settled.type === "aborted") return outcome(void 0, true);
125790
125790
  lastAttemptSettled = settled.type !== "timeout";
@@ -131945,23 +131945,6 @@ function deriveSelector(node) {
131945
131945
  if (node.role && !GENERIC_ROLES.has(node.role.toLowerCase())) return { role: node.role };
131946
131946
  return null;
131947
131947
  }
131948
- async function fetchTree(registry2, device, opts = {}) {
131949
- if (device.platform === "ios") {
131950
- return describeIos(registry2, device, { bundleId: opts.bundleId });
131951
- }
131952
- if (device.platform === "android") {
131953
- return describeAndroid(registry2, device.id);
131954
- }
131955
- if (device.platform === "chromium") {
131956
- const ref = chromiumCdpRef(device);
131957
- const api = await registry2.resolveService(ref.urn, ref.options);
131958
- return describeChromium(api);
131959
- }
131960
- if (device.platform === "vega") {
131961
- return describeVega(device.id);
131962
- }
131963
- throw new Error(`ui-tree matching is not supported on platform "${device.platform}"`);
131964
- }
131965
131948
 
131966
131949
  // ../tool-server/src/tools/await-ui-element/index.ts
131967
131950
  var AWAIT_UI_ELEMENT_TOOL_ID = "await-ui-element";
@@ -132076,7 +132059,7 @@ function timeoutNote(params, lastTree, fetchError, lastData) {
132076
132059
  return appendDiagnostics(base, lastData);
132077
132060
  }
132078
132061
  function createAwaitUiElementTool(registry2) {
132079
- async function fetchTree2(device, params, services, isTvOs, androidIsTv) {
132062
+ async function fetchTree(device, params, services, isTvOs, androidIsTv) {
132080
132063
  if (device.platform === "ios" || device.platform === "ios-remote") {
132081
132064
  if (device.kind === "device") {
132082
132065
  return describeIosDevice(registry2, device);
@@ -132158,7 +132141,7 @@ tap/navigation to wait for the next screen, or before tapping an element that ap
132158
132141
  let everMatched = false;
132159
132142
  let lastTrustedReadAt;
132160
132143
  const poll = await pollDescribeTree({
132161
- fetchTree: () => fetchTree2(device, params, services, isTvOs, androidIsTv),
132144
+ fetchTree: () => fetchTree(device, params, services, isTvOs, androidIsTv),
132162
132145
  timeoutMs,
132163
132146
  pollIntervalMs,
132164
132147
  signal,
@@ -134831,7 +134814,7 @@ function treeSignature(root) {
134831
134814
  return parts2.join("\n");
134832
134815
  }
134833
134816
  function createAwaitScreenIdleTool(registry2) {
134834
- function fetchTree2(device, services, isTvOs, androidIsTv) {
134817
+ function fetchTree(device, services, isTvOs, androidIsTv) {
134835
134818
  if (device.platform === "ios" || device.platform === "ios-remote") {
134836
134819
  if (device.kind === "device") {
134837
134820
  return describeIosDevice(registry2, device);
@@ -134879,7 +134862,7 @@ still before the timeout. Use after a launch/navigation to wait for the UI to re
134879
134862
  let stableSignature;
134880
134863
  let stableSince = 0;
134881
134864
  const poll = await pollDescribeTree({
134882
- fetchTree: () => fetchTree2(device, services, isTvOs, androidIsTv),
134865
+ fetchTree: () => fetchTree(device, services, isTvOs, androidIsTv),
134883
134866
  timeoutMs: params.timeoutMs ?? DEFAULT_TIMEOUT_MS4,
134884
134867
  pollIntervalMs: params.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2,
134885
134868
  signal: ctx?.signal,
@@ -147517,6 +147500,7 @@ function bindDeviceArgs(registry2, toolName, deviceId, args, deviceIsExplicit =
147517
147500
 
147518
147501
  // ../tool-server/src/tools/flows/flow-ios-tree.ts
147519
147502
  init_src();
147503
+ init_device_info();
147520
147504
 
147521
147505
  // ../tool-server/src/tools/flows/flow-tree-flatten.ts
147522
147506
  function intersectClip(rect, clip3) {
@@ -147891,6 +147875,9 @@ Flow selector steps auto-target and cannot provide a bundleId. Bring that app to
147891
147875
  );
147892
147876
  }
147893
147877
  async function terminateCommand(device) {
147878
+ if (device.platform === "ios-remote") {
147879
+ return `sim-remote simctl terminate ${stripRemotePrefix(device.id)} <bundleId>`;
147880
+ }
147894
147881
  try {
147895
147882
  const { prefix } = await simctlTargetForUdid(device.id);
147896
147883
  return `xcrun ${prefix.join(" ")} terminate <udid> <bundleId>`;
@@ -148170,21 +148157,22 @@ async function queryVegaTree(device) {
148170
148157
 
148171
148158
  // ../tool-server/src/tools/flows/flow-tree.ts
148172
148159
  async function fetchFlowTree(registry2, device, target) {
148173
- const source = FLOW_TREE_SOURCES[device.platform];
148174
- if (!source) return fetchTree(registry2, device);
148175
- return source(registry2, device, target);
148160
+ return FLOW_TREE_SOURCES[device.platform](registry2, device, target);
148176
148161
  }
148177
148162
  var FLOW_TREE_SOURCES = {
148178
148163
  // Simulator iOS uses the injected hierarchy and an optional target.
148179
148164
  // Physical devices use the XCUITest runner tree.
148180
- ios: (registry2, device, target) => device.kind === "device" ? queryIosDeviceFlowTree(registry2, device) : queryFullHierarchyTree(registry2, device, target),
148181
- android: (registry2, device) => queryAndroidFullHierarchy(registry2, device),
148182
- chromium: (registry2, device) => queryChromiumTree(registry2, device),
148183
- vega: (_registry, device) => queryVegaTree(device)
148165
+ "ios": (registry2, device, target) => device.kind === "device" ? queryIosDeviceFlowTree(registry2, device) : queryFullHierarchyTree(registry2, device, target),
148166
+ // A remote sim is an iOS simulator reached over the sim-remote tunnel, and
148167
+ // the native-devtools blueprint routes `getFullHierarchy` over TCP for one.
148168
+ // So it is the local simulator source with no `kind === "device"` arm:
148169
+ // `ios-remote` is always kind "simulator" (utils/device-info.ts) and has no
148170
+ // physical-device variant.
148171
+ "ios-remote": (registry2, device, target) => queryFullHierarchyTree(registry2, device, target),
148172
+ "android": (registry2, device) => queryAndroidFullHierarchy(registry2, device),
148173
+ "chromium": (registry2, device) => queryChromiumTree(registry2, device),
148174
+ "vega": (_registry, device) => queryVegaTree(device)
148184
148175
  };
148185
- function supportsFlowTree(platform) {
148186
- return FLOW_TREE_SOURCES[platform] !== void 0;
148187
- }
148188
148176
 
148189
148177
  // ../tool-server/src/tools/flows/flow-pixels.ts
148190
148178
  var fs53 = __toESM(require("node:fs/promises"));
@@ -148628,12 +148616,10 @@ async function runDirective(env, step) {
148628
148616
  }
148629
148617
  async function settleForGesture(env) {
148630
148618
  let warning;
148631
- if (supportsFlowTree(env.device.platform)) {
148632
- try {
148633
- await settleTree(env, { skipProvenOutage: true });
148634
- } catch (err) {
148635
- warning = unsettledGestureWarning(err);
148636
- }
148619
+ try {
148620
+ await settleTree(env, { skipProvenOutage: true });
148621
+ } catch (err) {
148622
+ warning = unsettledGestureWarning(err);
148637
148623
  }
148638
148624
  if (env.signal?.aborted) return { aborted: true };
148639
148625
  return warning !== void 0 ? { warning } : {};
@@ -149516,9 +149502,6 @@ function fallbackSourceWarning(source, platform) {
149516
149502
  function platformOf(udid) {
149517
149503
  return typeof udid === "string" ? authoringPlatform(resolveDevice(udid).platform) : void 0;
149518
149504
  }
149519
- function hasRunnerTree(udid) {
149520
- return typeof udid === "string" && supportsFlowTree(resolveDevice(udid).platform);
149521
- }
149522
149505
  var UNSUPPORTED_PLATFORM = {
149523
149506
  divergence: "The recorder and the runner read different projections of the screen.",
149524
149507
  read: "No read-only tool is known to report the runner's projection on this platform \u2014 keep the step raw"
@@ -149592,7 +149575,6 @@ function unmetWaitWarningFor(cause) {
149592
149575
  }
149593
149576
  function indeterminateReasonCaveat(udid) {
149594
149577
  if (platformOf(udid) !== "ios") return "";
149595
- if (!hasRunnerTree(udid)) return "";
149596
149578
  return ". One thing that reason cannot see is this step: the probe predicts an `await:`/`assert:` directive, and no directive takes a bundleId, so neither this probe nor the runner accepts one (the `bundleId` on this step reached the live wait only)";
149597
149579
  }
149598
149580
  var CANCELLED_PROBE_WARNING = "recorded, but the re-probe against the tree the RUNNER reads was cancelled before it answered. The step itself ran and is written to the flow; only the verdict is missing, so whether it would convert to `await:`/`assert:` is UNKNOWN, not known-bad \u2014 record the wait again, uncancelled, before trusting the conversion";
@@ -149657,9 +149639,8 @@ async function probeAgainstRunnerTree(registry2, ctx, args) {
149657
149639
  // The reason is quoted whole rather than through `cappedReason`; see
149658
149640
  // {@link MAX_PROBE_REASON_CHARS}.
149659
149641
  warning: `this check could not be re-verified against the tree the RUNNER reads (${outcome.reason ?? "no reason given"}), so it passed against the tree \`${AWAIT_UI_ELEMENT_TOOL_ID}\` reads and nothing else. Whether it would convert to \`await:\`/\`assert:\` is UNKNOWN, not known-bad \u2014 ` + // A timeout and an outage need different next moves: "once that tree
149660
- // source is back" is nonsense for a source that never left, and for one
149661
- // that never existed.
149662
- (timedOut2 ? `re-record this step when the device is quieter, or settle the conversion directly by putting the directive in a flow and running \`flow-execute\`, which has no such ceiling` : (hasRunnerTree(args.udid) ? `re-probe once that tree source is back before trusting the conversion` : `this platform's runner has no tree to probe, so the conversion stays unverified`) + indeterminateReasonCaveat(args.udid))
149642
+ // source is back" is nonsense for a source that never left.
149643
+ (timedOut2 ? `re-record this step when the device is quieter, or settle the conversion directly by putting the directive in a flow and running \`flow-execute\`, which has no such ceiling` : `re-probe once that tree source is back before trusting the conversion` + indeterminateReasonCaveat(args.udid))
149663
149644
  };
149664
149645
  }
149665
149646
  return {
@@ -154212,7 +154193,7 @@ async function treeSourceGate(registry2, device, bundleId, signal) {
154212
154193
  return `the on-device XCUITest runner did not become ready for ${device.id}: ${err instanceof Error ? err.message : String(err)}`;
154213
154194
  }
154214
154195
  }
154215
- if (device.platform === "ios" && !signal?.aborted) {
154196
+ if ((device.platform === "ios" || device.platform === "ios-remote") && !signal?.aborted) {
154216
154197
  const reason = await waitForNativeDevtools(registry2, device, bundleId, signal);
154217
154198
  if (reason !== null && !signal?.aborted) {
154218
154199
  return `could not connect to native devtools. ${reason}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.25.1-next.30",
3
+ "version": "0.25.1-next.32",
4
4
  "mcpName": "io.github.software-mansion/argent",
5
5
  "description": "MCP server for iOS Simulator and Android Emulator control",
6
6
  "license": "Apache-2.0",
@@ -111,7 +111,7 @@ Scopes can combine and nest, with at most six scope keys. Use strict selectors f
111
111
 
112
112
  Directives stop the flow on failure and skip later steps. The available directives are `launch`, `tap`, `long-press`, `swipe`, `type`, `scroll-to`, `pinch`, `rotate`, `await`, `assert`, `wait`, `snapshot`, `run`, `script`, `when`, `echo`, and `tool`.
113
113
 
114
- Use the launch map for cross-platform flows. A bare launch applies everywhere and becomes an app path on Chromium. The map takes `native:`, `ios:`, `android:`, `vega:`, and `chromium:`. `native:` is one id shared by iOS, Android, and Vega, and a per-platform key overrides it for that platform. `chromium:` accepts a relative or absolute app path. A launch that declares no id for the run's platform is an error, not a cue to switch platforms. On iOS, a successful launch also pins later tree reads to that app until the next raw `tool:` step, so read [The runner tree is not the discovery tree](#the-runner-tree-is-not-the-discovery-tree) when a read describes the wrong screen.
114
+ Use the launch map for cross-platform flows. A bare launch applies everywhere and becomes an app path on Chromium. The map takes `native:`, `ios:`, `android:`, `vega:`, and `chromium:`. `native:` is one id shared by iOS, Android, and Vega, and a per-platform key overrides it for that platform. `chromium:` accepts a relative or absolute app path. A launch that declares no id for the run's platform is an error, not a cue to switch platforms. A run on a remote simulator uses the `ios:` id, or the `native:` id when the map has no `ios:` key, so no flow needs a key for a remote run. On iOS, a successful launch also pins later tree reads to that app until the next raw `tool:` step, so read [The runner tree is not the discovery tree](#the-runner-tree-is-not-the-discovery-tree) when a read describes the wrong screen.
115
115
 
116
116
  ```yaml
117
117
  - launch: { native: com.acme.app, chromium: ../../app }
@@ -219,7 +219,7 @@ Use `when:` only for optional setup or an interstitial that reconverges:
219
219
  - tap: { text: Got it }
220
220
  ```
221
221
 
222
- The guard accepts one `exists`, `visible`, `hidden`, or `text` condition, or `{ platform: ios|android|chromium|vega }`. UI guards use the short assert grace and reject `timeout`. There is no `else` or per-step `optional`. Put separate behavioral paths in separate flows. Never place a required acceptance check inside `when:`.
222
+ The guard accepts one `exists`, `visible`, `hidden`, or `text` condition, or `{ platform: ios|android|chromium|vega }`. A run on a remote simulator matches `ios`. UI guards use the short assert grace and reject `timeout`. There is no `else` or per-step `optional`. Put separate behavioral paths in separate flows. Never place a required acceptance check inside `when:`.
223
223
 
224
224
  ## Composition and platform limits
225
225
 
@@ -249,7 +249,7 @@ If a script fails, check its changes before you retry.
249
249
 
250
250
  ## Snapshots and standalone runs
251
251
 
252
- `argent flow run <name> [--device <id>] [--platform ios|android|chromium|vega] [--update-baselines] [--output <dir>] [--json]` runs without an LLM and exits non-zero on failure.
252
+ `argent flow run <name> [--device <id>] [--platform ios|android|chromium|vega|ios-remote] [--update-baselines] [--output <dir>] [--json]` runs without an LLM and exits non-zero on failure.
253
253
 
254
254
  A screenshot is human evidence. A `snapshot:` is executable visual verification. A missing baseline or excessive mismatch fails. A `cropOn` size change also fails. Use snapshots for color, layout, size, spacing, typography, clipping, overflow, images, icons, or stable component appearance. Use full screen for global changes and `cropOn` for one component.
255
255