@swmansion/argent 0.15.1-next.6 → 0.15.1-next.8
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/dist/cli-cmds.mjs +2 -1
- package/dist/installer.mjs +2 -1
- package/dist/mcp-server.mjs +19 -2
- package/dist/tool-server.cjs +147 -42
- package/package.json +1 -1
- package/rules/argent.md +1 -1
- package/skills/argent-create-flow/SKILL.md +2 -0
- package/skills/argent-device-interact/SKILL.md +12 -0
- package/skills/argent-metro-debugger/SKILL.md +8 -6
- package/skills/argent-metro-debugger/references/failure-scenarios.md +6 -6
- package/skills/argent-tv-interact/SKILL.md +11 -1
package/dist/cli-cmds.mjs
CHANGED
|
@@ -6234,10 +6234,10 @@ var FAILURE_CODES = {
|
|
|
6234
6234
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
6235
6235
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
6236
6236
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
6237
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
6238
6237
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
6239
6238
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
6240
6239
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
6240
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
6241
6241
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
6242
6242
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
6243
6243
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -6324,6 +6324,7 @@ var FAILURE_CODES = {
|
|
|
6324
6324
|
CHROMIUM_ELECTRON_EXITED_BEFORE_READY: "CHROMIUM_ELECTRON_EXITED_BEFORE_READY",
|
|
6325
6325
|
KEYBOARD_KEY_UNSUPPORTED: "KEYBOARD_KEY_UNSUPPORTED",
|
|
6326
6326
|
KEYBOARD_CHARACTER_UNSUPPORTED: "KEYBOARD_CHARACTER_UNSUPPORTED",
|
|
6327
|
+
SECRET_PLACEHOLDER_UNKNOWN: "SECRET_PLACEHOLDER_UNKNOWN",
|
|
6327
6328
|
SCREENSHOT_DIFF_INPUT_INVALID: "SCREENSHOT_DIFF_INPUT_INVALID",
|
|
6328
6329
|
BOOT_DEVICE_TARGET_SELECTION_INVALID: "BOOT_DEVICE_TARGET_SELECTION_INVALID",
|
|
6329
6330
|
BOOT_IOS_UNSUPPORTED_HOST: "BOOT_IOS_UNSUPPORTED_HOST",
|
package/dist/installer.mjs
CHANGED
|
@@ -16141,10 +16141,10 @@ var FAILURE_CODES = {
|
|
|
16141
16141
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
16142
16142
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
16143
16143
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
16144
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
16145
16144
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
16146
16145
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
16147
16146
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
16147
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
16148
16148
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
16149
16149
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
16150
16150
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -16231,6 +16231,7 @@ var FAILURE_CODES = {
|
|
|
16231
16231
|
CHROMIUM_ELECTRON_EXITED_BEFORE_READY: "CHROMIUM_ELECTRON_EXITED_BEFORE_READY",
|
|
16232
16232
|
KEYBOARD_KEY_UNSUPPORTED: "KEYBOARD_KEY_UNSUPPORTED",
|
|
16233
16233
|
KEYBOARD_CHARACTER_UNSUPPORTED: "KEYBOARD_CHARACTER_UNSUPPORTED",
|
|
16234
|
+
SECRET_PLACEHOLDER_UNKNOWN: "SECRET_PLACEHOLDER_UNKNOWN",
|
|
16234
16235
|
SCREENSHOT_DIFF_INPUT_INVALID: "SCREENSHOT_DIFF_INPUT_INVALID",
|
|
16235
16236
|
BOOT_DEVICE_TARGET_SELECTION_INVALID: "BOOT_DEVICE_TARGET_SELECTION_INVALID",
|
|
16236
16237
|
BOOT_IOS_UNSUPPORTED_HOST: "BOOT_IOS_UNSUPPORTED_HOST",
|
package/dist/mcp-server.mjs
CHANGED
|
@@ -17660,10 +17660,10 @@ var FAILURE_CODES = {
|
|
|
17660
17660
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
17661
17661
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
17662
17662
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
17663
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
17664
17663
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
17665
17664
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
17666
17665
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
17666
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
17667
17667
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
17668
17668
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
17669
17669
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -17750,6 +17750,7 @@ var FAILURE_CODES = {
|
|
|
17750
17750
|
CHROMIUM_ELECTRON_EXITED_BEFORE_READY: "CHROMIUM_ELECTRON_EXITED_BEFORE_READY",
|
|
17751
17751
|
KEYBOARD_KEY_UNSUPPORTED: "KEYBOARD_KEY_UNSUPPORTED",
|
|
17752
17752
|
KEYBOARD_CHARACTER_UNSUPPORTED: "KEYBOARD_CHARACTER_UNSUPPORTED",
|
|
17753
|
+
SECRET_PLACEHOLDER_UNKNOWN: "SECRET_PLACEHOLDER_UNKNOWN",
|
|
17753
17754
|
SCREENSHOT_DIFF_INPUT_INVALID: "SCREENSHOT_DIFF_INPUT_INVALID",
|
|
17754
17755
|
BOOT_DEVICE_TARGET_SELECTION_INVALID: "BOOT_DEVICE_TARGET_SELECTION_INVALID",
|
|
17755
17756
|
BOOT_IOS_UNSUPPORTED_HOST: "BOOT_IOS_UNSUPPORTED_HOST",
|
|
@@ -18981,6 +18982,14 @@ var DEFAULT_DELAY_MS = 1400;
|
|
|
18981
18982
|
function autoScreenshotEnabled(options) {
|
|
18982
18983
|
return !isFlagEnabled("disable-auto-screenshot", options);
|
|
18983
18984
|
}
|
|
18985
|
+
var SECRET_PLACEHOLDER_MARKER = "{{secret:";
|
|
18986
|
+
function containsSecretPlaceholder(args) {
|
|
18987
|
+
try {
|
|
18988
|
+
return JSON.stringify(args)?.includes(SECRET_PLACEHOLDER_MARKER) ?? false;
|
|
18989
|
+
} catch {
|
|
18990
|
+
return true;
|
|
18991
|
+
}
|
|
18992
|
+
}
|
|
18984
18993
|
function getUdidFromArgs(args) {
|
|
18985
18994
|
if (args && typeof args === "object" && "udid" in args && typeof args.udid === "string") {
|
|
18986
18995
|
return args.udid;
|
|
@@ -19209,7 +19218,15 @@ async function startMcpServer(options) {
|
|
|
19209
19218
|
content = await toMcpContent(result, outputHint, ctx, params.arguments);
|
|
19210
19219
|
}
|
|
19211
19220
|
const udid = getUdidFromArgs(params.arguments);
|
|
19212
|
-
if (autoScreenshotOn && udid && shouldAutoScreenshot(params.name)) {
|
|
19221
|
+
if (autoScreenshotOn && udid && shouldAutoScreenshot(params.name) && containsSecretPlaceholder(params.arguments)) {
|
|
19222
|
+
content = [
|
|
19223
|
+
...content,
|
|
19224
|
+
{
|
|
19225
|
+
type: "text",
|
|
19226
|
+
text: "Auto-screenshot skipped: the input contains a {{secret:\u2026}} placeholder, and a screenshot of this screen could reveal the typed secret. Submit or navigate away first, then verify the resulting screen as usual."
|
|
19227
|
+
}
|
|
19228
|
+
];
|
|
19229
|
+
} else if (autoScreenshotOn && udid && shouldAutoScreenshot(params.name)) {
|
|
19213
19230
|
const maxWaitMs = getAutoScreenshotDelayMs(params.name);
|
|
19214
19231
|
if (maxWaitMs > 0) {
|
|
19215
19232
|
try {
|
package/dist/tool-server.cjs
CHANGED
|
@@ -314,10 +314,10 @@ var init_failure_codes = __esm({
|
|
|
314
314
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
315
315
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
316
316
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
317
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
318
317
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
319
318
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
320
319
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
320
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
321
321
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
322
322
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
323
323
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -404,6 +404,7 @@ var init_failure_codes = __esm({
|
|
|
404
404
|
CHROMIUM_ELECTRON_EXITED_BEFORE_READY: "CHROMIUM_ELECTRON_EXITED_BEFORE_READY",
|
|
405
405
|
KEYBOARD_KEY_UNSUPPORTED: "KEYBOARD_KEY_UNSUPPORTED",
|
|
406
406
|
KEYBOARD_CHARACTER_UNSUPPORTED: "KEYBOARD_CHARACTER_UNSUPPORTED",
|
|
407
|
+
SECRET_PLACEHOLDER_UNKNOWN: "SECRET_PLACEHOLDER_UNKNOWN",
|
|
407
408
|
SCREENSHOT_DIFF_INPUT_INVALID: "SCREENSHOT_DIFF_INPUT_INVALID",
|
|
408
409
|
BOOT_DEVICE_TARGET_SELECTION_INVALID: "BOOT_DEVICE_TARGET_SELECTION_INVALID",
|
|
409
410
|
BOOT_IOS_UNSUPPORTED_HOST: "BOOT_IOS_UNSUPPORTED_HOST",
|
|
@@ -114406,6 +114407,8 @@ var CDPClient = class {
|
|
|
114406
114407
|
nextId = 1;
|
|
114407
114408
|
pending = /* @__PURE__ */ new Map();
|
|
114408
114409
|
pendingBindings = /* @__PURE__ */ new Map();
|
|
114410
|
+
/** Set by addBinding when the runtime ACKs the command but installs nothing. */
|
|
114411
|
+
bindingUnavailable = false;
|
|
114409
114412
|
scripts = /* @__PURE__ */ new Map();
|
|
114410
114413
|
enabledDomains = /* @__PURE__ */ new Set();
|
|
114411
114414
|
wsUrl;
|
|
@@ -114538,6 +114541,8 @@ var CDPClient = class {
|
|
|
114538
114541
|
}
|
|
114539
114542
|
async addBinding(name) {
|
|
114540
114543
|
await this.send("Runtime.addBinding", { name });
|
|
114544
|
+
const probe3 = await this.evaluate(`typeof ${name}`).catch(() => void 0);
|
|
114545
|
+
this.bindingUnavailable = probe3 === "undefined";
|
|
114541
114546
|
}
|
|
114542
114547
|
/**
|
|
114543
114548
|
* Inject a script that will push a result via the binding using a unique requestId.
|
|
@@ -114546,6 +114551,19 @@ var CDPClient = class {
|
|
|
114546
114551
|
evaluateWithBinding(expression, requestId, options) {
|
|
114547
114552
|
const id = requestId ?? crypto3.randomUUID();
|
|
114548
114553
|
const timeout = options?.timeout ?? DEFAULT_TIMEOUT_MS2;
|
|
114554
|
+
if (this.bindingUnavailable) {
|
|
114555
|
+
return Promise.reject(
|
|
114556
|
+
new FailureError(
|
|
114557
|
+
"This JS runtime acknowledges Runtime.addBinding but never installs the binding (legacy Hermes, React Native <= 0.72), so it cannot deliver a result over the binding channel. Tools that read the React tree this way are unavailable here; use `describe` to read on-screen structure.",
|
|
114558
|
+
{
|
|
114559
|
+
error_code: FAILURE_CODES.DEBUGGER_CDP_BINDING_UNAVAILABLE,
|
|
114560
|
+
failure_stage: "debugger_cdp_binding",
|
|
114561
|
+
failure_area: "tool_server",
|
|
114562
|
+
error_kind: "unsupported"
|
|
114563
|
+
}
|
|
114564
|
+
)
|
|
114565
|
+
);
|
|
114566
|
+
}
|
|
114549
114567
|
return new Promise((resolve7, reject) => {
|
|
114550
114568
|
const timer = setTimeout(() => {
|
|
114551
114569
|
this.pendingBindings.delete(id);
|
|
@@ -121982,12 +122000,14 @@ init_src();
|
|
|
121982
122000
|
|
|
121983
122001
|
// ../tool-server/src/utils/debugger/discovery.ts
|
|
121984
122002
|
init_src();
|
|
122003
|
+
var DECOY_VM = "don't use";
|
|
121985
122004
|
async function discoverMetro(port) {
|
|
121986
|
-
|
|
121987
|
-
|
|
121988
|
-
|
|
122005
|
+
let statusRes;
|
|
122006
|
+
try {
|
|
122007
|
+
statusRes = await fetch(`http://localhost:${port}/status`);
|
|
122008
|
+
} catch (err) {
|
|
121989
122009
|
throw new FailureError(
|
|
121990
|
-
`Metro at port ${port} is not running (got: ${
|
|
122010
|
+
`Metro at port ${port} is not running (got: ${err instanceof Error ? err.message : String(err)})`,
|
|
121991
122011
|
{
|
|
121992
122012
|
error_code: FAILURE_CODES.DEBUGGER_METRO_NOT_RUNNING,
|
|
121993
122013
|
failure_stage: "debugger_discover_metro_status",
|
|
@@ -121996,21 +122016,25 @@ async function discoverMetro(port) {
|
|
|
121996
122016
|
}
|
|
121997
122017
|
);
|
|
121998
122018
|
}
|
|
121999
|
-
const
|
|
122000
|
-
if (!
|
|
122019
|
+
const statusText = await statusRes.text();
|
|
122020
|
+
if (!statusText.includes("packager-status:running")) {
|
|
122001
122021
|
throw new FailureError(
|
|
122002
|
-
`Metro at port ${port}
|
|
122022
|
+
`Metro at port ${port} is not running (got: ${statusText.slice(0, 100)})`,
|
|
122003
122023
|
{
|
|
122004
|
-
error_code: FAILURE_CODES.
|
|
122005
|
-
failure_stage: "
|
|
122024
|
+
error_code: FAILURE_CODES.DEBUGGER_METRO_NOT_RUNNING,
|
|
122025
|
+
failure_stage: "debugger_discover_metro_status",
|
|
122006
122026
|
failure_area: "tool_server",
|
|
122007
122027
|
error_kind: "network"
|
|
122008
122028
|
}
|
|
122009
122029
|
);
|
|
122010
122030
|
}
|
|
122031
|
+
const projectRoot = statusRes.headers.get("X-React-Native-Project-Root") ?? "";
|
|
122011
122032
|
const listRes = await fetch(`http://localhost:${port}/json/list`);
|
|
122012
|
-
const
|
|
122013
|
-
|
|
122033
|
+
const parsed = await listRes.json().catch(() => null);
|
|
122034
|
+
const targets = (Array.isArray(parsed) ? parsed : []).filter(
|
|
122035
|
+
(t) => t?.vm !== DECOY_VM
|
|
122036
|
+
);
|
|
122037
|
+
if (!targets.length) {
|
|
122014
122038
|
throw new FailureError(
|
|
122015
122039
|
`Metro at port ${port} has no CDP targets \u2014 is a React Native app connected?`,
|
|
122016
122040
|
{
|
|
@@ -122025,8 +122049,19 @@ async function discoverMetro(port) {
|
|
|
122025
122049
|
}
|
|
122026
122050
|
|
|
122027
122051
|
// ../tool-server/src/utils/debugger/target-selection.ts
|
|
122052
|
+
function deviceKey(target) {
|
|
122053
|
+
const logicalId = target.reactNative?.logicalDeviceId;
|
|
122054
|
+
if (logicalId) return logicalId;
|
|
122055
|
+
try {
|
|
122056
|
+
const device = new URL(target.webSocketDebuggerUrl).searchParams.get("device");
|
|
122057
|
+
if (device) return `device=${device}`;
|
|
122058
|
+
} catch {
|
|
122059
|
+
}
|
|
122060
|
+
return target.deviceName;
|
|
122061
|
+
}
|
|
122028
122062
|
function selectTarget(targets, port, options) {
|
|
122029
|
-
|
|
122063
|
+
const pool = targets;
|
|
122064
|
+
let candidates = pool;
|
|
122030
122065
|
if (typeof options?.deviceId === "string" && options.deviceId) {
|
|
122031
122066
|
const deviceId = options.deviceId;
|
|
122032
122067
|
const filtered = candidates.filter((t) => t.reactNative?.logicalDeviceId === deviceId);
|
|
@@ -122034,16 +122069,21 @@ function selectTarget(targets, port, options) {
|
|
|
122034
122069
|
candidates = filtered;
|
|
122035
122070
|
} else {
|
|
122036
122071
|
const distinctDevices = /* @__PURE__ */ new Map();
|
|
122037
|
-
for (const t of
|
|
122038
|
-
const
|
|
122039
|
-
if (
|
|
122040
|
-
distinctDevices.set(
|
|
122072
|
+
for (const t of pool) {
|
|
122073
|
+
const key = deviceKey(t);
|
|
122074
|
+
if (key && !distinctDevices.has(key)) {
|
|
122075
|
+
distinctDevices.set(key, {
|
|
122076
|
+
name: t.deviceName,
|
|
122077
|
+
logicalId: t.reactNative?.logicalDeviceId
|
|
122078
|
+
});
|
|
122041
122079
|
}
|
|
122042
122080
|
}
|
|
122043
122081
|
if (distinctDevices.size > 1) {
|
|
122044
|
-
const listed = [...distinctDevices.
|
|
122082
|
+
const listed = [...distinctDevices.values()].map(
|
|
122083
|
+
(d) => d.logicalId ? `${d.name ?? "unknown"} (${d.logicalId})` : `${d.name ?? "unknown"} (legacy inspector \u2014 no logicalDeviceId)`
|
|
122084
|
+
).join(", ");
|
|
122045
122085
|
throw new Error(
|
|
122046
|
-
`No debugger target matches device_id "${deviceId}". ${distinctDevices.size} devices are connected to Metro on port ${port}: ${listed}.
|
|
122086
|
+
`No debugger target matches device_id "${deviceId}". ${distinctDevices.size} devices are connected to Metro on port ${port}: ${listed}. Re-target with the logicalDeviceId in parentheses \u2014 that is what debugger-connect returns and what subsequent debugger-* calls must pass. A legacy-inspector device (RN 0.72 / Vega) reports none and cannot be singled out of a shared Metro: give it its own Metro port.`
|
|
122047
122087
|
);
|
|
122048
122088
|
}
|
|
122049
122089
|
}
|
|
@@ -122184,6 +122224,7 @@ function parseNode(line) {
|
|
|
122184
122224
|
// ../tool-server/src/utils/debugger/source-resolver.ts
|
|
122185
122225
|
var ALLOWED_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"]);
|
|
122186
122226
|
function isInsideProject(absFile, projectRoot) {
|
|
122227
|
+
if (!projectRoot) return false;
|
|
122187
122228
|
const resolvedRoot = path17.resolve(projectRoot);
|
|
122188
122229
|
const resolvedFile = path17.resolve(absFile);
|
|
122189
122230
|
const rel = path17.relative(resolvedRoot, resolvedFile);
|
|
@@ -122226,7 +122267,7 @@ function createSourceResolver(port, projectRoot) {
|
|
|
122226
122267
|
const frame = data.stack?.[0];
|
|
122227
122268
|
if (!frame?.file) return null;
|
|
122228
122269
|
if (/^https?:\/\//.test(frame.file)) return null;
|
|
122229
|
-
const relFile = frame.file.replace(projectRoot + "/", "").replace(/^\/+/, "");
|
|
122270
|
+
const relFile = projectRoot ? frame.file.replace(projectRoot + "/", "").replace(/^\/+/, "") : frame.file;
|
|
122230
122271
|
return {
|
|
122231
122272
|
file: relFile,
|
|
122232
122273
|
line: frame.lineNumber ?? 0,
|
|
@@ -122245,6 +122286,7 @@ function createSourceResolver(port, projectRoot) {
|
|
|
122245
122286
|
},
|
|
122246
122287
|
symbolicate: symbolicateFrame,
|
|
122247
122288
|
async readSourceFragment(location, contextLines = 3) {
|
|
122289
|
+
if (!projectRoot) return null;
|
|
122248
122290
|
try {
|
|
122249
122291
|
const absPath = path17.isAbsolute(location.file) ? path17.resolve(location.file) : path17.resolve(projectRoot, location.file);
|
|
122250
122292
|
const realRoot = await fs18.realpath(projectRoot);
|
|
@@ -126687,6 +126729,54 @@ Fails if the device backend is not reachable \u2014 the simulator-server for iOS
|
|
|
126687
126729
|
// ../tool-server/src/tools/keyboard/index.ts
|
|
126688
126730
|
init_zod();
|
|
126689
126731
|
|
|
126732
|
+
// ../tool-server/src/utils/secrets.ts
|
|
126733
|
+
init_src();
|
|
126734
|
+
var SECRET_ENV_PREFIX = "ARGENT_SECRET_";
|
|
126735
|
+
var SECRET_PLACEHOLDER_MARKER = "{{secret:";
|
|
126736
|
+
var PLACEHOLDER_RE = /\{\{secret:([A-Za-z_][A-Za-z0-9_]*)\}\}/g;
|
|
126737
|
+
function availableSecretNames(env = process.env) {
|
|
126738
|
+
return Object.keys(env).filter((k) => k.startsWith(SECRET_ENV_PREFIX) && env[k] !== void 0).map((k) => k.slice(SECRET_ENV_PREFIX.length)).sort();
|
|
126739
|
+
}
|
|
126740
|
+
var REDUNDANT_PREFIX_RE = /^argent_secret_/i;
|
|
126741
|
+
function resolveSecretPlaceholders(text, env = process.env) {
|
|
126742
|
+
const secrets = [];
|
|
126743
|
+
const resolved = text.replace(PLACEHOLDER_RE, (placeholder, rawName) => {
|
|
126744
|
+
let name = rawName;
|
|
126745
|
+
let value = env[SECRET_ENV_PREFIX + name];
|
|
126746
|
+
if (value === void 0 && REDUNDANT_PREFIX_RE.test(name)) {
|
|
126747
|
+
name = name.replace(REDUNDANT_PREFIX_RE, "");
|
|
126748
|
+
value = env[SECRET_ENV_PREFIX + name];
|
|
126749
|
+
}
|
|
126750
|
+
if (value === void 0) {
|
|
126751
|
+
const names = availableSecretNames(env);
|
|
126752
|
+
throw new InvalidToolInputError(
|
|
126753
|
+
`Unknown secret "${rawName}" \u2014 no ${SECRET_ENV_PREFIX}${name} environment variable is set on the machine running the tool-server. Available secrets: ${names.length ? names.join(", ") : "(none)"}. To make it available, ask the user to export ${SECRET_ENV_PREFIX}${name} in the tool-server's environment \u2014 never ask the user for the secret value itself.`,
|
|
126754
|
+
{
|
|
126755
|
+
error_code: FAILURE_CODES.SECRET_PLACEHOLDER_UNKNOWN,
|
|
126756
|
+
failure_stage: "secret_placeholder_resolution",
|
|
126757
|
+
error_kind: "validation"
|
|
126758
|
+
}
|
|
126759
|
+
);
|
|
126760
|
+
}
|
|
126761
|
+
if (!secrets.some((s) => s.name === name)) secrets.push({ name, value });
|
|
126762
|
+
return value;
|
|
126763
|
+
});
|
|
126764
|
+
return { text: resolved, secrets };
|
|
126765
|
+
}
|
|
126766
|
+
function redactSecretsFromError(err, secrets) {
|
|
126767
|
+
const scrub = (s) => secrets.reduce(
|
|
126768
|
+
(acc, { name, value }) => value ? acc.split(value).join(`${SECRET_PLACEHOLDER_MARKER}${name}}}`) : acc,
|
|
126769
|
+
s
|
|
126770
|
+
);
|
|
126771
|
+
if (err instanceof Error) {
|
|
126772
|
+
err.message = scrub(err.message);
|
|
126773
|
+
if (err.stack) err.stack = scrub(err.stack);
|
|
126774
|
+
return err;
|
|
126775
|
+
}
|
|
126776
|
+
if (typeof err === "string") return scrub(err);
|
|
126777
|
+
return err;
|
|
126778
|
+
}
|
|
126779
|
+
|
|
126690
126780
|
// ../tool-server/src/tools/keyboard/simulator-server-keys.ts
|
|
126691
126781
|
init_src();
|
|
126692
126782
|
|
|
@@ -127165,7 +127255,9 @@ var zodSchema24 = external_exports.object({
|
|
|
127165
127255
|
udid: external_exports.string().describe(
|
|
127166
127256
|
"Target device id from `list-devices` (iOS UDID, Android serial, Vega serial, or Chromium id)."
|
|
127167
127257
|
),
|
|
127168
|
-
text: external_exports.string().optional().describe(
|
|
127258
|
+
text: external_exports.string().optional().describe(
|
|
127259
|
+
'Text to type character by character. Handles uppercase and common punctuation. To type a credential without its plaintext ever entering your context, use a secret placeholder: `{{secret:<NAME>}}` types the value of the `ARGENT_SECRET_<NAME>` environment variable set on the machine running the tool-server \u2014 e.g. text: "{{secret:APP_PASSWORD}}" types the value of `ARGENT_SECRET_APP_PASSWORD`. Only env vars with the `ARGENT_SECRET_` prefix are resolvable. Placeholders can be embedded in longer text and are never echoed back resolved. If the secret you need is not set, ask the user to export it as `ARGENT_SECRET_<NAME>` and restart the session \u2014 NEVER ask the user to paste the secret value into the conversation.'
|
|
127260
|
+
),
|
|
127169
127261
|
key: external_exports.string().optional().describe(
|
|
127170
127262
|
"Named key to press: enter, escape, backspace, tab, space, arrow-up, arrow-down, arrow-left, arrow-right, f1\u2013f12. When combined with `text`, the key is pressed AFTER the text is typed (so text + enter types and submits). Not supported on TV targets \u2014 move focus with `tv-remote` (up/down/left/right) instead."
|
|
127171
127263
|
),
|
|
@@ -127181,12 +127273,21 @@ var capability16 = {
|
|
|
127181
127273
|
vega: { vvd: true }
|
|
127182
127274
|
};
|
|
127183
127275
|
function createKeyboardTool(registry2) {
|
|
127276
|
+
const dispatch = dispatchByPlatform({
|
|
127277
|
+
toolId: "keyboard",
|
|
127278
|
+
capability: capability16,
|
|
127279
|
+
ios: makeIosImpl3(registry2),
|
|
127280
|
+
iosRemote: makeIosRemoteImpl(registry2),
|
|
127281
|
+
android: makeAndroidImpl(registry2),
|
|
127282
|
+
chromium: makeChromiumImpl(registry2),
|
|
127283
|
+
vega: vegaImpl4
|
|
127284
|
+
});
|
|
127184
127285
|
return {
|
|
127185
127286
|
id: "keyboard",
|
|
127186
127287
|
description: `Type text or press special keys on the device (iOS simulator, Android emulator or device, Chromium app, Vega Virtual Device, or Apple TV / Android TV) using keyboard events.
|
|
127187
127288
|
Use when you need to enter text or trigger a named key such as enter, escape, or arrow keys. On Vega and Apple TV / Android TV, prefer the remote tools for D-pad navigation; use keyboard to type into a focused text field (e.g. a search or login box).
|
|
127188
127289
|
Returns { typed: string, keys: number }. Fails if an unsupported key name is provided or the device's input backend is not reachable.
|
|
127189
|
-
- text: types a string (supports uppercase, digits, common punctuation)
|
|
127290
|
+
- text: types a string (supports uppercase, digits, common punctuation). To type a credential, use \`{{secret:<NAME>}}\` \u2014 resolved server-side from the \`ARGENT_SECRET_<NAME>\` env var (prefix mandatory; \`{{secret:APP_PASSWORD}}\` \u2194 \`ARGENT_SECRET_APP_PASSWORD\`), so the plaintext never enters agent context; the result echoes the placeholder, not the value, and the after-typing auto-screenshot is skipped.
|
|
127190
127291
|
- key: presses a single named key (enter, escape, backspace, tab, arrow-up/down/left/right, f1\u2013f12) \u2014 NOT supported on TV targets; move focus with \`tv-remote\` instead.
|
|
127191
127292
|
On a TV target (runtimeKind 'tv') only \`text\` applies \u2014 focus a text field first (with \`tv-remote\`), then type into it (injected HID keyboard on Apple TV, \`adb input text\` on Android TV).
|
|
127192
127293
|
Provide text, key, or both \u2014 when both are given, the text is typed first and the key is pressed after it (text + key:"enter" types and submits).`,
|
|
@@ -127197,15 +127298,17 @@ Provide text, key, or both \u2014 when both are given, the text is typed first a
|
|
|
127197
127298
|
// simulator-server, CDP, or Vega adb), since distinguishing a TV target is
|
|
127198
127299
|
// async and a tvOS udid must never resolve simulator-server.
|
|
127199
127300
|
services: () => ({}),
|
|
127200
|
-
execute:
|
|
127201
|
-
|
|
127202
|
-
|
|
127203
|
-
|
|
127204
|
-
|
|
127205
|
-
|
|
127206
|
-
|
|
127207
|
-
|
|
127208
|
-
|
|
127301
|
+
execute: async (services, params, options) => {
|
|
127302
|
+
if (params.text === void 0) return dispatch(services, params, options);
|
|
127303
|
+
const { text, secrets } = resolveSecretPlaceholders(params.text);
|
|
127304
|
+
if (secrets.length === 0) return dispatch(services, params, options);
|
|
127305
|
+
try {
|
|
127306
|
+
const result = await dispatch(services, { ...params, text }, options);
|
|
127307
|
+
return { ...result, typed: params.text };
|
|
127308
|
+
} catch (err) {
|
|
127309
|
+
throw redactSecretsFromError(err, secrets);
|
|
127310
|
+
}
|
|
127311
|
+
}
|
|
127209
127312
|
};
|
|
127210
127313
|
}
|
|
127211
127314
|
|
|
@@ -133622,6 +133725,7 @@ Allowed tools and their args (udid is auto-injected, do NOT include it in args):
|
|
|
133622
133725
|
gesture-rotate: { centerX: number, centerY: number, radius: number, startAngle: number, endAngle: number, durationMs?: number } [ios only]
|
|
133623
133726
|
button: { button: "home"|"back"|"power"|"volumeUp"|"volumeDown"|"appSwitch"|"actionButton" } [ios/android]
|
|
133624
133727
|
keyboard: { text?: string, key?: string, delayMs?: number } (key pressed after text; TV: text only) [ios/android/chromium/vega/tv]
|
|
133728
|
+
text supports {{secret:<NAME>}} placeholders, resolved server-side from ARGENT_SECRET_<NAME> env vars (prefix mandatory) \u2014 credentials never enter agent context
|
|
133625
133729
|
rotate: { orientation: "Portrait"|"LandscapeLeft"|"LandscapeRight"|"PortraitUpsideDown" } [ios/android]
|
|
133626
133730
|
tv-remote: { button: <remote button | array of them>, repeat?: number } [apple tv/android tv/vega]
|
|
133627
133731
|
buttons: up/down/left/right/select/back/home/menu/playPause (+ rewind/fastForward/next/previous/volumeUp/volumeDown/mute \u2014 work on Android TV and Vega; rejected on the Apple TV simulator)
|
|
@@ -133734,7 +133838,8 @@ var DEBUGGER_TOOL_CAPABILITY = {
|
|
|
133734
133838
|
apple: { simulator: true, device: true },
|
|
133735
133839
|
appleRemote: { simulator: true },
|
|
133736
133840
|
android: { emulator: true, device: true, unknown: true },
|
|
133737
|
-
chromium: { app: true }
|
|
133841
|
+
chromium: { app: true },
|
|
133842
|
+
vega: { vvd: true }
|
|
133738
133843
|
};
|
|
133739
133844
|
var RN_ONLY_TOOL_CAPABILITY = {
|
|
133740
133845
|
apple: { simulator: true, device: true },
|
|
@@ -133753,14 +133858,14 @@ function debuggerServiceRef(params) {
|
|
|
133753
133858
|
var zodSchema29 = external_exports.object({
|
|
133754
133859
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium \u2014 its CDP port is encoded in device_id)"),
|
|
133755
133860
|
device_id: external_exports.string().describe(
|
|
133756
|
-
"Device id: iOS simulator UDID, Android logicalDeviceId returned by Metro, or Chromium device id (chromium-cdp-<port>) from list-devices.
|
|
133861
|
+
"Device id: iOS simulator UDID, Android logicalDeviceId returned by Metro, Vega serial (amazon-...), or Chromium device id (chromium-cdp-<port>) from list-devices. When a logicalDeviceId is returned, forward it as device_id to all subsequent debugger-* calls to pin them to this device; when none is returned (Vega), keep passing the id you connected with."
|
|
133757
133862
|
)
|
|
133758
133863
|
});
|
|
133759
133864
|
var debuggerConnectTool = {
|
|
133760
133865
|
id: "debugger-connect",
|
|
133761
133866
|
description: `Connect to a JS runtime CDP debugger.
|
|
133762
|
-
iOS / Android: connects to Metro's CDP endpoint on the given port. Chromium: re-uses the page CDP session opened by boot-device \u2014 port is ignored.
|
|
133763
|
-
Returns connection info including port, projectRoot (empty on Chromium), deviceName, appName, logicalDeviceId, and isNewDebugger. If already connected, returns the existing connection.
|
|
133867
|
+
iOS / Android / Vega: connects to Metro's CDP endpoint on the given port. Chromium: re-uses the page CDP session opened by boot-device \u2014 port is ignored.
|
|
133868
|
+
Returns connection info including port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, logicalDeviceId (absent on Vega), and isNewDebugger. If already connected, returns the existing connection.
|
|
133764
133869
|
Use when starting a debug session or before calling other debugger-* tools. Fails if the runtime is unreachable (Metro down, or Chromium CDP terminated).`,
|
|
133765
133870
|
zodSchema: zodSchema29,
|
|
133766
133871
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
@@ -133786,13 +133891,13 @@ init_zod();
|
|
|
133786
133891
|
var zodSchema30 = external_exports.object({
|
|
133787
133892
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium)"),
|
|
133788
133893
|
device_id: external_exports.string().describe(
|
|
133789
|
-
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, or Chromium device id)."
|
|
133894
|
+
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, Vega serial, or Chromium device id)."
|
|
133790
133895
|
)
|
|
133791
133896
|
});
|
|
133792
133897
|
var debuggerStatusTool = {
|
|
133793
133898
|
id: "debugger-status",
|
|
133794
133899
|
description: `Get JS runtime debugger connection status and diagnostic info.
|
|
133795
|
-
Use when you need to verify connectivity before using other debugger tools. Returns port, projectRoot (empty on Chromium), deviceName, appName, logicalDeviceId, connected flag, loadedScripts count, and sourceMapReady (always true \u2014 waits for pending source maps before returning; no-op on Chromium). Fails if the runtime is unreachable.`,
|
|
133900
|
+
Use when you need to verify connectivity before using other debugger tools. Returns port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, logicalDeviceId (absent on Vega), isNewDebugger (false on the legacy inspector), connected flag, loadedScripts count, and sourceMapReady (always true \u2014 waits for pending source maps before returning; no-op on Chromium). Fails if the runtime is unreachable.`,
|
|
133796
133901
|
zodSchema: zodSchema30,
|
|
133797
133902
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
133798
133903
|
services: (params) => ({
|
|
@@ -133821,13 +133926,13 @@ init_zod();
|
|
|
133821
133926
|
var zodSchema31 = external_exports.object({
|
|
133822
133927
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium)"),
|
|
133823
133928
|
device_id: external_exports.string().describe(
|
|
133824
|
-
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, or Chromium device id)."
|
|
133929
|
+
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, Vega serial, or Chromium device id)."
|
|
133825
133930
|
),
|
|
133826
133931
|
expression: external_exports.string().describe("JavaScript expression to evaluate in the app runtime")
|
|
133827
133932
|
});
|
|
133828
133933
|
var debuggerEvaluateTool = {
|
|
133829
133934
|
id: "debugger-evaluate",
|
|
133830
|
-
description: `Execute arbitrary JavaScript in the app's JS runtime via CDP \u2014 Hermes on iOS / Android, V8 on Chromium.
|
|
133935
|
+
description: `Execute arbitrary JavaScript in the app's JS runtime via CDP \u2014 Hermes on iOS / Android / Vega, V8 on Chromium.
|
|
133831
133936
|
Returns the evaluation result as a JSON-serializable value, along with deviceName, appName, and logicalDeviceId for context. Use when you need to read app state, call app functions, or test logic at runtime. The result is serialized by value, so cyclic objects (many RN runtime values \u2014 fiber nodes, navigation refs, global \u2014 are cyclic) fail with a serialization error rather than returning silently. Fails if the expression throws or the runtime is not connected.`,
|
|
133832
133937
|
zodSchema: zodSchema31,
|
|
133833
133938
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
@@ -135311,13 +135416,13 @@ init_zod();
|
|
|
135311
135416
|
var zodSchema35 = external_exports.object({
|
|
135312
135417
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium)"),
|
|
135313
135418
|
device_id: external_exports.string().describe(
|
|
135314
|
-
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, or Chromium device id)."
|
|
135419
|
+
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, Vega serial, or Chromium device id)."
|
|
135315
135420
|
)
|
|
135316
135421
|
});
|
|
135317
135422
|
var debuggerLogRegistryTool = {
|
|
135318
135423
|
id: "debugger-log-registry",
|
|
135319
135424
|
description: `Get a summary of all console logs captured from the app's JS runtime.
|
|
135320
|
-
Returns the log file path, entry counts by level, and message clusters (grouped by similarity). Works against Hermes (iOS / Android) and V8 (Chromium).
|
|
135425
|
+
Returns the log file path, entry counts by level, and message clusters (grouped by similarity). Works against Hermes (iOS / Android / Vega) and V8 (Chromium).
|
|
135321
135426
|
Use when investigating warnings, errors, or unexpected output \u2014 call this first for an overview, then read the returned file for details. Returns empty stats if no log data has been captured yet.`,
|
|
135322
135427
|
zodSchema: zodSchema35,
|
|
135323
135428
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
@@ -135409,7 +135514,7 @@ var networkLogsTool = {
|
|
|
135409
135514
|
description: `Retrieve captured network (HTTP) requests from the running app.
|
|
135410
135515
|
Returns a paginated list of requests with method, URL, status, resource type, size, and duration.
|
|
135411
135516
|
Each entry includes a requestId that can be passed to view-network-request-details for full details.
|
|
135412
|
-
On React Native (iOS/Android) interception is injected into the JS runtime \u2014 it captures fetch() calls. On Chromium it reads the browser's native CDP Network domain (the active tab; all request types).
|
|
135517
|
+
On React Native (iOS / Android / Vega) interception is injected into the JS runtime \u2014 it captures fetch() calls. On Chromium it reads the browser's native CDP Network domain (the active tab; all request types).
|
|
135413
135518
|
Use when inspecting outbound HTTP traffic or debugging API calls in the running app.
|
|
135414
135519
|
Fails if the app is not connected (RN) or the device is not reachable (Chromium).`,
|
|
135415
135520
|
zodSchema: zodSchema36,
|
package/package.json
CHANGED
package/rules/argent.md
CHANGED
|
@@ -119,7 +119,7 @@ Prompt keywords: permission, grant, deny, revoke, reset permission, privacy, cam
|
|
|
119
119
|
|
|
120
120
|
TV INTERACTION (APPLE TV / ANDROID TV / FIRE TV)
|
|
121
121
|
Skill: `argent-tv-interact`
|
|
122
|
-
When: Any TV target — a `list-devices` entry with `runtimeKind: "tv"` (Apple TV simulator or Android TV emulator) or `platform:"vega"` / `kind:"vvd"` (Amazon Fire TV / VVD), or the user mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV. A TV UI is focus-driven, not touch-driven: drive it with `describe` (read focus) + `tv-remote` (D-pad presses) + `keyboard` (type); `gesture-*` tools do NOT apply. Covers booting the target, app lifecycle, focus navigation, typing, screenshots, and (Vega) VVD lifecycle + Fast Refresh.
|
|
122
|
+
When: Any TV target — a `list-devices` entry with `runtimeKind: "tv"` (Apple TV simulator or Android TV emulator) or `platform:"vega"` / `kind:"vvd"` (Amazon Fire TV / VVD), or the user mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV. A TV UI is focus-driven, not touch-driven: drive it with `describe` (read focus) + `tv-remote` (D-pad presses) + `keyboard` (type); `gesture-*` tools do NOT apply. Covers booting the target, app lifecycle, focus navigation, typing, screenshots, and (Vega) VVD lifecycle + Fast Refresh + JS-runtime debugging (evaluate, console logs, network inspector).
|
|
123
123
|
Prompt keywords: apple tv, tvos, android tv, leanback, vega, fire tv, vvd, d-pad
|
|
124
124
|
|
|
125
125
|
SCREENSHOT DIFF & VISUAL REGRESSION
|
|
@@ -60,6 +60,8 @@ For a custom poll interval or bundleId, drop to an explicit `- tool: await-ui-el
|
|
|
60
60
|
|
|
61
61
|
`type` presses Enter after typing to commit the value and dismiss the keyboard, so it can't cover later targets. For a chained form whose fields feed one explicit submit — e.g. email then password then a `tap: "Log in"` — set `submit: false` on the intermediate fields so a premature Enter doesn't fire the form early: `type: { into: password, text: "hunter2", submit: false }`.
|
|
62
62
|
|
|
63
|
+
Never record a real credential into a flow — the YAML is committed to the repo. Use a secret placeholder instead: `type: { into: password, text: "{{secret:APP_PASSWORD}}" }`. The placeholder is stored verbatim (the YAML stays secret-free) and is resolved at run time by the tool-server from the `ARGENT_SECRET_APP_PASSWORD` environment variable — including agent-less `argent flow run` in CI, where the variable comes from the job's secrets.
|
|
64
|
+
|
|
63
65
|
`scroll-to` takes an optional `direction` (`up` | `down` | `left` | `right`, default `down` — so the common case is just `- scroll-to: <selector>`) and optionally a `within: <selector>` that anchors the scroll inside a specific container — required to drive a **nested** scroller (e.g. a horizontal carousel inside a vertical list), since the device can't be asked which container to scroll. It scrolls in bounded momentum-free increments, re-checks after each, and stops if a scroll reveals nothing new (end of the container). `tap`/`type` do **not** scroll — add a `scroll-to` before any target that may be off-screen. It's a no-op when the target is already visible, so a defensive `scroll-to` costs nothing on replay and keeps the flow working on smaller screens.
|
|
64
66
|
|
|
65
67
|
### TV targets (Vega)
|
|
@@ -171,6 +171,18 @@ Values: `home`, `back`, `power`, `volumeUp`, `volumeDown`, `appSwitch`, `actionB
|
|
|
171
171
|
|
|
172
172
|
Special keys: `enter`, `escape`, `backspace`, `tab`, `space`, `arrow-up`, `arrow-down`, `arrow-left`, `arrow-right`, `f1`–`f12`. Optional: `"delayMs": 100` between keystrokes (default 50ms) — applies to the iOS simulator and Chromium; it is ignored on Android phones/tablets (typed via `adb input text`, no per-key cadence), on Vega, and on TV targets.
|
|
173
173
|
|
|
174
|
+
**Typing secrets.** To enter a credential without its plaintext ever entering your context, transcript, or logs, use a secret placeholder in `text` (works in `keyboard`, `paste`, `run-sequence` keyboard steps, and flow `type` steps):
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{ "udid": "<UDID>", "text": "{{secret:APP_PASSWORD}}", "key": "enter" }
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The placeholder is resolved on the machine running the tool-server from the `ARGENT_SECRET_<NAME>` environment variable (here `ARGENT_SECRET_APP_PASSWORD`) — the CI-native pattern: expose the secret under that prefix in the environment that starts the tool-server. Rules:
|
|
181
|
+
|
|
182
|
+
- The result echoes the placeholder, never the value. An unknown name fails with the list of available secret _names_.
|
|
183
|
+
- The auto-screenshot after the call is skipped so the typed value cannot re-enter your context as pixels. Do **not** `describe` or `screenshot` a non-secure field you just filled with a secret — submit or navigate away first, then verify the resulting screen.
|
|
184
|
+
- Only `ARGENT_SECRET_*` variables are resolvable; never ask the user to paste a secret value into the conversation — ask them to export the env var instead.
|
|
185
|
+
|
|
174
186
|
### rotate — Change orientation
|
|
175
187
|
|
|
176
188
|
```json
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: argent-metro-debugger
|
|
3
|
-
description: Debug a JS runtime via CDP using argent debugger tools. Primary path is React Native via Metro (iOS / Android); a subset of the tools (debugger-connect, debugger-status, debugger-evaluate, debugger-log-registry) also drive a Chromium (CDP) app's renderer (an Electron app, or any Chromium browser exposing CDP) through the same surface. Use when connecting to the runtime, inspecting React components, reading console logs, or evaluating JavaScript.
|
|
3
|
+
description: Debug a JS runtime via CDP using argent debugger tools. Primary path is React Native via Metro (iOS / Android / Vega); a subset of the tools (debugger-connect, debugger-status, debugger-evaluate, debugger-log-registry) also drive a Chromium (CDP) app's renderer (an Electron app, or any Chromium browser exposing CDP) through the same surface. Use when connecting to the runtime, inspecting React components, reading console logs, or evaluating JavaScript.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
## 1. Prerequisites
|
|
7
7
|
|
|
8
8
|
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`.
|
|
9
9
|
|
|
10
|
+
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.
|
|
11
|
+
|
|
10
12
|
For **Chromium (CDP)**: requires a Chromium/CDP app already available — an Electron app booted via `boot-device` with `electronAppPath`, or any Chromium browser exposing a CDP port (auto-discovered by `list-devices` on `9222` / `ARGENT_CHROMIUM_PORTS`). The debugger re-uses the page CDP session — `port` is ignored, `device_id` is the `chromium-cdp-<port>` value from `list-devices` / `boot-device`. Only `debugger-connect`, `debugger-status`, `debugger-evaluate`, `debugger-log-registry`, `view-network-logs`, and `view-network-request-details` work on Chromium (the latter two read the browser's native CDP Network recording for the active tab instead of the Metro-injected `fetch` interceptor); `debugger-component-tree`, `debugger-reload-metro`, `debugger-inspect-element`, and the `react-profiler-*` / `profiler-*` tools are RN-only and reject Chromium at the capability gate with `Tool 'X' is not supported on chromium app`.
|
|
11
13
|
|
|
12
14
|
### Android: reverse port for Metro
|
|
@@ -21,16 +23,16 @@ adb -s <serial> reverse tcp:8081 tcp:8081
|
|
|
21
23
|
|
|
22
24
|
## 2. Tool Overview
|
|
23
25
|
|
|
24
|
-
All tools accept `port` (default 8081) AND `device_id` (the iOS Simulator UDID
|
|
26
|
+
All tools accept `port` (default 8081) AND `device_id` (the iOS Simulator UDID, Android serial, or Vega serial — a.k.a. `logicalDeviceId`, the CDP-reported id that matches the device). Vega's legacy inspector reports no `logicalDeviceId`, so there keep passing the serial. Always make sure you target the correct app on the correct device.
|
|
25
27
|
|
|
26
28
|
One Metro port can serve multiple connected devices (e.g. two simulators on `localhost:8081`, or an iOS simulator alongside an Android emulator with `adb reverse` set up). `device_id` pins every debugger/network/profiler call to a specific device so sessions do not collide.
|
|
27
29
|
|
|
28
30
|
### Connect & diagnostics
|
|
29
31
|
|
|
30
|
-
| Tool | Purpose
|
|
31
|
-
| ------------------ |
|
|
32
|
-
| `debugger-connect` | Connect to the JS runtime's CDP (Metro on iOS / Android; the page CDP session on Chromium). Returns port, projectRoot (empty on Chromium), deviceName, appName, `logicalDeviceId
|
|
33
|
-
| `debugger-status` | Like connect + loadedScripts, enabledDomains, sourceMapReady (no-op on Chromium). **Use to diagnose.**
|
|
32
|
+
| Tool | Purpose |
|
|
33
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| `debugger-connect` | Connect to the JS runtime's CDP (Metro on iOS / Android / Vega; the page CDP session on Chromium). Returns port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, `logicalDeviceId` (absent on Vega), isNewDebugger, connected. When a `logicalDeviceId` comes back, use it as the `device_id` for every subsequent debugger call. |
|
|
35
|
+
| `debugger-status` | Like connect + loadedScripts, enabledDomains, sourceMapReady (no-op on Chromium). **Use to diagnose.** |
|
|
34
36
|
|
|
35
37
|
### Reload & recovery
|
|
36
38
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
When a debugger tool fails, use **`debugger-status`** first to diagnose. Then match the error or situation below and act as specified. Do not retry the same failing tool repeatedly without following the recovery steps.
|
|
4
4
|
|
|
5
|
-
| Scenario | Error or situation | What to do
|
|
6
|
-
| ---------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
7
|
-
| **Metro not running** | Error contains: `Metro at port 8081 is not running (got: ...)` | **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status`. If you cannot determine the project root, ask the user. |
|
|
8
|
-
| **
|
|
9
|
-
| **App not connected** | Error contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status`. Do **not** use `debugger-reload-metro` to fix this — it also requires at least one target.
|
|
10
|
-
| **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls.
|
|
5
|
+
| Scenario | Error or situation | What to do |
|
|
6
|
+
| ---------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Metro not running** | Error contains: `Metro at port 8081 is not running (got: ...)` | **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status`. If you cannot determine the project root, ask the user. A non-Metro server occupying the port lands here too — the `got:` text shows what answered. |
|
|
8
|
+
| **No source locations** | `projectRoot` is `""` and source lookups report no file:line | Not a failure. Legacy Metro (RN 0.72 and older, e.g. Vega) sends no `X-React-Native-Project-Root` header, so paths cannot be resolved against a project root. `debugger-evaluate`, console logs and the network inspector work regardless — do not restart Metro to "fix" it. |
|
|
9
|
+
| **App not connected** | Error contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status`. Do **not** use `debugger-reload-metro` to fix this — it also requires at least one target. |
|
|
10
|
+
| **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: argent-tv-interact
|
|
3
|
-
description: Control and inspect TV apps via argent — Apple TV (tvOS), Android TV (leanback), and Amazon Fire TV (Vega). Boot the target, read focus, navigate with the D-pad remote, type, and
|
|
3
|
+
description: Control and inspect TV apps via argent — Apple TV (tvOS), Android TV (leanback), and Amazon Fire TV (Vega). Boot the target, read focus, navigate with the D-pad remote, type, screenshot, and on Vega debug the JS runtime (evaluate, console logs, network inspector). Use when a task targets a TV (runtimeKind "tv", or platform "vega"), or mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV / VVD.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Argent TV (Apple TV + Android TV + Fire TV)
|
|
@@ -58,3 +58,13 @@ Needs a Debug build + Metro running. argent only _connects_ to Metro — start M
|
|
|
58
58
|
|
|
59
59
|
- **Apple TV / Android TV:** use the dev-build deep-links above; `npm start` for Metro.
|
|
60
60
|
- **Vega:** build/install a Debug `.vpkg` (`vega device install-app -p <path>`), `npm start`, `vega device start-port-forwarding --port 8081 --forward false`, then `vega device launch-app -a <appId>`. Confirm `http://localhost:8081/json/list` shows a `Hermes React Native` target; `.tsx` edits then hot-reload.
|
|
61
|
+
|
|
62
|
+
## Debugging the JS runtime (Vega)
|
|
63
|
+
|
|
64
|
+
Once that same Debug build + Metro setup is in place, the JS-runtime tools work on a Vega VVD: `debugger-connect`, `debugger-status`, `debugger-evaluate`, `debugger-log-registry` (console logs), `view-network-logs`, and `view-network-request-details`. See the `argent-metro-debugger` skill.
|
|
65
|
+
|
|
66
|
+
Vega's React Native forks RN 0.72 and serves the legacy Hermes inspector, so three things differ from iOS / Android:
|
|
67
|
+
|
|
68
|
+
- `debugger-component-tree`, `debugger-inspect-element`, `debugger-reload-metro` and the `react-profiler-*` / `profiler-*` tools are **not supported**. Component-tree and inspect-element are hard-blocked: they need `Runtime.addBinding`, which this Hermes acknowledges but never installs. The rest are simply unverified on the legacy inspector. Use `describe` for on-screen structure; with both component tools gated off, component `file:line` tracing has no path on Vega.
|
|
69
|
+
- `debugger-status` reports `isNewDebugger: false`.
|
|
70
|
+
- `projectRoot` is empty (RN 0.72's Metro sends no project-root header), so lookups that resolve paths against the project root return no location.
|