@swmansion/argent 0.28.1-next.2 → 0.28.1-next.21

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.
@@ -13223,8 +13223,8 @@ function finalize(ctx, schema) {
13223
13223
  const root = ctx.seen.get(schema);
13224
13224
  if (!root)
13225
13225
  throw new Error("Unprocessed schema. This is a bug in Zod.");
13226
- const flattenRef = (zodSchema80) => {
13227
- const seen = ctx.seen.get(zodSchema80);
13226
+ const flattenRef = (zodSchema81) => {
13227
+ const seen = ctx.seen.get(zodSchema81);
13228
13228
  if (seen.ref === null)
13229
13229
  return;
13230
13230
  const schema2 = seen.def ?? seen.schema;
@@ -13242,7 +13242,7 @@ function finalize(ctx, schema) {
13242
13242
  Object.assign(schema2, refSchema);
13243
13243
  }
13244
13244
  Object.assign(schema2, _cached);
13245
- const isParentRef = zodSchema80._zod.parent === ref;
13245
+ const isParentRef = zodSchema81._zod.parent === ref;
13246
13246
  if (isParentRef) {
13247
13247
  for (const key2 in schema2) {
13248
13248
  if (key2 === "$ref" || key2 === "allOf")
@@ -13262,7 +13262,7 @@ function finalize(ctx, schema) {
13262
13262
  }
13263
13263
  }
13264
13264
  }
13265
- const parent = zodSchema80._zod.parent;
13265
+ const parent = zodSchema81._zod.parent;
13266
13266
  if (parent && parent !== ref) {
13267
13267
  flattenRef(parent);
13268
13268
  const parentSeen = ctx.seen.get(parent);
@@ -13280,7 +13280,7 @@ function finalize(ctx, schema) {
13280
13280
  }
13281
13281
  }
13282
13282
  ctx.override({
13283
- zodSchema: zodSchema80,
13283
+ zodSchema: zodSchema81,
13284
13284
  jsonSchema: schema2,
13285
13285
  path: seen.path ?? []
13286
13286
  });
@@ -16081,10 +16081,10 @@ function convertBaseSchema(schema, ctx) {
16081
16081
  }
16082
16082
  ctx.processing.add(refPath);
16083
16083
  const resolved = resolveRef(refPath, ctx);
16084
- const zodSchema81 = convertSchema(resolved, ctx);
16085
- ctx.refs.set(refPath, zodSchema81);
16084
+ const zodSchema82 = convertSchema(resolved, ctx);
16085
+ ctx.refs.set(refPath, zodSchema82);
16086
16086
  ctx.processing.delete(refPath);
16087
- return zodSchema81;
16087
+ return zodSchema82;
16088
16088
  }
16089
16089
  if (schema.enum !== void 0) {
16090
16090
  const enumValues = schema.enum;
@@ -16126,7 +16126,7 @@ function convertBaseSchema(schema, ctx) {
16126
16126
  if (!type) {
16127
16127
  return z.any();
16128
16128
  }
16129
- let zodSchema80;
16129
+ let zodSchema81;
16130
16130
  switch (type) {
16131
16131
  case "string": {
16132
16132
  let stringSchema = z.string();
@@ -16189,7 +16189,7 @@ function convertBaseSchema(schema, ctx) {
16189
16189
  if (schema.pattern) {
16190
16190
  stringSchema = stringSchema.regex(new RegExp(schema.pattern));
16191
16191
  }
16192
- zodSchema80 = stringSchema;
16192
+ zodSchema81 = stringSchema;
16193
16193
  break;
16194
16194
  }
16195
16195
  case "number":
@@ -16214,15 +16214,15 @@ function convertBaseSchema(schema, ctx) {
16214
16214
  if (typeof schema.multipleOf === "number") {
16215
16215
  numberSchema = numberSchema.multipleOf(schema.multipleOf);
16216
16216
  }
16217
- zodSchema80 = numberSchema;
16217
+ zodSchema81 = numberSchema;
16218
16218
  break;
16219
16219
  }
16220
16220
  case "boolean": {
16221
- zodSchema80 = z.boolean();
16221
+ zodSchema81 = z.boolean();
16222
16222
  break;
16223
16223
  }
16224
16224
  case "null": {
16225
- zodSchema80 = z.null();
16225
+ zodSchema81 = z.null();
16226
16226
  break;
16227
16227
  }
16228
16228
  case "object": {
@@ -16237,12 +16237,12 @@ function convertBaseSchema(schema, ctx) {
16237
16237
  const keySchema = convertSchema(schema.propertyNames, ctx);
16238
16238
  const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z.any();
16239
16239
  if (Object.keys(shape).length === 0) {
16240
- zodSchema80 = z.record(keySchema, valueSchema);
16240
+ zodSchema81 = z.record(keySchema, valueSchema);
16241
16241
  break;
16242
16242
  }
16243
16243
  const objectSchema2 = z.object(shape).passthrough();
16244
16244
  const recordSchema = z.looseRecord(keySchema, valueSchema);
16245
- zodSchema80 = z.intersection(objectSchema2, recordSchema);
16245
+ zodSchema81 = z.intersection(objectSchema2, recordSchema);
16246
16246
  break;
16247
16247
  }
16248
16248
  if (schema.patternProperties) {
@@ -16260,25 +16260,25 @@ function convertBaseSchema(schema, ctx) {
16260
16260
  }
16261
16261
  schemasToIntersect.push(...looseRecords);
16262
16262
  if (schemasToIntersect.length === 0) {
16263
- zodSchema80 = z.object({}).passthrough();
16263
+ zodSchema81 = z.object({}).passthrough();
16264
16264
  } else if (schemasToIntersect.length === 1) {
16265
- zodSchema80 = schemasToIntersect[0];
16265
+ zodSchema81 = schemasToIntersect[0];
16266
16266
  } else {
16267
16267
  let result = z.intersection(schemasToIntersect[0], schemasToIntersect[1]);
16268
16268
  for (let i = 2; i < schemasToIntersect.length; i++) {
16269
16269
  result = z.intersection(result, schemasToIntersect[i]);
16270
16270
  }
16271
- zodSchema80 = result;
16271
+ zodSchema81 = result;
16272
16272
  }
16273
16273
  break;
16274
16274
  }
16275
16275
  const objectSchema = z.object(shape);
16276
16276
  if (schema.additionalProperties === false) {
16277
- zodSchema80 = objectSchema.strict();
16277
+ zodSchema81 = objectSchema.strict();
16278
16278
  } else if (typeof schema.additionalProperties === "object") {
16279
- zodSchema80 = objectSchema.catchall(convertSchema(schema.additionalProperties, ctx));
16279
+ zodSchema81 = objectSchema.catchall(convertSchema(schema.additionalProperties, ctx));
16280
16280
  } else {
16281
- zodSchema80 = objectSchema.passthrough();
16281
+ zodSchema81 = objectSchema.passthrough();
16282
16282
  }
16283
16283
  break;
16284
16284
  }
@@ -16289,29 +16289,29 @@ function convertBaseSchema(schema, ctx) {
16289
16289
  const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
16290
16290
  const rest = items && typeof items === "object" && !Array.isArray(items) ? convertSchema(items, ctx) : void 0;
16291
16291
  if (rest) {
16292
- zodSchema80 = z.tuple(tupleItems).rest(rest);
16292
+ zodSchema81 = z.tuple(tupleItems).rest(rest);
16293
16293
  } else {
16294
- zodSchema80 = z.tuple(tupleItems);
16294
+ zodSchema81 = z.tuple(tupleItems);
16295
16295
  }
16296
16296
  if (typeof schema.minItems === "number") {
16297
- zodSchema80 = zodSchema80.check(z.minLength(schema.minItems));
16297
+ zodSchema81 = zodSchema81.check(z.minLength(schema.minItems));
16298
16298
  }
16299
16299
  if (typeof schema.maxItems === "number") {
16300
- zodSchema80 = zodSchema80.check(z.maxLength(schema.maxItems));
16300
+ zodSchema81 = zodSchema81.check(z.maxLength(schema.maxItems));
16301
16301
  }
16302
16302
  } else if (Array.isArray(items)) {
16303
16303
  const tupleItems = items.map((item) => convertSchema(item, ctx));
16304
16304
  const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : void 0;
16305
16305
  if (rest) {
16306
- zodSchema80 = z.tuple(tupleItems).rest(rest);
16306
+ zodSchema81 = z.tuple(tupleItems).rest(rest);
16307
16307
  } else {
16308
- zodSchema80 = z.tuple(tupleItems);
16308
+ zodSchema81 = z.tuple(tupleItems);
16309
16309
  }
16310
16310
  if (typeof schema.minItems === "number") {
16311
- zodSchema80 = zodSchema80.check(z.minLength(schema.minItems));
16311
+ zodSchema81 = zodSchema81.check(z.minLength(schema.minItems));
16312
16312
  }
16313
16313
  if (typeof schema.maxItems === "number") {
16314
- zodSchema80 = zodSchema80.check(z.maxLength(schema.maxItems));
16314
+ zodSchema81 = zodSchema81.check(z.maxLength(schema.maxItems));
16315
16315
  }
16316
16316
  } else if (items !== void 0) {
16317
16317
  const element = convertSchema(items, ctx);
@@ -16322,16 +16322,16 @@ function convertBaseSchema(schema, ctx) {
16322
16322
  if (typeof schema.maxItems === "number") {
16323
16323
  arraySchema = arraySchema.max(schema.maxItems);
16324
16324
  }
16325
- zodSchema80 = arraySchema;
16325
+ zodSchema81 = arraySchema;
16326
16326
  } else {
16327
- zodSchema80 = z.array(z.any());
16327
+ zodSchema81 = z.array(z.any());
16328
16328
  }
16329
16329
  break;
16330
16330
  }
16331
16331
  default:
16332
16332
  throw new Error(`Unsupported type: ${type}`);
16333
16333
  }
16334
- return zodSchema80;
16334
+ return zodSchema81;
16335
16335
  }
16336
16336
  function convertSchema(schema, ctx) {
16337
16337
  if (typeof schema === "boolean") {
@@ -73655,16 +73655,16 @@ function lookupExternalDeviceNow(id) {
73655
73655
  }
73656
73656
  return device;
73657
73657
  }
73658
- async function assertExternalCapability(namespace, device, capability37) {
73659
- assertExternalCapabilitySync(namespace, device, capability37);
73658
+ async function assertExternalCapability(namespace, device, capability38) {
73659
+ assertExternalCapabilitySync(namespace, device, capability38);
73660
73660
  }
73661
- function assertExternalCapabilitySync(namespace, device, capability37) {
73661
+ function assertExternalCapabilitySync(namespace, device, capability38) {
73662
73662
  const id = typeof device === "string" ? device : device.id;
73663
73663
  const externalDevice = isExternalId(id) ? lookupExternalDeviceNow(id) : externalClaimForNativeId(id);
73664
73664
  if (!externalDevice) return;
73665
- if (externalDevice.capabilities.has(capability37)) return;
73665
+ if (externalDevice.capabilities.has(capability38)) return;
73666
73666
  throw new FailureError(
73667
- `${namespace} is not available on '${externalDevice.name}': ${externalDevice.provider.name} did not grant the '${capability37}' capability for this device.`,
73667
+ `${namespace} is not available on '${externalDevice.name}': ${externalDevice.provider.name} did not grant the '${capability38}' capability for this device.`,
73668
73668
  {
73669
73669
  error_code: FAILURE_CODES.EXTERNAL_DEVICE_CAPABILITY_DENIED,
73670
73670
  error_kind: "unsupported",
@@ -94920,7 +94920,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
94920
94920
  var SESSION_ID = (0, import_node_crypto3.randomUUID)();
94921
94921
  function readCliVersion() {
94922
94922
  if (true) {
94923
- return "0.28.1-next.2";
94923
+ return "0.28.1-next.21";
94924
94924
  }
94925
94925
  return "0.0.0";
94926
94926
  }
@@ -96694,8 +96694,8 @@ async function simctlArgsForUdid(udid, args, options) {
96694
96694
  return [...simctlPrefix(await deviceSetForUdid(udid)), ...nativeArgs(udid, args)];
96695
96695
  }
96696
96696
  function assertSimctlEntitlement(udid, options) {
96697
- const capability37 = options?.granted ?? "simctl";
96698
- assertExternalCapabilitySync(capability37, udid, capability37);
96697
+ const capability38 = options?.granted ?? "simctl";
96698
+ assertExternalCapabilitySync(capability38, udid, capability38);
96699
96699
  }
96700
96700
  async function simctlTargetForUdid(udid, options) {
96701
96701
  assertSimctlEntitlement(udid, options);
@@ -97760,6 +97760,9 @@ var axServiceBlueprint = {
97760
97760
  treeVersion: result.treeVersion
97761
97761
  };
97762
97762
  },
97763
+ async foregroundApp() {
97764
+ return await query("foreground_app");
97765
+ },
97763
97766
  async livePanel() {
97764
97767
  const result = await query("live_panel", LIVE_PANEL_TIMEOUT_MS);
97765
97768
  if (result.error) {
@@ -97869,23 +97872,23 @@ var InvalidToolInputError = class extends Error {
97869
97872
  });
97870
97873
  }
97871
97874
  };
97872
- function platformMatrix(platform, capability37) {
97875
+ function platformMatrix(platform, capability38) {
97873
97876
  switch (platform) {
97874
97877
  case "ios":
97875
- return capability37.apple;
97878
+ return capability38.apple;
97876
97879
  case "ios-remote":
97877
- return capability37.appleRemote;
97880
+ return capability38.appleRemote;
97878
97881
  case "android":
97879
- return capability37.android;
97882
+ return capability38.android;
97880
97883
  case "chromium":
97881
- return capability37.chromium;
97884
+ return capability38.chromium;
97882
97885
  case "vega":
97883
- return capability37.vega;
97886
+ return capability38.vega;
97884
97887
  }
97885
97888
  }
97886
- function assertSupported(toolId, capability37, device) {
97887
- if (!capability37) return;
97888
- const matrix = platformMatrix(device.platform, capability37);
97889
+ function assertSupported(toolId, capability38, device) {
97890
+ if (!capability38) return;
97891
+ const matrix = platformMatrix(device.platform, capability38);
97889
97892
  if (!matrix) {
97890
97893
  throw new UnsupportedOperationError(toolId, device, `no ${device.platform} support declared`);
97891
97894
  }
@@ -97893,7 +97896,7 @@ function assertSupported(toolId, capability37, device) {
97893
97896
  if (!supported) {
97894
97897
  throw new UnsupportedOperationError(toolId, device, `kind '${device.kind}' not supported`);
97895
97898
  }
97896
- if (capability37.supports && !capability37.supports(device)) {
97899
+ if (capability38.supports && !capability38.supports(device)) {
97897
97900
  throw new UnsupportedOperationError(toolId, device, "supports() refiner rejected device");
97898
97901
  }
97899
97902
  }
@@ -113332,7 +113335,8 @@ function parseUiAutomatorDump(rawOutput, screenW, screenH, options = {}) {
113332
113335
  if (xmlEnd !== -1) xml = xml.slice(0, xmlEnd + "</hierarchy>".length);
113333
113336
  const root = parseUiAutomatorXml(xml);
113334
113337
  if (!root) {
113335
- throw new FailureError("Failed to parse uiautomator dump output", {
113338
+ const got = rawOutput.trim() ? `${rawOutput.length} chars: ${JSON.stringify(rawOutput.slice(0, 200))}` : "empty";
113339
+ throw new FailureError(`Failed to parse uiautomator dump output (${got})`, {
113336
113340
  error_code: FAILURE_CODES.ANDROID_UIAUTOMATOR_PARSE_FAILED,
113337
113341
  failure_stage: "android_uiautomator_parse_dump",
113338
113342
  failure_area: "tool_server",
@@ -116728,13 +116732,13 @@ function scheduleGroupSigkill(pid, graceMs, opts) {
116728
116732
  }, graceMs).unref();
116729
116733
  }
116730
116734
  async function pollPidsUntilGone(pids, opts) {
116731
- const isAlive = opts.isAlive ?? pidIsAlive;
116735
+ const isAlive2 = opts.isAlive ?? pidIsAlive;
116732
116736
  const sleep14 = opts.sleep ?? ((ms) => new Promise((resolve14) => setTimeout(resolve14, ms)));
116733
116737
  const maxPolls = Math.max(1, Math.ceil(opts.timeoutMs / opts.pollIntervalMs));
116734
- let remaining = pids.filter((pid) => isAlive(pid));
116738
+ let remaining = pids.filter((pid) => isAlive2(pid));
116735
116739
  for (let poll = 0; poll < maxPolls && remaining.length > 0; poll += 1) {
116736
116740
  await sleep14(opts.pollIntervalMs);
116737
- remaining = remaining.filter((pid) => isAlive(pid));
116741
+ remaining = remaining.filter((pid) => isAlive2(pid));
116738
116742
  }
116739
116743
  return remaining;
116740
116744
  }
@@ -117834,9 +117838,11 @@ var fs29 = __toESM(require("node:fs"));
117834
117838
  var path26 = __toESM(require("node:path"));
117835
117839
  var os12 = __toESM(require("node:os"));
117836
117840
  var MAX_ENTRIES = 5e4;
117841
+ var STALE_LOG_MS = 24 * 60 * 60 * 1e3;
117837
117842
  var CLUSTER_KEY_LENGTH = 80;
117838
117843
  var SOURCE_EXT = /\.(tsx?|jsx?|mjs|cjs)$/;
117839
117844
  var LINE_RE = /^\[L:(\d+)\] (\S+) (\S+)\s+(\S+) \| (.*)$/;
117845
+ var liveLogFiles = /* @__PURE__ */ new Set();
117840
117846
  var LogFileWriter = class {
117841
117847
  filePath;
117842
117848
  fd = null;
@@ -117850,7 +117856,9 @@ var LogFileWriter = class {
117850
117856
  const timestamp = Date.now();
117851
117857
  const dir = path26.join(os12.homedir(), ".argent", "tmp");
117852
117858
  fs29.mkdirSync(dir, { recursive: true });
117853
- this.filePath = path26.join(dir, `argent-logs-${port}-${timestamp}.log`);
117859
+ pruneStaleLogs(dir);
117860
+ this.filePath = path26.join(dir, `argent-logs-${port}-${timestamp}-p${process.pid}.log`);
117861
+ liveLogFiles.add(this.filePath);
117854
117862
  this.open();
117855
117863
  }
117856
117864
  open() {
@@ -117943,9 +117951,11 @@ var LogFileWriter = class {
117943
117951
  }
117944
117952
  return { entries: filtered, total };
117945
117953
  }
117946
- close() {
117954
+ /** `keepFile` leaves the log to the sweep, 24h after the close. */
117955
+ close({ keepFile = false } = {}) {
117947
117956
  if (this.closed) return;
117948
117957
  this.closed = true;
117958
+ liveLogFiles.delete(this.filePath);
117949
117959
  if (this.fd !== null) {
117950
117960
  try {
117951
117961
  fs29.closeSync(this.fd);
@@ -117953,12 +117963,47 @@ var LogFileWriter = class {
117953
117963
  }
117954
117964
  this.fd = null;
117955
117965
  }
117966
+ if (keepFile) {
117967
+ try {
117968
+ const now = /* @__PURE__ */ new Date();
117969
+ fs29.utimesSync(this.filePath, now, now);
117970
+ } catch {
117971
+ }
117972
+ return;
117973
+ }
117956
117974
  try {
117957
117975
  fs29.unlinkSync(this.filePath);
117958
117976
  } catch {
117959
117977
  }
117960
117978
  }
117961
117979
  };
117980
+ function pruneStaleLogs(dir) {
117981
+ const cutoff = Date.now() - STALE_LOG_MS;
117982
+ let names;
117983
+ try {
117984
+ names = fs29.readdirSync(dir);
117985
+ } catch {
117986
+ return;
117987
+ }
117988
+ for (const name of names) {
117989
+ const pid = Number(/^argent-logs-.*-p(\d+)\.log$/.exec(name)?.[1]);
117990
+ if (!pid) continue;
117991
+ const file2 = path26.join(dir, name);
117992
+ if (pid === process.pid ? liveLogFiles.has(file2) : isAlive(pid)) continue;
117993
+ try {
117994
+ if (fs29.statSync(file2).mtimeMs < cutoff) fs29.unlinkSync(file2);
117995
+ } catch {
117996
+ }
117997
+ }
117998
+ }
117999
+ function isAlive(pid) {
118000
+ try {
118001
+ process.kill(pid, 0);
118002
+ return true;
118003
+ } catch (err) {
118004
+ return err.code === "EPERM";
118005
+ }
118006
+ }
117962
118007
  function cleanSourceUrl(url2) {
117963
118008
  try {
117964
118009
  const { pathname } = new URL(url2);
@@ -117996,20 +118041,36 @@ var reaped = /* @__PURE__ */ new Map();
117996
118041
  function key(kind, deviceId) {
117997
118042
  return `${kind}:${deviceId.toLowerCase()}`;
117998
118043
  }
117999
- function recordReapedSession(kind, deviceId, salvage) {
118000
- const entry = { kind, deviceId, atMs: Date.now() };
118044
+ function recordReapedSession(kind, deviceIds, salvage, connectionLost = false) {
118045
+ const ids = [deviceIds].flat().filter((id) => id !== void 0);
118046
+ const entry = { kind, deviceId: ids[0], ids, atMs: Date.now() };
118001
118047
  if (salvage) entry.salvage = salvage;
118002
- reaped.set(key(kind, deviceId), entry);
118048
+ if (connectionLost) entry.connectionLost = true;
118049
+ for (const id of ids) reaped.set(key(kind, id), entry);
118003
118050
  }
118004
118051
  function takeReapedSession(kind, deviceId) {
118005
- const k = key(kind, deviceId);
118006
- const entry = reaped.get(k);
118007
- if (entry) reaped.delete(k);
118052
+ const entry = reaped.get(key(kind, deviceId));
118053
+ for (const id of entry?.ids ?? []) {
118054
+ if (reaped.get(key(kind, id)) === entry) reaped.delete(key(kind, id));
118055
+ }
118008
118056
  return entry;
118009
118057
  }
118058
+ function takeReapedSessionAnyId(kind, ids) {
118059
+ let first;
118060
+ for (const id of new Set(ids)) {
118061
+ if (id === void 0) continue;
118062
+ const entry = takeReapedSession(kind, id);
118063
+ first ??= entry;
118064
+ }
118065
+ return first;
118066
+ }
118010
118067
  function describeReapedSession(entry, what) {
118011
118068
  const secondsAgo = Math.max(0, Math.round((Date.now() - entry.atMs) / 1e3));
118012
- return `The ${what} for device ${entry.deviceId} was torn down ${secondsAgo}s ago \u2014 by a stop-all-simulator-servers, which reaps every service a device owns, or by another teardown that reaches the same services (a stop-simulator-server on Chromium, or a react-profiler-start reclaiming the session with force). One tool-server serves every agent using this argent install, so this may have been another agent rather than your own call. It was not a session that never started.` + (entry.salvage ? ` ${entry.salvage}` : "");
118069
+ const salvage = entry.salvage ? ` ${entry.salvage}` : "";
118070
+ if (entry.connectionLost) {
118071
+ return `The ${what} for device ${entry.deviceId} lost its connection ${secondsAgo}s ago \u2014 the app crashed or quit, or its debugger endpoint went away.${salvage}`;
118072
+ }
118073
+ return `The ${what} for device ${entry.deviceId} was torn down ${secondsAgo}s ago \u2014 by a stop-all-simulator-servers, which reaps every service a device owns, or by another teardown that reaches the same services (a stop-simulator-server on Chromium, or a react-profiler-start reclaiming the session with force). One tool-server serves every agent using this argent install, so this may have been another agent rather than your own call. It was not a session that never started.${salvage}`;
118013
118074
  }
118014
118075
 
118015
118076
  // ../tool-server/src/blueprints/chromium-js-runtime-debugger.ts
@@ -118174,14 +118235,17 @@ var chromiumJsRuntimeDebuggerBlueprint = {
118174
118235
  cdp.events.off("disconnected", onDisconnected);
118175
118236
  await consoleServer.close();
118176
118237
  const captured = logWriter.getStats().totalEntries;
118238
+ const keepFile = captured > 0 && !cdp.isConnected();
118177
118239
  if (captured > 0) {
118240
+ const entries = `${captured} captured console ${captured === 1 ? "entry" : "entries"}`;
118178
118241
  recordReapedSession(
118179
118242
  "js-runtime-debugger",
118180
118243
  device.id,
118181
- `The ${captured} captured console ${captured === 1 ? "entry" : "entries"} went with it \u2014 the log file is deleted on teardown, so this registry starts empty rather than the app having logged nothing.`
118244
+ keepFile ? `The log file with its ${entries} is kept at ${logWriter.getFilePath()}.` : `The ${entries} went with it \u2014 the log file is deleted on teardown, so this registry starts empty rather than the app having logged nothing.`,
118245
+ keepFile
118182
118246
  );
118183
118247
  }
118184
- logWriter.close();
118248
+ logWriter.close({ keepFile });
118185
118249
  },
118186
118250
  events
118187
118251
  };
@@ -119997,17 +120061,21 @@ var jsRuntimeDebuggerBlueprint = {
119997
120061
  api,
119998
120062
  dispose: async () => {
119999
120063
  const captured = logWriter.getStats().totalEntries;
120064
+ const keepFile = captured > 0 && !cdp.isConnected();
120000
120065
  if (captured > 0) {
120001
- const salvage = `The ${captured} captured console ${captured === 1 ? "entry" : "entries"} went with it \u2014 the log file is deleted on teardown, so this registry starts empty rather than the app having logged nothing.`;
120002
- recordReapedSession("js-runtime-debugger", deviceId, salvage);
120003
- if (api.logicalDeviceId && api.logicalDeviceId !== deviceId) {
120004
- recordReapedSession("js-runtime-debugger", api.logicalDeviceId, salvage);
120005
- }
120066
+ const entries = `${captured} captured console ${captured === 1 ? "entry" : "entries"}`;
120067
+ const salvage = keepFile ? `The log file with its ${entries} is kept at ${logWriter.getFilePath()}.` : `The ${entries} went with it \u2014 the log file is deleted on teardown, so this registry starts empty rather than the app having logged nothing.`;
120068
+ recordReapedSession(
120069
+ "js-runtime-debugger",
120070
+ [deviceId, api.logicalDeviceId],
120071
+ salvage,
120072
+ keepFile
120073
+ );
120006
120074
  }
120007
120075
  forgetDeviceAlias(api.logicalDeviceId);
120008
120076
  forgetLogicalKeyedDevice(deviceId);
120009
120077
  await consoleServer.close();
120010
- logWriter.close();
120078
+ logWriter.close({ keepFile });
120011
120079
  await cdp.disconnect();
120012
120080
  },
120013
120081
  events
@@ -122643,8 +122711,9 @@ async function resolveLauncherActivity(udid, bundleId, isTv = false) {
122643
122711
  }
122644
122712
  const launcher = await resolveFor();
122645
122713
  if (launcher) return launcher;
122714
+ const pmPath = await adbShell(udid, `pm path ${shellQuote(bundleId)}; true`);
122646
122715
  throw new FailureError(
122647
- `Could not resolve a ${isTv ? "LEANBACK_LAUNCHER or LAUNCHER" : "LAUNCHER"} activity for ${bundleId}. Install the app first, or pass an explicit \`activity\`. (resolve-activity output: ${lastRaw.trim() || "empty"})`,
122716
+ `Could not resolve a ${isTv ? "LEANBACK_LAUNCHER or LAUNCHER" : "LAUNCHER"} activity for ${bundleId}. ` + (pmPath.includes("package:") ? `It is installed but declares no such activity: pass an explicit \`activity\`. ` : `It is not installed on ${udid}: install it with \`reinstall-app\`. `) + `(resolve-activity output: ${lastRaw.trim() || "empty"})`,
122648
122717
  {
122649
122718
  error_code: FAILURE_CODES.ANDROID_LAUNCH_ACTIVITY_RESOLVE_FAILED,
122650
122719
  failure_stage: "android_launch_resolve_activity",
@@ -124825,7 +124894,6 @@ var gestureScrollTool = {
124825
124894
  description: `Scroll content in a Chromium app by dispatching mouse-wheel events at a point. Anchor x/y are normalized 0.0\u20131.0 (fractions of the window, not pixels), same coordinate space as gesture-tap and describe. Deltas are fractions of the window too: deltaY 0.5 scrolls down half a window; negative scrolls back up.
124826
124895
  Use when content is below/above the fold (describe shows off-screen elements with zero height) or a list needs scrolling. Chromium only \u2014 on iOS/Android use gesture-swipe.
124827
124896
  Returns { scrolled: true, timestampMs }. Fails if the Chromium CDP session is not reachable for the given device.`,
124828
- alwaysLoad: true,
124829
124897
  searchHint: "scroll wheel list page chromium mouse down up content fold",
124830
124898
  zodSchema: zodSchema19,
124831
124899
  capability: capability11,
@@ -124892,7 +124960,6 @@ var gestureDragTool = {
124892
124960
  description: `Press the left mouse button at a start point, move to an end point, and release \u2014 a desktop mouse drag in a Chromium app. All positions are normalized 0.0\u20131.0 (fractions of the window, not pixels), same coordinate space as gesture-tap and describe, except that a coordinate of exactly 1.0 lands one pixel inside the window edge (gesture-tap maps it to the edge itself). Interpolates mouse-move events at ~60fps over durationMs for a natural drag (a momentum-free drag samples more finely when durationMs is short, so its ease-out has a curve).
124893
124961
  Use for slider thumbs, drag-and-drop, text selection, or draggable UI elements. Dragging never scrolls content on desktop \u2014 use gesture-scroll for lists/pages. Chromium only \u2014 on iOS/Android use gesture-swipe.
124894
124962
  Pass momentum:false for a momentum-free drag that decelerates into the release, so apps that compute a fling from the pointer stream read ~0 velocity and the drag ends where it was aimed instead of flinging past it (a durationMs under ~100ms is too short for the deceleration to suppress the fling entirely). Returns { dragged: true, timestampMs }. Fails if the Chromium CDP session is not reachable for the given device.`,
124895
- alwaysLoad: true,
124896
124963
  searchHint: "drag drop slider mouse press move release chromium select",
124897
124964
  zodSchema: zodSchema20,
124898
124965
  capability: capability12,
@@ -126150,6 +126217,10 @@ On a TV target (runtimeKind 'tv') only \`text\` applies \u2014 focus a text fiel
126150
126217
  One call does one action: pass text OR key, never both. To type and then press a key, send two \`keyboard\` steps in one \`run-sequence\` \u2014 { text: "hello" } then { key: "enter" } \u2014 which also keeps it to a single round-trip.`,
126151
126218
  zodSchema: zodSchema25,
126152
126219
  capability: capability17,
126220
+ alwaysLoad: true,
126221
+ // Typing time grows with text length on several backends and can outlast the MCP
126222
+ // fetch timeout, whose abort replays the call: the text would be typed twice.
126223
+ longRunning: true,
126153
126224
  searchHint: "type text keyboard input named key enter escape arrow tv vega fire tv search field hid leanback",
126154
126225
  services: () => ({}),
126155
126226
  execute: async (services, params, options) => {
@@ -127146,7 +127217,6 @@ Single press: { button: "down" }. Repeat the same button: { button: "down", repe
127146
127217
  Multi-step navigation: pass a path as { button: ["up","right","right","select"] } \u2014 it runs in one tool call, far cheaper than separate presses.
127147
127218
  Read the screen with \`describe\` before and after to see where focus landed.
127148
127219
  Returns { pressed, count }.`,
127149
- alwaysLoad: true,
127150
127220
  // A path (≤64 buttons) × repeat (≤50) flattens to thousands of presses, sent
127151
127221
  // one round-trip at a time on the Apple/Android path — minutes of wall-clock.
127152
127222
  longRunning: true,
@@ -127197,9 +127267,9 @@ async function invokeSubTool(registry2, ctx, toolId, args, extra) {
127197
127267
  }
127198
127268
  function describeNestedParamError(registry2, err, toolId, dispatchedArgs, authoredArgs) {
127199
127269
  if (getFailureSignal(err)?.error_code !== FAILURE_CODES.TOOL_INPUT_INVALID) return void 0;
127200
- const zodSchema80 = registry2.getTool(toolId)?.zodSchema;
127201
- if (!zodSchema80) return void 0;
127202
- const parsed = zodSchema80.safeParse(dispatchedArgs ?? {});
127270
+ const zodSchema81 = registry2.getTool(toolId)?.zodSchema;
127271
+ if (!zodSchema81) return void 0;
127272
+ const parsed = zodSchema81.safeParse(dispatchedArgs ?? {});
127203
127273
  if (parsed.success) return void 0;
127204
127274
  return `Invalid params for tool "${toolId}": ${describeParamIssues(parsed.error, authoredArgs)}`;
127205
127275
  }
@@ -133512,7 +133582,7 @@ var zodSchema29 = external_exports.object({
133512
133582
  `Max time to wait for the condition before giving up (default ${DEFAULT_TIMEOUT_MS3}).`
133513
133583
  ),
133514
133584
  pollIntervalMs: external_exports.number().int().min(50).max(5e3).optional().describe(`How often to re-check the tree (default ${DEFAULT_POLL_INTERVAL_MS}).`)
133515
- }).refine((p) => p.condition !== "text" || p.expectedText !== void 0, {
133585
+ }).strict().refine((p) => p.condition !== "text" || p.expectedText !== void 0, {
133516
133586
  message: "condition `text` requires expectedText",
133517
133587
  path: ["expectedText"]
133518
133588
  });
@@ -133935,7 +134005,7 @@ var debuggerConnectTool = {
133935
134005
  },
133936
134006
  description: `Connect to a JS runtime CDP debugger.
133937
134007
  iOS / Android / Vega: connects to Metro's CDP endpoint on the given port. Chromium: re-uses the page CDP session opened by boot-device \u2014 port is ignored.
133938
- Returns connection info including port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, logicalDeviceId (absent on Vega), and isNewDebugger. If already connected, returns the existing connection.
134008
+ Returns connection info including port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, logicalDeviceId (absent on Vega), and isNewDebugger, plus a note naming the kept log file when the previous session ended because the app crashed. If already connected, returns the existing connection.
133939
134009
  Use when starting a debug session or before calling other debugger-* tools. Fails if the runtime is unreachable (Metro down, or Chromium CDP terminated).`,
133940
134010
  zodSchema: zodSchema31,
133941
134011
  capability: DEBUGGER_TOOL_CAPABILITY,
@@ -133944,11 +134014,10 @@ Use when starting a debug session or before calling other debugger-* tools. Fail
133944
134014
  }),
133945
134015
  async execute(services, params) {
133946
134016
  const api = services.debugger;
133947
- for (const id of new Set(
133948
- [params.device_id, api.logicalDeviceId].filter((v) => v !== void 0)
133949
- )) {
133950
- takeReapedSession("js-runtime-debugger", id);
133951
- }
134017
+ const reaped2 = takeReapedSessionAnyId("js-runtime-debugger", [
134018
+ params.device_id,
134019
+ api.logicalDeviceId
134020
+ ]);
133952
134021
  return {
133953
134022
  port: api.port,
133954
134023
  projectRoot: api.projectRoot,
@@ -133956,7 +134025,8 @@ Use when starting a debug session or before calling other debugger-* tools. Fail
133956
134025
  appName: api.appName,
133957
134026
  logicalDeviceId: api.logicalDeviceId,
133958
134027
  isNewDebugger: api.isNewDebugger,
133959
- connected: api.cdp.isConnected()
134028
+ connected: api.cdp.isConnected(),
134029
+ ...reaped2?.connectionLost ? { note: describeReapedSession(reaped2, "previous JS-runtime debugger session") } : {}
133960
134030
  };
133961
134031
  }
133962
134032
  };
@@ -135803,8 +135873,8 @@ function createDebuggerLogRegistryTool(registry2) {
135803
135873
  },
135804
135874
  description: `Get a summary of all console logs captured from the app's JS runtime.
135805
135875
  Returns the log file path, entry counts by level, and message clusters (grouped by similarity). Works against Hermes (iOS / Android / Vega) and V8 (Chromium).
135806
- Use when investigating warnings, errors, or unexpected output \u2014 call this first for an overview, then read the returned file for details. Returns empty stats if no log data has been captured yet \u2014 but check { note }, which is present only when the stats are empty BECAUSE a stop-all-simulator-servers tore the previous debugger session down and deleted its log file. Absent that note, empty really does mean the app has logged nothing.
135807
- When the debugger cannot be reached, this tool does not fail: it returns { status: "not_connected", reason, detail, guidance } with NO log file \u2014 follow the guidance (do not retry in a loop, and do not try to read a log file from this state). A "connected" result's stats may come from a session whose socket has since died \u2014 use debugger-status, not this tool, to judge debugger health.`,
135876
+ Use when investigating warnings, errors, or unexpected output \u2014 call this first for an overview, then read the returned file for details. Returns empty stats if no log data has been captured yet \u2014 but check { note }, which is present only when the stats are empty BECAUSE the previous debugger session ended: torn down (e.g. by stop-all-simulator-servers) with its log file deleted, or cut off by the app crashing with its log file kept at the path the note names. Absent that note, empty really does mean the app has logged nothing.
135877
+ When the debugger cannot be reached, this tool does not fail: it returns { status: "not_connected", reason, detail, guidance } with NO log file \u2014 follow the guidance (do not retry in a loop). Read a log file in this state only when a { note } names one kept from before the app crashed. A "connected" result's stats may come from a session whose socket has since died \u2014 use debugger-status, not this tool, to judge debugger health.`,
135808
135878
  zodSchema: zodSchema37,
135809
135879
  capability: DEBUGGER_TOOL_CAPABILITY,
135810
135880
  // Resolved manually in execute so a not-connected precondition becomes a
@@ -135825,16 +135895,11 @@ When the debugger cannot be reached, this tool does not fail: it returns { statu
135825
135895
  logicalDeviceId: api.logicalDeviceId
135826
135896
  };
135827
135897
  if (stats.totalEntries === 0) {
135828
- const aliases = [
135898
+ const reaped2 = takeReapedSessionAnyId("js-runtime-debugger", [
135829
135899
  canonicalDeviceId(params.device_id),
135830
135900
  params.device_id,
135831
135901
  api.logicalDeviceId
135832
- ].filter((id) => id !== void 0);
135833
- let reaped2;
135834
- for (const id of new Set(aliases)) {
135835
- const entry = takeReapedSession("js-runtime-debugger", id);
135836
- reaped2 ??= entry;
135837
- }
135902
+ ]);
135838
135903
  if (reaped2) response.note = describeReapedSession(reaped2, "JS-runtime debugger session");
135839
135904
  }
135840
135905
  return response;
@@ -135842,7 +135907,17 @@ When the debugger cannot be reached, this tool does not fail: it returns { statu
135842
135907
  const reason = classifyNotConnected(err);
135843
135908
  if (!reason) throw err;
135844
135909
  trackDebuggerOutcome("debugger-log-registry", reason, params, ctx);
135845
- return buildNotConnected(reason, err, params);
135910
+ const result = buildNotConnected(
135911
+ reason,
135912
+ err,
135913
+ params
135914
+ );
135915
+ const reaped2 = takeReapedSessionAnyId("js-runtime-debugger", [
135916
+ canonicalDeviceId(params.device_id),
135917
+ params.device_id
135918
+ ]);
135919
+ if (reaped2) result.note = describeReapedSession(reaped2, "JS-runtime debugger session");
135920
+ return result;
135846
135921
  }
135847
135922
  }
135848
135923
  };
@@ -136972,6 +137047,73 @@ Fails if the iOS ax-service predates the tree command; update argent.`,
136972
137047
  };
136973
137048
  }
136974
137049
 
137050
+ // ../tool-server/src/tools/foreground-app/index.ts
137051
+ init_zod();
137052
+ var zodSchema42 = external_exports.object({
137053
+ udid: external_exports.string().min(1).describe("Target device id from `list-devices`.")
137054
+ });
137055
+ var capability27 = {
137056
+ apple: { simulator: true },
137057
+ appleRemote: { simulator: true },
137058
+ android: { emulator: true, device: true, unknown: true }
137059
+ };
137060
+ async function readIosForegroundApp(registry2, device) {
137061
+ const ref = axServiceRef(device);
137062
+ const ax = await registry2.resolveService(ref.urn, ref.options);
137063
+ const { bundleId, name, alertVisible } = await ax.foregroundApp();
137064
+ return { bundleId, name, alertVisible };
137065
+ }
137066
+ async function readAndroidForegroundApp(registry2, device) {
137067
+ const ref = androidDevtoolsRef(device);
137068
+ const devtools = await registry2.resolveService(ref.urn, ref.options);
137069
+ const [capture, size] = await Promise.all([
137070
+ // The default settle, as ui-tree: free on a settled screen, and it keeps a
137071
+ // mid-transition window list (right after home or a launch) from naming the old app.
137072
+ devtools.getHierarchy({ maxDepth: 0, clearCache: true }),
137073
+ devtools.getScreenSize()
137074
+ ]);
137075
+ const tree = adaptAndroidTree({ ...capture, truncated: false }, size);
137076
+ return { bundleId: tree.foregroundApp, alertVisible: tree.alertVisible };
137077
+ }
137078
+ function createForegroundAppTool(registry2) {
137079
+ return {
137080
+ id: "foreground-app",
137081
+ interaction: {
137082
+ startedMsg: () => "Reading foreground app",
137083
+ completedMsg: () => "Read foreground app",
137084
+ failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to read foreground app: ${failureSignal2.error_code}`
137085
+ },
137086
+ description: `Read which app is in front, for SDK callers.
137087
+ Returns { bundleId, name, alertVisible }; under a system alert, bundleId is the app it covers.
137088
+ A field is unset when it is unknown.`,
137089
+ hideFromMcp: true,
137090
+ zodSchema: zodSchema42,
137091
+ capability: capability27,
137092
+ services: () => ({}),
137093
+ execute: dispatchByPlatform({
137094
+ toolId: "foreground-app",
137095
+ capability: capability27,
137096
+ ios: {
137097
+ requires: iosRequires,
137098
+ handler: async (_services, _params, device) => {
137099
+ if (await isTvOsSimulator(device.id)) {
137100
+ throw new UnsupportedOperationError("foreground-app", device, "tvOS");
137101
+ }
137102
+ return readIosForegroundApp(registry2, device);
137103
+ }
137104
+ },
137105
+ iosRemote: {
137106
+ requires: ["sim-remote"],
137107
+ handler: async (_services, _params, device) => readIosForegroundApp(registry2, device)
137108
+ },
137109
+ android: {
137110
+ requires: androidRequires,
137111
+ handler: async (_services, _params, device) => readAndroidForegroundApp(registry2, device)
137112
+ }
137113
+ })
137114
+ };
137115
+ }
137116
+
136975
137117
  // ../tool-server/src/tools/await-screen-idle/index.ts
136976
137118
  init_zod();
136977
137119
  init_device_info();
@@ -136980,7 +137122,7 @@ var AWAIT_SCREEN_IDLE_TOOL_ID = "await-screen-idle";
136980
137122
  var DEFAULT_TIMEOUT_MS4 = 3e3;
136981
137123
  var DEFAULT_POLL_INTERVAL_MS2 = 200;
136982
137124
  var DEFAULT_MIN_STABLE_MS = 250;
136983
- var zodSchema42 = external_exports.object({
137125
+ var zodSchema43 = external_exports.object({
136984
137126
  udid: external_exports.string().min(1).describe("Target device id from `list-devices` (iOS UDID, Android serial, or Chromium id)."),
136985
137127
  timeoutMs: external_exports.number().int().positive().max(12e4).optional().describe(
136986
137128
  `Max time to wait for the screen to settle before giving up (default ${DEFAULT_TIMEOUT_MS4}).`
@@ -136989,8 +137131,8 @@ var zodSchema42 = external_exports.object({
136989
137131
  minStableMs: external_exports.number().int().min(0).max(1e4).optional().describe(
136990
137132
  `The screen must hold the same content for at least this long to count as settled (default ${DEFAULT_MIN_STABLE_MS}).`
136991
137133
  )
136992
- });
136993
- var capability27 = {
137134
+ }).strict();
137135
+ var capability28 = {
136994
137136
  apple: { simulator: true, device: true },
136995
137137
  appleRemote: { simulator: true },
136996
137138
  android: { emulator: true, device: true, unknown: true },
@@ -137037,8 +137179,8 @@ ${DEFAULT_TIMEOUT_MS4}ms) is reached. Returns { settled, waitedMs, polls } \u201
137037
137179
  still before the timeout. Use after a launch/navigation to wait for the UI to render before screenshotting or tapping.`,
137038
137180
  searchHint: "wait until screen settles idle stable stops changing animation transition rendered ready before screenshot",
137039
137181
  longRunning: true,
137040
- zodSchema: zodSchema42,
137041
- capability: capability27,
137182
+ zodSchema: zodSchema43,
137183
+ capability: capability28,
137042
137184
  services: (params) => {
137043
137185
  const device = resolveDevice(params.udid);
137044
137186
  if (device.platform === "chromium") {
@@ -137048,7 +137190,7 @@ still before the timeout. Use after a launch/navigation to wait for the UI to re
137048
137190
  },
137049
137191
  async execute(services, params, ctx) {
137050
137192
  const device = resolveDevice(params.udid);
137051
- assertSupported(AWAIT_SCREEN_IDLE_TOOL_ID, capability27, device);
137193
+ assertSupported(AWAIT_SCREEN_IDLE_TOOL_ID, capability28, device);
137052
137194
  if (device.platform === "ios") await ensureDeps(iosRequires);
137053
137195
  else if (device.platform === "ios-remote") await ensureDeps(["sim-remote"]);
137054
137196
  else if (device.platform === "android") await ensureDeps(androidRequires);
@@ -137135,7 +137277,7 @@ function bootstrapFailureMessage(bootstrap) {
137135
137277
  // ../tool-server/src/tools/profiler/react/react-profiler-start.ts
137136
137278
  var NO_DEVTOOLS_HOOK_ERROR = "React DevTools hook (__REACT_DEVTOOLS_GLOBAL_HOOK__) is not present in this app's JavaScript runtime. React profiling requires a development build with React DevTools enabled. Likely causes: (1) the app is a release/production build \u2014 DevTools is stripped to reduce bundle size; (2) you connected to the wrong JS runtime; (3) this isn't a React (Native) app. Fix: rebuild in debug/dev mode (e.g. `npx react-native run-ios` without --configuration Release; for Expo, run a dev client). Once the app is running with DevTools attached, call react-profiler-start again.";
137137
137279
  var NO_RENDERERS_ATTACHED_ERROR = "React DevTools hook is present but no React renderer has registered yet. The hook is loaded but no fiber renderer has attached \u2014 typically because the app has not committed its first render, or the DevTools backend has not been bootstrapped on a bridgeless React Native dev build. Fix: ensure the app has rendered (interact with it once, then retry); if it stays empty, call react-profiler-start first \u2014 it will attempt to attach the DevTools backend automatically.";
137138
- var zodSchema43 = external_exports.object({
137280
+ var zodSchema44 = external_exports.object({
137139
137281
  port: metroPortField,
137140
137282
  device_id: external_exports.string().describe(
137141
137283
  "Device id from list-devices \u2014 the SAME id you passed to debugger-connect (iOS simulator UDID or Android serial)."
@@ -137167,7 +137309,7 @@ Before calling this, ask the user if they also want native profiling (native-pro
137167
137309
  After starting, ask the user to perform the interaction to profile, then call react-profiler-stop.
137168
137310
  Returns { started_at, startedAtEpochMs, hermes_version, detected_architecture } on success, or the already_running payload described above.
137169
137311
  Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot be established.`,
137170
- zodSchema: zodSchema43,
137312
+ zodSchema: zodSchema44,
137171
137313
  capability: RN_ONLY_TOOL_CAPABILITY,
137172
137314
  services: () => ({}),
137173
137315
  async execute(_services, params) {
@@ -137438,7 +137580,7 @@ async function readCommitTree(path53) {
137438
137580
  }
137439
137581
 
137440
137582
  // ../tool-server/src/tools/profiler/react/react-profiler-stop.ts
137441
- var zodSchema44 = external_exports.object({
137583
+ var zodSchema45 = external_exports.object({
137442
137584
  port: metroPortField,
137443
137585
  device_id: external_exports.string().describe(
137444
137586
  "Device id from list-devices \u2014 the SAME id you passed to debugger-connect (iOS simulator UDID or Android serial)."
@@ -137527,7 +137669,7 @@ Call react-profiler-start first, then exercise the app, then call this.
137527
137669
  Returns { duration_ms, sample_count, fiber_renders_captured, total_react_commits, hot_commit_indices } summarizing the session.
137528
137670
  When any commit had fibers whose display name could not be resolved at stop time (typically transient components like modals/tooltips/animations that unmounted before stop), the response also includes { unattributed_ms, unattributed_fiber_count, unattributed_commit_count } \u2014 these quantify how much work is not accounted for in the per-component breakdown (the per-commit duration itself remains correct).
137529
137671
  Fails if no active profiling session exists or the CDP connection was lost during recording.`,
137530
- zodSchema: zodSchema44,
137672
+ zodSchema: zodSchema45,
137531
137673
  capability: RN_ONLY_TOOL_CAPABILITY,
137532
137674
  services: () => ({}),
137533
137675
  async execute(_services, params) {
@@ -137752,7 +137894,7 @@ Fails if no active profiling session exists or the CDP connection was lost durin
137752
137894
 
137753
137895
  // ../tool-server/src/tools/profiler/react/react-profiler-status.ts
137754
137896
  init_zod();
137755
- var zodSchema45 = external_exports.object({
137897
+ var zodSchema46 = external_exports.object({
137756
137898
  port: metroPortField,
137757
137899
  device_id: external_exports.string().describe(
137758
137900
  "Device logicalDeviceId from debugger-connect (iOS simulator UDID or Android logicalDeviceId)."
@@ -137767,7 +137909,7 @@ function createReactProfilerStatusTool(registry2) {
137767
137909
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to check React profiler: ${failureSignal2.error_code}`
137768
137910
  },
137769
137911
  description: `Check the state of the React profiler session without side effects. Use after an interruption (debugger disconnect, unexpected error, agent pause) to decide whether to continue with react-profiler-stop, start a new session, or reconnect the debugger. Ownership is verified server-side against this tool-server's in-memory session \u2014 no token-threading is required. Returns { session_status, is_running, current_owner, \u2026 }. If this tool-server process restarted after react-profiler-start, status will report 'taken_over'; use react-profiler-start { force: true } to reclaim.`,
137770
- zodSchema: zodSchema45,
137912
+ zodSchema: zodSchema46,
137771
137913
  // RN-only: companion to react-profiler-start.
137772
137914
  capability: RN_ONLY_TOOL_CAPABILITY,
137773
137915
  services: () => ({}),
@@ -139381,7 +139523,7 @@ var annotationSchema = external_exports.object({
139381
139523
  ),
139382
139524
  label: external_exports.string().describe("Description of the action performed")
139383
139525
  });
139384
- var zodSchema46 = external_exports.object({
139526
+ var zodSchema47 = external_exports.object({
139385
139527
  port: metroPortField,
139386
139528
  device_id: external_exports.string().describe(
139387
139529
  "Device logicalDeviceId from debugger-connect (iOS simulator UDID or Android logicalDeviceId)."
@@ -139414,7 +139556,7 @@ where tapTimestampMs is the timestampMs returned by the tap/swipe tool and start
139414
139556
  is returned by react-profiler-start.
139415
139557
  Use when the profiling session is complete and you need to interpret the collected data.
139416
139558
  Fails if react-profiler-stop has not been called or no profiling data is stored.`,
139417
- zodSchema: zodSchema46,
139559
+ zodSchema: zodSchema47,
139418
139560
  // RN-only: reads commit data captured via the React DevTools backend, which
139419
139561
  // Chromium does not have.
139420
139562
  capability: RN_ONLY_TOOL_CAPABILITY,
@@ -139551,7 +139693,7 @@ Fails if react-profiler-stop has not been called or no profiling data is stored.
139551
139693
  // ../tool-server/src/tools/profiler/react/react-profiler-component-source.ts
139552
139694
  init_zod();
139553
139695
  var import_fs6 = require("fs");
139554
- var zodSchema47 = external_exports.object({
139696
+ var zodSchema48 = external_exports.object({
139555
139697
  component_name: external_exports.string().describe("Name of the React component to look up"),
139556
139698
  project_root: external_exports.string().describe("Absolute path to the RN project root")
139557
139699
  });
@@ -139569,7 +139711,7 @@ var reactProfilerComponentSourceTool = {
139569
139711
  Call this per-finding after react-profiler-analyze to inspect source before proposing a fix.
139570
139712
  Returns found: false if the component is not found in user-owned code (e.g. lives in node_modules).
139571
139713
  When several files define a component with the same name (e.g. platform variants like List.tsx and List.web.tsx), returns the primary match and lists the rest under otherMatches[] (file/line/col) \u2014 check it before assuming the returned file is the one you meant.`,
139572
- zodSchema: zodSchema47,
139714
+ zodSchema: zodSchema48,
139573
139715
  // Declared so the tool catalogue groups this with the other react-profiler-*
139574
139716
  // tools; the HTTP gate itself is a no-op here, as there is no device arg to
139575
139717
  // inspect.
@@ -139625,7 +139767,7 @@ When several files define a component with the same name (e.g. platform variants
139625
139767
  // ../tool-server/src/tools/profiler/react/react-profiler-cpu-summary.ts
139626
139768
  init_zod();
139627
139769
  init_src2();
139628
- var zodSchema48 = external_exports.object({
139770
+ var zodSchema49 = external_exports.object({
139629
139771
  port: metroPortField,
139630
139772
  device_id: external_exports.string().describe(
139631
139773
  "Device logicalDeviceId from debugger-connect (iOS simulator UDID or Android logicalDeviceId)."
@@ -139707,7 +139849,7 @@ Use when you specifically need to investigate JS CPU hotspots that are NOT tied
139707
139849
  Call react-profiler-stop first. Reads directly from the stored cpuProfile.
139708
139850
  Returns a markdown table of the top hotspot functions with self-time, total-time, and location.
139709
139851
  Fails if react-profiler-stop has not been called or no CPU profile is stored.`,
139710
- zodSchema: zodSchema48,
139852
+ zodSchema: zodSchema49,
139711
139853
  // RN-only: reads a Hermes CPU profile; Chromium's V8 sample format differs.
139712
139854
  capability: RN_ONLY_TOOL_CAPABILITY,
139713
139855
  services: () => ({}),
@@ -139803,7 +139945,7 @@ function renderMarkdownTable2(entries) {
139803
139945
  );
139804
139946
  return [header, sep5, ...rows].join("\n");
139805
139947
  }
139806
- var zodSchema49 = external_exports.object({
139948
+ var zodSchema50 = external_exports.object({
139807
139949
  port: metroPortField,
139808
139950
  device_id: external_exports.string().describe(
139809
139951
  "Device logicalDeviceId from debugger-connect (iOS simulator UDID or Android logicalDeviceId)."
@@ -139821,7 +139963,7 @@ var reactProfilerRendersTool = {
139821
139963
  Returns a markdown table of the top re-rendering components. No profiling session required \u2014 works on a live connected app.
139822
139964
  Use when you want a quick snapshot of render counts without a full profiling session.
139823
139965
  Fails if the React DevTools hook is not present in the runtime or the app is not connected.`,
139824
- zodSchema: zodSchema49,
139966
+ zodSchema: zodSchema50,
139825
139967
  // RN-only: queries the React DevTools backend hook on the live runtime.
139826
139968
  capability: RN_ONLY_TOOL_CAPABILITY,
139827
139969
  services: (params) => ({
@@ -139978,7 +140120,7 @@ function buildFiberTreeScript(maxDepth, filter) {
139978
140120
  }
139979
140121
  })()`;
139980
140122
  }
139981
- var zodSchema50 = external_exports.object({
140123
+ var zodSchema51 = external_exports.object({
139982
140124
  port: metroPortField,
139983
140125
  device_id: external_exports.string().describe(
139984
140126
  "Device logicalDeviceId from debugger-connect (iOS simulator UDID or Android logicalDeviceId)."
@@ -139997,7 +140139,7 @@ var reactProfilerFiberTreeTool = {
139997
140139
  Use when tracing ancestry of a library component or checking for useMemoCache hook (confirms React Compiler is active on a component).
139998
140140
  Returns a nested JSON tree of fiber nodes with name, tag, actualDuration, selfBaseDuration, and children.
139999
140141
  Fails if the React DevTools hook is not present or no fiber roots have been committed yet.`,
140000
- zodSchema: zodSchema50,
140142
+ zodSchema: zodSchema51,
140001
140143
  // RN-only: walks the fiber tree via the React DevTools backend hook.
140002
140144
  capability: RN_ONLY_TOOL_CAPABILITY,
140003
140145
  services: (params) => ({
@@ -143795,7 +143937,7 @@ function metroDeviceIdParam(description) {
143795
143937
  }
143796
143938
 
143797
143939
  // ../tool-server/src/tools/profiler/native-profiler/native-profiler-start.ts
143798
- var zodSchema51 = external_exports.object({
143940
+ var zodSchema52 = external_exports.object({
143799
143941
  device_id: metroDeviceIdParam(
143800
143942
  "Target device id from `list-devices` (iOS UDID or Android serial)."
143801
143943
  ),
@@ -143809,7 +143951,7 @@ var zodSchema51 = external_exports.object({
143809
143951
  "iOS-only. When true, cold-launches the app under the profiler with Malloc Stack Logging enabled so memory leaks carry an allocation backtrace (responsible frame + library). Without it, leaks are still detected but unattributable \u2014 Instruments reports '<Call stack limit reached>'. Trade-offs: this RESTARTS the app (current state is lost), adds memory/CPU overhead, and makes the app noticeably slow to launch (every startup allocation records a backtrace), so leave it off for pure CPU/hang profiling. Requires a non-degraded Xcode: on Xcode 26.4 and later the cold-launch path is broken, so the call is rejected up front (re-run without the flag, or set ARGENT_IOS_CAPTURE=device to override if the device path works on your host). ARGENT_IOS_CAPTURE=all-processes \u2014 e.g. exported globally for the normal capture path \u2014 also rejects this flag up front, since that fallback cannot cold-launch; unset it (or set it to device) first. Ignored on Android."
143810
143952
  )
143811
143953
  });
143812
- var capability28 = {
143954
+ var capability29 = {
143813
143955
  apple: { simulator: true },
143814
143956
  android: { emulator: true, device: true, unknown: true }
143815
143957
  };
@@ -143820,21 +143962,21 @@ var nativeProfilerStartTool = {
143820
143962
  completedMsg: () => "Started native profiler",
143821
143963
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to start native profiler: ${failureSignal2.error_code}`
143822
143964
  },
143823
- capability: capability28,
143965
+ capability: capability29,
143824
143966
  description: `Start native profiling on a booted device. iOS: Instruments via xctrace (CPU, hangs, memory). Android: Perfetto (CPU, jank, RSS-growth weak signal).
143825
143967
  Auto-detects the running app process unless app_process is explicitly provided.
143826
143968
  After starting, let the user interact with the app, then call native-profiler-stop.
143827
143969
  Use when you want to capture native CPU, hang, and memory data for a running app.
143828
143970
  Returns { status, pid, traceFile } confirming the recording has started.
143829
143971
  Fails if no app is running on the device, or the profiler cannot attach to the process.`,
143830
- zodSchema: zodSchema51,
143972
+ zodSchema: zodSchema52,
143831
143973
  services: (params) => ({
143832
143974
  session: nativeProfilerSessionRef(resolveDevice(params.device_id))
143833
143975
  }),
143834
143976
  async execute(services, params) {
143835
143977
  const api = services.session;
143836
143978
  const device = resolveDevice(params.device_id);
143837
- assertSupported("native-profiler-start", capability28, device);
143979
+ assertSupported("native-profiler-start", capability29, device);
143838
143980
  if (api.platform === "ios") {
143839
143981
  await ensureDeps(["xcrun"]);
143840
143982
  return startNativeProfilerIos(api, params);
@@ -143847,12 +143989,12 @@ Fails if no app is running on the device, or the profiler cannot attach to the p
143847
143989
  // ../tool-server/src/tools/profiler/native-profiler/native-profiler-stop.ts
143848
143990
  init_zod();
143849
143991
  init_device_info();
143850
- var zodSchema52 = external_exports.object({
143992
+ var zodSchema53 = external_exports.object({
143851
143993
  device_id: metroDeviceIdParam(
143852
143994
  "Target device id from `list-devices` (iOS UDID or Android serial)."
143853
143995
  )
143854
143996
  });
143855
- var capability29 = {
143997
+ var capability30 = {
143856
143998
  apple: { simulator: true },
143857
143999
  android: { emulator: true, device: true, unknown: true }
143858
144000
  };
@@ -143880,7 +144022,7 @@ var nativeProfilerStopTool = {
143880
144022
  completedMsg: ({ result }) => `Saved native profile ${result.traceFile.filename}`,
143881
144023
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to stop native profiler: ${failureSignal2.error_code}`
143882
144024
  },
143883
- capability: capability29,
144025
+ capability: capability30,
143884
144026
  // Packaging plus the export passes routinely exceed the 30s MCP fetch timeout.
143885
144027
  longRunning: true,
143886
144028
  description: `Stop native profiling and export trace data.
@@ -143890,14 +144032,14 @@ Call native-profiler-start first.
143890
144032
  Use when the user has finished the interaction to profile and you need to export the trace.
143891
144033
  Returns { traceFile, exportedFiles, exportDiagnostics? }; traceFile is the raw trace bundle and exportedFiles the exports, all downloadable artifacts materialized to local paths.
143892
144034
  Fails if no active native-profiler-start session exists for the given device_id.`,
143893
- zodSchema: zodSchema52,
144035
+ zodSchema: zodSchema53,
143894
144036
  services: (params) => ({
143895
144037
  session: nativeProfilerSessionRef(resolveDevice(params.device_id))
143896
144038
  }),
143897
144039
  async execute(services, params, ctx) {
143898
144040
  const api = services.session;
143899
144041
  const device = resolveDevice(params.device_id);
143900
- assertSupported("native-profiler-stop", capability29, device);
144042
+ assertSupported("native-profiler-stop", capability30, device);
143901
144043
  if (api.platform === "ios") {
143902
144044
  await ensureDeps(["xcrun"]);
143903
144045
  const ios = await stopNativeProfilerIos(api);
@@ -143925,12 +144067,12 @@ Fails if no active native-profiler-start session exists for the given device_id.
143925
144067
  // ../tool-server/src/tools/profiler/native-profiler/native-profiler-analyze.ts
143926
144068
  init_zod();
143927
144069
  init_device_info();
143928
- var zodSchema53 = external_exports.object({
144070
+ var zodSchema54 = external_exports.object({
143929
144071
  device_id: metroDeviceIdParam(
143930
144072
  "Target device id from `list-devices` (iOS UDID or Android serial)."
143931
144073
  )
143932
144074
  });
143933
- var capability30 = {
144075
+ var capability31 = {
143934
144076
  apple: { simulator: true },
143935
144077
  android: { emulator: true, device: true, unknown: true }
143936
144078
  };
@@ -143941,7 +144083,7 @@ var nativeProfilerAnalyzeTool = {
143941
144083
  completedMsg: () => "Analyzed native profile",
143942
144084
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to analyze native profile: ${failureSignal2.error_code}`
143943
144085
  },
143944
- capability: capability30,
144086
+ capability: capability31,
143945
144087
  // Parsing a trace from a recording up to RECORDING_CAP_MS long routinely exceeds
143946
144088
  // the 30s MCP fetch timeout, and an aborted call is replayed, not cancelled.
143947
144089
  longRunning: true,
@@ -143954,14 +144096,14 @@ profiler-stack-query for hang stacks, CPU context, leak details) or implement fi
143954
144096
  Call native-profiler-stop first to export the trace data.
143955
144097
  Use when you need to interpret a completed native profiling recording.
143956
144098
  Fails if native-profiler-stop has not been called first to export trace data.`,
143957
- zodSchema: zodSchema53,
144099
+ zodSchema: zodSchema54,
143958
144100
  services: (params) => ({
143959
144101
  session: nativeProfilerSessionRef(resolveDevice(params.device_id))
143960
144102
  }),
143961
144103
  async execute(services, params, ctx) {
143962
144104
  const api = services.session;
143963
144105
  const device = resolveDevice(params.device_id);
143964
- assertSupported("native-profiler-analyze", capability30, device);
144106
+ assertSupported("native-profiler-analyze", capability31, device);
143965
144107
  let result;
143966
144108
  if (api.platform === "ios") {
143967
144109
  await ensureDeps(["xcrun"]);
@@ -145024,7 +145166,7 @@ var DEFAULT_TIME_LIMIT_SECONDS = 180;
145024
145166
  var MAX_TIME_LIMIT_SECONDS = 600;
145025
145167
  var POINTER_TRAIL_LENGTH = 8;
145026
145168
  var POINTER_REQUEST_TIMEOUT_MS = 2e3;
145027
- var zodSchema54 = external_exports.object({
145169
+ var zodSchema55 = external_exports.object({
145028
145170
  udid: external_exports.string().describe("Target device id from `list-devices` (iOS Simulator UDID or Android serial)."),
145029
145171
  timeLimitSeconds: external_exports.number().int().min(1).max(MAX_TIME_LIMIT_SECONDS).optional().describe(
145030
145172
  `Auto-stop cap in seconds (default ${DEFAULT_TIME_LIMIT_SECONDS}, max ${MAX_TIME_LIMIT_SECONDS}). Set it to slightly more than the interaction you plan to capture.`
@@ -145036,7 +145178,7 @@ var zodSchema54 = external_exports.object({
145036
145178
  "Default true. Draw simulator-server's touch visualizer into the recording: a pulse marks each tap, a comet trail follows swipes and drags, and paired markers show two-finger pinch/rotate, so the video makes clear where every interaction landed. Set false to record the raw screen with no overlay."
145037
145179
  )
145038
145180
  });
145039
- var capability31 = {
145181
+ var capability32 = {
145040
145182
  apple: { simulator: true },
145041
145183
  android: { emulator: true, device: true, unknown: true }
145042
145184
  };
@@ -145048,7 +145190,7 @@ function createScreenRecordingStartTool(registry2) {
145048
145190
  completedMsg: () => "Started screen recording",
145049
145191
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to start screen recording: ${failureSignal2.error_code}`
145050
145192
  },
145051
- capability: capability31,
145193
+ capability: capability32,
145052
145194
  description: `Start recording the device screen to a video file (h264 mp4, 30fps at the device's native resolution).
145053
145195
  By default stretches where the screen does not change are trimmed out (see trimStatic), so a long session with only brief activity comes back as a short clip instead of minutes of dead air.
145054
145196
  By default every tap, swipe, drag, pinch and rotate is drawn into the video as an on-screen touch marker (see showTouches), so the recording shows where each interaction landed.
@@ -145057,7 +145199,7 @@ Use when the user wants a video of an interaction, animation, or app behavior \u
145057
145199
  Returns { status: "recording", timeLimitSeconds, outputFile } \u2014 the video is retrieved later by \`screen-recording-stop\`, not by reading outputFile directly.
145058
145200
  Fails if a recording is already running on the device, the device is not booted, ffmpeg is not installed, or the platform cannot be recorded (tvOS, Chromium, Vega and remote simulators are unsupported).`,
145059
145201
  searchHint: "record video screen capture movie mp4 start filming screencast",
145060
- zodSchema: zodSchema54,
145202
+ zodSchema: zodSchema55,
145061
145203
  // Resolved inside execute, not declared eagerly: a tvOS udid classifies as
145062
145204
  // iOS by shape, so an eager service would spawn simulator-server for a
145063
145205
  // device it cannot drive and hang on its ready timeout (as in `screenshot`).
@@ -145067,7 +145209,7 @@ Fails if a recording is already running on the device, the device is not booted,
145067
145209
  async execute(services, params) {
145068
145210
  const api = services.session;
145069
145211
  const device = resolveDevice(params.udid);
145070
- assertSupported("screen-recording-start", capability31, device);
145212
+ assertSupported("screen-recording-start", capability32, device);
145071
145213
  if (device.platform === "ios" && await isTvOsSimulator(params.udid)) {
145072
145214
  throw new FailureError(
145073
145215
  `Screen recording is not supported on tvOS simulators (device ${params.udid}).`,
@@ -145156,11 +145298,11 @@ function makePointerControl(simulator) {
145156
145298
  var import_node_path22 = require("node:path");
145157
145299
  init_zod();
145158
145300
  init_device_info();
145159
- var zodSchema55 = external_exports.object({
145301
+ var zodSchema56 = external_exports.object({
145160
145302
  udid: external_exports.string().describe("Target device id from `list-devices` (iOS Simulator UDID or Android serial).")
145161
145303
  });
145162
145304
  var RECORDINGS_DIR = ".argent/recordings";
145163
- var capability32 = {
145305
+ var capability33 = {
145164
145306
  apple: { simulator: true },
145165
145307
  android: { emulator: true, device: true, unknown: true }
145166
145308
  };
@@ -145171,21 +145313,21 @@ var screenRecordingStopTool = {
145171
145313
  completedMsg: ({ result }) => `Saved screen recording ${result.video.filename}`,
145172
145314
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to stop screen recording: ${failureSignal2.error_code}`
145173
145315
  },
145174
- capability: capability32,
145316
+ capability: capability33,
145175
145317
  description: `Stop the screen recording started by \`screen-recording-start\` and retrieve the video: frame capture ends and ffmpeg finalizes the mp4.
145176
145318
  Also retrieves the video when the recording already ended on its own (time limit reached, capture process died) \u2014 call it even after the cap fired.
145177
145319
  Use when the interaction being captured is finished, or a tool-result note reminds you a recording is still running.
145178
145320
  Returns { video, durationMs, wallClockMs?, trimmedMs?, panelSwitches?, warning? }; video is a downloadable artifact materialized to a local path. When static-frame trimming removed dead air, durationMs is the trimmed video length and wallClockMs/trimmedMs report the real duration and how much was cut. On a foldable simulator, the recording follows the panel that shows the UI. panelSwitches gives the number of panel changes. The video keeps the size of the first panel. warning is set when argent could not find that panel during the recording.
145179
145321
  Fails if no recording (running or finished-but-unretrieved) exists for the given udid.`,
145180
145322
  searchHint: "stop end finish screen recording video capture save retrieve",
145181
- zodSchema: zodSchema55,
145323
+ zodSchema: zodSchema56,
145182
145324
  services: (params) => ({
145183
145325
  session: screenRecordingSessionRef(resolveDevice(params.udid))
145184
145326
  }),
145185
145327
  async execute(services, params, ctx) {
145186
145328
  const api = services.session;
145187
145329
  const device = resolveDevice(params.udid);
145188
- assertSupported("screen-recording-stop", capability32, device);
145330
+ assertSupported("screen-recording-stop", capability33, device);
145189
145331
  const stopped = await stopCapture(api);
145190
145332
  const artifacts = requireArtifacts(ctx);
145191
145333
  const video = await artifacts.register({
@@ -145217,7 +145359,7 @@ var timeWindowSchema = external_exports.object({
145217
145359
  "End of window in ms since profiling started \u2014 the same clock profiler-commit-query prints"
145218
145360
  )
145219
145361
  });
145220
- var zodSchema56 = external_exports.object({
145362
+ var zodSchema57 = external_exports.object({
145221
145363
  port: metroPortField,
145222
145364
  device_id: metroDeviceIdParam(
145223
145365
  "Device logicalDeviceId from debugger-connect (iOS simulator UDID or Android logicalDeviceId)."
@@ -145506,7 +145648,7 @@ Every table states how many samples it covers and how much of that was idle.
145506
145648
  Use when investigating JS CPU hotspots or correlating CPU cost with specific components.
145507
145649
  Returns a markdown table of CPU hotspots, call tree, or per-component CPU breakdown.
145508
145650
  Fails if no CPU profile is stored \u2014 run react-profiler-stop first.`,
145509
- zodSchema: zodSchema56,
145651
+ zodSchema: zodSchema57,
145510
145652
  // RN-only: reads Hermes-format CPU profiles; Chromium's V8 sample format differs.
145511
145653
  capability: RN_ONLY_TOOL_CAPABILITY,
145512
145654
  services: () => ({}),
@@ -145592,7 +145734,7 @@ var timeRangeSchema = external_exports.object({
145592
145734
  "End of range in ms since profiling started \u2014 the same clock profiler-commit-query prints"
145593
145735
  )
145594
145736
  });
145595
- var zodSchema57 = external_exports.object({
145737
+ var zodSchema58 = external_exports.object({
145596
145738
  port: metroPortField,
145597
145739
  device_id: metroDeviceIdParam(
145598
145740
  "Device logicalDeviceId from debugger-connect (iOS simulator UDID or Android logicalDeviceId)."
@@ -145865,7 +146007,7 @@ Modes:
145865
146007
  Use when drilling into specific components or time windows after react-profiler-analyze.
145866
146008
  Returns a markdown table or tree of commit data matching the requested mode.
145867
146009
  Fails if react-profiler-stop has not been called or no commit data is stored.`,
145868
- zodSchema: zodSchema57,
146010
+ zodSchema: zodSchema58,
145869
146011
  // Reads React commit data captured via the React DevTools backend.
145870
146012
  capability: RN_ONLY_TOOL_CAPABILITY,
145871
146013
  services: () => ({}),
@@ -145936,7 +146078,7 @@ Fails if react-profiler-stop has not been called or no commit data is stored.`,
145936
146078
  init_zod();
145937
146079
  init_src2();
145938
146080
  init_device_info();
145939
- var zodSchema58 = external_exports.object({
146081
+ var zodSchema59 = external_exports.object({
145940
146082
  device_id: metroDeviceIdParam("iOS Simulator UDID or Android serial."),
145941
146083
  mode: external_exports.enum(["hang_stacks", "function_callers", "thread_breakdown", "leak_stacks"]).describe(
145942
146084
  "Query mode: hang_stacks (full CPU context during a hang), function_callers (who calls a native function), thread_breakdown (CPU split by thread), leak_stacks (leak details by object type)"
@@ -146254,7 +146396,7 @@ Modes:
146254
146396
  Use when drilling into native hang stacks, thread CPU breakdown, or memory leaks after native-profiler-analyze.
146255
146397
  Returns a markdown report with native call stacks, thread weights, or leak details for the selected mode.
146256
146398
  Fails if native-profiler-analyze has not been run or no parsed trace data is in memory.`,
146257
- zodSchema: zodSchema58,
146399
+ zodSchema: zodSchema59,
146258
146400
  // No chromium entry: it has no native trace capture.
146259
146401
  capability: {
146260
146402
  apple: { simulator: true },
@@ -146324,7 +146466,7 @@ function buildPerfettoAnchor(wallClockStartMs) {
146324
146466
  }
146325
146467
 
146326
146468
  // ../tool-server/src/tools/profiler/combined/profiler-combined-report.ts
146327
- var zodSchema59 = external_exports.object({
146469
+ var zodSchema60 = external_exports.object({
146328
146470
  port: metroPortField,
146329
146471
  device_id: metroDeviceIdParam("iOS Simulator/device UDID or Android serial")
146330
146472
  });
@@ -146341,7 +146483,7 @@ Requires both react-profiler-analyze and native-profiler-analyze to have been ca
146341
146483
  Call this tool when both profilers were run in parallel on the same session.
146342
146484
  Returns a markdown report correlating hangs with React commits, memory leaks, and investigation hints.
146343
146485
  Fails if either react-profiler-analyze or native-profiler-analyze has not been called first.`,
146344
- zodSchema: zodSchema59,
146486
+ zodSchema: zodSchema60,
146345
146487
  // iOS reads xctrace output; Android re-queries the Perfetto .pftrace via
146346
146488
  // loadAndroidCombinedData. Chromium has no native trace capture.
146347
146489
  capability: {
@@ -146665,7 +146807,7 @@ function assertSafeSessionId(sessionId) {
146665
146807
  );
146666
146808
  }
146667
146809
  }
146668
- var zodSchema60 = external_exports.object({
146810
+ var zodSchema61 = external_exports.object({
146669
146811
  mode: external_exports.enum(["list", "load_react", "load_native"]).describe(
146670
146812
  "list: show available sessions on disk. load_react: load a React profiler session into memory for query tools. load_native: re-parse native profiler XML files (xctrace on iOS) into memory for query tools."
146671
146813
  ),
@@ -147026,7 +147168,7 @@ Modes:
147026
147168
  For Android .pftrace restores, pass app_process for older sessions that do not have a metadata sidecar.
147027
147169
  Returns a summary of the loaded session or a session list for the list mode.
147028
147170
  Fails if the session_id is not found or required XML files are missing from disk.`,
147029
- zodSchema: zodSchema60,
147171
+ zodSchema: zodSchema61,
147030
147172
  // The Hermes, xctrace and perfetto formats this loads have no Chromium
147031
147173
  // equivalent; the gate fails at the call site, not inside the trace parser.
147032
147174
  capability: RN_ONLY_TOOL_CAPABILITY,
@@ -147155,7 +147297,7 @@ function unnameableSessionUrns(urns) {
147155
147297
  }
147156
147298
 
147157
147299
  // ../tool-server/src/tools/simulator/stop-simulator-server.ts
147158
- var zodSchema61 = external_exports.object({
147300
+ var zodSchema62 = external_exports.object({
147159
147301
  udid: external_exports.string().describe(
147160
147302
  "Target device id (iOS UDID, Android serial, or Chromium id) whose transport session to stop"
147161
147303
  )
@@ -147169,7 +147311,7 @@ function createStopSimulatorServerTool(registry2) {
147169
147311
  failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to stop simulator server for ${params.udid}: ${failureSignal2.error_code}`
147170
147312
  },
147171
147313
  description: `Stop the transport session for a specific device (iOS simulator / Android: simulator-server process; physical iOS: the on-device runner; Chromium: CDP WebSocket) and free its resources; on a TV target it also reaps that device's TV-control daemons. Use when you are done interacting with one device but want to keep others running, or to restart a wedged transport. On iOS / Android / TV it deliberately leaves this device's native-devtools, accessibility, profiler and debugger services running - to drain those as well, use stop-all-simulator-servers with \`devices\`. On CHROMIUM that does not hold: the JS-runtime debugger declares the CDP session as a dependency, so stopping the transport cascades to it and its captured console history goes with it - reconnect with debugger-connect afterwards. Returns { stopped, udid }. Fails silently if no session is open for the given id.`,
147172
- zodSchema: zodSchema61,
147314
+ zodSchema: zodSchema62,
147173
147315
  services: () => ({}),
147174
147316
  async execute(_services, params) {
147175
147317
  const udid = params.udid;
@@ -147200,7 +147342,7 @@ function createStopSimulatorServerTool(registry2) {
147200
147342
  init_zod();
147201
147343
  init_src2();
147202
147344
  init_external_devices();
147203
- var zodSchema62 = external_exports.object({
147345
+ var zodSchema63 = external_exports.object({
147204
147346
  devices: external_exports.array(external_exports.string()).optional().describe(
147205
147347
  "Device ids (iOS UDID / Android serial / Chromium id) to scope the teardown to \u2014 pass the devices THIS session actually used. Omit only for a deliberate machine-wide cleanup: one tool-server serves every agent using this argent install, so an unscoped stop also kills devices another agent is mid-session on."
147206
147348
  )
@@ -147238,8 +147380,8 @@ function createStopAllSimulatorServersTool(registry2) {
147238
147380
  description: `Stop the services a device owns - simulator-server processes (iOS + Android), native devtools, the iOS accessibility service, TV-control daemons, Chromium CDP sessions, screen recordings, native profiler sessions, and JS-runtime debugger sessions along with the network inspectors and React profiler sessions that ride on them - freeing their spawned processes, sockets and ports. Call this when your session ends or the user says they are done.
147239
147381
  PASS \`devices\` with the device ids this session used \u2014 one tool-server serves every agent, subagent and CLI call using this argent install, and an unscoped call tears down THEIR devices too (a mid-recording devtools teardown degrades another agent's flow to brittle coordinate taps; that agent is warned, but its recorded steps are already the worse kind). Omit \`devices\` only when a machine-wide cleanup is what you actually want. Passing an EMPTY array scopes to nothing and stops nothing - it is not a way to ask for the machine-wide sweep.
147240
147382
  A JS-runtime debugger session is keyed by the id you called \`debugger-connect\` with. On a Metro serving two or more devices that id is not a udid or serial - connect refuses those and tells you to re-target with the \`logicalDeviceId\` it returns - so a scope built from \`list-devices\` ids cannot reach that session. Pass any such \`logicalDeviceId\` in \`devices\` ALONGSIDE the device id; { left_running } names the ones you missed.
147241
- Returns { stopped } - the URNs of the services that were actually live and got shut down; an ERROR node is disposed too but never appears there, so an empty \`stopped\` only means nothing was still running. { unmatched } lists supplied ids that own no service here, so a mistyped id - or a device NAME passed where an id was expected - does not read as a clean machine. It is NOT proof the id is wrong: a Vega device is driven through CLI/adb shell-outs, so one you only booted and drove with the remote registers no service and always lands here \u2014 as does a real device of any platform this session never started anything on. Present ONLY when \`devices\` was supplied AND at least one id matched nothing - absent on an unscoped call and when every id matched. Stopping the same device twice does not report it unmatched: ownership counts regardless of service state. { left_running } lists live debugger sessions (and the network inspectors / React profiler sessions riding on them) whose id no device scope can name - re-call with that id to reap them. { aborted: true } means the caller cancelled the request part-way, so the rest of the machine was left untouched and neither of the other two fields was computed. Past the schema - which rejects an unknown key outright, so the \`udids\` slip is an error rather than a silent machine-wide sweep - the call always succeeds; reaping nothing is a result, not a failure.`,
147242
- zodSchema: zodSchema62,
147383
+ Returns { stopped } - the URNs of the services that were actually live and got shut down; an ERROR node is disposed too but never appears there, so an empty \`stopped\` only means nothing was still running. { unmatched } lists supplied ids that own no service here, so a mistyped id - or a device NAME passed where an id was expected - does not read as a clean machine. It is NOT proof the id is wrong: a Vega device is driven through CLI/adb shell-outs, so one you only booted and drove with the remote registers no service and always lands here \u2014 as does a real device of any platform this session never started anything on. Present ONLY when \`devices\` was supplied AND at least one id matched nothing - absent on an unscoped call and when every id matched. Stopping the same device twice does not report it unmatched: ownership counts regardless of service state. { left_running } lists the URNs of live debugger sessions (and the network inspectors / React profiler sessions riding on them) whose id no device scope can name - re-call with the id after each URN's \`<namespace>:<port>:\` prefix to reap them. { aborted: true } means the caller cancelled the request part-way, so the rest of the machine was left untouched and neither of the other two fields was computed. Past the schema - which rejects an unknown key outright, so the \`udids\` slip is an error rather than a silent machine-wide sweep - the call always succeeds; reaping nothing is a result, not a failure.`,
147384
+ zodSchema: zodSchema63,
147243
147385
  services: () => ({}),
147244
147386
  async execute(_services, params, ctx) {
147245
147387
  const devices = params.devices;
@@ -147319,7 +147461,7 @@ function listeningPids(port) {
147319
147461
  if (!output) return [];
147320
147462
  return output.split("\n").map((s) => parseInt(s.trim(), 10)).filter((n) => !Number.isNaN(n));
147321
147463
  }
147322
- var zodSchema63 = external_exports.object({
147464
+ var zodSchema64 = external_exports.object({
147323
147465
  port: external_exports.number().int().min(1).max(65535).default(8081).describe("TCP port Metro is listening on (default 8081)")
147324
147466
  });
147325
147467
  var stopMetroTool = {
@@ -147330,7 +147472,7 @@ var stopMetroTool = {
147330
147472
  failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to stop Metro on port ${params.port}: ${failureSignal2.error_code}`
147331
147473
  },
147332
147474
  description: `Stop the Metro bundler process listening on a given port (default 8081). Use when ending a React Native session or when Metro must be restarted. Returns { stopped, port, pids }; stopped=false if no process is found on the port. Fails if the port lookup command times out or the process cannot be killed. This is DESTRUCTIVE \u2014 always ask the user for confirmation before calling this tool.`,
147333
- zodSchema: zodSchema63,
147475
+ zodSchema: zodSchema64,
147334
147476
  services: () => ({}),
147335
147477
  async execute(_services, params) {
147336
147478
  const port = params.port;
@@ -149674,7 +149816,7 @@ async function appendStepToFlow(session, step) {
149674
149816
  }
149675
149817
 
149676
149818
  // ../tool-server/src/tools/flows/flow-start-recording.ts
149677
- var zodSchema64 = external_exports.object({
149819
+ var zodSchema65 = external_exports.object({
149678
149820
  name: external_exports.string().describe(
149679
149821
  'Name for this flow (e.g. "settings-explore") \u2014 letters, digits, underscore and hyphen only.'
149680
149822
  ),
@@ -149731,7 +149873,7 @@ recording. Over a link, the next recorded step writes over your edit.
149731
149873
  Without a link, the recorder reads the file again before each step, but an
149732
149874
  edit that renumbers the steps drops the warnings that flow-finish-recording
149733
149875
  reports for those steps.`,
149734
- zodSchema: zodSchema64,
149876
+ zodSchema: zodSchema65,
149735
149877
  fileInputs: fileInputs2,
149736
149878
  services: () => ({}),
149737
149879
  async execute(_services, params, ctx) {
@@ -152231,7 +152373,7 @@ function stepAnchor(step) {
152231
152373
 
152232
152374
  // ../tool-server/src/tools/flows/flow-add-step.ts
152233
152375
  init_device_info();
152234
- var zodSchema65 = external_exports.object({
152376
+ var zodSchema66 = external_exports.object({
152235
152377
  name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
152236
152378
  project_root: external_exports.string().describe(
152237
152379
  "Absolute path to the project root of the flow being recorded \u2014 the same value passed to flow-start-recording. Together with `name` it identifies which recording this step belongs to."
@@ -152690,7 +152832,7 @@ Returns { message, stepCount, recorded, savedTo }; \`recorded\`, not the status,
152690
152832
  // more times — and every retry re-runs the action and appends another step,
152691
152833
  // because an aborted request still appends its first.
152692
152834
  longRunning: true,
152693
- zodSchema: zodSchema65,
152835
+ zodSchema: zodSchema66,
152694
152836
  fileInputs: fileInputs3,
152695
152837
  services: () => ({}),
152696
152838
  async execute(_services, params, ctx) {
@@ -152879,7 +153021,7 @@ Returns { message, stepCount, recorded, savedTo }; \`recorded\`, not the status,
152879
153021
 
152880
153022
  // ../tool-server/src/tools/flows/flow-insert-echo.ts
152881
153023
  init_zod();
152882
- var zodSchema66 = external_exports.object({
153024
+ var zodSchema67 = external_exports.object({
152883
153025
  name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
152884
153026
  project_root: external_exports.string().describe(
152885
153027
  "Absolute path to the project root of the flow being recorded \u2014 the same value passed to flow-start-recording. Together with `name` it identifies which recording this echo belongs to."
@@ -152897,7 +153039,7 @@ var flowInsertEchoTool = {
152897
153039
  description: `Record an echo step in the flow named by \`name\` + \`project_root\`. Echo steps print a message when the flow is replayed \u2014 useful as labels between tool calls.
152898
153040
  Use when you want to annotate a recorded flow with a human-readable label or checkpoint message.
152899
153041
  Returns { message, stepCount, savedTo }. Fails if that flow has no recording in progress.`,
152900
- zodSchema: zodSchema66,
153042
+ zodSchema: zodSchema67,
152901
153043
  services: () => ({}),
152902
153044
  async execute(_services, params) {
152903
153045
  const session = await requireRecordingSession(params.project_root, params.name);
@@ -153317,7 +153459,7 @@ var FlowScriptExecutor = class {
153317
153459
  { notes, durationMs: Date.now() - startedAt }
153318
153460
  );
153319
153461
  }
153320
- const lifeline = child.stdio[4];
153462
+ const lifeline = child.stdio?.[4];
153321
153463
  lifeline?.unref?.();
153322
153464
  let startedSeen = false;
153323
153465
  let terminal = null;
@@ -154200,7 +154342,7 @@ function errMsg3(err) {
154200
154342
 
154201
154343
  // ../tool-server/src/tools/flows/flow-add-script.ts
154202
154344
  var OUTPUT_RENDER_LIMIT_BYTES = 64 * 1024;
154203
- var zodSchema67 = external_exports.object({
154345
+ var zodSchema68 = external_exports.object({
154204
154346
  name: external_exports.string().describe("Flow name passed to flow-start-recording."),
154205
154347
  project_root: external_exports.string().describe("Absolute project root passed to flow-start-recording."),
154206
154348
  path: external_exports.string().describe(
@@ -154257,7 +154399,7 @@ var flowAddScriptTool = {
154257
154399
  // The flag only skips the adapter's own abort timer; its retry loop is
154258
154400
  // untouched, so a call that fails some other way is still re-POSTed.
154259
154401
  longRunning: true,
154260
- zodSchema: zodSchema67,
154402
+ zodSchema: zodSchema68,
154261
154403
  services: () => ({}),
154262
154404
  async execute(_services, params, ctx) {
154263
154405
  const session = await requireRecordingSession(params.project_root, params.name);
@@ -154347,7 +154489,7 @@ var flowAddScriptTool = {
154347
154489
  // ../tool-server/src/tools/flows/flow-finish-recording.ts
154348
154490
  init_zod();
154349
154491
  var fs60 = __toESM(require("node:fs/promises"));
154350
- var zodSchema68 = external_exports.object({
154492
+ var zodSchema69 = external_exports.object({
154351
154493
  name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
154352
154494
  project_root: external_exports.string().describe(
154353
154495
  "Absolute path to the project root of the flow being recorded \u2014 the same value passed to flow-start-recording. Together with `name` it identifies which recording to finish."
@@ -154406,7 +154548,7 @@ var flowFinishRecordingTool = {
154406
154548
  description: `Finish recording the flow named by \`name\` + \`project_root\`, leaving recordings under any other key untouched. Returns { message, path, executionPrerequisite, steps, summary, flowFile, savedTo } - a summary of all recorded steps plus the final YAML. Use when you have added all desired steps and want to finalize the flow file. Fails if that flow has no recording in progress.
154407
154549
  A warning flow-add-step raised on a recorded \`await-ui-element\` is repeated in \`summary\` as a \`warning:\` line of its own, right below the step it judges, and \`message\` counts them by kind. A warning is repeated only while the step it judges is still identifiable by its number: hand-editing the .yaml during the recording moves the steps, so those warnings are DROPPED rather than pinned on whichever step inherited the number, and \`message\` says how many were dropped. A step that carries a cross-tree warning was re-probed against the runner's tree: read it before converting that wait to \`await:\`/\`assert:\`, which is what the verdict is about and what this moment is for. A step that recorded a wait which did not pass was never probed at all, and its own warning names the CAUSE, because only one of them judges the condition: an unmet wait was read and found false, and it stops the run at replay; a wait whose tree source could not be read, or one that was cancelled, observed nothing and leaves the condition UNKNOWN rather than known-bad. Read those before replaying.
154408
154550
  You can still edit the .yaml file directly afterwards to remove or reorder steps.`,
154409
- zodSchema: zodSchema68,
154551
+ zodSchema: zodSchema69,
154410
154552
  services: () => ({}),
154411
154553
  async execute(_services, params) {
154412
154554
  const { filePath, flowFile, savedTo, flow, summary, headline } = await withFlowFileLock(
@@ -155741,7 +155883,7 @@ function formatScreenshotDiffSummary(result) {
155741
155883
  const shownRegions = result.regions.slice(0, MAX_SUMMARY_REGIONS);
155742
155884
  const coordinateSpace = coordinateSpaceForSummary(result.imageSize);
155743
155885
  const lines = ["Screenshot diff summary", "", "Overall:"];
155744
- lines.push(`- status: ${status}`);
155886
+ lines.push(statusLine(status));
155745
155887
  if (result.sizeNormalization) {
155746
155888
  const { baseline, current, comparedAt } = result.sizeNormalization;
155747
155889
  lines.push(
@@ -155802,6 +155944,12 @@ function formatScreenshotDiffSummary(result) {
155802
155944
  }
155803
155945
  return lines.join("\n");
155804
155946
  }
155947
+ function statusLine(status) {
155948
+ return `- status: ${status}`;
155949
+ }
155950
+ function summaryReportsDimensionMismatch(summary) {
155951
+ return summary.split("\n").includes(statusLine("dimension_mismatch"));
155952
+ }
155805
155953
  function screenshotDiffStatus(result) {
155806
155954
  if (result.dimensionMismatch) return "dimension_mismatch";
155807
155955
  if (!Number.isFinite(result.totalPixels) || !Number.isFinite(result.differentPixels) || !Number.isFinite(result.mismatchPercentage)) {
@@ -156878,7 +157026,7 @@ async function restoreStatusBar(device) {
156878
157026
  }
156879
157027
 
156880
157028
  // ../tool-server/src/tools/flows/flow-run.ts
156881
- var zodSchema69 = external_exports.object({
157029
+ var zodSchema70 = external_exports.object({
156882
157030
  name: external_exports.string().optional().describe(
156883
157031
  'Name of a saved flow to run from `.argent/flows` (e.g. "settings-explore"). Omit when flow_path is set.'
156884
157032
  ),
@@ -157385,7 +157533,7 @@ one-off interaction use the gesture tools instead, and to author a flow use flow
157385
157533
  exactly one flow source: name (under project_root) or flow_path.
157386
157534
  Returns a per-step report: the first failure stops the run and the rest report as skipped.`,
157387
157535
  longRunning: true,
157388
- zodSchema: zodSchema69,
157536
+ zodSchema: zodSchema70,
157389
157537
  fileInputs: fileInputs4,
157390
157538
  services: () => ({}),
157391
157539
  async execute(_services, params, ctx) {
@@ -158362,7 +158510,7 @@ async function resolveFlowSource(params, fileInput, flowPathInput) {
158362
158510
  // ../tool-server/src/tools/flows/flow-read-prerequisite.ts
158363
158511
  init_zod();
158364
158512
  var fs64 = __toESM(require("node:fs/promises"));
158365
- var zodSchema70 = external_exports.object({
158513
+ var zodSchema71 = external_exports.object({
158366
158514
  name: external_exports.string().optional().describe(
158367
158515
  'Name of a saved flow to inspect from `.argent/flows` (e.g. "settings-explore"). Omit when flow_path is set.'
158368
158516
  ),
@@ -158418,7 +158566,7 @@ Touches no device: nothing is launched, tapped, dispatched or torn down, and no
158418
158566
  needs booting, so calling this costs nothing but a file read.
158419
158567
  Fails if the flow file does not exist.
158420
158568
  Address the flow exactly as you will address it in flow-execute: name or flow_path, one and only one; supplying both or neither is rejected. The name goes in \`name\`, which resolves <project_root>/.argent/flows/<name>.yaml.`,
158421
- zodSchema: zodSchema70,
158569
+ zodSchema: zodSchema71,
158422
158570
  fileInputs: fileInputs5,
158423
158571
  services: () => ({}),
158424
158572
  async execute(_services, params, ctx) {
@@ -158734,7 +158882,7 @@ async function readWorkspaceSnapshot(workspacePath) {
158734
158882
  }
158735
158883
 
158736
158884
  // ../tool-server/src/tools/workspace/gather-workspace-data.ts
158737
- var zodSchema71 = external_exports.object({
158885
+ var zodSchema72 = external_exports.object({
158738
158886
  workspacePath: external_exports.string().describe("Absolute path to the project root directory to inspect (e.g. /Users/dev/MyApp)")
158739
158887
  });
158740
158888
  var fileInputs6 = [
@@ -158765,7 +158913,7 @@ exploration of anything the snapshot surfaces.
158765
158913
  Use when you need to inspect project configuration without manually reading multiple files.
158766
158914
  Returns partial data if workspacePath does not exist or is not readable; missing items are represented as null or empty collections.
158767
158915
  Fails if the workspacePath is not an absolute path or the directory cannot be accessed.`,
158768
- zodSchema: zodSchema71,
158916
+ zodSchema: zodSchema72,
158769
158917
  fileInputs: fileInputs6,
158770
158918
  services: () => ({}),
158771
158919
  async execute(_services, params) {
@@ -158839,7 +158987,7 @@ function targetFlagsFor(target) {
158839
158987
  if (target === "both") return ["--global", "--local"];
158840
158988
  return [`--${target}`];
158841
158989
  }
158842
- var zodSchema72 = external_exports.object({
158990
+ var zodSchema73 = external_exports.object({
158843
158991
  target: external_exports.enum(["auto", "global", "local", "both"]).optional().describe(
158844
158992
  "Which install to update. 'auto' (default) updates the install serving this session \u2014 the global PATH install or this project's local devDependency, whichever this server runs from. Pass 'global' / 'local' to force one, or 'both' when the user has both and wants each updated."
158845
158993
  )
@@ -158853,7 +159001,7 @@ var updateArgentTool = {
158853
159001
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to update Argent: ${failureSignal2.error_code}`
158854
159002
  },
158855
159003
  description: "Apply a pending Argent update. Only call this tool when the user has explicitly consented to updating Argent in this conversation. Use when an update notification indicates a new version is available and the user agrees to update. By default updates the install serving this session; pass `target` to choose global/local/both. Returns { message } with the update status and version info. The tool server will restart automatically after the update. Fails if no update is available or an update is already in progress.",
158856
- zodSchema: zodSchema72,
159004
+ zodSchema: zodSchema73,
158857
159005
  services: () => ({}),
158858
159006
  async execute(_services, params, _options) {
158859
159007
  const { updateAvailable, updateInstallable, currentVersion, installableVersion } = getUpdateState();
@@ -158938,7 +159086,7 @@ var updateArgentTool = {
158938
159086
 
158939
159087
  // ../tool-server/src/tools/system/dismiss-update.ts
158940
159088
  init_zod();
158941
- var zodSchema73 = external_exports.object({
159089
+ var zodSchema74 = external_exports.object({
158942
159090
  hours: external_exports.number().min(0).describe("Number of hours to suppress the update notification")
158943
159091
  });
158944
159092
  var dismissUpdateTool = {
@@ -158949,7 +159097,7 @@ var dismissUpdateTool = {
158949
159097
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to dismiss Argent update: ${failureSignal2.error_code}`
158950
159098
  },
158951
159099
  description: "Clear the Argent update notification for the given number of hours. Use when the user asks to postpone or silence update reminders. Returns { message } confirming the suppression duration. Fails if the hours value is negative or the suppression state cannot be persisted.",
158952
- zodSchema: zodSchema73,
159100
+ zodSchema: zodSchema74,
158953
159101
  services: () => ({}),
158954
159102
  async execute(_services, params, _options) {
158955
159103
  const durationMs = params.hours * 60 * 60 * 1e3;
@@ -158968,7 +159116,7 @@ var import_path8 = __toESM(require("path"));
158968
159116
  init_zod();
158969
159117
  init_src2();
158970
159118
  init_device_info();
158971
- var zodSchema74 = external_exports.object({
159119
+ var zodSchema75 = external_exports.object({
158972
159120
  baselinePath: external_exports.string().min(1).optional().describe("Path to the baseline PNG file. Required unless captureBaseline is true."),
158973
159121
  currentPath: external_exports.string().min(1).optional().describe("Path to the current PNG file. Required unless captureCurrent is true."),
158974
159122
  udid: external_exports.string().min(1).describe("Target device id from `list-devices` (iOS UDID or Android serial)."),
@@ -158985,7 +159133,7 @@ var zodSchema74 = external_exports.object({
158985
159133
  "Directory where diff artifacts should be written. Optional \u2014 defaults to a temp directory; the diff images are returned in the result either way."
158986
159134
  )
158987
159135
  }).strict();
158988
- var capability33 = {
159136
+ var capability34 = {
158989
159137
  apple: { simulator: true, device: true },
158990
159138
  android: { emulator: true, device: true, unknown: true }
158991
159139
  };
@@ -158998,7 +159146,7 @@ var screenshotDiffTool = {
158998
159146
  id: "screenshot-diff",
158999
159147
  interaction: {
159000
159148
  startedMsg: () => "Comparing screenshots",
159001
- completedMsg: () => "Compared screenshots",
159149
+ completedMsg: ({ result }) => summaryReportsDimensionMismatch(result.summary) ? "Skipped comparison - screenshot dimensions differ" : "Compared screenshots",
159002
159150
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to compare screenshots: ${failureSignal2.error_code}`
159003
159151
  },
159004
159152
  description: `Compare two PNG screenshots and return a compact visual-diff summary.
@@ -159010,8 +159158,8 @@ Returns { summary, diffPath, contextDiffPath }. The summary uses normalized [0,1
159010
159158
  Ignores the fixed top status-bar band for both pixel and OCR text comparisons.
159011
159159
  Fails if the input sources are invalid, PNG files cannot be read, outputDir cannot be written, or the simulator-server / emulator backend is not reachable.`,
159012
159160
  searchHint: "compare screenshots png diff visual UI changes UI regression visual regression screenshot diff changed regions text ocr live capture",
159013
- zodSchema: zodSchema74,
159014
- capability: capability33,
159161
+ zodSchema: zodSchema75,
159162
+ capability: capability34,
159015
159163
  fileInputs: fileInputs7,
159016
159164
  services: (params) => {
159017
159165
  if (params.captureBaseline || params.captureCurrent) {
@@ -159324,7 +159472,7 @@ async function captureElementFrame(registry2, udid, match, opts = {}) {
159324
159472
  }
159325
159473
 
159326
159474
  // ../tool-server/src/tools/variants/propose-variant.ts
159327
- var zodSchema75 = external_exports.object({
159475
+ var zodSchema76 = external_exports.object({
159328
159476
  element: external_exports.string().min(1).max(200).describe(
159329
159477
  'Human name of the on-screen element this variant targets, e.g. "Foo button" or "profile header". Repeated calls with the same element accumulate multiple variants on it. Used as the default screen matcher when `match` is omitted.'
159330
159478
  ),
@@ -159384,7 +159532,7 @@ arrives as a follow-up message (this is the case in an \`argent lens\` CLI sessi
159384
159532
  Returns { round, elementId, variantId, element, variantCount, totalElements } \u2014 confirmation only;
159385
159533
  it does not wait for the user.`,
159386
159534
  searchHint: "propose design variant alternative option for element non-blocking ab choice",
159387
- zodSchema: zodSchema75,
159535
+ zodSchema: zodSchema76,
159388
159536
  services: () => ({}),
159389
159537
  async execute(_services, params) {
159390
159538
  let frame = params.variant.frame;
@@ -159408,7 +159556,7 @@ it does not wait for the user.`,
159408
159556
 
159409
159557
  // ../tool-server/src/tools/variants/await-user-selection.ts
159410
159558
  init_zod();
159411
- var zodSchema76 = external_exports.object({
159559
+ var zodSchema77 = external_exports.object({
159412
159560
  timeoutSeconds: external_exports.number().int().min(5).max(86400).optional().describe(
159413
159561
  "Max seconds to block this call before returning a re-awaitable { status: 'pending' } result (default 1800). The user's proposals stay live across timeouts \u2014 on 'pending' just call await_user_selection again. Lower this if your MCP client enforces a short request timeout."
159414
159562
  )
@@ -159449,7 +159597,7 @@ This tool is long-running; it intentionally holds the request open. It honors cl
159449
159597
  disconnects (aborts cleanly).`,
159450
159598
  searchHint: "await wait user selection choice variant blocking confirm picks complete",
159451
159599
  longRunning: true,
159452
- zodSchema: zodSchema76,
159600
+ zodSchema: zodSchema77,
159453
159601
  services: () => ({}),
159454
159602
  async execute(_services, params, options) {
159455
159603
  const timeoutMs = (params.timeoutSeconds ?? 1800) * 1e3;
@@ -159464,7 +159612,7 @@ disconnects (aborts cleanly).`,
159464
159612
  init_zod();
159465
159613
  init_src2();
159466
159614
  init_device_info();
159467
- var zodSchema77 = external_exports.object({
159615
+ var zodSchema78 = external_exports.object({
159468
159616
  udid: external_exports.string().describe("Chromium device id from `list-devices` (e.g. `chromium-cdp-9222`)."),
159469
159617
  action: external_exports.enum(["list", "select", "new", "close"]).describe(
159470
159618
  "list: enumerate tabs/windows. select: make a tab active (every other tool then acts on it). new: open a tab. close: close a tab."
@@ -159497,7 +159645,7 @@ var tabAction = {
159497
159645
  failure: "close"
159498
159646
  }
159499
159647
  };
159500
- var capability34 = {
159648
+ var capability35 = {
159501
159649
  chromium: { app: true }
159502
159650
  };
159503
159651
  var chromiumTabsTool = {
@@ -159515,8 +159663,8 @@ var chromiumTabsTool = {
159515
159663
  Use when an app exposes multiple windows or tabs and you need to inspect or drive one other than the current page, or to open/close a page during a flow. tabIds are stable for the session and never reused.
159516
159664
  Returns { tabs: [{ tabId, targetId, title, url, active, label? }] }. Fails if the device is not a Chromium (CDP) device, or the requested tabId/label no longer matches a live tab. Chromium-only.`,
159517
159665
  searchHint: "tab tabs window windows switch select close new open multi-tab chromium electron",
159518
- zodSchema: zodSchema77,
159519
- capability: capability34,
159666
+ zodSchema: zodSchema78,
159667
+ capability: capability35,
159520
159668
  services: (params) => {
159521
159669
  const device = resolveDevice(params.udid);
159522
159670
  if (device.platform === "chromium") {
@@ -159617,7 +159765,7 @@ async function clearStorage(cdp, type) {
159617
159765
  }
159618
159766
 
159619
159767
  // ../tool-server/src/tools/chromium-cookies/index.ts
159620
- var zodSchema78 = external_exports.object({
159768
+ var zodSchema79 = external_exports.object({
159621
159769
  udid: external_exports.string().describe("Chromium device id from `list-devices` (e.g. `chromium-cdp-9222`)."),
159622
159770
  action: external_exports.enum(["get", "set", "delete", "clear"]).describe(
159623
159771
  "get: read cookies. set: create/update a cookie. delete: remove a named cookie. clear: remove all browser cookies."
@@ -159640,7 +159788,7 @@ var cookieAction = {
159640
159788
  delete: { started: "Deleting", completed: "Deleted", failure: "delete" },
159641
159789
  clear: { started: "Clearing", completed: "Cleared", failure: "clear" }
159642
159790
  };
159643
- var capability35 = {
159791
+ var capability36 = {
159644
159792
  chromium: { app: true }
159645
159793
  };
159646
159794
  var chromiumCookiesTool = {
@@ -159658,8 +159806,8 @@ var chromiumCookiesTool = {
159658
159806
  Use when seeding an authenticated session before a flow (set the session cookie, then navigate) or asserting cookie state after one.
159659
159807
  Returns { cookies, count } for get, or a small status object ({ set } / { deleted } / { cleared }) otherwise. Fails if the device is not a Chromium (CDP) device, or set is missing name/value. Chromium-only.`,
159660
159808
  searchHint: "cookies cookie get set delete clear httponly samesite session auth chromium",
159661
- zodSchema: zodSchema78,
159662
- capability: capability35,
159809
+ zodSchema: zodSchema79,
159810
+ capability: capability36,
159663
159811
  services: (params) => {
159664
159812
  const device = resolveDevice(params.udid);
159665
159813
  if (device.platform === "chromium") {
@@ -159724,7 +159872,7 @@ Returns { cookies, count } for get, or a small status object ({ set } / { delete
159724
159872
  init_zod();
159725
159873
  init_src2();
159726
159874
  init_device_info();
159727
- var zodSchema79 = external_exports.object({
159875
+ var zodSchema80 = external_exports.object({
159728
159876
  udid: external_exports.string().describe("Chromium device id from `list-devices` (e.g. `chromium-cdp-9222`)."),
159729
159877
  store: external_exports.enum(["local", "session"]).describe("Which Web Storage area: `local` (localStorage) or `session` (sessionStorage)."),
159730
159878
  action: external_exports.enum(["get", "set", "remove", "clear"]).describe(
@@ -159739,7 +159887,7 @@ var storageAction = {
159739
159887
  remove: { started: "Removing from", completed: "Removed from", failure: "remove from" },
159740
159888
  clear: { started: "Clearing", completed: "Cleared", failure: "clear" }
159741
159889
  };
159742
- var capability36 = {
159890
+ var capability37 = {
159743
159891
  chromium: { app: true }
159744
159892
  };
159745
159893
  var chromiumStorageTool = {
@@ -159758,8 +159906,8 @@ Set \`store\` to "local" or "session". Storage is per-origin, so it reflects the
159758
159906
  Use when seeding feature flags / auth tokens before a flow or asserting persisted app state after one.
159759
159907
  Returns { value } for a single key, { entries, count } for all, or a status object ({ set } / { removed } / { cleared }) otherwise. Fails if the device is not a Chromium (CDP) device, or set is missing key/value. Chromium-only.`,
159760
159908
  searchHint: "storage localstorage sessionstorage local session get set remove clear key value chromium",
159761
- zodSchema: zodSchema79,
159762
- capability: capability36,
159909
+ zodSchema: zodSchema80,
159910
+ capability: capability37,
159763
159911
  services: (params) => {
159764
159912
  const device = resolveDevice(params.udid);
159765
159913
  if (device.platform === "chromium") {
@@ -159871,6 +160019,7 @@ function createRegistry() {
159871
160019
  registry2.registerTool(networkRequestTool);
159872
160020
  registry2.registerTool(createDescribeTool(registry2));
159873
160021
  registry2.registerTool(createUiTreeTool(registry2));
160022
+ registry2.registerTool(createForegroundAppTool(registry2));
159874
160023
  registry2.registerTool(createAwaitUiElementTool(registry2));
159875
160024
  registry2.registerTool(createAwaitScreenIdleTool(registry2));
159876
160025
  registry2.registerTool(createReactProfilerStartTool(registry2));
@@ -160140,9 +160289,9 @@ function createPreviewWindowManager(opts = {}) {
160140
160289
  if (fs68.existsSync(bundled)) return bundled;
160141
160290
  return require.resolve("@argent/preview-window/dist/main.js");
160142
160291
  };
160143
- const isAlive = (c) => c !== null && c.exitCode === null && !c.killed;
160292
+ const isAlive2 = (c) => c !== null && c.exitCode === null && !c.killed;
160144
160293
  const ensureOpen = (url2) => {
160145
- if (isAlive(child) && !closing) {
160294
+ if (isAlive2(child) && !closing) {
160146
160295
  send({ cmd: "foreground", url: url2 });
160147
160296
  return;
160148
160297
  }
@@ -160187,12 +160336,12 @@ function createPreviewWindowManager(opts = {}) {
160187
160336
  closing = false;
160188
160337
  };
160189
160338
  const requestClose = () => {
160190
- if (!isAlive(child)) return;
160339
+ if (!isAlive2(child)) return;
160191
160340
  closing = true;
160192
160341
  send({ cmd: "close" });
160193
160342
  };
160194
160343
  const dispose = () => {
160195
- if (isAlive(child)) child.kill();
160344
+ if (isAlive2(child)) child.kill();
160196
160345
  child = null;
160197
160346
  closing = false;
160198
160347
  };