@swmansion/argent 0.22.1-next.1 → 0.22.1-next.3
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-simulator-server.cjs +12 -19
- package/dist/bundled-paths.js +21 -28
- package/dist/bundled-paths.js.map +1 -1
- package/dist/cli-cmds.mjs +28 -46
- package/dist/cli.d.ts +3 -25
- package/dist/cli.js +12 -41
- package/dist/cli.js.map +1 -1
- package/dist/fatal-handlers.js +13 -17
- package/dist/fatal-handlers.js.map +1 -1
- package/dist/installer-help.d.ts +31 -49
- package/dist/installer-help.js +31 -54
- package/dist/installer-help.js.map +1 -1
- package/dist/installer.mjs +63 -120
- package/dist/mcp-server.mjs +16 -30
- package/dist/preview-window/main.cjs +9 -13
- package/dist/tool-server.cjs +518 -713
- package/package.json +1 -1
package/dist/tool-server.cjs
CHANGED
|
@@ -434,12 +434,13 @@ var init_artifacts = __esm({
|
|
|
434
434
|
};
|
|
435
435
|
ArtifactStore = class {
|
|
436
436
|
entries = /* @__PURE__ */ new Map();
|
|
437
|
-
async register(
|
|
438
|
-
const
|
|
439
|
-
const
|
|
437
|
+
async register(opts) {
|
|
438
|
+
const { hostPath, kind } = opts;
|
|
439
|
+
const filename = opts.filename ?? (0, import_node_path.basename)(hostPath);
|
|
440
|
+
const mimeType = opts.mimeType ?? inferMimeType(hostPath);
|
|
440
441
|
let size = 0;
|
|
441
442
|
let mtimeMs;
|
|
442
|
-
let isDirectory2 = opts
|
|
443
|
+
let isDirectory2 = opts.archive === "tar.gz";
|
|
443
444
|
try {
|
|
444
445
|
const st = await (0, import_promises.stat)(hostPath);
|
|
445
446
|
size = st.size;
|
|
@@ -448,10 +449,11 @@ var init_artifacts = __esm({
|
|
|
448
449
|
} catch {
|
|
449
450
|
}
|
|
450
451
|
const id = (0, import_node_crypto.randomUUID)();
|
|
451
|
-
this.entries.set(id, { path: hostPath, filename, mimeType, size, isDirectory: isDirectory2 });
|
|
452
|
+
this.entries.set(id, { path: hostPath, kind, filename, mimeType, size, isDirectory: isDirectory2 });
|
|
452
453
|
const handle = {
|
|
453
454
|
[ARTIFACT_MARKER]: true,
|
|
454
455
|
id,
|
|
456
|
+
kind,
|
|
455
457
|
filename,
|
|
456
458
|
mimeType,
|
|
457
459
|
size,
|
|
@@ -459,7 +461,7 @@ var init_artifacts = __esm({
|
|
|
459
461
|
};
|
|
460
462
|
if (mtimeMs != null) handle.mtimeMs = mtimeMs;
|
|
461
463
|
if (isDirectory2) handle.archive = "tar.gz";
|
|
462
|
-
if (opts
|
|
464
|
+
if (opts.saveDir) handle.saveDir = opts.saveDir;
|
|
463
465
|
return handle;
|
|
464
466
|
}
|
|
465
467
|
get(id) {
|
|
@@ -468,6 +470,7 @@ var init_artifacts = __esm({
|
|
|
468
470
|
list() {
|
|
469
471
|
return [...this.entries.entries()].map(([id, entry]) => ({
|
|
470
472
|
id,
|
|
473
|
+
kind: entry.kind,
|
|
471
474
|
filename: entry.filename,
|
|
472
475
|
mimeType: entry.mimeType,
|
|
473
476
|
size: entry.size,
|
|
@@ -706,15 +709,12 @@ var init_failure_codes = __esm({
|
|
|
706
709
|
NATIVE_PROFILER_SESSION_TORN_DOWN: "NATIVE_PROFILER_SESSION_TORN_DOWN",
|
|
707
710
|
NATIVE_PROFILER_APP_PROCESS_NOT_FOUND: "NATIVE_PROFILER_APP_PROCESS_NOT_FOUND",
|
|
708
711
|
NATIVE_PROFILER_NO_EXPORTED_TRACE: "NATIVE_PROFILER_NO_EXPORTED_TRACE",
|
|
709
|
-
// Android perfetto start
|
|
710
|
-
// failed recording start is classified rather than falling through to the
|
|
711
|
-
// generic tool-execution bucket.
|
|
712
|
+
// Android perfetto start failures, mirroring the iOS xctrace set above.
|
|
712
713
|
NATIVE_PROFILER_PERFETTO_PROCESS_ERROR: "NATIVE_PROFILER_PERFETTO_PROCESS_ERROR",
|
|
713
714
|
NATIVE_PROFILER_PERFETTO_READY_TIMEOUT: "NATIVE_PROFILER_PERFETTO_READY_TIMEOUT",
|
|
714
715
|
NATIVE_PROFILER_PERFETTO_READY_EXITED: "NATIVE_PROFILER_PERFETTO_READY_EXITED",
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
// the step that failed rather than the device family.
|
|
716
|
+
// iOS and Android share one capture path (simulator-server frames into
|
|
717
|
+
// ffmpeg), so these name the failing stage, not the device family.
|
|
718
718
|
SCREEN_RECORDING_FACTORY_OPTIONS_MISSING: "SCREEN_RECORDING_FACTORY_OPTIONS_MISSING",
|
|
719
719
|
SCREEN_RECORDING_WRONG_PLATFORM: "SCREEN_RECORDING_WRONG_PLATFORM",
|
|
720
720
|
SCREEN_RECORDING_ALREADY_ACTIVE: "SCREEN_RECORDING_ALREADY_ACTIVE",
|
|
@@ -16083,22 +16083,19 @@ var init_registry = __esm({
|
|
|
16083
16083
|
init_zod_to_json_schema();
|
|
16084
16084
|
import_node_crypto2 = require("node:crypto");
|
|
16085
16085
|
Registry = class {
|
|
16086
|
-
/** Single map: URN -> ServiceNode (all instances). */
|
|
16087
16086
|
services = /* @__PURE__ */ new Map();
|
|
16088
16087
|
blueprints = /* @__PURE__ */ new Map();
|
|
16089
16088
|
tools = /* @__PURE__ */ new Map();
|
|
16090
16089
|
/**
|
|
16091
|
-
*
|
|
16092
|
-
*
|
|
16093
|
-
*
|
|
16094
|
-
* existing `new Registry()` call sites (tests, non-flag deployments) keep
|
|
16095
|
-
* their previous behavior. The tool-server wires the real `isFlagEnabled`.
|
|
16090
|
+
* Injected so the registry needs no dependency on the flag store; the
|
|
16091
|
+
* tool-server wires the real check. The default enables every flag, so a
|
|
16092
|
+
* plain `new Registry()` (tests, non-flag deployments) gates nothing.
|
|
16096
16093
|
*/
|
|
16097
16094
|
isFlagEnabled;
|
|
16098
16095
|
/**
|
|
16099
|
-
* Host files produced by tools,
|
|
16100
|
-
*
|
|
16101
|
-
* path and the HTTP route
|
|
16096
|
+
* Host files produced by tools, served by the tool-server's `/artifacts/:id`
|
|
16097
|
+
* route. Owned per registry rather than as a module singleton, so the tool
|
|
16098
|
+
* path and the HTTP route see the same store.
|
|
16102
16099
|
*/
|
|
16103
16100
|
artifacts = new ArtifactStore();
|
|
16104
16101
|
events = new TypedEventEmitter();
|
|
@@ -16119,8 +16116,8 @@ var init_registry = __esm({
|
|
|
16119
16116
|
return this.tools.get(id)?.definition;
|
|
16120
16117
|
}
|
|
16121
16118
|
/**
|
|
16122
|
-
* Resolve a service by URN
|
|
16123
|
-
*
|
|
16119
|
+
* Resolve a service by URN, JIT-instantiating from its blueprint on first use.
|
|
16120
|
+
* `options` reach the blueprint factory only on that first instantiation.
|
|
16124
16121
|
*/
|
|
16125
16122
|
resolveService(urn, options) {
|
|
16126
16123
|
return this._resolve(urn, [], options);
|
|
@@ -16237,14 +16234,10 @@ var init_registry = __esm({
|
|
|
16237
16234
|
};
|
|
16238
16235
|
}
|
|
16239
16236
|
/**
|
|
16240
|
-
*
|
|
16241
|
-
*
|
|
16242
|
-
*
|
|
16243
|
-
*
|
|
16244
|
-
*
|
|
16245
|
-
* Only currently-RUNNING nodes are considered: a service that already
|
|
16246
|
-
* errored/torn down during resolution needs no recovery here, and a URN this
|
|
16247
|
-
* tool never resolved must not be touched.
|
|
16237
|
+
* Dispose every service in `refs` whose blueprint calls `error` recoverable, so
|
|
16238
|
+
* the next `resolveService` re-creates it; returns whether anything was
|
|
16239
|
+
* disposed, i.e. whether retrying the tool is worthwhile. Only RUNNING nodes
|
|
16240
|
+
* qualify — one that already errored or tore down needs no recovery.
|
|
16248
16241
|
*/
|
|
16249
16242
|
async _recoverFailedServices(refs, error52) {
|
|
16250
16243
|
let recoveredAny = false;
|
|
@@ -16260,10 +16253,7 @@ var init_registry = __esm({
|
|
|
16260
16253
|
}
|
|
16261
16254
|
return recoveredAny;
|
|
16262
16255
|
}
|
|
16263
|
-
/**
|
|
16264
|
-
* Tear down a single service by URN (and cascade to its dependents).
|
|
16265
|
-
* After disposal the service returns to IDLE and can be re-resolved.
|
|
16266
|
-
*/
|
|
16256
|
+
/** Tear down a service and its dependents; it returns to IDLE and can be re-resolved. */
|
|
16267
16257
|
async disposeService(urn) {
|
|
16268
16258
|
const node = this.services.get(urn);
|
|
16269
16259
|
if (!node) throw new ServiceNotFoundError(urn);
|
|
@@ -16276,7 +16266,6 @@ var init_registry = __esm({
|
|
|
16276
16266
|
}
|
|
16277
16267
|
}
|
|
16278
16268
|
}
|
|
16279
|
-
// ── Private: Resolution ──
|
|
16280
16269
|
_resolve(urn, resolutionPath, options) {
|
|
16281
16270
|
let node = this.services.get(urn);
|
|
16282
16271
|
if (!node) {
|
|
@@ -69925,16 +69914,12 @@ function androidRoots() {
|
|
|
69925
69914
|
function defaultAndroidRoots() {
|
|
69926
69915
|
const home = (0, import_node_os2.homedir)();
|
|
69927
69916
|
const roots = [
|
|
69928
|
-
// Android Studio defaults (the big ones — cover the majority of user
|
|
69929
|
-
// installs that arrive without any env-var setup).
|
|
69930
69917
|
(0, import_node_path3.join)(home, "Library", "Android", "sdk"),
|
|
69931
69918
|
// macOS Android Studio default
|
|
69932
69919
|
(0, import_node_path3.join)(home, "Android", "Sdk"),
|
|
69933
69920
|
// Linux Android Studio default
|
|
69934
|
-
// Common manual install convention. Not picked by any installer but used
|
|
69935
|
-
// often enough in tutorials and Dockerfiles that probing it costs little.
|
|
69936
69921
|
(0, import_node_path3.join)(home, "android-sdk"),
|
|
69937
|
-
//
|
|
69922
|
+
// manual-install convention; no installer picks it
|
|
69938
69923
|
"/opt/android-sdk",
|
|
69939
69924
|
"/usr/lib/android-sdk",
|
|
69940
69925
|
// Debian/Ubuntu `android-sdk` apt package
|
|
@@ -72069,9 +72054,7 @@ var require_min_release_age = __commonJS({
|
|
|
72069
72054
|
var PROBE_TIMEOUT_MS = 3e3;
|
|
72070
72055
|
var OVERRIDE_ENV = "ARGENT_MIN_RELEASE_AGE_DAYS";
|
|
72071
72056
|
var PM_PROBES = {
|
|
72072
|
-
//
|
|
72073
|
-
// npm 11.x builds report `min-release-age=null` even while the policy is
|
|
72074
|
-
// active. Probe `before`, which is what the resolver actually uses.
|
|
72057
|
+
// Probe `before`: that is the effective cutoff npm's resolver applies.
|
|
72075
72058
|
npm: { command: "npm config get before", parse: config_parse_1.parseBeforeAgeMs },
|
|
72076
72059
|
pnpm: {
|
|
72077
72060
|
command: "pnpm config get minimumReleaseAge",
|
|
@@ -92082,14 +92065,12 @@ var CONFIG_SCHEMA = [
|
|
|
92082
92065
|
description: "Whether anonymous opt-out telemetry is enabled (on by default; environment opt-outs like DO_NOT_TRACK are not reflected here \u2014 `argent telemetry status` shows effective consent).",
|
|
92083
92066
|
scopes: ["global"],
|
|
92084
92067
|
parse: asBoolean,
|
|
92085
|
-
// A committed project file must never re-enable telemetry a user disabled
|
|
92086
|
-
// globally, so the more-restrictive (opt-out) value always wins.
|
|
92087
92068
|
merge: "prioritize-restrictive",
|
|
92088
|
-
//
|
|
92089
|
-
//
|
|
92069
|
+
// Opt-out: consent.ts reads an unstored value as enabled, so the config
|
|
92070
|
+
// surface must show the same rather than "(unset)".
|
|
92090
92071
|
default: true,
|
|
92091
|
-
//
|
|
92092
|
-
//
|
|
92072
|
+
// Opt-in/out goes through the dedicated command so the live client is
|
|
92073
|
+
// drained/reset, not just the file rewritten.
|
|
92093
92074
|
manageCommand: "argent telemetry"
|
|
92094
92075
|
},
|
|
92095
92076
|
{
|
|
@@ -92097,8 +92078,6 @@ var CONFIG_SCHEMA = [
|
|
|
92097
92078
|
description: "Coding-agent id remembered by `argent lens` to skip the picker.",
|
|
92098
92079
|
scopes: ["project", "global"],
|
|
92099
92080
|
parse: asString,
|
|
92100
|
-
// A repo can pin the agent its screenshots should use; falls back to the
|
|
92101
|
-
// user's global remembered choice.
|
|
92102
92081
|
merge: "prioritize-local",
|
|
92103
92082
|
example: "claude"
|
|
92104
92083
|
},
|
|
@@ -92107,11 +92086,9 @@ var CONFIG_SCHEMA = [
|
|
|
92107
92086
|
description: "Additional CoreSimulator device-set directories whose simulators argent should see alongside the default set. Absolute paths (or ~/\u2026); relative entries resolve against the project root (project scope) or home (global scope).",
|
|
92108
92087
|
scopes: ["project", "global"],
|
|
92109
92088
|
parse: asStringArray,
|
|
92110
|
-
// Additive
|
|
92111
|
-
//
|
|
92112
|
-
//
|
|
92113
|
-
// `getAdditionalIosDeviceSets` re-implements this union (path resolution
|
|
92114
|
-
// must precede dedup) and guards on the preset staying "union".
|
|
92089
|
+
// Additive rather than shadowing: global baseline first, project extras
|
|
92090
|
+
// after, deduplicated. `getAdditionalIosDeviceSets` re-implements this union
|
|
92091
|
+
// (path resolution must precede dedup) and guards on the preset staying "union".
|
|
92115
92092
|
merge: "union",
|
|
92116
92093
|
example: '["~/DeviceSets/ci"]'
|
|
92117
92094
|
},
|
|
@@ -92120,10 +92097,8 @@ var CONFIG_SCHEMA = [
|
|
|
92120
92097
|
description: "Directory where finished screen recordings (mp4) are saved on the client host. Absolute, `~`-prefixed, or relative to the project root (home dir when not in a project). Unset \u21D2 `.argent/recordings` under the project root.",
|
|
92121
92098
|
scopes: ["project", "global"],
|
|
92122
92099
|
parse: asString,
|
|
92123
|
-
//
|
|
92124
|
-
//
|
|
92125
|
-
// persisted to), so with a remote `argent link` tool-server it is the
|
|
92126
|
-
// *client's* config that decides.
|
|
92100
|
+
// Resolved on the client (the machine the mp4 is persisted to), so with a
|
|
92101
|
+
// remote `argent link` tool-server it is the *client's* config that decides.
|
|
92127
92102
|
merge: "prioritize-local",
|
|
92128
92103
|
example: "~/Movies/argent"
|
|
92129
92104
|
}
|
|
@@ -94850,17 +94825,16 @@ function createExporter(config2) {
|
|
|
94850
94825
|
// The exporter bounds a request with `req.setTimeout()`, which Node only
|
|
94851
94826
|
// arms once the socket is CONNECTED — so a collector whose address drops
|
|
94852
94827
|
// packets (corporate egress filter, dead host behind a firewall) leaves a
|
|
94853
|
-
// socket stuck
|
|
94854
|
-
//
|
|
94855
|
-
//
|
|
94856
|
-
//
|
|
94857
|
-
//
|
|
94828
|
+
// socket stuck connecting that no export deadline can reach, holding the
|
|
94829
|
+
// process open for the OS connect timeout after shutdown() has resolved.
|
|
94830
|
+
// The agent's socket timeout is armed when the socket is CREATED, so it
|
|
94831
|
+
// covers connect too: it fires, the request emits 'timeout', and the
|
|
94832
|
+
// exporter's handler destroys it.
|
|
94858
94833
|
//
|
|
94859
94834
|
// keepAlive is restated because supplying httpAgentOptions at all
|
|
94860
|
-
// replaces the agent the SDK would otherwise build,
|
|
94861
|
-
// keepAlive: true
|
|
94862
|
-
// TCP+TLS handshake for every
|
|
94863
|
-
// request against a loopback collector, versus one socket shared.
|
|
94835
|
+
// replaces the agent the SDK would otherwise build, whose default is
|
|
94836
|
+
// keepAlive: true; without it the long-lived tool-server pays a fresh
|
|
94837
|
+
// TCP+TLS handshake for every batch.
|
|
94864
94838
|
httpAgentOptions: { timeout: EXPORT_TIMEOUT_MS, keepAlive: true }
|
|
94865
94839
|
});
|
|
94866
94840
|
} finally {
|
|
@@ -95079,7 +95053,6 @@ var ALLOWED = {
|
|
|
95079
95053
|
install_mode: INSTALL_MODE
|
|
95080
95054
|
},
|
|
95081
95055
|
"installation:global_install_decision": {
|
|
95082
|
-
// `from_tar` is intentionally absent; the installer skips that dev path.
|
|
95083
95056
|
decision: oneOf(["install", "cancel", "already_installed"])
|
|
95084
95057
|
},
|
|
95085
95058
|
"installation:update_decision": {
|
|
@@ -95158,9 +95131,8 @@ var ALLOWED = {
|
|
|
95158
95131
|
tool_invocation_id: UUID,
|
|
95159
95132
|
platform: PLATFORM,
|
|
95160
95133
|
duration_ms: DURATION_MS,
|
|
95161
|
-
//
|
|
95162
|
-
//
|
|
95163
|
-
// voids anything longer or with a non-identifier element.
|
|
95134
|
+
// Emit side sends only names declared in the tool's zod shape, capped at 16
|
|
95135
|
+
// because arrayOf voids the whole array once it is longer.
|
|
95164
95136
|
invalid_params: arrayOf(matches(/^[a-z][a-z0-9_]{0,63}$/i, 64), 16),
|
|
95165
95137
|
...FAILURE_SIGNAL2,
|
|
95166
95138
|
...AI_TELEMETRY
|
|
@@ -95692,7 +95664,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
95692
95664
|
var SESSION_ID = (0, import_node_crypto3.randomUUID)();
|
|
95693
95665
|
function readCliVersion() {
|
|
95694
95666
|
if (true) {
|
|
95695
|
-
return "0.22.1-next.
|
|
95667
|
+
return "0.22.1-next.3";
|
|
95696
95668
|
}
|
|
95697
95669
|
return "0.0.0";
|
|
95698
95670
|
}
|
|
@@ -96094,15 +96066,11 @@ function resolveHostFingerprint() {
|
|
|
96094
96066
|
const out = (0, import_node_child_process.execFileSync)(simulatorServerBinaryPath(), ["fingerprint"], {
|
|
96095
96067
|
encoding: "utf8",
|
|
96096
96068
|
timeout: FINGERPRINT_TIMEOUT_MS,
|
|
96097
|
-
//
|
|
96098
|
-
//
|
|
96099
|
-
// SIGKILL can't be trapped, so the timeout is a genuine bound here.
|
|
96069
|
+
// SIGKILL, not the default SIGTERM: a binary that ignores SIGTERM would
|
|
96070
|
+
// otherwise block the (synchronous) event loop past the cap forever.
|
|
96100
96071
|
killSignal: "SIGKILL",
|
|
96101
|
-
// Cap captured stdout (same limit as the async variant): a binary streaming
|
|
96102
|
-
// output is SIGKILL'd at this cap rather than filling Node's 1 MiB default.
|
|
96103
96072
|
maxBuffer: FINGERPRINT_MAX_BUFFER,
|
|
96104
|
-
// Ignore stderr so
|
|
96105
|
-
// caller's stderr; stdout (index 1) is captured as the return value.
|
|
96073
|
+
// Ignore stderr so the binary's diagnostics don't pollute the caller's.
|
|
96106
96074
|
stdio: ["ignore", "pipe", "ignore"]
|
|
96107
96075
|
}).trim();
|
|
96108
96076
|
return out.length > 0 ? out : null;
|
|
@@ -96751,11 +96719,10 @@ function describeVegaFailure(args, err, kindOverride) {
|
|
|
96751
96719
|
error_code: FAILURE_CODES.VEGA_CLI_COMMAND_FAILED,
|
|
96752
96720
|
failure_stage: "vega_cli_command",
|
|
96753
96721
|
failure_area: "tool_server",
|
|
96754
|
-
// A
|
|
96755
|
-
//
|
|
96756
|
-
//
|
|
96757
|
-
//
|
|
96758
|
-
// timeout. Those callers pass an explicit kind; everything else uses the heuristic.
|
|
96722
|
+
// A forced reap shapes the error with killed=true so the message reads correctly, but
|
|
96723
|
+
// only a genuine *timeout* may classify as `error_kind: "timeout"` — listVegaDevices
|
|
96724
|
+
// keys its skip-the-recovery-call decision off that, so an overflow must not
|
|
96725
|
+
// masquerade as a wedged agent. Those callers pass an explicit kind.
|
|
96759
96726
|
error_kind: kindOverride ?? (e.killed || e.signal ? "timeout" : "subprocess"),
|
|
96760
96727
|
...subprocessFailureMetadata(err, "vega")
|
|
96761
96728
|
};
|
|
@@ -96800,7 +96767,7 @@ async function runVega(args, options = {}) {
|
|
|
96800
96767
|
};
|
|
96801
96768
|
const rejectTimeout = () => (
|
|
96802
96769
|
// Shape like an execFile timeout rejection (killed=true) so it classifies as a
|
|
96803
|
-
// timeout downstream
|
|
96770
|
+
// timeout downstream.
|
|
96804
96771
|
settle(
|
|
96805
96772
|
() => reject(
|
|
96806
96773
|
describeVegaFailure(
|
|
@@ -96823,9 +96790,9 @@ async function runVega(args, options = {}) {
|
|
|
96823
96790
|
new Error(`vega ${args.join(" ")} output exceeded ${maxOutputBytes} bytes`),
|
|
96824
96791
|
{ killed: true, signal: VEGA_KILL_SIGNAL, stdout, stderr }
|
|
96825
96792
|
),
|
|
96826
|
-
// Force "subprocess": an overflow is a misbehaving child, not a wedged
|
|
96827
|
-
//
|
|
96828
|
-
//
|
|
96793
|
+
// Force "subprocess": an overflow is a misbehaving child, not a wedged agent.
|
|
96794
|
+
// The killed=true shape would otherwise classify as "timeout" and wrongly
|
|
96795
|
+
// suppress the listVegaDevices recovery call.
|
|
96829
96796
|
"subprocess"
|
|
96830
96797
|
)
|
|
96831
96798
|
)
|
|
@@ -97452,7 +97419,6 @@ async function run(args, options) {
|
|
|
97452
97419
|
timeout: options?.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
97453
97420
|
maxBuffer: 16 * 1024 * 1024,
|
|
97454
97421
|
encoding: "utf8",
|
|
97455
|
-
// sim-remote pipes stdin through to pbcopy etc.
|
|
97456
97422
|
input: options?.stdin
|
|
97457
97423
|
});
|
|
97458
97424
|
return { stdout: typeof stdout === "string" ? stdout : stdout.toString("utf8") };
|
|
@@ -97744,9 +97710,9 @@ async function readProcessLaunchState(pid) {
|
|
|
97744
97710
|
({ stdout } = await execFileAsync8(PS_BIN, ["eww", "-p", String(pid), "-o", "etime=,command="], {
|
|
97745
97711
|
encoding: "utf8",
|
|
97746
97712
|
timeout: PS_PROBE_TIMEOUT_MS,
|
|
97747
|
-
// Matches the other `ps` probes (vega-process.ts)
|
|
97713
|
+
// Matches the other `ps` probes (vega-process.ts): an environment can run
|
|
97748
97714
|
// to `kern.argmax` (1 MiB), exactly Node's default cap, so the default
|
|
97749
|
-
// would ENOBUFS on a maximal one
|
|
97715
|
+
// would ENOBUFS on a maximal one.
|
|
97750
97716
|
maxBuffer: 16 * 1024 * 1024
|
|
97751
97717
|
}));
|
|
97752
97718
|
} catch (err) {
|
|
@@ -97842,17 +97808,16 @@ var remoteIosHost = {
|
|
|
97842
97808
|
const { stdout } = await simctlSpawn(udid, { args: ["launchctl", "list"] });
|
|
97843
97809
|
return parseUIKitApplicationBundleIds(stdout);
|
|
97844
97810
|
},
|
|
97845
|
-
// App processes live on the orchestrator,
|
|
97846
|
-
//
|
|
97847
|
-
//
|
|
97811
|
+
// App processes live on the orchestrator, out of reach of the local process
|
|
97812
|
+
// table, so only running-ness is answerable; the null process keeps callers on
|
|
97813
|
+
// their no-evidence path.
|
|
97848
97814
|
async inspectRunningApp(udid, bundleId) {
|
|
97849
97815
|
const { stdout } = await simctlSpawn(udid, { args: ["launchctl", "list"] });
|
|
97850
97816
|
return { running: parseUIKitApplicationJobs(stdout).has(bundleId), process: null };
|
|
97851
97817
|
},
|
|
97852
|
-
//
|
|
97853
|
-
//
|
|
97854
|
-
//
|
|
97855
|
-
// sims; if it isn't, describe will still surface a useful error.
|
|
97818
|
+
// The same accessibility `defaults write`s the local host performs, routed
|
|
97819
|
+
// through the remote generic spawn. The entitlement-bypass plist is assumed
|
|
97820
|
+
// active on cloud sims.
|
|
97856
97821
|
async bootstrapAx(udid) {
|
|
97857
97822
|
for (const flag of ACCESSIBILITY_DEFAULT_FLAGS) {
|
|
97858
97823
|
await simctlSpawn(udid, {
|
|
@@ -98263,13 +98228,11 @@ var NotImplementedOnPlatformError = class extends Error {
|
|
|
98263
98228
|
};
|
|
98264
98229
|
var InvalidToolInputError = class extends Error {
|
|
98265
98230
|
/**
|
|
98266
|
-
* @param signal
|
|
98267
|
-
*
|
|
98268
|
-
*
|
|
98269
|
-
*
|
|
98270
|
-
*
|
|
98271
|
-
* (from #420) — and keep both the granular telemetry bucket AND the 400
|
|
98272
|
-
* status. Defaults to the generic `TOOL_INPUT_INVALID` / validation signal.
|
|
98231
|
+
* @param signal Telemetry-signal overrides. The HTTP 400 mapping keys off the
|
|
98232
|
+
* error *class* (see http.ts), not the `error_code`, so a caller can pass a
|
|
98233
|
+
* more granular code (e.g. the keyboard backends'
|
|
98234
|
+
* `KEYBOARD_CHARACTER_UNSUPPORTED`) and keep both the granular telemetry
|
|
98235
|
+
* bucket and the 400 status.
|
|
98273
98236
|
*/
|
|
98274
98237
|
constructor(message, signal) {
|
|
98275
98238
|
super(message);
|
|
@@ -108486,21 +108449,13 @@ var simulatorServerBlueprint = {
|
|
|
108486
108449
|
return `${SIMULATOR_SERVER_NAMESPACE}:${device.id}`;
|
|
108487
108450
|
},
|
|
108488
108451
|
/**
|
|
108489
|
-
* A
|
|
108490
|
-
*
|
|
108491
|
-
*
|
|
108492
|
-
*
|
|
108493
|
-
*
|
|
108494
|
-
*
|
|
108495
|
-
*
|
|
108496
|
-
*
|
|
108497
|
-
* Treat a connection-refused failure as proof the instance is dead so the
|
|
108498
|
-
* registry disposes it (killing the wedged process) and re-spawns a fresh
|
|
108499
|
-
* simulator-server on the next call. Scoped to connection-refused only:
|
|
108500
|
-
* ECONNREFUSED means the request never reached the server, so retrying can't
|
|
108501
|
-
* double-apply a gesture. Timeouts and resets are deliberately excluded — the
|
|
108502
|
-
* request there may have taken effect, and a hung-but-listening server is a
|
|
108503
|
-
* different failure that respawning wouldn't fix.
|
|
108452
|
+
* A wedged simulator-server (sim un-booted, native server crashed) can keep its
|
|
108453
|
+
* process alive while no longer listening, so it never emits `exit`, the
|
|
108454
|
+
* registry's teardown never fires, and every later call gets `ECONNREFUSED`
|
|
108455
|
+
* until a human runs `stop-simulator-server`. Calling that recoverable makes
|
|
108456
|
+
* the registry dispose the instance and re-spawn. Scoped to connection-refused
|
|
108457
|
+
* only: the request provably never reached the server, so a retry can't
|
|
108458
|
+
* double-apply a gesture, whereas a timeout or reset may have taken effect.
|
|
108504
108459
|
*/
|
|
108505
108460
|
recoverable(error52) {
|
|
108506
108461
|
return getFailureSignal(error52)?.network_failure === "connection_refused";
|
|
@@ -108779,17 +108734,10 @@ var CDPClient = class {
|
|
|
108779
108734
|
});
|
|
108780
108735
|
}
|
|
108781
108736
|
/**
|
|
108782
|
-
* Re-point this client at
|
|
108783
|
-
*
|
|
108784
|
-
*
|
|
108785
|
-
*
|
|
108786
|
-
* (`server.cdp`, `api.cdp`, and every closure that captured it) automatically
|
|
108787
|
-
* target the new tab after the swap — no rewiring needed. Callers that wire
|
|
108788
|
-
* `disconnected` to teardown/termination therefore do not see a tab switch as
|
|
108789
|
-
* a device loss.
|
|
108790
|
-
*
|
|
108791
|
-
* In-flight requests are rejected and per-connection state (enabled domains,
|
|
108792
|
-
* parsed scripts) is reset — the new target starts fresh, so the caller must
|
|
108737
|
+
* Re-point this client at another CDP target (e.g. a new browser tab) without
|
|
108738
|
+
* emitting `disconnected`, which callers treat as a device loss. Object
|
|
108739
|
+
* identity is preserved, so existing references need no rewiring. In-flight
|
|
108740
|
+
* requests are rejected and per-connection state is reset, so the caller must
|
|
108793
108741
|
* re-enable any domains it needs.
|
|
108794
108742
|
*/
|
|
108795
108743
|
async reconnect(newWsUrl) {
|
|
@@ -108825,10 +108773,9 @@ var CDPClient = class {
|
|
|
108825
108773
|
const timer = setTimeout(() => {
|
|
108826
108774
|
this.pending.delete(id);
|
|
108827
108775
|
reject(
|
|
108828
|
-
// The message carries its own recovery guidance
|
|
108829
|
-
//
|
|
108830
|
-
//
|
|
108831
|
-
// retry-looping (each loop iteration waits out this full timeout).
|
|
108776
|
+
// The message carries its own recovery guidance: agents otherwise read
|
|
108777
|
+
// this state as transient and retry-loop, each pass waiting out the
|
|
108778
|
+
// full timeout.
|
|
108832
108779
|
new FailureError(
|
|
108833
108780
|
`CDP request ${method} (id=${id}) timed out \u2014 the runtime accepted the connection but did not answer; it may be frozen, or paused at a breakpoint. debugger-status can still report "connected" in this state (the socket is open). Do not retry in a loop \u2014 restart the app, then reconnect and retry once.`,
|
|
108834
108781
|
{
|
|
@@ -108875,8 +108822,8 @@ var CDPClient = class {
|
|
|
108875
108822
|
this.bindingUnavailable = probe3 === "undefined";
|
|
108876
108823
|
}
|
|
108877
108824
|
/**
|
|
108878
|
-
* Inject a script that
|
|
108879
|
-
*
|
|
108825
|
+
* Inject a script that pushes its result over the binding tagged with a
|
|
108826
|
+
* requestId; resolves with the payload of the matching binding call.
|
|
108880
108827
|
*/
|
|
108881
108828
|
evaluateWithBinding(expression, requestId, options) {
|
|
108882
108829
|
const id = requestId ?? crypto3.randomUUID();
|
|
@@ -109074,9 +109021,8 @@ async function browserWebSocketUrl(port, signal) {
|
|
|
109074
109021
|
throw new FailureError(
|
|
109075
109022
|
`Chromium CDP on port ${port} did not report a browser webSocketDebuggerUrl in /json/version.`,
|
|
109076
109023
|
{
|
|
109077
|
-
//
|
|
109078
|
-
//
|
|
109079
|
-
// conflate "reached but malformed" with a genuinely down debug port.
|
|
109024
|
+
// Reached but malformed — telemetry must not conflate this with a
|
|
109025
|
+
// genuinely down debug port.
|
|
109080
109026
|
error_code: FAILURE_CODES.CHROMIUM_CDP_INVALID_RESPONSE,
|
|
109081
109027
|
failure_stage: "chromium_cdp_browser_ws",
|
|
109082
109028
|
failure_area: "tool_server",
|
|
@@ -109431,19 +109377,14 @@ var ScreencastManager = class {
|
|
|
109431
109377
|
fps;
|
|
109432
109378
|
activeCount = 0;
|
|
109433
109379
|
currentOpts = null;
|
|
109434
|
-
// The in-flight Page.startScreencast
|
|
109435
|
-
//
|
|
109436
|
-
//
|
|
109437
|
-
// when no start is in flight (idle, or a live session already running).
|
|
109380
|
+
// The first subscriber's in-flight Page.startScreencast, published so joiners
|
|
109381
|
+
// await the SAME start instead of assuming a live session and stranding
|
|
109382
|
+
// themselves on a frame-less stream if it fails.
|
|
109438
109383
|
startInFlight = null;
|
|
109439
109384
|
lastFrame = null;
|
|
109440
109385
|
cdpListenerInstalled = false;
|
|
109441
|
-
/**
|
|
109442
|
-
*
|
|
109443
|
-
* Chromium hasn't pushed a frame yet. Exposed so single-shot consumers
|
|
109444
|
-
* (preview overlay, snapshot debug tool) can grab the last frame without
|
|
109445
|
-
* starting their own session.
|
|
109446
|
-
*/
|
|
109386
|
+
/** Never cleared on stop, so single-shot consumers can read a frame without
|
|
109387
|
+
* starting their own session. */
|
|
109447
109388
|
getLastFrame() {
|
|
109448
109389
|
return this.lastFrame;
|
|
109449
109390
|
}
|
|
@@ -109571,7 +109512,7 @@ function warnSharpMissingOnce(reason) {
|
|
|
109571
109512
|
var DOWNSCALER_TO_KERNEL = {
|
|
109572
109513
|
lanczos3: "lanczos3",
|
|
109573
109514
|
box: "mitchell",
|
|
109574
|
-
// sharp
|
|
109515
|
+
// sharp has no box kernel
|
|
109575
109516
|
bilinear: "lanczos2",
|
|
109576
109517
|
nearest: "nearest"
|
|
109577
109518
|
};
|
|
@@ -109786,12 +109727,8 @@ function createTabsManager(deps) {
|
|
|
109786
109727
|
error_code: FAILURE_CODES.CHROMIUM_TAB_OPEN_FAILED,
|
|
109787
109728
|
failure_stage: "chromium_tab_open",
|
|
109788
109729
|
failure_area: "tool_server",
|
|
109789
|
-
//
|
|
109790
|
-
//
|
|
109791
|
-
// classified `unknown` like the other CDP-command failures in this
|
|
109792
|
-
// server (CHROMIUM_SCREENSHOT_FAILED, the viewport/storage evals).
|
|
109793
|
-
// `network`/`invalid_response` is reserved for the HTTP /json
|
|
109794
|
-
// discovery layer, which has a genuine fetch transport.
|
|
109730
|
+
// A malformed CDP response, not a transport failure:
|
|
109731
|
+
// `network`/`invalid_response` is reserved for the HTTP /json layer.
|
|
109795
109732
|
error_kind: "unknown"
|
|
109796
109733
|
});
|
|
109797
109734
|
return out.targetId;
|
|
@@ -109885,9 +109822,8 @@ function createNetworkManager(deps) {
|
|
|
109885
109822
|
rec.resourceType = params.type ?? rec.resourceType;
|
|
109886
109823
|
break;
|
|
109887
109824
|
}
|
|
109888
|
-
// The *ExtraInfo events carry
|
|
109889
|
-
//
|
|
109890
|
-
// before the base event, so `record()` creates the entry if needed.
|
|
109825
|
+
// The *ExtraInfo events carry on-the-wire headers (Authorization, Set-Cookie, …)
|
|
109826
|
+
// the base events omit, and may arrive before them — hence `record()`, not `get()`.
|
|
109891
109827
|
case "Network.requestWillBeSentExtraInfo": {
|
|
109892
109828
|
const h = params.headers;
|
|
109893
109829
|
if (h) {
|
|
@@ -110554,11 +110490,9 @@ Booted/ready devices are listed first. Platforms whose CLI is unavailable are si
|
|
|
110554
110490
|
withDeadline(listIosSimulators(), [], "ios"),
|
|
110555
110491
|
withDeadline(listRemoteIosSimulators(), [], "ios-remote"),
|
|
110556
110492
|
withDeadline(
|
|
110557
|
-
//
|
|
110558
|
-
//
|
|
110559
|
-
//
|
|
110560
|
-
// bound (NOT boot-device's 30s default) so the Android branch self-bounds
|
|
110561
|
-
// under BRANCH_DEADLINE_MS — see ADB_DEVICES_TIMEOUT_MS.
|
|
110493
|
+
// list-devices is the one caller that surfaces TV vs mobile, so it pays for
|
|
110494
|
+
// runtimeKind's extra per-device probe. The explicit `adb devices` bound
|
|
110495
|
+
// (not runAdb's 30s default) keeps this branch under BRANCH_DEADLINE_MS.
|
|
110562
110496
|
listAndroidDevices({ runtimeKind: true, devicesTimeoutMs: ADB_DEVICES_TIMEOUT_MS }).catch(
|
|
110563
110497
|
() => []
|
|
110564
110498
|
),
|
|
@@ -110617,39 +110551,33 @@ var VariantProposalStore = class {
|
|
|
110617
110551
|
consumed = false;
|
|
110618
110552
|
globalComment = "";
|
|
110619
110553
|
/**
|
|
110620
|
-
*
|
|
110621
|
-
*
|
|
110622
|
-
* — so it is intentionally NOT cleared by `reset()`.
|
|
110554
|
+
* Last non-empty udid an agent passed to `propose_variant`. One device spans
|
|
110555
|
+
* many rounds, so `reset()` intentionally does NOT clear it.
|
|
110623
110556
|
*/
|
|
110624
110557
|
device = null;
|
|
110625
110558
|
/**
|
|
110626
|
-
* True while an `argent lens` CLI session owns the window.
|
|
110627
|
-
*
|
|
110628
|
-
* many propose→submit rounds, like `device`.
|
|
110559
|
+
* True while an `argent lens` CLI session owns the window. A session spans many
|
|
110560
|
+
* propose→submit rounds, so `reset()` deliberately does NOT clear it.
|
|
110629
110561
|
*/
|
|
110630
110562
|
cliSession = false;
|
|
110631
110563
|
/**
|
|
110632
110564
|
* The agent choices a CLI Lens session offers (when more than one is
|
|
110633
|
-
* installed) and the one the human picked
|
|
110634
|
-
*
|
|
110635
|
-
*
|
|
110636
|
-
* `cliSession`, deliberately NOT cleared by `reset()`.
|
|
110565
|
+
* installed) and the one the human picked. `argent lens` passes the choices in
|
|
110566
|
+
* on begin and learns the pick over `/preview/lens-stream`. Like `cliSession`,
|
|
110567
|
+
* deliberately NOT cleared by `reset()`.
|
|
110637
110568
|
*/
|
|
110638
110569
|
lensAgents = [];
|
|
110639
110570
|
lensAgentChoice = null;
|
|
110640
110571
|
/**
|
|
110641
|
-
* Whether the human
|
|
110642
|
-
*
|
|
110643
|
-
*
|
|
110644
|
-
* picker. Tied to `lensAgentChoice`; reset with it.
|
|
110572
|
+
* Whether the human ticked the picker's "Remember this choice". `argent lens`
|
|
110573
|
+
* reads it alongside the pick and persists it to `~/.argent/config.json` so
|
|
110574
|
+
* later runs skip the picker. Tied to `lensAgentChoice`; reset with it.
|
|
110645
110575
|
*/
|
|
110646
110576
|
lensAgentRemember = false;
|
|
110647
110577
|
/**
|
|
110648
|
-
* Devices
|
|
110649
|
-
*
|
|
110650
|
-
*
|
|
110651
|
-
* session ends (`takeOwnedDevices`), without ever touching a device the user
|
|
110652
|
-
* had already booted. Like `cliSession`, NOT cleared by `reset()`.
|
|
110578
|
+
* Devices `POST /preview/boot` started because they were not already running,
|
|
110579
|
+
* so session-end teardown (`takeOwnedDevices`) shuts down only those and never
|
|
110580
|
+
* one the user had booted. Like `cliSession`, NOT cleared by `reset()`.
|
|
110653
110581
|
*/
|
|
110654
110582
|
ownedDevices = /* @__PURE__ */ new Set();
|
|
110655
110583
|
submitted = [];
|
|
@@ -110660,15 +110588,12 @@ var VariantProposalStore = class {
|
|
|
110660
110588
|
/** Frozen result of the current round once the user submits. */
|
|
110661
110589
|
lastOutcome = null;
|
|
110662
110590
|
/**
|
|
110663
|
-
* Completed outcomes that finished with no
|
|
110664
|
-
*
|
|
110665
|
-
*
|
|
110666
|
-
*
|
|
110667
|
-
*
|
|
110668
|
-
*
|
|
110669
|
-
* drained first by `awaitSelection`, oldest first. Without it, a human's
|
|
110670
|
-
* already-submitted selection is destroyed the moment the next
|
|
110671
|
-
* `propose_variant` call rolls the round out from under it.
|
|
110591
|
+
* Completed outcomes that finished with no await parked to receive them, in
|
|
110592
|
+
* completion order. `autoRollIfCompleted` rolls on the next `propose_variant`
|
|
110593
|
+
* whether or not the outcome was retrieved, so this queue — unlike
|
|
110594
|
+
* `lastOutcome`/`completed`/`consumed`, which describe only the CURRENT round —
|
|
110595
|
+
* survives `reset()` and is drained first by `awaitSelection`. Without it a
|
|
110596
|
+
* roll destroys a human's already-submitted selection.
|
|
110672
110597
|
*/
|
|
110673
110598
|
pendingOutcomes = [];
|
|
110674
110599
|
/** Begin a fresh round, discarding the previous one's proposals/selections. */
|
|
@@ -110704,15 +110629,12 @@ var VariantProposalStore = class {
|
|
|
110704
110629
|
this.events.emit("changed");
|
|
110705
110630
|
}
|
|
110706
110631
|
/**
|
|
110707
|
-
* Emit the drop-off signal for a round still staged
|
|
110708
|
-
*
|
|
110709
|
-
* tool-server calls this
|
|
110710
|
-
*
|
|
110711
|
-
*
|
|
110712
|
-
*
|
|
110713
|
-
* so a completed or empty round is a no-op — which also settles any await still
|
|
110714
|
-
* parked on the dying round rather than letting it hang. Returns whether an
|
|
110715
|
-
* abandonment was emitted (for the caller's logging / tests).
|
|
110632
|
+
* Emit the drop-off signal for a round still staged at process shutdown — "the
|
|
110633
|
+
* server died mid-review" — so it is counted instead of vanishing into the
|
|
110634
|
+
* unattributable opens-minus-completions residue. The tool-server calls this
|
|
110635
|
+
* before its final telemetry drain. Routes through reset(), the single
|
|
110636
|
+
* abandonment choke point, which also settles any await parked on the dying
|
|
110637
|
+
* round. Returns whether an abandonment was emitted.
|
|
110716
110638
|
*/
|
|
110717
110639
|
flushAbandonedRound() {
|
|
110718
110640
|
if (this.completed || this.proposals.length === 0) return false;
|
|
@@ -110725,13 +110647,12 @@ var VariantProposalStore = class {
|
|
|
110725
110647
|
return p?.variants.find((v) => v.id === variantId) ?? null;
|
|
110726
110648
|
}
|
|
110727
110649
|
/**
|
|
110728
|
-
*
|
|
110729
|
-
*
|
|
110730
|
-
*
|
|
110731
|
-
*
|
|
110732
|
-
*
|
|
110733
|
-
*
|
|
110734
|
-
* when nothing is parked.
|
|
110650
|
+
* Settle every parked waiter with a `pending` outcome pointing at the browser
|
|
110651
|
+
* fallback URL when the native preview window could not launch (e.g. the
|
|
110652
|
+
* optional `electron` dependency is absent on a headless/CI host), rather than
|
|
110653
|
+
* letting the await run its full timeout with no window and no feedback. The
|
|
110654
|
+
* proposals stay live, so the agent can relay the URL and re-await. No-ops when
|
|
110655
|
+
* nothing is parked.
|
|
110735
110656
|
*/
|
|
110736
110657
|
notifyWindowUnavailable(reason, url2) {
|
|
110737
110658
|
const toSettle = this.waitersList.filter((w) => !w.settled);
|
|
@@ -110812,10 +110733,10 @@ var VariantProposalStore = class {
|
|
|
110812
110733
|
}
|
|
110813
110734
|
/**
|
|
110814
110735
|
* Begin or end a CLI-driven Lens session (`argent lens`), optionally offering
|
|
110815
|
-
*
|
|
110816
|
-
*
|
|
110817
|
-
*
|
|
110818
|
-
*
|
|
110736
|
+
* agent choices for the window's picker. `cliSessionChanged` fires only on an
|
|
110737
|
+
* actual begin/end transition (so the window opens/closes once), but the
|
|
110738
|
+
* choices are refreshed on every begin — a re-begin from a fresh `argent lens`
|
|
110739
|
+
* must replace stale ones.
|
|
110819
110740
|
*/
|
|
110820
110741
|
setCliSession(active, agents = []) {
|
|
110821
110742
|
const transitioned = this.cliSession !== active;
|
|
@@ -110833,8 +110754,7 @@ var VariantProposalStore = class {
|
|
|
110833
110754
|
}
|
|
110834
110755
|
this.events.emit("changed");
|
|
110835
110756
|
}
|
|
110836
|
-
/** Record the agent the human picked
|
|
110837
|
-
* asked to remember it. */
|
|
110757
|
+
/** Record the agent the human picked, and whether they asked to remember it. */
|
|
110838
110758
|
setLensAgentChoice(id, remember = false) {
|
|
110839
110759
|
this.lensAgentChoice = id;
|
|
110840
110760
|
this.lensAgentRemember = remember;
|
|
@@ -110857,18 +110777,16 @@ var VariantProposalStore = class {
|
|
|
110857
110777
|
if (id.trim()) this.ownedDevices.add(id.trim());
|
|
110858
110778
|
}
|
|
110859
110779
|
/**
|
|
110860
|
-
* Whether Lens booted this device itself
|
|
110861
|
-
*
|
|
110862
|
-
*
|
|
110863
|
-
* read a single device's ownership. Kept as a non-mutating way for tests to
|
|
110864
|
-
* assert ownership without draining it via `takeOwnedDevices`.
|
|
110780
|
+
* Whether Lens booted this device itself. Test-only: production manages
|
|
110781
|
+
* ownership through `markDeviceOwned` / `releaseDevice` / `takeOwnedDevices`,
|
|
110782
|
+
* so this exists as a non-mutating way to assert it without draining the set.
|
|
110865
110783
|
*/
|
|
110866
110784
|
isDeviceOwned(id) {
|
|
110867
110785
|
return this.ownedDevices.has(id.trim());
|
|
110868
110786
|
}
|
|
110869
110787
|
/**
|
|
110870
|
-
* Drop a single owned device — e.g. the user shut it down
|
|
110871
|
-
*
|
|
110788
|
+
* Drop a single owned device — e.g. the user shut it down from the preview
|
|
110789
|
+
* window, so session-end teardown must not try to kill it again.
|
|
110872
110790
|
*/
|
|
110873
110791
|
releaseDevice(id) {
|
|
110874
110792
|
this.ownedDevices.delete(id.trim());
|
|
@@ -110881,22 +110799,21 @@ var VariantProposalStore = class {
|
|
|
110881
110799
|
}
|
|
110882
110800
|
/**
|
|
110883
110801
|
* The frozen outcome of the last submitted round, or null if nothing has been
|
|
110884
|
-
* submitted since the last reset.
|
|
110885
|
-
* `argent lens` watcher can format the user's
|
|
110886
|
-
*
|
|
110802
|
+
* submitted since the last reset. Served over `/preview/outcome` and
|
|
110803
|
+
* `/preview/lens-stream` so the `argent lens` watcher can format the user's
|
|
110804
|
+
* feedback and type it into the spawned agent terminal.
|
|
110887
110805
|
*/
|
|
110888
110806
|
getLastOutcome() {
|
|
110889
110807
|
return this.lastOutcome;
|
|
110890
110808
|
}
|
|
110891
|
-
/** Called by the preview UI when the human
|
|
110809
|
+
/** Called by the preview UI when the human submits their picks. */
|
|
110892
110810
|
submitSelection(input) {
|
|
110893
110811
|
if (typeof input.round === "number" && input.round !== this.round) {
|
|
110894
110812
|
return { ok: true, round: this.round, resolved: 0, stale: true };
|
|
110895
110813
|
}
|
|
110896
110814
|
const cleanAnnotations = (input.annotations ?? []).filter((a) => a && typeof a.comment === "string" && a.comment.trim()).slice(0, MAX_ANNOTATIONS).map((a) => ({
|
|
110897
110815
|
target: String(a.target ?? "").slice(0, 200) || "(element)",
|
|
110898
|
-
//
|
|
110899
|
-
// comment, was previously ingested uncapped.
|
|
110816
|
+
// Caller-supplied and, unlike the comment, otherwise ingested uncapped.
|
|
110900
110817
|
match: {
|
|
110901
110818
|
by: a.match?.by ?? "text",
|
|
110902
110819
|
value: String(a.match?.value ?? "").slice(0, MAX_MATCH_VALUE_LENGTH)
|
|
@@ -111012,14 +110929,12 @@ var VariantProposalStore = class {
|
|
|
111012
110929
|
};
|
|
111013
110930
|
}
|
|
111014
110931
|
/**
|
|
111015
|
-
* Block until the user submits a selection for the current round
|
|
111016
|
-
*
|
|
111017
|
-
*
|
|
111018
|
-
*
|
|
111019
|
-
*
|
|
111020
|
-
*
|
|
111021
|
-
* await parked on a round is resolved when that round is submitted (or the
|
|
111022
|
-
* round is superseded), so concurrent / re-entrant awaits never strand.
|
|
110932
|
+
* Block until the user submits a selection for the current round, resolving
|
|
110933
|
+
* immediately if one is already waiting to be consumed. On `timeoutMs` returns
|
|
110934
|
+
* a `pending` outcome so the caller can re-await without losing the live
|
|
110935
|
+
* proposals; a `signal` abort rejects with an AbortError. Every await parked on
|
|
110936
|
+
* a round is resolved when that round is submitted or superseded, so concurrent
|
|
110937
|
+
* / re-entrant awaits never strand.
|
|
111023
110938
|
*/
|
|
111024
110939
|
awaitSelection(opts) {
|
|
111025
110940
|
if (opts.signal?.aborted) {
|
|
@@ -112071,9 +111986,8 @@ function deriveUiAutomatorRole(className) {
|
|
|
112071
111986
|
return short || "View";
|
|
112072
111987
|
}
|
|
112073
111988
|
var NOISY_CLASSES = /* @__PURE__ */ new Set([
|
|
112074
|
-
//
|
|
112075
|
-
// carries the icon's content-desc
|
|
112076
|
-
// 40+ leaf nodes. Drop the entire subtree.
|
|
111989
|
+
// react-native-svg icon internals: never tappable, and the parent already
|
|
111990
|
+
// carries the icon's content-desc.
|
|
112077
111991
|
"com.horcrux.svg.PathView",
|
|
112078
111992
|
"com.horcrux.svg.GroupView",
|
|
112079
111993
|
"com.horcrux.svg.SvgView"
|
|
@@ -112082,10 +111996,8 @@ function isNoisyUiAutomatorClass(className) {
|
|
|
112082
111996
|
return NOISY_CLASSES.has(className);
|
|
112083
111997
|
}
|
|
112084
111998
|
var SYSTEM_PACKAGES = /* @__PURE__ */ new Set([
|
|
112085
|
-
// Status bar / nav bar / quick settings
|
|
112086
|
-
//
|
|
112087
|
-
// the foreground-app's own package even when the foreground IS a system app
|
|
112088
|
-
// (settings, permission dialog), so permission prompts still surface.
|
|
111999
|
+
// Status bar / nav bar / quick settings. Only systemui is listed on purpose:
|
|
112000
|
+
// a foreground system app (settings, permission dialog) must still surface.
|
|
112089
112001
|
"com.android.systemui"
|
|
112090
112002
|
]);
|
|
112091
112003
|
var SYSTEM_RID_PREFIXES = [
|
|
@@ -112100,8 +112012,8 @@ var LAYOUT_CONTAINERS = /* @__PURE__ */ new Set([
|
|
|
112100
112012
|
"androidx.constraintlayout.widget.ConstraintLayout",
|
|
112101
112013
|
"androidx.coordinatorlayout.widget.CoordinatorLayout",
|
|
112102
112014
|
"android.view.ViewGroup",
|
|
112103
|
-
//
|
|
112104
|
-
//
|
|
112015
|
+
// Compose emits bare android.view.View for semantics nodes with no widget
|
|
112016
|
+
// mapping.
|
|
112105
112017
|
"android.view.View"
|
|
112106
112018
|
]);
|
|
112107
112019
|
function isUiAutomatorLayoutContainer(className) {
|
|
@@ -112439,8 +112351,7 @@ function resolveTraceProcessorAssets() {
|
|
|
112439
112351
|
}
|
|
112440
112352
|
function patchGlueForNode(src) {
|
|
112441
112353
|
const edits = [
|
|
112442
|
-
// Force memory32: skip the memory64
|
|
112443
|
-
// memory64 __syscall_mprotect path; no global WebAssembly wrapper).
|
|
112354
|
+
// Force memory32: skip the memory64 probe and its __syscall_mprotect path.
|
|
112444
112355
|
["this.useMemory64 = hasMemory64Support();", "this.useMemory64 = false;"],
|
|
112445
112356
|
// Hand the wasm bytes straight to emscripten -> it never calls readBinary/XHR.
|
|
112446
112357
|
["locateFile: (s) => s,", "locateFile: (s) => s, wasmBinary: globalThis.__TP_WASM_BYTES,"],
|
|
@@ -113219,10 +113130,8 @@ async function describeAndroid(registry2, serial, _bundleId, isTv) {
|
|
|
113219
113130
|
throw new FailureError(
|
|
113220
113131
|
`uiautomator could not capture the screen: ${trimmed}. Common causes: device locked / keyguard, DRM or secure overlay, Play Integrity screen. Unlock the device or take a screenshot as a fallback.`,
|
|
113221
113132
|
{
|
|
113222
|
-
//
|
|
113223
|
-
//
|
|
113224
|
-
// subprocess. Classified `subprocess` to match the sibling
|
|
113225
|
-
// ANDROID_UIAUTOMATOR_PARSE_FAILED (also adb-exit-0, unusable output).
|
|
113133
|
+
// adb exits 0, but uiautomator reported an in-band `ERROR:` line — same
|
|
113134
|
+
// adb-exit-0/unusable-output shape as ANDROID_UIAUTOMATOR_PARSE_FAILED.
|
|
113226
113135
|
error_code: FAILURE_CODES.ANDROID_UIAUTOMATOR_CAPTURE_FAILED,
|
|
113227
113136
|
failure_stage: "android_uiautomator_capture",
|
|
113228
113137
|
failure_area: "tool_server",
|
|
@@ -113267,10 +113176,9 @@ function createPreviewRouter(registry2) {
|
|
|
113267
113176
|
element_count: snap.proposals.length,
|
|
113268
113177
|
variant_count: snap.proposals.reduce((n, p) => n + p.variants.length, 0),
|
|
113269
113178
|
is_cli_session: snap.cliSession,
|
|
113270
|
-
//
|
|
113271
|
-
//
|
|
113272
|
-
//
|
|
113273
|
-
// prior flow's platform — a stale value next to a zero-count open.
|
|
113179
|
+
// `device` deliberately survives the store's reset(), so a CLI up-front
|
|
113180
|
+
// open (no proposals staged yet) would otherwise report a prior flow's
|
|
113181
|
+
// platform.
|
|
113274
113182
|
platform: snap.proposals.length > 0 && snap.device ? classifyDeviceForTelemetry(snap.device) : void 0
|
|
113275
113183
|
});
|
|
113276
113184
|
};
|
|
@@ -113536,16 +113444,16 @@ data: ${JSON.stringify(data)}
|
|
|
113536
113444
|
}
|
|
113537
113445
|
try {
|
|
113538
113446
|
const result = variantProposalStore.submitSelection({
|
|
113539
|
-
// The round the UI built this submit against
|
|
113540
|
-
// rejects it
|
|
113541
|
-
//
|
|
113447
|
+
// The round the UI built this submit against, if it sent one. The store
|
|
113448
|
+
// rejects it once the round has rolled, so a click from a stale tab can't
|
|
113449
|
+
// mint a phantom completion.
|
|
113542
113450
|
round: typeof body.round === "number" ? body.round : void 0,
|
|
113543
113451
|
selections,
|
|
113544
113452
|
annotations,
|
|
113545
113453
|
globalComment: typeof body.globalComment === "string" ? body.globalComment : void 0,
|
|
113546
|
-
//
|
|
113547
|
-
//
|
|
113548
|
-
//
|
|
113454
|
+
// UI usage signals for `lens:round_completed`. Coerced to strict booleans
|
|
113455
|
+
// so a malformed field from this unauthenticated route can't carry
|
|
113456
|
+
// anything else into telemetry.
|
|
113549
113457
|
inspectorUsed: body.inspectorUsed === true,
|
|
113550
113458
|
offscreenRevealed: body.offscreenRevealed === true
|
|
113551
113459
|
});
|
|
@@ -115062,7 +114970,7 @@ var SourceMapsRegistry = class {
|
|
|
115062
114970
|
}
|
|
115063
114971
|
/**
|
|
115064
114972
|
* Begin fetching and registering a source map from a Debugger.scriptParsed event.
|
|
115065
|
-
* Returns immediately;
|
|
114973
|
+
* Returns immediately; `waitForPending()` blocks until all maps are loaded.
|
|
115066
114974
|
*/
|
|
115067
114975
|
registerFromScriptParsed(scriptUrl, scriptId, sourceMapURL) {
|
|
115068
114976
|
if (!sourceMapURL) return;
|
|
@@ -115076,10 +114984,8 @@ var SourceMapsRegistry = class {
|
|
|
115076
114984
|
/**
|
|
115077
114985
|
* Resolve an original source file + line to its generated position in the bundle.
|
|
115078
114986
|
*
|
|
115079
|
-
* `filePath`
|
|
115080
|
-
*
|
|
115081
|
-
* - absolute, e.g. "/Users/.../App.tsx"
|
|
115082
|
-
* - aliased, e.g. "/[metro-project]/App.tsx"
|
|
114987
|
+
* `filePath` may be project-relative ("src/Foo.tsx"), absolute, or aliased
|
|
114988
|
+
* ("/[metro-project]/App.tsx").
|
|
115083
114989
|
*/
|
|
115084
114990
|
toGeneratedPosition(filePath, line1Based, column0Based = 0) {
|
|
115085
114991
|
const candidates = this.buildSourceCandidates(filePath);
|
|
@@ -115107,10 +115013,7 @@ var SourceMapsRegistry = class {
|
|
|
115107
115013
|
}
|
|
115108
115014
|
return null;
|
|
115109
115015
|
}
|
|
115110
|
-
/**
|
|
115111
|
-
* Find which source map source path matches the given file path.
|
|
115112
|
-
* Returns the matched source string or null.
|
|
115113
|
-
*/
|
|
115016
|
+
/** Matching entry in a registered map's `sources`, or null. */
|
|
115114
115017
|
findMatchingSource(filePath) {
|
|
115115
115018
|
const candidates = this.buildSourceCandidates(filePath);
|
|
115116
115019
|
for (const map2 of this.maps) {
|
|
@@ -115453,22 +115356,12 @@ var chromiumJsRuntimeDebuggerBlueprint = {
|
|
|
115453
115356
|
getDependencies(_payload) {
|
|
115454
115357
|
return { chromium: `${CHROMIUM_CDP_NAMESPACE}:${_payload}` };
|
|
115455
115358
|
},
|
|
115456
|
-
// Deliberately NO recoverable()
|
|
115457
|
-
//
|
|
115458
|
-
//
|
|
115459
|
-
//
|
|
115460
|
-
//
|
|
115461
|
-
//
|
|
115462
|
-
// RUNNING is a tab switch, where CDPClient.reconnect() rejects in-flight
|
|
115463
|
-
// requests with CONNECTION_CLOSED (late sends with NOT_CONNECTED) but
|
|
115464
|
-
// re-points the SAME client object at the new tab — the cached node heals
|
|
115465
|
-
// itself for the next call without any dispose. The failing call surfaces a
|
|
115466
|
-
// classified error that debugger-status maps to a structured "reconnecting"
|
|
115467
|
-
// result with retry-once guidance. A genuinely dead Chromium socket instead
|
|
115468
|
-
// fires ChromiumCdp's own terminated event, whose teardown cascades into this
|
|
115469
|
-
// dependent — the node leaves RUNNING and the next call re-resolves fresh.
|
|
115470
|
-
// (Same log-preservation reasoning as debugger-log-registry's missing socket
|
|
115471
|
-
// gate — see that tool's comment.)
|
|
115359
|
+
// Deliberately NO recoverable(): the registry's self-heal disposes the node
|
|
115360
|
+
// before retrying, and dispose unlinks the captured console log. It would
|
|
115361
|
+
// also buy nothing — the only failure window while this node and ChromiumCdp
|
|
115362
|
+
// both stay RUNNING is a tab switch, where CDPClient.reconnect() re-points
|
|
115363
|
+
// the same client object and the cached node heals itself; a genuinely dead
|
|
115364
|
+
// socket arrives instead as ChromiumCdp's terminated cascade.
|
|
115472
115365
|
async factory(deps, payload, options) {
|
|
115473
115366
|
const opts = options;
|
|
115474
115367
|
const device = opts?.device;
|
|
@@ -115524,14 +115417,13 @@ var chromiumJsRuntimeDebuggerBlueprint = {
|
|
|
115524
115417
|
const sourceResolver = makeStubSourceResolver();
|
|
115525
115418
|
const api = {
|
|
115526
115419
|
port,
|
|
115527
|
-
//
|
|
115528
|
-
//
|
|
115529
|
-
// source resolver) are gated out before they ever touch this field.
|
|
115420
|
+
// No Metro project root on Chromium; debugger-connect and debugger-status
|
|
115421
|
+
// document the field as empty here.
|
|
115530
115422
|
projectRoot: "",
|
|
115531
115423
|
deviceName: device.name ?? "Chromium",
|
|
115532
115424
|
appName: "Chromium",
|
|
115533
115425
|
logicalDeviceId: device.id,
|
|
115534
|
-
//
|
|
115426
|
+
// No legacy RN inspector on Chromium.
|
|
115535
115427
|
isNewDebugger: true,
|
|
115536
115428
|
cdp,
|
|
115537
115429
|
sourceResolver,
|
|
@@ -115910,14 +115802,11 @@ var ANDROID_NAMED_KEYCODES = {
|
|
|
115910
115802
|
"esc": 111,
|
|
115911
115803
|
// alias of escape
|
|
115912
115804
|
"backspace": 67,
|
|
115913
|
-
// KEYCODE_DEL
|
|
115914
|
-
//
|
|
115915
|
-
// key-codes.ts
|
|
115916
|
-
//
|
|
115917
|
-
// key must mean the same thing on every platform, so map it to KEYCODE_DEL (67)
|
|
115918
|
-
// here too rather than KEYCODE_FORWARD_DEL (112).
|
|
115805
|
+
// KEYCODE_DEL
|
|
115806
|
+
// KEYCODE_DEL, not KEYCODE_FORWARD_DEL (112): the shared HID vocabulary in
|
|
115807
|
+
// key-codes.ts maps both `backspace` and `delete` to usage 42, and a named key
|
|
115808
|
+
// must mean the same thing on every platform.
|
|
115919
115809
|
"delete": 67,
|
|
115920
|
-
// KEYCODE_DEL (alias of backspace — see note above)
|
|
115921
115810
|
"tab": 61,
|
|
115922
115811
|
// KEYCODE_TAB
|
|
115923
115812
|
"space": 62,
|
|
@@ -115930,7 +115819,7 @@ var ANDROID_NAMED_KEYCODES = {
|
|
|
115930
115819
|
// KEYCODE_DPAD_LEFT
|
|
115931
115820
|
"arrow-right": 22,
|
|
115932
115821
|
// KEYCODE_DPAD_RIGHT
|
|
115933
|
-
//
|
|
115822
|
+
// KEYCODE_F1 (131) .. KEYCODE_F12 (142) are contiguous.
|
|
115934
115823
|
...Object.fromEntries(Array.from({ length: 12 }, (_, i) => [`f${i + 1}`, 131 + i]))
|
|
115935
115824
|
};
|
|
115936
115825
|
var ANDROID_BUTTON_KEYCODES = {
|
|
@@ -115950,9 +115839,8 @@ var ANDROID_BUTTON_KEYCODES = {
|
|
|
115950
115839
|
function assertTypeableAndroidText(text) {
|
|
115951
115840
|
if (/[\n\r]/.test(text)) {
|
|
115952
115841
|
throw new InvalidToolInputError(
|
|
115953
|
-
//
|
|
115954
|
-
//
|
|
115955
|
-
// equivalent is the tv-remote select press.
|
|
115842
|
+
// The advice must also hold on the TV path (typeTv), which rejects named
|
|
115843
|
+
// keys in favour of tv-remote select.
|
|
115956
115844
|
'keyboard text must not contain a newline on Android; press enter separately instead (key: "enter" on a phone or tablet, tv-remote select on a TV)',
|
|
115957
115845
|
{
|
|
115958
115846
|
error_code: FAILURE_CODES.KEYBOARD_CHARACTER_UNSUPPORTED,
|
|
@@ -116178,15 +116066,13 @@ var androidTvControlBlueprint = {
|
|
|
116178
116066
|
await injectAndroidText(serial, words[i]);
|
|
116179
116067
|
}
|
|
116180
116068
|
},
|
|
116181
|
-
// Android TV reads the live hierarchy on every describe
|
|
116182
|
-
// daemon), so there is no stale-cache class of bug to recover from.
|
|
116069
|
+
// Android TV reads the live hierarchy on every describe — no cache to drop.
|
|
116183
116070
|
async recycleAx() {
|
|
116184
116071
|
}
|
|
116185
116072
|
};
|
|
116186
116073
|
const instance = {
|
|
116187
116074
|
api,
|
|
116188
|
-
// Stateless: every
|
|
116189
|
-
// tear down. Present to satisfy the ServiceInstance contract.
|
|
116075
|
+
// Stateless: every call is a fresh adb shell-out, so nothing to tear down.
|
|
116190
116076
|
dispose: async () => {
|
|
116191
116077
|
},
|
|
116192
116078
|
events
|
|
@@ -116213,9 +116099,8 @@ var nativeDevtoolsStatusTool = {
|
|
|
116213
116099
|
},
|
|
116214
116100
|
capability: { apple: { simulator: true, device: true }, appleRemote: { simulator: true } },
|
|
116215
116101
|
// The "injectable is false" recovery sentence inlines NON_INJECTABLE_RECOVERY
|
|
116216
|
-
// verbatim: the description must stay
|
|
116217
|
-
//
|
|
116218
|
-
// by native-devtools-status.test.ts.
|
|
116102
|
+
// verbatim (pinned by native-devtools-status.test.ts): the description must stay
|
|
116103
|
+
// a plain literal for scripts/extract-tools.mjs to read statically.
|
|
116219
116104
|
description: `Check whether native devtools are connected to a specific app and whether the next launch is prepared for injection.
|
|
116220
116105
|
Use when you need to verify native devtools readiness before calling native-full-hierarchy, native-describe-screen, or native-network-logs.
|
|
116221
116106
|
|
|
@@ -116294,13 +116179,13 @@ Fails if the simulator server is not running for the given UDID.`,
|
|
|
116294
116179
|
// fresh process fixes — `indeterminate` among them, since an uninspectable
|
|
116295
116180
|
// host (ios-remote) supports no finer reading. Both already carry a live
|
|
116296
116181
|
// process (the settling above rewrote an empty `indeterminate` to
|
|
116297
|
-
// `not_running`), so an `appRunning` conjunct would
|
|
116182
|
+
// `not_running`), so an `appRunning` conjunct would restate the state.
|
|
116298
116183
|
requiresRestart: state3 === "stale_process" || state3 === "indeterminate",
|
|
116299
116184
|
state: state3,
|
|
116300
116185
|
// The booleans cannot express "one restart, then stop" — the shape
|
|
116301
116186
|
// `indeterminate` needs, and the only one ios-remote can report for a
|
|
116302
|
-
// running app.
|
|
116303
|
-
//
|
|
116187
|
+
// running app. The shared prose puts that escape in front of an agent who
|
|
116188
|
+
// never read this tool's description.
|
|
116304
116189
|
...state3 === "connected" ? {} : { message: buildAppStateMessage(params.bundleId, state3) },
|
|
116305
116190
|
nextLaunchWillBeInjected: envSetup,
|
|
116306
116191
|
injectable: true
|
|
@@ -117178,22 +117063,11 @@ var jsRuntimeDebuggerBlueprint = {
|
|
|
117178
117063
|
getURN(payload) {
|
|
117179
117064
|
return `${JS_RUNTIME_DEBUGGER_NAMESPACE}:${payload}`;
|
|
117180
117065
|
},
|
|
117181
|
-
//
|
|
117182
|
-
//
|
|
117183
|
-
//
|
|
117184
|
-
//
|
|
117185
|
-
//
|
|
117186
|
-
// there the request provably never left the host, making a retry safe.
|
|
117187
|
-
// Deliberately NOT recoverable:
|
|
117188
|
-
// - DEBUGGER_CDP_CONNECTION_CLOSED: the request was delivered and may have
|
|
117189
|
-
// taken effect (double-execution risk); on this path the node has also
|
|
117190
|
-
// already left RUNNING when it fires.
|
|
117191
|
-
// - DEBUGGER_CDP_REQUEST_TIMEOUT: the request may have taken effect, and a
|
|
117192
|
-
// hung-but-open runtime (e.g. paused at a breakpoint) is not fixed by
|
|
117193
|
-
// reconnecting.
|
|
117194
|
-
// - Metro discovery / target-selection codes: init-path failures — the node
|
|
117195
|
-
// never reaches RUNNING, so recovery is never consulted, and a retry would
|
|
117196
|
-
// be hopeless anyway.
|
|
117066
|
+
// Only the send() guard's DEBUGGER_CDP_NOT_CONNECTED proves the request never
|
|
117067
|
+
// left the host, so only it is safe to retry. CONNECTION_CLOSED and
|
|
117068
|
+
// REQUEST_TIMEOUT reject requests that were delivered and may have taken
|
|
117069
|
+
// effect; Metro discovery and target-selection codes throw before the node is
|
|
117070
|
+
// RUNNING, where the registry never consults this.
|
|
117197
117071
|
recoverable(error52) {
|
|
117198
117072
|
return getFailureSignal(error52)?.error_code === FAILURE_CODES.DEBUGGER_CDP_NOT_CONNECTED;
|
|
117199
117073
|
},
|
|
@@ -118364,11 +118238,8 @@ async function waitForAdbDevice(serial, timeoutMs) {
|
|
|
118364
118238
|
error_code: FAILURE_CODES.VEGA_DEVICE_NOT_REGISTERED,
|
|
118365
118239
|
failure_stage: "vega_adb_register",
|
|
118366
118240
|
failure_area: "tool_server",
|
|
118367
|
-
//
|
|
118368
|
-
//
|
|
118369
|
-
// (vs VEGA_BOOT_TIMEOUT, the VVD never starting) already carries the
|
|
118370
|
-
// "registered vs started" distinction — error_kind reflects the true
|
|
118371
|
-
// nature (deadline expiry) rather than double-encoding that.
|
|
118241
|
+
// Deadline expiry, hence `timeout`; the error_code already separates this
|
|
118242
|
+
// from VEGA_BOOT_TIMEOUT (the VVD never starting).
|
|
118372
118243
|
error_kind: "timeout"
|
|
118373
118244
|
}
|
|
118374
118245
|
);
|
|
@@ -118668,11 +118539,9 @@ async function bootElectronApp(options) {
|
|
|
118668
118539
|
child = (0, import_node_child_process17.spawn)(launcher.command, args, {
|
|
118669
118540
|
detached: true,
|
|
118670
118541
|
stdio: ["ignore", "pipe", "pipe"],
|
|
118671
|
-
// Strip ELECTRON_RUN_AS_NODE (see electronGuiChildEnv):
|
|
118672
|
-
//
|
|
118673
|
-
//
|
|
118674
|
-
// child exits early, or the readiness probe times out) instead of the app
|
|
118675
|
-
// coming up.
|
|
118542
|
+
// Strip ELECTRON_RUN_AS_NODE (see electronGuiChildEnv): inherited from an
|
|
118543
|
+
// Electron-based MCP host it would boot the binary in Node mode with no
|
|
118544
|
+
// CDP endpoint, failing boot-device instead of bringing the app up.
|
|
118676
118545
|
env: electronGuiChildEnv({ ELECTRON_ENABLE_LOGGING: "1" })
|
|
118677
118546
|
});
|
|
118678
118547
|
} catch (err) {
|
|
@@ -118835,11 +118704,9 @@ var STAGE_BUDGET = {
|
|
|
118835
118704
|
pmReady: 45e3,
|
|
118836
118705
|
// pm path android answers (retried; non-fatal on the final attempt)
|
|
118837
118706
|
firstRealFrame: 9e4,
|
|
118838
|
-
// screencap returns ≥1 non-zero pixel after cold boot
|
|
118839
118707
|
firstRealFrameHot: 8e3
|
|
118840
|
-
//
|
|
118841
|
-
//
|
|
118842
|
-
// few seconds is enough to discriminate transient blanks from genuine wedge.
|
|
118708
|
+
// the sticky-blank state never clears on its own, so a
|
|
118709
|
+
// few seconds is enough to tell it from a transient blank.
|
|
118843
118710
|
};
|
|
118844
118711
|
var VALID_GPU_MODES = /* @__PURE__ */ new Set([
|
|
118845
118712
|
"auto",
|
|
@@ -119358,14 +119225,13 @@ async function bootAndroidImpl(params) {
|
|
|
119358
119225
|
emulatorArgs: hotArgs,
|
|
119359
119226
|
attemptDeadline: hotAttemptDeadline,
|
|
119360
119227
|
serialsBefore,
|
|
119361
|
-
// Snapshot restores register with adb within a
|
|
119362
|
-
//
|
|
119363
|
-
// scenario where load fails and the child silently cold-boots.
|
|
119228
|
+
// Snapshot restores register with adb within seconds; a minute-long
|
|
119229
|
+
// wait here would mask a failed load that silently cold-boots.
|
|
119364
119230
|
adbRegisterBudgetMs: 3e4,
|
|
119365
119231
|
deviceReadyBudgetMs: 3e4,
|
|
119366
119232
|
bootCompletedBudgetMs: 3e4,
|
|
119367
|
-
// Keep the hot path tight:
|
|
119368
|
-
//
|
|
119233
|
+
// Keep the hot path tight: one ~10 s PM window, tear down on failure so
|
|
119234
|
+
// we fall through to the cold boot below.
|
|
119369
119235
|
pmProbeBudgetMs: 1e4,
|
|
119370
119236
|
tearDownIfUnready: true
|
|
119371
119237
|
});
|
|
@@ -119406,9 +119272,9 @@ async function bootAndroidImpl(params) {
|
|
|
119406
119272
|
adbRegisterBudgetMs: STAGE_BUDGET.adbRegister,
|
|
119407
119273
|
deviceReadyBudgetMs: STAGE_BUDGET.deviceReady,
|
|
119408
119274
|
bootCompletedBudgetMs: STAGE_BUDGET.bootCompleted,
|
|
119409
|
-
// Final attempt: retry PM for longer
|
|
119410
|
-
//
|
|
119411
|
-
//
|
|
119275
|
+
// Final attempt: retry PM for longer and don't tear the emulator down if
|
|
119276
|
+
// it stays slow — a guest that reached boot_completed is usable, and there
|
|
119277
|
+
// is no further fallback to justify destroying it.
|
|
119412
119278
|
pmProbeBudgetMs: STAGE_BUDGET.pmReady,
|
|
119413
119279
|
tearDownIfUnready: false
|
|
119414
119280
|
});
|
|
@@ -119896,11 +119762,8 @@ Common Android packages: com.android.settings, com.android.chrome, com.google.an
|
|
|
119896
119762
|
searchHint: "open start app bundle id package simulator emulator chromium vega launch tvos apple tv fire tv",
|
|
119897
119763
|
zodSchema: zodSchema10,
|
|
119898
119764
|
capability: capability2,
|
|
119899
|
-
//
|
|
119900
|
-
//
|
|
119901
|
-
// which reads `services.nativeDevtools`). Local iOS resolves native-devtools
|
|
119902
|
-
// lazily in its handler so a tvOS udid never spins up the iOS-only injection
|
|
119903
|
-
// (see header comment); Android and Vega need no service.
|
|
119765
|
+
// ios-remote's handler reads `services.nativeDevtools`; local iOS resolves
|
|
119766
|
+
// it lazily instead (see header comment).
|
|
119904
119767
|
services: (params) => {
|
|
119905
119768
|
const device = resolveDevice(params.udid);
|
|
119906
119769
|
if (device.platform === "ios-remote") return { nativeDevtools: nativeDevtoolsRef(device) };
|
|
@@ -120081,11 +119944,8 @@ Returns { restarted, bundleId }. Fails if the app is not installed.`,
|
|
|
120081
119944
|
searchHint: "terminate relaunch restart reset app bundle id package simulator emulator vega tvos fire tv",
|
|
120082
119945
|
zodSchema: zodSchema11,
|
|
120083
119946
|
capability: capability3,
|
|
120084
|
-
// ios-remote
|
|
120085
|
-
//
|
|
120086
|
-
// iOS resolves native-devtools lazily in its handler so a tvOS udid never
|
|
120087
|
-
// spins up the iOS-only injection (see header comment); Android and Vega
|
|
120088
|
-
// need no service.
|
|
119947
|
+
// Only ios-remote's handler reads `services.nativeDevtools`, so only it
|
|
119948
|
+
// needs an eager declaration.
|
|
120089
119949
|
services: (params) => {
|
|
120090
119950
|
const device = resolveDevice(params.udid);
|
|
120091
119951
|
if (device.platform === "ios-remote") return { nativeDevtools: nativeDevtoolsRef(device) };
|
|
@@ -120378,8 +120238,8 @@ function buildIosHandler(backend) {
|
|
|
120378
120238
|
failure_stage: "ios_settings_permission_simctl_privacy",
|
|
120379
120239
|
failure_area: "tool_server",
|
|
120380
120240
|
error_kind: "subprocess",
|
|
120381
|
-
// Both backends run the `simctl privacy` verb
|
|
120382
|
-
//
|
|
120241
|
+
// Both backends run the same `simctl privacy` verb, so telemetry
|
|
120242
|
+
// uses one subprocess name.
|
|
120383
120243
|
...subprocessFailureMetadata(err, "xcrun_simctl")
|
|
120384
120244
|
},
|
|
120385
120245
|
{ cause: err instanceof Error ? err : new Error(String(err)) }
|
|
@@ -120559,12 +120419,11 @@ var permissionAction = {
|
|
|
120559
120419
|
reset: { started: "Resetting", completed: "Reset" }
|
|
120560
120420
|
};
|
|
120561
120421
|
var capability5 = {
|
|
120562
|
-
// `simctl privacy` edits the simulator's TCC store
|
|
120563
|
-
// equivalent host-side switch,
|
|
120422
|
+
// `simctl privacy` edits the simulator's TCC store; physical iPhones have no
|
|
120423
|
+
// equivalent host-side switch, hence no `device: true`.
|
|
120564
120424
|
apple: { simulator: true },
|
|
120565
|
-
// sim-remote
|
|
120566
|
-
//
|
|
120567
|
-
// launch-app / restart-app / reinstall-app / open-url family.
|
|
120425
|
+
// sim-remote exposes the same `simctl privacy` verb, so remote sims can
|
|
120426
|
+
// pre-set permissions too.
|
|
120568
120427
|
appleRemote: { simulator: true },
|
|
120569
120428
|
android: { emulator: true, device: true, unknown: true }
|
|
120570
120429
|
};
|
|
@@ -121215,9 +121074,9 @@ Fails if the simulator-server / emulator backend / Chromium CDP is not reachable
|
|
|
121215
121074
|
zodSchema: zodSchema15,
|
|
121216
121075
|
outputHint: "image",
|
|
121217
121076
|
capability: capability7,
|
|
121218
|
-
// No eager service: a tvOS udid classifies as iOS by shape,
|
|
121219
|
-
// simulator-server here would spawn it for
|
|
121220
|
-
//
|
|
121077
|
+
// No eager service: a tvOS udid classifies as iOS by shape, so declaring
|
|
121078
|
+
// simulator-server here would spawn it for a device it cannot drive and hang
|
|
121079
|
+
// on the ready timeout. Resolve the backend lazily instead.
|
|
121221
121080
|
services: () => ({}),
|
|
121222
121081
|
async execute(_services, params, ctx) {
|
|
121223
121082
|
const signal = ctx?.signal ?? AbortSignal.timeout(16e3);
|
|
@@ -121231,17 +121090,29 @@ Fails if the simulator-server / emulator backend / Chromium CDP is not reachable
|
|
|
121231
121090
|
scale: params.scale,
|
|
121232
121091
|
downscaler: params.downscaler
|
|
121233
121092
|
});
|
|
121234
|
-
const image2 = await requireArtifacts(ctx).register(
|
|
121093
|
+
const image2 = await requireArtifacts(ctx).register({
|
|
121094
|
+
hostPath: capturedPath2,
|
|
121095
|
+
kind: "screenshot",
|
|
121096
|
+
mimeType: "image/png"
|
|
121097
|
+
});
|
|
121235
121098
|
return { image: image2 };
|
|
121236
121099
|
}
|
|
121237
121100
|
if (device.platform === "ios" && await isTvOsSimulator(params.udid)) {
|
|
121238
121101
|
const pngPath = await tvScreenshot(params.udid, scale, signal);
|
|
121239
|
-
const image2 = await requireArtifacts(ctx).register(
|
|
121102
|
+
const image2 = await requireArtifacts(ctx).register({
|
|
121103
|
+
hostPath: pngPath,
|
|
121104
|
+
kind: "screenshot",
|
|
121105
|
+
mimeType: "image/png"
|
|
121106
|
+
});
|
|
121240
121107
|
return { image: image2 };
|
|
121241
121108
|
}
|
|
121242
121109
|
if (device.platform === "vega") {
|
|
121243
121110
|
const pngPath = await captureVegaScreenshotPng({ scale: params.scale });
|
|
121244
|
-
const image2 = await requireArtifacts(ctx).register(
|
|
121111
|
+
const image2 = await requireArtifacts(ctx).register({
|
|
121112
|
+
hostPath: pngPath,
|
|
121113
|
+
kind: "screenshot",
|
|
121114
|
+
mimeType: "image/png"
|
|
121115
|
+
});
|
|
121245
121116
|
return { image: image2 };
|
|
121246
121117
|
}
|
|
121247
121118
|
const ref = simulatorServerRef(device);
|
|
@@ -121255,7 +121126,11 @@ Fails if the simulator-server / emulator backend / Chromium CDP is not reachable
|
|
|
121255
121126
|
void 0,
|
|
121256
121127
|
androidDevtoolsRotationPeek(registry2, device)
|
|
121257
121128
|
);
|
|
121258
|
-
const image = await requireArtifacts(ctx).register(
|
|
121129
|
+
const image = await requireArtifacts(ctx).register({
|
|
121130
|
+
hostPath: capturedPath,
|
|
121131
|
+
kind: "screenshot",
|
|
121132
|
+
mimeType: "image/png"
|
|
121133
|
+
});
|
|
121259
121134
|
return { image };
|
|
121260
121135
|
}
|
|
121261
121136
|
};
|
|
@@ -121889,15 +121764,12 @@ var zodSchema23 = external_exports.object({
|
|
|
121889
121764
|
});
|
|
121890
121765
|
var BUTTONS_BY_PLATFORM = {
|
|
121891
121766
|
"ios": /* @__PURE__ */ new Set(["home", "power", "volumeUp", "volumeDown", "appSwitch", "actionButton"]),
|
|
121892
|
-
// Remote iOS sims expose the same hardware buttons as local iOS.
|
|
121893
121767
|
"ios-remote": /* @__PURE__ */ new Set(["home", "power", "volumeUp", "volumeDown", "appSwitch", "actionButton"]),
|
|
121894
121768
|
"android": /* @__PURE__ */ new Set(["home", "back", "power", "volumeUp", "volumeDown", "appSwitch"]),
|
|
121895
|
-
//
|
|
121896
|
-
// excludes them, the empty set keeps the lookup total if one slips through.
|
|
121769
|
+
// The capability gate excludes chromium; the empty set keeps the lookup total.
|
|
121897
121770
|
"chromium": /* @__PURE__ */ new Set([]),
|
|
121898
|
-
// Vega
|
|
121899
|
-
// `
|
|
121900
|
-
// rejected before this map is consulted. Empty set keeps the record total.
|
|
121771
|
+
// Vega buttons / D-pad go through the `tv-remote` tool; the capability omits
|
|
121772
|
+
// `vega`, so this entry only keeps the record total.
|
|
121901
121773
|
"vega": /* @__PURE__ */ new Set([])
|
|
121902
121774
|
};
|
|
121903
121775
|
var capability15 = {
|
|
@@ -121919,12 +121791,9 @@ Returns { pressed: buttonName }.
|
|
|
121919
121791
|
Fails if the device backend is not reachable \u2014 the simulator-server for iOS, or \`adb\` for Android (Android presses are injected with \`adb shell input keyevent\`).`,
|
|
121920
121792
|
zodSchema: zodSchema23,
|
|
121921
121793
|
capability: capability15,
|
|
121922
|
-
// Android
|
|
121923
|
-
//
|
|
121924
|
-
//
|
|
121925
|
-
// to a 30s ready-wait) and could throw ServiceInitializationError before the
|
|
121926
|
-
// adb path even runs. Declare it only for the iOS / ios-remote path that
|
|
121927
|
-
// actually consumes it (mirrors the sibling `keyboard` tool's lazy services).
|
|
121794
|
+
// The Android path uses `adb`, so declaring the service for an Android target
|
|
121795
|
+
// would spawn a sim-server the tool never uses (up to a 30s ready-wait) and
|
|
121796
|
+
// could throw ServiceInitializationError before the adb path even runs.
|
|
121928
121797
|
services: (params) => {
|
|
121929
121798
|
const device = resolveDevice(params.udid);
|
|
121930
121799
|
return device.platform === "android" ? {} : { simulatorServer: simulatorServerRef(device) };
|
|
@@ -122204,12 +122073,9 @@ async function typeAndroidPhone(device, params) {
|
|
|
122204
122073
|
}
|
|
122205
122074
|
function makeAndroidImpl(registry2) {
|
|
122206
122075
|
return {
|
|
122207
|
-
// Both sub-paths shell out to `adb
|
|
122208
|
-
//
|
|
122209
|
-
// `
|
|
122210
|
-
// missing binary fails with the clean 424 install hint rather than surfacing
|
|
122211
|
-
// from deeper in the probe. Matches the android branch of `describe` and
|
|
122212
|
-
// `tv-remote`.
|
|
122076
|
+
// Both sub-paths shell out to `adb` (the `isAndroidTv` probe, then `input`
|
|
122077
|
+
// either way), so declaring it makes a missing binary fail with
|
|
122078
|
+
// `dispatchByPlatform`'s 424 install hint instead of from inside the probe.
|
|
122213
122079
|
requires: ["adb"],
|
|
122214
122080
|
handler: async (_services, params, device) => await isAndroidTv(device.id) ? typeTv(registry2, device, params) : typeAndroidPhone(device, params)
|
|
122215
122081
|
};
|
|
@@ -122380,11 +122246,9 @@ var REMOTE_BUTTONS = Object.keys(REMOTE_KEYCODES);
|
|
|
122380
122246
|
var NAMED_KEYCODES = {
|
|
122381
122247
|
"enter": "KEY_ENTER",
|
|
122382
122248
|
"return": "KEY_ENTER",
|
|
122383
|
-
// alias of enter (matches iOS/Android/Chromium)
|
|
122384
122249
|
// Back is the TV analog of Escape; KEY_ESC is inert for the focus engine.
|
|
122385
122250
|
"escape": "KEY_BACK",
|
|
122386
122251
|
"esc": "KEY_BACK",
|
|
122387
|
-
// alias of escape
|
|
122388
122252
|
"backspace": "KEY_BACKSPACE",
|
|
122389
122253
|
"delete": "KEY_DELETE",
|
|
122390
122254
|
"tab": "KEY_TAB",
|
|
@@ -122393,8 +122257,7 @@ var NAMED_KEYCODES = {
|
|
|
122393
122257
|
"arrow-down": "KEY_DOWN",
|
|
122394
122258
|
"arrow-left": "KEY_LEFT",
|
|
122395
122259
|
"arrow-right": "KEY_RIGHT",
|
|
122396
|
-
// Vega names function keys KEY_FN_F<n
|
|
122397
|
-
// in the device key-name table (verified against system.ext4, SDK 0.22.6759).
|
|
122260
|
+
// Vega names function keys KEY_FN_F<n>, not KEY_F<n> (SDK 0.22.6759 key table).
|
|
122398
122261
|
...Object.fromEntries(Array.from({ length: 12 }, (_, i) => [`f${i + 1}`, `KEY_FN_F${i + 1}`]))
|
|
122399
122262
|
};
|
|
122400
122263
|
var SETTLE_BETWEEN_PRESSES_S = 0.3;
|
|
@@ -122505,16 +122368,13 @@ function createKeyboardTool(registry2) {
|
|
|
122505
122368
|
return {
|
|
122506
122369
|
id: "keyboard",
|
|
122507
122370
|
interaction: {
|
|
122508
|
-
//
|
|
122509
|
-
//
|
|
122510
|
-
//
|
|
122371
|
+
// Never quote the parameters: `text` may hold a plaintext credential and
|
|
122372
|
+
// `key` is an unvalidated free string here, yet these messages reach the
|
|
122373
|
+
// event log before `execute` runs.
|
|
122511
122374
|
//
|
|
122512
|
-
//
|
|
122513
|
-
//
|
|
122514
|
-
// a
|
|
122515
|
-
// after a call that succeeded, so it sees neither. Each formatter
|
|
122516
|
-
// therefore has to word a different set of shapes, and the empty
|
|
122517
|
-
// request — neither parameter, a documented no-op — reaches both.
|
|
122375
|
+
// That ordering also makes `startedMsg` word requests `execute` then
|
|
122376
|
+
// rejects (text+key, `{ key: "" }`), while `completedMsg` runs only after
|
|
122377
|
+
// a success and sees neither. Both see the empty request, a no-op.
|
|
122518
122378
|
startedMsg: ({ params }) => {
|
|
122519
122379
|
if (params.text === void 0) return "Pressing a key";
|
|
122520
122380
|
if (params.key === void 0) return "Entering text";
|
|
@@ -122534,29 +122394,21 @@ One call does one action: pass text OR key, never both. To type and then press a
|
|
|
122534
122394
|
zodSchema: zodSchema24,
|
|
122535
122395
|
capability: capability16,
|
|
122536
122396
|
searchHint: "type text keyboard input named key enter escape arrow tv vega fire tv search field hid leanback",
|
|
122537
|
-
// No eager service: each branch resolves its backend lazily (TV control,
|
|
122538
|
-
// simulator-server, CDP, or Vega adb), since distinguishing a TV target is
|
|
122539
|
-
// async and a tvOS udid must never resolve simulator-server.
|
|
122540
122397
|
services: () => ({}),
|
|
122541
122398
|
execute: async (services, params, options) => {
|
|
122542
122399
|
if (params.text !== void 0 && params.key !== void 0) {
|
|
122543
122400
|
throw new InvalidToolInputError(
|
|
122544
122401
|
// Says what did NOT happen, so the caller retries instead of first
|
|
122545
|
-
// inspecting the field
|
|
122546
|
-
//
|
|
122402
|
+
// inspecting the field. The example is literal because an ellipsis is
|
|
122403
|
+
// non-ASCII and the Android backend rejects it.
|
|
122547
122404
|
//
|
|
122548
|
-
// The TV caveat is
|
|
122549
|
-
// target
|
|
122550
|
-
//
|
|
122551
|
-
//
|
|
122552
|
-
|
|
122553
|
-
//
|
|
122554
|
-
//
|
|
122555
|
-
'keyboard takes `text` or `key`, not both \u2014 nothing was typed. To type and then press a key, send two `keyboard` steps in one `run-sequence`: { text: "hello" } followed by { key: "enter" }. On a TV target (Apple TV / Android TV) `key` is not supported at all \u2014 type with `text` and move focus with `tv-remote` (up/down/left/right/select).' + // The one-`run-sequence` form and two bare calls are NOT equivalent
|
|
122556
|
-
// once the text carries a placeholder, and this message is where an
|
|
122557
|
-
// agent converts a combined secret call — the tool description's
|
|
122558
|
-
// caveat is read long before that moment, if at all. The check is
|
|
122559
|
-
// syntactic (the same `.includes` flow-utils.ts uses), so the guard
|
|
122405
|
+
// The TV caveat is static, not probed: this guard runs above the
|
|
122406
|
+
// dispatch, so the target kind is unknown here — yet without it the
|
|
122407
|
+
// prescribed `{ key: "enter" }` is a retry that cannot succeed on a
|
|
122408
|
+
// TV, where `key` is rejected outright (platforms/tv.ts).
|
|
122409
|
+
'keyboard takes `text` or `key`, not both \u2014 nothing was typed. To type and then press a key, send two `keyboard` steps in one `run-sequence`: { text: "hello" } followed by { key: "enter" }. On a TV target (Apple TV / Android TV) `key` is not supported at all \u2014 type with `text` and move focus with `tv-remote` (up/down/left/right/select).' + // One `run-sequence` and two bare calls are NOT equivalent once the
|
|
122410
|
+
// text carries a placeholder, and this message is where an agent
|
|
122411
|
+
// converts a combined secret call. Syntactic check, so the guard
|
|
122560
122412
|
// still resolves nothing.
|
|
122561
122413
|
(params.text.includes(SECRET_PLACEHOLDER_MARKER) ? " This `text` carries a `" + SECRET_PLACEHOLDER_MARKER + '...}}` placeholder, so keep both steps in that ONE `run-sequence` rather than splitting them into two bare calls: the auto-screenshot skip is decided per tool call from the whole request, and a separate { key: "enter" } call carries no placeholder \u2014 its screenshot is taken after the key lands and can capture the still-visible secret.' : ""),
|
|
122562
122414
|
{
|
|
@@ -122567,12 +122419,12 @@ One call does one action: pass text OR key, never both. To type and then press a
|
|
|
122567
122419
|
}
|
|
122568
122420
|
if (params.key === "") {
|
|
122569
122421
|
throw new InvalidToolInputError(
|
|
122570
|
-
// Names the omission as the alternative
|
|
122571
|
-
//
|
|
122422
|
+
// Names the omission as the alternative: a caller that sent an empty
|
|
122423
|
+
// string usually built the value from something absent.
|
|
122572
122424
|
"`key` is an empty string, which names no key \u2014 nothing was pressed. Pass a named key (enter, escape, backspace, tab, space, arrow-up, arrow-down, arrow-left, arrow-right, f1\u2013f12), or omit `key` if there is nothing to press.",
|
|
122573
122425
|
{
|
|
122574
|
-
// The same code an unknown name gets
|
|
122575
|
-
//
|
|
122426
|
+
// The same code an unknown name gets: one telemetry bucket for
|
|
122427
|
+
// every unusable `key` value.
|
|
122576
122428
|
error_code: FAILURE_CODES.KEYBOARD_KEY_UNSUPPORTED,
|
|
122577
122429
|
failure_stage: "keyboard_named_key_empty",
|
|
122578
122430
|
error_kind: "unsupported"
|
|
@@ -122629,8 +122481,8 @@ async function pasteSimulator(api, text) {
|
|
|
122629
122481
|
}
|
|
122630
122482
|
function makeIosImpl4(registry2) {
|
|
122631
122483
|
return {
|
|
122632
|
-
// `
|
|
122633
|
-
//
|
|
122484
|
+
// `xcrun` is for the `isTvOsSimulator` probe; simulator-server comes from
|
|
122485
|
+
// the blueprint.
|
|
122634
122486
|
requires: ["xcrun"],
|
|
122635
122487
|
async handler(_services, params, device) {
|
|
122636
122488
|
if (await isTvOsSimulator(device.id)) rejectTv(device);
|
|
@@ -122683,21 +122535,16 @@ function makeAndroidImpl2(registry2) {
|
|
|
122683
122535
|
|
|
122684
122536
|
// ../tool-server/src/tools/paste/index.ts
|
|
122685
122537
|
var capability17 = {
|
|
122686
|
-
// Simulators only. A physical iPhone's pasteboard is reachable through the
|
|
122687
|
-
// same simulator-server endpoint, but the paste keystroke is not verified
|
|
122688
|
-
// over the CoreDevice HID path, so `device` stays off until it is.
|
|
122689
122538
|
apple: { simulator: true },
|
|
122690
|
-
// A remote
|
|
122691
|
-
//
|
|
122539
|
+
// A remote sim pastes over the MoQ transport (`simctl pbcopy` + ⌘V); the HTTP
|
|
122540
|
+
// clipboard route does not exist there.
|
|
122692
122541
|
appleRemote: { simulator: true },
|
|
122693
|
-
// Emulators only: the clipboard is set through the emulator's gRPC
|
|
122694
|
-
//
|
|
122695
|
-
//
|
|
122696
|
-
// simulator-server refuses a phone either way.
|
|
122542
|
+
// Emulators only: the clipboard is set through the emulator's gRPC endpoint,
|
|
122543
|
+
// which a physical phone does not have. `unknown` is admitted because an
|
|
122544
|
+
// unresolved serial may still be an emulator.
|
|
122697
122545
|
android: { emulator: true, unknown: true }
|
|
122698
|
-
// No `chromium`:
|
|
122699
|
-
//
|
|
122700
|
-
// clipboard API is exposed by the VVD tooling.
|
|
122546
|
+
// No `chromium`: its only clipboard is the HOST one, so a paste would
|
|
122547
|
+
// overwrite what the user copied. No `vega`: VVD exposes no clipboard API.
|
|
122701
122548
|
//
|
|
122702
122549
|
// TV targets are not separate platforms (an Apple TV simulator is
|
|
122703
122550
|
// `ios`/`simulator`, an Android TV emulator `android`/`emulator`), so each
|
|
@@ -123026,9 +122873,8 @@ function shakeFailure(udid, detail, cause) {
|
|
|
123026
122873
|
failure_stage: "ios_shake_notifyutil",
|
|
123027
122874
|
failure_area: "tool_server",
|
|
123028
122875
|
error_kind: "subprocess",
|
|
123029
|
-
// Only a thrown subprocess error carries the syscall/exit metadata
|
|
123030
|
-
// remote backend reports a
|
|
123031
|
-
// throwing, so there is no error object to mine there.
|
|
122876
|
+
// Only a thrown subprocess error carries the syscall/exit metadata; the
|
|
122877
|
+
// remote backend reports a failed child in its JSON payload instead.
|
|
123032
122878
|
...cause ? subprocessFailureMetadata(cause, "xcrun_simctl") : {}
|
|
123033
122879
|
},
|
|
123034
122880
|
cause ? { cause } : void 0
|
|
@@ -123210,26 +123056,22 @@ var androidImpl6 = {
|
|
|
123210
123056
|
|
|
123211
123057
|
// ../tool-server/src/tools/shake/index.ts
|
|
123212
123058
|
var capability19 = {
|
|
123213
|
-
// Simulator only
|
|
123214
|
-
//
|
|
123215
|
-
// gets a clean 400 instead of a silent no-op.
|
|
123059
|
+
// Simulator only: a physical iPhone's motion is real hardware, with no
|
|
123060
|
+
// host-side hook to fake it.
|
|
123216
123061
|
apple: { simulator: true },
|
|
123217
|
-
//
|
|
123218
|
-
//
|
|
123062
|
+
// `sim-remote spawn` runs the same in-simulator `notifyutil` argv the local
|
|
123063
|
+
// path does.
|
|
123219
123064
|
appleRemote: { simulator: true },
|
|
123220
|
-
//
|
|
123221
|
-
//
|
|
123222
|
-
// because a serial that didn't resolve may still be an emulator; the handler
|
|
123223
|
-
// re-checks and rejects a non-emulator serial explicitly.
|
|
123065
|
+
// Emulators only, for the same reason as iOS. `unknown` is let through and
|
|
123066
|
+
// the handler rejects a serial with no emulator console.
|
|
123224
123067
|
android: { emulator: true, unknown: true }
|
|
123225
|
-
// No `vega
|
|
123068
|
+
// No `vega` block, so a Fire TV is rejected by the capability gate.
|
|
123226
123069
|
//
|
|
123227
|
-
// TV
|
|
123228
|
-
//
|
|
123229
|
-
// `android`/`emulator
|
|
123230
|
-
//
|
|
123231
|
-
//
|
|
123232
|
-
// kind is an async `simctl list` / `adb` probe.
|
|
123070
|
+
// A TV that is not a separate platform can't be excluded here: an Apple TV
|
|
123071
|
+
// simulator is `ios`/`simulator` and an Android TV emulator is
|
|
123072
|
+
// `android`/`emulator`. Each platform handler probes the runtime and rejects
|
|
123073
|
+
// a TV instead; `supports` can't, being synchronous while the probe is an
|
|
123074
|
+
// async `simctl list` / `adb` call.
|
|
123233
123075
|
};
|
|
123234
123076
|
var shakeTool = {
|
|
123235
123077
|
id: "shake",
|
|
@@ -123248,8 +123090,8 @@ Only phone/tablet simulators and emulators are supported.`,
|
|
|
123248
123090
|
searchHint: "shake motion accelerometer undo typing dev menu gesture",
|
|
123249
123091
|
zodSchema: shakeZodSchema,
|
|
123250
123092
|
capability: capability19,
|
|
123251
|
-
//
|
|
123252
|
-
//
|
|
123093
|
+
// No simulator-server is resolved: `simctl`/`adb` are called directly, so a
|
|
123094
|
+
// tool that never uses one doesn't spawn it or wait for it to be ready.
|
|
123253
123095
|
services: () => ({}),
|
|
123254
123096
|
execute: dispatchByPlatform({
|
|
123255
123097
|
toolId: "shake",
|
|
@@ -123376,10 +123218,8 @@ Multi-step navigation: pass a path as { button: ["up","right","right","select"]
|
|
|
123376
123218
|
Read the screen with \`describe\` before and after to see where focus landed.
|
|
123377
123219
|
Returns { pressed, count }.`,
|
|
123378
123220
|
alwaysLoad: true,
|
|
123379
|
-
// A path (≤64 buttons) × repeat (≤50) flattens to thousands of presses
|
|
123380
|
-
//
|
|
123381
|
-
// long-running so the MCP adapter doesn't abort it at its per-request fetch
|
|
123382
|
-
// timeout and the idle-shutdown timer is kept warm for the call's duration.
|
|
123221
|
+
// A path (≤64 buttons) × repeat (≤50) flattens to thousands of presses, sent
|
|
123222
|
+
// one round-trip at a time on the Apple/Android path — minutes of wall-clock.
|
|
123383
123223
|
longRunning: true,
|
|
123384
123224
|
searchHint: "tv remote dpad d-pad navigate focus up down left right select ok back home menu play pause rewind fast forward sequence path apple tv tvos android tv leanback vega fire tv",
|
|
123385
123225
|
zodSchema: zodSchema26,
|
|
@@ -129758,16 +129598,13 @@ var ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
129758
129598
|
"gesture-rotate",
|
|
129759
129599
|
"button",
|
|
129760
129600
|
"keyboard",
|
|
129761
|
-
//
|
|
129762
|
-
//
|
|
129601
|
+
// Sequenceable for the same reason `keyboard` is: the focus tap, the paste
|
|
129602
|
+
// and the submit are one user action.
|
|
129763
129603
|
"paste",
|
|
129764
129604
|
"rotate",
|
|
129765
|
-
//
|
|
129766
|
-
//
|
|
129767
|
-
// dispatched back-to-back rather than across separate round-trips.
|
|
129605
|
+
// Shake's interesting cases are races (shake while a sheet is dismissing,
|
|
129606
|
+
// shake right after typing), which need back-to-back dispatch.
|
|
129768
129607
|
"shake",
|
|
129769
|
-
// `tv-remote` drives the D-pad on a TV target (Apple TV / Android TV / Vega);
|
|
129770
|
-
// `keyboard` types into the focused field there.
|
|
129771
129608
|
"tv-remote",
|
|
129772
129609
|
AWAIT_UI_ELEMENT_TOOL_ID
|
|
129773
129610
|
]);
|
|
@@ -129793,9 +129630,8 @@ var capability22 = {
|
|
|
129793
129630
|
android: { emulator: true, device: true, unknown: true },
|
|
129794
129631
|
chromium: { app: true },
|
|
129795
129632
|
// Vega (Fire TV) is a valid target: its `tv-remote` / `keyboard` steps are
|
|
129796
|
-
// supported
|
|
129797
|
-
//
|
|
129798
|
-
// before any step runs — each step's own capability is still enforced below.
|
|
129633
|
+
// supported. Without this key the HTTP layer's `assertSupported` would reject
|
|
129634
|
+
// a Vega udid before any step runs.
|
|
129799
129635
|
vega: { vvd: true }
|
|
129800
129636
|
};
|
|
129801
129637
|
function createRunSequenceTool(registry2) {
|
|
@@ -129869,15 +129705,10 @@ Stops on the first error (or unmet await-ui-element condition) and returns parti
|
|
|
129869
129705
|
searchHint: "batch sequence multiple gesture steps sequentially",
|
|
129870
129706
|
zodSchema: zodSchema28,
|
|
129871
129707
|
capability: capability22,
|
|
129872
|
-
//
|
|
129873
|
-
// `
|
|
129874
|
-
//
|
|
129875
|
-
//
|
|
129876
|
-
// `tvos` platform) — declaring simulator-server for it would spawn a
|
|
129877
|
-
// controller it can't drive and hang on the ready timeout before any tv-*
|
|
129878
|
-
// step could run. The sub-tool invocations still pay only their own
|
|
129879
|
-
// first-step spawn cost, and `ctx` is threaded through so nested steps keep
|
|
129880
|
-
// the outer request's telemetry attribution.
|
|
129708
|
+
// Each step resolves its own services. An eager resolver can't be used
|
|
129709
|
+
// because a tvOS udid shape-classifies as `ios` (there is no `tvos`
|
|
129710
|
+
// platform), so declaring simulator-server would spawn a controller it
|
|
129711
|
+
// can't drive and hang on the ready timeout before any tv-remote step runs.
|
|
129881
129712
|
services: () => ({}),
|
|
129882
129713
|
async execute(_services, params, ctx) {
|
|
129883
129714
|
const { udid, steps } = params;
|
|
@@ -130025,16 +129856,15 @@ var NOT_CONNECTED_CODE_MAP = {
|
|
|
130025
129856
|
[FAILURE_CODES.DEBUGGER_CDP_SOCKET_CLOSED_BEFORE_OPEN]: "cdp_unreachable",
|
|
130026
129857
|
[FAILURE_CODES.DEBUGGER_CDP_NOT_CONNECTED]: "cdp_unreachable",
|
|
130027
129858
|
[FAILURE_CODES.DEBUGGER_CDP_CONNECTION_CLOSED]: "cdp_unreachable",
|
|
130028
|
-
//
|
|
130029
|
-
// accepts the socket but its JS runtime never answers
|
|
130030
|
-
//
|
|
130031
|
-
//
|
|
129859
|
+
// Raised by the connect pipeline's enable/binding sends when the target
|
|
129860
|
+
// accepts the socket but its JS runtime never answers. A post-connect hang
|
|
129861
|
+
// differs: the OPEN socket still reports status "connected" (see the
|
|
129862
|
+
// socket-state gate in debugger-status).
|
|
130032
129863
|
[FAILURE_CODES.DEBUGGER_CDP_REQUEST_TIMEOUT]: "runtime_unresponsive",
|
|
130033
129864
|
[FAILURE_CODES.CHROMIUM_CDP_UNREACHABLE]: "cdp_unreachable",
|
|
130034
|
-
//
|
|
130035
|
-
//
|
|
130036
|
-
//
|
|
130037
|
-
// actually answered), so it must not escape as a thrown tool failure.
|
|
129865
|
+
// Reached but not CDP: a squatter on the debug port, an HTTP error status, or
|
|
129866
|
+
// a non-JSON body — the same precondition class as the Metro arm's non-Metro
|
|
129867
|
+
// occupant, so it must not escape as a thrown tool failure.
|
|
130038
129868
|
[FAILURE_CODES.CHROMIUM_CDP_INVALID_RESPONSE]: "cdp_unreachable",
|
|
130039
129869
|
[FAILURE_CODES.CHROMIUM_CDP_NO_PAGE_TARGET]: "cdp_unreachable",
|
|
130040
129870
|
[FAILURE_CODES.REGISTRY_SERVICE_TERMINATING]: "reconnecting"
|
|
@@ -130103,7 +129933,7 @@ Use when you need to verify connectivity before using other debugger tools. Neve
|
|
|
130103
129933
|
zodSchema: zodSchema30,
|
|
130104
129934
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
130105
129935
|
// Resolved manually in execute so a not-connected precondition becomes a
|
|
130106
|
-
// structured result instead of a
|
|
129936
|
+
// structured result instead of a tool failure.
|
|
130107
129937
|
services: () => ({}),
|
|
130108
129938
|
async execute(_services, params, ctx) {
|
|
130109
129939
|
try {
|
|
@@ -130226,11 +130056,8 @@ var debuggerReloadMetroTool = {
|
|
|
130226
130056
|
description: `Restart the Metro JS bundle in the connected React Native app without restarting the native process.
|
|
130227
130057
|
Use when you want to apply code changes or reset JS state. Returns { reloaded, port, method, deviceName, appName, logicalDeviceId } indicating which reload path was used and which device/app was targeted. Fails if Metro is not running on the given port.`,
|
|
130228
130058
|
zodSchema: zodSchema32,
|
|
130229
|
-
//
|
|
130230
|
-
//
|
|
130231
|
-
// — preserving the URL but re-fetching index.html, blowing away in-memory
|
|
130232
|
-
// app state — that calling it under the same tool name would mislead. If we
|
|
130233
|
-
// want that on Chromium later, it deserves its own tool.
|
|
130059
|
+
// RN-only: reloading a Chromium page is a different operation from restarting
|
|
130060
|
+
// the Metro bundle, so it would need its own tool.
|
|
130234
130061
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
130235
130062
|
services: (params) => ({
|
|
130236
130063
|
debugger: `JsRuntimeDebugger:${params.port}:${canonicalDeviceId(params.device_id)}`
|
|
@@ -131075,9 +130902,8 @@ Use when you need tap coordinates for a React Native UI element. Returns a compa
|
|
|
131075
130902
|
alwaysLoad: true,
|
|
131076
130903
|
searchHint: "react native component tree discovery tap coordinates",
|
|
131077
130904
|
zodSchema: zodSchema33,
|
|
131078
|
-
// RN-only:
|
|
131079
|
-
//
|
|
131080
|
-
// for DOM-tree discovery on Chromium.
|
|
130905
|
+
// RN-only: needs the React DevTools backend from the dev JS bundle. Chromium has
|
|
130906
|
+
// no equivalent — use `describe` there.
|
|
131081
130907
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
131082
130908
|
services: (params) => ({
|
|
131083
130909
|
debugger: `JsRuntimeDebugger:${params.port}:${canonicalDeviceId(params.device_id)}`
|
|
@@ -131445,7 +131271,6 @@ var SKIP_SET = /* @__PURE__ */ new Set([
|
|
|
131445
131271
|
"TextInputLabel",
|
|
131446
131272
|
"ThemeContext",
|
|
131447
131273
|
"BaseHTMLEngineProvider",
|
|
131448
|
-
// Fabric / cross-app entries
|
|
131449
131274
|
"VScrollViewNativeComponent",
|
|
131450
131275
|
"InnerScreen",
|
|
131451
131276
|
"ScreenStackItem",
|
|
@@ -131584,10 +131409,8 @@ Set resolveSourceMaps to false to skip symbolication and get raw bundled locatio
|
|
|
131584
131409
|
Set includeSkipped=true to see filtered items annotated with skip reasons.
|
|
131585
131410
|
Use when you need the source file and line for a component at a tap coordinate. Fails if the app is not connected or the coordinate is outside the screen.`,
|
|
131586
131411
|
zodSchema: zodSchema34,
|
|
131587
|
-
// RN-only:
|
|
131588
|
-
// Metro's /symbolicate
|
|
131589
|
-
// for "what's here?" but the source-map flow would need a complete rewrite —
|
|
131590
|
-
// out of scope for this port.
|
|
131412
|
+
// RN-only: needs React Native's internal getInspectorDataForViewAtPoint and
|
|
131413
|
+
// Metro's /symbolicate; the Chromium session has no source resolver.
|
|
131591
131414
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
131592
131415
|
services: (params) => ({
|
|
131593
131416
|
debugger: `JsRuntimeDebugger:${params.port}:${canonicalDeviceId(params.device_id)}`
|
|
@@ -131827,8 +131650,6 @@ On React Native (iOS / Android / Vega) interception is injected into the JS runt
|
|
|
131827
131650
|
Use when inspecting outbound HTTP traffic or debugging API calls in the running app.
|
|
131828
131651
|
Fails if the app is not connected (RN) or the device is not reachable (Chromium).`,
|
|
131829
131652
|
zodSchema: zodSchema36,
|
|
131830
|
-
// Works on RN (Metro-injected interceptor) and Chromium (native CDP Network
|
|
131831
|
-
// domain), dispatched on the device id in `services` / `execute`.
|
|
131832
131653
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
131833
131654
|
services: (params) => {
|
|
131834
131655
|
const device = resolveDevice(params.device_id);
|
|
@@ -131917,8 +131738,6 @@ Returns request/response headers (sensitive headers redacted), status, timing, a
|
|
|
131917
131738
|
Large response bodies are truncated. Use when you need headers, body, or timing for a specific request after listing logs.
|
|
131918
131739
|
Returns an error message string if the requestId is not found \u2014 use view-network-logs to get valid requestId values.`,
|
|
131919
131740
|
zodSchema: zodSchema37,
|
|
131920
|
-
// Companion to view-network-logs: RN via the injected interceptor, Chromium
|
|
131921
|
-
// via the native CDP Network recording. Dispatched on the device id.
|
|
131922
131741
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
131923
131742
|
services: (params) => {
|
|
131924
131743
|
const device = resolveDevice(params.device_id);
|
|
@@ -132029,10 +131848,9 @@ init_zod();
|
|
|
132029
131848
|
|
|
132030
131849
|
// ../tool-server/src/tools/describe/format-tree.ts
|
|
132031
131850
|
var CONTENT_ROLES = /* @__PURE__ */ new Set([
|
|
132032
|
-
//
|
|
132033
|
-
//
|
|
132034
|
-
//
|
|
132035
|
-
// groupings out of the output.
|
|
131851
|
+
// The roles mapNativeTraitsToDescribeRole can return. AXGroup is excluded on
|
|
131852
|
+
// purpose: as its catch-all fallback, requiring it to carry its own
|
|
131853
|
+
// label/value before we emit a line keeps decorative groupings out.
|
|
132036
131854
|
"AXButton",
|
|
132037
131855
|
"AXStaticText",
|
|
132038
131856
|
"AXImage",
|
|
@@ -132261,10 +132079,9 @@ function makeDescribeExecute(registry2) {
|
|
|
132261
132079
|
)
|
|
132262
132080
|
},
|
|
132263
132081
|
iosRemote: {
|
|
132264
|
-
//
|
|
132265
|
-
//
|
|
132266
|
-
//
|
|
132267
|
-
// (never tvOS), so the isTvOs verdict is always false.
|
|
132082
|
+
// Both the ax-service and native-devtools blueprints route through
|
|
132083
|
+
// sim-remote for an ios-remote device, so only the preflight dep differs
|
|
132084
|
+
// from the ios branch.
|
|
132268
132085
|
requires: ["sim-remote"],
|
|
132269
132086
|
handler: async (_services, params, device) => withDescription(
|
|
132270
132087
|
withBootCaveatOncePerDevice(
|
|
@@ -132276,9 +132093,8 @@ function makeDescribeExecute(registry2) {
|
|
|
132276
132093
|
android: {
|
|
132277
132094
|
requires: androidRequires,
|
|
132278
132095
|
handler: async (_services, params, device) => (
|
|
132279
|
-
// Resolve the form factor once and
|
|
132280
|
-
//
|
|
132281
|
-
// known `isTv: false` through so describeAndroid doesn't re-probe.
|
|
132096
|
+
// Resolve the form factor once and thread the known `isTv: false`
|
|
132097
|
+
// through so describeAndroid doesn't re-probe.
|
|
132282
132098
|
await isAndroidTv(device.id) ? describeTv(registry2, device) : withDescription(await describeAndroid(registry2, params.udid, params.bundleId, false))
|
|
132283
132099
|
)
|
|
132284
132100
|
},
|
|
@@ -132534,9 +132350,6 @@ After starting, ask the user to perform the interaction to profile, then call re
|
|
|
132534
132350
|
Returns { started_at, startedAtEpochMs, hermes_version, detected_architecture } on success, or the already_running payload described above.
|
|
132535
132351
|
Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot be established.`,
|
|
132536
132352
|
zodSchema: zodSchema40,
|
|
132537
|
-
// RN-only: bootstraps the React DevTools backend and uses Hermes'
|
|
132538
|
-
// Profiler.start. A CDP-direct CPU profile for Chromium is tracked as a
|
|
132539
|
-
// follow-up; the React commit recording has no Chromium analog.
|
|
132540
132353
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
132541
132354
|
services: () => ({}),
|
|
132542
132355
|
async execute(_services, params) {
|
|
@@ -132681,8 +132494,8 @@ Fails if the Hermes runtime is not reachable or the Metro CDP connection cannot
|
|
|
132681
132494
|
const sessionId = crypto6.randomUUID();
|
|
132682
132495
|
const ownerPayload = {
|
|
132683
132496
|
sessionId,
|
|
132684
|
-
//
|
|
132685
|
-
//
|
|
132497
|
+
// Set inside the start script from the wrapper-captured clock, to
|
|
132498
|
+
// eliminate skew.
|
|
132686
132499
|
startedAtEpochMs: 0,
|
|
132687
132500
|
lastHeartbeatEpochMs: 0
|
|
132688
132501
|
};
|
|
@@ -132896,7 +132709,6 @@ Returns { duration_ms, sample_count, fiber_renders_captured, total_react_commits
|
|
|
132896
132709
|
When any commit had fibers whose display name could not be resolved at stop time (typically transient components like modals/tooltips/animations that unmounted before stop), the response also includes { unattributed_ms, unattributed_fiber_count, unattributed_commit_count } \u2014 these quantify how much work is not accounted for in the per-component breakdown (the per-commit duration itself remains correct).
|
|
132897
132710
|
Fails if no active profiling session exists or the CDP connection was lost during recording.`,
|
|
132898
132711
|
zodSchema: zodSchema41,
|
|
132899
|
-
// RN-only: companion to react-profiler-start.
|
|
132900
132712
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
132901
132713
|
services: () => ({}),
|
|
132902
132714
|
async execute(_services, params) {
|
|
@@ -132935,10 +132747,8 @@ Fails if no active profiling session exists or the CDP connection was lost durin
|
|
|
132935
132747
|
error_code: FAILURE_CODES.REACT_PROFILER_NO_ACTIVE_SESSION,
|
|
132936
132748
|
failure_stage: "react_profiler_stop_inactive",
|
|
132937
132749
|
failure_area: "tool_server",
|
|
132938
|
-
// Internal session-state
|
|
132939
|
-
//
|
|
132940
|
-
// native NATIVE_PROFILER_NO_ACTIVE_SESSION so this code carries one
|
|
132941
|
-
// consistent kind rather than splitting by which guard tripped.
|
|
132750
|
+
// Internal session-state, not caller input — matches the session-lookup
|
|
132751
|
+
// site above and the native NATIVE_PROFILER_NO_ACTIVE_SESSION twin.
|
|
132942
132752
|
error_kind: "not_found"
|
|
132943
132753
|
}
|
|
132944
132754
|
);
|
|
@@ -134047,7 +133857,7 @@ async function runPipeline(input, options) {
|
|
|
134047
133857
|
allClear: input.sessionMeta.allClear ?? false,
|
|
134048
133858
|
maxCommitMs: input.sessionMeta.maxCommitMs,
|
|
134049
133859
|
anyRuntimeCompilerDetected: tagOutput.anyRuntimeCompilerDetected,
|
|
134050
|
-
//
|
|
133860
|
+
// The all-clear path keeps no commits, so tagOutput.reactCommits is 0
|
|
134051
133861
|
reactCommits: input.sessionMeta.totalReactCommits ?? tagOutput.reactCommits,
|
|
134052
133862
|
fiberRenders: tagOutput.fiberRenders,
|
|
134053
133863
|
totalFirstMounts: tagOutput.totalFirstMounts,
|
|
@@ -134743,8 +134553,8 @@ async function writeReport(path41, content) {
|
|
|
134743
134553
|
}
|
|
134744
134554
|
|
|
134745
134555
|
// ../tool-server/src/tools/profiler/react/react-profiler-analyze.ts
|
|
134746
|
-
async function fileArtifact(store, p) {
|
|
134747
|
-
return p ? store.register(p) : null;
|
|
134556
|
+
async function fileArtifact(store, p, kind) {
|
|
134557
|
+
return p ? store.register({ hostPath: p, kind }) : null;
|
|
134748
134558
|
}
|
|
134749
134559
|
var annotationSchema = external_exports.object({
|
|
134750
134560
|
offsetMs: external_exports.coerce.number().describe(
|
|
@@ -134786,8 +134596,8 @@ is returned by react-profiler-start.
|
|
|
134786
134596
|
Use when the profiling session is complete and you need to interpret the collected data.
|
|
134787
134597
|
Fails if react-profiler-stop has not been called or no profiling data is stored.`,
|
|
134788
134598
|
zodSchema: zodSchema43,
|
|
134789
|
-
// RN-only:
|
|
134790
|
-
//
|
|
134599
|
+
// RN-only: reads commit data captured via the React DevTools backend, which
|
|
134600
|
+
// Chromium does not have.
|
|
134791
134601
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
134792
134602
|
services: () => ({}),
|
|
134793
134603
|
async execute(_services, params, ctx) {
|
|
@@ -134903,13 +134713,13 @@ Fails if react-profiler-stop has not been called or no profiling data is stored.
|
|
|
134903
134713
|
const artifacts = requireArtifacts(ctx);
|
|
134904
134714
|
const result = {
|
|
134905
134715
|
report,
|
|
134906
|
-
reportFile: await fileArtifact(artifacts, reportFile),
|
|
134716
|
+
reportFile: await fileArtifact(artifacts, reportFile, "react-profile-report"),
|
|
134907
134717
|
hotCommitsTotal,
|
|
134908
134718
|
hotCommitsShown,
|
|
134909
134719
|
sessionFiles: {
|
|
134910
134720
|
sessionId: sessionPaths.sessionId,
|
|
134911
|
-
cpuProfile: await fileArtifact(artifacts, sessionPaths.cpuProfilePath),
|
|
134912
|
-
commits: await fileArtifact(artifacts, sessionPaths.commitsPath)
|
|
134721
|
+
cpuProfile: await fileArtifact(artifacts, sessionPaths.cpuProfilePath, "react-profile-cpu"),
|
|
134722
|
+
commits: await fileArtifact(artifacts, sessionPaths.commitsPath, "react-profile-commits")
|
|
134913
134723
|
}
|
|
134914
134724
|
};
|
|
134915
134725
|
if (hotCommitIndices === null) {
|
|
@@ -134941,12 +134751,9 @@ Call this per-finding after react-profiler-analyze to inspect source before prop
|
|
|
134941
134751
|
Returns found: false if the component is not found in user-owned code (e.g. lives in node_modules).
|
|
134942
134752
|
When several files define a component with the same name (e.g. platform variants like List.tsx and List.web.tsx), returns the primary match and lists the rest under otherMatches[] (file/line/col) \u2014 check it before assuming the returned file is the one you meant.`,
|
|
134943
134753
|
zodSchema: zodSchema44,
|
|
134944
|
-
//
|
|
134945
|
-
//
|
|
134946
|
-
//
|
|
134947
|
-
// there's nothing for the gate to inspect). An LLM agent reading the tool
|
|
134948
|
-
// catalogue should see this is paired with the other react-profiler tools
|
|
134949
|
-
// and not reach for it on a Chromium app.
|
|
134754
|
+
// Declared so the tool catalogue groups this with the other react-profiler-*
|
|
134755
|
+
// tools; the HTTP gate itself is a no-op here, as there is no device arg to
|
|
134756
|
+
// inspect.
|
|
134950
134757
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
134951
134758
|
fileInputs,
|
|
134952
134759
|
services: () => ({}),
|
|
@@ -134980,8 +134787,8 @@ When several files define a component with the same name (e.g. platform variants
|
|
|
134980
134787
|
}
|
|
134981
134788
|
return {
|
|
134982
134789
|
found: true,
|
|
134983
|
-
// The key that
|
|
134984
|
-
//
|
|
134790
|
+
// The key that matched, so the caller sees when a wrapped name resolved
|
|
134791
|
+
// through to a bare source identifier.
|
|
134985
134792
|
component: matchedKey ?? params.component_name,
|
|
134986
134793
|
requested: params.component_name,
|
|
134987
134794
|
file: entry.file,
|
|
@@ -135082,9 +134889,7 @@ Call react-profiler-stop first. Reads directly from the stored cpuProfile.
|
|
|
135082
134889
|
Returns a markdown table of the top hotspot functions with self-time, total-time, and location.
|
|
135083
134890
|
Fails if react-profiler-stop has not been called or no CPU profile is stored.`,
|
|
135084
134891
|
zodSchema: zodSchema45,
|
|
135085
|
-
// RN-only: reads a Hermes CPU profile
|
|
135086
|
-
// session. Chromium's V8 Profiler emits a different sample format — see the
|
|
135087
|
-
// PR description for the follow-up scope.
|
|
134892
|
+
// RN-only: reads a Hermes CPU profile; Chromium's V8 sample format differs.
|
|
135088
134893
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
135089
134894
|
services: () => ({}),
|
|
135090
134895
|
async execute(_services, params) {
|
|
@@ -135793,11 +135598,8 @@ async function execFileAsyncWithTimeout(file2, args, options = {}) {
|
|
|
135793
135598
|
const { stdout, stderr } = await execFileAsync25(file2, args, {
|
|
135794
135599
|
encoding: "utf-8",
|
|
135795
135600
|
...options,
|
|
135796
|
-
//
|
|
135797
|
-
//
|
|
135798
|
-
// applied AFTER ...options — a caller can never silently weaken them by
|
|
135799
|
-
// passing its own. maxBuffer stays a floor: a caller may raise it for an
|
|
135800
|
-
// even larger capture, but never drop below the 256 MiB guard.
|
|
135601
|
+
// Applied after ...options so a caller cannot weaken the guards; maxBuffer
|
|
135602
|
+
// is a floor, so a caller may still raise it for a larger capture.
|
|
135801
135603
|
timeout: DEFAULT_EXEC_TIMEOUT_MS,
|
|
135802
135604
|
maxBuffer: Math.max(options.maxBuffer ?? 0, DEFAULT_EXEC_MAX_BUFFER)
|
|
135803
135605
|
});
|
|
@@ -135882,7 +135684,11 @@ async function tryCpuExportFallback(traceFile, outPath, diagnostics) {
|
|
|
135882
135684
|
return false;
|
|
135883
135685
|
}
|
|
135884
135686
|
async function exportIosTraceData(traceFile) {
|
|
135885
|
-
const exportedFiles = {
|
|
135687
|
+
const exportedFiles = {
|
|
135688
|
+
cpu: null,
|
|
135689
|
+
hangs: null,
|
|
135690
|
+
leaks: null
|
|
135691
|
+
};
|
|
135886
135692
|
const diagnostics = {
|
|
135887
135693
|
tocSchemas: [],
|
|
135888
135694
|
cpuSchemaUsed: null,
|
|
@@ -135890,7 +135696,8 @@ async function exportIosTraceData(traceFile) {
|
|
|
135890
135696
|
};
|
|
135891
135697
|
const dir = path23.dirname(traceFile);
|
|
135892
135698
|
const baseName = path23.basename(traceFile, ".trace");
|
|
135893
|
-
for (const
|
|
135699
|
+
for (const key2 of Object.keys(EXPORTS)) {
|
|
135700
|
+
const config2 = EXPORTS[key2];
|
|
135894
135701
|
const outPath = path23.join(dir, `${baseName}${config2.suffix}`);
|
|
135895
135702
|
if (key2 === "cpu") {
|
|
135896
135703
|
const resolvedXpath = await resolveCpuXpath(traceFile, diagnostics);
|
|
@@ -136345,8 +136152,7 @@ function aggregateCpuHotspots(rows, options) {
|
|
|
136345
136152
|
duringHang,
|
|
136346
136153
|
timeRangeMs: { first: firstMs, last: lastMs },
|
|
136347
136154
|
burstWindows,
|
|
136348
|
-
//
|
|
136349
|
-
// hotspot object shape byte-identical to before this change.
|
|
136155
|
+
// Omit the key on iOS rather than emitting `dominantMapping: undefined`.
|
|
136350
136156
|
...acc.dominantMapping !== void 0 ? { dominantMapping: acc.dominantMapping } : {}
|
|
136351
136157
|
});
|
|
136352
136158
|
}
|
|
@@ -136760,17 +136566,16 @@ var SYSTEM_FRAME_PATTERNS = [
|
|
|
136760
136566
|
/gfxstream/i,
|
|
136761
136567
|
/rcCreateSync/,
|
|
136762
136568
|
/_enc\b/,
|
|
136763
|
-
//
|
|
136569
|
+
// emulator GL/Vulkan encoder trampolines
|
|
136764
136570
|
// Linux kernel syscall entry + mm/vfs internals (no app symbol to act on).
|
|
136765
136571
|
// x86-64 entry path:
|
|
136766
136572
|
/\bdo_syscall_64\b/,
|
|
136767
136573
|
/\bentry_SYSCALL/,
|
|
136768
136574
|
/\b__x64_sys_/,
|
|
136769
136575
|
/\bx64_sys_call\b/,
|
|
136770
|
-
// arm64
|
|
136771
|
-
//
|
|
136772
|
-
//
|
|
136773
|
-
// SVC (syscall) handler, which calls invoke_syscall → __arm64_sys_<name>.
|
|
136576
|
+
// arm64 entry path, named nothing like the x86 one: the EL0
|
|
136577
|
+
// synchronous-exception vector dispatches to the SVC (syscall) handler, which
|
|
136578
|
+
// calls invoke_syscall → __arm64_sys_<name>.
|
|
136774
136579
|
// arch/arm64/kernel/{entry.S,entry-common.c,syscall.c}.
|
|
136775
136580
|
/\b__arm64_sys_/,
|
|
136776
136581
|
/\bel0t_64_sync(_handler)?\b/,
|
|
@@ -136780,9 +136585,9 @@ var SYSTEM_FRAME_PATTERNS = [
|
|
|
136780
136585
|
/\bdo_el0_svc\b/,
|
|
136781
136586
|
/\binvoke_syscall\b/,
|
|
136782
136587
|
/\bel0_(da|ia)\b/,
|
|
136783
|
-
// data / instruction abort
|
|
136588
|
+
// data / instruction abort (page-fault) handlers
|
|
136784
136589
|
/\b__arch_copy_(from|to)_user\b/,
|
|
136785
|
-
// arm64 uaccess copy helpers
|
|
136590
|
+
// arm64 uaccess copy helpers
|
|
136786
136591
|
/\bksys_/,
|
|
136787
136592
|
/\bvfs_(read|write|fsync)\b/,
|
|
136788
136593
|
/\bgup_/,
|
|
@@ -137307,8 +137112,8 @@ function resolveDefaultTemplatePath() {
|
|
|
137307
137112
|
${candidates.map((c) => ` - ${c}`).join("\n")}
|
|
137308
137113
|
Pass template_path explicitly, or rebuild so the template is copied into place.`,
|
|
137309
137114
|
{
|
|
137310
|
-
// A
|
|
137311
|
-
//
|
|
137115
|
+
// A missing bundled asset is a packaging/build problem, not a device or
|
|
137116
|
+
// subprocess failure.
|
|
137312
137117
|
error_code: FAILURE_CODES.NATIVE_PROFILER_TRACE_TEMPLATE_MISSING,
|
|
137313
137118
|
failure_stage: "ios_native_profiler_template_resolve",
|
|
137314
137119
|
failure_area: "tool_server",
|
|
@@ -137845,8 +137650,7 @@ async function stopNativeProfilerIos(api) {
|
|
|
137845
137650
|
failure_stage: "native_profiler_stop_session_state",
|
|
137846
137651
|
failure_area: "tool_server",
|
|
137847
137652
|
// Internal session-state, not caller input — matches the react twin
|
|
137848
|
-
// REACT_PROFILER_NO_ACTIVE_SESSION
|
|
137849
|
-
// "no active session" family carries one consistent kind.
|
|
137653
|
+
// REACT_PROFILER_NO_ACTIVE_SESSION and the Android site.
|
|
137850
137654
|
error_kind: "not_found"
|
|
137851
137655
|
}
|
|
137852
137656
|
);
|
|
@@ -137922,13 +137726,12 @@ async function analyzeNativeProfilerIos(api) {
|
|
|
137922
137726
|
uiHangs,
|
|
137923
137727
|
cpuHotspots,
|
|
137924
137728
|
memoryLeaks,
|
|
137925
|
-
// Freeze the
|
|
137926
|
-
//
|
|
137927
|
-
//
|
|
137729
|
+
// Freeze the capture mode with the parsed data so drill-down consumers
|
|
137730
|
+
// (leak_stacks, combined report) stay paired with it after a newer capture
|
|
137731
|
+
// re-stamps the session fields.
|
|
137928
137732
|
mallocStackLogging: api.mallocStackLogging,
|
|
137929
|
-
// Freeze the
|
|
137930
|
-
//
|
|
137931
|
-
// a later native-profiler-start re-stamps onto the live session field.
|
|
137733
|
+
// Freeze the start time too — the combined report anchors these hangs to
|
|
137734
|
+
// wall-clock time and must use THIS capture's start, not a later one's.
|
|
137932
137735
|
wallClockStartMs: api.wallClockStartMs
|
|
137933
137736
|
};
|
|
137934
137737
|
const exportErrors = {};
|
|
@@ -137957,21 +137760,17 @@ async function analyzeNativeProfilerIos(api) {
|
|
|
137957
137760
|
payload,
|
|
137958
137761
|
traceFile: api.traceFile,
|
|
137959
137762
|
exportErrors,
|
|
137960
|
-
//
|
|
137961
|
-
//
|
|
137962
|
-
// trace from an earlier capture in this same process run, not a fresh one.
|
|
137763
|
+
// A large gap between the in-memory start time and "now" means analyze is reusing
|
|
137764
|
+
// a trace from an earlier capture in this same process run, not a fresh one.
|
|
137963
137765
|
//
|
|
137964
|
-
//
|
|
137965
|
-
//
|
|
137966
|
-
//
|
|
137967
|
-
//
|
|
137968
|
-
// for one restored from disk. Restoring iOS start-time across loads needs an
|
|
137969
|
-
// iOS sidecar this Android-scoped change does not add; formatTraceFreshness
|
|
137970
|
-
// degrades cleanly to null in that case. See test/ios-instruments/load-freshness.test.ts.
|
|
137766
|
+
// iOS, unlike Android, has no on-disk metadata sidecar, so profiler-load (raw_*.xml
|
|
137767
|
+
// only) cannot recover the start time: wallClockStartMs is null for a loaded
|
|
137768
|
+
// session, formatTraceFreshness returns null, and the note stays off. See
|
|
137769
|
+
// test/ios-instruments/load-freshness.test.ts.
|
|
137971
137770
|
freshnessNote: formatTraceFreshness(api.wallClockStartMs, Date.now()) ?? void 0,
|
|
137972
137771
|
// Same live-session-only caveat as wallClockStartMs: profiler-load has no
|
|
137973
137772
|
// capture-mode sidecar, so a restored session renders with null (the
|
|
137974
|
-
// unattributed-leaks note then
|
|
137773
|
+
// unattributed-leaks note then goes by the attributed-leak count instead).
|
|
137975
137774
|
mallocStackLogging: api.mallocStackLogging
|
|
137976
137775
|
});
|
|
137977
137776
|
}
|
|
@@ -138819,20 +138618,18 @@ function cpuRowsToAggregatorRows(rows, traceStartNs) {
|
|
|
138819
138618
|
const thread = normaliseAndroidThread(row.thread_name, row.is_main_thread === 1);
|
|
138820
138619
|
out.push({
|
|
138821
138620
|
dominantFunction: dominant,
|
|
138822
|
-
//
|
|
138823
|
-
// threaded through so classifyNativeFrame can recognise `/kernel` leaves.
|
|
138621
|
+
// Threaded through so classifyNativeFrame can recognise `/kernel` leaves.
|
|
138824
138622
|
...row.leaf_mapping != null ? { dominantMapping: row.leaf_mapping } : {},
|
|
138825
138623
|
thread,
|
|
138826
138624
|
weightNs: row.sample_count * SAMPLE_PERIOD_NS,
|
|
138827
|
-
//
|
|
138828
|
-
//
|
|
138625
|
+
// Bursts are precomputed in SQL, so no raw timestamps ship; the aggregator's
|
|
138626
|
+
// duringHang stays false (Android never passes hangSampleTimestamps).
|
|
138829
138627
|
timestampsNs: [],
|
|
138830
138628
|
callChains: [{ chain: [dominant], count: row.sample_count }],
|
|
138831
138629
|
precomputedBursts: parseBurstWindows(row.burst_windows, traceStartMs),
|
|
138832
|
-
//
|
|
138833
|
-
//
|
|
138834
|
-
//
|
|
138835
|
-
// avoid "Cannot mix BigInt and other types" — values stay integral.
|
|
138630
|
+
// Absolute CLOCK_MONOTONIC ns passes 2^53 after ~104 days of uptime and
|
|
138631
|
+
// readCell hands those back as bigint — coerce before mixing with the
|
|
138632
|
+
// plain-Number traceStartNs.
|
|
138836
138633
|
firstMs: Math.round((Number(row.first_ts_ns) - traceStartNs) / 1e6),
|
|
138837
138634
|
lastMs: Math.round((Number(row.last_ts_ns) - traceStartNs) / 1e6),
|
|
138838
138635
|
sampleCount: row.sample_count
|
|
@@ -139054,8 +138851,8 @@ async function stopNativeProfilerAndroid(api) {
|
|
|
139054
138851
|
failure_stage: "android_native_profiler_stop",
|
|
139055
138852
|
failure_area: "tool_server",
|
|
139056
138853
|
// Internal session-state, not caller input — matches the react twin
|
|
139057
|
-
// REACT_PROFILER_NO_ACTIVE_SESSION
|
|
139058
|
-
//
|
|
138854
|
+
// REACT_PROFILER_NO_ACTIVE_SESSION so the "no active session" family
|
|
138855
|
+
// carries one consistent kind.
|
|
139059
138856
|
error_kind: "not_found"
|
|
139060
138857
|
}
|
|
139061
138858
|
);
|
|
@@ -139093,7 +138890,8 @@ async function stopNativeProfilerAndroid(api) {
|
|
|
139093
138890
|
api.lastExitInfo = null;
|
|
139094
138891
|
}
|
|
139095
138892
|
const { hostTracePath, warning } = stopResult;
|
|
139096
|
-
|
|
138893
|
+
const exportedFiles = { pftrace: hostTracePath };
|
|
138894
|
+
api.exportedFiles = exportedFiles;
|
|
139097
138895
|
if (api.appProcess) {
|
|
139098
138896
|
await writeAndroidNativeProfilerMetadata(hostTracePath, {
|
|
139099
138897
|
platform: "android",
|
|
@@ -139103,7 +138901,7 @@ async function stopNativeProfilerAndroid(api) {
|
|
|
139103
138901
|
}
|
|
139104
138902
|
const result = {
|
|
139105
138903
|
traceFile: hostTracePath,
|
|
139106
|
-
exportedFiles
|
|
138904
|
+
exportedFiles
|
|
139107
138905
|
};
|
|
139108
138906
|
if (warning) result.warning = warning;
|
|
139109
138907
|
return result;
|
|
@@ -139148,9 +138946,8 @@ async function analyzeNativeProfilerAndroid(api) {
|
|
|
139148
138946
|
payload,
|
|
139149
138947
|
traceFile: hostTracePath,
|
|
139150
138948
|
exportErrors: pipelineResult.exportErrors,
|
|
139151
|
-
//
|
|
139152
|
-
//
|
|
139153
|
-
// means we're analyzing a trace from an earlier session, not a fresh capture.
|
|
138949
|
+
// Recording start time, persisted in the metadata sidecar and restored by
|
|
138950
|
+
// profiler-load, so a large gap to "now" means an earlier session's trace.
|
|
139154
138951
|
freshnessNote: formatTraceFreshness(api.wallClockStartMs, Date.now()) ?? void 0,
|
|
139155
138952
|
// Explains an absent CPU section when samples exist but carry no stacks.
|
|
139156
138953
|
cpuDiagnostic: pipelineResult.cpuDiagnostic
|
|
@@ -139224,15 +139021,22 @@ var capability26 = {
|
|
|
139224
139021
|
apple: { simulator: true, device: true },
|
|
139225
139022
|
android: { emulator: true, device: true, unknown: true }
|
|
139226
139023
|
};
|
|
139024
|
+
var EXPORTED_FILE_KINDS = {
|
|
139025
|
+
cpu: "native-profile-cpu",
|
|
139026
|
+
hangs: "native-profile-hangs",
|
|
139027
|
+
leaks: "native-profile-leaks",
|
|
139028
|
+
pftrace: "native-profile-trace"
|
|
139029
|
+
};
|
|
139227
139030
|
async function exportedFilesToArtifacts(store, files) {
|
|
139228
139031
|
const out = {};
|
|
139229
|
-
for (const
|
|
139230
|
-
|
|
139032
|
+
for (const key2 of Object.keys(files)) {
|
|
139033
|
+
const filePath = files[key2];
|
|
139034
|
+
out[key2] = filePath ? await store.register({ hostPath: filePath, kind: EXPORTED_FILE_KINDS[key2] }) : null;
|
|
139231
139035
|
}
|
|
139232
139036
|
return out;
|
|
139233
139037
|
}
|
|
139234
139038
|
function registerTrace(store, traceFile) {
|
|
139235
|
-
return store.register(traceFile,
|
|
139039
|
+
return store.register({ hostPath: traceFile, kind: "native-profile-trace", archive: "tar.gz" });
|
|
139236
139040
|
}
|
|
139237
139041
|
var nativeProfilerStopTool = {
|
|
139238
139042
|
id: "native-profiler-stop",
|
|
@@ -139242,7 +139046,7 @@ var nativeProfilerStopTool = {
|
|
|
139242
139046
|
failedMsg: ({ failureSignal: failureSignal2 }) => `Failed to stop native profiler: ${failureSignal2.error_code}`
|
|
139243
139047
|
},
|
|
139244
139048
|
capability: capability26,
|
|
139245
|
-
// Packaging plus the export passes routinely exceed the 30s fetch timeout.
|
|
139049
|
+
// Packaging plus the export passes routinely exceed the 30s MCP fetch timeout.
|
|
139246
139050
|
longRunning: true,
|
|
139247
139051
|
description: `Stop native profiling and export trace data.
|
|
139248
139052
|
iOS: sends SIGINT to xctrace, waits for packaging, then exports CPU, hangs, and leaks XML.
|
|
@@ -139329,7 +139133,10 @@ Fails if native-profiler-stop has not been called first to export trace data.`,
|
|
|
139329
139133
|
}
|
|
139330
139134
|
return {
|
|
139331
139135
|
...result,
|
|
139332
|
-
reportFile: result.reportFile ? await requireArtifacts(ctx).register(
|
|
139136
|
+
reportFile: result.reportFile ? await requireArtifacts(ctx).register({
|
|
139137
|
+
hostPath: result.reportFile,
|
|
139138
|
+
kind: "native-profile-report"
|
|
139139
|
+
}) : null
|
|
139333
139140
|
};
|
|
139334
139141
|
}
|
|
139335
139142
|
};
|
|
@@ -139742,8 +139549,7 @@ function assertStoppableSession(api, stage) {
|
|
|
139742
139549
|
error_code: reaped2 ? FAILURE_CODES.SCREEN_RECORDING_SERVER_SHUTTING_DOWN : FAILURE_CODES.SCREEN_RECORDING_NO_ACTIVE_SESSION,
|
|
139743
139550
|
failure_stage: stage,
|
|
139744
139551
|
failure_area: "tool_server",
|
|
139745
|
-
// Session-state, not caller input — matches the profiler family's
|
|
139746
|
-
// "no active session" kind.
|
|
139552
|
+
// Session-state, not caller input — matches the profiler family's kind.
|
|
139747
139553
|
error_kind: "not_found"
|
|
139748
139554
|
}
|
|
139749
139555
|
);
|
|
@@ -139891,7 +139697,7 @@ function ffmpegArgs(opts) {
|
|
|
139891
139697
|
"-loglevel",
|
|
139892
139698
|
"warning",
|
|
139893
139699
|
// The pump feeds whole JPEGs at a fixed cadence, so the input timeline is
|
|
139894
|
-
// exactly OUTPUT_FPS — no timestamp guessing
|
|
139700
|
+
// exactly OUTPUT_FPS — no timestamp guessing.
|
|
139895
139701
|
"-f",
|
|
139896
139702
|
"image2pipe",
|
|
139897
139703
|
"-framerate",
|
|
@@ -140319,10 +140125,9 @@ Returns { status: "recording", timeLimitSeconds, outputFile } \u2014 the video i
|
|
|
140319
140125
|
Fails if a recording is already running on the device, the device is not booted, ffmpeg is not installed, or the platform cannot be recorded (tvOS, Chromium, Vega and remote simulators are unsupported).`,
|
|
140320
140126
|
searchHint: "record video screen capture movie mp4 start filming screencast",
|
|
140321
140127
|
zodSchema: zodSchema51,
|
|
140322
|
-
//
|
|
140323
|
-
//
|
|
140324
|
-
//
|
|
140325
|
-
// timeout (same reasoning as `screenshot`).
|
|
140128
|
+
// Resolved inside execute, not declared eagerly: a tvOS udid classifies as
|
|
140129
|
+
// iOS by shape, so an eager service would spawn simulator-server for a
|
|
140130
|
+
// device it cannot drive and hang on its ready timeout (as in `screenshot`).
|
|
140326
140131
|
services: (params) => ({
|
|
140327
140132
|
session: screenRecordingSessionRef(resolveDevice(params.udid))
|
|
140328
140133
|
}),
|
|
@@ -140432,10 +140237,11 @@ Fails if no recording (running or finished-but-unretrieved) exists for the given
|
|
|
140432
140237
|
assertSupported("screen-recording-stop", capability29, device);
|
|
140433
140238
|
const stopped = await stopCapture(api);
|
|
140434
140239
|
const artifacts = requireArtifacts(ctx);
|
|
140435
|
-
const video = await artifacts.register(
|
|
140240
|
+
const video = await artifacts.register({
|
|
140241
|
+
hostPath: stopped.outputFile,
|
|
140242
|
+
kind: "screen-recording",
|
|
140436
140243
|
mimeType: "video/mp4",
|
|
140437
|
-
// Drop the internal `argent-` temp prefix
|
|
140438
|
-
// as `.argent/recordings/screen-recording-<device>-<ts>.mp4`.
|
|
140244
|
+
// Drop the internal `argent-` temp-file prefix from the saved name.
|
|
140439
140245
|
filename: (0, import_node_path20.basename)(stopped.outputFile).replace(/^argent-/, ""),
|
|
140440
140246
|
saveDir: RECORDINGS_DIR
|
|
140441
140247
|
});
|
|
@@ -140749,8 +140555,7 @@ Use when investigating JS CPU hotspots or correlating CPU cost with specific com
|
|
|
140749
140555
|
Returns a markdown table of CPU hotspots, call tree, or per-component CPU breakdown.
|
|
140750
140556
|
Fails if no CPU profile is stored \u2014 run react-profiler-stop first.`,
|
|
140751
140557
|
zodSchema: zodSchema53,
|
|
140752
|
-
// RN-only: reads Hermes-format CPU profiles
|
|
140753
|
-
// different — see the PR description for the follow-up scope.
|
|
140558
|
+
// RN-only: reads Hermes-format CPU profiles; Chromium's V8 sample format differs.
|
|
140754
140559
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
140755
140560
|
services: () => ({}),
|
|
140756
140561
|
async execute(_services, params) {
|
|
@@ -141109,7 +140914,7 @@ Use when drilling into specific components or time windows after react-profiler-
|
|
|
141109
140914
|
Returns a markdown table or tree of commit data matching the requested mode.
|
|
141110
140915
|
Fails if react-profiler-stop has not been called or no commit data is stored.`,
|
|
141111
140916
|
zodSchema: zodSchema54,
|
|
141112
|
-
//
|
|
140917
|
+
// Reads React commit data captured via the React DevTools backend.
|
|
141113
140918
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
141114
140919
|
services: () => ({}),
|
|
141115
140920
|
async execute(_services, params) {
|
|
@@ -141497,9 +141302,7 @@ Use when drilling into native hang stacks, thread CPU breakdown, or memory leaks
|
|
|
141497
141302
|
Returns a markdown report with native call stacks, thread weights, or leak details for the selected mode.
|
|
141498
141303
|
Fails if native-profiler-analyze has not been run or no parsed trace data is in memory.`,
|
|
141499
141304
|
zodSchema: zodSchema55,
|
|
141500
|
-
//
|
|
141501
|
-
// in-process trace-processor engine (see executeAndroid). Chromium has no
|
|
141502
|
-
// native trace capture.
|
|
141305
|
+
// No chromium entry: it has no native trace capture.
|
|
141503
141306
|
capability: {
|
|
141504
141307
|
apple: { simulator: true, device: true },
|
|
141505
141308
|
android: { emulator: true, device: true, unknown: true }
|
|
@@ -141581,9 +141384,8 @@ Call this tool when both profilers were run in parallel on the same session.
|
|
|
141581
141384
|
Returns a markdown report correlating hangs with React commits, memory leaks, and investigation hints.
|
|
141582
141385
|
Fails if either react-profiler-analyze or native-profiler-analyze has not been called first.`,
|
|
141583
141386
|
zodSchema: zodSchema56,
|
|
141584
|
-
//
|
|
141585
|
-
//
|
|
141586
|
-
// capture half exists on neither platform's Chromium.
|
|
141387
|
+
// iOS reads xctrace output; Android re-queries the Perfetto .pftrace via
|
|
141388
|
+
// loadAndroidCombinedData. Chromium has no native trace capture.
|
|
141587
141389
|
capability: {
|
|
141588
141390
|
apple: { simulator: true, device: true },
|
|
141589
141391
|
android: { emulator: true, device: true, unknown: true }
|
|
@@ -141830,7 +141632,7 @@ Fails if either react-profiler-analyze or native-profiler-analyze has not been c
|
|
|
141830
141632
|
memoryLeaks,
|
|
141831
141633
|
mountComponents,
|
|
141832
141634
|
// From parsedData, not the live session field: a recording started
|
|
141833
|
-
// after
|
|
141635
|
+
// after analyze must not re-label the data rendered here.
|
|
141834
141636
|
nativeApi.parsedData?.mallocStackLogging ?? null
|
|
141835
141637
|
)
|
|
141836
141638
|
);
|
|
@@ -142197,10 +141999,8 @@ async function loadNativeSession(debugDir, sessionId, api, appProcessOverride) {
|
|
|
142197
141999
|
error_code: FAILURE_CODES.PROFILER_NATIVE_TRACE_MISSING,
|
|
142198
142000
|
failure_stage: "profiler_load_native_session",
|
|
142199
142001
|
failure_area: "tool_server",
|
|
142200
|
-
// A trace
|
|
142201
|
-
//
|
|
142202
|
-
// split into two kinds by platform (validation stays for the
|
|
142203
|
-
// analyze-before-stop guard, NATIVE_PROFILER_NO_EXPORTED_TRACE).
|
|
142002
|
+
// A trace missing on disk is not_found; validation stays for the
|
|
142003
|
+
// analyze-before-stop guard (NATIVE_PROFILER_NO_EXPORTED_TRACE).
|
|
142204
142004
|
error_kind: "not_found"
|
|
142205
142005
|
}
|
|
142206
142006
|
);
|
|
@@ -142266,9 +142066,8 @@ Modes:
|
|
|
142266
142066
|
Returns a summary of the loaded session or a session list for the list mode.
|
|
142267
142067
|
Fails if the session_id is not found or required XML files are missing from disk.`,
|
|
142268
142068
|
zodSchema: zodSchema57,
|
|
142269
|
-
//
|
|
142270
|
-
//
|
|
142271
|
-
// letting it surface from inside the trace parser.
|
|
142069
|
+
// The Hermes, xctrace and perfetto formats this loads have no Chromium
|
|
142070
|
+
// equivalent; the gate fails at the call site, not inside the trace parser.
|
|
142272
142071
|
capability: RN_ONLY_TOOL_CAPABILITY,
|
|
142273
142072
|
services: (params) => {
|
|
142274
142073
|
const svcs = {};
|
|
@@ -142330,12 +142129,9 @@ init_src();
|
|
|
142330
142129
|
var URN_SUFFIXES = ["", ":tcp"];
|
|
142331
142130
|
var PORT_KEYED_NAMESPACES = [
|
|
142332
142131
|
JS_RUNTIME_DEBUGGER_NAMESPACE,
|
|
142333
|
-
// Both
|
|
142334
|
-
//
|
|
142335
|
-
//
|
|
142336
|
-
// reports: a session that had a network inspector or a React profiler open is
|
|
142337
|
-
// told those went away by name, rather than inferring it from the debugger
|
|
142338
|
-
// line.
|
|
142132
|
+
// Both depend on `JsRuntimeDebugger:<payload>`, so a cascade already reaps
|
|
142133
|
+
// them; listed so `stopped` names them instead of leaving the caller to infer
|
|
142134
|
+
// them from the debugger line.
|
|
142339
142135
|
NETWORK_INSPECTOR_NAMESPACE,
|
|
142340
142136
|
REACT_PROFILER_SESSION_NAMESPACE
|
|
142341
142137
|
];
|
|
@@ -142441,8 +142237,7 @@ function createStopAllSimulatorServersTool(registry2) {
|
|
|
142441
142237
|
id: "stop-all-simulator-servers",
|
|
142442
142238
|
interaction: {
|
|
142443
142239
|
// "all" only holds for the unscoped sweep; a scoped call touches just the
|
|
142444
|
-
// ids it was given
|
|
142445
|
-
// deliberately left another agent's devices running.
|
|
142240
|
+
// ids it was given.
|
|
142446
142241
|
startedMsg: ({ params }) => {
|
|
142447
142242
|
const devices = params?.devices;
|
|
142448
142243
|
return devices ? `Stopping simulator servers for ${devices.length} ${devices.length === 1 ? "device" : "devices"}` : "Stopping all simulator servers";
|
|
@@ -142538,9 +142333,8 @@ function listeningPids(port) {
|
|
|
142538
142333
|
const output2 = (0, import_node_child_process28.execFileSync)("netstat", ["-ano"], {
|
|
142539
142334
|
encoding: "utf-8",
|
|
142540
142335
|
timeout: 5e3,
|
|
142541
|
-
// `netstat -ano` dumps every socket on the host;
|
|
142542
|
-
//
|
|
142543
|
-
// throw would misread as "port is free" (stopped:false).
|
|
142336
|
+
// `netstat -ano` dumps every socket on the host; overflowing Node's
|
|
142337
|
+
// default 1 MiB throws, which this tool would misread as "port is free".
|
|
142544
142338
|
maxBuffer: 16 * 1024 * 1024
|
|
142545
142339
|
});
|
|
142546
142340
|
return parseNetstatListeningPids(output2, port);
|
|
@@ -144309,8 +144103,8 @@ var fileInputs2 = [
|
|
|
144309
144103
|
var flowStartRecordingTool = {
|
|
144310
144104
|
id: "flow-start-recording",
|
|
144311
144105
|
interaction: {
|
|
144312
|
-
// Name the flow: recordings
|
|
144313
|
-
//
|
|
144106
|
+
// Name the flow: concurrent recordings interleave in one log, and "flow
|
|
144107
|
+
// recording" would not say which.
|
|
144314
144108
|
startedMsg: ({ params }) => `Starting recording of flow ${params.name}`,
|
|
144315
144109
|
completedMsg: ({ params, result }) => {
|
|
144316
144110
|
if (!result.restarted) return `Started recording flow ${params.name}`;
|
|
@@ -144673,7 +144467,7 @@ function projectIosNode(node, screenW, screenH) {
|
|
|
144673
144467
|
children: node.children ?? [],
|
|
144674
144468
|
// Text hoists only from on-screen nodes (frame is null when the view is
|
|
144675
144469
|
// scrolled off or zero-area) — otherwise a text assert against an ancestor
|
|
144676
|
-
// would pass on content the screen doesn't show.
|
|
144470
|
+
// would pass on content the screen doesn't show. A label makes a node
|
|
144677
144471
|
// leaf-eligible, so `frame` was computed for any node with text.
|
|
144678
144472
|
ownText: frame ? node.label ?? "" : "",
|
|
144679
144473
|
leaf,
|
|
@@ -144714,8 +144508,8 @@ var FULL_HIERARCHY_FIELDS = [
|
|
|
144714
144508
|
"windowFrame",
|
|
144715
144509
|
"hidden",
|
|
144716
144510
|
"alpha",
|
|
144717
|
-
//
|
|
144718
|
-
//
|
|
144511
|
+
// Read by the type directive's focus wait; an injected framework that omits
|
|
144512
|
+
// it just leaves that wait's poll unconfirmed.
|
|
144719
144513
|
"firstResponder"
|
|
144720
144514
|
];
|
|
144721
144515
|
async function unreadableHierarchyReason(nativeApi, bundleId) {
|
|
@@ -144843,18 +144637,17 @@ function projectAndroidNode(node, screenW, screenH) {
|
|
|
144843
144637
|
return {
|
|
144844
144638
|
skip: skip2,
|
|
144845
144639
|
children: childNodes(node),
|
|
144846
|
-
//
|
|
144847
|
-
//
|
|
144848
|
-
//
|
|
144849
|
-
// leaf-eligible (its label is non-empty), so `frame` was computed for it.
|
|
144640
|
+
// Off-screen text must not hoist, or an ancestor text assert would pass on
|
|
144641
|
+
// content the screen doesn't show. Any node with text is leaf-eligible (its
|
|
144642
|
+
// label is non-empty), so `frame` was computed for it.
|
|
144850
144643
|
ownText: frame ? ownText2 : "",
|
|
144851
144644
|
leaf,
|
|
144852
|
-
// A password
|
|
144853
|
-
//
|
|
144645
|
+
// A password field shields even when it carries no id, so nothing from it
|
|
144646
|
+
// bubbles into an ancestor's hoisted text.
|
|
144854
144647
|
shield: Boolean(identifier) || isPassword,
|
|
144855
|
-
// Scroll-clip inputs (see `flattenHoisting`): a
|
|
144856
|
-
//
|
|
144857
|
-
//
|
|
144648
|
+
// Scroll-clip inputs (see `flattenHoisting`): a scroller's raw bounds clip
|
|
144649
|
+
// its subtree, so a row scrolled out of view — but still on the device
|
|
144650
|
+
// screen — is dropped, matching the describe path's prune.
|
|
144858
144651
|
rect,
|
|
144859
144652
|
scrolls: isUiAutomatorScrollable(attrs)
|
|
144860
144653
|
};
|
|
@@ -144917,9 +144710,9 @@ function projectChromiumNode(node) {
|
|
|
144917
144710
|
return {
|
|
144918
144711
|
skip: false,
|
|
144919
144712
|
children: node.children,
|
|
144920
|
-
//
|
|
144921
|
-
//
|
|
144922
|
-
//
|
|
144713
|
+
// Off-screen text must not hoist, or a text assert against an ancestor
|
|
144714
|
+
// would pass on content the screen doesn't show. A password's text never
|
|
144715
|
+
// bubbles up.
|
|
144923
144716
|
ownText: onScreen && !node.password ? nodeText(node) : "",
|
|
144924
144717
|
leaf,
|
|
144925
144718
|
shield: Boolean(node.identifier) || node.password === true
|
|
@@ -144950,8 +144743,8 @@ function projectVegaNode(node) {
|
|
|
144950
144743
|
return {
|
|
144951
144744
|
skip: false,
|
|
144952
144745
|
children: node.children,
|
|
144953
|
-
//
|
|
144954
|
-
//
|
|
144746
|
+
// Off-screen text must not hoist, or a text assert against an ancestor
|
|
144747
|
+
// would pass on content the screen doesn't show.
|
|
144955
144748
|
ownText: onScreen ? nodeText(node) : "",
|
|
144956
144749
|
leaf: { ...node, children: [] },
|
|
144957
144750
|
shield: isAuthoredVegaTestId(node.identifier)
|
|
@@ -145789,10 +145582,9 @@ async function waitForIdle(env, step) {
|
|
|
145789
145582
|
ok: false,
|
|
145790
145583
|
indeterminate: true,
|
|
145791
145584
|
// The underlying reader reports an instrumentation failure, whose remedy
|
|
145792
|
-
// (relaunch the app) is the wrong repair for the commonest cause
|
|
145793
|
-
//
|
|
145794
|
-
//
|
|
145795
|
-
// before relaunching anything.
|
|
145585
|
+
// (relaunch the app) is the wrong repair for the commonest cause here: the
|
|
145586
|
+
// app is simply not in the foreground, which reads exactly the same from the
|
|
145587
|
+
// tree source. Name that first.
|
|
145796
145588
|
reason: `could not read the UI tree while waiting for the screen to settle \u2014 check the app is still in the foreground (a backgrounded app reads the same as an uninstrumented one). Underlying error: ${underlying}`
|
|
145797
145589
|
});
|
|
145798
145590
|
const degraded = () => ({
|
|
@@ -145939,13 +145731,12 @@ function anchoredWarnings(session, steps) {
|
|
|
145939
145731
|
var flowFinishRecordingTool = {
|
|
145940
145732
|
id: "flow-finish-recording",
|
|
145941
145733
|
interaction: {
|
|
145942
|
-
// Name the flow: other recordings stay live
|
|
145943
|
-
//
|
|
145734
|
+
// Name the flow: other recordings stay live, so an unqualified message would
|
|
145735
|
+
// not identify which one.
|
|
145944
145736
|
startedMsg: ({ params }) => `Finishing recording of flow ${params.name}`,
|
|
145945
|
-
// `params.name`
|
|
145946
|
-
//
|
|
145947
|
-
//
|
|
145948
|
-
// and this spelling matches the two formatters either side of it.
|
|
145737
|
+
// `params.name` equals the basename of `result.path` on every branch
|
|
145738
|
+
// (`assertSafeFlowName` admits no dots or separators), and matches the two
|
|
145739
|
+
// formatters either side.
|
|
145949
145740
|
completedMsg: ({ params }) => `Saved recorded flow ${params.name}`,
|
|
145950
145741
|
failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to finish recording of flow ${params.name}: ${failureSignal2.error_code}`
|
|
145951
145742
|
},
|
|
@@ -146380,7 +146171,7 @@ function createFlowAddStepTool(registry2) {
|
|
|
146380
146171
|
id: "flow-add-step",
|
|
146381
146172
|
interaction: {
|
|
146382
146173
|
// Name the flow: recordings are concurrent, so several of these lines can
|
|
146383
|
-
// interleave in one log and "the recorded flow" would not
|
|
146174
|
+
// interleave in one log and "the recorded flow" would not say which.
|
|
146384
146175
|
startedMsg: ({ params }) => `Adding ${params.command} step to flow ${params.name}`,
|
|
146385
146176
|
completedMsg: ({ params }) => `Added ${params.command} step to flow ${params.name}`,
|
|
146386
146177
|
failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to add ${params.command} step to flow ${params.name}: ${failureSignal2.error_code}`
|
|
@@ -146460,9 +146251,6 @@ If a step was recorded by mistake, remove it from the .yaml after \`flow-finish-
|
|
|
146460
146251
|
toolResult,
|
|
146461
146252
|
stepCount,
|
|
146462
146253
|
recorded: summarizeStep(step, stepCount),
|
|
146463
|
-
// Host mode: a path. Client mode: the directive that carries the YAML
|
|
146464
|
-
// to the client, which IS the persistence mechanism there — the one
|
|
146465
|
-
// place the full file still has to travel per step.
|
|
146466
146254
|
savedTo
|
|
146467
146255
|
};
|
|
146468
146256
|
}
|
|
@@ -146481,8 +146269,7 @@ var zodSchema64 = external_exports.object({
|
|
|
146481
146269
|
var flowInsertEchoTool = {
|
|
146482
146270
|
id: "flow-add-echo",
|
|
146483
146271
|
interaction: {
|
|
146484
|
-
// Name the flow: recordings are concurrent, so
|
|
146485
|
-
// interleave in one log and "the recorded flow" would not identify which.
|
|
146272
|
+
// Name the flow: recordings are concurrent, so an unqualified message is ambiguous.
|
|
146486
146273
|
startedMsg: ({ params }) => `Adding note to flow ${params.name}`,
|
|
146487
146274
|
completedMsg: ({ params }) => `Added note to flow ${params.name}`,
|
|
146488
146275
|
failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to add note to flow ${params.name}: ${failureSignal2.error_code}`
|
|
@@ -148743,7 +148530,9 @@ async function runSnapshot(env, opts) {
|
|
|
148743
148530
|
const currentArtifact = async () => {
|
|
148744
148531
|
if (cropDir === void 0) return shot.image;
|
|
148745
148532
|
keepCropped = true;
|
|
148746
|
-
return store.register(
|
|
148533
|
+
return store.register({
|
|
148534
|
+
hostPath: currentPath,
|
|
148535
|
+
kind: "screenshot",
|
|
148747
148536
|
mimeType: "image/png",
|
|
148748
148537
|
filename: `${snapshotKey}-current.png`
|
|
148749
148538
|
});
|
|
@@ -148768,7 +148557,11 @@ async function runSnapshot(env, opts) {
|
|
|
148768
148557
|
if (opts.updateBaselines) {
|
|
148769
148558
|
await fs50.mkdir(dir, { recursive: true });
|
|
148770
148559
|
await fs50.copyFile(currentPath, baselinePath);
|
|
148771
|
-
const baseline = await store.register(
|
|
148560
|
+
const baseline = await store.register({
|
|
148561
|
+
hostPath: baselinePath,
|
|
148562
|
+
kind: "screenshot",
|
|
148563
|
+
mimeType: "image/png"
|
|
148564
|
+
});
|
|
148772
148565
|
return {
|
|
148773
148566
|
status: "pass",
|
|
148774
148567
|
reason: exists2 ? `baseline updated (${key2})` : `baseline written (${key2})`,
|
|
@@ -148791,12 +148584,11 @@ async function runSnapshot(env, opts) {
|
|
|
148791
148584
|
baselinePath,
|
|
148792
148585
|
currentPath,
|
|
148793
148586
|
outputDir,
|
|
148794
|
-
// A crop compares EVERY pixel of the element's region
|
|
148795
|
-
//
|
|
148796
|
-
//
|
|
148797
|
-
//
|
|
148798
|
-
//
|
|
148799
|
-
// asserts the element clears it.
|
|
148587
|
+
// A crop compares EVERY pixel of the element's region, wherever it
|
|
148588
|
+
// sits. Masking a crop's overlap with the screen's top status-bar band
|
|
148589
|
+
// would degenerate into comparing nothing for an element inside the
|
|
148590
|
+
// band (a vacuous pass); a crop overlapping the band leans on the run's
|
|
148591
|
+
// best-effort pinStatusBar instead.
|
|
148800
148592
|
topMask: cropFrame === void 0 ? "status-bar" : "none",
|
|
148801
148593
|
// Crop dimensions track the element — size drift must hard-fail below
|
|
148802
148594
|
// instead of being resampled away like a full-screen scale difference.
|
|
@@ -148809,7 +148601,11 @@ async function runSnapshot(env, opts) {
|
|
|
148809
148601
|
reason: `baseline is ${expected.width}x${expected.height} but the ${opts.cropOn ? "cropOn region" : "capture"} is ${actual.width}x${actual.height} (${key2}) \u2014 nothing was compared` + (opts.cropOn ? `. The element's size drifted \u2014 crop a fixed-size container, or re-adopt with updateBaselines` : ""),
|
|
148810
148602
|
snapshotKey,
|
|
148811
148603
|
artifacts: {
|
|
148812
|
-
baseline: await store.register(
|
|
148604
|
+
baseline: await store.register({
|
|
148605
|
+
hostPath: baselinePath,
|
|
148606
|
+
kind: "screenshot",
|
|
148607
|
+
mimeType: "image/png"
|
|
148608
|
+
}),
|
|
148813
148609
|
current: await currentArtifact()
|
|
148814
148610
|
}
|
|
148815
148611
|
};
|
|
@@ -148820,11 +148616,17 @@ async function runSnapshot(env, opts) {
|
|
|
148820
148616
|
return { status: "pass", reason };
|
|
148821
148617
|
}
|
|
148822
148618
|
const artifacts = {
|
|
148823
|
-
baseline: await store.register(
|
|
148619
|
+
baseline: await store.register({
|
|
148620
|
+
hostPath: baselinePath,
|
|
148621
|
+
kind: "screenshot",
|
|
148622
|
+
mimeType: "image/png"
|
|
148623
|
+
}),
|
|
148824
148624
|
current: await currentArtifact()
|
|
148825
148625
|
};
|
|
148826
148626
|
if (result.contextDiffPath) {
|
|
148827
|
-
artifacts.diff = await store.register(
|
|
148627
|
+
artifacts.diff = await store.register({
|
|
148628
|
+
hostPath: result.contextDiffPath,
|
|
148629
|
+
kind: "screenshot-diff-context",
|
|
148828
148630
|
mimeType: "image/png",
|
|
148829
148631
|
filename: `${snapshotKey}-diff.png`
|
|
148830
148632
|
});
|
|
@@ -149381,8 +149183,8 @@ Pass exactly one flow source: name for a saved flow under project_root, or flow_
|
|
|
149381
149183
|
// One holder per ExecState, shared by nested `run:` flows: `deviceEnv`
|
|
149382
149184
|
// spreads the reference, so what one step's settle learns about the
|
|
149383
149185
|
// tree source the next one already has. A `tool: flow-execute` builds
|
|
149384
|
-
// its own
|
|
149385
|
-
//
|
|
149186
|
+
// its own, which is why that step spends this verdict rather than
|
|
149187
|
+
// inheriting whatever the sub-run proved.
|
|
149386
149188
|
treeOutage: {},
|
|
149387
149189
|
flowsDir,
|
|
149388
149190
|
viaUpload,
|
|
@@ -149573,8 +149375,7 @@ function summarize(flowName, deviceId, executionPrerequisite, steps, aborted2) {
|
|
|
149573
149375
|
// A cancelled run must never read as PASS — it may contain skips alone
|
|
149574
149376
|
// (no fail/error report), so the verdict folds the abort in directly. A
|
|
149575
149377
|
// skip by itself is NOT a failure: an unmet `when:` guard skips its block
|
|
149576
|
-
// as a successful omission
|
|
149577
|
-
// fail/error report.
|
|
149378
|
+
// as a successful omission.
|
|
149578
149379
|
ok: failed === 0 && errored === 0 && !aborted2,
|
|
149579
149380
|
...aborted2 ? { aborted: true } : {},
|
|
149580
149381
|
passed,
|
|
@@ -150847,9 +150648,17 @@ async function executeScreenshotDiffTool(services, params, options, captureScree
|
|
|
150847
150648
|
const artifacts = requireArtifacts(options);
|
|
150848
150649
|
return {
|
|
150849
150650
|
summary: result.summary,
|
|
150850
|
-
...result.diffPath ? {
|
|
150651
|
+
...result.diffPath ? {
|
|
150652
|
+
diffPath: await artifacts.register({
|
|
150653
|
+
hostPath: result.diffPath,
|
|
150654
|
+
kind: "screenshot-diff",
|
|
150655
|
+
mimeType: "image/png"
|
|
150656
|
+
})
|
|
150657
|
+
} : {},
|
|
150851
150658
|
...result.contextDiffPath ? {
|
|
150852
|
-
contextDiffPath: await artifacts.register(
|
|
150659
|
+
contextDiffPath: await artifacts.register({
|
|
150660
|
+
hostPath: result.contextDiffPath,
|
|
150661
|
+
kind: "screenshot-diff-context",
|
|
150853
150662
|
mimeType: "image/png"
|
|
150854
150663
|
})
|
|
150855
150664
|
} : {}
|
|
@@ -151161,11 +150970,10 @@ var awaitUserSelectionTool = {
|
|
|
151161
150970
|
failedMsg: ({ failureSignal: failureSignal2 }) => `Failed while waiting for variant selection: ${failureSignal2.error_code}`
|
|
151162
150971
|
},
|
|
151163
150972
|
featureFlag: "argent-lens",
|
|
151164
|
-
// Hidden
|
|
151165
|
-
//
|
|
151166
|
-
//
|
|
151167
|
-
//
|
|
151168
|
-
// CLI-relay surface honest — propose_variant then end the turn.
|
|
150973
|
+
// Hidden while an `argent lens` CLI session owns the preview window: there the
|
|
150974
|
+
// user's picks are relayed into the agent's terminal as a normal message (see
|
|
150975
|
+
// `argent-cli/src/lens.ts`), so the agent ends its turn after propose_variant
|
|
150976
|
+
// instead of blocking.
|
|
151169
150977
|
hideWhen: () => variantProposalStore.isCliSession(),
|
|
151170
150978
|
description: `Block until the human finishes picking among the variants you proposed (the ONE blocking call).
|
|
151171
150979
|
|
|
@@ -151840,10 +151648,8 @@ function createPreviewWindowManager(opts = {}) {
|
|
|
151840
151648
|
const launchBin = wrapperBin ?? electronBin;
|
|
151841
151649
|
const launchArgs = wrapperBin ? ["--no-sandbox", mainScript] : [mainScript];
|
|
151842
151650
|
const next = (0, import_node_child_process33.spawn)(launchBin, launchArgs, {
|
|
151843
|
-
//
|
|
151844
|
-
//
|
|
151845
|
-
// host puts it in our env, and inheriting it makes main.cjs crash at
|
|
151846
|
-
// app.setName() with `app` undefined — the window never opens.
|
|
151651
|
+
// Strips ELECTRON_RUN_AS_NODE, which an Electron-based MCP host leaves in
|
|
151652
|
+
// our env, so the child boots as a GUI app instead of bare Node.
|
|
151847
151653
|
env: electronGuiChildEnv({ ARGENT_PREVIEW_URL: url2 }),
|
|
151848
151654
|
stdio: ["pipe", "ignore", "pipe"]
|
|
151849
151655
|
});
|
|
@@ -151992,11 +151798,10 @@ function start() {
|
|
|
151992
151798
|
const { stop: stopWatcher, ready: watcherReady } = startSimulatorWatcher(registry2);
|
|
151993
151799
|
let server = null;
|
|
151994
151800
|
const previewWindow = createPreviewWindowManager({
|
|
151995
|
-
//
|
|
151996
|
-
//
|
|
151997
|
-
//
|
|
151998
|
-
//
|
|
151999
|
-
// this fires at runtime, long after module init.
|
|
151801
|
+
// Electron is an optionalDependency (absent on headless/CI hosts); on a launch
|
|
151802
|
+
// failure unblock any parked await with the browser fallback URL rather than
|
|
151803
|
+
// stranding it for the full timeout. `previewWindowBaseUrl` is declared below
|
|
151804
|
+
// but only called at runtime.
|
|
152000
151805
|
onLaunchFailure: (err) => variantProposalStore.notifyWindowUnavailable(err.message, previewWindowBaseUrl())
|
|
152001
151806
|
});
|
|
152002
151807
|
const previewWindowBaseUrl = () => {
|