@swmansion/argent 0.7.0 → 0.7.1

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.
@@ -11,7 +11,6 @@ description: >
11
11
  Use proactively at session start when required to gather the environment information.
12
12
  If subagent delegation is not available, run the steps in the main thread instead.
13
13
  The main agent is responsible for persisting the result to project memory.
14
- model: haiku
15
14
  ---
16
15
 
17
16
  You are the **environment-inspector** subagent. Your job is to inspect a mobile app
package/bin/ax-service CHANGED
Binary file
package/dist/cli.js CHANGED
@@ -22,6 +22,7 @@
22
22
  import * as fs from "node:fs";
23
23
  import * as path from "node:path";
24
24
  import { BUNDLED_RUNTIME_PATHS } from "./bundled-paths.js";
25
+ import { installFatalHandlers } from "./fatal-handlers.js";
25
26
  const PACKAGE_NAME = "@swmansion/argent";
26
27
  function getInstalledVersion() {
27
28
  try {
@@ -37,16 +38,7 @@ function getInstalledVersion() {
37
38
  }
38
39
  const [, , command, ...rest] = process.argv;
39
40
  const isMcpServer = command === "mcp";
40
- process.on("uncaughtException", (err) => {
41
- process.stderr.write(`[argent] Uncaught exception: ${err.stack ?? err}\n`);
42
- if (!isMcpServer)
43
- process.exit(1);
44
- });
45
- process.on("unhandledRejection", (reason) => {
46
- process.stderr.write(`[argent] Unhandled rejection: ${reason instanceof Error ? (reason.stack ?? reason.message) : reason}\n`);
47
- if (!isMcpServer)
48
- process.exit(1);
49
- });
41
+ installFatalHandlers({ isMcpServer });
50
42
  function printHelp() {
51
43
  const version = getInstalledVersion() ?? "unknown";
52
44
  console.log(`
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function installFatalHandlers(opts: {
2
+ isMcpServer: boolean;
3
+ }): void;
@@ -0,0 +1,75 @@
1
+ // Process-level handlers for uncaughtException and unhandledRejection.
2
+ //
3
+ // In MCP-server mode we do NOT exit on every uncaught error — many are
4
+ // transient and the editor expects the server to keep running. But the naive
5
+ // version (`stderr.write(...); if (!isMcp) exit`) burns 100% CPU when stderr
6
+ // itself is broken (e.g. the parent process is gone): the write emits an
7
+ // async 'error' event on the stream, which without a listener becomes another
8
+ // uncaughtException, runs the handler, writes to the same broken stream, ...
9
+ //
10
+ // The fix has three pieces:
11
+ // 1. `'error'` listeners on stdout/stderr — broken stdio is fatal; exit
12
+ // before the failure round-trips into uncaughtException. This is what
13
+ // breaks the production loop.
14
+ // 2. try/catch around `stderr.write` — synchronous write failures also exit
15
+ // cleanly instead of escaping into another uncaughtException.
16
+ // 3. try/catch around the formatter — a throwing `.stack` getter or
17
+ // `toString` (the production trace pointed at defaultPrepareStackTrace)
18
+ // can't take down the handler.
19
+ //
20
+ // When stdio is unusable we cannot tell the parent process what went wrong,
21
+ // so we leave a breadcrumb on disk at `~/.argent/mcp-fatal.log`. Sibling of
22
+ // the other persistent argent diagnostic logs (`tool-server.log`, etc.).
23
+ import * as fs from "node:fs";
24
+ import * as os from "node:os";
25
+ import * as path from "node:path";
26
+ let installed = false;
27
+ const FATAL_LOG_PATH = path.join(os.homedir(), ".argent", "mcp-fatal.log");
28
+ function appendFatalLog(label, detail) {
29
+ try {
30
+ fs.mkdirSync(path.dirname(FATAL_LOG_PATH), { recursive: true });
31
+ const line = `[${new Date().toISOString()}] pid=${process.pid} ${label}: ${detail}\n`;
32
+ fs.appendFileSync(FATAL_LOG_PATH, line);
33
+ }
34
+ catch {
35
+ // Last-resort log — if even this write fails (read-only fs, missing home),
36
+ // there is nothing more we can do. Swallow so we still exit cleanly.
37
+ }
38
+ }
39
+ export function installFatalHandlers(opts) {
40
+ if (installed)
41
+ return;
42
+ installed = true;
43
+ for (const stream of [process.stdout, process.stderr]) {
44
+ const name = stream === process.stdout ? "stdout" : "stderr";
45
+ stream.on("error", (err) => {
46
+ appendFatalLog(`Broken ${name}`, String(err?.stack ?? err));
47
+ process.exit(1);
48
+ });
49
+ }
50
+ function reportFatal(label, getDetail) {
51
+ let detail;
52
+ try {
53
+ try {
54
+ detail = getDetail();
55
+ }
56
+ catch {
57
+ detail = "<failed to format>";
58
+ }
59
+ process.stderr.write(`[argent] ${label}: ${detail}\n`);
60
+ }
61
+ catch {
62
+ appendFatalLog(label, detail);
63
+ process.exit(1);
64
+ }
65
+ if (!opts.isMcpServer)
66
+ process.exit(1);
67
+ }
68
+ process.on("uncaughtException", (err) => {
69
+ reportFatal("Uncaught exception", () => String(err?.stack ?? err));
70
+ });
71
+ process.on("unhandledRejection", (reason) => {
72
+ reportFatal("Unhandled rejection", () => reason instanceof Error ? (reason.stack ?? reason.message) : String(reason));
73
+ });
74
+ }
75
+ //# sourceMappingURL=fatal-handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fatal-handlers.js","sourceRoot":"","sources":["../src/fatal-handlers.ts"],"names":[],"mappings":"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"}
@@ -14154,7 +14154,7 @@ async function fetchWithReconnect(getUrl, reconnect, config2) {
14154
14154
  let lastError;
14155
14155
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
14156
14156
  const controller = new AbortController();
14157
- const timer = setTimeout(() => controller.abort(), fetchTimeoutMs);
14157
+ const timer = fetchTimeoutMs !== null ? setTimeout(() => controller.abort(), fetchTimeoutMs) : void 0;
14158
14158
  try {
14159
14159
  return await fetch(getUrl(), { ...init, signal: controller.signal });
14160
14160
  } catch (err) {
@@ -14220,7 +14220,8 @@ async function startMcpServer(options) {
14220
14220
  method: "POST",
14221
14221
  headers: { "Content-Type": "application/json" },
14222
14222
  body: JSON.stringify(args ?? {})
14223
- }
14223
+ },
14224
+ fetchTimeoutMs: meta?.longRunning ? null : FETCH_TIMEOUT_MS
14224
14225
  });
14225
14226
  const json = await res.json();
14226
14227
  if (!res.ok) throw new Error(json.error ?? json.message ?? res.statusText);
@@ -41478,6 +41478,9 @@ function zodTypeToJsonSchema(type) {
41478
41478
  if (type instanceof external_exports.ZodNumber) return { type: "number" };
41479
41479
  if (type instanceof external_exports.ZodBoolean) return { type: "boolean" };
41480
41480
  if (type instanceof external_exports.ZodOptional) return zodTypeToJsonSchema(type.unwrap());
41481
+ if (type instanceof external_exports.ZodDefault) {
41482
+ return { ...zodTypeToJsonSchema(type._def.innerType), default: type._def.defaultValue() };
41483
+ }
41481
41484
  if (type instanceof external_exports.ZodArray) {
41482
41485
  return { type: "array", items: zodTypeToJsonSchema(type.element) };
41483
41486
  }
@@ -41493,7 +41496,7 @@ function zodTypeToJsonSchema(type) {
41493
41496
  return {};
41494
41497
  }
41495
41498
  function isOptional(type) {
41496
- return type instanceof external_exports.ZodOptional;
41499
+ return type instanceof external_exports.ZodOptional || type instanceof external_exports.ZodDefault;
41497
41500
  }
41498
41501
 
41499
41502
  // ../registry/src/registry.ts
@@ -41948,7 +41951,7 @@ var import_node_https = __toESM(require("node:https"));
41948
41951
  var import_semver = __toESM(require_semver2());
41949
41952
 
41950
41953
  // ../tool-server/package.json
41951
- var version = "0.7.0";
41954
+ var version = "0.7.1";
41952
41955
 
41953
41956
  // ../tool-server/src/utils/update-checker.ts
41954
41957
  var PACKAGE_NAME = "@swmansion/argent";
@@ -42937,6 +42940,7 @@ function createHttpApp(registry, options) {
42937
42940
  if (def?.outputHint) entry.outputHint = def.outputHint;
42938
42941
  if (def?.alwaysLoad) entry.alwaysLoad = true;
42939
42942
  if (def?.searchHint) entry.searchHint = def.searchHint;
42943
+ if (def?.longRunning) entry.longRunning = true;
42940
42944
  return entry;
42941
42945
  });
42942
42946
  res.json({ tools });
@@ -44930,6 +44934,136 @@ var REACT_NATIVE_PROFILER_SETUP_SCRIPT = `
44930
44934
  });
44931
44935
  })();
44932
44936
  `;
44937
+ var BOOTSTRAP_DEVTOOLS_BACKEND_SCRIPT = `
44938
+ (function __argent_bootstrapDevtoolsBackend() {
44939
+ var h = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
44940
+ if (!h) return JSON.stringify({ ok: false, reason: 'no-hook' });
44941
+
44942
+ function sizeOf(m) {
44943
+ if (!m || typeof m.forEach !== 'function') return 0;
44944
+ var n = 0;
44945
+ m.forEach(function () { n++; });
44946
+ return n;
44947
+ }
44948
+
44949
+ var renderersCount = sizeOf(h.renderers);
44950
+ var rendererInterfacesCount = sizeOf(h.rendererInterfaces);
44951
+
44952
+ if (rendererInterfacesCount > 0) {
44953
+ return JSON.stringify({
44954
+ ok: true,
44955
+ reason: 'already-attached',
44956
+ renderersCount: renderersCount,
44957
+ rendererInterfacesCount: rendererInterfacesCount,
44958
+ });
44959
+ }
44960
+
44961
+ if (renderersCount === 0) {
44962
+ return JSON.stringify({
44963
+ ok: false,
44964
+ reason: 'no-renderers',
44965
+ renderersCount: renderersCount,
44966
+ rendererInterfacesCount: rendererInterfacesCount,
44967
+ });
44968
+ }
44969
+
44970
+ if (typeof globalThis.__r !== 'function' || typeof globalThis.__r.getModules !== 'function') {
44971
+ return JSON.stringify({
44972
+ ok: false,
44973
+ reason: 'no-metro-modules',
44974
+ renderersCount: renderersCount,
44975
+ rendererInterfacesCount: rendererInterfacesCount,
44976
+ });
44977
+ }
44978
+
44979
+ var found = null;
44980
+ var moduleSeenButUnsupported = false;
44981
+ try {
44982
+ var mods = globalThis.__r.getModules();
44983
+ var inspect = function (id, meta) {
44984
+ if (found) return;
44985
+ var name = meta && meta.verboseName;
44986
+ if (typeof name !== 'string') return;
44987
+ if (name.indexOf('react-devtools-core/dist/backend') < 0) return;
44988
+ try {
44989
+ var m = globalThis.__r(id);
44990
+ if (!m) return;
44991
+ if (typeof m.connectWithCustomMessagingProtocol === 'function') {
44992
+ found = m;
44993
+ } else {
44994
+ // Module exists but exposes only legacy WebSocket-based connectToDevTools
44995
+ // (rdt-core <5.1). We can't bootstrap without a real ws endpoint, so the
44996
+ // user has to attach an external backend (\`npx react-devtools\` + reload).
44997
+ moduleSeenButUnsupported = true;
44998
+ }
44999
+ } catch (_e) {
45000
+ // require failure on this id \u2014 keep searching.
45001
+ }
45002
+ };
45003
+ // Metro's getModules() returns a Map<id, meta> in modern versions.
45004
+ // Map#forEach calls back as (value, key); array-like fallback handled below.
45005
+ if (typeof mods.forEach === 'function' && typeof mods.size === 'number') {
45006
+ mods.forEach(function (meta, id) { inspect(id, meta); });
45007
+ } else if (typeof mods.length === 'number') {
45008
+ for (var i = 0; i < mods.length; i++) {
45009
+ if (mods[i]) inspect(i, mods[i]);
45010
+ }
45011
+ } else if (typeof mods.forEach === 'function') {
45012
+ mods.forEach(function (meta, id) { inspect(id, meta); });
45013
+ }
45014
+ } catch (err) {
45015
+ return JSON.stringify({
45016
+ ok: false,
45017
+ reason: 'metro-scan-error',
45018
+ message: String((err && err.message) || err),
45019
+ renderersCount: renderersCount,
45020
+ rendererInterfacesCount: rendererInterfacesCount,
45021
+ });
45022
+ }
45023
+
45024
+ if (!found) {
45025
+ return JSON.stringify({
45026
+ ok: false,
45027
+ reason: moduleSeenButUnsupported ? 'unsupported-rdt-version' : 'no-rdt-module',
45028
+ renderersCount: renderersCount,
45029
+ rendererInterfacesCount: rendererInterfacesCount,
45030
+ });
45031
+ }
45032
+
45033
+ try {
45034
+ found.connectWithCustomMessagingProtocol({
45035
+ onSubscribe: function () {},
45036
+ onUnsubscribe: function () {},
45037
+ onMessage: function () {},
45038
+ });
45039
+ } catch (err) {
45040
+ return JSON.stringify({
45041
+ ok: false,
45042
+ reason: 'bootstrap-threw',
45043
+ message: String((err && err.message) || err),
45044
+ renderersCount: renderersCount,
45045
+ rendererInterfacesCount: rendererInterfacesCount,
45046
+ });
45047
+ }
45048
+
45049
+ var afterCount = sizeOf(h.rendererInterfaces);
45050
+ if (afterCount === 0) {
45051
+ return JSON.stringify({
45052
+ ok: false,
45053
+ reason: 'bootstrap-no-effect',
45054
+ renderersCount: renderersCount,
45055
+ rendererInterfacesCount: rendererInterfacesCount,
45056
+ });
45057
+ }
45058
+
45059
+ return JSON.stringify({
45060
+ ok: true,
45061
+ reason: 'bootstrapped',
45062
+ renderersCount: renderersCount,
45063
+ rendererInterfacesCount: afterCount,
45064
+ });
45065
+ })()
45066
+ `;
44933
45067
  var HEARTBEAT_SCRIPT = `
44934
45068
  (function(){
44935
45069
  if (typeof globalThis.__argent_profilerHeartbeat === 'function') {
@@ -46255,7 +46389,6 @@ Use when you need to scroll a list, dismiss a modal, or navigate between pages.
46255
46389
  };
46256
46390
 
46257
46391
  // ../tool-server/src/utils/gesture-utils.ts
46258
- var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
46259
46392
  function lerp(a, b, t) {
46260
46393
  return a + (b - a) * t;
46261
46394
  }
@@ -46303,7 +46436,7 @@ function sendTouchEvent(api, type, x, y, x2, y2) {
46303
46436
  }
46304
46437
 
46305
46438
  // ../tool-server/src/tools/gesture-custom/index.ts
46306
- var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
46439
+ var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
46307
46440
  var eventSchema = external_exports.object({
46308
46441
  type: external_exports.enum(["Down", "Move", "Up"]).describe("Touch event type"),
46309
46442
  x: external_exports.number().describe("Normalized x 0.0\u20131.0 (not pixels; same as tap/swipe)"),
@@ -46356,7 +46489,7 @@ Example pinch-to-zoom (with interpolate:10 for smoothness):
46356
46489
  const api = services.simulatorServer;
46357
46490
  const events = params.interpolate && params.interpolate > 0 ? interpolateEvents(params.events, params.interpolate) : params.events;
46358
46491
  for (const event of events) {
46359
- await sleep4(event.delayMs ?? 16);
46492
+ await sleep3(event.delayMs ?? 16);
46360
46493
  sendCommand(api, {
46361
46494
  cmd: "touch",
46362
46495
  type: event.type,
@@ -46370,6 +46503,10 @@ Example pinch-to-zoom (with interpolate:10 for smoothness):
46370
46503
  }
46371
46504
  };
46372
46505
 
46506
+ // ../tool-server/src/utils/timing.ts
46507
+ var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
46508
+ var DEFAULT_INTER_STEP_DELAY_MS = 100;
46509
+
46373
46510
  // ../tool-server/src/tools/gesture-pinch/index.ts
46374
46511
  var zodSchema18 = external_exports.object({
46375
46512
  udid: external_exports.string().describe("Target device id from `list-devices` (iOS UDID or Android serial)."),
@@ -46424,7 +46561,7 @@ Use when you need to zoom in or out on a map, image, or zoomable view. Returns {
46424
46561
  const type = i === 0 ? "Down" : i === steps ? "Up" : "Move";
46425
46562
  if (i === 0) timestampMs = Date.now();
46426
46563
  sendTouchEvent(api, type, x1, y1, x2, y2);
46427
- if (i < steps) await sleep3(16);
46564
+ if (i < steps) await sleep4(16);
46428
46565
  }
46429
46566
  return { pinched: true, timestampMs };
46430
46567
  }
@@ -46478,7 +46615,7 @@ Use when you need to rotate a map, image picker, or any rotateable UI element. R
46478
46615
  const type = i === 0 ? "Down" : i === steps ? "Up" : "Move";
46479
46616
  if (i === 0) timestampMs = Date.now();
46480
46617
  sendTouchEvent(api, type, x1, y1, x2, y2);
46481
- if (i < steps) await sleep3(16);
46618
+ if (i < steps) await sleep4(16);
46482
46619
  }
46483
46620
  return { rotated: true, timestampMs };
46484
46621
  }
@@ -46700,7 +46837,6 @@ Returns { orientation }. Fails if the target device is not booted.`,
46700
46837
  };
46701
46838
 
46702
46839
  // ../tool-server/src/tools/run-sequence/index.ts
46703
- var sleep7 = (ms) => new Promise((r) => setTimeout(r, ms));
46704
46840
  var ALLOWED_TOOLS = /* @__PURE__ */ new Set([
46705
46841
  "gesture-tap",
46706
46842
  "gesture-swipe",
@@ -46721,7 +46857,9 @@ var zodSchema23 = external_exports.object({
46721
46857
  "Tool name \u2014 one of: gesture-tap, gesture-swipe, gesture-custom, gesture-pinch, gesture-rotate, button, keyboard, rotate"
46722
46858
  ),
46723
46859
  args: external_exports.record(external_exports.unknown()).describe("Tool arguments (excluding udid, which is injected automatically)"),
46724
- delayMs: external_exports.number().optional().describe("Wait time in ms after this step before the next (default 100)")
46860
+ delayMs: external_exports.number().optional().describe(
46861
+ `Wait time in ms after this step before the next (default ${DEFAULT_INTER_STEP_DELAY_MS})`
46862
+ )
46725
46863
  })
46726
46864
  ).min(1).describe("Ordered list of interaction steps to execute sequentially")
46727
46865
  });
@@ -46768,6 +46906,7 @@ Example \u2014 type text and submit:
46768
46906
 
46769
46907
  Stops on the first error and returns partial results.`,
46770
46908
  alwaysLoad: true,
46909
+ longRunning: true,
46771
46910
  searchHint: "batch sequence multiple gesture steps sequentially",
46772
46911
  zodSchema: zodSchema23,
46773
46912
  capability: capability15,
@@ -46796,8 +46935,8 @@ Stops on the first error and returns partial results.`,
46796
46935
  });
46797
46936
  break;
46798
46937
  }
46799
- const delay = step.delayMs ?? 100;
46800
- if (delay > 0) await sleep7(delay);
46938
+ const delay = step.delayMs ?? DEFAULT_INTER_STEP_DELAY_MS;
46939
+ if (delay > 0) await sleep4(delay);
46801
46940
  }
46802
46941
  return {
46803
46942
  completed: results.filter((r) => "result" in r).length,
@@ -49020,6 +49159,25 @@ function classifyStaleness({
49020
49159
  };
49021
49160
  }
49022
49161
 
49162
+ // ../tool-server/src/utils/react-profiler/devtools-bootstrap.ts
49163
+ function bootstrapFailureMessage(bootstrap) {
49164
+ switch (bootstrap.reason) {
49165
+ case "no-hook":
49166
+ case "no-rdt-module":
49167
+ return "React DevTools is not available in this app. This usually means the app is a production build. Ask the user to run a development build of the app, then retry.";
49168
+ case "no-renderers":
49169
+ return "React has not rendered yet, so there is nothing to profile. Ask the user to wait until the app shows React content (or navigate to a screen with React content), then retry.";
49170
+ case "no-metro-modules":
49171
+ return "Could not attach the React DevTools backend: the JS runtime does not expose a Metro module registry. This runtime is not a standard Metro-bundled React Native app and the React profiler cannot proceed. Inform the user that React profiling is only supported on standard Metro / React Native bundles.";
49172
+ case "unsupported-rdt-version":
49173
+ return "This app is running React Native older than 0.74, which the React profiler does not support. Ask the user to upgrade React Native to 0.74 or newer to use this tool.";
49174
+ default: {
49175
+ const detail = bootstrap.message ? ` (runtime error: ${bootstrap.message})` : "";
49176
+ return `Could not attach the React DevTools backend${detail}. Ask the user to fully reload the JS bundle and retry. If the error persists, the runtime may not be supported by the React profiler.`;
49177
+ }
49178
+ }
49179
+ }
49180
+
49023
49181
  // ../tool-server/src/tools/profiler/react/react-profiler-start.ts
49024
49182
  var zodSchema34 = external_exports.object({
49025
49183
  port: external_exports.coerce.number().default(8081).describe("Metro server port"),
@@ -49090,20 +49248,40 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
49090
49248
  }
49091
49249
  const cdp = api.cdp;
49092
49250
  await cdp.evaluate(REACT_NATIVE_PROFILER_SETUP_SCRIPT);
49093
- const stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49251
+ let stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49094
49252
  if (!stateJson) {
49095
49253
  throw new Error("Failed to read React profiler state from runtime (no value returned).");
49096
49254
  }
49097
- const state2 = JSON.parse(stateJson);
49255
+ let state2 = JSON.parse(stateJson);
49098
49256
  if (!state2.hookExists) {
49099
49257
  throw new Error(
49100
- "__REACT_DEVTOOLS_GLOBAL_HOOK__ not present. React profiling requires a development build of the app."
49258
+ "React DevTools is not available in this app. This usually means the app is a production build. Ask the user to run a development build of the app, then retry."
49101
49259
  );
49102
49260
  }
49103
49261
  if (!("rendererInterfaceFound" in state2) || !state2.rendererInterfaceFound) {
49104
- throw new Error(
49105
- "No React renderer interface attached yet. Wait for the app to render its first commit and retry."
49106
- );
49262
+ const bootstrapJson = await cdp.evaluate(BOOTSTRAP_DEVTOOLS_BACKEND_SCRIPT);
49263
+ if (!bootstrapJson) {
49264
+ throw new Error(
49265
+ "Failed to attach React DevTools backend (no value returned from runtime)."
49266
+ );
49267
+ }
49268
+ const bootstrap = JSON.parse(bootstrapJson);
49269
+ if (!bootstrap.ok) {
49270
+ throw new Error(bootstrapFailureMessage(bootstrap));
49271
+ }
49272
+ await cdp.evaluate(REACT_NATIVE_PROFILER_SETUP_SCRIPT);
49273
+ stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49274
+ if (!stateJson) {
49275
+ throw new Error(
49276
+ "Failed to re-read React profiler state after attach (no value returned)."
49277
+ );
49278
+ }
49279
+ state2 = JSON.parse(stateJson);
49280
+ if (!state2.hookExists || !("rendererInterfaceFound" in state2) || !state2.rendererInterfaceFound) {
49281
+ throw new Error(
49282
+ "Attached the React DevTools backend but no React renderer registered itself afterwards. Ask the user to fully reload the JS bundle and retry."
49283
+ );
49284
+ }
49107
49285
  }
49108
49286
  if (state2.isRunning) {
49109
49287
  const owner = state2.owner;
@@ -49119,7 +49297,7 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
49119
49297
  owner,
49120
49298
  age_seconds: staleness.ageSeconds,
49121
49299
  stale: staleness.stale,
49122
- how_to_reclaim: 'A profiling session is already active. Stop and ask the user whether you should take over the session. To take over and discard the current session, call react-profiler-start again with { force: true }. Details about the current owner are in the `owner` field. If the sessions is marked as "stale", takeover is safe and may be initiated without prompting the user. Inform about possible cause of already running or stale session. When informing the user, warn about caveats of continuing profiling and taking over the old session.'
49300
+ how_to_reclaim: "Another profiling session is already active \u2014 see the `owner` field. Ask the user before taking over and explain that the prior session's data will be discarded; to take over, call react-profiler-start again with { force: true }. If `stale` is true, the prior owner is likely gone and you may take over without prompting the user."
49123
49301
  };
49124
49302
  }
49125
49303
  await cdp.evaluate(STOP_FOR_TAKEOVER_SCRIPT).catch(ignore);
@@ -54522,14 +54700,20 @@ function toYamlStep(step) {
54522
54700
  if (step.kind === "echo") {
54523
54701
  return { echo: step.message };
54524
54702
  }
54525
- const hasArgs = Object.keys(step.args).length > 0;
54526
- return hasArgs ? { tool: step.name, args: step.args } : { tool: step.name };
54703
+ const yaml = {
54704
+ tool: step.name
54705
+ };
54706
+ if (Object.keys(step.args).length > 0) yaml.args = step.args;
54707
+ if (step.delayMs !== void 0) yaml.delayMs = step.delayMs;
54708
+ return yaml;
54527
54709
  }
54528
54710
  function fromYamlStep(raw) {
54529
54711
  if ("echo" in raw) {
54530
54712
  return { kind: "echo", message: raw.echo };
54531
54713
  }
54532
- return { kind: "tool", name: raw.tool, args: raw.args ?? {} };
54714
+ const step = { kind: "tool", name: raw.tool, args: raw.args ?? {} };
54715
+ if (raw.delayMs !== void 0) step.delayMs = raw.delayMs;
54716
+ return step;
54533
54717
  }
54534
54718
  function serializeFlow(flow) {
54535
54719
  const doc = {
@@ -54622,7 +54806,8 @@ var zodSchema53 = external_exports.object({
54622
54806
  command: external_exports.string().describe('MCP tool name (e.g. "tap", "screenshot", "launch-app")'),
54623
54807
  args: external_exports.string().optional().describe(
54624
54808
  `Tool arguments as a JSON string, e.g. '{"udid": "ABC", "x": 0.5, "y": 0.3}'. Omit for tools with no arguments.`
54625
- )
54809
+ ),
54810
+ delayMs: external_exports.number().int().min(0).optional().describe("Milliseconds to sleep before executing this step during replay.")
54626
54811
  });
54627
54812
  function createFlowAddStepTool(registry) {
54628
54813
  return {
@@ -54639,7 +54824,8 @@ If a step was recorded by mistake, edit the .yaml file directly to remove it.`,
54639
54824
  const flowFile = await appendStep(filePath, {
54640
54825
  kind: "tool",
54641
54826
  name: params.command,
54642
- args
54827
+ args,
54828
+ delayMs: params.delayMs
54643
54829
  });
54644
54830
  return {
54645
54831
  message: `Step added to "${flowName}" flow`,
@@ -54723,13 +54909,15 @@ function createRunFlowTool(registry) {
54723
54909
  id: "flow-execute",
54724
54910
  description: `Run a saved flow from the .argent/flows/ directory.
54725
54911
  Each step is executed in order: tool calls are dispatched through the registry,
54726
- echo steps print a message. Returns the result of every step, including images.
54912
+ echo steps print a message. A tool step may carry \`delayMs: <ms>\` to sleep
54913
+ that long before the step runs. Returns the result of every step, including images.
54727
54914
  Use when you want to replay a recorded flow or run a scripted sequence of simulator actions.
54728
54915
  Fails if the flow file does not exist or a step tool raises an error (execution stops at that step).
54729
54916
 
54730
54917
  If the flow has an execution prerequisite and prerequisiteAcknowledged is not
54731
54918
  set to true, the tool returns a notice with the prerequisite instead of running.
54732
54919
  Use flow-read-prerequisite to inspect the prerequisite beforehand.`,
54920
+ longRunning: true,
54733
54921
  zodSchema: zodSchema56,
54734
54922
  services: () => ({}),
54735
54923
  async execute(_services, params) {
@@ -54751,6 +54939,7 @@ Use flow-read-prerequisite to inspect the prerequisite beforehand.`,
54751
54939
  steps.push({ kind: "echo", message: step.message });
54752
54940
  continue;
54753
54941
  }
54942
+ if (step.delayMs) await sleep4(step.delayMs);
54754
54943
  const toolDef = registry.getTool(step.name);
54755
54944
  try {
54756
54945
  const result = await registry.invokeTool(step.name, step.args);
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "MCP server for iOS Simulator and Android Emulator control",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -99,7 +99,7 @@ flow-execute { name: "open-settings", project_root: "/Users/dev/MyApp", prereq
99
99
  Flow files use YAML. The top-level is an object with `executionPrerequisite` (describes required state) and `steps` (array of actions):
100
100
 
101
101
  - `- echo: <message>` — a label
102
- - `- tool: <name>` with optional `args:` — a tool call
102
+ - `- tool: <name>` with optional `args:` — a tool call. Add `delayMs: <ms>` to sleep that long before the step runs (use sparingly — only when the app needs a fixed wait between actions).
103
103
 
104
104
  Example `.yaml` file:
105
105