@swmansion/argent 0.21.1-next.16 → 0.21.1-next.18

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.
Binary file
Binary file
Binary file
Binary file
package/dist/cli-cmds.mjs CHANGED
@@ -2309,6 +2309,8 @@ var FAILURE_CODES = {
2309
2309
  IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
2310
2310
  IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
2311
2311
  ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
2312
+ PASTE_CLIPBOARD_SET_FAILED: "PASTE_CLIPBOARD_SET_FAILED",
2313
+ PASTE_CLIPBOARD_UNSUPPORTED: "PASTE_CLIPBOARD_UNSUPPORTED",
2312
2314
  SETTINGS_PERMISSION_UNSUPPORTED: "SETTINGS_PERMISSION_UNSUPPORTED",
2313
2315
  NATIVE_DEVTOOLS_DESCRIBE_ERROR: "NATIVE_DEVTOOLS_DESCRIBE_ERROR",
2314
2316
  NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR: "NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR",
@@ -7214,7 +7216,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
7214
7216
  var SESSION_ID2 = randomUUID5();
7215
7217
  function readCliVersion() {
7216
7218
  if (true) {
7217
- return "0.21.1-next.16";
7219
+ return "0.21.1-next.18";
7218
7220
  }
7219
7221
  return "0.0.0";
7220
7222
  }
@@ -15468,6 +15468,8 @@ var FAILURE_CODES = {
15468
15468
  IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
15469
15469
  IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
15470
15470
  ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
15471
+ PASTE_CLIPBOARD_SET_FAILED: "PASTE_CLIPBOARD_SET_FAILED",
15472
+ PASTE_CLIPBOARD_UNSUPPORTED: "PASTE_CLIPBOARD_UNSUPPORTED",
15471
15473
  SETTINGS_PERMISSION_UNSUPPORTED: "SETTINGS_PERMISSION_UNSUPPORTED",
15472
15474
  NATIVE_DEVTOOLS_DESCRIBE_ERROR: "NATIVE_DEVTOOLS_DESCRIBE_ERROR",
15473
15475
  NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR: "NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR",
@@ -16434,7 +16436,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
16434
16436
  var SESSION_ID = randomUUID4();
16435
16437
  function readCliVersion() {
16436
16438
  if (true) {
16437
- return "0.21.1-next.16";
16439
+ return "0.21.1-next.18";
16438
16440
  }
16439
16441
  return "0.0.0";
16440
16442
  }
@@ -16493,6 +16493,8 @@ var FAILURE_CODES = {
16493
16493
  IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
16494
16494
  IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
16495
16495
  ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
16496
+ PASTE_CLIPBOARD_SET_FAILED: "PASTE_CLIPBOARD_SET_FAILED",
16497
+ PASTE_CLIPBOARD_UNSUPPORTED: "PASTE_CLIPBOARD_UNSUPPORTED",
16496
16498
  SETTINGS_PERMISSION_UNSUPPORTED: "SETTINGS_PERMISSION_UNSUPPORTED",
16497
16499
  NATIVE_DEVTOOLS_DESCRIBE_ERROR: "NATIVE_DEVTOOLS_DESCRIBE_ERROR",
16498
16500
  NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR: "NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR",
@@ -18491,6 +18493,7 @@ var AUTO_SCREENSHOT_TOOLS = /* @__PURE__ */ new Set([
18491
18493
  "gesture-rotate",
18492
18494
  "button",
18493
18495
  "keyboard",
18496
+ "paste",
18494
18497
  "rotate",
18495
18498
  "launch-app",
18496
18499
  "restart-app",
@@ -18513,6 +18516,7 @@ var AUTO_SCREENSHOT_DELAY_MS_BY_TOOL = {
18513
18516
  "button": 1500,
18514
18517
  "rotate": 1e3,
18515
18518
  "keyboard": 300,
18519
+ "paste": 300,
18516
18520
  "describe": 100
18517
18521
  };
18518
18522
  var DEFAULT_DELAY_MS = 1400;
@@ -610,6 +610,8 @@ var init_failure_codes = __esm({
610
610
  IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
611
611
  IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
612
612
  ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
613
+ PASTE_CLIPBOARD_SET_FAILED: "PASTE_CLIPBOARD_SET_FAILED",
614
+ PASTE_CLIPBOARD_UNSUPPORTED: "PASTE_CLIPBOARD_UNSUPPORTED",
613
615
  SETTINGS_PERMISSION_UNSUPPORTED: "SETTINGS_PERMISSION_UNSUPPORTED",
614
616
  NATIVE_DEVTOOLS_DESCRIBE_ERROR: "NATIVE_DEVTOOLS_DESCRIBE_ERROR",
615
617
  NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR: "NATIVE_DEVTOOLS_VIEW_AT_POINT_ERROR",
@@ -95690,7 +95692,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
95690
95692
  var SESSION_ID = (0, import_node_crypto3.randomUUID)();
95691
95693
  function readCliVersion() {
95692
95694
  if (true) {
95693
- return "0.21.1-next.16";
95695
+ return "0.21.1-next.18";
95694
95696
  }
95695
95697
  return "0.0.0";
95696
95698
  }
@@ -98281,23 +98283,23 @@ var InvalidToolInputError = class extends Error {
98281
98283
  });
98282
98284
  }
98283
98285
  };
98284
- function platformMatrix(platform, capability33) {
98286
+ function platformMatrix(platform, capability34) {
98285
98287
  switch (platform) {
98286
98288
  case "ios":
98287
- return capability33.apple;
98289
+ return capability34.apple;
98288
98290
  case "ios-remote":
98289
- return capability33.appleRemote;
98291
+ return capability34.appleRemote;
98290
98292
  case "android":
98291
- return capability33.android;
98293
+ return capability34.android;
98292
98294
  case "chromium":
98293
- return capability33.chromium;
98295
+ return capability34.chromium;
98294
98296
  case "vega":
98295
- return capability33.vega;
98297
+ return capability34.vega;
98296
98298
  }
98297
98299
  }
98298
- function assertSupported(toolId, capability33, device) {
98299
- if (!capability33) return;
98300
- const matrix = platformMatrix(device.platform, capability33);
98300
+ function assertSupported(toolId, capability34, device) {
98301
+ if (!capability34) return;
98302
+ const matrix = platformMatrix(device.platform, capability34);
98301
98303
  if (!matrix) {
98302
98304
  throw new UnsupportedOperationError(toolId, device, `no ${device.platform} support declared`);
98303
98305
  }
@@ -98305,7 +98307,7 @@ function assertSupported(toolId, capability33, device) {
98305
98307
  if (!supported) {
98306
98308
  throw new UnsupportedOperationError(toolId, device, `kind '${device.kind}' not supported`);
98307
98309
  }
98308
- if (capability33.supports && !capability33.supports(device)) {
98310
+ if (capability34.supports && !capability34.supports(device)) {
98309
98311
  throw new UnsupportedOperationError(toolId, device, "supports() refiner rejected device");
98310
98312
  }
98311
98313
  }
@@ -108130,6 +108132,42 @@ async function pointerPost(api, body, signal) {
108130
108132
  return false;
108131
108133
  }
108132
108134
  }
108135
+ async function setSimulatorClipboardText(api, text, signal) {
108136
+ let res;
108137
+ try {
108138
+ res = await fetch(`${api.apiUrl}/api/clipboard/text`, {
108139
+ method: "POST",
108140
+ headers: { "Content-Type": "application/json" },
108141
+ body: JSON.stringify({ text }),
108142
+ signal
108143
+ });
108144
+ } catch (err) {
108145
+ throw toSimulatorNetworkError("Paste", err, api.apiUrl);
108146
+ }
108147
+ if (res.status === 404) {
108148
+ throw new FailureError(
108149
+ "Paste failed: this simulator-server build has no clipboard endpoint. Update argent so its bundled simulator-server includes clipboard support, or type the text with the keyboard tool instead.",
108150
+ {
108151
+ error_code: FAILURE_CODES.PASTE_CLIPBOARD_UNSUPPORTED,
108152
+ failure_stage: "simulator_clipboard_endpoint_missing",
108153
+ failure_area: "tool_server",
108154
+ error_kind: "unsupported"
108155
+ }
108156
+ );
108157
+ }
108158
+ const body = await res.json().catch(() => null);
108159
+ if (!res.ok || body?.status !== "ok") {
108160
+ throw new FailureError(
108161
+ `Paste failed: could not set the device clipboard (${body?.error ?? `HTTP ${res.status}`}).`,
108162
+ {
108163
+ error_code: FAILURE_CODES.PASTE_CLIPBOARD_SET_FAILED,
108164
+ failure_stage: "simulator_clipboard_set",
108165
+ failure_area: "tool_server",
108166
+ error_kind: "unknown"
108167
+ }
108168
+ );
108169
+ }
108170
+ }
108133
108171
  async function simulatorPost(toolLabel, api, endpoint, reqBody, signal, fallbackHint) {
108134
108172
  let res;
108135
108173
  try {
@@ -108245,10 +108283,6 @@ function routeViaTransport(transport, cmd) {
108245
108283
  case "rotate":
108246
108284
  transport.rotate(cmd.direction);
108247
108285
  return;
108248
- case "paste": {
108249
- void Promise.resolve(transport.paste(cmd.text));
108250
- return;
108251
- }
108252
108286
  default:
108253
108287
  throw new Error(`MoQ transport does not implement sendCommand cmd '${String(cmd.cmd)}'`);
108254
108288
  }
@@ -122346,13 +122380,176 @@ One call does one action: pass text OR key, never both. To type and then press a
122346
122380
  };
122347
122381
  }
122348
122382
 
122383
+ // ../tool-server/src/tools/paste/schema.ts
122384
+ init_zod();
122385
+ var pasteZodSchema = external_exports.object({
122386
+ udid: external_exports.string().min(1).describe(
122387
+ "Target device id from `list-devices` (iOS simulator UDID or Android emulator serial)."
122388
+ ),
122389
+ text: external_exports.string().min(1).describe(
122390
+ "Text to put on the device clipboard and paste into the focused field. Supports `{{secret:<NAME>}}` placeholders, resolved on the tool-server from the `ARGENT_SECRET_<NAME>` environment variable or an argent secrets file \u2014 the same sources as `keyboard` \u2014 so a credential never enters your context. If the secret is not set, the failure lists the available names and every source it looked in; ask the user to add it there, NEVER ask for the value in the conversation."
122391
+ )
122392
+ });
122393
+
122394
+ // ../tool-server/src/tools/paste/platforms/ios.ts
122395
+ var LEFT_GUI_KEYCODE = 227;
122396
+ var V_KEYCODE = charToKeyPress("v").keyCode;
122397
+ var CHORD_STEP_MS = 50;
122398
+ var sleep10 = (ms) => new Promise((r) => setTimeout(r, ms));
122399
+ function rejectTv(device) {
122400
+ throw new UnsupportedOperationError(
122401
+ "paste",
122402
+ device,
122403
+ "tvOS has no pasteboard to paste from \u2014 type into the focused field with keyboard instead"
122404
+ );
122405
+ }
122406
+ async function pasteSimulator(api, text) {
122407
+ await setSimulatorClipboardText(api, text);
122408
+ api.pressKey("Down", LEFT_GUI_KEYCODE);
122409
+ await sleep10(CHORD_STEP_MS);
122410
+ api.pressKey("Down", V_KEYCODE);
122411
+ await sleep10(CHORD_STEP_MS);
122412
+ api.pressKey("Up", V_KEYCODE);
122413
+ await sleep10(CHORD_STEP_MS);
122414
+ api.pressKey("Up", LEFT_GUI_KEYCODE);
122415
+ await sleep10(CHORD_STEP_MS);
122416
+ return { pasted: true };
122417
+ }
122418
+ function makeIosImpl4(registry2) {
122419
+ return {
122420
+ // `isTvOsSimulator` shells out to `simctl`; the simulator-server itself is
122421
+ // resolved through the blueprint.
122422
+ requires: ["xcrun"],
122423
+ async handler(_services, params, device) {
122424
+ if (await isTvOsSimulator(device.id)) rejectTv(device);
122425
+ const ref = simulatorServerRef(device);
122426
+ const api = await registry2.resolveService(ref.urn, ref.options);
122427
+ return pasteSimulator(api, params.text);
122428
+ }
122429
+ };
122430
+ }
122431
+ function makeIosRemoteImpl2(registry2) {
122432
+ return {
122433
+ requires: ["sim-remote"],
122434
+ async handler(_services, params, device) {
122435
+ if (await isRemoteTvOsSimulator(device.id)) rejectTv(device);
122436
+ const ref = simulatorServerRef(device);
122437
+ const api = await registry2.resolveService(ref.urn, ref.options);
122438
+ if (!api.transport) {
122439
+ throw new Error(
122440
+ `Tool 'paste' resolved an ios-remote simulator-server without a transport for ${device.id}.`
122441
+ );
122442
+ }
122443
+ await api.transport.paste(params.text);
122444
+ return { pasted: true };
122445
+ }
122446
+ };
122447
+ }
122448
+
122449
+ // ../tool-server/src/tools/paste/platforms/android.ts
122450
+ init_adb();
122451
+ var KEYCODE_PASTE = 279;
122452
+ function makeAndroidImpl2(registry2) {
122453
+ return {
122454
+ requires: ["adb"],
122455
+ async handler(_services, params, device) {
122456
+ if (await isAndroidTv(device.id)) {
122457
+ throw new UnsupportedOperationError(
122458
+ "paste",
122459
+ device,
122460
+ "Android TV is focus-driven \u2014 type into the focused field with keyboard instead"
122461
+ );
122462
+ }
122463
+ const ref = simulatorServerRef(device);
122464
+ const api = await registry2.resolveService(ref.urn, ref.options);
122465
+ await setSimulatorClipboardText(api, params.text);
122466
+ await injectAndroidKeycode(device.id, KEYCODE_PASTE);
122467
+ return { pasted: true };
122468
+ }
122469
+ };
122470
+ }
122471
+
122472
+ // ../tool-server/src/tools/paste/index.ts
122473
+ var capability17 = {
122474
+ // Simulators only. A physical iPhone's pasteboard is reachable through the
122475
+ // same simulator-server endpoint, but the paste keystroke is not verified
122476
+ // over the CoreDevice HID path, so `device` stays off until it is.
122477
+ apple: { simulator: true },
122478
+ // A remote simulator pastes through the MoQ transport's existing paste
122479
+ // primitive (device pasteboard + ⌘V on the remote host).
122480
+ appleRemote: { simulator: true },
122481
+ // Emulators only: the clipboard is set through the emulator's gRPC
122482
+ // endpoint, which a physical phone does not have. `unknown` is admitted
122483
+ // because an unresolved serial may still be an emulator — the
122484
+ // simulator-server refuses a phone either way.
122485
+ android: { emulator: true, unknown: true }
122486
+ // No `chromium`: the renderer can only reach the HOST clipboard, so a paste
122487
+ // there would overwrite whatever the user has copied. No `vega`: no
122488
+ // clipboard API is exposed by the VVD tooling.
122489
+ //
122490
+ // TV targets are not separate platforms (an Apple TV simulator is
122491
+ // `ios`/`simulator`, an Android TV emulator `android`/`emulator`), so each
122492
+ // handler probes the runtime kind and rejects a TV itself.
122493
+ };
122494
+ var pasteQueues = /* @__PURE__ */ new Map();
122495
+ function serializedPerDevice(deviceId, task) {
122496
+ const previous = pasteQueues.get(deviceId) ?? Promise.resolve();
122497
+ const next = previous.then(task, task);
122498
+ pasteQueues.set(deviceId, next);
122499
+ void next.then(
122500
+ () => {
122501
+ if (pasteQueues.get(deviceId) === next) pasteQueues.delete(deviceId);
122502
+ },
122503
+ () => {
122504
+ if (pasteQueues.get(deviceId) === next) pasteQueues.delete(deviceId);
122505
+ }
122506
+ );
122507
+ return next;
122508
+ }
122509
+ function createPasteTool(registry2) {
122510
+ const dispatch = dispatchByPlatform({
122511
+ toolId: "paste",
122512
+ capability: capability17,
122513
+ ios: makeIosImpl4(registry2),
122514
+ iosRemote: makeIosRemoteImpl2(registry2),
122515
+ android: makeAndroidImpl2(registry2)
122516
+ });
122517
+ return {
122518
+ id: "paste",
122519
+ interaction: {
122520
+ startedMsg: () => "Pasting text",
122521
+ completedMsg: () => "Pasted text",
122522
+ failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to paste text: ${failureSignal2.error_code}`
122523
+ },
122524
+ description: `Paste text into the focused field: puts \`text\` on the DEVICE clipboard (the host clipboard is untouched), then triggers the platform's paste shortcut (iOS simulator, Android emulator).
122525
+ Do NOT use this in place of \`keyboard\`. \`keyboard\` types as a user would and is the default for all text entry; use \`paste\` only where a real user would paste \u2014 a 2FA/OTP code copied from another app, a long link or token, or when testing the app's own paste handling.
122526
+ Tap the field first so it has focus. Returns { pasted: true }. Fails on a TV target, when the device clipboard cannot be set, or when the simulator-server build lacks clipboard support.
122527
+ Supports \`{{secret:<NAME>}}\` placeholders like \`keyboard\`; the value is never echoed back.`,
122528
+ searchHint: "paste clipboard pasteboard otp 2fa code fill field",
122529
+ zodSchema: pasteZodSchema,
122530
+ capability: capability17,
122531
+ services: () => ({}),
122532
+ execute: async (services, params, options) => {
122533
+ const { text, secrets } = resolveSecretPlaceholders(params.text);
122534
+ return serializedPerDevice(params.udid, async () => {
122535
+ if (secrets.length === 0) return dispatch(services, params, options);
122536
+ try {
122537
+ return await dispatch(services, { ...params, text }, options);
122538
+ } catch (err) {
122539
+ throw redactSecretsFromError(err, secrets);
122540
+ }
122541
+ });
122542
+ }
122543
+ };
122544
+ }
122545
+
122349
122546
  // ../tool-server/src/tools/rotate/index.ts
122350
122547
  init_zod();
122351
122548
  var zodSchema25 = external_exports.object({
122352
122549
  udid: external_exports.string().describe("Target device id from `list-devices` (iOS UDID or Android serial)."),
122353
122550
  orientation: external_exports.enum(["Portrait", "LandscapeLeft", "LandscapeRight", "PortraitUpsideDown"]).describe("Target orientation")
122354
122551
  });
122355
- var capability17 = {
122552
+ var capability18 = {
122356
122553
  apple: { simulator: true, device: true },
122357
122554
  appleRemote: { simulator: true },
122358
122555
  android: { emulator: true, device: true, unknown: true }
@@ -122368,7 +122565,7 @@ var rotateTool = {
122368
122565
  Use to test layout in a different orientation. Re-run \`describe\` afterwards \u2014 frame coordinates change with the orientation.
122369
122566
  Returns { orientation }. Fails if the target device is not booted.`,
122370
122567
  zodSchema: zodSchema25,
122371
- capability: capability17,
122568
+ capability: capability18,
122372
122569
  services: (params) => ({
122373
122570
  simulatorServer: simulatorServerRef(resolveDevice(params.udid))
122374
122571
  }),
@@ -122599,9 +122796,9 @@ async function prepareHostWindowShake(target) {
122599
122796
  var execFileAsync20 = (0, import_node_util20.promisify)(import_node_child_process27.execFile);
122600
122797
  var SHAKE_NOTIFICATION = "com.apple.UIKit.SimulatorShake";
122601
122798
  var SHAKE_INTERVAL_MS = 400;
122602
- var sleep10 = (ms) => new Promise((r) => setTimeout(r, ms));
122799
+ var sleep11 = (ms) => new Promise((r) => setTimeout(r, ms));
122603
122800
  var NOTIFYUTIL_ARGV = ["notifyutil", "-p", SHAKE_NOTIFICATION];
122604
- function rejectTv(toolId, device) {
122801
+ function rejectTv2(toolId, device) {
122605
122802
  throw new UnsupportedOperationError(
122606
122803
  toolId,
122607
122804
  device,
@@ -122630,11 +122827,11 @@ var iosImpl4 = {
122630
122827
  async handler(_services, params, device) {
122631
122828
  const { udid } = params;
122632
122829
  const count2 = params.count ?? 1;
122633
- if (await isTvOsSimulator(udid)) rejectTv("shake", device);
122830
+ if (await isTvOsSimulator(udid)) rejectTv2("shake", device);
122634
122831
  const args = await simctlArgsForUdid(udid, ["spawn", udid, ...NOTIFYUTIL_ARGV]);
122635
122832
  const shaker = await prepareHostWindowShake({ kind: "ios", udid, name: device.name });
122636
122833
  for (let i = 0; i < count2; i++) {
122637
- if (i > 0) await sleep10(SHAKE_INTERVAL_MS);
122834
+ if (i > 0) await sleep11(SHAKE_INTERVAL_MS);
122638
122835
  shaker.begin();
122639
122836
  try {
122640
122837
  await execFileAsync20("xcrun", args, { timeout: 15e3 });
@@ -122652,9 +122849,9 @@ var iosRemoteImpl6 = {
122652
122849
  async handler(_services, params, device) {
122653
122850
  const { udid } = params;
122654
122851
  const count2 = params.count ?? 1;
122655
- if (await isRemoteTvOsSimulator(udid)) rejectTv("shake", device);
122852
+ if (await isRemoteTvOsSimulator(udid)) rejectTv2("shake", device);
122656
122853
  for (let i = 0; i < count2; i++) {
122657
- if (i > 0) await sleep10(SHAKE_INTERVAL_MS);
122854
+ if (i > 0) await sleep11(SHAKE_INTERVAL_MS);
122658
122855
  let result;
122659
122856
  try {
122660
122857
  result = await simctlSpawn(udid, { args: NOTIFYUTIL_ARGV });
@@ -122701,7 +122898,7 @@ function restingVectorFrom(stdout) {
122701
122898
  return read;
122702
122899
  }
122703
122900
  var fmt = (v) => `${v.x.toFixed(4)}:${v.y.toFixed(4)}:${v.z.toFixed(4)}`;
122704
- var sleep11 = (ms) => new Promise((r) => setTimeout(r, ms));
122901
+ var sleep12 = (ms) => new Promise((r) => setTimeout(r, ms));
122705
122902
  async function emuConsole(serial, args) {
122706
122903
  const { stdout } = await runAdb(["-s", serial, "emu", ...args], { timeoutMs: 1e4 });
122707
122904
  const lines = stdout.split("\n").map((line) => line.trim()).filter(Boolean);
@@ -122775,7 +122972,7 @@ var androidImpl6 = {
122775
122972
  y: rest.y,
122776
122973
  z: rest.z
122777
122974
  });
122778
- await sleep11(SWING_INTERVAL_MS);
122975
+ await sleep12(SWING_INTERVAL_MS);
122779
122976
  }
122780
122977
  }
122781
122978
  } catch (err) {
@@ -122800,7 +122997,7 @@ var androidImpl6 = {
122800
122997
  };
122801
122998
 
122802
122999
  // ../tool-server/src/tools/shake/index.ts
122803
- var capability18 = {
123000
+ var capability19 = {
122804
123001
  // Simulator only. A physical iPhone's motion comes from real hardware; there
122805
123002
  // is no host-side hook to fake it, so `device` stays false and a paired phone
122806
123003
  // gets a clean 400 instead of a silent no-op.
@@ -122838,13 +123035,13 @@ Works on local and remote (sim-remote) iOS simulators.
122838
123035
  Only phone/tablet simulators and emulators are supported.`,
122839
123036
  searchHint: "shake motion accelerometer undo typing dev menu gesture",
122840
123037
  zodSchema: shakeZodSchema,
122841
- capability: capability18,
123038
+ capability: capability19,
122842
123039
  // Talks to `simctl` / `adb` directly, so no simulator-server is resolved —
122843
123040
  // avoids spawning one (and its ready-wait) for a tool that never uses it.
122844
123041
  services: () => ({}),
122845
123042
  execute: dispatchByPlatform({
122846
123043
  toolId: "shake",
122847
- capability: capability18,
123044
+ capability: capability19,
122848
123045
  ios: iosImpl4,
122849
123046
  iosRemote: iosRemoteImpl6,
122850
123047
  android: androidImpl6
@@ -122894,14 +123091,14 @@ var APPLE_TV_UNSUPPORTED = /* @__PURE__ */ new Set([
122894
123091
  "volumeDown",
122895
123092
  "mute"
122896
123093
  ]);
122897
- function makeIosImpl4(registry2) {
123094
+ function makeIosImpl5(registry2) {
122898
123095
  return {
122899
123096
  handler: (_services, params, device, options) => pressFocusRemote(registry2, device, params, APPLE_TV_UNSUPPORTED, options)
122900
123097
  };
122901
123098
  }
122902
123099
 
122903
123100
  // ../tool-server/src/tools/tv-remote/platforms/android.ts
122904
- function makeAndroidImpl2(registry2) {
123101
+ function makeAndroidImpl3(registry2) {
122905
123102
  return {
122906
123103
  requires: ["adb"],
122907
123104
  handler: (_services, params, device, options) => pressFocusRemote(registry2, device, params, void 0, options)
@@ -122947,7 +123144,7 @@ var zodSchema26 = external_exports.object({
122947
123144
  'Repeat the whole `button` value this many times (default 1). Compact for long same-button runs, e.g. { button: "down", repeat: 12 }.'
122948
123145
  )
122949
123146
  });
122950
- var capability19 = {
123147
+ var capability20 = {
122951
123148
  apple: { simulator: true, device: true },
122952
123149
  android: { emulator: true, device: true, unknown: true },
122953
123150
  vega: { vvd: true }
@@ -122974,13 +123171,13 @@ Returns { pressed, count }.`,
122974
123171
  longRunning: true,
122975
123172
  searchHint: "tv remote dpad d-pad navigate focus up down left right select ok back home menu play pause rewind fast forward sequence path apple tv tvos android tv leanback vega fire tv",
122976
123173
  zodSchema: zodSchema26,
122977
- capability: capability19,
123174
+ capability: capability20,
122978
123175
  services: () => ({}),
122979
123176
  execute: dispatchByPlatform({
122980
123177
  toolId: "tv-remote",
122981
- capability: capability19,
122982
- ios: makeIosImpl4(registry2),
122983
- android: makeAndroidImpl2(registry2),
123178
+ capability: capability20,
123179
+ ios: makeIosImpl5(registry2),
123180
+ android: makeAndroidImpl3(registry2),
122984
123181
  vega: vegaImpl5
122985
123182
  })
122986
123183
  };
@@ -129152,7 +129349,7 @@ var conditionCompleted = {
129152
129349
  hidden: "UI element became hidden",
129153
129350
  text: "UI element matched expected text"
129154
129351
  };
129155
- var capability20 = {
129352
+ var capability21 = {
129156
129353
  apple: { simulator: true, device: true },
129157
129354
  android: { emulator: true, device: true, unknown: true },
129158
129355
  chromium: { app: true },
@@ -129244,7 +129441,7 @@ or before tapping an element that appears asynchronously.`,
129244
129441
  searchHint: "wait await poll until visible hidden exists text appears disappears timeout element condition settle",
129245
129442
  longRunning: true,
129246
129443
  zodSchema: zodSchema27,
129247
- capability: capability20,
129444
+ capability: capability21,
129248
129445
  services: (params) => {
129249
129446
  const device = resolveDevice(params.udid);
129250
129447
  if (device.platform === "chromium") {
@@ -129255,7 +129452,7 @@ or before tapping an element that appears asynchronously.`,
129255
129452
  async execute(services, params, ctx) {
129256
129453
  const signal = ctx?.signal;
129257
129454
  const device = resolveDevice(params.udid);
129258
- assertSupported(AWAIT_UI_ELEMENT_TOOL_ID, capability20, device);
129455
+ assertSupported(AWAIT_UI_ELEMENT_TOOL_ID, capability21, device);
129259
129456
  if (device.platform === "ios") await ensureDeps(iosRequires);
129260
129457
  else if (device.platform === "android") await ensureDeps(androidRequires);
129261
129458
  else if (device.platform === "vega") await ensureDeps(vegaRequires);
@@ -129312,6 +129509,9 @@ var ALLOWED_TOOLS = /* @__PURE__ */ new Set([
129312
129509
  "gesture-rotate",
129313
129510
  "button",
129314
129511
  "keyboard",
129512
+ // `paste` belongs in a sequence for the same reason `keyboard` does: the
129513
+ // focus tap, the paste and the submit are one user action.
129514
+ "paste",
129315
129515
  "rotate",
129316
129516
  // Sequencing matters for shake: the interesting cases are races (shake while
129317
129517
  // a sheet is dismissing, shake right after typing), which need the steps
@@ -129329,7 +129529,7 @@ var zodSchema28 = external_exports.object({
129329
129529
  steps: external_exports.array(
129330
129530
  external_exports.object({
129331
129531
  tool: external_exports.string().describe(
129332
- "Tool name \u2014 one of: gesture-tap, gesture-swipe, gesture-scroll, gesture-drag, gesture-custom, gesture-pinch, gesture-rotate, button, keyboard, rotate, shake, tv-remote, await-ui-element. On a TV target (Apple TV / Android TV / Vega) use tv-remote (remote presses) and keyboard (text)."
129532
+ "Tool name \u2014 one of: gesture-tap, gesture-swipe, gesture-scroll, gesture-drag, gesture-custom, gesture-pinch, gesture-rotate, button, keyboard, paste, rotate, shake, tv-remote, await-ui-element. On a TV target (Apple TV / Android TV / Vega) use tv-remote (remote presses) and keyboard (text)."
129333
129533
  ),
129334
129534
  args: external_exports.record(external_exports.string(), external_exports.unknown()).describe("Tool arguments (excluding udid, which is injected automatically)"),
129335
129535
  delayMs: external_exports.number().optional().describe(
@@ -129338,7 +129538,7 @@ var zodSchema28 = external_exports.object({
129338
129538
  })
129339
129539
  ).min(1).describe("Ordered list of interaction steps to execute sequentially")
129340
129540
  });
129341
- var capability21 = {
129541
+ var capability22 = {
129342
129542
  apple: { simulator: true, device: true },
129343
129543
  appleRemote: { simulator: true },
129344
129544
  android: { emulator: true, device: true, unknown: true },
@@ -129380,6 +129580,7 @@ Allowed tools and their args (udid is auto-injected, do NOT include it in args):
129380
129580
  button: { button: "home"|"back"|"power"|"volumeUp"|"volumeDown"|"appSwitch"|"actionButton" } [ios/android]
129381
129581
  keyboard: { text?: string, key?: string, delayMs?: number } (text OR key per step, never both; TV: text only) [ios/android/chromium/vega/tv]
129382
129582
  text supports {{secret:<NAME>}} placeholders, resolved server-side from ARGENT_SECRET_<NAME> env vars or an argent secrets file \u2014 credentials never enter agent context
129583
+ paste: { text: string } (device clipboard + paste shortcut; only where a user would paste, e.g. an OTP \u2014 keyboard otherwise) [ios sim/android emu]
129383
129584
  rotate: { orientation: "Portrait"|"LandscapeLeft"|"LandscapeRight"|"PortraitUpsideDown" } [ios/android]
129384
129585
  shake: { count?: number } [ios sim/android emu]
129385
129586
  tv-remote: { button: <remote button | array of them>, repeat?: number } [apple tv/android tv/vega]
@@ -129418,7 +129619,7 @@ Stops on the first error (or unmet await-ui-element condition) and returns parti
129418
129619
  longRunning: true,
129419
129620
  searchHint: "batch sequence multiple gesture steps sequentially",
129420
129621
  zodSchema: zodSchema28,
129421
- capability: capability21,
129622
+ capability: capability22,
129422
129623
  // No eagerly-declared service: each step resolves its own services through
129423
129624
  // `invokeSubTool` below (simulator-server for iOS/Android, CDP for
129424
129625
  // Chromium), so run-sequence itself needs none. An eager resolver can't be
@@ -131696,7 +131897,7 @@ function formatDescribeTree(root, opts) {
131696
131897
  }
131697
131898
 
131698
131899
  // ../tool-server/src/tools/describe/platforms/tv.ts
131699
- var sleep12 = (ms) => new Promise((r) => setTimeout(r, ms));
131900
+ var sleep13 = (ms) => new Promise((r) => setTimeout(r, ms));
131700
131901
  var EMPTY_RETRY_ATTEMPTS = 3;
131701
131902
  var EMPTY_RETRY_DELAY_MS = 600;
131702
131903
  var EMPTY_HINT = "No focusable elements after retrying and recycling the read path. The app is most likely still launching (splash / loading screen) or mid-transition \u2014 this is normal right after launch-app / restart-app. Wait ~2-3s and call describe again; a React Native app only exposes focus once its JS bundle has loaded. If it stays empty, take a screenshot to confirm what's actually on screen.";
@@ -131737,7 +131938,7 @@ async function describeTv(registry2, device) {
131737
131938
  let res = await api.describe();
131738
131939
  if (device.platform !== "android") {
131739
131940
  for (let attempt = 1; attempt < EMPTY_RETRY_ATTEMPTS && isEmpty(res); attempt++) {
131740
- await sleep12(EMPTY_RETRY_DELAY_MS);
131941
+ await sleep13(EMPTY_RETRY_DELAY_MS);
131741
131942
  res = await api.describe();
131742
131943
  }
131743
131944
  }
@@ -131787,7 +131988,7 @@ var zodSchema38 = external_exports.object({
131787
131988
  "Optional app bundle ID. Used as a target hint on iOS when the AX-service returns no elements and the describe tool falls back to native-devtools inspection. If omitted, the fallback auto-detects the frontmost connected app. Ignored on Android / Chromium."
131788
131989
  )
131789
131990
  });
131790
- var capability22 = {
131991
+ var capability23 = {
131791
131992
  apple: { simulator: true, device: true },
131792
131993
  appleRemote: { simulator: true },
131793
131994
  android: { emulator: true, device: true, unknown: true },
@@ -131797,7 +131998,7 @@ var capability22 = {
131797
131998
  function makeDescribeExecute(registry2) {
131798
131999
  return dispatchByPlatform({
131799
132000
  toolId: "describe",
131800
- capability: capability22,
132001
+ capability: capability23,
131801
132002
  ios: {
131802
132003
  requires: iosRequires,
131803
132004
  handler: async (_services, params, device) => (
@@ -131882,7 +132083,7 @@ back/menu/home), then call describe again to confirm where focus landed.`,
131882
132083
  alwaysLoad: true,
131883
132084
  searchHint: "accessibility element tree ui hierarchy tap coordinates ios android chromium vega dom tv tvos apple tv android tv fire tv focus focusable remote dpad",
131884
132085
  zodSchema: zodSchema38,
131885
- capability: capability22,
132086
+ capability: capability23,
131886
132087
  services: (params) => {
131887
132088
  const device = resolveDevice(params.udid);
131888
132089
  if (device.platform === "chromium") {
@@ -131911,7 +132112,7 @@ var zodSchema39 = external_exports.object({
131911
132112
  `The screen must hold the same content for at least this long to count as settled (default ${DEFAULT_MIN_STABLE_MS}).`
131912
132113
  )
131913
132114
  });
131914
- var capability23 = {
132115
+ var capability24 = {
131915
132116
  apple: { simulator: true, device: true },
131916
132117
  android: { emulator: true, device: true, unknown: true },
131917
132118
  chromium: { app: true }
@@ -131955,7 +132156,7 @@ still before the timeout. Use after a launch/navigation to wait for the UI to re
131955
132156
  searchHint: "wait until screen settles idle stable stops changing animation transition rendered ready before screenshot",
131956
132157
  longRunning: true,
131957
132158
  zodSchema: zodSchema39,
131958
- capability: capability23,
132159
+ capability: capability24,
131959
132160
  services: (params) => {
131960
132161
  const device = resolveDevice(params.udid);
131961
132162
  if (device.platform === "chromium") {
@@ -131965,7 +132166,7 @@ still before the timeout. Use after a launch/navigation to wait for the UI to re
131965
132166
  },
131966
132167
  async execute(services, params, ctx) {
131967
132168
  const device = resolveDevice(params.udid);
131968
- assertSupported(AWAIT_SCREEN_IDLE_TOOL_ID, capability23, device);
132169
+ assertSupported(AWAIT_SCREEN_IDLE_TOOL_ID, capability24, device);
131969
132170
  if (device.platform === "ios") await ensureDeps(iosRequires);
131970
132171
  else if (device.platform === "android") await ensureDeps(androidRequires);
131971
132172
  const isTvOs = device.platform === "ios" && await isTvOsSimulator(device.id);
@@ -138728,7 +138929,7 @@ var zodSchema48 = external_exports.object({
138728
138929
  "iOS-only. When true, cold-launches the app under the profiler with Malloc Stack Logging enabled so memory leaks carry an allocation backtrace (responsible frame + library). Without it, leaks are still detected but unattributable \u2014 Instruments reports '<Call stack limit reached>'. Trade-offs: this RESTARTS the app (current state is lost), adds memory/CPU overhead, and makes the app noticeably slow to launch (every startup allocation records a backtrace), so leave it off for pure CPU/hang profiling. Requires a non-degraded Xcode: on Xcode 26.4 and later the cold-launch path is broken, so the call is rejected up front (re-run without the flag, or set ARGENT_IOS_CAPTURE=device to override if the device path works on your host). ARGENT_IOS_CAPTURE=all-processes \u2014 e.g. exported globally for the normal capture path \u2014 also rejects this flag up front, since that fallback cannot cold-launch; unset it (or set it to device) first. Ignored on Android."
138729
138930
  )
138730
138931
  });
138731
- var capability24 = {
138932
+ var capability25 = {
138732
138933
  apple: { simulator: true, device: true },
138733
138934
  android: { emulator: true, device: true, unknown: true }
138734
138935
  };
@@ -138739,7 +138940,7 @@ var nativeProfilerStartTool = {
138739
138940
  completedMsg: () => "Started native profiler",
138740
138941
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to start native profiler: ${failureSignal2.error_code}`
138741
138942
  },
138742
- capability: capability24,
138943
+ capability: capability25,
138743
138944
  description: `Start native profiling on a booted device. iOS: Instruments via xctrace (CPU, hangs, memory). Android: Perfetto (CPU, jank, RSS-growth weak signal).
138744
138945
  Auto-detects the running app process unless app_process is explicitly provided.
138745
138946
  After starting, let the user interact with the app, then call native-profiler-stop.
@@ -138753,7 +138954,7 @@ Fails if no app is running on the device, or the profiler cannot attach to the p
138753
138954
  async execute(services, params) {
138754
138955
  const api = services.session;
138755
138956
  const device = resolveDevice(params.device_id);
138756
- assertSupported("native-profiler-start", capability24, device);
138957
+ assertSupported("native-profiler-start", capability25, device);
138757
138958
  if (api.platform === "ios") {
138758
138959
  await ensureDeps(["xcrun"]);
138759
138960
  return startNativeProfilerIos(api, params);
@@ -138770,7 +138971,7 @@ var zodSchema49 = external_exports.object({
138770
138971
  "Target device id from `list-devices` (iOS UDID or Android serial)."
138771
138972
  )
138772
138973
  });
138773
- var capability25 = {
138974
+ var capability26 = {
138774
138975
  apple: { simulator: true, device: true },
138775
138976
  android: { emulator: true, device: true, unknown: true }
138776
138977
  };
@@ -138791,7 +138992,7 @@ var nativeProfilerStopTool = {
138791
138992
  completedMsg: ({ result }) => `Saved native profile ${result.traceFile.filename}`,
138792
138993
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to stop native profiler: ${failureSignal2.error_code}`
138793
138994
  },
138794
- capability: capability25,
138995
+ capability: capability26,
138795
138996
  // Packaging plus the export passes routinely exceed the 30s fetch timeout.
138796
138997
  longRunning: true,
138797
138998
  description: `Stop native profiling and export trace data.
@@ -138808,7 +139009,7 @@ Fails if no active native-profiler-start session exists for the given device_id.
138808
139009
  async execute(services, params, ctx) {
138809
139010
  const api = services.session;
138810
139011
  const device = resolveDevice(params.device_id);
138811
- assertSupported("native-profiler-stop", capability25, device);
139012
+ assertSupported("native-profiler-stop", capability26, device);
138812
139013
  if (api.platform === "ios") {
138813
139014
  await ensureDeps(["xcrun"]);
138814
139015
  const ios = await stopNativeProfilerIos(api);
@@ -138840,7 +139041,7 @@ var zodSchema50 = external_exports.object({
138840
139041
  "Target device id from `list-devices` (iOS UDID or Android serial)."
138841
139042
  )
138842
139043
  });
138843
- var capability26 = {
139044
+ var capability27 = {
138844
139045
  apple: { simulator: true, device: true },
138845
139046
  android: { emulator: true, device: true, unknown: true }
138846
139047
  };
@@ -138851,7 +139052,7 @@ var nativeProfilerAnalyzeTool = {
138851
139052
  completedMsg: () => "Analyzed native profile",
138852
139053
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to analyze native profile: ${failureSignal2.error_code}`
138853
139054
  },
138854
- capability: capability26,
139055
+ capability: capability27,
138855
139056
  description: `Analyze exported native trace data and return an LLM-optimized markdown report.
138856
139057
  iOS: parses CPU time profile, UI hangs, and memory leaks from the exported XML files.
138857
139058
  Android: queries the Perfetto .pftrace via the in-process Perfetto trace-processor engine for CPU hotspots, UI hangs with jank reason + main-thread state breakdown, GC annotation, and an RSS-growth weak signal.
@@ -138868,7 +139069,7 @@ Fails if native-profiler-stop has not been called first to export trace data.`,
138868
139069
  async execute(services, params, ctx) {
138869
139070
  const api = services.session;
138870
139071
  const device = resolveDevice(params.device_id);
138871
- assertSupported("native-profiler-analyze", capability26, device);
139072
+ assertSupported("native-profiler-analyze", capability27, device);
138872
139073
  let result;
138873
139074
  if (api.platform === "ios") {
138874
139075
  await ensureDeps(["xcrun"]);
@@ -139847,7 +140048,7 @@ var zodSchema51 = external_exports.object({
139847
140048
  "Default true. Draw simulator-server's touch visualizer into the recording: a pulse marks each tap, a comet trail follows swipes and drags, and paired markers show two-finger pinch/rotate, so the video makes clear where every interaction landed. Set false to record the raw screen with no overlay."
139848
140049
  )
139849
140050
  });
139850
- var capability27 = {
140051
+ var capability28 = {
139851
140052
  apple: { simulator: true },
139852
140053
  android: { emulator: true, device: true, unknown: true }
139853
140054
  };
@@ -139859,7 +140060,7 @@ function createScreenRecordingStartTool(registry2) {
139859
140060
  completedMsg: () => "Started screen recording",
139860
140061
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to start screen recording: ${failureSignal2.error_code}`
139861
140062
  },
139862
- capability: capability27,
140063
+ capability: capability28,
139863
140064
  description: `Start recording the device screen to a video file (h264 mp4, 30fps at the device's native resolution).
139864
140065
  By default stretches where the screen does not change are trimmed out (see trimStatic), so a long session with only brief activity comes back as a short clip instead of minutes of dead air.
139865
140066
  By default every tap, swipe, drag, pinch and rotate is drawn into the video as an on-screen touch marker (see showTouches), so the recording shows where each interaction landed.
@@ -139879,7 +140080,7 @@ Fails if a recording is already running on the device, the device is not booted,
139879
140080
  async execute(services, params) {
139880
140081
  const api = services.session;
139881
140082
  const device = resolveDevice(params.udid);
139882
- assertSupported("screen-recording-start", capability27, device);
140083
+ assertSupported("screen-recording-start", capability28, device);
139883
140084
  if (device.platform === "ios" && await isTvOsSimulator(params.udid)) {
139884
140085
  throw new FailureError(
139885
140086
  `Screen recording is not supported on tvOS simulators (device ${params.udid}).`,
@@ -139954,7 +140155,7 @@ var zodSchema52 = external_exports.object({
139954
140155
  udid: external_exports.string().describe("Target device id from `list-devices` (iOS Simulator UDID or Android serial).")
139955
140156
  });
139956
140157
  var RECORDINGS_DIR = ".argent/recordings";
139957
- var capability28 = {
140158
+ var capability29 = {
139958
140159
  apple: { simulator: true },
139959
140160
  android: { emulator: true, device: true, unknown: true }
139960
140161
  };
@@ -139965,7 +140166,7 @@ var screenRecordingStopTool = {
139965
140166
  completedMsg: ({ result }) => `Saved screen recording ${result.video.filename}`,
139966
140167
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to stop screen recording: ${failureSignal2.error_code}`
139967
140168
  },
139968
- capability: capability28,
140169
+ capability: capability29,
139969
140170
  description: `Stop the screen recording started by \`screen-recording-start\` and retrieve the video: frame capture ends and ffmpeg finalizes the mp4.
139970
140171
  Also retrieves the video when the recording already ended on its own (time limit reached, capture process died) \u2014 call it even after the cap fired.
139971
140172
  Use when the interaction being captured is finished, or a tool-result note reminds you a recording is still running.
@@ -139979,7 +140180,7 @@ Fails if no recording (running or finished-but-unretrieved) exists for the given
139979
140180
  async execute(services, params, ctx) {
139980
140181
  const api = services.session;
139981
140182
  const device = resolveDevice(params.udid);
139982
- assertSupported("screen-recording-stop", capability28, device);
140183
+ assertSupported("screen-recording-stop", capability29, device);
139983
140184
  const stopped = await stopCapture(api);
139984
140185
  const artifacts = requireArtifacts(ctx);
139985
140186
  const video = await artifacts.register(stopped.outputFile, {
@@ -150048,7 +150249,7 @@ var zodSchema70 = external_exports.object({
150048
150249
  "Directory where diff artifacts should be written. Optional \u2014 defaults to a temp directory; the diff images are returned in the result either way."
150049
150250
  )
150050
150251
  }).strict();
150051
- var capability29 = {
150252
+ var capability30 = {
150052
150253
  apple: { simulator: true, device: true },
150053
150254
  android: { emulator: true, device: true, unknown: true }
150054
150255
  };
@@ -150073,7 +150274,7 @@ Ignores the fixed top status-bar band for both pixel and OCR text comparisons.
150073
150274
  Fails if the input sources are invalid, PNG files cannot be read, outputDir cannot be written, or the simulator-server / emulator backend is not reachable.`,
150074
150275
  searchHint: "compare screenshots png diff visual UI changes UI regression visual regression screenshot diff changed regions text ocr live capture",
150075
150276
  zodSchema: zodSchema70,
150076
- capability: capability29,
150277
+ capability: capability30,
150077
150278
  fileInputs: fileInputs6,
150078
150279
  services: (params) => {
150079
150280
  if (params.captureBaseline || params.captureCurrent) {
@@ -150472,7 +150673,7 @@ var tabAction = {
150472
150673
  failure: "close"
150473
150674
  }
150474
150675
  };
150475
- var capability30 = {
150676
+ var capability31 = {
150476
150677
  chromium: { app: true }
150477
150678
  };
150478
150679
  var chromiumTabsTool = {
@@ -150491,7 +150692,7 @@ Use when an app exposes multiple windows or tabs and you need to inspect or driv
150491
150692
  Returns { tabs: [{ tabId, targetId, title, url, active, label? }] }. Fails if the device is not a Chromium (CDP) device, or the requested tabId/label no longer matches a live tab. Chromium-only.`,
150492
150693
  searchHint: "tab tabs window windows switch select close new open multi-tab chromium electron",
150493
150694
  zodSchema: zodSchema73,
150494
- capability: capability30,
150695
+ capability: capability31,
150495
150696
  services: (params) => {
150496
150697
  const device = resolveDevice(params.udid);
150497
150698
  if (device.platform === "chromium") {
@@ -150614,7 +150815,7 @@ var cookieAction = {
150614
150815
  delete: { started: "Deleting", completed: "Deleted", failure: "delete" },
150615
150816
  clear: { started: "Clearing", completed: "Cleared", failure: "clear" }
150616
150817
  };
150617
- var capability31 = {
150818
+ var capability32 = {
150618
150819
  chromium: { app: true }
150619
150820
  };
150620
150821
  var chromiumCookiesTool = {
@@ -150633,7 +150834,7 @@ Use when seeding an authenticated session before a flow (set the session cookie,
150633
150834
  Returns { cookies, count } for get, or a small status object ({ set } / { deleted } / { cleared }) otherwise. Fails if the device is not a Chromium (CDP) device, or set is missing name/value. Chromium-only.`,
150634
150835
  searchHint: "cookies cookie get set delete clear httponly samesite session auth chromium",
150635
150836
  zodSchema: zodSchema74,
150636
- capability: capability31,
150837
+ capability: capability32,
150637
150838
  services: (params) => {
150638
150839
  const device = resolveDevice(params.udid);
150639
150840
  if (device.platform === "chromium") {
@@ -150712,7 +150913,7 @@ var storageAction = {
150712
150913
  remove: { started: "Removing from", completed: "Removed from", failure: "remove from" },
150713
150914
  clear: { started: "Clearing", completed: "Cleared", failure: "clear" }
150714
150915
  };
150715
- var capability32 = {
150916
+ var capability33 = {
150716
150917
  chromium: { app: true }
150717
150918
  };
150718
150919
  var chromiumStorageTool = {
@@ -150732,7 +150933,7 @@ Use when seeding feature flags / auth tokens before a flow or asserting persiste
150732
150933
  Returns { value } for a single key, { entries, count } for all, or a status object ({ set } / { removed } / { cleared }) otherwise. Fails if the device is not a Chromium (CDP) device, or set is missing key/value. Chromium-only.`,
150733
150934
  searchHint: "storage localstorage sessionstorage local session get set remove clear key value chromium",
150734
150935
  zodSchema: zodSchema75,
150735
- capability: capability32,
150936
+ capability: capability33,
150736
150937
  services: (params) => {
150737
150938
  const device = resolveDevice(params.udid);
150738
150939
  if (device.platform === "chromium") {
@@ -150820,6 +151021,7 @@ function createRegistry() {
150820
151021
  registry2.registerTool(gestureRotateTool);
150821
151022
  registry2.registerTool(buttonTool);
150822
151023
  registry2.registerTool(createKeyboardTool(registry2));
151024
+ registry2.registerTool(createPasteTool(registry2));
150823
151025
  registry2.registerTool(rotateTool);
150824
151026
  registry2.registerTool(shakeTool);
150825
151027
  registry2.registerTool(createTvRemoteTool(registry2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.21.1-next.16",
3
+ "version": "0.21.1-next.18",
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",
@@ -56,27 +56,28 @@ Common schemes: `messages://`, `settings://`, `maps://?q=<query>`, `tel://<numbe
56
56
 
57
57
  ## 4. Choosing the Right Tool
58
58
 
59
- | Action | Tool | Notes |
60
- | ----------------- | ------------------- | ---------------------------------------------------------------- |
61
- | Multiple actions | `run-sequence` | Batch steps in one call (no intermediate screenshots) |
62
- | Open an app | `launch-app` | **Always — never tap home-screen icons** |
63
- | Restart an app | `restart-app` | Terminate and relaunch by bundle ID |
64
- | Open URL/scheme | `open-url` | Web pages, deep links, URL schemes |
65
- | Single tap | `gesture-tap` | Buttons, links, checkboxes |
66
- | Scroll/swipe | `gesture-swipe` | Straight-line scroll or swipe |
67
- | Scroll (Chromium) | `gesture-scroll` | Wheel-based; deltas are window fractions, positive deltaY = down |
68
- | Drag (Chromium) | `gesture-drag` | Sliders, drag-and-drop, text selection |
69
- | Long press | `gesture-custom` | Context menus, drag start |
70
- | Drag & drop | `gesture-custom` | Complex drag interactions |
71
- | Pinch/zoom | `gesture-pinch` | Two-finger pinch with auto-interpolation |
72
- | Rotation | `gesture-rotate` | Two-finger rotation with auto-interpolation |
73
- | Custom gesture | `gesture-custom` | Arbitrary touch sequences, optional interpolation |
74
- | Hardware key | `button` | Home, back, power, volume, appSwitch, actionButton |
75
- | Type text | `keyboard` | Every platform. Text or one named key per call, never both |
76
- | Rotate device | `rotate` | Orientation changes |
77
- | Shake device | `shake` | Shake handlers (sim/emu only), Undo-typing prompt, RN dev menu |
78
- | Wait for UI | `await-ui-element` | Block until an element is visible/hidden/exists/contains text |
79
- | Wait for idle | `await-screen-idle` | Block until a non-empty screen tree stops changing |
59
+ | Action | Tool | Notes |
60
+ | ----------------- | ------------------- | ----------------------------------------------------------------- |
61
+ | Multiple actions | `run-sequence` | Batch steps in one call (no intermediate screenshots) |
62
+ | Open an app | `launch-app` | **Always — never tap home-screen icons** |
63
+ | Restart an app | `restart-app` | Terminate and relaunch by bundle ID |
64
+ | Open URL/scheme | `open-url` | Web pages, deep links, URL schemes |
65
+ | Single tap | `gesture-tap` | Buttons, links, checkboxes |
66
+ | Scroll/swipe | `gesture-swipe` | Straight-line scroll or swipe |
67
+ | Scroll (Chromium) | `gesture-scroll` | Wheel-based; deltas are window fractions, positive deltaY = down |
68
+ | Drag (Chromium) | `gesture-drag` | Sliders, drag-and-drop, text selection |
69
+ | Long press | `gesture-custom` | Context menus, drag start |
70
+ | Drag & drop | `gesture-custom` | Complex drag interactions |
71
+ | Pinch/zoom | `gesture-pinch` | Two-finger pinch with auto-interpolation |
72
+ | Rotation | `gesture-rotate` | Two-finger rotation with auto-interpolation |
73
+ | Custom gesture | `gesture-custom` | Arbitrary touch sequences, optional interpolation |
74
+ | Hardware key | `button` | Home, back, power, volume, appSwitch, actionButton |
75
+ | Type text | `keyboard` | Every platform. Text or one named key per call, never both |
76
+ | Paste text | `paste` | Only where a user would paste (OTP code, long link). Sim/emu only |
77
+ | Rotate device | `rotate` | Orientation changes |
78
+ | Shake device | `shake` | Shake handlers (sim/emu only), Undo-typing prompt, RN dev menu |
79
+ | Wait for UI | `await-ui-element` | Block until an element is visible/hidden/exists/contains text |
80
+ | Wait for idle | `await-screen-idle` | Block until a non-empty screen tree stops changing |
80
81
 
81
82
  ## 5. Finding Tap Targets
82
83
 
@@ -197,6 +198,18 @@ Rules:
197
198
  - Nothing outside those sources is reachable; never ask the user to paste a secret value into the conversation. Ask them to put it in a secrets file instead — a file edit applies to the next call, while an exported env var only reaches a tool-server started afterwards.
198
199
  - The project sources are found by walking up from the tool-server's working directory. If a project file is not being picked up, the failure's source list shows the paths actually consulted; `~/.argent/secrets.env` needs no project and always applies.
199
200
 
201
+ ### paste — Paste text into the focused field
202
+
203
+ ```json
204
+ { "udid": "<UDID>", "text": "482913" }
205
+ ```
206
+
207
+ Puts `text` on the **device** clipboard (the host clipboard is untouched) and triggers the platform's paste shortcut. iOS simulator and Android emulator only; a TV target, a physical device, Chromium and Vega are rejected.
208
+
209
+ `paste` is **not** a faster `keyboard`. `keyboard` types the way a user types and stays the default for every text entry — a search query, a login, a form field. Reach for `paste` only where a real user would paste: a 2FA / OTP code copied from another app, a long link or token, or to test how the app handles pasted input. It also carries what `keyboard` can't type on a given platform (multi-line text, non-ASCII on Android), but that alone is not a reason to paste — ask whether the user would.
210
+
211
+ Tap the field first so it has focus; pasting with no focused field is a silent no-op, as with `keyboard`. `text` accepts the same `{{secret:<NAME>}}` placeholders as `keyboard`, with the same auto-screenshot skip.
212
+
200
213
  ### rotate — Change orientation
201
214
 
202
215
  ```json
@@ -297,7 +310,7 @@ Use the sequencing when:
297
310
 
298
311
  ### Allowed tools inside `run-sequence`
299
312
 
300
- `gesture-tap`, `gesture-swipe`, `gesture-scroll`, `gesture-drag`, `gesture-custom`, `gesture-pinch`, `gesture-rotate`, `button`, `keyboard`, `rotate`, `await-ui-element`
313
+ `gesture-tap`, `gesture-swipe`, `gesture-scroll`, `gesture-drag`, `gesture-custom`, `gesture-pinch`, `gesture-rotate`, `button`, `keyboard`, `paste`, `rotate`, `shake`, `tv-remote`, `await-ui-element`
301
314
 
302
315
  The `udid` is shared — do **not** include it in each step's `args`. Optional `delayMs` per step (default 100ms).
303
316