@swmansion/argent 0.7.0-next.4 → 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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"}
@@ -12813,6 +12813,18 @@ function getInstalledVersion() {
12813
12813
  return null;
12814
12814
  }
12815
12815
  }
12816
+ function getGloballyInstalledVersion() {
12817
+ const binaryPath = getGlobalBinaryPath();
12818
+ if (!binaryPath) return null;
12819
+ try {
12820
+ const realPath = fs.realpathSync(binaryPath);
12821
+ const pkgRoot = resolvePackageRoot(path.dirname(realPath));
12822
+ const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
12823
+ return pkg.version ?? null;
12824
+ } catch {
12825
+ return null;
12826
+ }
12827
+ }
12816
12828
  var PROBE_TIMEOUT_MS = 3e3;
12817
12829
  function getLatestVersion() {
12818
12830
  const result = execSync(`npm view ${PACKAGE_NAME} version --registry ${NPM_REGISTRY}`, {
@@ -12835,18 +12847,21 @@ var TEMP_RUNNER_MARKERS = [
12835
12847
  function isTempRunnerPath(binaryPath) {
12836
12848
  return TEMP_RUNNER_MARKERS.some((marker) => binaryPath.includes(marker));
12837
12849
  }
12838
- function isGloballyInstalled() {
12850
+ function getGlobalBinaryPath() {
12839
12851
  try {
12840
12852
  const cmd = process.platform === "win32" ? "where" : "which -a";
12841
12853
  const output = execSync(`${cmd} ${MCP_BINARY_NAME}`, {
12842
12854
  encoding: "utf8",
12843
12855
  stdio: ["ignore", "pipe", "ignore"]
12844
12856
  });
12845
- return output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).some((line) => !isTempRunnerPath(line));
12857
+ return output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).find((line) => !isTempRunnerPath(line)) ?? null;
12846
12858
  } catch {
12847
- return false;
12859
+ return null;
12848
12860
  }
12849
12861
  }
12862
+ function isGloballyInstalled() {
12863
+ return getGlobalBinaryPath() !== null;
12864
+ }
12850
12865
  function isSkillsCliAvailable() {
12851
12866
  try {
12852
12867
  execSync("npx --no-install skills --version", {
@@ -14250,7 +14265,7 @@ async function update(args) {
14250
14265
  const nonInteractive = args.includes("--yes") || args.includes("-y");
14251
14266
  Wt2(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" argent update ")));
14252
14267
  const globallyInstalled = isGloballyInstalled();
14253
- const installed = globallyInstalled ? getInstalledVersion() : null;
14268
+ const installed = globallyInstalled ? getGloballyInstalledVersion() : null;
14254
14269
  if (globallyInstalled && !installed) {
14255
14270
  R2.error("Could not determine installed version.");
14256
14271
  process.exit(1);
@@ -14695,6 +14710,7 @@ export {
14695
14710
  MCP_BINARY_NAME,
14696
14711
  MCP_SERVER_KEY,
14697
14712
  PACKAGE_NAME,
14713
+ getGloballyInstalledVersion,
14698
14714
  getInstalledVersion,
14699
14715
  init,
14700
14716
  uninstall,
@@ -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);
@@ -18403,7 +18403,7 @@ var require_view = __commonJS({
18403
18403
  var path11 = require("path");
18404
18404
  var fs22 = require("fs");
18405
18405
  var dirname3 = path11.dirname;
18406
- var basename6 = path11.basename;
18406
+ var basename5 = path11.basename;
18407
18407
  var extname = path11.extname;
18408
18408
  var join15 = path11.join;
18409
18409
  var resolve2 = path11.resolve;
@@ -18442,7 +18442,7 @@ var require_view = __commonJS({
18442
18442
  var root = roots[i];
18443
18443
  var loc = resolve2(root, name);
18444
18444
  var dir = dirname3(loc);
18445
- var file = basename6(loc);
18445
+ var file = basename5(loc);
18446
18446
  path12 = this.resolve(dir, file);
18447
18447
  }
18448
18448
  return path12;
@@ -18458,7 +18458,7 @@ var require_view = __commonJS({
18458
18458
  if (stat2 && stat2.isFile()) {
18459
18459
  return path12;
18460
18460
  }
18461
- path12 = join15(dir, basename6(file, ext), "index" + ext);
18461
+ path12 = join15(dir, basename5(file, ext), "index" + ext);
18462
18462
  stat2 = tryStat(path12);
18463
18463
  if (stat2 && stat2.isFile()) {
18464
18464
  return path12;
@@ -18539,7 +18539,7 @@ var require_content_disposition = __commonJS({
18539
18539
  "use strict";
18540
18540
  module2.exports = contentDisposition;
18541
18541
  module2.exports.parse = parse;
18542
- var basename6 = require("path").basename;
18542
+ var basename5 = require("path").basename;
18543
18543
  var Buffer2 = require_safe_buffer().Buffer;
18544
18544
  var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
18545
18545
  var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
@@ -18575,9 +18575,9 @@ var require_content_disposition = __commonJS({
18575
18575
  if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
18576
18576
  throw new TypeError("fallback must be ISO-8859-1 string");
18577
18577
  }
18578
- var name = basename6(filename);
18578
+ var name = basename5(filename);
18579
18579
  var isQuotedString = TEXT_REGEXP.test(name);
18580
- var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename6(fallback);
18580
+ var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename5(fallback);
18581
18581
  var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
18582
18582
  if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
18583
18583
  params["filename*"] = name;
@@ -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-next.4";
41954
+ var version = "0.7.1";
41952
41955
 
41953
41956
  // ../tool-server/src/utils/update-checker.ts
41954
41957
  var PACKAGE_NAME = "@swmansion/argent";
@@ -42492,11 +42495,15 @@ var ADB_KILL_SIGNAL = "SIGKILL";
42492
42495
  function describeAdbFailure(args, err) {
42493
42496
  const e = err;
42494
42497
  const argv = args.join(" ");
42495
- const stderrText = (e.stderr ?? "").trim();
42496
- const stdoutText = (e.stdout ?? "").trim();
42497
- const baseMsg = e.message ?? String(err);
42498
- const detail = stderrText || stdoutText || baseMsg;
42499
- return new Error(`adb ${argv} failed: ${detail}`);
42498
+ const ioDetail = (e.stderr ?? "").trim() || (e.stdout ?? "").trim();
42499
+ if (ioDetail) return new Error(`adb ${argv} failed: ${ioDetail}`);
42500
+ const meta = [];
42501
+ if (e.killed) meta.push("killed=true");
42502
+ if (e.signal) meta.push(`signal=${e.signal}`);
42503
+ if (e.code) meta.push(`code=${e.code}`);
42504
+ const baseMsg = (e.message ?? String(err)).trim();
42505
+ const suffix = meta.length ? ` (${meta.join(" ")})` : "";
42506
+ return new Error(`adb ${argv} failed: ${baseMsg}${suffix}`);
42500
42507
  }
42501
42508
  async function runAdb(args, options = {}) {
42502
42509
  const adbPath = await resolveAdbOrThrow();
@@ -42933,6 +42940,7 @@ function createHttpApp(registry, options) {
42933
42940
  if (def?.outputHint) entry.outputHint = def.outputHint;
42934
42941
  if (def?.alwaysLoad) entry.alwaysLoad = true;
42935
42942
  if (def?.searchHint) entry.searchHint = def.searchHint;
42943
+ if (def?.longRunning) entry.longRunning = true;
42936
42944
  return entry;
42937
42945
  });
42938
42946
  res.json({ tools });
@@ -44926,6 +44934,136 @@ var REACT_NATIVE_PROFILER_SETUP_SCRIPT = `
44926
44934
  });
44927
44935
  })();
44928
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
+ `;
44929
45067
  var HEARTBEAT_SCRIPT = `
44930
45068
  (function(){
44931
45069
  if (typeof globalThis.__argent_profilerHeartbeat === 'function') {
@@ -46251,7 +46389,6 @@ Use when you need to scroll a list, dismiss a modal, or navigate between pages.
46251
46389
  };
46252
46390
 
46253
46391
  // ../tool-server/src/utils/gesture-utils.ts
46254
- var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
46255
46392
  function lerp(a, b, t) {
46256
46393
  return a + (b - a) * t;
46257
46394
  }
@@ -46299,7 +46436,7 @@ function sendTouchEvent(api, type, x, y, x2, y2) {
46299
46436
  }
46300
46437
 
46301
46438
  // ../tool-server/src/tools/gesture-custom/index.ts
46302
- var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
46439
+ var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
46303
46440
  var eventSchema = external_exports.object({
46304
46441
  type: external_exports.enum(["Down", "Move", "Up"]).describe("Touch event type"),
46305
46442
  x: external_exports.number().describe("Normalized x 0.0\u20131.0 (not pixels; same as tap/swipe)"),
@@ -46352,7 +46489,7 @@ Example pinch-to-zoom (with interpolate:10 for smoothness):
46352
46489
  const api = services.simulatorServer;
46353
46490
  const events = params.interpolate && params.interpolate > 0 ? interpolateEvents(params.events, params.interpolate) : params.events;
46354
46491
  for (const event of events) {
46355
- await sleep4(event.delayMs ?? 16);
46492
+ await sleep3(event.delayMs ?? 16);
46356
46493
  sendCommand(api, {
46357
46494
  cmd: "touch",
46358
46495
  type: event.type,
@@ -46366,6 +46503,10 @@ Example pinch-to-zoom (with interpolate:10 for smoothness):
46366
46503
  }
46367
46504
  };
46368
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
+
46369
46510
  // ../tool-server/src/tools/gesture-pinch/index.ts
46370
46511
  var zodSchema18 = external_exports.object({
46371
46512
  udid: external_exports.string().describe("Target device id from `list-devices` (iOS UDID or Android serial)."),
@@ -46420,7 +46561,7 @@ Use when you need to zoom in or out on a map, image, or zoomable view. Returns {
46420
46561
  const type = i === 0 ? "Down" : i === steps ? "Up" : "Move";
46421
46562
  if (i === 0) timestampMs = Date.now();
46422
46563
  sendTouchEvent(api, type, x1, y1, x2, y2);
46423
- if (i < steps) await sleep3(16);
46564
+ if (i < steps) await sleep4(16);
46424
46565
  }
46425
46566
  return { pinched: true, timestampMs };
46426
46567
  }
@@ -46474,7 +46615,7 @@ Use when you need to rotate a map, image picker, or any rotateable UI element. R
46474
46615
  const type = i === 0 ? "Down" : i === steps ? "Up" : "Move";
46475
46616
  if (i === 0) timestampMs = Date.now();
46476
46617
  sendTouchEvent(api, type, x1, y1, x2, y2);
46477
- if (i < steps) await sleep3(16);
46618
+ if (i < steps) await sleep4(16);
46478
46619
  }
46479
46620
  return { rotated: true, timestampMs };
46480
46621
  }
@@ -46696,7 +46837,6 @@ Returns { orientation }. Fails if the target device is not booted.`,
46696
46837
  };
46697
46838
 
46698
46839
  // ../tool-server/src/tools/run-sequence/index.ts
46699
- var sleep7 = (ms) => new Promise((r) => setTimeout(r, ms));
46700
46840
  var ALLOWED_TOOLS = /* @__PURE__ */ new Set([
46701
46841
  "gesture-tap",
46702
46842
  "gesture-swipe",
@@ -46717,7 +46857,9 @@ var zodSchema23 = external_exports.object({
46717
46857
  "Tool name \u2014 one of: gesture-tap, gesture-swipe, gesture-custom, gesture-pinch, gesture-rotate, button, keyboard, rotate"
46718
46858
  ),
46719
46859
  args: external_exports.record(external_exports.unknown()).describe("Tool arguments (excluding udid, which is injected automatically)"),
46720
- 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
+ )
46721
46863
  })
46722
46864
  ).min(1).describe("Ordered list of interaction steps to execute sequentially")
46723
46865
  });
@@ -46764,6 +46906,7 @@ Example \u2014 type text and submit:
46764
46906
 
46765
46907
  Stops on the first error and returns partial results.`,
46766
46908
  alwaysLoad: true,
46909
+ longRunning: true,
46767
46910
  searchHint: "batch sequence multiple gesture steps sequentially",
46768
46911
  zodSchema: zodSchema23,
46769
46912
  capability: capability15,
@@ -46792,8 +46935,8 @@ Stops on the first error and returns partial results.`,
46792
46935
  });
46793
46936
  break;
46794
46937
  }
46795
- const delay = step.delayMs ?? 100;
46796
- if (delay > 0) await sleep7(delay);
46938
+ const delay = step.delayMs ?? DEFAULT_INTER_STEP_DELAY_MS;
46939
+ if (delay > 0) await sleep4(delay);
46797
46940
  }
46798
46941
  return {
46799
46942
  completed: results.filter((r) => "result" in r).length,
@@ -48296,226 +48439,6 @@ ${body.slice(0, MAX_BODY_SIZE)}...`;
48296
48439
  }
48297
48440
  };
48298
48441
 
48299
- // ../tool-server/src/tools/describe/contract.ts
48300
- var describeFrameSchema = external_exports.object({
48301
- x: external_exports.number().finite().min(0).max(1),
48302
- y: external_exports.number().finite().min(0).max(1),
48303
- width: external_exports.number().finite().min(0).max(1),
48304
- height: external_exports.number().finite().min(0).max(1)
48305
- });
48306
- var describeNodeSchema = external_exports.lazy(
48307
- () => external_exports.object({
48308
- role: external_exports.string().min(1),
48309
- frame: describeFrameSchema,
48310
- children: external_exports.array(describeNodeSchema),
48311
- label: external_exports.string().optional(),
48312
- identifier: external_exports.string().optional(),
48313
- value: external_exports.string().optional(),
48314
- clickable: external_exports.boolean().optional(),
48315
- longClickable: external_exports.boolean().optional(),
48316
- scrollable: external_exports.boolean().optional(),
48317
- checkable: external_exports.boolean().optional(),
48318
- checked: external_exports.boolean().optional(),
48319
- disabled: external_exports.boolean().optional(),
48320
- password: external_exports.boolean().optional(),
48321
- scrollHidden: external_exports.number().int().nonnegative().optional()
48322
- }).passthrough()
48323
- );
48324
- function parseDescribeResult(input) {
48325
- return describeNodeSchema.parse(input);
48326
- }
48327
-
48328
- // ../tool-server/src/tools/describe/platforms/ios-native-adapter.ts
48329
- function clamp01(value) {
48330
- return Math.min(1, Math.max(0, value));
48331
- }
48332
- function roundNormalized(value) {
48333
- return Math.round(value * 1e12) / 1e12;
48334
- }
48335
- function clampNormalizedFrame(frame) {
48336
- const x1 = clamp01(frame.x);
48337
- const y1 = clamp01(frame.y);
48338
- const x2 = clamp01(frame.x + frame.width);
48339
- const y2 = clamp01(frame.y + frame.height);
48340
- const width = x2 - x1;
48341
- const height = y2 - y1;
48342
- if (width <= 0 || height <= 0) {
48343
- return null;
48344
- }
48345
- return {
48346
- x: roundNormalized(x1),
48347
- y: roundNormalized(y1),
48348
- width: roundNormalized(width),
48349
- height: roundNormalized(height)
48350
- };
48351
- }
48352
- function mapNativeTraitsToDescribeRole(traits) {
48353
- const set = new Set(traits);
48354
- if (set.has("header")) return "AXHeading";
48355
- if (set.has("button") || set.has("toggleButton")) return "AXButton";
48356
- if (set.has("searchField")) return "AXTextField";
48357
- if (set.has("link")) return "AXLink";
48358
- if (set.has("image")) return "AXImage";
48359
- if (set.has("staticText")) return "AXStaticText";
48360
- if (set.has("tabBar")) return "AXTabBar";
48361
- if (set.has("adjustable")) return "AXAdjustable";
48362
- return "AXGroup";
48363
- }
48364
- function adaptNativeDescribeElementToDescribeNode(element) {
48365
- const frame = clampNormalizedFrame(element.normalizedFrame);
48366
- if (!frame) return null;
48367
- return {
48368
- role: mapNativeTraitsToDescribeRole(element.traits),
48369
- frame,
48370
- children: [],
48371
- label: element.label,
48372
- identifier: element.identifier,
48373
- value: element.value
48374
- };
48375
- }
48376
- function adaptNativeDescribeToDescribeResult(result) {
48377
- const children = result.elements.map(adaptNativeDescribeElementToDescribeNode).filter((node) => node !== null);
48378
- return parseDescribeResult({
48379
- role: "AXGroup",
48380
- frame: {
48381
- x: 0,
48382
- y: 0,
48383
- width: 1,
48384
- height: 1
48385
- },
48386
- children
48387
- });
48388
- }
48389
-
48390
- // ../tool-server/src/tools/describe/platforms/ios-ax-adapter.ts
48391
- function clamp012(value) {
48392
- return Math.min(1, Math.max(0, value));
48393
- }
48394
- function roundNormalized2(value) {
48395
- return Math.round(value * 1e12) / 1e12;
48396
- }
48397
- function adaptAXElement(el) {
48398
- if (!el.frame) return null;
48399
- const x1 = clamp012(el.frame.x);
48400
- const y1 = clamp012(el.frame.y);
48401
- const x2 = clamp012(el.frame.x + el.frame.width);
48402
- const y2 = clamp012(el.frame.y + el.frame.height);
48403
- const width = x2 - x1;
48404
- const height = y2 - y1;
48405
- if (width <= 0 || height <= 0) return null;
48406
- return {
48407
- role: mapNativeTraitsToDescribeRole(el.traits ?? []),
48408
- frame: {
48409
- x: roundNormalized2(x1),
48410
- y: roundNormalized2(y1),
48411
- width: roundNormalized2(width),
48412
- height: roundNormalized2(height)
48413
- },
48414
- children: [],
48415
- label: el.label,
48416
- value: el.value
48417
- };
48418
- }
48419
- function adaptAXDescribeToDescribeResult(response) {
48420
- const children = response.elements.map(adaptAXElement).filter((n) => n !== null);
48421
- return parseDescribeResult({
48422
- role: "AXGroup",
48423
- frame: { x: 0, y: 0, width: 1, height: 1 },
48424
- children
48425
- });
48426
- }
48427
-
48428
- // ../tool-server/src/utils/native-target-app.ts
48429
- function chooseFrontmostConnectedApp(apps) {
48430
- const strongCandidates = apps.filter(
48431
- (app) => app.applicationState === "active" || app.foregroundActiveSceneCount > 0
48432
- );
48433
- if (strongCandidates.length === 1) {
48434
- return strongCandidates[0];
48435
- }
48436
- const weakCandidates = apps.filter(
48437
- (app) => app.applicationState === "inactive" || app.foregroundInactiveSceneCount > 0
48438
- );
48439
- if (strongCandidates.length === 0 && weakCandidates.length === 1) {
48440
- return weakCandidates[0];
48441
- }
48442
- return null;
48443
- }
48444
- async function inspectConnectedNativeApps(api) {
48445
- const bundleIds = api.listConnectedBundleIds();
48446
- const appStates = await Promise.all(bundleIds.map((bundleId) => api.getAppState(bundleId)));
48447
- return appStates.sort((a, b) => a.bundleId.localeCompare(b.bundleId));
48448
- }
48449
- async function resolveNativeTargetApp(api, bundleId) {
48450
- if (bundleId) {
48451
- return { bundleId, source: "explicit" };
48452
- }
48453
- const connectedApps = await inspectConnectedNativeApps(api);
48454
- if (connectedApps.length === 0) {
48455
- throw new Error(
48456
- "No native-devtools-connected apps are available for auto-targeting. Launch or restart the app first, provide bundleId explicitly, or use screenshot to inspect visible Home/system UI."
48457
- );
48458
- }
48459
- const frontmost = chooseFrontmostConnectedApp(connectedApps);
48460
- if (connectedApps.length === 1) {
48461
- if (frontmost) {
48462
- return {
48463
- bundleId: connectedApps[0].bundleId,
48464
- source: "single_connected_foreground_like"
48465
- };
48466
- }
48467
- const app = connectedApps[0];
48468
- throw new Error(
48469
- `A single native-devtools-connected app is available, but it is not foreground-like and may be backgrounded while home/system UI is visible.
48470
- - ${app.bundleId} (applicationState=${app.applicationState}, foregroundActiveScenes=${app.foregroundActiveSceneCount}, foregroundInactiveScenes=${app.foregroundInactiveSceneCount})
48471
- Provide bundleId explicitly if you still want to target this app.`
48472
- );
48473
- }
48474
- if (frontmost) {
48475
- return { bundleId: frontmost.bundleId, source: "frontmost_detected" };
48476
- }
48477
- const appList = connectedApps.map(
48478
- (app) => `- ${app.bundleId} (applicationState=${app.applicationState}, foregroundActiveScenes=${app.foregroundActiveSceneCount}, foregroundInactiveScenes=${app.foregroundInactiveSceneCount})`
48479
- ).join("\n");
48480
- throw new Error(
48481
- `Multiple native-devtools-connected apps are available and none can be identified as uniquely frontmost.
48482
- ${appList}
48483
- Provide bundleId explicitly.`
48484
- );
48485
- }
48486
-
48487
- // ../tool-server/src/tools/describe/platforms/ios.ts
48488
- var iosRequires = ["xcrun"];
48489
- async function describeIos(registry, device, params) {
48490
- const axRef = axServiceRef(device);
48491
- const axApi = await registry.resolveService(axRef.urn, axRef.options);
48492
- const response = await axApi.describe();
48493
- const tree = adaptAXDescribeToDescribeResult(response);
48494
- if (tree.children.length > 0) {
48495
- return { tree, source: "ax-service" };
48496
- }
48497
- try {
48498
- const ndRef = nativeDevtoolsRef(device);
48499
- const nativeApi = await registry.resolveService(ndRef.urn, ndRef.options);
48500
- const target = await resolveNativeTargetApp(nativeApi, params.bundleId);
48501
- if (await nativeApi.requiresAppRestart(target.bundleId)) {
48502
- return { tree, source: "ax-service", should_restart: true };
48503
- }
48504
- const rawResult = await nativeApi.queryViewHierarchy(
48505
- target.bundleId,
48506
- "ViewHierarchy.describeScreen"
48507
- );
48508
- if (rawResult.error) {
48509
- return { tree, source: "ax-service" };
48510
- }
48511
- const parsed = parseNativeDescribeScreenResult(rawResult);
48512
- const nativeTree = adaptNativeDescribeToDescribeResult(parsed);
48513
- return { tree: nativeTree, source: "native-devtools" };
48514
- } catch {
48515
- return { tree, source: "ax-service" };
48516
- }
48517
- }
48518
-
48519
48442
  // ../tool-server/src/utils/android-screen.ts
48520
48443
  async function getAndroidScreenSize(serial) {
48521
48444
  const out = await adbShell(serial, "wm size", { timeoutMs: 5e3 });
@@ -48533,7 +48456,7 @@ async function getAndroidScreenSize(serial) {
48533
48456
  return { width, height };
48534
48457
  }
48535
48458
 
48536
- // ../tool-server/src/utils/uiautomator-parser.ts
48459
+ // ../tool-server/src/tools/describe/platforms/android/uiautomator-parser.ts
48537
48460
  function parseUiAutomatorXml(xml) {
48538
48461
  const body = xml.replace(/^\s*<\?xml[^?]*\?>\s*/, "");
48539
48462
  const tagRe = /<(\/?)([A-Za-z_][\w.-]*)((?:"[^"]*"|'[^']*'|[^"'/<>])*?)\s*(\/?)>/gs;
@@ -48915,7 +48838,7 @@ function parseUiAutomatorDump(rawOutput, screenW, screenH, options = {}) {
48915
48838
  };
48916
48839
  }
48917
48840
 
48918
- // ../tool-server/src/tools/describe/platforms/android.ts
48841
+ // ../tool-server/src/tools/describe/platforms/android/index.ts
48919
48842
  var androidRequires = ["adb"];
48920
48843
  async function describeAndroid(udid, _bundleId) {
48921
48844
  const randomSuffix = `${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;
@@ -48939,6 +48862,226 @@ async function describeAndroid(udid, _bundleId) {
48939
48862
  return { tree, source: "uiautomator" };
48940
48863
  }
48941
48864
 
48865
+ // ../tool-server/src/utils/native-target-app.ts
48866
+ function chooseFrontmostConnectedApp(apps) {
48867
+ const strongCandidates = apps.filter(
48868
+ (app) => app.applicationState === "active" || app.foregroundActiveSceneCount > 0
48869
+ );
48870
+ if (strongCandidates.length === 1) {
48871
+ return strongCandidates[0];
48872
+ }
48873
+ const weakCandidates = apps.filter(
48874
+ (app) => app.applicationState === "inactive" || app.foregroundInactiveSceneCount > 0
48875
+ );
48876
+ if (strongCandidates.length === 0 && weakCandidates.length === 1) {
48877
+ return weakCandidates[0];
48878
+ }
48879
+ return null;
48880
+ }
48881
+ async function inspectConnectedNativeApps(api) {
48882
+ const bundleIds = api.listConnectedBundleIds();
48883
+ const appStates = await Promise.all(bundleIds.map((bundleId) => api.getAppState(bundleId)));
48884
+ return appStates.sort((a, b) => a.bundleId.localeCompare(b.bundleId));
48885
+ }
48886
+ async function resolveNativeTargetApp(api, bundleId) {
48887
+ if (bundleId) {
48888
+ return { bundleId, source: "explicit" };
48889
+ }
48890
+ const connectedApps = await inspectConnectedNativeApps(api);
48891
+ if (connectedApps.length === 0) {
48892
+ throw new Error(
48893
+ "No native-devtools-connected apps are available for auto-targeting. Launch or restart the app first, provide bundleId explicitly, or use screenshot to inspect visible Home/system UI."
48894
+ );
48895
+ }
48896
+ const frontmost = chooseFrontmostConnectedApp(connectedApps);
48897
+ if (connectedApps.length === 1) {
48898
+ if (frontmost) {
48899
+ return {
48900
+ bundleId: connectedApps[0].bundleId,
48901
+ source: "single_connected_foreground_like"
48902
+ };
48903
+ }
48904
+ const app = connectedApps[0];
48905
+ throw new Error(
48906
+ `A single native-devtools-connected app is available, but it is not foreground-like and may be backgrounded while home/system UI is visible.
48907
+ - ${app.bundleId} (applicationState=${app.applicationState}, foregroundActiveScenes=${app.foregroundActiveSceneCount}, foregroundInactiveScenes=${app.foregroundInactiveSceneCount})
48908
+ Provide bundleId explicitly if you still want to target this app.`
48909
+ );
48910
+ }
48911
+ if (frontmost) {
48912
+ return { bundleId: frontmost.bundleId, source: "frontmost_detected" };
48913
+ }
48914
+ const appList = connectedApps.map(
48915
+ (app) => `- ${app.bundleId} (applicationState=${app.applicationState}, foregroundActiveScenes=${app.foregroundActiveSceneCount}, foregroundInactiveScenes=${app.foregroundInactiveSceneCount})`
48916
+ ).join("\n");
48917
+ throw new Error(
48918
+ `Multiple native-devtools-connected apps are available and none can be identified as uniquely frontmost.
48919
+ ${appList}
48920
+ Provide bundleId explicitly.`
48921
+ );
48922
+ }
48923
+
48924
+ // ../tool-server/src/tools/describe/contract.ts
48925
+ var describeFrameSchema = external_exports.object({
48926
+ x: external_exports.number().finite().min(0).max(1),
48927
+ y: external_exports.number().finite().min(0).max(1),
48928
+ width: external_exports.number().finite().min(0).max(1),
48929
+ height: external_exports.number().finite().min(0).max(1)
48930
+ });
48931
+ var describeNodeSchema = external_exports.lazy(
48932
+ () => external_exports.object({
48933
+ role: external_exports.string().min(1),
48934
+ frame: describeFrameSchema,
48935
+ children: external_exports.array(describeNodeSchema),
48936
+ label: external_exports.string().optional(),
48937
+ identifier: external_exports.string().optional(),
48938
+ value: external_exports.string().optional(),
48939
+ clickable: external_exports.boolean().optional(),
48940
+ longClickable: external_exports.boolean().optional(),
48941
+ scrollable: external_exports.boolean().optional(),
48942
+ checkable: external_exports.boolean().optional(),
48943
+ checked: external_exports.boolean().optional(),
48944
+ disabled: external_exports.boolean().optional(),
48945
+ password: external_exports.boolean().optional(),
48946
+ scrollHidden: external_exports.number().int().nonnegative().optional()
48947
+ }).passthrough()
48948
+ );
48949
+ function parseDescribeResult(input) {
48950
+ return describeNodeSchema.parse(input);
48951
+ }
48952
+
48953
+ // ../tool-server/src/tools/describe/platforms/ios/ios-native-adapter.ts
48954
+ function clamp01(value) {
48955
+ return Math.min(1, Math.max(0, value));
48956
+ }
48957
+ function roundNormalized(value) {
48958
+ return Math.round(value * 1e12) / 1e12;
48959
+ }
48960
+ function clampNormalizedFrame(frame) {
48961
+ const x1 = clamp01(frame.x);
48962
+ const y1 = clamp01(frame.y);
48963
+ const x2 = clamp01(frame.x + frame.width);
48964
+ const y2 = clamp01(frame.y + frame.height);
48965
+ const width = x2 - x1;
48966
+ const height = y2 - y1;
48967
+ if (width <= 0 || height <= 0) {
48968
+ return null;
48969
+ }
48970
+ return {
48971
+ x: roundNormalized(x1),
48972
+ y: roundNormalized(y1),
48973
+ width: roundNormalized(width),
48974
+ height: roundNormalized(height)
48975
+ };
48976
+ }
48977
+ function mapNativeTraitsToDescribeRole(traits) {
48978
+ const set = new Set(traits);
48979
+ if (set.has("header")) return "AXHeading";
48980
+ if (set.has("button") || set.has("toggleButton")) return "AXButton";
48981
+ if (set.has("searchField")) return "AXTextField";
48982
+ if (set.has("link")) return "AXLink";
48983
+ if (set.has("image")) return "AXImage";
48984
+ if (set.has("staticText")) return "AXStaticText";
48985
+ if (set.has("tabBar")) return "AXTabBar";
48986
+ if (set.has("adjustable")) return "AXAdjustable";
48987
+ return "AXGroup";
48988
+ }
48989
+ function adaptNativeDescribeElementToDescribeNode(element) {
48990
+ const frame = clampNormalizedFrame(element.normalizedFrame);
48991
+ if (!frame) return null;
48992
+ return {
48993
+ role: mapNativeTraitsToDescribeRole(element.traits),
48994
+ frame,
48995
+ children: [],
48996
+ label: element.label,
48997
+ identifier: element.identifier,
48998
+ value: element.value
48999
+ };
49000
+ }
49001
+ function adaptNativeDescribeToDescribeResult(result) {
49002
+ const children = result.elements.map(adaptNativeDescribeElementToDescribeNode).filter((node) => node !== null);
49003
+ return parseDescribeResult({
49004
+ role: "AXGroup",
49005
+ frame: {
49006
+ x: 0,
49007
+ y: 0,
49008
+ width: 1,
49009
+ height: 1
49010
+ },
49011
+ children
49012
+ });
49013
+ }
49014
+
49015
+ // ../tool-server/src/tools/describe/platforms/ios/ios-ax-adapter.ts
49016
+ function clamp012(value) {
49017
+ return Math.min(1, Math.max(0, value));
49018
+ }
49019
+ function roundNormalized2(value) {
49020
+ return Math.round(value * 1e12) / 1e12;
49021
+ }
49022
+ function adaptAXElement(el) {
49023
+ if (!el.frame) return null;
49024
+ const x1 = clamp012(el.frame.x);
49025
+ const y1 = clamp012(el.frame.y);
49026
+ const x2 = clamp012(el.frame.x + el.frame.width);
49027
+ const y2 = clamp012(el.frame.y + el.frame.height);
49028
+ const width = x2 - x1;
49029
+ const height = y2 - y1;
49030
+ if (width <= 0 || height <= 0) return null;
49031
+ return {
49032
+ role: mapNativeTraitsToDescribeRole(el.traits ?? []),
49033
+ frame: {
49034
+ x: roundNormalized2(x1),
49035
+ y: roundNormalized2(y1),
49036
+ width: roundNormalized2(width),
49037
+ height: roundNormalized2(height)
49038
+ },
49039
+ children: [],
49040
+ label: el.label,
49041
+ value: el.value
49042
+ };
49043
+ }
49044
+ function adaptAXDescribeToDescribeResult(response) {
49045
+ const children = response.elements.map(adaptAXElement).filter((n) => n !== null);
49046
+ return parseDescribeResult({
49047
+ role: "AXGroup",
49048
+ frame: { x: 0, y: 0, width: 1, height: 1 },
49049
+ children
49050
+ });
49051
+ }
49052
+
49053
+ // ../tool-server/src/tools/describe/platforms/ios/index.ts
49054
+ var iosRequires = ["xcrun"];
49055
+ async function describeIos(registry, device, params) {
49056
+ const axRef = axServiceRef(device);
49057
+ const axApi = await registry.resolveService(axRef.urn, axRef.options);
49058
+ const response = await axApi.describe();
49059
+ const tree = adaptAXDescribeToDescribeResult(response);
49060
+ if (tree.children.length > 0) {
49061
+ return { tree, source: "ax-service" };
49062
+ }
49063
+ try {
49064
+ const ndRef = nativeDevtoolsRef(device);
49065
+ const nativeApi = await registry.resolveService(ndRef.urn, ndRef.options);
49066
+ const target = await resolveNativeTargetApp(nativeApi, params.bundleId);
49067
+ if (await nativeApi.requiresAppRestart(target.bundleId)) {
49068
+ return { tree, source: "ax-service", should_restart: true };
49069
+ }
49070
+ const rawResult = await nativeApi.queryViewHierarchy(
49071
+ target.bundleId,
49072
+ "ViewHierarchy.describeScreen"
49073
+ );
49074
+ if (rawResult.error) {
49075
+ return { tree, source: "ax-service" };
49076
+ }
49077
+ const parsed = parseNativeDescribeScreenResult(rawResult);
49078
+ const nativeTree = adaptNativeDescribeToDescribeResult(parsed);
49079
+ return { tree: nativeTree, source: "native-devtools" };
49080
+ } catch {
49081
+ return { tree, source: "ax-service" };
49082
+ }
49083
+ }
49084
+
48942
49085
  // ../tool-server/src/tools/describe/index.ts
48943
49086
  var zodSchema33 = external_exports.object({
48944
49087
  udid: external_exports.string().min(1).describe("Target device id from `list-devices` (iOS UDID or Android serial)."),
@@ -49016,6 +49159,25 @@ function classifyStaleness({
49016
49159
  };
49017
49160
  }
49018
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
+
49019
49181
  // ../tool-server/src/tools/profiler/react/react-profiler-start.ts
49020
49182
  var zodSchema34 = external_exports.object({
49021
49183
  port: external_exports.coerce.number().default(8081).describe("Metro server port"),
@@ -49086,20 +49248,40 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
49086
49248
  }
49087
49249
  const cdp = api.cdp;
49088
49250
  await cdp.evaluate(REACT_NATIVE_PROFILER_SETUP_SCRIPT);
49089
- const stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49251
+ let stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49090
49252
  if (!stateJson) {
49091
49253
  throw new Error("Failed to read React profiler state from runtime (no value returned).");
49092
49254
  }
49093
- const state2 = JSON.parse(stateJson);
49255
+ let state2 = JSON.parse(stateJson);
49094
49256
  if (!state2.hookExists) {
49095
49257
  throw new Error(
49096
- "__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."
49097
49259
  );
49098
49260
  }
49099
49261
  if (!("rendererInterfaceFound" in state2) || !state2.rendererInterfaceFound) {
49100
- throw new Error(
49101
- "No React renderer interface attached yet. Wait for the app to render its first commit and retry."
49102
- );
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
+ }
49103
49285
  }
49104
49286
  if (state2.isRunning) {
49105
49287
  const owner = state2.owner;
@@ -49115,7 +49297,7 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
49115
49297
  owner,
49116
49298
  age_seconds: staleness.ageSeconds,
49117
49299
  stale: staleness.stale,
49118
- 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."
49119
49301
  };
49120
49302
  }
49121
49303
  await cdp.evaluate(STOP_FOR_TAKEOVER_SCRIPT).catch(ignore);
@@ -54518,14 +54700,20 @@ function toYamlStep(step) {
54518
54700
  if (step.kind === "echo") {
54519
54701
  return { echo: step.message };
54520
54702
  }
54521
- const hasArgs = Object.keys(step.args).length > 0;
54522
- 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;
54523
54709
  }
54524
54710
  function fromYamlStep(raw) {
54525
54711
  if ("echo" in raw) {
54526
54712
  return { kind: "echo", message: raw.echo };
54527
54713
  }
54528
- 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;
54529
54717
  }
54530
54718
  function serializeFlow(flow) {
54531
54719
  const doc = {
@@ -54618,7 +54806,8 @@ var zodSchema53 = external_exports.object({
54618
54806
  command: external_exports.string().describe('MCP tool name (e.g. "tap", "screenshot", "launch-app")'),
54619
54807
  args: external_exports.string().optional().describe(
54620
54808
  `Tool arguments as a JSON string, e.g. '{"udid": "ABC", "x": 0.5, "y": 0.3}'. Omit for tools with no arguments.`
54621
- )
54809
+ ),
54810
+ delayMs: external_exports.number().int().min(0).optional().describe("Milliseconds to sleep before executing this step during replay.")
54622
54811
  });
54623
54812
  function createFlowAddStepTool(registry) {
54624
54813
  return {
@@ -54635,7 +54824,8 @@ If a step was recorded by mistake, edit the .yaml file directly to remove it.`,
54635
54824
  const flowFile = await appendStep(filePath, {
54636
54825
  kind: "tool",
54637
54826
  name: params.command,
54638
- args
54827
+ args,
54828
+ delayMs: params.delayMs
54639
54829
  });
54640
54830
  return {
54641
54831
  message: `Step added to "${flowName}" flow`,
@@ -54719,13 +54909,15 @@ function createRunFlowTool(registry) {
54719
54909
  id: "flow-execute",
54720
54910
  description: `Run a saved flow from the .argent/flows/ directory.
54721
54911
  Each step is executed in order: tool calls are dispatched through the registry,
54722
- 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.
54723
54914
  Use when you want to replay a recorded flow or run a scripted sequence of simulator actions.
54724
54915
  Fails if the flow file does not exist or a step tool raises an error (execution stops at that step).
54725
54916
 
54726
54917
  If the flow has an execution prerequisite and prerequisiteAcknowledged is not
54727
54918
  set to true, the tool returns a notice with the prerequisite instead of running.
54728
54919
  Use flow-read-prerequisite to inspect the prerequisite beforehand.`,
54920
+ longRunning: true,
54729
54921
  zodSchema: zodSchema56,
54730
54922
  services: () => ({}),
54731
54923
  async execute(_services, params) {
@@ -54747,6 +54939,7 @@ Use flow-read-prerequisite to inspect the prerequisite beforehand.`,
54747
54939
  steps.push({ kind: "echo", message: step.message });
54748
54940
  continue;
54749
54941
  }
54942
+ if (step.delayMs) await sleep4(step.delayMs);
54750
54943
  const toolDef = registry.getTool(step.name);
54751
54944
  try {
54752
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-next.4",
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