@swmansion/argent 0.15.1-next.3 → 0.15.1-next.4

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.
@@ -144547,6 +144547,12 @@ function toYamlStep(step) {
144547
144547
  const body = step.selector ? selectorToYaml(step.selector) : { x: step.x, y: step.y };
144548
144548
  return { tap: body };
144549
144549
  }
144550
+ case "long-press": {
144551
+ const sel = selectorToYaml(step.selector);
144552
+ return {
144553
+ "long-press": step.duration !== void 0 ? { on: sel, duration: step.duration } : sel
144554
+ };
144555
+ }
144550
144556
  case "type": {
144551
144557
  const body = {
144552
144558
  into: selectorToYaml(step.into),
@@ -144796,6 +144802,7 @@ var STEP_DIRECTIVE_KEYS = [
144796
144802
  "run",
144797
144803
  "tool",
144798
144804
  "tap",
144805
+ "long-press",
144799
144806
  "type",
144800
144807
  "await",
144801
144808
  "assert",
@@ -144803,6 +144810,35 @@ var STEP_DIRECTIVE_KEYS = [
144803
144810
  "scroll-to",
144804
144811
  "snapshot"
144805
144812
  ];
144813
+ function parseLongPress(body, entry) {
144814
+ const obj = body !== null && typeof body === "object" ? body : {};
144815
+ if (obj.on !== void 0 || obj.duration !== void 0) {
144816
+ if (obj.text !== void 0 || obj.id !== void 0 || obj.identifier !== void 0 || obj.role !== void 0) {
144817
+ badEntry(
144818
+ entry,
144819
+ 'the long-press options form takes a nested selector \u2014 e.g. long-press: { on: { text: "Row" }, duration: 1200 }'
144820
+ );
144821
+ }
144822
+ if (!Object.keys(obj).every((k) => k === "on" || k === "duration")) {
144823
+ badEntry(entry, "the long-press options form accepts only { on, duration }");
144824
+ }
144825
+ if (obj.on === void 0) {
144826
+ badEntry(entry, 'long-press needs a target \u2014 e.g. long-press: { on: "Row", duration: 1200 }');
144827
+ }
144828
+ const step = { kind: "long-press", selector: parseSelector(obj.on, "long-press.on") };
144829
+ if (obj.duration !== void 0) {
144830
+ if (typeof obj.duration !== "number" || !Number.isFinite(obj.duration) || obj.duration <= 0) {
144831
+ badEntry(
144832
+ entry,
144833
+ "long-press.duration needs a positive number of milliseconds (e.g. `duration: 1200`)"
144834
+ );
144835
+ }
144836
+ step.duration = obj.duration;
144837
+ }
144838
+ return step;
144839
+ }
144840
+ return { kind: "long-press", selector: parseSelector(body, "long-press") };
144841
+ }
144806
144842
  function fromYamlStep(raw) {
144807
144843
  const entry = raw;
144808
144844
  const kinds = STEP_DIRECTIVE_KEYS.filter((k) => k in entry);
@@ -144845,6 +144881,9 @@ function fromYamlStep(raw) {
144845
144881
  }
144846
144882
  return { kind: "tap", selector: parseSelector(body, "tap") };
144847
144883
  }
144884
+ if ("long-press" in raw) {
144885
+ return parseLongPress(raw["long-press"], raw);
144886
+ }
144848
144887
  if ("type" in raw) {
144849
144888
  const body = raw.type;
144850
144889
  if (!body || typeof body !== "object") badEntry(raw, "type needs { into, text }");
@@ -145776,6 +145815,8 @@ You can still edit the .yaml file directly afterwards to remove or reorder steps
145776
145815
  return `${n}. run: ${step.flow}`;
145777
145816
  case "tap":
145778
145817
  return `${n}. tap: ${step.selector ? selectorLabel(step.selector) : `(${step.x}, ${step.y})`}`;
145818
+ case "long-press":
145819
+ return `${n}. long-press: ${selectorLabel(step.selector)}`;
145779
145820
  case "type":
145780
145821
  return `${n}. type: ${selectorLabel(step.into)} \u2190 "${step.text}"`;
145781
145822
  case "await":
@@ -146022,7 +146063,7 @@ function offscreenHint(sel) {
146022
146063
  return `no visible element matched selector ${describeSelector(sel)} \u2014 if it is off-screen, add a scroll-to step before this one`;
146023
146064
  }
146024
146065
  async function runDirective(env, step) {
146025
- if (env.device.platform === "vega" && (step.kind === "tap" || step.kind === "type" || step.kind === "scroll-to")) {
146066
+ if (env.device.platform === "vega" && (step.kind === "tap" || step.kind === "long-press" || step.kind === "type" || step.kind === "scroll-to")) {
146026
146067
  return {
146027
146068
  ok: false,
146028
146069
  reason: `${step.kind} is a touch directive and Vega is remote-driven \u2014 move focus with \`tool: tv-remote\` steps (and type via \`tool: keyboard\`) instead`
@@ -146031,6 +146072,8 @@ async function runDirective(env, step) {
146031
146072
  switch (step.kind) {
146032
146073
  case "tap":
146033
146074
  return runTap(env, step);
146075
+ case "long-press":
146076
+ return runLongPress(env, step);
146034
146077
  case "type":
146035
146078
  return runType(env, step);
146036
146079
  case "await":
@@ -146061,6 +146104,33 @@ async function runTap(env, target) {
146061
146104
  await invokeOnDevice(env, "gesture-tap", point);
146062
146105
  return { ok: true };
146063
146106
  }
146107
+ var DEFAULT_LONG_PRESS_MS = 800;
146108
+ async function runLongPress(env, step) {
146109
+ const frame = await waitForFrame(env, step.selector);
146110
+ if (frame === "aborted") return ABORTED_OUTCOME;
146111
+ if (!frame) {
146112
+ return { ok: false, reason: offscreenHint(step.selector) };
146113
+ }
146114
+ const point = getDescribeTapPoint(frame);
146115
+ const duration3 = step.duration ?? DEFAULT_LONG_PRESS_MS;
146116
+ if (env.device.platform === "chromium") {
146117
+ await invokeOnDevice(env, "gesture-drag", {
146118
+ fromX: point.x,
146119
+ fromY: point.y,
146120
+ toX: point.x,
146121
+ toY: point.y,
146122
+ durationMs: duration3
146123
+ });
146124
+ } else {
146125
+ await invokeOnDevice(env, "gesture-custom", {
146126
+ events: [
146127
+ { type: "Down", x: point.x, y: point.y, delayMs: 0 },
146128
+ { type: "Up", x: point.x, y: point.y, delayMs: duration3 }
146129
+ ]
146130
+ });
146131
+ }
146132
+ return { ok: true };
146133
+ }
146064
146134
  async function runType(env, step) {
146065
146135
  const frame = await waitForFrame(env, step.into);
146066
146136
  if (frame === "aborted") return ABORTED_OUTCOME;
@@ -148495,8 +148565,9 @@ function createRunFlowTool(registry2) {
148495
148565
  id: "flow-execute",
148496
148566
  description: `Run a saved flow from the .argent/flows/ directory.
148497
148567
  Steps run in order: \`launch\` starts an app from scratch (terminate + relaunch) and waits until it is
148498
- ready; \`tool\` calls dispatch through the registry; \`tap\`/\`type\` resolve a selector to an element and
148499
- act on it; \`scroll-to\` scrolls (momentum-free) until a target is visible; \`await\` waits for a UI
148568
+ ready; \`tool\` calls dispatch through the registry; \`tap\`/\`long-press\`/\`type\` resolve a selector to an
148569
+ element and act on it (\`long-press: { on, duration }\` presses and holds); \`scroll-to\` scrolls
148570
+ (momentum-free) until a target is visible; \`await\` waits for a UI
148500
148571
  condition; \`wait\` pauses for a fixed number of milliseconds; \`assert\` checks one now; \`snapshot\`
148501
148572
  diffs a screenshot against a stored baseline (a missing baseline fails the step \u2014 set updateBaselines
148502
148573
  to adopt the current screen); \`echo\` annotates; \`run\` executes a referenced fragment inline.
@@ -148651,6 +148722,8 @@ function stepTarget(step) {
148651
148722
  if (step.selector) return selectorLabel2(step.selector);
148652
148723
  if (step.x !== void 0 && step.y !== void 0) return `(${step.x}, ${step.y})`;
148653
148724
  return void 0;
148725
+ case "long-press":
148726
+ return selectorLabel2(step.selector);
148654
148727
  case "type":
148655
148728
  return `into ${selectorLabel2(step.into)}`;
148656
148729
  case "await":
@@ -148746,6 +148819,7 @@ async function execLeafStep(state3, step, index, sourceFlow) {
148746
148819
  return { ...base, status: r.ok ? "pass" : "error", reason: r.reason };
148747
148820
  }
148748
148821
  case "tap":
148822
+ case "long-press":
148749
148823
  case "type":
148750
148824
  case "await":
148751
148825
  case "assert":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.15.1-next.3",
3
+ "version": "0.15.1-next.4",
4
4
  "description": "MCP server for iOS Simulator and Android Emulator control",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -20,17 +20,18 @@ Both run via `argent flow run <name>` — a fragment simply runs against whateve
20
20
 
21
21
  Beyond raw `tool:` steps and `echo:`, flows support declarative directives interpreted by the runner (they are **not** agent-callable tools). **Every directive hard-stops the flow on failure**; later steps are reported `skip`.
22
22
 
23
- | Directive | YAML | Meaning |
24
- | ----------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
25
- | `launch` | `- launch: com.acme.app` or `- launch: { ios: …, android: … }` | start the app from scratch (terminate + relaunch) and wait until ready |
26
- | `tap` | `- tap: Login` or `- tap: { x: 0.5, y: 0.57 }` | tap an element by selector (auto-waits), or a raw normalized point |
27
- | `type` | `- type: { into: email, text: "a@b.com" }` | focus a field, type, then press Enter to submit + dismiss the keyboard |
28
- | `scroll-to` | `- scroll-to: "Order #1234"` (scrolls down) or `- scroll-to: { target: …, direction: right, within: }` | momentum-free scroll until the target is visible |
29
- | `await` | `- await: { visible: Home }` | wait for a UI condition |
30
- | `wait` | `- wait: 500` | pause for a fixed number of milliseconds (last resort — prefer `await`) |
31
- | `assert` | `- assert: { visible: Welcome }` | check a condition, hard-fail if it never holds |
32
- | `snapshot` | `- snapshot: home` or `- snapshot: { name: home, maxMismatch: 0.5 }` | diff a screenshot against a stored baseline |
33
- | `run` | `- run: login` | execute a fragment's steps inline |
23
+ | Directive | YAML | Meaning |
24
+ | ------------ | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
25
+ | `launch` | `- launch: com.acme.app` or `- launch: { ios: …, android: … }` | start the app from scratch (terminate + relaunch) and wait until ready |
26
+ | `tap` | `- tap: Login` or `- tap: { x: 0.5, y: 0.57 }` | tap an element by selector (auto-waits), or a raw normalized point |
27
+ | `long-press` | `- long-press: Row 3` or `- long-press: { on: <sel>, duration: 1200 }` | press and hold an element (default 800ms; Chromium: mouse press-hold) |
28
+ | `type` | `- type: { into: email, text: "a@b.com" }` | focus a field, type, then press Enter to submit + dismiss the keyboard |
29
+ | `scroll-to` | `- scroll-to: "Order #1234"` (scrolls down) or `- scroll-to: { target: …, direction: right, within: … }` | momentum-free scroll until the target is visible |
30
+ | `await` | `- await: { visible: Home }` | wait for a UI condition |
31
+ | `wait` | `- wait: 500` | pause for a fixed number of milliseconds (last resort — prefer `await`) |
32
+ | `assert` | `- assert: { visible: Welcome }` | check a condition, hard-fail if it never holds |
33
+ | `snapshot` | `- snapshot: home` or `- snapshot: { name: home, maxMismatch: 0.5 }` | diff a screenshot against a stored baseline |
34
+ | `run` | `- run: login` | execute a fragment's steps inline |
34
35
 
35
36
  ### Selectors
36
37
 
@@ -60,7 +61,7 @@ For a custom poll interval or bundleId, drop to an explicit `- tool: await-ui-el
60
61
 
61
62
  ### TV targets (Vega)
62
63
 
63
- A Vega (Fire TV) device is remote-driven — there is no touch input, so the touch directives (`tap`, `type`, `scroll-to`) fail on it with guidance. Drive focus with `tool: tv-remote` steps and type with `tool: keyboard` instead; everything else (`launch`, `await`, `assert`, `wait`, `snapshot`, `echo`, `run`, selectors) works unchanged — the tree comes from the on-device automation toolkit, which attaches at app launch (the `launch` step waits for it, so a leading `launch` also guarantees selectors resolve).
64
+ A Vega (Fire TV) device is remote-driven — there is no touch input, so the touch directives (`tap`, `long-press`, `type`, `scroll-to`) fail on it with guidance. Drive focus with `tool: tv-remote` steps and type with `tool: keyboard` instead; everything else (`launch`, `await`, `assert`, `wait`, `snapshot`, `echo`, `run`, selectors) works unchanged — the tree comes from the on-device automation toolkit, which attaches at app launch (the `launch` step waits for it, so a leading `launch` also guarantees selectors resolve).
64
65
 
65
66
  ```yaml
66
67
  steps: