@swmansion/argent 0.32.1-next.8 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/assets/manifest.json +2 -2
  3. package/bin/argent-android-devtools-0.4.0.apk +0 -0
  4. package/bin/darwin/argent-macos-helper +0 -0
  5. package/bin/darwin/ax-service +0 -0
  6. package/bin/darwin/tvos-ax-service +0 -0
  7. package/bin/darwin/tvos-hid-daemon +0 -0
  8. package/bin/network-inspector/network-inspector.jar +0 -0
  9. package/bin/tcp/ax-service +0 -0
  10. package/dist/cli-cmds.mjs +530 -438
  11. package/dist/client.d.ts +5 -0
  12. package/dist/client.js +60 -9
  13. package/dist/installer.mjs +372 -202
  14. package/dist/mcp-server.mjs +156 -20
  15. package/dist/tool-args.generated.d.ts +87 -51
  16. package/dist/tool-server.cjs +39520 -34927
  17. package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
  18. package/dylibs/libKeyboardPatch.dylib +0 -0
  19. package/dylibs/libNativeDevtoolsIos.dylib +0 -0
  20. package/dylibs/macos/libArgentInjectionBootstrap.dylib +0 -0
  21. package/dylibs/macos/libNativeDevtoolsMacos.dylib +0 -0
  22. package/dylibs/tcp/libArgentInjectionBootstrap.dylib +0 -0
  23. package/dylibs/tcp/libKeyboardPatch.dylib +0 -0
  24. package/dylibs/tcp/libNativeDevtoolsIos.dylib +0 -0
  25. package/dylibs/tvos/libArgentInjectionBootstrap.dylib +0 -0
  26. package/dylibs/tvos/libKeyboardPatch.dylib +0 -0
  27. package/dylibs/tvos/libNativeDevtoolsIos.dylib +0 -0
  28. package/package.json +2 -2
  29. package/rules/argent.md +1 -1
  30. package/skills/argent-create-e2e/references/e2e-yaml.md +4 -4
  31. package/skills/argent-create-e2e/references/reliability-and-recovery.md +3 -3
  32. package/skills/argent-device-interact/SKILL.md +3 -2
  33. package/skills/argent-device-interact/references/chromium.md +1 -1
  34. package/skills/argent-device-interact/references/harmonyos.md +1 -1
  35. package/skills/argent-ios-simulator-setup/SKILL.md +1 -1
  36. package/skills/argent-macos-app-interact/SKILL.md +44 -0
  37. package/skills/argent-macos-app-interact/references/e2e.md +6 -0
  38. package/skills/argent-qa-e2e/SKILL.md +1 -1
  39. package/skills/argent-react-native-app-workflow/SKILL.md +2 -0
  40. package/skills/argent-react-native-optimization/SKILL.md +2 -3
  41. package/skills/argent-react-native-profiler/SKILL.md +8 -8
  42. package/skills/argent-screenshot-diff/SKILL.md +1 -1
  43. package/skills/argent-test-ui-flow/SKILL.md +1 -1
  44. package/skills/argent-tv-interact/SKILL.md +4 -4
  45. package/bin/argent-android-devtools-0.3.0.apk +0 -0
@@ -24943,6 +24943,11 @@ var FLAG_REGISTRY = [
24943
24943
  name: "video-watermark",
24944
24944
  description: "Overlay the argent corner watermark on recorded screen videos. On by default; turn it off with `argent disable video-watermark`.",
24945
24945
  defaultEnabled: true
24946
+ },
24947
+ {
24948
+ name: "macos-apps",
24949
+ description: "Drive native Mac apps (AppKit, SwiftUI, react-native-macos) from inside the app. Adds the macos platform to list-devices and boot-device, and the file-panel and menu-bar tools. On by default; turn it off with `argent disable macos-apps`.",
24950
+ defaultEnabled: true
24946
24951
  }
24947
24952
  ];
24948
24953
  function getFlagDefinition(name, registry2 = FLAG_REGISTRY) {
@@ -25735,6 +25740,8 @@ var FAILURE_CODES = {
25735
25740
  CLI_RUN_ARGS_JSON_INVALID: "CLI_RUN_ARGS_JSON_INVALID",
25736
25741
  CLI_RUN_INPUT_VALIDATION_FAILED: "CLI_RUN_INPUT_VALIDATION_FAILED",
25737
25742
  CLI_RUN_TOOL_CALL_FAILED: "CLI_RUN_TOOL_CALL_FAILED",
25743
+ // The result carried the tool-server's `failure` field.
25744
+ CLI_RUN_TOOL_RESULT_FAILED: "CLI_RUN_TOOL_RESULT_FAILED",
25738
25745
  CLI_RUN_SAVE_IMAGE_FAILED: "CLI_RUN_SAVE_IMAGE_FAILED",
25739
25746
  TOOL_CAPABILITY_UNSUPPORTED_OPERATION: "TOOL_CAPABILITY_UNSUPPORTED_OPERATION",
25740
25747
  TOOL_PLATFORM_NOT_IMPLEMENTED: "TOOL_PLATFORM_NOT_IMPLEMENTED",
@@ -25750,6 +25757,7 @@ var FAILURE_CODES = {
25750
25757
  INSTALL_MODE_FLAG_CONFLICT: "INSTALL_MODE_FLAG_CONFLICT",
25751
25758
  INSTALL_FROM_TAR_PACKAGE_FAILED: "INSTALL_FROM_TAR_PACKAGE_FAILED",
25752
25759
  INSTALL_INIT_TRIGGERED_UPDATE_FAILED: "INSTALL_INIT_TRIGGERED_UPDATE_FAILED",
25760
+ INSTALL_SKILLS_FAILED: "INSTALL_SKILLS_FAILED",
25753
25761
  INSTALL_SKILLS_REFRESH_FAILED: "INSTALL_SKILLS_REFRESH_FAILED",
25754
25762
  INSTALL_UNCLASSIFIED_FAILED: "INSTALL_UNCLASSIFIED_FAILED",
25755
25763
  UPDATE_INSTALLED_VERSION_DETECT_FAILED: "UPDATE_INSTALLED_VERSION_DETECT_FAILED",
@@ -25946,6 +25954,8 @@ var FAILURE_CODES = {
25946
25954
  REACT_PROFILER_START_FAILED: "REACT_PROFILER_START_FAILED",
25947
25955
  REACT_PROFILER_START_VERIFY_FAILED: "REACT_PROFILER_START_VERIFY_FAILED",
25948
25956
  REACT_PROFILER_SESSION_TORN_DOWN: "REACT_PROFILER_SESSION_TORN_DOWN",
25957
+ REACT_PROFILER_SESSION_TAKEN_OVER: "REACT_PROFILER_SESSION_TAKEN_OVER",
25958
+ REACT_PROFILER_STOP_IN_PROGRESS: "REACT_PROFILER_STOP_IN_PROGRESS",
25949
25959
  REACT_PROFILER_HOOK_ERROR: "REACT_PROFILER_HOOK_ERROR",
25950
25960
  REACT_PROFILER_ANALYZE_NO_DATA: "REACT_PROFILER_ANALYZE_NO_DATA",
25951
25961
  NATIVE_PROFILER_FACTORY_OPTIONS_MISSING: "NATIVE_PROFILER_FACTORY_OPTIONS_MISSING",
@@ -26024,6 +26034,32 @@ var FAILURE_CODES = {
26024
26034
  CHROMIUM_ELECTRON_SPAWN_FAILED: "CHROMIUM_ELECTRON_SPAWN_FAILED",
26025
26035
  CHROMIUM_ELECTRON_CDP_TIMEOUT: "CHROMIUM_ELECTRON_CDP_TIMEOUT",
26026
26036
  CHROMIUM_ELECTRON_EXITED_BEFORE_READY: "CHROMIUM_ELECTRON_EXITED_BEFORE_READY",
26037
+ /**
26038
+ * Native Mac apps (the `macos-apps` flag)
26039
+ * @see [macos-app.ts](../../tool-server/src/blueprints/macos-app.ts)
26040
+ */
26041
+ MACOS_APP_UNSUPPORTED_HOST: "MACOS_APP_UNSUPPORTED_HOST",
26042
+ MACOS_APP_PATH_INVALID: "MACOS_APP_PATH_INVALID",
26043
+ MACOS_APP_BUNDLE_INVALID: "MACOS_APP_BUNDLE_INVALID",
26044
+ MACOS_APP_NOT_FOUND: "MACOS_APP_NOT_FOUND",
26045
+ MACOS_APP_HARDENED_RUNTIME: "MACOS_APP_HARDENED_RUNTIME",
26046
+ MACOS_APP_LIBRARY_MISSING: "MACOS_APP_LIBRARY_MISSING",
26047
+ MACOS_APP_LIBRARY_STAGE_FAILED: "MACOS_APP_LIBRARY_STAGE_FAILED",
26048
+ MACOS_APP_ALREADY_RUNNING: "MACOS_APP_ALREADY_RUNNING",
26049
+ MACOS_APP_SPAWN_FAILED: "MACOS_APP_SPAWN_FAILED",
26050
+ MACOS_APP_EXITED_BEFORE_READY: "MACOS_APP_EXITED_BEFORE_READY",
26051
+ MACOS_APP_HANDSHAKE_TIMEOUT: "MACOS_APP_HANDSHAKE_TIMEOUT",
26052
+ MACOS_APP_HANDSHAKE_INVALID: "MACOS_APP_HANDSHAKE_INVALID",
26053
+ MACOS_APP_NOT_RUNNING: "MACOS_APP_NOT_RUNNING",
26054
+ MACOS_APP_NOT_CONNECTED: "MACOS_APP_NOT_CONNECTED",
26055
+ MACOS_APP_CONNECTION_LOST: "MACOS_APP_CONNECTION_LOST",
26056
+ MACOS_APP_CONNECTION_CLOSED: "MACOS_APP_CONNECTION_CLOSED",
26057
+ MACOS_APP_RPC_TIMEOUT: "MACOS_APP_RPC_TIMEOUT",
26058
+ MACOS_APP_RPC_ERROR: "MACOS_APP_RPC_ERROR",
26059
+ MACOS_APP_TERMINATE_FAILED: "MACOS_APP_TERMINATE_FAILED",
26060
+ MACOS_APP_BUNDLE_ID_MISMATCH: "MACOS_APP_BUNDLE_ID_MISMATCH",
26061
+ MACOS_APP_OPEN_URL_FAILED: "MACOS_APP_OPEN_URL_FAILED",
26062
+ MACOS_APP_FILE_ACCESS_FAILED: "MACOS_APP_FILE_ACCESS_FAILED",
26027
26063
  KEYBOARD_KEY_UNSUPPORTED: "KEYBOARD_KEY_UNSUPPORTED",
26028
26064
  KEYBOARD_CHARACTER_UNSUPPORTED: "KEYBOARD_CHARACTER_UNSUPPORTED",
26029
26065
  KEYBOARD_TEXT_AND_KEY_COMBINED: "KEYBOARD_TEXT_AND_KEY_COMBINED",
@@ -27151,7 +27187,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
27151
27187
  final = {
27152
27188
  data: msg.data,
27153
27189
  note: msg.note,
27154
- ...msg.profiling === true ? { profiling: true } : {}
27190
+ ...msg.profiling === true ? { profiling: true } : {},
27191
+ ...typeof msg.failure === "string" ? { failure: msg.failure } : {}
27155
27192
  };
27156
27193
  } else if (msg.event === "error") {
27157
27194
  throw new ToolInvocationError(msg.error ?? "tool invocation failed", {
@@ -27203,7 +27240,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
27203
27240
  return {
27204
27241
  data: final.data,
27205
27242
  note: final.note,
27206
- ...final.profiling ? { profiling: true } : {}
27243
+ ...final.profiling ? { profiling: true } : {},
27244
+ ...final.failure !== void 0 ? { failure: final.failure } : {}
27207
27245
  };
27208
27246
  }
27209
27247
  function errorBodyMessage(body) {
@@ -27368,6 +27406,7 @@ function createToolsClient(options = {}) {
27368
27406
  }
27369
27407
  const shadowWarning = await e2eShadowWarningFor(name, args);
27370
27408
  const baselineDirs = [];
27409
+ let unwrittenBaselines = [];
27371
27410
  if (meta2?.fileInputs?.length) {
27372
27411
  if (remote) assertRequiredPresent(meta2, finalArgs);
27373
27412
  finalArgs = await prepareFileInputs(meta2.fileInputs, finalArgs ?? {}, {
@@ -27381,8 +27420,9 @@ function createToolsClient(options = {}) {
27381
27420
  signal: opts?.signal
27382
27421
  });
27383
27422
  }
27384
- const settle2 = async (data) => {
27385
- const applied = await applyClientFileDirectives(data, { allowedDirs: baselineDirs });
27423
+ const settle2 = async (data2) => {
27424
+ const applied = await applyClientFileDirectives(data2, { allowedDirs: baselineDirs });
27425
+ unwrittenBaselines = applied.failed.map((f) => f.path);
27386
27426
  for (const { path: file, error: error2 } of applied.failed) {
27387
27427
  diagnose(`The baseline ${file} was not written on this client: ${error2}`);
27388
27428
  }
@@ -27399,6 +27439,7 @@ function createToolsClient(options = {}) {
27399
27439
  }
27400
27440
  return { ...result, warning: shadowWarning };
27401
27441
  };
27442
+ const unwrittenFailure = () => unwrittenBaselines.length > 0 ? `Baselines not written on this client: ${unwrittenBaselines.join(", ")}` : void 0;
27402
27443
  const stream = opts?.onProgress !== void 0 || carriesMembers(finalArgs);
27403
27444
  const sentOnce = carriesUpload(finalArgs);
27404
27445
  const forwarded = remote ? await forwardedSecrets(finalArgs) : void 0;
@@ -27462,11 +27503,14 @@ function createToolsClient(options = {}) {
27462
27503
  }),
27463
27504
  opts?.signal
27464
27505
  );
27506
+ const data2 = await settle2(streamed.data);
27507
+ const failure3 = streamed.failure ?? unwrittenFailure();
27465
27508
  return {
27466
- data: await settle2(streamed.data),
27509
+ data: data2,
27467
27510
  note: streamed.note,
27468
27511
  outputHint: meta2?.outputHint,
27469
- ...streamed.profiling ? { profiling: true } : {}
27512
+ ...streamed.profiling ? { profiling: true } : {},
27513
+ ...failure3 !== void 0 ? { failure: failure3 } : {}
27470
27514
  };
27471
27515
  }
27472
27516
  let json;
@@ -27502,11 +27546,14 @@ function createToolsClient(options = {}) {
27502
27546
  });
27503
27547
  }
27504
27548
  opts?.signal?.throwIfAborted();
27549
+ const data = await settle2(json.data);
27550
+ const failure2 = (typeof json.failure === "string" ? json.failure : void 0) ?? unwrittenFailure();
27505
27551
  return {
27506
- data: await settle2(json.data),
27552
+ data,
27507
27553
  note: json.note,
27508
27554
  outputHint: meta2?.outputHint,
27509
- ...json.profiling === true ? { profiling: true } : {}
27555
+ ...json.profiling === true ? { profiling: true } : {},
27556
+ ...failure2 !== void 0 ? { failure: failure2 } : {}
27510
27557
  };
27511
27558
  }
27512
27559
  return { fetchTools, fetchTool, callTool, baseUrl };
@@ -27798,7 +27845,8 @@ var PLATFORMS = [
27798
27845
  "vega",
27799
27846
  "harmony",
27800
27847
  "tvos",
27801
- "android-tv"
27848
+ "android-tv",
27849
+ "macos"
27802
27850
  ];
27803
27851
  var DEVICE_KINDS = [
27804
27852
  "simulator",
@@ -27972,6 +28020,9 @@ var ALLOWED = {
27972
28020
  warned_count: COUNT
27973
28021
  },
27974
28022
  "installation:skill_install": {
28023
+ source: oneOf(["pinned", "bundled"]),
28024
+ used_fallback: bool,
28025
+ fallback_reason: oneOf(["ref_missing", "unclassified"]),
27975
28026
  method: oneOf(["default", "interactive", "manual"]),
27976
28027
  is_online: bool,
27977
28028
  has_offline_cache: bool,
@@ -28856,7 +28907,9 @@ var AUTO_SCREENSHOT_TOOLS = /* @__PURE__ */ new Set([
28856
28907
  "describe",
28857
28908
  "run-sequence",
28858
28909
  // A wait is almost always followed by a look at the screen it waited for.
28859
- "await-ui-element"
28910
+ "await-ui-element",
28911
+ "file-panel",
28912
+ "menu-bar"
28860
28913
  ]);
28861
28914
  var AUTO_SCREENSHOT_DELAY_MS_BY_TOOL = {
28862
28915
  "launch-app": 3e3,
@@ -28904,15 +28957,18 @@ var AUTO_DESCRIBE_TOOLS = /* @__PURE__ */ new Set([
28904
28957
  "restart-app",
28905
28958
  "open-url",
28906
28959
  "run-sequence",
28907
- "await-ui-element"
28960
+ "await-ui-element",
28961
+ "file-panel",
28962
+ "menu-bar"
28908
28963
  ]);
28909
28964
  function autoDescribeEnabled(options) {
28910
28965
  return !isFlagEnabled("disable-auto-describe", options);
28911
28966
  }
28912
28967
  var PROFILING_CAPTURE_SKIPPED_NOTE = "Auto-screenshot and element tree skipped while a profiler is recording on this device. Call screenshot or describe if you need to see the screen.";
28913
28968
  var AUTO_DESCRIBE_HEADER = "--- Elements after action (describe) ---";
28914
- function shouldAutoDescribe(toolName) {
28915
- return AUTO_DESCRIBE_TOOLS.has(normalizeToolName(toolName));
28969
+ function shouldAutoDescribe(toolName, args) {
28970
+ const canonical = normalizeToolName(toolName);
28971
+ return AUTO_DESCRIBE_TOOLS.has(canonical) && !isListCall(canonical, args);
28916
28972
  }
28917
28973
  var SECRET_PLACEHOLDER_MARKER = "{{secret:";
28918
28974
  function containsSecretPlaceholder(args) {
@@ -28932,9 +28988,12 @@ function normalizeToolName(name) {
28932
28988
  const idx = name.lastIndexOf("__");
28933
28989
  return idx === -1 ? name : name.slice(idx + 2);
28934
28990
  }
28935
- function shouldAutoScreenshot(toolName) {
28991
+ function shouldAutoScreenshot(toolName, args) {
28936
28992
  const canonical = normalizeToolName(toolName);
28937
- return canonical !== "screenshot" && AUTO_SCREENSHOT_TOOLS.has(canonical);
28993
+ return canonical !== "screenshot" && AUTO_SCREENSHOT_TOOLS.has(canonical) && !isListCall(canonical, args);
28994
+ }
28995
+ function isListCall(canonical, args) {
28996
+ return (canonical === "menu-bar" || canonical === "file-panel") && args?.action === "list";
28938
28997
  }
28939
28998
  function getAutoScreenshotDelayMs(toolName) {
28940
28999
  const canonical = normalizeToolName(toolName);
@@ -29112,6 +29171,78 @@ function toMcpToolList(tools, options = {}) {
29112
29171
  return tools.filter((t) => !t.hideFromMcp).map((t) => toMcpTool(t, options));
29113
29172
  }
29114
29173
 
29174
+ // ../argent-mcp/src/list-devices-text.ts
29175
+ var RUNTIME_PREFIX = "com.apple.CoreSimulator.SimRuntime.";
29176
+ var STOPPED_SIMULATORS_HEADER = "iOS simulators that are shut down, one per line (platform, udid, name, runtime, state, tags); start one with boot-device:";
29177
+ function isRecord3(value) {
29178
+ return value !== null && typeof value === "object" && !Array.isArray(value);
29179
+ }
29180
+ function shortRuntime(runtime) {
29181
+ if (!runtime.startsWith(RUNTIME_PREFIX)) return runtime;
29182
+ const rest = runtime.slice(RUNTIME_PREFIX.length);
29183
+ const match = /^([A-Za-z]+)-(\d+(?:-\d+)*)$/.exec(rest);
29184
+ return match ? `${match[1]} ${match[2].replace(/-/g, ".")}` : rest;
29185
+ }
29186
+ function cleanEntry(device) {
29187
+ const out = {};
29188
+ for (const [key, value] of Object.entries(device)) {
29189
+ if (value === null || value === void 0) continue;
29190
+ if (key === "isEmulator") continue;
29191
+ if (key === "runtimeKind" && value === "mobile") continue;
29192
+ out[key] = key === "runtime" && typeof value === "string" ? shortRuntime(value) : value;
29193
+ }
29194
+ return out;
29195
+ }
29196
+ function isStoppedSimulator(device) {
29197
+ if (device.platform !== "ios" && device.platform !== "ios-remote") return false;
29198
+ if ("kind" in device || "external" in device) return false;
29199
+ return typeof device.udid === "string" && device.state === "Shutdown";
29200
+ }
29201
+ var ONE_LINE_FIELDS = /* @__PURE__ */ new Set(["platform", "udid", "name", "runtime", "state"]);
29202
+ function quoteIfNeeded(value) {
29203
+ return value === "" || /[\s"\\]/.test(value) ? JSON.stringify(value) : value;
29204
+ }
29205
+ function stoppedSimulatorLine(device) {
29206
+ const d = cleanEntry(device);
29207
+ const name = typeof d.name === "string" ? d.name : "";
29208
+ const parts = [String(d.platform), String(d.udid), JSON.stringify(name)];
29209
+ if (typeof d.runtime === "string") parts.push(d.runtime);
29210
+ if (typeof d.state === "string") parts.push(quoteIfNeeded(d.state));
29211
+ for (const [key, value] of Object.entries(d)) {
29212
+ if (ONE_LINE_FIELDS.has(key)) continue;
29213
+ if (value === true) parts.push(key);
29214
+ else if (typeof value === "string" || typeof value === "number")
29215
+ parts.push(`${key}=${quoteIfNeeded(String(value))}`);
29216
+ else parts.push(`${key}=${JSON.stringify(value)}`);
29217
+ }
29218
+ return parts.join(" ");
29219
+ }
29220
+ function listDevicesText(result) {
29221
+ if (!isRecord3(result) || !Array.isArray(result.devices)) return void 0;
29222
+ if (!result.devices.every(isRecord3)) return void 0;
29223
+ const devices = result.devices;
29224
+ const listed = [];
29225
+ const stopped = [];
29226
+ for (const device of devices) {
29227
+ if (isStoppedSimulator(device)) stopped.push(stoppedSimulatorLine(device));
29228
+ else listed.push(JSON.stringify(cleanEntry(device)));
29229
+ }
29230
+ const rest = [];
29231
+ for (const [key, value] of Object.entries(result)) {
29232
+ if (key === "devices") continue;
29233
+ rest.push(`${JSON.stringify(key)}:${JSON.stringify(value)}`);
29234
+ }
29235
+ const devicesPart = listed.length > 0 ? `[
29236
+ ${listed.join(",\n")}
29237
+ ]` : "[]";
29238
+ const object3 = `{"devices":${devicesPart}${rest.map((r) => `,
29239
+ ${r}`).join("")}}`;
29240
+ if (stopped.length === 0) return object3;
29241
+ return `${object3}
29242
+ ${STOPPED_SIMULATORS_HEADER}
29243
+ ${stopped.join("\n")}`;
29244
+ }
29245
+
29115
29246
  // ../argent-mcp/src/instructions.ts
29116
29247
  var SERVER_INSTRUCTIONS = "Argent \u2014 iOS Simulator, Android Emulator, and Chromium app control for interacting, testing, profiling and debugging mobile and Chromium applications. Interaction tools return the screen after the action: a screenshot plus the accessibility element tree with normalized tap frames. Take coordinates from that tree; call describe only when no fresh tree is available \u2014 never guess coordinates from pixels. Do not stop simulator servers when a task finishes: the next task reuses them. Call stop-all-simulator-servers when the user asks to clean up or ends the session, or when a skill tells you to recycle a device's services, always with devices: [...] naming the devices this session used. Never stop a Metro the user started unless they ask. One tool-server is shared by every agent using this argent install, so an unscoped call tears down their devices too \u2014 reserve it for a deliberate machine-wide cleanup.";
29117
29248
 
@@ -29349,7 +29480,7 @@ async function startMcpServer(options) {
29349
29480
  const t1 = Date.now();
29350
29481
  try {
29351
29482
  const d = await callTool("describe", { udid }, { signal });
29352
- const desc = d.result?.description;
29483
+ const { description: desc, hint } = d.result ?? {};
29353
29484
  await spyLog({
29354
29485
  ts: (/* @__PURE__ */ new Date()).toISOString(),
29355
29486
  event: "auto_describe",
@@ -29358,8 +29489,10 @@ async function startMcpServer(options) {
29358
29489
  chars: typeof desc === "string" ? desc.length : 0
29359
29490
  });
29360
29491
  if (typeof desc !== "string" || desc.length === 0) return [];
29492
+ const hintLine = typeof hint === "string" && hint && !desc.includes(hint) ? `Hint: ${hint}
29493
+ ` : "";
29361
29494
  return [{ type: "text", text: `${AUTO_DESCRIBE_HEADER}
29362
- ${desc}` }];
29495
+ ${hintLine}${desc}` }];
29363
29496
  } catch (e) {
29364
29497
  await spyLog({
29365
29498
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -29420,8 +29553,11 @@ ${desc}` }];
29420
29553
  authToken: AUTH_TOKEN,
29421
29554
  deviceId: getDeviceIdFromArgs(params.arguments)
29422
29555
  };
29556
+ const devicesText = canonicalToolId(params.name) === "list-devices" ? listDevicesText(result) : void 0;
29423
29557
  let content;
29424
- if (canonicalToolId(params.name) === "e2e-execute" && result && typeof result === "object" && ("e2eTest" in result || "flow" in result) && "steps" in result) {
29558
+ if (devicesText !== void 0) {
29559
+ content = [{ type: "text", text: devicesText }];
29560
+ } else if (canonicalToolId(params.name) === "e2e-execute" && result && typeof result === "object" && ("e2eTest" in result || "flow" in result) && "steps" in result) {
29425
29561
  content = await flowRunToMcpContent(result, ctx);
29426
29562
  } else if (params.name === "screenshot-diff" && isScreenshotDiffResult(result)) {
29427
29563
  content = await screenshotDiffToMcpContent(result, ctx);
@@ -29429,8 +29565,8 @@ ${desc}` }];
29429
29565
  content = await toMcpContent(result, outputHint, ctx, params.arguments);
29430
29566
  }
29431
29567
  const udid = getUdidFromArgs(params.arguments);
29432
- const wantScreenshot = autoScreenshotOn && shouldAutoScreenshot(params.name);
29433
- const wantTree = autoDescribeOn && shouldAutoDescribe(params.name);
29568
+ const wantScreenshot = autoScreenshotOn && shouldAutoScreenshot(params.name, params.arguments);
29569
+ const wantTree = autoDescribeOn && shouldAutoDescribe(params.name, params.arguments);
29434
29570
  if (udid && (wantScreenshot || wantTree) && containsSecretPlaceholder(params.arguments)) {
29435
29571
  content = [
29436
29572
  ...content,