@swmansion/argent 0.7.0 → 0.8.0

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.
@@ -17652,6 +17652,7 @@ var require_path_to_regexp = __commonJS({
17652
17652
  }
17653
17653
  pos = offset + match.length;
17654
17654
  if (match === "*") {
17655
+ backtrack = "";
17655
17656
  extraOffset += 3;
17656
17657
  return "(.*)";
17657
17658
  }
@@ -17672,6 +17673,7 @@ var require_path_to_regexp = __commonJS({
17672
17673
  offset: offset + extraOffset
17673
17674
  });
17674
17675
  var result = "(?:" + format + slash + capture + (star ? "((?:[/" + format + "].+?)?)" : "") + ")" + optional;
17676
+ backtrack = "";
17675
17677
  extraOffset += result.length - match.length;
17676
17678
  return result;
17677
17679
  }
@@ -23413,6 +23415,47 @@ var require_coerce = __commonJS({
23413
23415
  }
23414
23416
  });
23415
23417
 
23418
+ // ../../node_modules/semver/functions/truncate.js
23419
+ var require_truncate = __commonJS({
23420
+ "../../node_modules/semver/functions/truncate.js"(exports2, module2) {
23421
+ "use strict";
23422
+ var parse = require_parse2();
23423
+ var constants = require_constants();
23424
+ var SemVer = require_semver();
23425
+ var truncate = (version2, truncation, options) => {
23426
+ if (!constants.RELEASE_TYPES.includes(truncation)) {
23427
+ return null;
23428
+ }
23429
+ const clonedVersion = cloneInputVersion(version2, options);
23430
+ return clonedVersion && doTruncation(clonedVersion, truncation);
23431
+ };
23432
+ var cloneInputVersion = (version2, options) => {
23433
+ const versionStringToParse = version2 instanceof SemVer ? version2.version : version2;
23434
+ return parse(versionStringToParse, options);
23435
+ };
23436
+ var doTruncation = (version2, truncation) => {
23437
+ if (isPrerelease(truncation)) {
23438
+ return version2.version;
23439
+ }
23440
+ version2.prerelease = [];
23441
+ switch (truncation) {
23442
+ case "major":
23443
+ version2.minor = 0;
23444
+ version2.patch = 0;
23445
+ break;
23446
+ case "minor":
23447
+ version2.patch = 0;
23448
+ break;
23449
+ }
23450
+ return version2.format();
23451
+ };
23452
+ var isPrerelease = (type) => {
23453
+ return type.startsWith("pre");
23454
+ };
23455
+ module2.exports = truncate;
23456
+ }
23457
+ });
23458
+
23416
23459
  // ../../node_modules/semver/internal/lrucache.js
23417
23460
  var require_lrucache = __commonJS({
23418
23461
  "../../node_modules/semver/internal/lrucache.js"(exports2, module2) {
@@ -24447,6 +24490,7 @@ var require_semver2 = __commonJS({
24447
24490
  var lte = require_lte();
24448
24491
  var cmp = require_cmp();
24449
24492
  var coerce2 = require_coerce();
24493
+ var truncate = require_truncate();
24450
24494
  var Comparator = require_comparator();
24451
24495
  var Range = require_range2();
24452
24496
  var satisfies = require_satisfies();
@@ -24485,6 +24529,7 @@ var require_semver2 = __commonJS({
24485
24529
  lte,
24486
24530
  cmp,
24487
24531
  coerce: coerce2,
24532
+ truncate,
24488
24533
  Comparator,
24489
24534
  Range,
24490
24535
  satisfies,
@@ -30631,6 +30676,8 @@ var require_Alias = __commonJS({
30631
30676
  * instance of the `source` anchor before this node.
30632
30677
  */
30633
30678
  resolve(doc, ctx) {
30679
+ if (ctx?.maxAliasCount === 0)
30680
+ throw new ReferenceError("Alias resolution is disabled");
30634
30681
  let nodes;
30635
30682
  if (ctx?.aliasResolveCache) {
30636
30683
  nodes = ctx.aliasResolveCache;
@@ -31703,18 +31750,18 @@ var require_merge = __commonJS({
31703
31750
  };
31704
31751
  var isMergeKey = (ctx, key) => (merge.identify(key) || identity.isScalar(key) && (!key.type || key.type === Scalar.Scalar.PLAIN) && merge.identify(key.value)) && ctx?.doc.schema.tags.some((tag2) => tag2.tag === merge.tag && tag2.default);
31705
31752
  function addMergeToJSMap(ctx, map, value) {
31706
- value = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
31707
- if (identity.isSeq(value))
31708
- for (const it of value.items)
31753
+ const source = resolveAliasValue(ctx, value);
31754
+ if (identity.isSeq(source))
31755
+ for (const it of source.items)
31709
31756
  mergeValue(ctx, map, it);
31710
- else if (Array.isArray(value))
31711
- for (const it of value)
31757
+ else if (Array.isArray(source))
31758
+ for (const it of source)
31712
31759
  mergeValue(ctx, map, it);
31713
31760
  else
31714
- mergeValue(ctx, map, value);
31761
+ mergeValue(ctx, map, source);
31715
31762
  }
31716
31763
  function mergeValue(ctx, map, value) {
31717
- const source = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
31764
+ const source = resolveAliasValue(ctx, value);
31718
31765
  if (!identity.isMap(source))
31719
31766
  throw new Error("Merge sources must be maps or map aliases");
31720
31767
  const srcMap = source.toJSON(null, ctx, Map);
@@ -31735,6 +31782,9 @@ var require_merge = __commonJS({
31735
31782
  }
31736
31783
  return map;
31737
31784
  }
31785
+ function resolveAliasValue(ctx, value) {
31786
+ return ctx && identity.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
31787
+ }
31738
31788
  exports2.addMergeToJSMap = addMergeToJSMap;
31739
31789
  exports2.isMergeKey = isMergeKey;
31740
31790
  exports2.merge = merge;
@@ -32372,7 +32422,7 @@ var require_stringifyNumber = __commonJS({
32372
32422
  if (!isFinite(num))
32373
32423
  return isNaN(num) ? ".nan" : num < 0 ? "-.inf" : ".inf";
32374
32424
  let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
32375
- if (!format && minFractionDigits && (!tag2 || tag2 === "tag:yaml.org,2002:float") && /^\d/.test(n)) {
32425
+ if (!format && minFractionDigits && (!tag2 || tag2 === "tag:yaml.org,2002:float") && /^-?\d/.test(n) && !n.includes("e")) {
32376
32426
  let i = n.indexOf(".");
32377
32427
  if (i < 0) {
32378
32428
  i = n.length;
@@ -34744,7 +34794,7 @@ var require_resolve_flow_scalar = __commonJS({
34744
34794
  while (next === " " || next === " ")
34745
34795
  next = source[++i + 1];
34746
34796
  } else if (next === "x" || next === "u" || next === "U") {
34747
- const length = { x: 2, u: 4, U: 8 }[next];
34797
+ const length = next === "x" ? 2 : next === "u" ? 4 : 8;
34748
34798
  res += parseCharCode(source, i + 1, length, onError);
34749
34799
  i += length;
34750
34800
  } else {
@@ -34819,12 +34869,13 @@ var require_resolve_flow_scalar = __commonJS({
34819
34869
  const cc = source.substr(offset, length);
34820
34870
  const ok = cc.length === length && /^[0-9a-fA-F]+$/.test(cc);
34821
34871
  const code = ok ? parseInt(cc, 16) : NaN;
34822
- if (isNaN(code)) {
34872
+ try {
34873
+ return String.fromCodePoint(code);
34874
+ } catch {
34823
34875
  const raw = source.substr(offset - 2, length + 2);
34824
34876
  onError(offset - 2, "BAD_DQ_ESCAPE", `Invalid escape sequence ${raw}`);
34825
34877
  return raw;
34826
34878
  }
34827
- return String.fromCodePoint(code);
34828
34879
  }
34829
34880
  exports2.resolveFlowScalar = resolveFlowScalar;
34830
34881
  }
@@ -35174,8 +35225,10 @@ ${cb}` : comment;
35174
35225
  }
35175
35226
  }
35176
35227
  if (afterDoc) {
35177
- Array.prototype.push.apply(doc.errors, this.errors);
35178
- Array.prototype.push.apply(doc.warnings, this.warnings);
35228
+ for (let i = 0; i < this.errors.length; ++i)
35229
+ doc.errors.push(this.errors[i]);
35230
+ for (let i = 0; i < this.warnings.length; ++i)
35231
+ doc.warnings.push(this.warnings[i]);
35179
35232
  } else {
35180
35233
  doc.errors = this.errors;
35181
35234
  doc.warnings = this.warnings;
@@ -35908,7 +35961,7 @@ var require_lexer = __commonJS({
35908
35961
  const n = (yield* this.pushCount(1)) + (yield* this.pushSpaces(true));
35909
35962
  this.indentNext = this.indentValue + 1;
35910
35963
  this.indentValue += n;
35911
- return yield* this.parseBlockStart();
35964
+ return "block-start";
35912
35965
  }
35913
35966
  return "doc";
35914
35967
  }
@@ -36207,28 +36260,38 @@ var require_lexer = __commonJS({
36207
36260
  return 0;
36208
36261
  }
36209
36262
  *pushIndicators() {
36210
- switch (this.charAt(0)) {
36211
- case "!":
36212
- return (yield* this.pushTag()) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
36213
- case "&":
36214
- return (yield* this.pushUntil(isNotAnchorChar)) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
36215
- case "-":
36216
- // this is an error
36217
- case "?":
36218
- // this is an error outside flow collections
36219
- case ":": {
36220
- const inFlow = this.flowLevel > 0;
36221
- const ch1 = this.charAt(1);
36222
- if (isEmpty(ch1) || inFlow && flowIndicatorChars.has(ch1)) {
36223
- if (!inFlow)
36224
- this.indentNext = this.indentValue + 1;
36225
- else if (this.flowKey)
36226
- this.flowKey = false;
36227
- return (yield* this.pushCount(1)) + (yield* this.pushSpaces(true)) + (yield* this.pushIndicators());
36263
+ let n = 0;
36264
+ loop: while (true) {
36265
+ switch (this.charAt(0)) {
36266
+ case "!":
36267
+ n += yield* this.pushTag();
36268
+ n += yield* this.pushSpaces(true);
36269
+ continue loop;
36270
+ case "&":
36271
+ n += yield* this.pushUntil(isNotAnchorChar);
36272
+ n += yield* this.pushSpaces(true);
36273
+ continue loop;
36274
+ case "-":
36275
+ // this is an error
36276
+ case "?":
36277
+ // this is an error outside flow collections
36278
+ case ":": {
36279
+ const inFlow = this.flowLevel > 0;
36280
+ const ch1 = this.charAt(1);
36281
+ if (isEmpty(ch1) || inFlow && flowIndicatorChars.has(ch1)) {
36282
+ if (!inFlow)
36283
+ this.indentNext = this.indentValue + 1;
36284
+ else if (this.flowKey)
36285
+ this.flowKey = false;
36286
+ n += yield* this.pushCount(1);
36287
+ n += yield* this.pushSpaces(true);
36288
+ continue loop;
36289
+ }
36228
36290
  }
36229
36291
  }
36292
+ break loop;
36230
36293
  }
36231
- return 0;
36294
+ return n;
36232
36295
  }
36233
36296
  *pushTag() {
36234
36297
  if (this.charAt(1) === "<") {
@@ -36387,6 +36450,13 @@ var require_parser = __commonJS({
36387
36450
  }
36388
36451
  return prev.splice(i, prev.length);
36389
36452
  }
36453
+ function arrayPushArray(target, source) {
36454
+ if (source.length < 1e5)
36455
+ Array.prototype.push.apply(target, source);
36456
+ else
36457
+ for (let i = 0; i < source.length; ++i)
36458
+ target.push(source[i]);
36459
+ }
36390
36460
  function fixFlowSeqItems(fc) {
36391
36461
  if (fc.start.type === "flow-seq-start") {
36392
36462
  for (const it of fc.items) {
@@ -36396,11 +36466,11 @@ var require_parser = __commonJS({
36396
36466
  delete it.key;
36397
36467
  if (isFlowToken(it.value)) {
36398
36468
  if (it.value.end)
36399
- Array.prototype.push.apply(it.value.end, it.sep);
36469
+ arrayPushArray(it.value.end, it.sep);
36400
36470
  else
36401
36471
  it.value.end = it.sep;
36402
36472
  } else
36403
- Array.prototype.push.apply(it.start, it.sep);
36473
+ arrayPushArray(it.start, it.sep);
36404
36474
  delete it.sep;
36405
36475
  }
36406
36476
  }
@@ -36755,7 +36825,7 @@ var require_parser = __commonJS({
36755
36825
  const prev = map.items[map.items.length - 2];
36756
36826
  const end = prev?.value?.end;
36757
36827
  if (Array.isArray(end)) {
36758
- Array.prototype.push.apply(end, it.start);
36828
+ arrayPushArray(end, it.start);
36759
36829
  end.push(this.sourceToken);
36760
36830
  map.items.pop();
36761
36831
  return;
@@ -36943,7 +37013,7 @@ var require_parser = __commonJS({
36943
37013
  const prev = seq.items[seq.items.length - 2];
36944
37014
  const end = prev?.value?.end;
36945
37015
  if (Array.isArray(end)) {
36946
- Array.prototype.push.apply(end, it.start);
37016
+ arrayPushArray(end, it.start);
36947
37017
  end.push(this.sourceToken);
36948
37018
  seq.items.pop();
36949
37019
  return;
@@ -41478,6 +41548,9 @@ function zodTypeToJsonSchema(type) {
41478
41548
  if (type instanceof external_exports.ZodNumber) return { type: "number" };
41479
41549
  if (type instanceof external_exports.ZodBoolean) return { type: "boolean" };
41480
41550
  if (type instanceof external_exports.ZodOptional) return zodTypeToJsonSchema(type.unwrap());
41551
+ if (type instanceof external_exports.ZodDefault) {
41552
+ return { ...zodTypeToJsonSchema(type._def.innerType), default: type._def.defaultValue() };
41553
+ }
41481
41554
  if (type instanceof external_exports.ZodArray) {
41482
41555
  return { type: "array", items: zodTypeToJsonSchema(type.element) };
41483
41556
  }
@@ -41493,7 +41566,7 @@ function zodTypeToJsonSchema(type) {
41493
41566
  return {};
41494
41567
  }
41495
41568
  function isOptional(type) {
41496
- return type instanceof external_exports.ZodOptional;
41569
+ return type instanceof external_exports.ZodOptional || type instanceof external_exports.ZodDefault;
41497
41570
  }
41498
41571
 
41499
41572
  // ../registry/src/registry.ts
@@ -41948,7 +42021,7 @@ var import_node_https = __toESM(require("node:https"));
41948
42021
  var import_semver = __toESM(require_semver2());
41949
42022
 
41950
42023
  // ../tool-server/package.json
41951
- var version = "0.7.0";
42024
+ var version = "0.8.0";
41952
42025
 
41953
42026
  // ../tool-server/src/utils/update-checker.ts
41954
42027
  var PACKAGE_NAME = "@swmansion/argent";
@@ -42108,6 +42181,11 @@ var net = __toESM(require("node:net"));
42108
42181
  var fs2 = __toESM(require("node:fs"));
42109
42182
  var import_node_util3 = require("node:util");
42110
42183
  var import_node_child_process3 = require("node:child_process");
42184
+
42185
+ // ../tool-server/src/utils/simctl-config.ts
42186
+ var SIMCTL_SPAWN_TIMEOUT_MS = 1e4;
42187
+
42188
+ // ../tool-server/src/blueprints/ax-service.ts
42111
42189
  var execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
42112
42190
  var AX_SERVICE_NAMESPACE = "AXService";
42113
42191
  function axServiceRef(device) {
@@ -42162,17 +42240,21 @@ async function pingDaemon(socketPath) {
42162
42240
  }
42163
42241
  }
42164
42242
  async function ensureAutomationEnabled(udid) {
42165
- await execFileAsync3("xcrun", [
42166
- "simctl",
42167
- "spawn",
42168
- udid,
42169
- "defaults",
42170
- "write",
42171
- "com.apple.Accessibility",
42172
- "AutomationEnabled",
42173
- "-bool",
42174
- "true"
42175
- ]);
42243
+ await execFileAsync3(
42244
+ "xcrun",
42245
+ [
42246
+ "simctl",
42247
+ "spawn",
42248
+ udid,
42249
+ "defaults",
42250
+ "write",
42251
+ "com.apple.Accessibility",
42252
+ "AutomationEnabled",
42253
+ "-bool",
42254
+ "true"
42255
+ ],
42256
+ { timeout: SIMCTL_SPAWN_TIMEOUT_MS }
42257
+ );
42176
42258
  }
42177
42259
  async function killExistingDaemon(socketPath) {
42178
42260
  try {
@@ -42738,6 +42820,10 @@ function sortAndroid(a, b) {
42738
42820
  const bEmu = b.isEmulator ? 0 : 1;
42739
42821
  return aEmu - bEmu;
42740
42822
  }
42823
+ function readinessRank(d) {
42824
+ if (d.platform === "ios") return d.state === "Booted" ? 0 : 1;
42825
+ return d.state === "device" ? 0 : 1;
42826
+ }
42741
42827
  var zodSchema = external_exports.object({});
42742
42828
  var listDevicesTool = {
42743
42829
  id: "list-devices",
@@ -42767,7 +42853,9 @@ Booted/ready devices are listed first. Platforms whose CLI is unavailable are si
42767
42853
  sdkLevel: d.sdkLevel
42768
42854
  }));
42769
42855
  androidTagged.sort(sortAndroid);
42770
- return { devices: [...iosTagged, ...androidTagged], avds };
42856
+ const devices = [...iosTagged, ...androidTagged];
42857
+ devices.sort((a, b) => readinessRank(a) - readinessRank(b));
42858
+ return { devices, avds };
42771
42859
  }
42772
42860
  };
42773
42861
 
@@ -42937,6 +43025,7 @@ function createHttpApp(registry, options) {
42937
43025
  if (def?.outputHint) entry.outputHint = def.outputHint;
42938
43026
  if (def?.alwaysLoad) entry.alwaysLoad = true;
42939
43027
  if (def?.searchHint) entry.searchHint = def.searchHint;
43028
+ if (def?.longRunning) entry.longRunning = true;
42940
43029
  return entry;
42941
43030
  });
42942
43031
  res.json({ tools });
@@ -43054,6 +43143,36 @@ var import_node_child_process7 = require("node:child_process");
43054
43143
  var import_node_util6 = require("node:util");
43055
43144
  var execFileAsync6 = (0, import_node_util6.promisify)(import_node_child_process7.execFile);
43056
43145
  var NATIVE_DEVTOOLS_NAMESPACE = "NativeDevtools";
43146
+ var MAX_NATIVE_DEVTOOLS_INIT_ATTEMPTS = 3;
43147
+ function buildInitFailedResult(udid, failure) {
43148
+ return {
43149
+ status: "init_failed",
43150
+ message: `Native devtools failed to initialize for ${udid} after ${failure.attempts} attempts. Last error: ${failure.lastError}. Try shutting down and re-booting the simulator, or restart CoreSimulatorService.`,
43151
+ attempts: failure.attempts
43152
+ };
43153
+ }
43154
+ async function precheckNativeDevtools(api, udid, bundleId) {
43155
+ const existing = api.getInitFailure();
43156
+ if (existing?.givenUp) return buildInitFailedResult(udid, existing);
43157
+ try {
43158
+ await api.ensureEnvReady();
43159
+ } catch {
43160
+ const failure = api.getInitFailure();
43161
+ if (failure) return buildInitFailedResult(udid, failure);
43162
+ return buildInitFailedResult(udid, {
43163
+ attempts: 1,
43164
+ lastError: "ensureEnvReady threw without recording state",
43165
+ givenUp: false
43166
+ });
43167
+ }
43168
+ if (bundleId !== void 0 && await api.requiresAppRestart(bundleId)) {
43169
+ return {
43170
+ status: "restart_required",
43171
+ message: "Native devtools are not injected into the running app. Call restart-app then retry."
43172
+ };
43173
+ }
43174
+ return null;
43175
+ }
43057
43176
  function nativeDevtoolsRef(device) {
43058
43177
  return {
43059
43178
  urn: `${NATIVE_DEVTOOLS_NAMESPACE}:${device.id}`,
@@ -43092,17 +43211,21 @@ async function ensureAccessibilityEnabled(udid) {
43092
43211
  const flags = ["AccessibilityEnabled", "ApplicationAccessibilityEnabled"];
43093
43212
  await Promise.all(
43094
43213
  flags.map(
43095
- (flag) => execFileAsync6("xcrun", [
43096
- "simctl",
43097
- "spawn",
43098
- udid,
43099
- "defaults",
43100
- "write",
43101
- "com.apple.Accessibility",
43102
- flag,
43103
- "-bool",
43104
- "true"
43105
- ])
43214
+ (flag) => execFileAsync6(
43215
+ "xcrun",
43216
+ [
43217
+ "simctl",
43218
+ "spawn",
43219
+ udid,
43220
+ "defaults",
43221
+ "write",
43222
+ "com.apple.Accessibility",
43223
+ flag,
43224
+ "-bool",
43225
+ "true"
43226
+ ],
43227
+ { timeout: SIMCTL_SPAWN_TIMEOUT_MS }
43228
+ )
43106
43229
  )
43107
43230
  );
43108
43231
  }
@@ -43111,30 +43234,22 @@ async function ensureEnv(udid, socketPath) {
43111
43234
  const result = await execFileAsync6(
43112
43235
  "xcrun",
43113
43236
  ["simctl", "spawn", udid, "launchctl", "getenv", "DYLD_INSERT_LIBRARIES"],
43114
- { encoding: "utf8" }
43237
+ { encoding: "utf8", timeout: SIMCTL_SPAWN_TIMEOUT_MS }
43115
43238
  ).catch((e) => ({ stdout: e.stdout ?? "" }));
43116
43239
  const existing = (result.stdout ?? "").trim();
43117
43240
  const updated = buildDyldInsertLibraries(existing, bootstrapPath);
43118
43241
  if (updated !== existing) {
43119
- await execFileAsync6("xcrun", [
43120
- "simctl",
43121
- "spawn",
43122
- udid,
43123
- "launchctl",
43124
- "setenv",
43125
- "DYLD_INSERT_LIBRARIES",
43126
- updated
43127
- ]);
43242
+ await execFileAsync6(
43243
+ "xcrun",
43244
+ ["simctl", "spawn", udid, "launchctl", "setenv", "DYLD_INSERT_LIBRARIES", updated],
43245
+ { timeout: SIMCTL_SPAWN_TIMEOUT_MS }
43246
+ );
43128
43247
  }
43129
- await execFileAsync6("xcrun", [
43130
- "simctl",
43131
- "spawn",
43132
- udid,
43133
- "launchctl",
43134
- "setenv",
43135
- "NATIVE_DEVTOOLS_IOS_CDP_SOCKET",
43136
- socketPath
43137
- ]);
43248
+ await execFileAsync6(
43249
+ "xcrun",
43250
+ ["simctl", "spawn", udid, "launchctl", "setenv", "NATIVE_DEVTOOLS_IOS_CDP_SOCKET", socketPath],
43251
+ { timeout: SIMCTL_SPAWN_TIMEOUT_MS }
43252
+ );
43138
43253
  await ensureAccessibilityEnabled(udid);
43139
43254
  }
43140
43255
  async function listRunningUIKitApplicationBundleIds(udid) {
@@ -43175,11 +43290,33 @@ var nativeDevtoolsBlueprint = {
43175
43290
  const pendingRpc = /* @__PURE__ */ new Map();
43176
43291
  let nextRpcId = 1;
43177
43292
  let envSetup = false;
43293
+ let initFailure = null;
43294
+ let inFlight = null;
43178
43295
  const activatedBundleIds = /* @__PURE__ */ new Set();
43179
43296
  const events = new TypedEventEmitter();
43180
- const ensureEnvReady = async () => {
43181
- await ensureEnv(udid, socketPath);
43182
- envSetup = true;
43297
+ const noteInitFailure = (err) => {
43298
+ const lastError = err instanceof Error ? err.message : String(err);
43299
+ const attempts = (initFailure?.attempts ?? 0) + 1;
43300
+ const givenUp = attempts >= MAX_NATIVE_DEVTOOLS_INIT_ATTEMPTS;
43301
+ initFailure = { attempts, lastError, givenUp };
43302
+ const message = givenUp ? `[native-devtools] giving up on ${udid} after ${attempts} attempts: ${lastError}
43303
+ ` : `[native-devtools] init attempt ${attempts}/${MAX_NATIVE_DEVTOOLS_INIT_ATTEMPTS} failed for ${udid}: ${lastError}
43304
+ `;
43305
+ process.stderr.write(message);
43306
+ };
43307
+ const ensureEnvReady = () => {
43308
+ if (envSetup || initFailure?.givenUp) return Promise.resolve();
43309
+ if (inFlight) return inFlight;
43310
+ inFlight = Promise.resolve().then(() => ensureEnv(udid, socketPath)).then(() => {
43311
+ envSetup = true;
43312
+ initFailure = null;
43313
+ }).catch((err) => {
43314
+ noteInitFailure(err);
43315
+ throw err;
43316
+ }).finally(() => {
43317
+ inFlight = null;
43318
+ });
43319
+ return inFlight;
43183
43320
  };
43184
43321
  const isAppRunning = async (bundleId) => {
43185
43322
  const runningBundleIds = await listRunningUIKitApplicationBundleIds(udid);
@@ -43278,11 +43415,13 @@ var nativeDevtoolsBlueprint = {
43278
43415
  });
43279
43416
  });
43280
43417
  server.listen(socketPath);
43281
- await ensureEnvReady();
43418
+ await ensureEnvReady().catch(() => {
43419
+ });
43282
43420
  const api = {
43283
43421
  isEnvSetup: () => envSetup,
43284
43422
  socketPath,
43285
43423
  ensureEnvReady,
43424
+ getInitFailure: () => initFailure,
43286
43425
  isConnected: (bundleId) => connections2.has(bundleId),
43287
43426
  isAppRunning,
43288
43427
  listConnectedBundleIds: () => [...connections2.keys()],
@@ -43403,7 +43542,8 @@ Fails if the simulator server is not running for the given UDID or the bundleId
43403
43542
  }),
43404
43543
  async execute(services, params) {
43405
43544
  const api = services.nativeDevtools;
43406
- await api.ensureEnvReady();
43545
+ const blocked = await precheckNativeDevtools(api, params.udid);
43546
+ if (blocked) return blocked;
43407
43547
  const appRunning = await api.isAppRunning(params.bundleId);
43408
43548
  const connected = api.isConnected(params.bundleId);
43409
43549
  const envSetup = api.isEnvSetup();
@@ -43439,12 +43579,8 @@ Fails if native devtools are not connected or the app is not running.`,
43439
43579
  }),
43440
43580
  async execute(services, params) {
43441
43581
  const api = services.nativeDevtools;
43442
- if (await api.requiresAppRestart(params.bundleId)) {
43443
- return {
43444
- status: "restart_required",
43445
- message: "Native devtools are not injected into the running app. Call restart-app then retry."
43446
- };
43447
- }
43582
+ const blocked = await precheckNativeDevtools(api, params.udid, params.bundleId);
43583
+ if (blocked) return blocked;
43448
43584
  api.activateNetworkInspection(params.bundleId);
43449
43585
  const events = api.getNetworkLog(params.bundleId).slice(-params.limit);
43450
43586
  if (params.clear) api.clearNetworkLog(params.bundleId);
@@ -43482,12 +43618,8 @@ Fails if native devtools are not connected, the app is not running, or status is
43482
43618
  }),
43483
43619
  async execute(services, params) {
43484
43620
  const api = services.nativeDevtools;
43485
- if (await api.requiresAppRestart(params.bundleId)) {
43486
- return {
43487
- status: "restart_required",
43488
- message: "Native devtools are not injected into the running app. Call restart-app then retry."
43489
- };
43490
- }
43621
+ const blocked = await precheckNativeDevtools(api, params.udid, params.bundleId);
43622
+ if (blocked) return blocked;
43491
43623
  const rpcParams = {};
43492
43624
  if (params.className !== void 0) rpcParams.className = params.className;
43493
43625
  if (params.identifier !== void 0) rpcParams.identifier = params.identifier;
@@ -43542,12 +43674,8 @@ Fails if native devtools are not connected or the app is not running.`,
43542
43674
  }),
43543
43675
  async execute(services, params) {
43544
43676
  const api = services.nativeDevtools;
43545
- if (await api.requiresAppRestart(params.bundleId)) {
43546
- return {
43547
- status: "restart_required",
43548
- message: "Native devtools are not injected into the running app. Call restart-app then retry."
43549
- };
43550
- }
43677
+ const blocked = await precheckNativeDevtools(api, params.udid, params.bundleId);
43678
+ if (blocked) return blocked;
43551
43679
  const rpcParams = {};
43552
43680
  if (params.fields !== void 0) rpcParams.fields = params.fields;
43553
43681
  if (params.skipClasses !== void 0) rpcParams.skipClasses = params.skipClasses;
@@ -43629,12 +43757,8 @@ If status is restart_required: call restart-app then retry.`,
43629
43757
  }),
43630
43758
  async execute(services, params) {
43631
43759
  const api = services.nativeDevtools;
43632
- if (await api.requiresAppRestart(params.bundleId)) {
43633
- return {
43634
- status: "restart_required",
43635
- message: "Native devtools are not injected into the running app. Call restart-app then retry."
43636
- };
43637
- }
43760
+ const blocked = await precheckNativeDevtools(api, params.udid, params.bundleId);
43761
+ if (blocked) return blocked;
43638
43762
  const rpcParams = {};
43639
43763
  if (params.skipClasses !== void 0) rpcParams.skipClasses = params.skipClasses;
43640
43764
  if (params.skipClassPrefixes !== void 0)
@@ -43690,12 +43814,8 @@ If status is restart_required: call restart-app then retry.`,
43690
43814
  }),
43691
43815
  async execute(services, params) {
43692
43816
  const api = services.nativeDevtools;
43693
- if (await api.requiresAppRestart(params.bundleId)) {
43694
- return {
43695
- status: "restart_required",
43696
- message: "Native devtools are not injected into the running app. Call restart-app then retry."
43697
- };
43698
- }
43817
+ const blocked = await precheckNativeDevtools(api, params.udid, params.bundleId);
43818
+ if (blocked) return blocked;
43699
43819
  const rpcParams = {
43700
43820
  x: params.x,
43701
43821
  y: params.y
@@ -43757,12 +43877,8 @@ If status is restart_required: call restart-app then retry.`,
43757
43877
  }),
43758
43878
  async execute(services, params) {
43759
43879
  const api = services.nativeDevtools;
43760
- if (await api.requiresAppRestart(params.bundleId)) {
43761
- return {
43762
- status: "restart_required",
43763
- message: "Native devtools are not injected into the running app. Call restart-app then retry."
43764
- };
43765
- }
43880
+ const blocked = await precheckNativeDevtools(api, params.udid, params.bundleId);
43881
+ if (blocked) return blocked;
43766
43882
  const rpcParams = {
43767
43883
  x: params.x,
43768
43884
  y: params.y
@@ -44930,6 +45046,136 @@ var REACT_NATIVE_PROFILER_SETUP_SCRIPT = `
44930
45046
  });
44931
45047
  })();
44932
45048
  `;
45049
+ var BOOTSTRAP_DEVTOOLS_BACKEND_SCRIPT = `
45050
+ (function __argent_bootstrapDevtoolsBackend() {
45051
+ var h = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
45052
+ if (!h) return JSON.stringify({ ok: false, reason: 'no-hook' });
45053
+
45054
+ function sizeOf(m) {
45055
+ if (!m || typeof m.forEach !== 'function') return 0;
45056
+ var n = 0;
45057
+ m.forEach(function () { n++; });
45058
+ return n;
45059
+ }
45060
+
45061
+ var renderersCount = sizeOf(h.renderers);
45062
+ var rendererInterfacesCount = sizeOf(h.rendererInterfaces);
45063
+
45064
+ if (rendererInterfacesCount > 0) {
45065
+ return JSON.stringify({
45066
+ ok: true,
45067
+ reason: 'already-attached',
45068
+ renderersCount: renderersCount,
45069
+ rendererInterfacesCount: rendererInterfacesCount,
45070
+ });
45071
+ }
45072
+
45073
+ if (renderersCount === 0) {
45074
+ return JSON.stringify({
45075
+ ok: false,
45076
+ reason: 'no-renderers',
45077
+ renderersCount: renderersCount,
45078
+ rendererInterfacesCount: rendererInterfacesCount,
45079
+ });
45080
+ }
45081
+
45082
+ if (typeof globalThis.__r !== 'function' || typeof globalThis.__r.getModules !== 'function') {
45083
+ return JSON.stringify({
45084
+ ok: false,
45085
+ reason: 'no-metro-modules',
45086
+ renderersCount: renderersCount,
45087
+ rendererInterfacesCount: rendererInterfacesCount,
45088
+ });
45089
+ }
45090
+
45091
+ var found = null;
45092
+ var moduleSeenButUnsupported = false;
45093
+ try {
45094
+ var mods = globalThis.__r.getModules();
45095
+ var inspect = function (id, meta) {
45096
+ if (found) return;
45097
+ var name = meta && meta.verboseName;
45098
+ if (typeof name !== 'string') return;
45099
+ if (name.indexOf('react-devtools-core/dist/backend') < 0) return;
45100
+ try {
45101
+ var m = globalThis.__r(id);
45102
+ if (!m) return;
45103
+ if (typeof m.connectWithCustomMessagingProtocol === 'function') {
45104
+ found = m;
45105
+ } else {
45106
+ // Module exists but exposes only legacy WebSocket-based connectToDevTools
45107
+ // (rdt-core <5.1). We can't bootstrap without a real ws endpoint, so the
45108
+ // user has to attach an external backend (\`npx react-devtools\` + reload).
45109
+ moduleSeenButUnsupported = true;
45110
+ }
45111
+ } catch (_e) {
45112
+ // require failure on this id \u2014 keep searching.
45113
+ }
45114
+ };
45115
+ // Metro's getModules() returns a Map<id, meta> in modern versions.
45116
+ // Map#forEach calls back as (value, key); array-like fallback handled below.
45117
+ if (typeof mods.forEach === 'function' && typeof mods.size === 'number') {
45118
+ mods.forEach(function (meta, id) { inspect(id, meta); });
45119
+ } else if (typeof mods.length === 'number') {
45120
+ for (var i = 0; i < mods.length; i++) {
45121
+ if (mods[i]) inspect(i, mods[i]);
45122
+ }
45123
+ } else if (typeof mods.forEach === 'function') {
45124
+ mods.forEach(function (meta, id) { inspect(id, meta); });
45125
+ }
45126
+ } catch (err) {
45127
+ return JSON.stringify({
45128
+ ok: false,
45129
+ reason: 'metro-scan-error',
45130
+ message: String((err && err.message) || err),
45131
+ renderersCount: renderersCount,
45132
+ rendererInterfacesCount: rendererInterfacesCount,
45133
+ });
45134
+ }
45135
+
45136
+ if (!found) {
45137
+ return JSON.stringify({
45138
+ ok: false,
45139
+ reason: moduleSeenButUnsupported ? 'unsupported-rdt-version' : 'no-rdt-module',
45140
+ renderersCount: renderersCount,
45141
+ rendererInterfacesCount: rendererInterfacesCount,
45142
+ });
45143
+ }
45144
+
45145
+ try {
45146
+ found.connectWithCustomMessagingProtocol({
45147
+ onSubscribe: function () {},
45148
+ onUnsubscribe: function () {},
45149
+ onMessage: function () {},
45150
+ });
45151
+ } catch (err) {
45152
+ return JSON.stringify({
45153
+ ok: false,
45154
+ reason: 'bootstrap-threw',
45155
+ message: String((err && err.message) || err),
45156
+ renderersCount: renderersCount,
45157
+ rendererInterfacesCount: rendererInterfacesCount,
45158
+ });
45159
+ }
45160
+
45161
+ var afterCount = sizeOf(h.rendererInterfaces);
45162
+ if (afterCount === 0) {
45163
+ return JSON.stringify({
45164
+ ok: false,
45165
+ reason: 'bootstrap-no-effect',
45166
+ renderersCount: renderersCount,
45167
+ rendererInterfacesCount: rendererInterfacesCount,
45168
+ });
45169
+ }
45170
+
45171
+ return JSON.stringify({
45172
+ ok: true,
45173
+ reason: 'bootstrapped',
45174
+ renderersCount: renderersCount,
45175
+ rendererInterfacesCount: afterCount,
45176
+ });
45177
+ })()
45178
+ `;
44933
45179
  var HEARTBEAT_SCRIPT = `
44934
45180
  (function(){
44935
45181
  if (typeof globalThis.__argent_profilerHeartbeat === 'function') {
@@ -45420,7 +45666,11 @@ async function bootIos(udid, registry) {
45420
45666
  });
45421
45667
  await execFileAsync7("xcrun", ["simctl", "bootstatus", udid, "-b"]);
45422
45668
  const ndRef = nativeDevtoolsRef({ id: udid, platform: "ios", kind: "simulator" });
45423
- await registry.resolveService(ndRef.urn, ndRef.options);
45669
+ const ndApi = await registry.resolveService(ndRef.urn, ndRef.options);
45670
+ const initFailure = ndApi.getInitFailure();
45671
+ if (initFailure?.givenUp) {
45672
+ return buildInitFailedResult(udid, initFailure);
45673
+ }
45424
45674
  await execFileAsync7("defaults", [
45425
45675
  "write",
45426
45676
  "com.apple.iphonesimulator",
@@ -45748,7 +45998,8 @@ var execFileAsync8 = (0, import_node_util8.promisify)(import_node_child_process9
45748
45998
  var iosImpl = {
45749
45999
  requires: ["xcrun"],
45750
46000
  handler: async (services, params) => {
45751
- await services.nativeDevtools.ensureEnvReady();
46001
+ const blocked = await precheckNativeDevtools(services.nativeDevtools, params.udid);
46002
+ if (blocked) return blocked;
45752
46003
  await execFileAsync8("xcrun", ["simctl", "launch", params.udid, params.bundleId]);
45753
46004
  return { launched: true, bundleId: params.bundleId };
45754
46005
  }
@@ -45848,7 +46099,8 @@ var iosImpl2 = {
45848
46099
  requires: ["xcrun"],
45849
46100
  handler: async (services, params) => {
45850
46101
  const { udid, bundleId } = params;
45851
- await services.nativeDevtools.ensureEnvReady();
46102
+ const blocked = await precheckNativeDevtools(services.nativeDevtools, udid);
46103
+ if (blocked) return blocked;
45852
46104
  try {
45853
46105
  await execFileAsync9("xcrun", ["simctl", "terminate", udid, bundleId]);
45854
46106
  } catch {
@@ -46255,7 +46507,6 @@ Use when you need to scroll a list, dismiss a modal, or navigate between pages.
46255
46507
  };
46256
46508
 
46257
46509
  // ../tool-server/src/utils/gesture-utils.ts
46258
- var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
46259
46510
  function lerp(a, b, t) {
46260
46511
  return a + (b - a) * t;
46261
46512
  }
@@ -46303,7 +46554,7 @@ function sendTouchEvent(api, type, x, y, x2, y2) {
46303
46554
  }
46304
46555
 
46305
46556
  // ../tool-server/src/tools/gesture-custom/index.ts
46306
- var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
46557
+ var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
46307
46558
  var eventSchema = external_exports.object({
46308
46559
  type: external_exports.enum(["Down", "Move", "Up"]).describe("Touch event type"),
46309
46560
  x: external_exports.number().describe("Normalized x 0.0\u20131.0 (not pixels; same as tap/swipe)"),
@@ -46356,7 +46607,7 @@ Example pinch-to-zoom (with interpolate:10 for smoothness):
46356
46607
  const api = services.simulatorServer;
46357
46608
  const events = params.interpolate && params.interpolate > 0 ? interpolateEvents(params.events, params.interpolate) : params.events;
46358
46609
  for (const event of events) {
46359
- await sleep4(event.delayMs ?? 16);
46610
+ await sleep3(event.delayMs ?? 16);
46360
46611
  sendCommand(api, {
46361
46612
  cmd: "touch",
46362
46613
  type: event.type,
@@ -46370,6 +46621,10 @@ Example pinch-to-zoom (with interpolate:10 for smoothness):
46370
46621
  }
46371
46622
  };
46372
46623
 
46624
+ // ../tool-server/src/utils/timing.ts
46625
+ var sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
46626
+ var DEFAULT_INTER_STEP_DELAY_MS = 100;
46627
+
46373
46628
  // ../tool-server/src/tools/gesture-pinch/index.ts
46374
46629
  var zodSchema18 = external_exports.object({
46375
46630
  udid: external_exports.string().describe("Target device id from `list-devices` (iOS UDID or Android serial)."),
@@ -46424,7 +46679,7 @@ Use when you need to zoom in or out on a map, image, or zoomable view. Returns {
46424
46679
  const type = i === 0 ? "Down" : i === steps ? "Up" : "Move";
46425
46680
  if (i === 0) timestampMs = Date.now();
46426
46681
  sendTouchEvent(api, type, x1, y1, x2, y2);
46427
- if (i < steps) await sleep3(16);
46682
+ if (i < steps) await sleep4(16);
46428
46683
  }
46429
46684
  return { pinched: true, timestampMs };
46430
46685
  }
@@ -46478,7 +46733,7 @@ Use when you need to rotate a map, image picker, or any rotateable UI element. R
46478
46733
  const type = i === 0 ? "Down" : i === steps ? "Up" : "Move";
46479
46734
  if (i === 0) timestampMs = Date.now();
46480
46735
  sendTouchEvent(api, type, x1, y1, x2, y2);
46481
- if (i < steps) await sleep3(16);
46736
+ if (i < steps) await sleep4(16);
46482
46737
  }
46483
46738
  return { rotated: true, timestampMs };
46484
46739
  }
@@ -46700,7 +46955,6 @@ Returns { orientation }. Fails if the target device is not booted.`,
46700
46955
  };
46701
46956
 
46702
46957
  // ../tool-server/src/tools/run-sequence/index.ts
46703
- var sleep7 = (ms) => new Promise((r) => setTimeout(r, ms));
46704
46958
  var ALLOWED_TOOLS = /* @__PURE__ */ new Set([
46705
46959
  "gesture-tap",
46706
46960
  "gesture-swipe",
@@ -46721,7 +46975,9 @@ var zodSchema23 = external_exports.object({
46721
46975
  "Tool name \u2014 one of: gesture-tap, gesture-swipe, gesture-custom, gesture-pinch, gesture-rotate, button, keyboard, rotate"
46722
46976
  ),
46723
46977
  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)")
46978
+ delayMs: external_exports.number().optional().describe(
46979
+ `Wait time in ms after this step before the next (default ${DEFAULT_INTER_STEP_DELAY_MS})`
46980
+ )
46725
46981
  })
46726
46982
  ).min(1).describe("Ordered list of interaction steps to execute sequentially")
46727
46983
  });
@@ -46768,6 +47024,7 @@ Example \u2014 type text and submit:
46768
47024
 
46769
47025
  Stops on the first error and returns partial results.`,
46770
47026
  alwaysLoad: true,
47027
+ longRunning: true,
46771
47028
  searchHint: "batch sequence multiple gesture steps sequentially",
46772
47029
  zodSchema: zodSchema23,
46773
47030
  capability: capability15,
@@ -46796,8 +47053,8 @@ Stops on the first error and returns partial results.`,
46796
47053
  });
46797
47054
  break;
46798
47055
  }
46799
- const delay = step.delayMs ?? 100;
46800
- if (delay > 0) await sleep7(delay);
47056
+ const delay = step.delayMs ?? DEFAULT_INTER_STEP_DELAY_MS;
47057
+ if (delay > 0) await sleep4(delay);
46801
47058
  }
46802
47059
  return {
46803
47060
  completed: results.filter((r) => "result" in r).length,
@@ -47513,7 +47770,7 @@ function buildTextTree(data, opts) {
47513
47770
  lines.push(`Screen: ${screenW}x${screenH}`);
47514
47771
  lines.push("");
47515
47772
  }
47516
- function formatLabel(c) {
47773
+ function formatLabel2(c) {
47517
47774
  let label = c.name;
47518
47775
  const displayText = c.text ?? c.accLabel;
47519
47776
  if (displayText) label += ` "${displayText}"`;
@@ -47535,12 +47792,12 @@ function buildTextTree(data, opts) {
47535
47792
  cur = childrenOf.get(cur)[0];
47536
47793
  }
47537
47794
  const indent = " ".repeat(depth);
47538
- lines.push(`${indent}${formatLabel(c)}`);
47795
+ lines.push(`${indent}${formatLabel2(c)}`);
47539
47796
  lines.push(`${indent} ... via ${chainLen} wrapper${chainLen > 1 ? "s" : ""}`);
47540
47797
  renderNode(cur, depth + 1);
47541
47798
  return;
47542
47799
  }
47543
- lines.push(" ".repeat(depth) + formatLabel(c));
47800
+ lines.push(" ".repeat(depth) + formatLabel2(c));
47544
47801
  const children = childrenOf.get(id);
47545
47802
  if (children) {
47546
47803
  let prevSibling = null;
@@ -48162,7 +48419,7 @@ function formatEntry(entry) {
48162
48419
  }
48163
48420
  var zodSchema31 = external_exports.object({
48164
48421
  port: external_exports.coerce.number().default(8081).describe("Metro server port"),
48165
- device_id: external_exports.string().describe("iOS Simulator UDID (logicalDeviceId)."),
48422
+ device_id: external_exports.string().describe("Device UDID (logicalDeviceId)."),
48166
48423
  pageIndex: external_exports.union([external_exports.coerce.number().int().nonnegative(), external_exports.literal("latest")]).default("latest").describe(
48167
48424
  'Page index (0-based) or "latest" for the most recent page. Each page contains up to 50 entries.'
48168
48425
  )
@@ -48236,7 +48493,7 @@ function redactHeaders(headers) {
48236
48493
  var MAX_BODY_SIZE = 1e3;
48237
48494
  var zodSchema32 = external_exports.object({
48238
48495
  port: external_exports.coerce.number().default(8081).describe("Metro server port"),
48239
- device_id: external_exports.string().describe("iOS Simulator UDID (logicalDeviceId)."),
48496
+ device_id: external_exports.string().describe("Device UDID (logicalDeviceId)."),
48240
48497
  requestId: external_exports.string().describe("The requestId from view-network-logs to get full details for"),
48241
48498
  includeBody: external_exports.coerce.boolean().default(true).describe("Whether to include the response body (if captured). Defaults to true.")
48242
48499
  });
@@ -48943,7 +49200,116 @@ async function describeIos(registry, device, params) {
48943
49200
  }
48944
49201
  }
48945
49202
 
49203
+ // ../tool-server/src/tools/describe/format-tree.ts
49204
+ var CONTENT_ROLES = /* @__PURE__ */ new Set([
49205
+ // iOS AX traits surfaced by mapNativeTraitsToDescribeRole. AXGroup is
49206
+ // deliberately excluded: it's the catch-all wrapper, so requiring it to
49207
+ // carry its own label/value before we emit a line keeps decorative
49208
+ // groupings out of the output.
49209
+ "AXButton",
49210
+ "AXStaticText",
49211
+ "AXImage",
49212
+ "AXLink",
49213
+ "AXTextField",
49214
+ "AXHeading",
49215
+ "AXTabBar",
49216
+ "AXAdjustable"
49217
+ ]);
49218
+ function clampFinite(n) {
49219
+ return Number.isFinite(n) ? n : 0;
49220
+ }
49221
+ function fmtFrame(f) {
49222
+ return `(${clampFinite(f.x).toFixed(3)}, ${clampFinite(f.y).toFixed(3)}, ${clampFinite(
49223
+ f.width
49224
+ ).toFixed(3)}, ${clampFinite(f.height).toFixed(3)})`;
49225
+ }
49226
+ function escapeForLine(s) {
49227
+ return s.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
49228
+ }
49229
+ function formatLabel(label) {
49230
+ if (!label) return "";
49231
+ return `"${escapeForLine(label)}"`;
49232
+ }
49233
+ function formatAttr(name, value) {
49234
+ if (!value) return "";
49235
+ return ` ${name}="${escapeForLine(value)}"`;
49236
+ }
49237
+ function formatFlags(n) {
49238
+ const flags = [];
49239
+ if (n.clickable) flags.push("clickable");
49240
+ if (n.longClickable) flags.push("long-clickable");
49241
+ if (n.scrollable) flags.push("scrollable");
49242
+ if (n.checkable) flags.push(n.checked ? "checked" : "checkable");
49243
+ if (n.disabled) flags.push("disabled");
49244
+ if (n.password) flags.push("password");
49245
+ if (typeof n.scrollHidden === "number" && n.scrollHidden > 0) {
49246
+ flags.push(`scrollHidden=${n.scrollHidden}`);
49247
+ }
49248
+ return flags.length === 0 ? "" : ` [${flags.join(",")}]`;
49249
+ }
49250
+ function hasContent(n) {
49251
+ return Boolean(
49252
+ n.label || n.value || n.identifier || n.clickable || n.longClickable || n.scrollable || n.checkable || typeof n.scrollHidden === "number" && n.scrollHidden > 0
49253
+ );
49254
+ }
49255
+ function shouldEmit(n) {
49256
+ return hasContent(n) || CONTENT_ROLES.has(n.role);
49257
+ }
49258
+ function formatLine(n, indent) {
49259
+ const pad = " ".repeat(indent);
49260
+ const dedupedValue = n.value && n.value !== n.label ? n.value : void 0;
49261
+ const labelPart = formatLabel(n.label);
49262
+ const valuePart = formatAttr("value", dedupedValue);
49263
+ const idPart = formatAttr("id", n.identifier);
49264
+ const flagPart = formatFlags(n);
49265
+ const annotations = `${labelPart}${valuePart}${idPart}${flagPart}`.trim();
49266
+ const annotated = annotations ? ` ${annotations}` : "";
49267
+ return `${pad}${n.role}${annotated} ${fmtFrame(n.frame)}`;
49268
+ }
49269
+ function renderFlat(root) {
49270
+ return root.children.filter(shouldEmit).slice().sort((a, b) => a.frame.y - b.frame.y || a.frame.x - b.frame.x).map((n) => formatLine(n, 1));
49271
+ }
49272
+ function renderNested(root) {
49273
+ const lines = [];
49274
+ const stack = [];
49275
+ for (let i = root.children.length - 1; i >= 0; i--) {
49276
+ stack.push({ node: root.children[i], depth: 1 });
49277
+ }
49278
+ while (stack.length > 0) {
49279
+ const { node, depth } = stack.pop();
49280
+ if (shouldEmit(node) || node.children.length > 0) {
49281
+ lines.push(formatLine(node, depth));
49282
+ }
49283
+ for (let i = node.children.length - 1; i >= 0; i--) {
49284
+ stack.push({ node: node.children[i], depth: depth + 1 });
49285
+ }
49286
+ }
49287
+ return lines;
49288
+ }
49289
+ function formatDescribeTree(root, opts) {
49290
+ const mode = opts.source === "uiautomator" ? "nested" : "flat";
49291
+ const header = [];
49292
+ header.push(`Source: ${opts.source}`);
49293
+ header.push(`Mode: ${mode}`);
49294
+ header.push(
49295
+ "Coordinates are normalized [0,1] fractions of the screen (x, y, width, height), not pixels \u2014 pass them straight to gesture-tap / gesture-swipe / gesture-pinch, which expect this same space. To tap an element, use its centre: tap_x = frame.x + frame.width / 2, tap_y = frame.y + frame.height / 2."
49296
+ );
49297
+ header.push("");
49298
+ header.push(`ROOT ${root.role} ${fmtFrame(root.frame)}`);
49299
+ header.push("");
49300
+ const body = mode === "flat" ? renderFlat(root) : renderNested(root);
49301
+ return [...header, ...body].join("\n").replace(/\n+$/, "\n");
49302
+ }
49303
+
48946
49304
  // ../tool-server/src/tools/describe/index.ts
49305
+ function withDescription(data) {
49306
+ const out = {
49307
+ description: formatDescribeTree(data.tree, { source: data.source }),
49308
+ source: data.source
49309
+ };
49310
+ if (data.should_restart) out.should_restart = data.should_restart;
49311
+ return out;
49312
+ }
48947
49313
  var zodSchema33 = external_exports.object({
48948
49314
  udid: external_exports.string().min(1).describe("Target device id from `list-devices` (iOS UDID or Android serial)."),
48949
49315
  bundleId: external_exports.string().optional().describe(
@@ -48964,11 +49330,14 @@ system dialogs, permission prompts, and any foreground app content. On Android,
48964
49330
  When a system dialog is visible, describe returns the dialog's interactive elements (buttons, text)
48965
49331
  with tap coordinates. When no dialog is present, it returns the foreground app's accessible elements.
48966
49332
 
48967
- Returns a JSON tree of UI elements with roles, labels, values, and frame coordinates in normalized
48968
- [0,1] space (fractions of the screen, not pixels) \u2014 the same coordinate space as tap/swipe/gesture
48969
- and simulator-server touch input.
49333
+ Returns \`{ description, source }\` where \`description\` is a text rendering of the UI tree \u2014 one
49334
+ line per element with its role, label/value/id, interactivity flags, and frame. Frame coordinates
49335
+ are normalized [0,1] fractions of the screen width/height (not pixels) \u2014 the same space as
49336
+ gesture-tap / gesture-swipe / gesture-pinch.
48970
49337
 
48971
- Use frame.x + frame.width/2 as the tap X coordinate, frame.y + frame.height/2 as tap Y.
49338
+ To tap an element use the centre of its frame: \`tap_x = frame.x + frame.width / 2\`,
49339
+ \`tap_y = frame.y + frame.height / 2\`. The same formula appears in the response header so it
49340
+ can be applied to a line in isolation.
48972
49341
 
48973
49342
  For app-scoped inspection with full UIKit properties (accessibilityIdentifier, viewClassName),
48974
49343
  use native-describe-screen with an explicit bundleId instead (iOS only).
@@ -48983,11 +49352,11 @@ For React Native apps, debugger-component-tree returns React component names wit
48983
49352
  capability: capability16,
48984
49353
  ios: {
48985
49354
  requires: iosRequires,
48986
- handler: (_services, params, device) => describeIos(registry, device, params)
49355
+ handler: async (_services, params, device) => withDescription(await describeIos(registry, device, params))
48987
49356
  },
48988
49357
  android: {
48989
49358
  requires: androidRequires,
48990
- handler: (_services, params) => describeAndroid(params.udid, params.bundleId)
49359
+ handler: async (_services, params) => withDescription(await describeAndroid(params.udid, params.bundleId))
48991
49360
  }
48992
49361
  })
48993
49362
  };
@@ -49020,6 +49389,25 @@ function classifyStaleness({
49020
49389
  };
49021
49390
  }
49022
49391
 
49392
+ // ../tool-server/src/utils/react-profiler/devtools-bootstrap.ts
49393
+ function bootstrapFailureMessage(bootstrap) {
49394
+ switch (bootstrap.reason) {
49395
+ case "no-hook":
49396
+ case "no-rdt-module":
49397
+ 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.";
49398
+ case "no-renderers":
49399
+ 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.";
49400
+ case "no-metro-modules":
49401
+ 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.";
49402
+ case "unsupported-rdt-version":
49403
+ 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.";
49404
+ default: {
49405
+ const detail = bootstrap.message ? ` (runtime error: ${bootstrap.message})` : "";
49406
+ 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.`;
49407
+ }
49408
+ }
49409
+ }
49410
+
49023
49411
  // ../tool-server/src/tools/profiler/react/react-profiler-start.ts
49024
49412
  var zodSchema34 = external_exports.object({
49025
49413
  port: external_exports.coerce.number().default(8081).describe("Metro server port"),
@@ -49090,20 +49478,40 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
49090
49478
  }
49091
49479
  const cdp = api.cdp;
49092
49480
  await cdp.evaluate(REACT_NATIVE_PROFILER_SETUP_SCRIPT);
49093
- const stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49481
+ let stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49094
49482
  if (!stateJson) {
49095
49483
  throw new Error("Failed to read React profiler state from runtime (no value returned).");
49096
49484
  }
49097
- const state2 = JSON.parse(stateJson);
49485
+ let state2 = JSON.parse(stateJson);
49098
49486
  if (!state2.hookExists) {
49099
49487
  throw new Error(
49100
- "__REACT_DEVTOOLS_GLOBAL_HOOK__ not present. React profiling requires a development build of the app."
49488
+ "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
49489
  );
49102
49490
  }
49103
49491
  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
- );
49492
+ const bootstrapJson = await cdp.evaluate(BOOTSTRAP_DEVTOOLS_BACKEND_SCRIPT);
49493
+ if (!bootstrapJson) {
49494
+ throw new Error(
49495
+ "Failed to attach React DevTools backend (no value returned from runtime)."
49496
+ );
49497
+ }
49498
+ const bootstrap = JSON.parse(bootstrapJson);
49499
+ if (!bootstrap.ok) {
49500
+ throw new Error(bootstrapFailureMessage(bootstrap));
49501
+ }
49502
+ await cdp.evaluate(REACT_NATIVE_PROFILER_SETUP_SCRIPT);
49503
+ stateJson = await cdp.evaluate(READ_STATE_SCRIPT);
49504
+ if (!stateJson) {
49505
+ throw new Error(
49506
+ "Failed to re-read React profiler state after attach (no value returned)."
49507
+ );
49508
+ }
49509
+ state2 = JSON.parse(stateJson);
49510
+ if (!state2.hookExists || !("rendererInterfaceFound" in state2) || !state2.rendererInterfaceFound) {
49511
+ throw new Error(
49512
+ "Attached the React DevTools backend but no React renderer registered itself afterwards. Ask the user to fully reload the JS bundle and retry."
49513
+ );
49514
+ }
49107
49515
  }
49108
49516
  if (state2.isRunning) {
49109
49517
  const owner = state2.owner;
@@ -49119,7 +49527,7 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
49119
49527
  owner,
49120
49528
  age_seconds: staleness.ageSeconds,
49121
49529
  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.'
49530
+ 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
49531
  };
49124
49532
  }
49125
49533
  await cdp.evaluate(STOP_FOR_TAKEOVER_SCRIPT).catch(ignore);
@@ -54522,14 +54930,20 @@ function toYamlStep(step) {
54522
54930
  if (step.kind === "echo") {
54523
54931
  return { echo: step.message };
54524
54932
  }
54525
- const hasArgs = Object.keys(step.args).length > 0;
54526
- return hasArgs ? { tool: step.name, args: step.args } : { tool: step.name };
54933
+ const yaml = {
54934
+ tool: step.name
54935
+ };
54936
+ if (Object.keys(step.args).length > 0) yaml.args = step.args;
54937
+ if (step.delayMs !== void 0) yaml.delayMs = step.delayMs;
54938
+ return yaml;
54527
54939
  }
54528
54940
  function fromYamlStep(raw) {
54529
54941
  if ("echo" in raw) {
54530
54942
  return { kind: "echo", message: raw.echo };
54531
54943
  }
54532
- return { kind: "tool", name: raw.tool, args: raw.args ?? {} };
54944
+ const step = { kind: "tool", name: raw.tool, args: raw.args ?? {} };
54945
+ if (raw.delayMs !== void 0) step.delayMs = raw.delayMs;
54946
+ return step;
54533
54947
  }
54534
54948
  function serializeFlow(flow) {
54535
54949
  const doc = {
@@ -54573,13 +54987,13 @@ var zodSchema52 = external_exports.object({
54573
54987
  "Absolute path to the project root directory (the directory that contains or should contain `.argent/flows/`). The flow file is created at `<project_root>/.argent/flows/<name>.yaml`."
54574
54988
  ),
54575
54989
  executionPrerequisite: external_exports.string().describe(
54576
- 'Describes the required app/simulator state before running this flow (e.g. "App on home screen after a fresh reload", "Settings app open on General page")'
54990
+ 'Describes the required app/device state before running this flow (e.g. "App on home screen after a fresh reload", "Settings app open on General page")'
54577
54991
  )
54578
54992
  });
54579
54993
  var flowStartRecordingTool = {
54580
54994
  id: "flow-start-recording",
54581
54995
  description: `Start recording a new flow. Creates a .yaml file in the .argent/flows/ directory.
54582
- Use when you want to capture a reusable sequence of simulator interactions for later replay.
54996
+ Use when you want to capture a reusable sequence of device interactions for later replay.
54583
54997
  Returns { message, flowFile } and optionally { previousFlow } if a prior recording was abandoned.
54584
54998
  Fails if the .argent/flows/ directory cannot be created or the flow file cannot be written.
54585
54999
 
@@ -54622,7 +55036,8 @@ var zodSchema53 = external_exports.object({
54622
55036
  command: external_exports.string().describe('MCP tool name (e.g. "tap", "screenshot", "launch-app")'),
54623
55037
  args: external_exports.string().optional().describe(
54624
55038
  `Tool arguments as a JSON string, e.g. '{"udid": "ABC", "x": 0.5, "y": 0.3}'. Omit for tools with no arguments.`
54625
- )
55039
+ ),
55040
+ delayMs: external_exports.number().int().min(0).optional().describe("Milliseconds to sleep before executing this step during replay.")
54626
55041
  });
54627
55042
  function createFlowAddStepTool(registry) {
54628
55043
  return {
@@ -54639,7 +55054,8 @@ If a step was recorded by mistake, edit the .yaml file directly to remove it.`,
54639
55054
  const flowFile = await appendStep(filePath, {
54640
55055
  kind: "tool",
54641
55056
  name: params.command,
54642
- args
55057
+ args,
55058
+ delayMs: params.delayMs
54643
55059
  });
54644
55060
  return {
54645
55061
  message: `Step added to "${flowName}" flow`,
@@ -54723,13 +55139,15 @@ function createRunFlowTool(registry) {
54723
55139
  id: "flow-execute",
54724
55140
  description: `Run a saved flow from the .argent/flows/ directory.
54725
55141
  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.
54727
- Use when you want to replay a recorded flow or run a scripted sequence of simulator actions.
55142
+ echo steps print a message. A tool step may carry \`delayMs: <ms>\` to sleep
55143
+ that long before the step runs. Returns the result of every step, including images.
55144
+ Use when you want to replay a recorded flow or run a scripted sequence of device actions.
54728
55145
  Fails if the flow file does not exist or a step tool raises an error (execution stops at that step).
54729
55146
 
54730
55147
  If the flow has an execution prerequisite and prerequisiteAcknowledged is not
54731
55148
  set to true, the tool returns a notice with the prerequisite instead of running.
54732
55149
  Use flow-read-prerequisite to inspect the prerequisite beforehand.`,
55150
+ longRunning: true,
54733
55151
  zodSchema: zodSchema56,
54734
55152
  services: () => ({}),
54735
55153
  async execute(_services, params) {
@@ -54751,6 +55169,7 @@ Use flow-read-prerequisite to inspect the prerequisite beforehand.`,
54751
55169
  steps.push({ kind: "echo", message: step.message });
54752
55170
  continue;
54753
55171
  }
55172
+ if (step.delayMs) await sleep4(step.delayMs);
54754
55173
  const toolDef = registry.getTool(step.name);
54755
55174
  try {
54756
55175
  const result = await registry.invokeTool(step.name, step.args);
@@ -55281,40 +55700,41 @@ async function getBootedUdids() {
55281
55700
  }
55282
55701
  return udids;
55283
55702
  }
55284
- async function initSimulator(registry, watchedUdids, udid) {
55285
- watchedUdids.add(udid);
55703
+ async function initUdid(registry, udid, trackedServices) {
55704
+ const ndRef = nativeDevtoolsRef({ id: udid, platform: "ios", kind: "simulator" });
55286
55705
  try {
55287
- const ndRef = nativeDevtoolsRef({ id: udid, platform: "ios", kind: "simulator" });
55288
- await registry.resolveService(ndRef.urn, ndRef.options);
55289
- } catch (err) {
55290
- watchedUdids.delete(udid);
55291
- process.stderr.write(
55292
- `[simulator-watcher] initSimulator failed for ${udid}: ${err instanceof Error ? err.message : err}
55293
- `
55294
- );
55706
+ const service = await registry.resolveService(ndRef.urn, ndRef.options);
55707
+ trackedServices.set(udid, service);
55708
+ } catch {
55295
55709
  }
55296
55710
  }
55297
55711
  function startSimulatorWatcher(registry) {
55298
- const watchedUdids = /* @__PURE__ */ new Set();
55299
- async function poll(awaitInit) {
55712
+ const trackedServices = /* @__PURE__ */ new Map();
55713
+ async function poll(shouldBlockUntilSettled) {
55300
55714
  let booted;
55301
55715
  try {
55302
55716
  booted = await getBootedUdids();
55303
55717
  } catch {
55304
55718
  return;
55305
55719
  }
55306
- const newUdids = [...booted].filter((udid) => !watchedUdids.has(udid));
55307
- if (awaitInit) {
55308
- await Promise.all(newUdids.map((udid) => initSimulator(registry, watchedUdids, udid)));
55309
- } else {
55310
- newUdids.forEach((udid) => {
55311
- initSimulator(registry, watchedUdids, udid).catch(() => {
55312
- });
55313
- });
55720
+ const newUdids = [...booted].filter((udid) => !trackedServices.has(udid));
55721
+ const pendingAttempts = newUdids.map(
55722
+ (udid) => initUdid(registry, udid, trackedServices)
55723
+ );
55724
+ for (const [udid, service] of trackedServices) {
55725
+ if (!booted.has(udid)) continue;
55726
+ const failure = service.getInitFailure();
55727
+ if (failure && !failure.givenUp) {
55728
+ pendingAttempts.push(service.ensureEnvReady().catch(() => {
55729
+ }));
55730
+ }
55314
55731
  }
55315
- for (const udid of watchedUdids) {
55732
+ if (shouldBlockUntilSettled) await Promise.all(pendingAttempts);
55733
+ else pendingAttempts.forEach((p) => p.catch(() => {
55734
+ }));
55735
+ for (const udid of [...trackedServices.keys()]) {
55316
55736
  if (!booted.has(udid)) {
55317
- watchedUdids.delete(udid);
55737
+ trackedServices.delete(udid);
55318
55738
  registry.disposeService(`${NATIVE_DEVTOOLS_NAMESPACE}:${udid}`).catch(() => {
55319
55739
  });
55320
55740
  }