@swmansion/argent 0.10.0 → 0.12.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 (63) hide show
  1. package/README.md +4 -1
  2. package/assets/argent.tracecfg.pbtxt +133 -0
  3. package/assets/queries/README.md +93 -0
  4. package/assets/queries/cpu-hotspots.sql +106 -0
  5. package/assets/queries/function-callers.sql +62 -0
  6. package/assets/queries/hang-folds-batched.sql +88 -0
  7. package/assets/queries/hang-main-thread-samples.sql +32 -0
  8. package/assets/queries/hang-state-breakdown.sql +44 -0
  9. package/assets/queries/memory-rss.sql +25 -0
  10. package/assets/queries/thread-breakdown.sql +34 -0
  11. package/assets/queries/trace-bounds.sql +6 -0
  12. package/assets/queries/ui-hangs.sql +59 -0
  13. package/assets/trace-processor/LICENSE +235 -0
  14. package/assets/trace-processor/SHA256SUMS +4 -0
  15. package/assets/trace-processor/engine.mjs +42423 -0
  16. package/assets/trace-processor/engine_bundle.node.js +11130 -0
  17. package/assets/trace-processor/trace_processor.wasm +0 -0
  18. package/{dist → bin}/argent-android-devtools-0.1.0.apk +0 -0
  19. package/bin/argent-simulator-server.cjs +11 -3
  20. package/bin/darwin/ax-service +0 -0
  21. package/bin/darwin/resources/android/LICENSE.txt +186 -0
  22. package/bin/darwin/resources/android/README.md +11 -0
  23. package/bin/darwin/resources/android/arm64-v8a/libscreen-sharing-agent.so +0 -0
  24. package/bin/darwin/resources/android/armeabi-v7a/libscreen-sharing-agent.so +0 -0
  25. package/bin/darwin/resources/android/screen-sharing-agent.jar +0 -0
  26. package/bin/darwin/resources/android/x86_64/libscreen-sharing-agent.so +0 -0
  27. package/bin/darwin/simulator-server +0 -0
  28. package/bin/linux/resources/android/LICENSE.txt +186 -0
  29. package/bin/linux/resources/android/README.md +11 -0
  30. package/bin/linux/resources/android/arm64-v8a/libscreen-sharing-agent.so +0 -0
  31. package/bin/linux/resources/android/armeabi-v7a/libscreen-sharing-agent.so +0 -0
  32. package/bin/linux/resources/android/screen-sharing-agent.jar +0 -0
  33. package/bin/linux/resources/android/x86_64/libscreen-sharing-agent.so +0 -0
  34. package/bin/linux/simulator-server +0 -0
  35. package/bin/linux-arm64/resources/android/LICENSE.txt +186 -0
  36. package/bin/linux-arm64/resources/android/README.md +11 -0
  37. package/bin/linux-arm64/resources/android/arm64-v8a/libscreen-sharing-agent.so +0 -0
  38. package/bin/linux-arm64/resources/android/armeabi-v7a/libscreen-sharing-agent.so +0 -0
  39. package/bin/linux-arm64/resources/android/screen-sharing-agent.jar +0 -0
  40. package/bin/linux-arm64/resources/android/x86_64/libscreen-sharing-agent.so +0 -0
  41. package/bin/linux-arm64/simulator-server +0 -0
  42. package/dist/cli-cmds.mjs +1858 -1578
  43. package/dist/cli.js +0 -3
  44. package/dist/cli.js.map +1 -1
  45. package/dist/installer.mjs +119 -96
  46. package/dist/mcp-server.mjs +452 -92
  47. package/dist/preview-ui/index.html +4500 -645
  48. package/dist/preview-ui/theme.css +231 -0
  49. package/dist/preview-window/main.cjs +182 -0
  50. package/dist/tool-server.cjs +11265 -5220
  51. package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
  52. package/dylibs/libKeyboardPatch.dylib +0 -0
  53. package/dylibs/libNativeDevtoolsIos.dylib +0 -0
  54. package/package.json +5 -2
  55. package/rules/argent.md +8 -2
  56. package/scripts/postinstall.cjs +6 -2
  57. package/skills/argent-device-interact/SKILL.md +36 -28
  58. package/skills/argent-lens/SKILL.md +101 -0
  59. package/skills/argent-metro-debugger/SKILL.md +18 -16
  60. package/skills/argent-native-profiler/SKILL.md +5 -5
  61. package/skills/argent-react-native-app-workflow/SKILL.md +8 -8
  62. /package/{dist → assets}/Argent.tracetemplate +0 -0
  63. /package/{manifest.json → assets/manifest.json} +0 -0
@@ -6,7 +6,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __commonJS = (cb, mod) => function __require() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ try {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ } catch (e) {
12
+ throw mod = 0, e;
13
+ }
10
14
  };
11
15
  var __export = (target, all) => {
12
16
  for (var name in all)
@@ -2980,7 +2984,7 @@ var require_compile = __commonJS({
2980
2984
  const schOrFunc = root.refs[ref];
2981
2985
  if (schOrFunc)
2982
2986
  return schOrFunc;
2983
- let _sch = resolve.call(this, root, ref);
2987
+ let _sch = resolve3.call(this, root, ref);
2984
2988
  if (_sch === void 0) {
2985
2989
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
2986
2990
  const { schemaId } = this.opts;
@@ -3007,7 +3011,7 @@ var require_compile = __commonJS({
3007
3011
  function sameSchemaEnv(s1, s2) {
3008
3012
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3009
3013
  }
3010
- function resolve(root, ref) {
3014
+ function resolve3(root, ref) {
3011
3015
  let sch;
3012
3016
  while (typeof (sch = this.refs[ref]) == "string")
3013
3017
  ref = sch;
@@ -3225,8 +3229,8 @@ var require_utils = __commonJS({
3225
3229
  }
3226
3230
  return ind;
3227
3231
  }
3228
- function removeDotSegments(path3) {
3229
- let input = path3;
3232
+ function removeDotSegments(path6) {
3233
+ let input = path6;
3230
3234
  const output = [];
3231
3235
  let nextSlash = -1;
3232
3236
  let len = 0;
@@ -3478,8 +3482,8 @@ var require_schemes = __commonJS({
3478
3482
  wsComponent.secure = void 0;
3479
3483
  }
3480
3484
  if (wsComponent.resourceName) {
3481
- const [path3, query] = wsComponent.resourceName.split("?");
3482
- wsComponent.path = path3 && path3 !== "/" ? path3 : void 0;
3485
+ const [path6, query] = wsComponent.resourceName.split("?");
3486
+ wsComponent.path = path6 && path6 !== "/" ? path6 : void 0;
3483
3487
  wsComponent.query = query;
3484
3488
  wsComponent.resourceName = void 0;
3485
3489
  }
@@ -3638,7 +3642,7 @@ var require_fast_uri = __commonJS({
3638
3642
  }
3639
3643
  return uri;
3640
3644
  }
3641
- function resolve(baseURI, relativeURI, options) {
3645
+ function resolve3(baseURI, relativeURI, options) {
3642
3646
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3643
3647
  const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
3644
3648
  schemelessOptions.skipEscape = true;
@@ -3896,7 +3900,7 @@ var require_fast_uri = __commonJS({
3896
3900
  var fastUri = {
3897
3901
  SCHEMES,
3898
3902
  normalize,
3899
- resolve,
3903
+ resolve: resolve3,
3900
3904
  resolveComponent,
3901
3905
  equal,
3902
3906
  serialize,
@@ -6872,12 +6876,12 @@ var require_dist = __commonJS({
6872
6876
  throw new Error(`Unknown format "${name}"`);
6873
6877
  return f;
6874
6878
  };
6875
- function addFormats(ajv, list, fs2, exportName) {
6879
+ function addFormats(ajv, list, fs4, exportName) {
6876
6880
  var _a3;
6877
6881
  var _b;
6878
6882
  (_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6879
6883
  for (const f of list)
6880
- ajv.addFormat(f, fs2[f]);
6884
+ ajv.addFormat(f, fs4[f]);
6881
6885
  }
6882
6886
  module.exports = exports = formatsPlugin;
6883
6887
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -6886,9 +6890,9 @@ var require_dist = __commonJS({
6886
6890
  });
6887
6891
 
6888
6892
  // ../argent-mcp/src/mcp-server.ts
6889
- import { appendFile, mkdir as mkdir3 } from "node:fs/promises";
6890
- import { dirname } from "node:path";
6891
- import { homedir as homedir3 } from "node:os";
6893
+ import { appendFile, mkdir as mkdir5 } from "node:fs/promises";
6894
+ import { dirname as dirname3 } from "node:path";
6895
+ import { homedir as homedir4 } from "node:os";
6892
6896
 
6893
6897
  // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
6894
6898
  import process3 from "node:process";
@@ -7133,10 +7137,10 @@ function mergeDefs(...defs) {
7133
7137
  function cloneDef(schema) {
7134
7138
  return mergeDefs(schema._zod.def);
7135
7139
  }
7136
- function getElementAtPath(obj, path3) {
7137
- if (!path3)
7140
+ function getElementAtPath(obj, path6) {
7141
+ if (!path6)
7138
7142
  return obj;
7139
- return path3.reduce((acc, key) => acc?.[key], obj);
7143
+ return path6.reduce((acc, key) => acc?.[key], obj);
7140
7144
  }
7141
7145
  function promiseAllObject(promisesObj) {
7142
7146
  const keys = Object.keys(promisesObj);
@@ -7545,11 +7549,11 @@ function explicitlyAborted(x, startIndex = 0) {
7545
7549
  }
7546
7550
  return false;
7547
7551
  }
7548
- function prefixIssues(path3, issues) {
7552
+ function prefixIssues(path6, issues) {
7549
7553
  return issues.map((iss) => {
7550
7554
  var _a3;
7551
7555
  (_a3 = iss).path ?? (_a3.path = []);
7552
- iss.path.unshift(path3);
7556
+ iss.path.unshift(path6);
7553
7557
  return iss;
7554
7558
  });
7555
7559
  }
@@ -7696,16 +7700,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
7696
7700
  }
7697
7701
  function formatError(error2, mapper = (issue2) => issue2.message) {
7698
7702
  const fieldErrors = { _errors: [] };
7699
- const processError = (error3, path3 = []) => {
7703
+ const processError = (error3, path6 = []) => {
7700
7704
  for (const issue2 of error3.issues) {
7701
7705
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7702
- issue2.errors.map((issues) => processError({ issues }, [...path3, ...issue2.path]));
7706
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
7703
7707
  } else if (issue2.code === "invalid_key") {
7704
- processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
7708
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
7705
7709
  } else if (issue2.code === "invalid_element") {
7706
- processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
7710
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
7707
7711
  } else {
7708
- const fullpath = [...path3, ...issue2.path];
7712
+ const fullpath = [...path6, ...issue2.path];
7709
7713
  if (fullpath.length === 0) {
7710
7714
  fieldErrors._errors.push(mapper(issue2));
7711
7715
  } else {
@@ -13697,12 +13701,12 @@ var StdioServerTransport = class {
13697
13701
  this.onclose?.();
13698
13702
  }
13699
13703
  send(message) {
13700
- return new Promise((resolve) => {
13704
+ return new Promise((resolve3) => {
13701
13705
  const json = serializeMessage(message);
13702
13706
  if (this._stdout.write(json)) {
13703
- resolve();
13707
+ resolve3();
13704
13708
  } else {
13705
- this._stdout.once("drain", resolve);
13709
+ this._stdout.once("drain", resolve3);
13706
13710
  }
13707
13711
  });
13708
13712
  }
@@ -14300,7 +14304,7 @@ var Protocol = class {
14300
14304
  return;
14301
14305
  }
14302
14306
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
14303
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
14307
+ await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
14304
14308
  options?.signal?.throwIfAborted();
14305
14309
  }
14306
14310
  } catch (error2) {
@@ -14317,7 +14321,7 @@ var Protocol = class {
14317
14321
  */
14318
14322
  request(request, resultSchema, options) {
14319
14323
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
14320
- return new Promise((resolve, reject) => {
14324
+ return new Promise((resolve3, reject) => {
14321
14325
  const earlyReject = (error2) => {
14322
14326
  reject(error2);
14323
14327
  };
@@ -14395,7 +14399,7 @@ var Protocol = class {
14395
14399
  if (!parseResult.success) {
14396
14400
  reject(parseResult.error);
14397
14401
  } else {
14398
- resolve(parseResult.data);
14402
+ resolve3(parseResult.data);
14399
14403
  }
14400
14404
  } catch (error2) {
14401
14405
  reject(error2);
@@ -14611,21 +14615,21 @@ var Protocol = class {
14611
14615
  * the error appropriately (e.g., by failing the task, logging, etc.). The Protocol layer
14612
14616
  * simply propagates the error.
14613
14617
  */
14614
- async _enqueueTaskMessage(taskId, message, sessionId) {
14618
+ async _enqueueTaskMessage(taskId, message, sessionId2) {
14615
14619
  if (!this._taskStore || !this._taskMessageQueue) {
14616
14620
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
14617
14621
  }
14618
14622
  const maxQueueSize = this._options?.maxTaskQueueSize;
14619
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
14623
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId2, maxQueueSize);
14620
14624
  }
14621
14625
  /**
14622
14626
  * Clears the message queue for a task and rejects any pending request resolvers.
14623
14627
  * @param taskId The task ID whose queue should be cleared
14624
14628
  * @param sessionId Optional session ID for binding the operation to a specific session
14625
14629
  */
14626
- async _clearTaskQueue(taskId, sessionId) {
14630
+ async _clearTaskQueue(taskId, sessionId2) {
14627
14631
  if (this._taskMessageQueue) {
14628
- const messages = await this._taskMessageQueue.dequeueAll(taskId, sessionId);
14632
+ const messages = await this._taskMessageQueue.dequeueAll(taskId, sessionId2);
14629
14633
  for (const message of messages) {
14630
14634
  if (message.type === "request" && isJSONRPCRequest(message.message)) {
14631
14635
  const requestId = message.message.id;
@@ -14656,19 +14660,19 @@ var Protocol = class {
14656
14660
  }
14657
14661
  } catch {
14658
14662
  }
14659
- return new Promise((resolve, reject) => {
14663
+ return new Promise((resolve3, reject) => {
14660
14664
  if (signal.aborted) {
14661
14665
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
14662
14666
  return;
14663
14667
  }
14664
- const timeoutId = setTimeout(resolve, interval);
14668
+ const timeoutId = setTimeout(resolve3, interval);
14665
14669
  signal.addEventListener("abort", () => {
14666
14670
  clearTimeout(timeoutId);
14667
14671
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
14668
14672
  }, { once: true });
14669
14673
  });
14670
14674
  }
14671
- requestTaskStore(request, sessionId) {
14675
+ requestTaskStore(request, sessionId2) {
14672
14676
  const taskStore = this._taskStore;
14673
14677
  if (!taskStore) {
14674
14678
  throw new Error("No task store configured");
@@ -14681,18 +14685,18 @@ var Protocol = class {
14681
14685
  return await taskStore.createTask(taskParams, request.id, {
14682
14686
  method: request.method,
14683
14687
  params: request.params
14684
- }, sessionId);
14688
+ }, sessionId2);
14685
14689
  },
14686
14690
  getTask: async (taskId) => {
14687
- const task = await taskStore.getTask(taskId, sessionId);
14691
+ const task = await taskStore.getTask(taskId, sessionId2);
14688
14692
  if (!task) {
14689
14693
  throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
14690
14694
  }
14691
14695
  return task;
14692
14696
  },
14693
14697
  storeTaskResult: async (taskId, status, result) => {
14694
- await taskStore.storeTaskResult(taskId, status, result, sessionId);
14695
- const task = await taskStore.getTask(taskId, sessionId);
14698
+ await taskStore.storeTaskResult(taskId, status, result, sessionId2);
14699
+ const task = await taskStore.getTask(taskId, sessionId2);
14696
14700
  if (task) {
14697
14701
  const notification = TaskStatusNotificationSchema.parse({
14698
14702
  method: "notifications/tasks/status",
@@ -14705,18 +14709,18 @@ var Protocol = class {
14705
14709
  }
14706
14710
  },
14707
14711
  getTaskResult: (taskId) => {
14708
- return taskStore.getTaskResult(taskId, sessionId);
14712
+ return taskStore.getTaskResult(taskId, sessionId2);
14709
14713
  },
14710
14714
  updateTaskStatus: async (taskId, status, statusMessage) => {
14711
- const task = await taskStore.getTask(taskId, sessionId);
14715
+ const task = await taskStore.getTask(taskId, sessionId2);
14712
14716
  if (!task) {
14713
14717
  throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
14714
14718
  }
14715
14719
  if (isTerminal(task.status)) {
14716
14720
  throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
14717
14721
  }
14718
- await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
14719
- const updatedTask = await taskStore.getTask(taskId, sessionId);
14722
+ await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId2);
14723
+ const updatedTask = await taskStore.getTask(taskId, sessionId2);
14720
14724
  if (updatedTask) {
14721
14725
  const notification = TaskStatusNotificationSchema.parse({
14722
14726
  method: "notifications/tasks/status",
@@ -14729,7 +14733,7 @@ var Protocol = class {
14729
14733
  }
14730
14734
  },
14731
14735
  listTasks: (cursor) => {
14732
- return taskStore.listTasks(cursor, sessionId);
14736
+ return taskStore.listTasks(cursor, sessionId2);
14733
14737
  }
14734
14738
  };
14735
14739
  }
@@ -15080,8 +15084,8 @@ var Server = class extends Protocol {
15080
15084
  this._serverInfo = _serverInfo;
15081
15085
  this._loggingLevels = /* @__PURE__ */ new Map();
15082
15086
  this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
15083
- this.isMessageIgnored = (level, sessionId) => {
15084
- const currentLevel = this._loggingLevels.get(sessionId);
15087
+ this.isMessageIgnored = (level, sessionId2) => {
15088
+ const currentLevel = this._loggingLevels.get(sessionId2);
15085
15089
  return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
15086
15090
  };
15087
15091
  this._capabilities = options?.capabilities ?? {};
@@ -15424,9 +15428,9 @@ var Server = class extends Protocol {
15424
15428
  * @param params
15425
15429
  * @param sessionId optional for stateless and backward compatibility
15426
15430
  */
15427
- async sendLoggingMessage(params, sessionId) {
15431
+ async sendLoggingMessage(params, sessionId2) {
15428
15432
  if (this._capabilities.logging) {
15429
- if (!this.isMessageIgnored(params.level, sessionId)) {
15433
+ if (!this.isMessageIgnored(params.level, sessionId2)) {
15430
15434
  return this.notification({ method: "notifications/message", params });
15431
15435
  }
15432
15436
  }
@@ -15483,7 +15487,7 @@ function generateToken() {
15483
15487
  return randomBytes(AUTH_TOKEN_BYTES).toString("hex");
15484
15488
  }
15485
15489
  function findFreePort() {
15486
- return new Promise((resolve, reject) => {
15490
+ return new Promise((resolve3, reject) => {
15487
15491
  const srv = net.createServer();
15488
15492
  srv.listen(0, "127.0.0.1", () => {
15489
15493
  const addr = srv.address();
@@ -15494,7 +15498,7 @@ function findFreePort() {
15494
15498
  const port = addr.port;
15495
15499
  srv.close((err) => {
15496
15500
  if (err) reject(err);
15497
- else resolve(port);
15501
+ else resolve3(port);
15498
15502
  });
15499
15503
  });
15500
15504
  srv.on("error", reject);
@@ -15536,7 +15540,7 @@ async function isToolsServerHealthy(port, host = "127.0.0.1", timeoutMs = 2e3, t
15536
15540
  }
15537
15541
  }
15538
15542
  function spawnToolsServer(paths, port, options = {}) {
15539
- return new Promise((resolve, reject) => {
15543
+ return new Promise((resolve3, reject) => {
15540
15544
  let logFd;
15541
15545
  try {
15542
15546
  fs.mkdirSync(STATE_DIR, { recursive: true });
@@ -15568,7 +15572,7 @@ function spawnToolsServer(paths, port, options = {}) {
15568
15572
  const actualPort = parseInt(match[1], 10);
15569
15573
  rl.close();
15570
15574
  child.stdout?.resume();
15571
- settle(() => resolve({ port: actualPort, pid }));
15575
+ settle(() => resolve3({ port: actualPort, pid }));
15572
15576
  }
15573
15577
  });
15574
15578
  child.on("error", (err) => {
@@ -15699,9 +15703,236 @@ async function isRemoteRouted() {
15699
15703
  return url !== null;
15700
15704
  }
15701
15705
 
15702
- // ../argent-mcp/src/content.ts
15706
+ // ../argent-tools-client/src/file-inputs.ts
15707
+ import { mkdir as mkdir3, stat, writeFile as writeFile3 } from "node:fs/promises";
15703
15708
  import { readFile as readFile3 } from "node:fs/promises";
15709
+ import * as path3 from "node:path";
15710
+ var FILE_INPUT_MARKER = "__argentFileInput";
15711
+ var CLIENT_FILE_MARKER = "__argentClientFile";
15712
+ var MAX_CONTENT_BYTES = 32 * 1024 * 1024;
15713
+ function interpolatePath(template, args) {
15714
+ let missing = false;
15715
+ const out = template.replace(/\$\{([A-Za-z0-9_]+)\}/g, (_m, name) => {
15716
+ const v = args[name];
15717
+ if (typeof v !== "string" || v.length === 0) {
15718
+ missing = true;
15719
+ return "";
15720
+ }
15721
+ return v;
15722
+ });
15723
+ return missing ? null : out;
15724
+ }
15725
+ async function prepareFileInputs(specs, args, opts) {
15726
+ if (!specs || specs.length === 0 || typeof args !== "object" || args === null) {
15727
+ return args;
15728
+ }
15729
+ const record2 = args;
15730
+ let out = null;
15731
+ for (const spec of specs) {
15732
+ if (spec.target in record2 && typeof record2[spec.target] !== "string") continue;
15733
+ const filePath = interpolatePath(spec.path, record2);
15734
+ if (filePath === null) continue;
15735
+ if (spec.target in record2 && record2[spec.target] !== filePath) continue;
15736
+ const wire = { [FILE_INPUT_MARKER]: true, path: filePath };
15737
+ if (spec.kind === "file") {
15738
+ try {
15739
+ const st = await stat(filePath);
15740
+ if (st.isFile()) {
15741
+ wire.size = st.size;
15742
+ wire.mtimeMs = st.mtimeMs;
15743
+ if (opts.includeContent && st.size <= MAX_CONTENT_BYTES) {
15744
+ wire.content = (await readFile3(filePath)).toString("base64");
15745
+ } else if (opts.includeContent) {
15746
+ wire.contentOmitted = "size-limit";
15747
+ }
15748
+ }
15749
+ } catch {
15750
+ }
15751
+ }
15752
+ out = out ?? { ...record2 };
15753
+ out[spec.target] = wire;
15754
+ }
15755
+ return out ?? args;
15756
+ }
15757
+ function isAllowedClientFilePath(p) {
15758
+ if (!path3.isAbsolute(p)) return false;
15759
+ const segments = p.split(/[\\/]+/);
15760
+ if (segments.includes("..")) return false;
15761
+ const file = segments[segments.length - 1] ?? "";
15762
+ if (!/^[A-Za-z0-9_-]+\.yaml$/.test(file)) return false;
15763
+ return segments[segments.length - 3] === ".argent" && segments[segments.length - 2] === "flows";
15764
+ }
15765
+ function isClientFileDirective(value) {
15766
+ return !!value && typeof value === "object" && value[CLIENT_FILE_MARKER] === true && typeof value.path === "string" && typeof value.content === "string";
15767
+ }
15768
+ async function applyClientFileDirectives(result) {
15769
+ const written = [];
15770
+ async function walk(value) {
15771
+ if (isClientFileDirective(value)) {
15772
+ if (!isAllowedClientFilePath(value.path)) return null;
15773
+ try {
15774
+ await mkdir3(path3.dirname(value.path), { recursive: true });
15775
+ await writeFile3(value.path, value.content, "utf8");
15776
+ written.push(value.path);
15777
+ return value.path;
15778
+ } catch {
15779
+ return null;
15780
+ }
15781
+ }
15782
+ if (Array.isArray(value)) {
15783
+ return Promise.all(value.map(walk));
15784
+ }
15785
+ if (value && typeof value === "object") {
15786
+ const out = {};
15787
+ for (const [k, v] of Object.entries(value)) {
15788
+ out[k] = await walk(v);
15789
+ }
15790
+ return out;
15791
+ }
15792
+ return value;
15793
+ }
15794
+ const rewritten = await walk(result);
15795
+ return { result: rewritten, written };
15796
+ }
15797
+
15798
+ // ../argent-tools-client/src/artifacts.ts
15799
+ import { mkdir as mkdir4, readFile as readFile4, rm, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
15800
+ import { tmpdir } from "node:os";
15801
+ import { basename, join as join3 } from "node:path";
15802
+ import { createHash } from "node:crypto";
15803
+ import { execFile } from "node:child_process";
15804
+ import { promisify } from "node:util";
15805
+ var execFileAsync = promisify(execFile);
15806
+ var ARTIFACT_MARKER = "__argentArtifact";
15807
+ function isArtifactHandle(value) {
15808
+ return !!value && typeof value === "object" && value[ARTIFACT_MARKER] === true && typeof value.id === "string" && typeof value.filename === "string";
15809
+ }
15810
+ var SESSION_ID = null;
15811
+ function sessionId() {
15812
+ if (!SESSION_ID) {
15813
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, (m) => m === "T" ? "-" : "").slice(0, 15);
15814
+ SESSION_ID = `${stamp}-${process.pid}`;
15815
+ }
15816
+ return SESSION_ID;
15817
+ }
15818
+ function sanitizeSegment(segment) {
15819
+ return segment.replace(/[^A-Za-z0-9._-]/g, "_");
15820
+ }
15821
+ function projectSlug() {
15822
+ const cwd = process.cwd();
15823
+ const hash = createHash("sha1").update(cwd).digest("hex").slice(0, 6);
15824
+ const name = sanitizeSegment(basename(cwd)) || "root";
15825
+ return `${name}-${hash}`;
15826
+ }
15827
+ function artifactsRoot() {
15828
+ return process.env.ARGENT_ARTIFACTS_DIR ?? join3(tmpdir(), "argent-artifacts");
15829
+ }
15830
+ function artifactDir(deviceId) {
15831
+ const parts = [artifactsRoot(), projectSlug(), sessionId()];
15832
+ if (deviceId) parts.push(sanitizeSegment(deviceId));
15833
+ return join3(...parts);
15834
+ }
15835
+ async function resolveLocalFile(handle) {
15836
+ if (!handle.hostPath) return null;
15837
+ try {
15838
+ const st = await stat2(handle.hostPath);
15839
+ if (handle.archive) {
15840
+ return st.isDirectory() ? handle.hostPath : null;
15841
+ }
15842
+ if (!st.isFile()) return null;
15843
+ if (st.size !== handle.size) return null;
15844
+ if (handle.mtimeMs != null && Math.round(st.mtimeMs) !== Math.round(handle.mtimeMs)) {
15845
+ return null;
15846
+ }
15847
+ return handle.hostPath;
15848
+ } catch {
15849
+ return null;
15850
+ }
15851
+ }
15852
+ async function downloadAndExtractArchive(handle, data, dir) {
15853
+ const tarball = join3(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
15854
+ try {
15855
+ await writeFile4(tarball, data);
15856
+ await execFileAsync("tar", ["-xzf", tarball, "-C", dir]);
15857
+ return join3(dir, handle.filename);
15858
+ } catch {
15859
+ return null;
15860
+ } finally {
15861
+ await rm(tarball, { force: true }).catch(() => {
15862
+ });
15863
+ }
15864
+ }
15865
+ async function materializeArtifacts(result, ctx) {
15866
+ const images = [];
15867
+ const fetchFn = ctx.fetchImpl ?? fetch;
15868
+ const authHeaders2 = ctx.authToken ? { Authorization: `Bearer ${ctx.authToken}` } : {};
15869
+ const dir = artifactDir(ctx.deviceId);
15870
+ let dirReady = false;
15871
+ async function ensureDir() {
15872
+ if (!dirReady) {
15873
+ await mkdir4(dir, { recursive: true });
15874
+ dirReady = true;
15875
+ }
15876
+ }
15877
+ async function walk(value) {
15878
+ if (isArtifactHandle(value)) {
15879
+ const localPath = await resolveLocalFile(value);
15880
+ if (localPath) {
15881
+ if (value.mimeType.startsWith("image/")) {
15882
+ images.push({ localPath, data: await readFile4(localPath), mimeType: value.mimeType });
15883
+ }
15884
+ return localPath;
15885
+ }
15886
+ try {
15887
+ const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
15888
+ headers: authHeaders2
15889
+ });
15890
+ if (!res.ok) return null;
15891
+ const data = Buffer.from(await res.arrayBuffer());
15892
+ await ensureDir();
15893
+ if (value.archive === "tar.gz") {
15894
+ return await downloadAndExtractArchive(value, data, dir);
15895
+ }
15896
+ if (value.size > 0 && data.length !== value.size) return null;
15897
+ const downloadedPath = join3(dir, sanitizeSegment(value.filename));
15898
+ await writeFile4(downloadedPath, data);
15899
+ if (value.mimeType.startsWith("image/")) {
15900
+ images.push({ localPath: downloadedPath, data, mimeType: value.mimeType });
15901
+ }
15902
+ return downloadedPath;
15903
+ } catch {
15904
+ return null;
15905
+ }
15906
+ }
15907
+ if (Array.isArray(value)) {
15908
+ return Promise.all(value.map(walk));
15909
+ }
15910
+ if (value && typeof value === "object") {
15911
+ const out = {};
15912
+ for (const [k, v] of Object.entries(value)) {
15913
+ out[k] = await walk(v);
15914
+ }
15915
+ return out;
15916
+ }
15917
+ return value;
15918
+ }
15919
+ const rewritten = await walk(result);
15920
+ return { result: rewritten, images };
15921
+ }
15922
+ function getDeviceIdFromArgs(args) {
15923
+ if (!args || typeof args !== "object") return void 0;
15924
+ const rec = args;
15925
+ if (typeof rec.udid === "string") return rec.udid;
15926
+ if (typeof rec.device_id === "string") return rec.device_id;
15927
+ return void 0;
15928
+ }
15929
+
15930
+ // ../argent-mcp/src/content.ts
15931
+ import { readFile as readFile5 } from "node:fs/promises";
15704
15932
  var PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
15933
+ function imageBlock(data, mimeType) {
15934
+ return { type: "image", data: data.toString("base64"), mimeType };
15935
+ }
15705
15936
  async function fetchPngBytes(url) {
15706
15937
  try {
15707
15938
  const res = await fetch(url);
@@ -15714,22 +15945,38 @@ async function fetchPngBytes(url) {
15714
15945
  return null;
15715
15946
  }
15716
15947
  }
15717
- async function toMcpContent(result, outputHint, args) {
15718
- if (outputHint === "image" && result && typeof result === "object" && "url" in result) {
15948
+ async function toMcpContent(result, outputHint, ctx, args) {
15949
+ const suppressImage = isRecord(args) && args.includeImageInContext === false;
15950
+ if (ctx) {
15951
+ const { result: rewritten, images } = await materializeArtifacts(result, ctx);
15952
+ if (outputHint === "image") {
15953
+ if (images.length > 0) {
15954
+ const saved = { type: "text", text: `Saved: ${images[0].localPath}` };
15955
+ if (suppressImage) return [saved];
15956
+ const blocks2 = images.map((img) => imageBlock(img.data, img.mimeType));
15957
+ blocks2.push(saved);
15958
+ return blocks2;
15959
+ }
15960
+ return legacyImageContent(rewritten, suppressImage);
15961
+ }
15962
+ const blocks = [{ type: "text", text: JSON.stringify(rewritten, null, 2) }];
15963
+ if (!suppressImage) for (const img of images) blocks.push(imageBlock(img.data, img.mimeType));
15964
+ return blocks;
15965
+ }
15966
+ if (outputHint === "image") {
15967
+ return legacyImageContent(result, suppressImage);
15968
+ }
15969
+ return [{ type: "text", text: JSON.stringify(result, null, 2) }];
15970
+ }
15971
+ async function legacyImageContent(result, suppressImage) {
15972
+ if (result && typeof result === "object" && "url" in result) {
15719
15973
  const r = result;
15720
- if (isRecord(args) && args.includeImageInContext === false) {
15721
- return [{ type: "text", text: `Saved: ${r.path}` }];
15974
+ if (suppressImage) {
15975
+ return [{ type: "text", text: `Saved: ${r.path ?? ""}` }];
15722
15976
  }
15723
15977
  const buf = await fetchPngBytes(r.url);
15724
15978
  if (buf) {
15725
- return [
15726
- {
15727
- type: "image",
15728
- data: buf.toString("base64"),
15729
- mimeType: "image/png"
15730
- },
15731
- { type: "text", text: `Saved: ${r.path ?? ""}` }
15732
- ];
15979
+ return [imageBlock(buf, "image/png"), { type: "text", text: `Saved: ${r.path ?? ""}` }];
15733
15980
  }
15734
15981
  return [
15735
15982
  {
@@ -15747,20 +15994,39 @@ function isScreenshotDiffResult(value) {
15747
15994
  if (!isRecord(value)) return false;
15748
15995
  return typeof value.summary === "string";
15749
15996
  }
15750
- async function screenshotDiffToMcpContent(result) {
15997
+ async function screenshotDiffToMcpContent(result, ctx) {
15751
15998
  const blocks = [];
15752
- if (typeof result.contextDiffPath === "string") {
15753
- const buf = await readFile3(result.contextDiffPath);
15754
- blocks.push({
15755
- type: "image",
15756
- data: buf.toString("base64"),
15757
- mimeType: "image/png"
15758
- });
15999
+ let contextDiffPath = result.contextDiffPath;
16000
+ let materializedImages = [];
16001
+ if (ctx) {
16002
+ const { result: rewritten, images } = await materializeArtifacts(result, ctx);
16003
+ contextDiffPath = rewritten.contextDiffPath;
16004
+ materializedImages = images;
16005
+ }
16006
+ if (typeof contextDiffPath === "string") {
16007
+ const fromMaterializer = materializedImages.find((img) => img.localPath === contextDiffPath);
16008
+ if (fromMaterializer) {
16009
+ blocks.push({
16010
+ type: "image",
16011
+ data: fromMaterializer.data.toString("base64"),
16012
+ mimeType: fromMaterializer.mimeType
16013
+ });
16014
+ } else {
16015
+ try {
16016
+ const buf = await readFile5(contextDiffPath);
16017
+ blocks.push({
16018
+ type: "image",
16019
+ data: buf.toString("base64"),
16020
+ mimeType: "image/png"
16021
+ });
16022
+ } catch {
16023
+ }
16024
+ }
15759
16025
  }
15760
16026
  blocks.push({ type: "text", text: result.summary });
15761
16027
  return blocks;
15762
16028
  }
15763
- async function flowRunToMcpContent(result) {
16029
+ async function flowRunToMcpContent(result, ctx) {
15764
16030
  const blocks = [];
15765
16031
  if (result.executionPrerequisite) {
15766
16032
  blocks.push({
@@ -15784,7 +16050,7 @@ async function flowRunToMcpContent(result) {
15784
16050
  });
15785
16051
  } else {
15786
16052
  blocks.push({ type: "text", text: `[${num}] ${step.tool}` });
15787
- const stepContent = await toMcpContent(step.result, step.outputHint, step.args);
16053
+ const stepContent = await toMcpContent(step.result, step.outputHint, ctx, step.args);
15788
16054
  blocks.push(...stepContent);
15789
16055
  }
15790
16056
  }
@@ -15792,10 +16058,70 @@ async function flowRunToMcpContent(result) {
15792
16058
  return blocks;
15793
16059
  }
15794
16060
 
16061
+ // ../configuration-core/src/flags.ts
16062
+ import * as fs2 from "node:fs";
16063
+ import * as path4 from "node:path";
16064
+ import { homedir as homedir3 } from "node:os";
16065
+ var PROJECT_MARKERS = [".argent", ".git", "package.json"];
16066
+ function resolveProjectRoot(startDir) {
16067
+ const initial = path4.resolve(startDir);
16068
+ let current = initial;
16069
+ while (true) {
16070
+ for (const marker of PROJECT_MARKERS) {
16071
+ if (fs2.existsSync(path4.join(current, marker))) return current;
16072
+ }
16073
+ const parent = path4.dirname(current);
16074
+ if (parent === current) return initial;
16075
+ current = parent;
16076
+ }
16077
+ }
16078
+ function getFlagsPath(scope, options = {}) {
16079
+ const home = options.homeDir ?? homedir3();
16080
+ if (scope === "global") {
16081
+ return path4.join(home, ".argent", "flags.json");
16082
+ }
16083
+ const cwd = options.cwd ?? process.cwd();
16084
+ return path4.join(resolveProjectRoot(cwd), ".argent", "flags.json");
16085
+ }
16086
+ function readFlagsFile(filePath) {
16087
+ let raw;
16088
+ try {
16089
+ raw = fs2.readFileSync(filePath, "utf8");
16090
+ } catch {
16091
+ return {};
16092
+ }
16093
+ let parsed;
16094
+ try {
16095
+ parsed = JSON.parse(raw);
16096
+ } catch {
16097
+ return {};
16098
+ }
16099
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
16100
+ const flags = parsed.flags;
16101
+ if (!flags || typeof flags !== "object" || Array.isArray(flags)) return {};
16102
+ const out = {};
16103
+ for (const [k, v] of Object.entries(flags)) {
16104
+ if (typeof v === "boolean") out[k] = v;
16105
+ }
16106
+ return out;
16107
+ }
16108
+ function readFlags(scope, options = {}) {
16109
+ return readFlagsFile(getFlagsPath(scope, options));
16110
+ }
16111
+ function isFlagEnabled(name, options = {}) {
16112
+ const projectFlags = readFlags("project", options);
16113
+ if (Object.hasOwn(projectFlags, name)) return projectFlags[name];
16114
+ const globalFlags = readFlags("global", options);
16115
+ if (Object.hasOwn(globalFlags, name)) return globalFlags[name];
16116
+ return false;
16117
+ }
16118
+
15795
16119
  // ../argent-mcp/src/auto-screenshot.ts
15796
16120
  var AUTO_SCREENSHOT_TOOLS = /* @__PURE__ */ new Set([
15797
16121
  "gesture-tap",
15798
16122
  "gesture-swipe",
16123
+ "gesture-scroll",
16124
+ "gesture-drag",
15799
16125
  "gesture-custom",
15800
16126
  "gesture-pinch",
15801
16127
  "gesture-rotate",
@@ -15813,6 +16139,8 @@ var AUTO_SCREENSHOT_DELAY_MS_BY_TOOL = {
15813
16139
  "restart-app": 3e3,
15814
16140
  "open-url": 2e3,
15815
16141
  "gesture-swipe": 1500,
16142
+ "gesture-scroll": 1500,
16143
+ "gesture-drag": 1500,
15816
16144
  "gesture-custom": 1500,
15817
16145
  "gesture-tap": 1500,
15818
16146
  "gesture-pinch": 1500,
@@ -15824,9 +16152,8 @@ var AUTO_SCREENSHOT_DELAY_MS_BY_TOOL = {
15824
16152
  "describe": 100
15825
16153
  };
15826
16154
  var DEFAULT_DELAY_MS = 1400;
15827
- function autoScreenshotEnabled() {
15828
- const v = process.env.ARGENT_AUTO_SCREENSHOT;
15829
- return v === void 0 || v === "" || v === "1" || v.toLowerCase() === "true";
16155
+ function autoScreenshotEnabled(options) {
16156
+ return !isFlagEnabled("disable-auto-screenshot", options);
15830
16157
  }
15831
16158
  function getUdidFromArgs(args) {
15832
16159
  if (args && typeof args === "object" && "udid" in args && typeof args.udid === "string") {
@@ -15866,6 +16193,19 @@ function toMcpTool(t) {
15866
16193
  };
15867
16194
  }
15868
16195
 
16196
+ // ../argent-mcp/src/installed-version.ts
16197
+ import * as fs3 from "node:fs";
16198
+ import * as path5 from "node:path";
16199
+ function getInstalledVersion() {
16200
+ try {
16201
+ const pkgPath = path5.resolve(import.meta.dirname, "..", "package.json");
16202
+ const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf8"));
16203
+ return pkg.version ?? "unknown";
16204
+ } catch {
16205
+ return "unknown";
16206
+ }
16207
+ }
16208
+
15869
16209
  // ../argent-mcp/src/mcp-server.ts
15870
16210
  var MAX_RETRIES = 4;
15871
16211
  var EXP_BACKOFF_BASE = 250;
@@ -15897,6 +16237,7 @@ async function fetchWithReconnect(getUrl, reconnect, config2) {
15897
16237
  throw lastError;
15898
16238
  }
15899
16239
  async function startMcpServer(options) {
16240
+ const autoScreenshotOn = autoScreenshotEnabled();
15900
16241
  let TOOLS_URL;
15901
16242
  let AUTH_TOKEN;
15902
16243
  const resolved = await getResolvedToolsUrl();
@@ -15930,12 +16271,12 @@ async function startMcpServer(options) {
15930
16271
  }
15931
16272
  return reconnectPromise;
15932
16273
  }
15933
- const LOG_FILE2 = process.env.ARGENT_MCP_LOG ?? `${homedir3()}/.argent/mcp-calls.log`;
16274
+ const LOG_FILE2 = process.env.ARGENT_MCP_LOG ?? `${homedir4()}/.argent/mcp-calls.log`;
15934
16275
  let logDirReady = false;
15935
16276
  async function spyLog(entry) {
15936
16277
  try {
15937
16278
  if (!logDirReady) {
15938
- await mkdir3(dirname(LOG_FILE2), { recursive: true });
16279
+ await mkdir5(dirname3(LOG_FILE2), { recursive: true });
15939
16280
  logDirReady = true;
15940
16281
  }
15941
16282
  await appendFile(LOG_FILE2, JSON.stringify(entry) + "\n");
@@ -15952,23 +16293,33 @@ async function startMcpServer(options) {
15952
16293
  async function callTool(name, args) {
15953
16294
  const tools = await fetchTools();
15954
16295
  const meta2 = tools.find((t) => t.name === name);
16296
+ let finalArgs = args;
16297
+ if (meta2?.fileInputs?.length) {
16298
+ finalArgs = await prepareFileInputs(meta2.fileInputs, args ?? {}, {
16299
+ // `resolved` is the startup routing decision that picked TOOLS_URL —
16300
+ // an external target means this process may not share the server's
16301
+ // filesystem, so file bytes must ride along.
16302
+ includeContent: resolved.url !== null
16303
+ });
16304
+ }
15955
16305
  const res = await fetchWithReconnect(() => `${TOOLS_URL}/tools/${name}`, reconnect, {
15956
16306
  init: {
15957
16307
  method: "POST",
15958
16308
  headers: { "Content-Type": "application/json", ...authHeader() },
15959
- body: JSON.stringify(args ?? {})
16309
+ body: JSON.stringify(finalArgs ?? {})
15960
16310
  },
15961
16311
  fetchTimeoutMs: meta2?.longRunning ? null : FETCH_TIMEOUT_MS
15962
16312
  });
15963
16313
  const json = await res.json();
15964
16314
  if (!res.ok) throw new Error(json.error ?? json.message ?? res.statusText);
15965
- return { result: json.data, outputHint: meta2?.outputHint, note: json.note };
16315
+ const { result: data } = await applyClientFileDirectives(json.data);
16316
+ return { result: data, outputHint: meta2?.outputHint, note: json.note };
15966
16317
  }
15967
16318
  const server = new Server(
15968
- { name: "argent", version: "0.5.3" },
16319
+ { name: "argent", version: getInstalledVersion() },
15969
16320
  {
15970
16321
  capabilities: { tools: {} },
15971
- instructions: "Argent \u2014 iOS Simulator and Android Emulator control for interacting, testing, profiling and debugging mobile applications. Always use discovery tools (describe / debugger-component-tree / screenshot) before tapping \u2014 never guess coordinates. On session end: call stop-all-simulator-servers and perform any necessary cleanup. Full guidance is in the argent rule loaded from .claude/rules/argent.md."
16322
+ instructions: "Argent \u2014 iOS Simulator, Android Emulator, and Chromium app control for interacting, testing, profiling and debugging mobile and Chromium applications. Always use discovery tools (describe / debugger-component-tree / screenshot) before tapping \u2014 never guess coordinates. On session end: call stop-all-simulator-servers and perform any necessary cleanup. Full guidance is in the argent rule loaded from .claude/rules/argent.md."
15972
16323
  }
15973
16324
  );
15974
16325
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -16006,21 +16357,30 @@ async function startMcpServer(options) {
16006
16357
  isError: false,
16007
16358
  result
16008
16359
  });
16360
+ const ctx = {
16361
+ toolsUrl: TOOLS_URL,
16362
+ authToken: AUTH_TOKEN,
16363
+ deviceId: getDeviceIdFromArgs(params.arguments)
16364
+ };
16009
16365
  let content;
16010
16366
  if (params.name === "flow-execute" && result && typeof result === "object" && "flow" in result && "steps" in result) {
16011
- content = await flowRunToMcpContent(result);
16367
+ content = await flowRunToMcpContent(result, ctx);
16012
16368
  } else if (params.name === "screenshot-diff" && isScreenshotDiffResult(result)) {
16013
- content = await screenshotDiffToMcpContent(result);
16369
+ content = await screenshotDiffToMcpContent(result, ctx);
16014
16370
  } else {
16015
- content = await toMcpContent(result, outputHint, params.arguments);
16371
+ content = await toMcpContent(result, outputHint, ctx, params.arguments);
16016
16372
  }
16017
16373
  const udid = getUdidFromArgs(params.arguments);
16018
- if (autoScreenshotEnabled() && udid && shouldAutoScreenshot(params.name)) {
16374
+ if (autoScreenshotOn && udid && shouldAutoScreenshot(params.name)) {
16019
16375
  const delayMs = getAutoScreenshotDelayMs(params.name);
16020
16376
  if (delayMs > 0) await new Promise((r) => setTimeout(r, delayMs));
16021
16377
  try {
16022
16378
  const screenshotResult = await callTool("screenshot", { udid });
16023
- const screenshotContent = await toMcpContent(screenshotResult.result, "image", { udid });
16379
+ const screenshotContent = await toMcpContent(screenshotResult.result, "image", {
16380
+ toolsUrl: TOOLS_URL,
16381
+ authToken: AUTH_TOKEN,
16382
+ deviceId: udid
16383
+ });
16024
16384
  const hasImage = screenshotContent.some((b) => b.type === "image");
16025
16385
  if (hasImage) {
16026
16386
  content = [
@@ -16083,7 +16443,7 @@ async function startMcpServer(options) {
16083
16443
  }, HEALTH_INTERVAL_MS);
16084
16444
  healthInterval.unref();
16085
16445
  }
16086
- if (process.env.ARGENT_AUTO_SHUTDOWN === "1") {
16446
+ if (process.env.ARGENT_TOOL_SERVER_SHUTDOWN_ON_MCP_EXIT === "1") {
16087
16447
  process.stdin.on("close", () => {
16088
16448
  fetch(`${TOOLS_URL}/shutdown`, { method: "POST", headers: authHeader() }).catch(() => {
16089
16449
  });