@swmansion/argent 0.26.1-next.11 → 0.26.1-next.13

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.
Binary file
Binary file
Binary file
Binary file
package/dist/cli-cmds.mjs CHANGED
@@ -17134,7 +17134,7 @@ function sha256File(filePath) {
17134
17134
  createReadStream(filePath).on("data", (chunk) => hash2.update(chunk)).on("end", () => resolve11(hash2.digest("hex"))).on("error", reject);
17135
17135
  });
17136
17136
  }
17137
- async function uploadTar(tarPath, endpoint) {
17137
+ async function uploadTar(tarPath, endpoint, signal) {
17138
17138
  const init2 = {
17139
17139
  method: "POST",
17140
17140
  headers: {
@@ -17142,7 +17142,8 @@ async function uploadTar(tarPath, endpoint) {
17142
17142
  ...endpoint.token ? { Authorization: `Bearer ${endpoint.token}` } : {}
17143
17143
  },
17144
17144
  body: createReadStream(tarPath),
17145
- duplex: "half"
17145
+ duplex: "half",
17146
+ signal
17146
17147
  };
17147
17148
  const res = await fetch(`${endpoint.url}/upload`, init2);
17148
17149
  if (!res.ok) {
@@ -17194,7 +17195,7 @@ async function prepareFileInputs(specs, args, opts) {
17194
17195
  );
17195
17196
  tarPath = await tarball(filePath);
17196
17197
  wire.contentHash = await sha256File(tarPath);
17197
- wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint);
17198
+ wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint, opts.signal);
17198
17199
  } finally {
17199
17200
  if (tarPath) await rm2(tarPath, { force: true }).catch(() => {
17200
17201
  });
@@ -17263,7 +17264,7 @@ var ToolInvocationError = class extends Error {
17263
17264
  function authHeaders2(token) {
17264
17265
  return token ? { Authorization: `Bearer ${token}` } : {};
17265
17266
  }
17266
- async function consumeToolStream(body, onProgress) {
17267
+ async function consumeToolStream(body, onProgress, signal) {
17267
17268
  let final;
17268
17269
  const handleLine = (line) => {
17269
17270
  if (!line.trim()) return;
@@ -17287,6 +17288,7 @@ async function consumeToolStream(body, onProgress) {
17287
17288
  buffered += decoder.decode(value, { stream: true });
17288
17289
  let newline;
17289
17290
  while ((newline = buffered.indexOf("\n")) !== -1) {
17291
+ signal?.throwIfAborted();
17290
17292
  const line = buffered.slice(0, newline);
17291
17293
  buffered = buffered.slice(newline + 1);
17292
17294
  handleLine(line);
@@ -17299,6 +17301,7 @@ async function consumeToolStream(body, onProgress) {
17299
17301
  });
17300
17302
  throw err;
17301
17303
  }
17304
+ signal?.throwIfAborted();
17302
17305
  if (!final) {
17303
17306
  throw new Error("tool stream ended without a result \u2014 connection lost mid-run?");
17304
17307
  }
@@ -17325,27 +17328,33 @@ function createToolsClient(options = {}) {
17325
17328
  cached3 = await ensureToolsServer(options.paths);
17326
17329
  return cached3;
17327
17330
  }
17328
- async function fetchTools() {
17331
+ async function fetchTools(opts) {
17332
+ opts?.signal?.throwIfAborted();
17329
17333
  const { url: url2, token } = await baseUrl();
17330
- const res = await fetch(`${url2}/tools`, { headers: authHeaders2(token) });
17334
+ const res = await fetch(`${url2}/tools`, {
17335
+ headers: authHeaders2(token),
17336
+ signal: opts?.signal
17337
+ });
17331
17338
  if (!res.ok) throw new Error(`GET /tools failed: ${res.status} ${res.statusText}`);
17332
17339
  const json2 = await res.json();
17333
17340
  return json2.tools;
17334
17341
  }
17335
- async function fetchTool(name) {
17336
- const tools2 = await fetchTools();
17342
+ async function fetchTool(name, opts) {
17343
+ const tools2 = await fetchTools(opts);
17337
17344
  return tools2.find((t2) => t2.name === name) ?? null;
17338
17345
  }
17339
17346
  async function callTool(name, args, opts) {
17347
+ opts?.signal?.throwIfAborted();
17340
17348
  const { url: url2, token } = await baseUrl();
17341
17349
  let finalArgs = args;
17342
- const meta3 = await fetchTool(name);
17350
+ const meta3 = await fetchTool(name, { signal: opts?.signal });
17343
17351
  if (meta3?.fileInputs?.length) {
17344
17352
  const { url: routedUrl } = await getResolvedToolsUrl();
17345
17353
  const isRemote = routedUrl !== null;
17346
17354
  finalArgs = await prepareFileInputs(meta3.fileInputs, args ?? {}, {
17347
17355
  includeContent: isRemote,
17348
- uploadEndpoint: isRemote ? { url: url2, token } : void 0
17356
+ uploadEndpoint: isRemote ? { url: url2, token } : void 0,
17357
+ signal: opts?.signal
17349
17358
  });
17350
17359
  }
17351
17360
  const res = await fetch(`${url2}/tools/${encodeURIComponent(name)}`, {
@@ -17355,13 +17364,17 @@ function createToolsClient(options = {}) {
17355
17364
  ...opts?.onProgress ? { Accept: "application/x-ndjson" } : {},
17356
17365
  ...authHeaders2(token)
17357
17366
  },
17358
- body: JSON.stringify(finalArgs ?? {})
17367
+ body: JSON.stringify(finalArgs ?? {}),
17368
+ signal: opts?.signal
17359
17369
  });
17360
17370
  const contentType = res.headers.get("content-type") ?? "";
17361
17371
  if (opts?.onProgress && res.ok && res.body && contentType.includes("application/x-ndjson")) {
17362
- return consumeToolStream(res.body, opts.onProgress);
17372
+ return consumeToolStream(res.body, opts.onProgress, opts.signal);
17363
17373
  }
17364
- const json2 = await res.json().catch(() => ({}));
17374
+ const json2 = await res.json().catch(() => {
17375
+ opts?.signal?.throwIfAborted();
17376
+ return {};
17377
+ });
17365
17378
  if (!res.ok) {
17366
17379
  throw new ToolInvocationError(errorBodyMessage(json2) ?? `${res.status} ${res.statusText}`, {
17367
17380
  errorCode: json2.error_code,
@@ -17369,6 +17382,7 @@ function createToolsClient(options = {}) {
17369
17382
  issues: Array.isArray(json2.issues) ? json2.issues : void 0
17370
17383
  });
17371
17384
  }
17385
+ opts?.signal?.throwIfAborted();
17372
17386
  const { result: data } = await applyClientFileDirectives(json2.data);
17373
17387
  return { data, note: json2.note };
17374
17388
  }
@@ -18279,7 +18293,8 @@ async function materializeArtifacts(result, ctx) {
18279
18293
  return null;
18280
18294
  }
18281
18295
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
18282
- headers: authHeaders3
18296
+ headers: authHeaders3,
18297
+ signal: ctx.signal
18283
18298
  });
18284
18299
  if (!res.ok) return null;
18285
18300
  const data = await readCapped(res, value.size);
@@ -18306,7 +18321,8 @@ async function materializeArtifacts(result, ctx) {
18306
18321
  }
18307
18322
  try {
18308
18323
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
18309
- headers: authHeaders3
18324
+ headers: authHeaders3,
18325
+ signal: ctx.signal
18310
18326
  });
18311
18327
  if (!res.ok) return null;
18312
18328
  const data = Buffer.from(await res.arrayBuffer());
@@ -21881,7 +21897,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
21881
21897
  var SESSION_ID2 = randomUUID5();
21882
21898
  function readCliVersion() {
21883
21899
  if (true) {
21884
- return "0.26.1-next.11";
21900
+ return "0.26.1-next.13";
21885
21901
  }
21886
21902
  return "0.0.0";
21887
21903
  }
package/dist/client.d.ts CHANGED
@@ -13,6 +13,8 @@ export interface ArgentToolResult<T = unknown> {
13
13
  export interface CallToolOptions {
14
14
  /** Receive progress events while a long-running tool works. */
15
15
  onProgress?: (event: unknown) => void;
16
+ /** Stop waiting for the call. It rejects with the signal's reason, not ArgentToolError. */
17
+ signal?: AbortSignal;
16
18
  }
17
19
  /** The tool-server rejected or failed a call. */
18
20
  export declare class ArgentToolError extends Error {
@@ -37,7 +39,9 @@ export interface ArgentFlag {
37
39
  /** Feature flags and their effective state: project overrides global, then the default. */
38
40
  export declare function listFlags(): ArgentFlag[];
39
41
  export interface ArgentClient {
40
- listTools(): Promise<ArgentTool[]>;
42
+ listTools(options?: {
43
+ signal?: AbortSignal;
44
+ }): Promise<ArgentTool[]>;
41
45
  callTool<T = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<ArgentToolResult<T>>;
42
46
  /**
43
47
  * Stop this install's local tool-server, like `argent server stop`. The next
package/dist/client.js CHANGED
@@ -1718,7 +1718,7 @@ function sha256File(filePath) {
1718
1718
  createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve7(hash.digest("hex"))).on("error", reject);
1719
1719
  });
1720
1720
  }
1721
- async function uploadTar(tarPath, endpoint) {
1721
+ async function uploadTar(tarPath, endpoint, signal) {
1722
1722
  const init = {
1723
1723
  method: "POST",
1724
1724
  headers: {
@@ -1726,7 +1726,8 @@ async function uploadTar(tarPath, endpoint) {
1726
1726
  ...endpoint.token ? { Authorization: `Bearer ${endpoint.token}` } : {}
1727
1727
  },
1728
1728
  body: createReadStream(tarPath),
1729
- duplex: "half"
1729
+ duplex: "half",
1730
+ signal
1730
1731
  };
1731
1732
  const res = await fetch(`${endpoint.url}/upload`, init);
1732
1733
  if (!res.ok) {
@@ -1778,7 +1779,7 @@ async function prepareFileInputs(specs, args, opts) {
1778
1779
  );
1779
1780
  tarPath = await tarball(filePath);
1780
1781
  wire.contentHash = await sha256File(tarPath);
1781
- wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint);
1782
+ wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint, opts.signal);
1782
1783
  } finally {
1783
1784
  if (tarPath) await rm2(tarPath, { force: true }).catch(() => {
1784
1785
  });
@@ -1847,7 +1848,7 @@ var ToolInvocationError = class extends Error {
1847
1848
  function authHeaders2(token) {
1848
1849
  return token ? { Authorization: `Bearer ${token}` } : {};
1849
1850
  }
1850
- async function consumeToolStream(body, onProgress) {
1851
+ async function consumeToolStream(body, onProgress, signal) {
1851
1852
  let final;
1852
1853
  const handleLine = (line) => {
1853
1854
  if (!line.trim()) return;
@@ -1871,6 +1872,7 @@ async function consumeToolStream(body, onProgress) {
1871
1872
  buffered += decoder.decode(value, { stream: true });
1872
1873
  let newline;
1873
1874
  while ((newline = buffered.indexOf("\n")) !== -1) {
1875
+ signal?.throwIfAborted();
1874
1876
  const line = buffered.slice(0, newline);
1875
1877
  buffered = buffered.slice(newline + 1);
1876
1878
  handleLine(line);
@@ -1883,6 +1885,7 @@ async function consumeToolStream(body, onProgress) {
1883
1885
  });
1884
1886
  throw err;
1885
1887
  }
1888
+ signal?.throwIfAborted();
1886
1889
  if (!final) {
1887
1890
  throw new Error("tool stream ended without a result \u2014 connection lost mid-run?");
1888
1891
  }
@@ -1909,27 +1912,33 @@ function createToolsClient(options = {}) {
1909
1912
  cached = await ensureToolsServer(options.paths);
1910
1913
  return cached;
1911
1914
  }
1912
- async function fetchTools() {
1915
+ async function fetchTools(opts) {
1916
+ opts?.signal?.throwIfAborted();
1913
1917
  const { url, token } = await baseUrl();
1914
- const res = await fetch(`${url}/tools`, { headers: authHeaders2(token) });
1918
+ const res = await fetch(`${url}/tools`, {
1919
+ headers: authHeaders2(token),
1920
+ signal: opts?.signal
1921
+ });
1915
1922
  if (!res.ok) throw new Error(`GET /tools failed: ${res.status} ${res.statusText}`);
1916
1923
  const json = await res.json();
1917
1924
  return json.tools;
1918
1925
  }
1919
- async function fetchTool(name) {
1920
- const tools = await fetchTools();
1926
+ async function fetchTool(name, opts) {
1927
+ const tools = await fetchTools(opts);
1921
1928
  return tools.find((t) => t.name === name) ?? null;
1922
1929
  }
1923
1930
  async function callTool(name, args, opts) {
1931
+ opts?.signal?.throwIfAborted();
1924
1932
  const { url, token } = await baseUrl();
1925
1933
  let finalArgs = args;
1926
- const meta = await fetchTool(name);
1934
+ const meta = await fetchTool(name, { signal: opts?.signal });
1927
1935
  if (meta?.fileInputs?.length) {
1928
1936
  const { url: routedUrl } = await getResolvedToolsUrl();
1929
1937
  const isRemote = routedUrl !== null;
1930
1938
  finalArgs = await prepareFileInputs(meta.fileInputs, args ?? {}, {
1931
1939
  includeContent: isRemote,
1932
- uploadEndpoint: isRemote ? { url, token } : void 0
1940
+ uploadEndpoint: isRemote ? { url, token } : void 0,
1941
+ signal: opts?.signal
1933
1942
  });
1934
1943
  }
1935
1944
  const res = await fetch(`${url}/tools/${encodeURIComponent(name)}`, {
@@ -1939,13 +1948,17 @@ function createToolsClient(options = {}) {
1939
1948
  ...opts?.onProgress ? { Accept: "application/x-ndjson" } : {},
1940
1949
  ...authHeaders2(token)
1941
1950
  },
1942
- body: JSON.stringify(finalArgs ?? {})
1951
+ body: JSON.stringify(finalArgs ?? {}),
1952
+ signal: opts?.signal
1943
1953
  });
1944
1954
  const contentType = res.headers.get("content-type") ?? "";
1945
1955
  if (opts?.onProgress && res.ok && res.body && contentType.includes("application/x-ndjson")) {
1946
- return consumeToolStream(res.body, opts.onProgress);
1956
+ return consumeToolStream(res.body, opts.onProgress, opts.signal);
1947
1957
  }
1948
- const json = await res.json().catch(() => ({}));
1958
+ const json = await res.json().catch(() => {
1959
+ opts?.signal?.throwIfAborted();
1960
+ return {};
1961
+ });
1949
1962
  if (!res.ok) {
1950
1963
  throw new ToolInvocationError(errorBodyMessage(json) ?? `${res.status} ${res.statusText}`, {
1951
1964
  errorCode: json.error_code,
@@ -1953,6 +1966,7 @@ function createToolsClient(options = {}) {
1953
1966
  issues: Array.isArray(json.issues) ? json.issues : void 0
1954
1967
  });
1955
1968
  }
1969
+ opts?.signal?.throwIfAborted();
1956
1970
  const { result: data } = await applyClientFileDirectives(json.data);
1957
1971
  return { data, note: json.note };
1958
1972
  }
@@ -2159,7 +2173,8 @@ async function materializeArtifacts(result, ctx) {
2159
2173
  return null;
2160
2174
  }
2161
2175
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
2162
- headers: authHeaders3
2176
+ headers: authHeaders3,
2177
+ signal: ctx.signal
2163
2178
  });
2164
2179
  if (!res.ok) return null;
2165
2180
  const data = await readCapped(res, value.size);
@@ -2186,7 +2201,8 @@ async function materializeArtifacts(result, ctx) {
2186
2201
  }
2187
2202
  try {
2188
2203
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
2189
- headers: authHeaders3
2204
+ headers: authHeaders3,
2205
+ signal: ctx.signal
2190
2206
  });
2191
2207
  if (!res.ok) return null;
2192
2208
  const data = Buffer.from(await res.arrayBuffer());
@@ -2345,19 +2361,22 @@ function createArgentClient() {
2345
2361
  client = createToolsClient({ paths: BUNDLED_RUNTIME_PATHS });
2346
2362
  return stopped;
2347
2363
  }
2348
- async function listTools() {
2349
- const tools = await client.fetchTools();
2364
+ async function listTools(options) {
2365
+ const tools = await client.fetchTools({ signal: options?.signal });
2350
2366
  return tools.map(({ name, description, inputSchema }) => ({ name, description, inputSchema }));
2351
2367
  }
2352
2368
  async function callTool(name, args = {}, options) {
2353
2369
  try {
2354
2370
  const response = await client.callTool(name, args, options);
2355
2371
  const { url, token } = await client.baseUrl();
2372
+ options?.signal?.throwIfAborted();
2356
2373
  const { result } = await materializeArtifacts(response.data, {
2357
2374
  toolsUrl: url,
2358
2375
  authToken: token,
2359
- deviceId: getDeviceIdFromArgs(args)
2376
+ deviceId: getDeviceIdFromArgs(args),
2377
+ signal: options?.signal
2360
2378
  });
2379
+ options?.signal?.throwIfAborted();
2361
2380
  return { data: result, note: response.note };
2362
2381
  } catch (err) {
2363
2382
  if (err instanceof ToolInvocationError) {
@@ -16730,7 +16730,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
16730
16730
  var SESSION_ID = randomUUID4();
16731
16731
  function readCliVersion() {
16732
16732
  if (true) {
16733
- return "0.26.1-next.11";
16733
+ return "0.26.1-next.13";
16734
16734
  }
16735
16735
  return "0.0.0";
16736
16736
  }
@@ -16796,7 +16796,7 @@ function sha256File(filePath) {
16796
16796
  createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve8(hash.digest("hex"))).on("error", reject);
16797
16797
  });
16798
16798
  }
16799
- async function uploadTar(tarPath, endpoint) {
16799
+ async function uploadTar(tarPath, endpoint, signal) {
16800
16800
  const init = {
16801
16801
  method: "POST",
16802
16802
  headers: {
@@ -16804,7 +16804,8 @@ async function uploadTar(tarPath, endpoint) {
16804
16804
  ...endpoint.token ? { Authorization: `Bearer ${endpoint.token}` } : {}
16805
16805
  },
16806
16806
  body: createReadStream(tarPath),
16807
- duplex: "half"
16807
+ duplex: "half",
16808
+ signal
16808
16809
  };
16809
16810
  const res = await fetch(`${endpoint.url}/upload`, init);
16810
16811
  if (!res.ok) {
@@ -16856,7 +16857,7 @@ async function prepareFileInputs(specs, args, opts) {
16856
16857
  );
16857
16858
  tarPath = await tarball(filePath);
16858
16859
  wire.contentHash = await sha256File(tarPath);
16859
- wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint);
16860
+ wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint, opts.signal);
16860
16861
  } finally {
16861
16862
  if (tarPath) await rm2(tarPath, { force: true }).catch(() => {
16862
16863
  });
@@ -17524,7 +17525,8 @@ async function materializeArtifacts(result, ctx) {
17524
17525
  return null;
17525
17526
  }
17526
17527
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
17527
- headers: authHeaders2
17528
+ headers: authHeaders2,
17529
+ signal: ctx.signal
17528
17530
  });
17529
17531
  if (!res.ok) return null;
17530
17532
  const data = await readCapped(res, value.size);
@@ -17551,7 +17553,8 @@ async function materializeArtifacts(result, ctx) {
17551
17553
  }
17552
17554
  try {
17553
17555
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
17554
- headers: authHeaders2
17556
+ headers: authHeaders2,
17557
+ signal: ctx.signal
17555
17558
  });
17556
17559
  if (!res.ok) return null;
17557
17560
  const data = Buffer.from(await res.arrayBuffer());
@@ -94814,7 +94814,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
94814
94814
  var SESSION_ID = (0, import_node_crypto3.randomUUID)();
94815
94815
  function readCliVersion() {
94816
94816
  if (true) {
94817
- return "0.26.1-next.11";
94817
+ return "0.26.1-next.13";
94818
94818
  }
94819
94819
  return "0.0.0";
94820
94820
  }
@@ -108061,14 +108061,16 @@ async function pointerPost(api, body, signal) {
108061
108061
  return false;
108062
108062
  }
108063
108063
  }
108064
- async function setSimulatorClipboardText(api, text, signal) {
108064
+ var SENSITIVE_TEXT_REFUSED = "refused to set sensitive text";
108065
+ async function setSimulatorClipboardText(api, text, options = {}) {
108066
+ const { sensitive = false, signal } = options;
108065
108067
  if (api.external) assertAllowedSimServerEndpoint("/api/clipboard/text");
108066
108068
  let res;
108067
108069
  try {
108068
108070
  res = await fetch(`${api.apiUrl}/api/clipboard/text`, {
108069
108071
  method: "POST",
108070
108072
  headers: { "Content-Type": "application/json" },
108071
- body: JSON.stringify({ text }),
108073
+ body: JSON.stringify(sensitive ? { text, sensitive } : { text }),
108072
108074
  signal
108073
108075
  });
108074
108076
  } catch (err) {
@@ -108087,6 +108089,7 @@ async function setSimulatorClipboardText(api, text, signal) {
108087
108089
  );
108088
108090
  }
108089
108091
  const body = await res.json().catch(() => null);
108092
+ if (sensitive && body?.error?.includes(SENSITIVE_TEXT_REFUSED)) return "refused";
108090
108093
  if (!res.ok || body?.status !== "ok") {
108091
108094
  throw new FailureError(
108092
108095
  `Paste failed: could not set the device clipboard (${body?.error ?? `HTTP ${res.status}`}).`,
@@ -108098,6 +108101,7 @@ async function setSimulatorClipboardText(api, text, signal) {
108098
108101
  }
108099
108102
  );
108100
108103
  }
108104
+ return "set";
108101
108105
  }
108102
108106
  async function simulatorPost(toolLabel, api, endpoint, reqBody, signal, fallbackHint) {
108103
108107
  if (api.external) assertAllowedSimServerEndpoint(endpoint);
@@ -125814,10 +125818,12 @@ var pasteZodSchema = external_exports.object({
125814
125818
  });
125815
125819
 
125816
125820
  // ../tool-server/src/tools/paste/platforms/ios.ts
125821
+ init_src2();
125817
125822
  var LEFT_GUI_KEYCODE = 227;
125818
125823
  var V_KEYCODE = charToKeyPress("v").keyCode;
125819
125824
  var CHORD_STEP_MS = 50;
125820
125825
  var sleep10 = (ms) => new Promise((r) => setTimeout(r, ms));
125826
+ var typesAsText = (char) => !"\n\r ".includes(char) && !!charToKeyPress(char);
125821
125827
  function rejectTv(device) {
125822
125828
  throw new UnsupportedOperationError(
125823
125829
  "paste",
@@ -125825,8 +125831,22 @@ function rejectTv(device) {
125825
125831
  "tvOS has no pasteboard to paste from \u2014 type into the focused field with keyboard instead"
125826
125832
  );
125827
125833
  }
125828
- async function pasteSimulator(api, text) {
125829
- await setSimulatorClipboardText(api, text);
125834
+ async function pasteSimulator(registry2, device, api, params) {
125835
+ const sensitive = params.hasSecrets === true;
125836
+ if (await setSimulatorClipboardText(api, params.text, { sensitive }) === "refused") {
125837
+ if (![...params.text].every(typesAsText)) {
125838
+ throw new InvalidToolInputError(
125839
+ "Paste failed: Device Hub has opened this simulator, so a secret is typed instead of pasted, and this secret holds a newline, a tab or a character the keyboard cannot type. Nothing was typed.",
125840
+ {
125841
+ error_code: FAILURE_CODES.KEYBOARD_CHARACTER_UNSUPPORTED,
125842
+ failure_stage: "paste_secret_typed_simulator",
125843
+ error_kind: "unsupported"
125844
+ }
125845
+ );
125846
+ }
125847
+ await typeSimulatorServer(registry2, device, { udid: params.udid, text: params.text });
125848
+ return { pasted: true, via: "keyboard" };
125849
+ }
125830
125850
  await api.pressKey("Down", LEFT_GUI_KEYCODE);
125831
125851
  await sleep10(CHORD_STEP_MS);
125832
125852
  await api.pressKey("Down", V_KEYCODE);
@@ -125846,7 +125866,7 @@ function makeIosImpl4(registry2) {
125846
125866
  if (await isTvOsSimulator(device.id)) rejectTv(device);
125847
125867
  const ref = simulatorServerRef(device);
125848
125868
  const api = await registry2.resolveService(ref.urn, ref.options);
125849
- return pasteSimulator(api, params.text);
125869
+ return pasteSimulator(registry2, device, api, params);
125850
125870
  }
125851
125871
  };
125852
125872
  }
@@ -125938,9 +125958,9 @@ function createPasteTool(registry2) {
125938
125958
  completedMsg: () => "Pasted text",
125939
125959
  failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to paste text: ${failureSignal2.error_code}`
125940
125960
  },
125941
- description: `Paste text into the focused field: puts \`text\` on the DEVICE clipboard (the host clipboard is untouched), then triggers the platform's paste shortcut (iOS simulator, Android emulator).
125961
+ description: `Paste text into the focused field: puts \`text\` on the DEVICE clipboard, then triggers the platform's paste shortcut (iOS simulator, Android emulator).
125942
125962
  Do NOT use this in place of \`keyboard\`. \`keyboard\` types as a user would and is the default for all text entry; use \`paste\` only where a real user would paste \u2014 a 2FA/OTP code copied from another app, a long link or token, or when testing the app's own paste handling.
125943
- Tap the field first so it has focus. Returns { pasted: true }. Fails on a TV target, when the device clipboard cannot be set, or when the simulator-server build lacks clipboard support.
125963
+ Tap the field first so it has focus. Returns { pasted: true }, plus via: "keyboard" when a secret was typed instead of pasted. Fails on a TV target, when the device clipboard cannot be set, when a secret that has to be typed holds a character that cannot be typed, or when the simulator-server build lacks clipboard support.
125944
125964
  Supports \`{{secret:<NAME>}}\` placeholders like \`keyboard\`; the value is never echoed back.`,
125945
125965
  searchHint: "paste clipboard pasteboard otp 2fa code fill field",
125946
125966
  zodSchema: pasteZodSchema,
@@ -125951,7 +125971,7 @@ Supports \`{{secret:<NAME>}}\` placeholders like \`keyboard\`; the value is neve
125951
125971
  return serializedPerDevice(params.udid, async () => {
125952
125972
  if (secrets.length === 0) return dispatch(services, params, options);
125953
125973
  try {
125954
- return await dispatch(services, { ...params, text }, options);
125974
+ return await dispatch(services, { ...params, text, hasSecrets: true }, options);
125955
125975
  } catch (err) {
125956
125976
  throw redactSecretsFromError(err, secrets);
125957
125977
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.26.1-next.11",
3
+ "version": "0.26.1-next.13",
4
4
  "mcpName": "io.github.software-mansion/argent",
5
5
  "description": "MCP server for iOS Simulator and Android Emulator control",
6
6
  "license": "Apache-2.0",
@@ -185,7 +185,7 @@ Where the value is read from, and the rules for using a placeholder — includin
185
185
  { "udid": "<UDID>", "text": "482913" }
186
186
  ```
187
187
 
188
- Puts `text` on the **device** clipboard (the host clipboard is untouched) and triggers the platform's paste shortcut. iOS simulator and Android emulator only; a TV target, a physical device, Chromium and Vega are rejected.
188
+ Puts `text` on the **device** clipboard and triggers the platform's paste shortcut. iOS simulator and Android emulator only; a TV target, a physical device, Chromium and Vega are rejected.
189
189
 
190
190
  `paste` is **not** a faster `keyboard`. `keyboard` types the way a user types and stays the default for every text entry — a search query, a login, a form field. Reach for `paste` only where a real user would paste: a 2FA / OTP code copied from another app, a long link or token, or to test how the app handles pasted input. It also carries what `keyboard` can't type on a given platform (multi-line text, non-ASCII on Android), but that alone is not a reason to paste — ask whether the user would.
191
191