@swmansion/argent 0.26.1-next.9 → 0.27.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.
@@ -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.9";
16733
+ return "0.27.0";
16734
16734
  }
16735
16735
  return "0.0.0";
16736
16736
  }
@@ -23224,9 +23224,13 @@ async function terminatePid(pid, stillOurs) {
23224
23224
  }
23225
23225
  async function killToolServer(bundlePath) {
23226
23226
  const state2 = await readState(bundlePath);
23227
- if (!state2) return;
23228
- await terminatePid(state2.pid);
23227
+ if (!state2) return false;
23228
+ const stillOurs = () => couldBeOurToolServer(state2.pid, state2.bundlePath);
23229
+ const alive = isProcessAlive(state2.pid);
23230
+ if (alive && !stillOurs()) return false;
23231
+ if (alive) await terminatePid(state2.pid, stillOurs);
23229
23232
  await clearToolsServerState(bundlePath ?? state2.bundlePath);
23233
+ return alive;
23230
23234
  }
23231
23235
  function isPathWithin(child, parent) {
23232
23236
  const rel = path18.relative(parent, child);
@@ -23263,8 +23267,10 @@ async function killToolServerForInstallDir(packageDir) {
23263
23267
  }
23264
23268
  var PS_BIN = ["/bin/ps", "/usr/bin/ps"].find((p) => fs17.existsSync(p)) ?? "ps";
23265
23269
  var PS_WIDTH_FLAGS = ["-ww"];
23266
- function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS) {
23270
+ var PS_LOCALE = process.platform === "darwin" ? "en_US.UTF-8" : "C.UTF-8";
23271
+ function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS, env = { ...process.env, LC_ALL: PS_LOCALE }) {
23267
23272
  return execFileSync5(PS_BIN, [...flags, "-p", String(pid), "-o", "command="], {
23273
+ env,
23268
23274
  encoding: "utf8",
23269
23275
  timeout: 2e3,
23270
23276
  // A recycled pid can sit on a process with an argv past Node's 1 MiB exec
@@ -23279,19 +23285,27 @@ function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS) {
23279
23285
  function couldBeOurToolServer(pid, marker) {
23280
23286
  if (!marker) return false;
23281
23287
  if (process.platform === "win32") return true;
23282
- let cmd;
23283
- try {
23284
- cmd = readProcessCommandLine(pid);
23285
- } catch (err) {
23288
+ const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23289
+ const ours = new RegExp(`(?:^|[\\t\\n\\v\\f\\r ])${escaped} start(?:[\\t\\n\\v\\f\\r ]|$)`);
23290
+ const nonAscii = [...marker].some((c2) => c2.charCodeAt(0) > 127);
23291
+ let failure;
23292
+ for (const env of [void 0, process.env]) {
23293
+ try {
23294
+ if (ours.test(readProcessCommandLine(pid, PS_WIDTH_FLAGS, env))) return true;
23295
+ failure = void 0;
23296
+ if (!nonAscii) break;
23297
+ } catch (err) {
23298
+ failure = String(err);
23299
+ if (err.code === "ETIMEDOUT") break;
23300
+ }
23301
+ }
23302
+ if (failure !== void 0) {
23286
23303
  process.stderr.write(
23287
- `[launcher] ps could not read pid ${pid}'s command line; leaving it alone: ${String(err)}
23304
+ `[launcher] ps could not read pid ${pid}'s command line; leaving it alone: ${failure}
23288
23305
  `
23289
23306
  );
23290
- return false;
23291
23307
  }
23292
- if (!cmd) return false;
23293
- const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23294
- return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
23308
+ return false;
23295
23309
  }
23296
23310
 
23297
23311
  // ../argent-tools-client/src/link-config.ts
@@ -15932,7 +15932,9 @@ function spawnToolsServer(paths, port, options = {}) {
15932
15932
  } catch {
15933
15933
  logFd = fs.openSync("/dev/null", "w");
15934
15934
  }
15935
- const child = spawn("node", [paths.bundlePath, "start"], {
15935
+ const { bun, deno, electron } = process.versions;
15936
+ const nodeBin = !(bun || deno || electron) && fs.existsSync(process.execPath) ? process.execPath : "node";
15937
+ const child = spawn(nodeBin, [paths.bundlePath, "start"], {
15936
15938
  detached: true,
15937
15939
  stdio: ["ignore", "pipe", logFd],
15938
15940
  env: buildToolsServerEnv(paths, port, process.env, options)
@@ -15940,7 +15942,14 @@ function spawnToolsServer(paths, port, options = {}) {
15940
15942
  child.unref();
15941
15943
  const pid = child.pid;
15942
15944
  if (!pid) {
15943
- reject(new Error("Failed to get PID of spawned tools server"));
15945
+ child.once(
15946
+ "error",
15947
+ (err) => reject(
15948
+ new Error(
15949
+ err.code === "ENOENT" && nodeBin === "node" ? "Could not start the argent tool-server: `node` was not found on PATH. Install Node.js 20+ or add it to PATH." : `Could not start the argent tool-server: ${err.message}`
15950
+ )
15951
+ )
15952
+ );
15944
15953
  return;
15945
15954
  }
15946
15955
  let settled = false;
@@ -16095,8 +16104,10 @@ async function terminatePid(pid, stillOurs) {
16095
16104
  }
16096
16105
  var PS_BIN = ["/bin/ps", "/usr/bin/ps"].find((p) => fs.existsSync(p)) ?? "ps";
16097
16106
  var PS_WIDTH_FLAGS = ["-ww"];
16098
- function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS) {
16107
+ var PS_LOCALE = process.platform === "darwin" ? "en_US.UTF-8" : "C.UTF-8";
16108
+ function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS, env = { ...process.env, LC_ALL: PS_LOCALE }) {
16099
16109
  return execFileSync(PS_BIN, [...flags, "-p", String(pid), "-o", "command="], {
16110
+ env,
16100
16111
  encoding: "utf8",
16101
16112
  timeout: 2e3,
16102
16113
  // A recycled pid can sit on a process with an argv past Node's 1 MiB exec
@@ -16111,19 +16122,27 @@ function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS) {
16111
16122
  function couldBeOurToolServer(pid, marker) {
16112
16123
  if (!marker) return false;
16113
16124
  if (process.platform === "win32") return true;
16114
- let cmd;
16115
- try {
16116
- cmd = readProcessCommandLine(pid);
16117
- } catch (err) {
16125
+ const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16126
+ const ours = new RegExp(`(?:^|[\\t\\n\\v\\f\\r ])${escaped} start(?:[\\t\\n\\v\\f\\r ]|$)`);
16127
+ const nonAscii = [...marker].some((c) => c.charCodeAt(0) > 127);
16128
+ let failure;
16129
+ for (const env of [void 0, process.env]) {
16130
+ try {
16131
+ if (ours.test(readProcessCommandLine(pid, PS_WIDTH_FLAGS, env))) return true;
16132
+ failure = void 0;
16133
+ if (!nonAscii) break;
16134
+ } catch (err) {
16135
+ failure = String(err);
16136
+ if (err.code === "ETIMEDOUT") break;
16137
+ }
16138
+ }
16139
+ if (failure !== void 0) {
16118
16140
  process.stderr.write(
16119
- `[launcher] ps could not read pid ${pid}'s command line; leaving it alone: ${String(err)}
16141
+ `[launcher] ps could not read pid ${pid}'s command line; leaving it alone: ${failure}
16120
16142
  `
16121
16143
  );
16122
- return false;
16123
16144
  }
16124
- if (!cmd) return false;
16125
- const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16126
- return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
16145
+ return false;
16127
16146
  }
16128
16147
  var LOCK_WAIT_TIMEOUT_MS = 3e4;
16129
16148
  var LOCK_STALE_MS = 45e3;
@@ -16796,7 +16815,7 @@ function sha256File(filePath) {
16796
16815
  createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve8(hash.digest("hex"))).on("error", reject);
16797
16816
  });
16798
16817
  }
16799
- async function uploadTar(tarPath, endpoint) {
16818
+ async function uploadTar(tarPath, endpoint, signal) {
16800
16819
  const init = {
16801
16820
  method: "POST",
16802
16821
  headers: {
@@ -16804,7 +16823,8 @@ async function uploadTar(tarPath, endpoint) {
16804
16823
  ...endpoint.token ? { Authorization: `Bearer ${endpoint.token}` } : {}
16805
16824
  },
16806
16825
  body: createReadStream(tarPath),
16807
- duplex: "half"
16826
+ duplex: "half",
16827
+ signal
16808
16828
  };
16809
16829
  const res = await fetch(`${endpoint.url}/upload`, init);
16810
16830
  if (!res.ok) {
@@ -16856,7 +16876,7 @@ async function prepareFileInputs(specs, args, opts) {
16856
16876
  );
16857
16877
  tarPath = await tarball(filePath);
16858
16878
  wire.contentHash = await sha256File(tarPath);
16859
- wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint);
16879
+ wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint, opts.signal);
16860
16880
  } finally {
16861
16881
  if (tarPath) await rm2(tarPath, { force: true }).catch(() => {
16862
16882
  });
@@ -17524,7 +17544,8 @@ async function materializeArtifacts(result, ctx) {
17524
17544
  return null;
17525
17545
  }
17526
17546
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
17527
- headers: authHeaders2
17547
+ headers: authHeaders2,
17548
+ signal: ctx.signal
17528
17549
  });
17529
17550
  if (!res.ok) return null;
17530
17551
  const data = await readCapped(res, value.size);
@@ -17551,7 +17572,8 @@ async function materializeArtifacts(result, ctx) {
17551
17572
  }
17552
17573
  try {
17553
17574
  const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
17554
- headers: authHeaders2
17575
+ headers: authHeaders2,
17576
+ signal: ctx.signal
17555
17577
  });
17556
17578
  if (!res.ok) return null;
17557
17579
  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.9";
94817
+ return "0.27.0";
94818
94818
  }
94819
94819
  return "0.0.0";
94820
94820
  }
@@ -96174,7 +96174,7 @@ var import_node_path6 = __toESM(require("node:path"));
96174
96174
  var import_semver2 = __toESM(require_semver2());
96175
96175
 
96176
96176
  // ../tool-server/package.json
96177
- var version2 = "0.26.0";
96177
+ var version2 = "0.27.0";
96178
96178
 
96179
96179
  // ../tool-server/src/utils/update-checker.ts
96180
96180
  var import_update_core = __toESM(require_dist4());
@@ -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
  }
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.26.1-next.9",
3
+ "version": "0.27.0",
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",
@@ -9,6 +9,31 @@
9
9
  "url": "git+https://github.com/software-mansion/argent.git"
10
10
  },
11
11
  "type": "module",
12
+ "exports": {
13
+ "./client": {
14
+ "types": "./dist/client.d.ts",
15
+ "default": "./dist/client.js"
16
+ },
17
+ "./assets/manifest": "./assets/manifest.json",
18
+ "./assets/trace-processor/engine": "./assets/trace-processor/engine.mjs",
19
+ "./assets/trace-processor/engine_bundle.node": "./assets/trace-processor/engine_bundle.node.js",
20
+ "./bin/argent-simulator-server": "./bin/argent-simulator-server.cjs",
21
+ "./dist/bundled-paths": "./dist/bundled-paths.js",
22
+ "./dist/cli": "./dist/cli.js",
23
+ "./dist/cli-cmds": "./dist/cli-cmds.mjs",
24
+ "./dist/fatal-handlers": "./dist/fatal-handlers.js",
25
+ "./dist/flow-script-runner": "./dist/flow-script-runner.mjs",
26
+ "./dist/flow-script-watchdog-deadline": "./dist/flow-script-watchdog-deadline.mjs",
27
+ "./dist/flow-script-watchdog-lifeline": "./dist/flow-script-watchdog-lifeline.mjs",
28
+ "./dist/installer": "./dist/installer.mjs",
29
+ "./dist/installer-help": "./dist/installer-help.js",
30
+ "./dist/mcp-server": "./dist/mcp-server.mjs",
31
+ "./dist/preview-ui/theme": "./dist/preview-ui/theme.css",
32
+ "./dist/preview-window/main": "./dist/preview-window/main.cjs",
33
+ "./dist/tool-server": "./dist/tool-server.cjs",
34
+ "./package": "./package.json",
35
+ "./*": "./*"
36
+ },
12
37
  "bin": {
13
38
  "argent": "dist/cli.js",
14
39
  "argent-simulator-server": "bin/argent-simulator-server.cjs"
@@ -54,6 +79,7 @@
54
79
  },
55
80
  "devDependencies": {
56
81
  "@argent/cli": "file:../argent-cli",
82
+ "@argent/configuration-core": "file:../configuration-core",
57
83
  "@argent/installer": "file:../argent-installer",
58
84
  "@argent/mcp": "file:../argent-mcp",
59
85
  "@argent/tools-client": "file:../argent-tools-client",
@@ -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