@swmansion/argent 0.26.1-next.8 → 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.
- package/bin/argent-android-devtools-0.1.0.apk +0 -0
- package/bin/darwin/ax-service +0 -0
- package/bin/darwin/simulator-server +0 -0
- package/bin/darwin/tvos-ax-service +0 -0
- package/bin/darwin/tvos-hid-daemon +0 -0
- package/bin/linux/simulator-server +0 -0
- package/bin/linux-arm64/simulator-server +0 -0
- package/bin/tcp/ax-service +0 -0
- package/bin/win32/simulator-server.exe +0 -0
- package/dist/cli-cmds.mjs +77 -33
- package/dist/client.d.ts +52 -0
- package/dist/client.js +2417 -0
- package/dist/installer.mjs +27 -13
- package/dist/mcp-server.mjs +39 -17
- package/dist/tool-server.cjs +125 -34
- package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/libKeyboardPatch.dylib +0 -0
- package/dylibs/libNativeDevtoolsIos.dylib +0 -0
- package/dylibs/tcp/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/tcp/libKeyboardPatch.dylib +0 -0
- package/dylibs/tcp/libNativeDevtoolsIos.dylib +0 -0
- package/dylibs/tvos/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/tvos/libKeyboardPatch.dylib +0 -0
- package/dylibs/tvos/libNativeDevtoolsIos.dylib +0 -0
- package/package.json +27 -1
- package/skills/argent-device-interact/SKILL.md +1 -1
package/dist/installer.mjs
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
23283
|
-
|
|
23284
|
-
|
|
23285
|
-
|
|
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: ${
|
|
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
|
-
|
|
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
|
package/dist/mcp-server.mjs
CHANGED
|
@@ -15932,7 +15932,9 @@ function spawnToolsServer(paths, port, options = {}) {
|
|
|
15932
15932
|
} catch {
|
|
15933
15933
|
logFd = fs.openSync("/dev/null", "w");
|
|
15934
15934
|
}
|
|
15935
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16117
|
-
|
|
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: ${
|
|
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
|
-
|
|
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());
|
package/dist/tool-server.cjs
CHANGED
|
@@ -73390,6 +73390,9 @@ function resolveDevice(udid) {
|
|
|
73390
73390
|
function isIosPhysicalDevice(device) {
|
|
73391
73391
|
return device.platform === "ios" && device.kind === "device";
|
|
73392
73392
|
}
|
|
73393
|
+
function isIosSimulator(device) {
|
|
73394
|
+
return device.platform === "ios" && device.kind === "simulator" || device.platform === "ios-remote";
|
|
73395
|
+
}
|
|
73393
73396
|
function parseChromiumCdpPort(udid) {
|
|
73394
73397
|
if (!udid.startsWith(CHROMIUM_ID_PREFIX)) return null;
|
|
73395
73398
|
const tail = udid.slice(CHROMIUM_ID_PREFIX.length);
|
|
@@ -94811,7 +94814,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
94811
94814
|
var SESSION_ID = (0, import_node_crypto3.randomUUID)();
|
|
94812
94815
|
function readCliVersion() {
|
|
94813
94816
|
if (true) {
|
|
94814
|
-
return "0.
|
|
94817
|
+
return "0.27.0";
|
|
94815
94818
|
}
|
|
94816
94819
|
return "0.0.0";
|
|
94817
94820
|
}
|
|
@@ -96171,7 +96174,7 @@ var import_node_path6 = __toESM(require("node:path"));
|
|
|
96171
96174
|
var import_semver2 = __toESM(require_semver2());
|
|
96172
96175
|
|
|
96173
96176
|
// ../tool-server/package.json
|
|
96174
|
-
var version2 = "0.
|
|
96177
|
+
var version2 = "0.27.0";
|
|
96175
96178
|
|
|
96176
96179
|
// ../tool-server/src/utils/update-checker.ts
|
|
96177
96180
|
var import_update_core = __toESM(require_dist4());
|
|
@@ -96626,6 +96629,7 @@ var path11 = __toESM(require("node:path"));
|
|
|
96626
96629
|
var import_node_child_process7 = require("node:child_process");
|
|
96627
96630
|
var import_node_util6 = require("node:util");
|
|
96628
96631
|
init_external_devices();
|
|
96632
|
+
init_device_info();
|
|
96629
96633
|
var execFileAsync6 = (0, import_node_util6.promisify)(import_node_child_process7.execFile);
|
|
96630
96634
|
async function listDeviceSetSimulators(deviceSet) {
|
|
96631
96635
|
if (deviceSet && !fs12.existsSync(deviceSet)) return [];
|
|
@@ -96686,11 +96690,15 @@ var runtimeKindCache = /* @__PURE__ */ new Map();
|
|
|
96686
96690
|
async function getSimulatorRuntimeKind(udid) {
|
|
96687
96691
|
const cached3 = runtimeKindCache.get(udid);
|
|
96688
96692
|
if (cached3) return cached3;
|
|
96689
|
-
const
|
|
96690
|
-
const kind = listing.find((s) => s.udid === externalNativeId(udid))?.runtimeKind;
|
|
96693
|
+
const kind = (await findIosSimulator(udid))?.runtimeKind;
|
|
96691
96694
|
if (kind) runtimeKindCache.set(udid, kind);
|
|
96692
96695
|
return kind;
|
|
96693
96696
|
}
|
|
96697
|
+
async function findIosSimulator(udid) {
|
|
96698
|
+
const listing = isExternalId(udid) ? await listDeviceSetSimulators(await deviceSetForUdid(udid)) : await listIosSimulators();
|
|
96699
|
+
const native = externalNativeId(udid);
|
|
96700
|
+
return listing.find((s) => s.udid === native);
|
|
96701
|
+
}
|
|
96694
96702
|
async function isTvOsSimulator(udid) {
|
|
96695
96703
|
return await getSimulatorRuntimeKind(udid) === "tv";
|
|
96696
96704
|
}
|
|
@@ -96754,11 +96762,11 @@ async function isFoldableDeviceType(identifier) {
|
|
|
96754
96762
|
return foldable;
|
|
96755
96763
|
}
|
|
96756
96764
|
async function isFoldableSimulator(udid) {
|
|
96765
|
+
const device = resolveDevice(udid);
|
|
96766
|
+
if (device.platform !== "ios" || device.kind !== "simulator") return false;
|
|
96757
96767
|
const cached3 = foldableCache.get(udid);
|
|
96758
96768
|
if (cached3 !== void 0) return cached3;
|
|
96759
|
-
const
|
|
96760
|
-
const native = externalNativeId(udid);
|
|
96761
|
-
const found = listing.find((s) => s.udid === native);
|
|
96769
|
+
const found = await findIosSimulator(udid);
|
|
96762
96770
|
const foldable = found?.foldable === true;
|
|
96763
96771
|
if (found) foldableCache.set(udid, foldable);
|
|
96764
96772
|
return foldable;
|
|
@@ -108053,14 +108061,16 @@ async function pointerPost(api, body, signal) {
|
|
|
108053
108061
|
return false;
|
|
108054
108062
|
}
|
|
108055
108063
|
}
|
|
108056
|
-
|
|
108064
|
+
var SENSITIVE_TEXT_REFUSED = "refused to set sensitive text";
|
|
108065
|
+
async function setSimulatorClipboardText(api, text, options = {}) {
|
|
108066
|
+
const { sensitive = false, signal } = options;
|
|
108057
108067
|
if (api.external) assertAllowedSimServerEndpoint("/api/clipboard/text");
|
|
108058
108068
|
let res;
|
|
108059
108069
|
try {
|
|
108060
108070
|
res = await fetch(`${api.apiUrl}/api/clipboard/text`, {
|
|
108061
108071
|
method: "POST",
|
|
108062
108072
|
headers: { "Content-Type": "application/json" },
|
|
108063
|
-
body: JSON.stringify({ text }),
|
|
108073
|
+
body: JSON.stringify(sensitive ? { text, sensitive } : { text }),
|
|
108064
108074
|
signal
|
|
108065
108075
|
});
|
|
108066
108076
|
} catch (err) {
|
|
@@ -108079,6 +108089,7 @@ async function setSimulatorClipboardText(api, text, signal) {
|
|
|
108079
108089
|
);
|
|
108080
108090
|
}
|
|
108081
108091
|
const body = await res.json().catch(() => null);
|
|
108092
|
+
if (sensitive && body?.error?.includes(SENSITIVE_TEXT_REFUSED)) return "refused";
|
|
108082
108093
|
if (!res.ok || body?.status !== "ok") {
|
|
108083
108094
|
throw new FailureError(
|
|
108084
108095
|
`Paste failed: could not set the device clipboard (${body?.error ?? `HTTP ${res.status}`}).`,
|
|
@@ -108090,6 +108101,7 @@ async function setSimulatorClipboardText(api, text, signal) {
|
|
|
108090
108101
|
}
|
|
108091
108102
|
);
|
|
108092
108103
|
}
|
|
108104
|
+
return "set";
|
|
108093
108105
|
}
|
|
108094
108106
|
async function simulatorPost(toolLabel, api, endpoint, reqBody, signal, fallbackHint) {
|
|
108095
108107
|
if (api.external) assertAllowedSimServerEndpoint(endpoint);
|
|
@@ -125806,10 +125818,12 @@ var pasteZodSchema = external_exports.object({
|
|
|
125806
125818
|
});
|
|
125807
125819
|
|
|
125808
125820
|
// ../tool-server/src/tools/paste/platforms/ios.ts
|
|
125821
|
+
init_src2();
|
|
125809
125822
|
var LEFT_GUI_KEYCODE = 227;
|
|
125810
125823
|
var V_KEYCODE = charToKeyPress("v").keyCode;
|
|
125811
125824
|
var CHORD_STEP_MS = 50;
|
|
125812
125825
|
var sleep10 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
125826
|
+
var typesAsText = (char) => !"\n\r ".includes(char) && !!charToKeyPress(char);
|
|
125813
125827
|
function rejectTv(device) {
|
|
125814
125828
|
throw new UnsupportedOperationError(
|
|
125815
125829
|
"paste",
|
|
@@ -125817,8 +125831,22 @@ function rejectTv(device) {
|
|
|
125817
125831
|
"tvOS has no pasteboard to paste from \u2014 type into the focused field with keyboard instead"
|
|
125818
125832
|
);
|
|
125819
125833
|
}
|
|
125820
|
-
async function pasteSimulator(api,
|
|
125821
|
-
|
|
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
|
+
}
|
|
125822
125850
|
await api.pressKey("Down", LEFT_GUI_KEYCODE);
|
|
125823
125851
|
await sleep10(CHORD_STEP_MS);
|
|
125824
125852
|
await api.pressKey("Down", V_KEYCODE);
|
|
@@ -125838,7 +125866,7 @@ function makeIosImpl4(registry2) {
|
|
|
125838
125866
|
if (await isTvOsSimulator(device.id)) rejectTv(device);
|
|
125839
125867
|
const ref = simulatorServerRef(device);
|
|
125840
125868
|
const api = await registry2.resolveService(ref.urn, ref.options);
|
|
125841
|
-
return pasteSimulator(api, params
|
|
125869
|
+
return pasteSimulator(registry2, device, api, params);
|
|
125842
125870
|
}
|
|
125843
125871
|
};
|
|
125844
125872
|
}
|
|
@@ -125930,9 +125958,9 @@ function createPasteTool(registry2) {
|
|
|
125930
125958
|
completedMsg: () => "Pasted text",
|
|
125931
125959
|
failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to paste text: ${failureSignal2.error_code}`
|
|
125932
125960
|
},
|
|
125933
|
-
description: `Paste text into the focused field: puts \`text\` on the DEVICE clipboard
|
|
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).
|
|
125934
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.
|
|
125935
|
-
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.
|
|
125936
125964
|
Supports \`{{secret:<NAME>}}\` placeholders like \`keyboard\`; the value is never echoed back.`,
|
|
125937
125965
|
searchHint: "paste clipboard pasteboard otp 2fa code fill field",
|
|
125938
125966
|
zodSchema: pasteZodSchema,
|
|
@@ -125943,7 +125971,7 @@ Supports \`{{secret:<NAME>}}\` placeholders like \`keyboard\`; the value is neve
|
|
|
125943
125971
|
return serializedPerDevice(params.udid, async () => {
|
|
125944
125972
|
if (secrets.length === 0) return dispatch(services, params, options);
|
|
125945
125973
|
try {
|
|
125946
|
-
return await dispatch(services, { ...params, text }, options);
|
|
125974
|
+
return await dispatch(services, { ...params, text, hasSecrets: true }, options);
|
|
125947
125975
|
} catch (err) {
|
|
125948
125976
|
throw redactSecretsFromError(err, secrets);
|
|
125949
125977
|
}
|
|
@@ -134469,22 +134497,36 @@ function buildTextTree(data, opts) {
|
|
|
134469
134497
|
}
|
|
134470
134498
|
}
|
|
134471
134499
|
const lines = [];
|
|
134472
|
-
const turn = opts.uiOrientation && opts.uiOrientation !== "unknown" && opts.uiOrientation !== "ambiguous" ? opts.uiOrientation : void 0;
|
|
134500
|
+
const turn = opts.uiOrientation && opts.uiOrientation !== "unknown" && opts.uiOrientation !== "ambiguous" && opts.uiOrientation !== "mismatched" ? opts.uiOrientation : void 0;
|
|
134473
134501
|
if (canNormalize) {
|
|
134474
134502
|
lines.push(`Screen: ${screenW}x${screenH}`);
|
|
134475
|
-
if (
|
|
134503
|
+
if (opts.uiOrientation === "mismatched") {
|
|
134504
|
+
lines.push(
|
|
134505
|
+
"Note: The udid is not the UDID of the simulator that shows this app. Thus, the tool did not use the udid. If the UI is landscape, the tap points are not correct. The describe tool gives correct tap points. This tool also gives correct tap points with the UDID of the simulator that shows this app."
|
|
134506
|
+
);
|
|
134507
|
+
} else if (turn && turn !== "portrait") {
|
|
134476
134508
|
lines.push(
|
|
134477
134509
|
`The UI is ${turn} on the screen. The tap points are on the screen's axes, which the gesture tools use.`
|
|
134478
134510
|
);
|
|
134479
134511
|
} else if (opts.uiOrientation === "ambiguous" && screenW > screenH) {
|
|
134480
134512
|
lines.push(
|
|
134481
|
-
"Note: the UI is landscape, and two booted simulators have this device's name, so its orientation could not be read. The tap points are on the UI's axes, so a tap can miss.
|
|
134513
|
+
"Note: the UI is landscape, and two booted simulators have this device's name, so its orientation could not be read. The tap points are on the UI's axes, so a tap can miss. Use describe for tap points, or call again with the udid of the simulator that shows this app."
|
|
134482
134514
|
);
|
|
134483
134515
|
} else if (opts.uiOrientation === "unknown" && screenW > screenH) {
|
|
134484
134516
|
lines.push(
|
|
134485
134517
|
"Note: the UI is landscape, and its orientation could not be read. The tap points are on the UI's axes, so a tap can miss. Use describe for tap points."
|
|
134486
134518
|
);
|
|
134487
134519
|
}
|
|
134520
|
+
if (opts.readInsteadOfUdid) {
|
|
134521
|
+
lines.push(
|
|
134522
|
+
`Note: the udid is not the UDID of the simulator that shows this app. The tool used ${opts.readInsteadOfUdid}, the UDID of that simulator.`
|
|
134523
|
+
);
|
|
134524
|
+
}
|
|
134525
|
+
if (opts.udidUnchecked && (screenW > screenH || turn !== void 0 && turn !== "portrait")) {
|
|
134526
|
+
lines.push(
|
|
134527
|
+
"Note: two booted simulators have this device's name, so the tool could not check that the udid is the simulator that shows this app. If it is another simulator, a tap can miss. Use describe for tap points."
|
|
134528
|
+
);
|
|
134529
|
+
}
|
|
134488
134530
|
lines.push("");
|
|
134489
134531
|
}
|
|
134490
134532
|
function formatLabel2(c) {
|
|
@@ -134588,14 +134630,57 @@ async function debuggedBundleId(api, appName) {
|
|
|
134588
134630
|
}
|
|
134589
134631
|
var BUNDLE_ID_NAMED_TARGET = /^[\w-]+(\.[\w-]+)+( \(|$)/;
|
|
134590
134632
|
var AMBIGUOUS_SIMULATOR = "ambiguous-simulator";
|
|
134591
|
-
|
|
134592
|
-
|
|
134593
|
-
}
|
|
134633
|
+
var MISMATCHED_UDID = "mismatched-udid";
|
|
134634
|
+
var UNLISTED_UDID = "unlisted-udid";
|
|
134594
134635
|
async function iosSimulatorOf(app) {
|
|
134595
|
-
if (app.udid) {
|
|
134596
|
-
const
|
|
134597
|
-
return
|
|
134636
|
+
if (!app.udid) {
|
|
134637
|
+
const session2 = await iosSimulatorOfSession(app);
|
|
134638
|
+
return session2 === AMBIGUOUS_SIMULATOR || !session2 ? session2 : { device: session2 };
|
|
134639
|
+
}
|
|
134640
|
+
const named = resolveDevice(app.udid);
|
|
134641
|
+
const own = resolveDevice(canonicalDeviceId(app.deviceId) ?? app.deviceId);
|
|
134642
|
+
if (isIosSimulator(own)) {
|
|
134643
|
+
if (own.id === named.id) return { device: own };
|
|
134644
|
+
if (isIosSimulator(named)) {
|
|
134645
|
+
const [listed2, ownListed] = await Promise.all([
|
|
134646
|
+
listedAs(named, app.deviceName),
|
|
134647
|
+
listedAs(own, app.deviceName)
|
|
134648
|
+
]);
|
|
134649
|
+
if (listed2 === "booted" && ownListed !== "booted") return { device: named };
|
|
134650
|
+
}
|
|
134651
|
+
return { device: own, readInsteadOfUdid: own.id };
|
|
134598
134652
|
}
|
|
134653
|
+
const [listed, session] = await Promise.all([
|
|
134654
|
+
isIosSimulator(named) ? listedAs(named, app.deviceName) : void 0,
|
|
134655
|
+
iosSimulatorOfSession(app)
|
|
134656
|
+
]);
|
|
134657
|
+
if (listed === "booted" || listed === "twin") {
|
|
134658
|
+
const sole = session === void 0 || session !== AMBIGUOUS_SIMULATOR && session.id === named.id;
|
|
134659
|
+
return listed === "booted" && sole ? { device: named } : { device: named, udidUnchecked: true };
|
|
134660
|
+
}
|
|
134661
|
+
if (session === AMBIGUOUS_SIMULATOR) return MISMATCHED_UDID;
|
|
134662
|
+
if (session) {
|
|
134663
|
+
return session.id === named.id ? { device: session } : { device: session, readInsteadOfUdid: session.id };
|
|
134664
|
+
}
|
|
134665
|
+
return listed === "unlisted" ? UNLISTED_UDID : void 0;
|
|
134666
|
+
}
|
|
134667
|
+
async function listedAs(device, name) {
|
|
134668
|
+
if (device.platform !== "ios-remote") {
|
|
134669
|
+
const sim2 = await findIosSimulator(device.id);
|
|
134670
|
+
if (!sim2) return "unlisted";
|
|
134671
|
+
return sim2.state === "Booted" && sim2.name === name ? "booted" : "other";
|
|
134672
|
+
}
|
|
134673
|
+
const listing = Object.values(
|
|
134674
|
+
(await simctlListDevices({ timeoutMs: ORIENTATION_READ_TIMEOUT_MS }).catch(() => ({
|
|
134675
|
+
devices: {}
|
|
134676
|
+
}))).devices
|
|
134677
|
+
).flat();
|
|
134678
|
+
const sim = listing.find((d) => d.udid === stripRemotePrefix(device.id));
|
|
134679
|
+
if (!sim) return "unlisted";
|
|
134680
|
+
if (sim.state !== "Booted" || sim.name !== name) return "other";
|
|
134681
|
+
return listing.some((d) => d !== sim && d.state === "Booted" && d.name === name) ? "twin" : "booted";
|
|
134682
|
+
}
|
|
134683
|
+
async function iosSimulatorOfSession(app) {
|
|
134599
134684
|
const device = resolveDevice(canonicalDeviceId(app.deviceId) ?? app.deviceId);
|
|
134600
134685
|
if (isIosSimulator(device)) return device;
|
|
134601
134686
|
const logicalKeyed = app.deviceId === app.logicalDeviceId || isLogicalKeyedDevice(app.deviceId);
|
|
@@ -134608,22 +134693,28 @@ async function iosSimulatorOf(app) {
|
|
|
134608
134693
|
}
|
|
134609
134694
|
async function readTapAxes(registry2, app) {
|
|
134610
134695
|
const read = (async () => {
|
|
134611
|
-
const
|
|
134612
|
-
if (
|
|
134613
|
-
if (
|
|
134696
|
+
const pick2 = await iosSimulatorOf(app);
|
|
134697
|
+
if (pick2 === void 0) return {};
|
|
134698
|
+
if (pick2 === AMBIGUOUS_SIMULATOR) return { uiOrientation: "ambiguous" };
|
|
134699
|
+
if (pick2 === MISMATCHED_UDID) return { uiOrientation: "mismatched" };
|
|
134700
|
+
if (pick2 === UNLISTED_UDID) return { uiOrientation: "unknown" };
|
|
134701
|
+
const { device, ...udid } = pick2;
|
|
134614
134702
|
const ref = nativeDevtoolsRef(device);
|
|
134615
134703
|
const api = await registry2.resolveService(ref.urn, ref.options);
|
|
134616
134704
|
const bundleId = await debuggedBundleId(api, app.appName);
|
|
134617
|
-
if (!bundleId) return "unknown";
|
|
134705
|
+
if (!bundleId) return { uiOrientation: "unknown", ...udid };
|
|
134618
134706
|
const raw = await api.queryViewHierarchy(bundleId, "ViewHierarchy.getFullHierarchy", {
|
|
134619
134707
|
fields: ["className"],
|
|
134620
134708
|
maxDepth: 1
|
|
134621
134709
|
});
|
|
134622
|
-
return
|
|
134623
|
-
|
|
134710
|
+
return {
|
|
134711
|
+
uiOrientation: asUiOrientation(raw?.screen?.interfaceOrientation) ?? "unknown",
|
|
134712
|
+
...udid
|
|
134713
|
+
};
|
|
134714
|
+
})().catch(() => ({ uiOrientation: "unknown" }));
|
|
134624
134715
|
let timer;
|
|
134625
134716
|
const timeout = new Promise((resolve14) => {
|
|
134626
|
-
timer = setTimeout(() => resolve14("unknown"), ORIENTATION_READ_TIMEOUT_MS);
|
|
134717
|
+
timer = setTimeout(() => resolve14({ uiOrientation: "unknown" }), ORIENTATION_READ_TIMEOUT_MS);
|
|
134627
134718
|
});
|
|
134628
134719
|
try {
|
|
134629
134720
|
return await Promise.race([read, timeout]);
|
|
@@ -134637,7 +134728,7 @@ var zodSchema34 = external_exports.object({
|
|
|
134637
134728
|
"Device id from list-devices \u2014 the SAME id you passed to debugger-connect (iOS simulator UDID or Android serial)."
|
|
134638
134729
|
),
|
|
134639
134730
|
udid: external_exports.string().optional().describe(
|
|
134640
|
-
"iOS simulator UDID from list-devices. Pass it when device_id is a logicalDeviceId (two or more devices share one Metro), so that the tap coordinates of a landscape UI are on the screen's axes."
|
|
134731
|
+
"iOS simulator UDID from list-devices. Pass it when device_id is a logicalDeviceId (two or more devices share one Metro), so that the tap coordinates of a landscape UI are on the screen's axes. Give the UDID of the simulator that shows the app."
|
|
134641
134732
|
),
|
|
134642
134733
|
onScreenOnly: external_exports.boolean().default(true).describe(
|
|
134643
134734
|
"When true (default), only components visible on screen are returned. Set to false to include all mounted components including those scrolled off-screen. Useful when you need to understand the full page structure."
|
|
@@ -134716,7 +134807,7 @@ Use when you need tap coordinates for a React Native UI element. Returns a compa
|
|
|
134716
134807
|
onScreenOnly: params.onScreenOnly,
|
|
134717
134808
|
maxNodes: params.maxNodes,
|
|
134718
134809
|
includeSkipped: params.includeSkipped,
|
|
134719
|
-
|
|
134810
|
+
...await tapAxes
|
|
134720
134811
|
});
|
|
134721
134812
|
const deviceLine = [
|
|
134722
134813
|
`device: ${api.deviceName}`,
|
|
@@ -150259,7 +150350,7 @@ async function runSwipe(env, step) {
|
|
|
150259
150350
|
toPoint = p;
|
|
150260
150351
|
}
|
|
150261
150352
|
const orientation = env.lastRead?.uiOrientation;
|
|
150262
|
-
if (settle.warning !== void 0 && step.direction) {
|
|
150353
|
+
if (settle.warning !== void 0 && step.direction && isIosSimulator(env.device)) {
|
|
150263
150354
|
settle = { ...settle, warning: `${settle.warning} ${unreadOrientationNote(orientation)}` };
|
|
150264
150355
|
}
|
|
150265
150356
|
let start2;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
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.
|
|
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
|
|
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
|
|