@swmansion/argent 0.23.1-next.0 → 0.23.1-next.2
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/README.md +1 -1
- package/dist/cli-cmds.mjs +32 -19
- package/dist/installer.mjs +30 -17
- package/dist/mcp-server.mjs +31 -18
- package/dist/tool-server.cjs +15 -7
- package/package.json +1 -1
- package/rules/argent.md +2 -2
- package/skills/argent-create-flow/SKILL.md +1 -1
- package/skills/argent-ios-device-interact/SKILL.md +6 -4
- package/skills/argent-ios-device-setup/SKILL.md +2 -2
- package/skills/argent-ios-simulator-setup/SKILL.md +1 -1
- package/skills/argent-metro-debugger/SKILL.md +2 -0
- package/skills/argent-native-profiler/SKILL.md +1 -0
- package/skills/argent-qa-flows/SKILL.md +1 -1
- package/skills/argent-react-native-app-workflow/SKILL.md +2 -0
- package/skills/argent-react-native-profiler/SKILL.md +2 -0
- package/skills/argent-test-ui-flow/SKILL.md +2 -0
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Argent drives a growing set of targets through a single toolkit, each with the r
|
|
|
23
23
|
|
|
24
24
|
| Platform | Targets | Interaction |
|
|
25
25
|
| ----------------- | ----------------------------------------------------------------------- | ---------------- |
|
|
26
|
-
| **iOS** | Simulators and physical iPhones
|
|
26
|
+
| **iOS** | Simulators and physical iPhones | Touch / gesture |
|
|
27
27
|
| **Android** | Emulators (AVDs) and physical devices over adb | Touch / gesture |
|
|
28
28
|
| **TV** | Apple TV (tvOS), Android TV / Google TV, Amazon Fire TV (Vega) | D-pad / remote |
|
|
29
29
|
| **Desktop & web** | Electron and Chromium apps (incl. React Native Web / Expo web) over CDP | Mouse / keyboard |
|
package/dist/cli-cmds.mjs
CHANGED
|
@@ -1805,14 +1805,10 @@ async function sweepDeadStateFiles() {
|
|
|
1805
1805
|
continue;
|
|
1806
1806
|
}
|
|
1807
1807
|
if (fs.existsSync(fresh.bundlePath)) continue;
|
|
1808
|
-
|
|
1809
|
-
if (guarded && !processCommandMatches(fresh.pid, fresh.bundlePath)) continue;
|
|
1808
|
+
if (!couldBeOurToolServer(fresh.pid, fresh.bundlePath)) continue;
|
|
1810
1809
|
await unlink(file).catch(() => {
|
|
1811
1810
|
});
|
|
1812
|
-
void terminatePid(
|
|
1813
|
-
fresh.pid,
|
|
1814
|
-
guarded ? () => processCommandMatches(fresh.pid, fresh.bundlePath) : void 0
|
|
1815
|
-
);
|
|
1811
|
+
void terminatePid(fresh.pid, () => couldBeOurToolServer(fresh.pid, fresh.bundlePath));
|
|
1816
1812
|
}
|
|
1817
1813
|
}
|
|
1818
1814
|
var readState = readToolsServerState;
|
|
@@ -1851,20 +1847,37 @@ async function killToolServer(bundlePath) {
|
|
|
1851
1847
|
await terminatePid(state2.pid);
|
|
1852
1848
|
await clearToolsServerState(bundlePath ?? state2.bundlePath);
|
|
1853
1849
|
}
|
|
1854
|
-
|
|
1850
|
+
var PS_BIN = ["/bin/ps", "/usr/bin/ps"].find((p) => fs.existsSync(p)) ?? "ps";
|
|
1851
|
+
var PS_WIDTH_FLAGS = ["-ww"];
|
|
1852
|
+
function readProcessCommandLine(pid, flags2 = PS_WIDTH_FLAGS) {
|
|
1853
|
+
return execFileSync(PS_BIN, [...flags2, "-p", String(pid), "-o", "command="], {
|
|
1854
|
+
encoding: "utf8",
|
|
1855
|
+
timeout: 2e3,
|
|
1856
|
+
// A recycled pid can sit on a process with an argv past Node's 1 MiB exec
|
|
1857
|
+
// default, where the overrun surfaces as ENOBUFS instead of a command line.
|
|
1858
|
+
// Same ceiling as tool-server's vega-process ps probes.
|
|
1859
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
1860
|
+
// Piping ps's stderr is what puts a rejected flag ("ps: invalid option --
|
|
1861
|
+
// 'w'") into the thrown error's message.
|
|
1862
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1863
|
+
}).trim();
|
|
1864
|
+
}
|
|
1865
|
+
function couldBeOurToolServer(pid, marker) {
|
|
1855
1866
|
if (!marker) return false;
|
|
1867
|
+
if (process.platform === "win32") return true;
|
|
1868
|
+
let cmd;
|
|
1856
1869
|
try {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1864
|
-
return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
|
|
1865
|
-
} catch {
|
|
1870
|
+
cmd = readProcessCommandLine(pid);
|
|
1871
|
+
} catch (err) {
|
|
1872
|
+
process.stderr.write(
|
|
1873
|
+
`[launcher] ps could not read pid ${pid}'s command line; leaving it alone: ${String(err)}
|
|
1874
|
+
`
|
|
1875
|
+
);
|
|
1866
1876
|
return false;
|
|
1867
1877
|
}
|
|
1878
|
+
if (!cmd) return false;
|
|
1879
|
+
const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1880
|
+
return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
|
|
1868
1881
|
}
|
|
1869
1882
|
var LOCK_WAIT_TIMEOUT_MS = 3e4;
|
|
1870
1883
|
var LOCK_STALE_MS = 45e3;
|
|
@@ -1953,8 +1966,8 @@ async function ensureToolsServer(paths) {
|
|
|
1953
1966
|
const state2 = await readState(paths.bundlePath);
|
|
1954
1967
|
const reuse = await reusableHandle(state2, paths.bundlePath, paths.version);
|
|
1955
1968
|
if (reuse) return reuse;
|
|
1956
|
-
if (state2 && state2.managed === "autospawn" && state2.bundlePath === paths.bundlePath && isProcessAlive(state2.pid) &&
|
|
1957
|
-
await terminatePid(state2.pid, () =>
|
|
1969
|
+
if (state2 && state2.managed === "autospawn" && state2.bundlePath === paths.bundlePath && isProcessAlive(state2.pid) && couldBeOurToolServer(state2.pid, state2.bundlePath)) {
|
|
1970
|
+
await terminatePid(state2.pid, () => couldBeOurToolServer(state2.pid, state2.bundlePath));
|
|
1958
1971
|
}
|
|
1959
1972
|
await clearToolsServerState(paths.bundlePath);
|
|
1960
1973
|
await sweepDeadStateFiles();
|
|
@@ -7240,7 +7253,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
7240
7253
|
var SESSION_ID2 = randomUUID5();
|
|
7241
7254
|
function readCliVersion() {
|
|
7242
7255
|
if (true) {
|
|
7243
|
-
return "0.23.1-next.
|
|
7256
|
+
return "0.23.1-next.2";
|
|
7244
7257
|
}
|
|
7245
7258
|
return "0.0.0";
|
|
7246
7259
|
}
|
package/dist/installer.mjs
CHANGED
|
@@ -16625,7 +16625,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
16625
16625
|
var SESSION_ID = randomUUID4();
|
|
16626
16626
|
function readCliVersion() {
|
|
16627
16627
|
if (true) {
|
|
16628
|
-
return "0.23.1-next.
|
|
16628
|
+
return "0.23.1-next.2";
|
|
16629
16629
|
}
|
|
16630
16630
|
return "0.0.0";
|
|
16631
16631
|
}
|
|
@@ -23046,15 +23046,11 @@ async function killToolServerForInstallDir(packageDir) {
|
|
|
23046
23046
|
const fresh = await readStateFile(file);
|
|
23047
23047
|
if (!fresh || fresh.pid !== state2.pid || fresh.bundlePath !== state2.bundlePath) continue;
|
|
23048
23048
|
const alive = isProcessAlive(fresh.pid);
|
|
23049
|
-
|
|
23050
|
-
if (alive && guarded && !processCommandMatches(fresh.pid, fresh.bundlePath)) {
|
|
23049
|
+
if (alive && !couldBeOurToolServer(fresh.pid, fresh.bundlePath)) {
|
|
23051
23050
|
continue;
|
|
23052
23051
|
}
|
|
23053
23052
|
if (alive) {
|
|
23054
|
-
await terminatePid(
|
|
23055
|
-
fresh.pid,
|
|
23056
|
-
guarded ? () => processCommandMatches(fresh.pid, fresh.bundlePath) : void 0
|
|
23057
|
-
);
|
|
23053
|
+
await terminatePid(fresh.pid, () => couldBeOurToolServer(fresh.pid, fresh.bundlePath));
|
|
23058
23054
|
}
|
|
23059
23055
|
await unlink(file).catch(() => {
|
|
23060
23056
|
});
|
|
@@ -23062,20 +23058,37 @@ async function killToolServerForInstallDir(packageDir) {
|
|
|
23062
23058
|
}
|
|
23063
23059
|
return killed;
|
|
23064
23060
|
}
|
|
23065
|
-
|
|
23061
|
+
var PS_BIN = ["/bin/ps", "/usr/bin/ps"].find((p) => fs16.existsSync(p)) ?? "ps";
|
|
23062
|
+
var PS_WIDTH_FLAGS = ["-ww"];
|
|
23063
|
+
function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS) {
|
|
23064
|
+
return execFileSync5(PS_BIN, [...flags, "-p", String(pid), "-o", "command="], {
|
|
23065
|
+
encoding: "utf8",
|
|
23066
|
+
timeout: 2e3,
|
|
23067
|
+
// A recycled pid can sit on a process with an argv past Node's 1 MiB exec
|
|
23068
|
+
// default, where the overrun surfaces as ENOBUFS instead of a command line.
|
|
23069
|
+
// Same ceiling as tool-server's vega-process ps probes.
|
|
23070
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
23071
|
+
// Piping ps's stderr is what puts a rejected flag ("ps: invalid option --
|
|
23072
|
+
// 'w'") into the thrown error's message.
|
|
23073
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
23074
|
+
}).trim();
|
|
23075
|
+
}
|
|
23076
|
+
function couldBeOurToolServer(pid, marker) {
|
|
23066
23077
|
if (!marker) return false;
|
|
23078
|
+
if (process.platform === "win32") return true;
|
|
23079
|
+
let cmd;
|
|
23067
23080
|
try {
|
|
23068
|
-
|
|
23069
|
-
|
|
23070
|
-
|
|
23071
|
-
|
|
23072
|
-
|
|
23073
|
-
|
|
23074
|
-
const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23075
|
-
return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
|
|
23076
|
-
} catch {
|
|
23081
|
+
cmd = readProcessCommandLine(pid);
|
|
23082
|
+
} catch (err) {
|
|
23083
|
+
process.stderr.write(
|
|
23084
|
+
`[launcher] ps could not read pid ${pid}'s command line; leaving it alone: ${String(err)}
|
|
23085
|
+
`
|
|
23086
|
+
);
|
|
23077
23087
|
return false;
|
|
23078
23088
|
}
|
|
23089
|
+
if (!cmd) return false;
|
|
23090
|
+
const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23091
|
+
return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
|
|
23079
23092
|
}
|
|
23080
23093
|
|
|
23081
23094
|
// ../argent-tools-client/src/link-config.ts
|
package/dist/mcp-server.mjs
CHANGED
|
@@ -16057,14 +16057,10 @@ async function sweepDeadStateFiles() {
|
|
|
16057
16057
|
continue;
|
|
16058
16058
|
}
|
|
16059
16059
|
if (fs.existsSync(fresh.bundlePath)) continue;
|
|
16060
|
-
|
|
16061
|
-
if (guarded && !processCommandMatches(fresh.pid, fresh.bundlePath)) continue;
|
|
16060
|
+
if (!couldBeOurToolServer(fresh.pid, fresh.bundlePath)) continue;
|
|
16062
16061
|
await unlink(file).catch(() => {
|
|
16063
16062
|
});
|
|
16064
|
-
void terminatePid(
|
|
16065
|
-
fresh.pid,
|
|
16066
|
-
guarded ? () => processCommandMatches(fresh.pid, fresh.bundlePath) : void 0
|
|
16067
|
-
);
|
|
16063
|
+
void terminatePid(fresh.pid, () => couldBeOurToolServer(fresh.pid, fresh.bundlePath));
|
|
16068
16064
|
}
|
|
16069
16065
|
}
|
|
16070
16066
|
var readState = readToolsServerState;
|
|
@@ -16097,20 +16093,37 @@ async function terminatePid(pid, stillOurs) {
|
|
|
16097
16093
|
}
|
|
16098
16094
|
await waitForExit(pid, SIGKILL_GRACE_MS);
|
|
16099
16095
|
}
|
|
16100
|
-
|
|
16096
|
+
var PS_BIN = ["/bin/ps", "/usr/bin/ps"].find((p) => fs.existsSync(p)) ?? "ps";
|
|
16097
|
+
var PS_WIDTH_FLAGS = ["-ww"];
|
|
16098
|
+
function readProcessCommandLine(pid, flags = PS_WIDTH_FLAGS) {
|
|
16099
|
+
return execFileSync(PS_BIN, [...flags, "-p", String(pid), "-o", "command="], {
|
|
16100
|
+
encoding: "utf8",
|
|
16101
|
+
timeout: 2e3,
|
|
16102
|
+
// A recycled pid can sit on a process with an argv past Node's 1 MiB exec
|
|
16103
|
+
// default, where the overrun surfaces as ENOBUFS instead of a command line.
|
|
16104
|
+
// Same ceiling as tool-server's vega-process ps probes.
|
|
16105
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
16106
|
+
// Piping ps's stderr is what puts a rejected flag ("ps: invalid option --
|
|
16107
|
+
// 'w'") into the thrown error's message.
|
|
16108
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
16109
|
+
}).trim();
|
|
16110
|
+
}
|
|
16111
|
+
function couldBeOurToolServer(pid, marker) {
|
|
16101
16112
|
if (!marker) return false;
|
|
16113
|
+
if (process.platform === "win32") return true;
|
|
16114
|
+
let cmd;
|
|
16102
16115
|
try {
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16110
|
-
return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
|
|
16111
|
-
} catch {
|
|
16116
|
+
cmd = readProcessCommandLine(pid);
|
|
16117
|
+
} catch (err) {
|
|
16118
|
+
process.stderr.write(
|
|
16119
|
+
`[launcher] ps could not read pid ${pid}'s command line; leaving it alone: ${String(err)}
|
|
16120
|
+
`
|
|
16121
|
+
);
|
|
16112
16122
|
return false;
|
|
16113
16123
|
}
|
|
16124
|
+
if (!cmd) return false;
|
|
16125
|
+
const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16126
|
+
return new RegExp(`(?:^|\\s)${escaped} start(?:\\s|$)`).test(cmd);
|
|
16114
16127
|
}
|
|
16115
16128
|
var LOCK_WAIT_TIMEOUT_MS = 3e4;
|
|
16116
16129
|
var LOCK_STALE_MS = 45e3;
|
|
@@ -16199,8 +16212,8 @@ async function ensureToolsServer(paths) {
|
|
|
16199
16212
|
const state = await readState(paths.bundlePath);
|
|
16200
16213
|
const reuse = await reusableHandle(state, paths.bundlePath, paths.version);
|
|
16201
16214
|
if (reuse) return reuse;
|
|
16202
|
-
if (state && state.managed === "autospawn" && state.bundlePath === paths.bundlePath && isProcessAlive(state.pid) &&
|
|
16203
|
-
await terminatePid(state.pid, () =>
|
|
16215
|
+
if (state && state.managed === "autospawn" && state.bundlePath === paths.bundlePath && isProcessAlive(state.pid) && couldBeOurToolServer(state.pid, state.bundlePath)) {
|
|
16216
|
+
await terminatePid(state.pid, () => couldBeOurToolServer(state.pid, state.bundlePath));
|
|
16204
16217
|
}
|
|
16205
16218
|
await clearToolsServerState(paths.bundlePath);
|
|
16206
16219
|
await sweepDeadStateFiles();
|
package/dist/tool-server.cjs
CHANGED
|
@@ -93916,7 +93916,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
93916
93916
|
var SESSION_ID = (0, import_node_crypto3.randomUUID)();
|
|
93917
93917
|
function readCliVersion() {
|
|
93918
93918
|
if (true) {
|
|
93919
|
-
return "0.23.1-next.
|
|
93919
|
+
return "0.23.1-next.2";
|
|
93920
93920
|
}
|
|
93921
93921
|
return "0.0.0";
|
|
93922
93922
|
}
|
|
@@ -95451,6 +95451,11 @@ function subjectValue(subject, key2) {
|
|
|
95451
95451
|
}
|
|
95452
95452
|
return null;
|
|
95453
95453
|
}
|
|
95454
|
+
function signingLabel(commonName) {
|
|
95455
|
+
const match = /^([^:]+):.*\(([A-Za-z0-9]+)\)\s*$/.exec(commonName);
|
|
95456
|
+
if (match) return `${match[1].trim()} (${match[2]})`;
|
|
95457
|
+
return commonName.split(":")[0].trim();
|
|
95458
|
+
}
|
|
95454
95459
|
function parseSigningTeams(pem) {
|
|
95455
95460
|
const newestByTeam = /* @__PURE__ */ new Map();
|
|
95456
95461
|
for (const block of pem.match(PEM_BLOCK_RE) ?? []) {
|
|
@@ -95461,11 +95466,12 @@ function parseSigningTeams(pem) {
|
|
|
95461
95466
|
continue;
|
|
95462
95467
|
}
|
|
95463
95468
|
const teamId = subjectValue(cert.subject, "OU");
|
|
95464
|
-
const
|
|
95469
|
+
const commonName = subjectValue(cert.subject, "CN");
|
|
95465
95470
|
const issuedAtMs = Date.parse(cert.validFrom);
|
|
95466
|
-
if (!teamId || !
|
|
95471
|
+
if (!teamId || !commonName || Number.isNaN(issuedAtMs)) {
|
|
95467
95472
|
continue;
|
|
95468
95473
|
}
|
|
95474
|
+
const label = signingLabel(commonName);
|
|
95469
95475
|
const known = newestByTeam.get(teamId);
|
|
95470
95476
|
if (!known || issuedAtMs > known.issuedAtMs) {
|
|
95471
95477
|
newestByTeam.set(teamId, { teamId, label, issuedAtMs });
|
|
@@ -113260,7 +113266,9 @@ function extractDeviceArg(data) {
|
|
|
113260
113266
|
return null;
|
|
113261
113267
|
}
|
|
113262
113268
|
function targetsIosPhysicalDevice(data) {
|
|
113263
|
-
const
|
|
113269
|
+
const record2 = data && typeof data === "object" ? data : null;
|
|
113270
|
+
const flowDevice = typeof record2?.device === "string" ? record2.device : null;
|
|
113271
|
+
const deviceArg = extractDeviceArg(data) ?? flowDevice;
|
|
113264
113272
|
return deviceArg !== null && isIosPhysicalDevice(resolveDevice(deviceArg));
|
|
113265
113273
|
}
|
|
113266
113274
|
function inferPlatform(deviceId) {
|
|
@@ -122048,7 +122056,7 @@ var gestureSwipeTool = {
|
|
|
122048
122056
|
Generates interpolated Move events for a natural feel (~60fps).
|
|
122049
122057
|
Swipe up (fromY > toY) to scroll content down.
|
|
122050
122058
|
Use when you need to scroll a list, dismiss a modal, drag an element, or navigate between pages. Not supported on Chromium \u2014 use gesture-scroll there instead.
|
|
122051
|
-
Physical iOS: an edge gesture (back-swipe) needs fromX 0 exactly.
|
|
122059
|
+
Physical iOS: an edge gesture (back-swipe) needs fromX 0 exactly; durationMs sets drag speed, not time; momentum:false only rests 300ms at the end and does not damp.
|
|
122052
122060
|
Pass momentum:false for a momentum-free swipe that lands where the finger lifts (little to no fling at the 300 default), when you need a deterministic scroll distance; it needs durationMs >= 150 and is rejected below that, a shorter ease-out leaving the OS too little wall clock to read the deceleration as a stop. At 150 it lands short of the lift point instead, and 2 of 47 runs still flung backwards. A plain swipe takes any duration up to 10000ms and is delivered as close to the speed it was authored as a 16ms frame allows: below ~32ms the whole travel lands in one or two frames, which the OS flings as hard as it flings anything. Returns { swiped: true, timestampMs }. On physical iOS, reactivated: true = app was re-fronted; re-describe. Fails if the simulator-server / emulator backend is not reachable for the given device.`,
|
|
122053
122061
|
alwaysLoad: true,
|
|
122054
122062
|
searchHint: "swipe scroll drag pan gesture device simulator emulator touch move",
|
|
@@ -133313,7 +133321,7 @@ The tree carries no z-order or occlusion information: an element listed at a poi
|
|
|
133313
133321
|
by an overlay (e.g. a toolbar over list rows), so check a screenshot when a tap lands unexpectedly.
|
|
133314
133322
|
|
|
133315
133323
|
For app-scoped inspection with full UIKit properties (accessibilityIdentifier, viewClassName),
|
|
133316
|
-
use native-describe-screen with an explicit bundleId instead (iOS only).
|
|
133324
|
+
use native-describe-screen with an explicit bundleId instead (iOS simulator only).
|
|
133317
133325
|
For React Native apps, debugger-component-tree returns React component names with tap coordinates.
|
|
133318
133326
|
|
|
133319
133327
|
On a TV target (Apple TV / Android TV \u2014 a \`list-devices\` entry with runtimeKind 'tv') this returns
|
|
@@ -145637,7 +145645,7 @@ function connectedIosDeviceHint(devices, platform) {
|
|
|
145637
145645
|
if (platform && platform !== "ios") return "";
|
|
145638
145646
|
const ids = devices.filter((d) => d.platform === "ios" && d.kind === "device" && d.state === "connected").map((d) => d.udid).filter((id) => Boolean(id));
|
|
145639
145647
|
if (ids.length === 0) return "";
|
|
145640
|
-
return ` A physical iPhone is connected (${ids.join(", ")}); hardware is never picked automatically, pass
|
|
145648
|
+
return ` A physical iPhone is connected (${ids.join(", ")}); hardware is never picked automatically, pass device <udid> (--device on the CLI) to run on it.`;
|
|
145641
145649
|
}
|
|
145642
145650
|
function describeDevice(d) {
|
|
145643
145651
|
return `${deviceEntryId(d) ?? "?"} (${d.platform}${d.state ? `, ${d.state}` : ""})`;
|
package/package.json
CHANGED
package/rules/argent.md
CHANGED
|
@@ -83,7 +83,7 @@ Decision order:
|
|
|
83
83
|
argent install, so an unscoped call tears down their devices too; reserve that form for a deliberate
|
|
84
84
|
machine-wide cleanup.
|
|
85
85
|
If the user started Metro separately, ask whether to call `stop-metro` (specify the port if not 8081).
|
|
86
|
-
- If tools provided by mcp-server are not sufficient and action can be done using `xcrun`, `adb`, or other commands, use the command. Examples: changing device options, performing a device action such as lock, shake, etc.
|
|
86
|
+
- If tools provided by mcp-server are not sufficient and action can be done using `xcrun`, `adb`, or other commands, use the command. Examples: changing device options, performing a device action such as lock, shake, etc. Not on a physical iPhone.
|
|
87
87
|
- When waiting for an action, do not call `screenshot` repeatedly without a proper wait mechanism. Use the `await-ui-element` tool to block until the UI settles (e.g. wait for an element to become `visible`/`hidden`, or to contain expected `text`) instead of polling.
|
|
88
88
|
</general_rules>
|
|
89
89
|
|
|
@@ -114,7 +114,7 @@ When: Beginning a task that involves the Android emulator, no emulator running y
|
|
|
114
114
|
|
|
115
115
|
PHYSICAL iPHONE (USB)
|
|
116
116
|
Skills: `argent-ios-device-setup` (cable, trust, signing), then `argent-ios-device-interact` (the app-scoped interaction contract)
|
|
117
|
-
When: The user names a physical iPhone, a real device, or hardware, or the target `list-devices` iOS entry has kind `"device"`. Never for a simulator, and never because a cabled phone is listed first. On hardware every interaction starts with `launch-app`; `paste`, `settings-permissions`, two-finger gestures, `rotate`
|
|
117
|
+
When: The user names a physical iPhone, a real device, or hardware, or the target `list-devices` iOS entry has kind `"device"`. Never for a simulator, and never because a cabled phone is listed first. On hardware every interaction starts with `launch-app`; `paste`, `settings-permissions`, two-finger gestures, `rotate`, `shake`, screen recording, `debugger-*`, `react-profiler-*`, `native-profiler-*` and `native-*` do not exist there.
|
|
118
118
|
Prompt keywords: physical iPhone, real device, on my phone, USB, hardware
|
|
119
119
|
|
|
120
120
|
TAPPING, SWIPING, TYPING, GESTURES, SCREENSHOTS, SCROLLING
|
|
@@ -13,7 +13,7 @@ For a saved QA test case, ticket, or acceptance criterion, load `argent-qa-flows
|
|
|
13
13
|
|
|
14
14
|
- Before creating or changing a flow, read [Live authoring](references/live-authoring.md) completely.
|
|
15
15
|
- When polishing, composing, or manually reviewing YAML, read [Flow YAML](references/flow-yaml.md). For Vega, read its platform limits before recording remote or keyboard tools.
|
|
16
|
-
- Flows run on physical iPhones (an iOS `list-devices` entry with kind `"device"`), but replay never auto-binds one, even when no simulator is booted: pass the phone's udid as `device` (CLI `--device`), and only a `connected` phone can run. `pinch`/`rotate` steps fail there like the live tools. See `argent-ios-device-interact` for the hardware contract.
|
|
16
|
+
- Flows run on physical iPhones (an iOS `list-devices` entry with kind `"device"`), but replay never auto-binds one, even when no simulator is booted: pass the phone's udid as `device` (CLI `--device`), and only a `connected` phone can run. `pinch`/`rotate` steps fail there like the live tools. On hardware the flow tree is the `describe` tree: same ids and roles, no UIView hierarchy. See `argent-ios-device-interact` for the hardware contract.
|
|
17
17
|
- On capture warnings, raw coordinates, unavailable trees, mistimed transitions, overlays, or replay failures, read [Reliability and recovery](references/reliability-and-recovery.md).
|
|
18
18
|
|
|
19
19
|
## Non-negotiable rules
|
|
@@ -9,10 +9,12 @@ Read this only for a physical iPhone. `argent-device-interact` still applies for
|
|
|
9
9
|
|
|
10
10
|
## Contract
|
|
11
11
|
|
|
12
|
-
- Observation never changes the screen; mutation may. `describe` and `await-ui-element` fail on a backgrounded target instead of re-fronting it. Gestures and `keyboard` re-front it and return `reactivated: true`; re-describe before the next step.
|
|
13
|
-
-
|
|
12
|
+
- Observation never changes the screen; mutation may. `describe` and `await-ui-element` fail on a backgrounded target instead of re-fronting it; `await-screen-idle` returns `settled: false` with no reason. The first `describe` within a second of `button home` can still return the old tree; describe again. Gestures and `keyboard` re-front it and return `reactivated: true`; re-describe before the next step.
|
|
13
|
+
- `launch-app`, `open-url` and `restart-app` set the app under automation; `reinstall-app` clears it; a tool-server restart forgets it: launch again.
|
|
14
|
+
- Each tool's description states its own hardware limits (named keys, `gesture-custom` shapes, buttons, edge swipes, tap counts). A gated tool fails with a bare `not supported on ios device`: the fix is in the list below, not in the error.
|
|
14
15
|
|
|
15
16
|
## Tools on hardware
|
|
16
17
|
|
|
17
|
-
- Only these exist: `list-devices`, `launch-app`, `restart-app`, `reinstall-app`, `open-url`, `describe`, `screenshot`, `screenshot-diff`, `gesture-tap`, `gesture-swipe`, `gesture-custom`, `button`, `keyboard`, `await-ui-element`, `await-screen-idle`, `run-sequence`, the flow tools, and `stop-simulator-
|
|
18
|
-
- No two-finger gestures, `rotate`, `shake`, `paste`,
|
|
18
|
+
- Only these exist: `list-devices`, `launch-app`, `restart-app`, `reinstall-app`, `open-url`, `describe`, `screenshot`, `screenshot-diff`, `gesture-tap`, `gesture-swipe`, `gesture-custom`, `button` (`home`, `volumeUp`, `volumeDown`, `actionButton` on models that have one), `keyboard`, `await-ui-element`, `await-screen-idle`, `run-sequence`, the flow tools, `stop-simulator-server` and `stop-all-simulator-servers` (session end). Every other device tool fails with `not supported on ios device`.
|
|
19
|
+
- No two-finger gestures, `rotate`, `shake`, `paste`, `settings-permissions`, screen recording, `debugger-*`, `react-profiler-*`, `native-profiler-*`, `native-*`, `boot-device`: drive the app's own zoom and rotate UI with taps and drags, move the phone by hand, type with `keyboard`, change permissions in the phone's Settings, and debug, profile or record on a simulator.
|
|
20
|
+
- `gesture-swipe`: `durationMs` sets drag speed, not time; `momentum:false` only rests 300 ms at the end, no damping. `open-url` https lands in Safari, never in the app that owns the link: pass `bundleId`.
|
|
@@ -10,11 +10,11 @@ Read this only for a physical iPhone. Simulators use `argent-ios-simulator-setup
|
|
|
10
10
|
## First run
|
|
11
11
|
|
|
12
12
|
1. Cable the phone, unlock it, keep the screen awake, and turn on Developer Mode (Settings > Privacy & Security > Developer Mode). `list-devices` must show it `connected`.
|
|
13
|
-
2.
|
|
13
|
+
2. `launch-app` only registers the app. The first `describe`, gesture or `screenshot` builds, signs and starts the on-device runner: minutes cold, tens of seconds from cache or after a tool-server restart. Build cap 15 min, runner ready 120 s.
|
|
14
14
|
3. On the first install the phone asks to trust the developer (Settings > General > VPN & Device Management), and an **ArgentRunner** app appears on the home screen. Tell the user it is argent's automation runner and must stay installed.
|
|
15
15
|
|
|
16
16
|
## Signing and failures
|
|
17
17
|
|
|
18
|
-
Signing needs no configuration. The
|
|
18
|
+
Signing needs no configuration. The first phone call of a tool-server process carries a note naming the team picked and the `ARGENT_IOS_TEAM_ID` override (tool-server environment; a change forces a cold rebuild). Cable, lock, trust, expired-profile and missing-certificate errors name their fix: apply it, retry the same call. Also: `errSecInternalComponent`: run `security set-key-partition-list -S apple-tool:,apple:,codesign: -s ~/Library/Keychains/login.keychain-db` (asks the user's login password), retry. `team has no devices`: keep the phone cabled, retry. Bundle id registration failed: free-team app-id cap, wait days or sign under a paid team. Any other xcodebuild failure prints raw `error:` lines: read `~/.argent/ios-device-runner/logs/runner-<udid8>.log`. `RUNNER_WEDGED`: `stop-simulator-server` for the udid, retry.
|
|
19
19
|
|
|
20
20
|
Then read `argent-ios-device-interact`.
|
|
@@ -8,7 +8,7 @@ description: Set up and connect to an iOS simulator using argent MCP tools. Use
|
|
|
8
8
|
If you delegate simulator tasks to sub-agents, make sure they have MCP permissions.
|
|
9
9
|
|
|
10
10
|
1. **Find a booted simulator**
|
|
11
|
-
Use `list-devices`. Filter for entries with `platform: "ios"`
|
|
11
|
+
Use `list-devices`. Filter for entries with `platform: "ios"` and skip any with `kind: "device"` (a physical iPhone, never a simulator target): booted simulators are listed first.
|
|
12
12
|
If none are booted, call `boot-device` with `udid: <chosen UDID>`.
|
|
13
13
|
|
|
14
14
|
2. **Verify connection**
|
|
@@ -5,6 +5,8 @@ description: Debug a JS runtime via CDP using argent debugger tools. Primary pat
|
|
|
5
5
|
|
|
6
6
|
## 1. Prerequisites
|
|
7
7
|
|
|
8
|
+
Physical iPhone: not supported; every `debugger-*` tool rejects `kind: "device"`. Use a simulator.
|
|
9
|
+
|
|
8
10
|
For **React Native (iOS / Android)**: requires **Metro dev server running** (default `localhost:8081`) and **a React Native app connected to Metro** (at least one CDP target). Verify via `debugger-status` — it returns `status: "connected"` or `status: "not_connected"` with a `reason` and `guidance` (it does not fail when the debugger is unreachable).
|
|
9
11
|
|
|
10
12
|
For **Vega (Fire TV)**: requires a **Debug `.vpkg`** (a Release build never attaches) and **Metro reachable from the device** (`vega device start-port-forwarding --port 8081 --forward false`). Verify via `debugger-status`. `debugger-component-tree`, `debugger-inspect-element`, `debugger-reload-metro` and the `react-profiler-*` / `profiler-*` tools are unavailable there — see the `argent-tv-interact` skill.
|
|
@@ -10,6 +10,7 @@ description: Native profiling for CPU hotspots, UI hangs, memory issues. iOS via
|
|
|
10
10
|
- `native-profiler-analyze` — parse exported trace data and return a structured bottleneck payload.
|
|
11
11
|
- `profiler-stack-query` — drill into parsed data: hang stacks, function callers, thread breakdown, leak details.
|
|
12
12
|
- `profiler-load` — list and reload previous trace sessions from disk for re-investigation.
|
|
13
|
+
- Physical iPhone: not supported; use a simulator.
|
|
13
14
|
|
|
14
15
|
---
|
|
15
16
|
|
|
@@ -11,7 +11,7 @@ Load `argent-create-flow` as the authoring engine. Follow its required reference
|
|
|
11
11
|
|
|
12
12
|
**Apple TV and Android TV are out of scope.** The runner does not reject touch directives there, so they fail at the gesture layer instead of with authoring guidance. Use `argent-tv-interact` and report the limitation.
|
|
13
13
|
|
|
14
|
-
**Physical iPhones** run QA flows, with
|
|
14
|
+
**Physical iPhones** run QA flows, with three hardware limits: replay never auto-binds a phone, so pass its udid as `device` (CLI `--device`) and keep it `connected`; `pinch`/`rotate` steps fail there like the live tools, so drive the app's own zoom UI instead; the flow tree is the `describe` tree (same ids and roles), so a selector authored on a simulator can miss there. Read `argent-ios-device-interact` for the app-scoped contract before recording.
|
|
15
15
|
|
|
16
16
|
## Definition of done
|
|
17
17
|
|
|
@@ -3,6 +3,8 @@ name: argent-react-native-app-workflow
|
|
|
3
3
|
description: Step-by-step workflows for developing or debugging React Native apps on iOS simulator or Android emulator. Use when starting the app, debugging Metro, fixing builds, diagnosing runtime errors, or running tests.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
Physical iPhone (`kind: "device"`): Metro debugging and profiling tools reject it. Use a simulator.
|
|
7
|
+
|
|
6
8
|
## 1. Starting the React Native App
|
|
7
9
|
|
|
8
10
|
### 1.1 Explore Configuration (MANDATORY — Do This First)
|
|
@@ -5,6 +5,8 @@ description: Profile a React Native Hermes app to measure re-render and CPU perf
|
|
|
5
5
|
|
|
6
6
|
This skill is complementary to `argent-react-native-optimization`, not a replacement for it.
|
|
7
7
|
|
|
8
|
+
Physical iPhone: not supported; `react-profiler-*` reject `kind: "device"`. Profile on a simulator.
|
|
9
|
+
|
|
8
10
|
## 2. Tool Overview
|
|
9
11
|
|
|
10
12
|
### React Profiler (Hermes / React commits)
|
|
@@ -5,6 +5,8 @@ description: Autonomously test an app UI (iOS or Android) by running interact-sc
|
|
|
5
5
|
|
|
6
6
|
## Platform-agnostic
|
|
7
7
|
|
|
8
|
+
Physical iPhone (`kind: "device"`): read `argent-ios-device-interact` first. `launch-app` before anything; `describe` fails while the app is backgrounded.
|
|
9
|
+
|
|
8
10
|
The interaction tool names are identical on iOS and Android — `gesture-tap`, `gesture-swipe`, `describe`, `screenshot`, `launch-app`, etc. — and the tool-server auto-dispatches based on the `udid` you pass (UUID-shape → iOS, adb serial → Android).
|
|
9
11
|
|
|
10
12
|
**Before testing, resolve which device to test on.** Call `list-devices` and follow `<device_selection_rule>`: prefer a running device on any platform;
|