@swmansion/argent 0.14.1-next.7 → 0.14.1-next.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-cmds.mjs +16 -0
- package/dist/tool-server.cjs +201 -87
- package/package.json +1 -1
package/dist/cli-cmds.mjs
CHANGED
|
@@ -7289,11 +7289,15 @@ function isScalarType(type) {
|
|
|
7289
7289
|
}
|
|
7290
7290
|
function coerceScalar(raw, type, field) {
|
|
7291
7291
|
if (type === "number") {
|
|
7292
|
+
if (raw.trim() === "")
|
|
7293
|
+
throw new FlagParseException(`--${field} expected a number, got "${raw}"`);
|
|
7292
7294
|
const n2 = Number(raw);
|
|
7293
7295
|
if (Number.isNaN(n2)) throw new FlagParseException(`--${field} expected a number, got "${raw}"`);
|
|
7294
7296
|
return n2;
|
|
7295
7297
|
}
|
|
7296
7298
|
if (type === "integer") {
|
|
7299
|
+
if (raw.trim() === "")
|
|
7300
|
+
throw new FlagParseException(`--${field} expected an integer, got "${raw}"`);
|
|
7297
7301
|
const n2 = Number(raw);
|
|
7298
7302
|
if (!Number.isInteger(n2))
|
|
7299
7303
|
throw new FlagParseException(`--${field} expected an integer, got "${raw}"`);
|
|
@@ -7322,6 +7326,7 @@ function parseFlags(argv, schema) {
|
|
|
7322
7326
|
let helpRequested = false;
|
|
7323
7327
|
let rawArgs = null;
|
|
7324
7328
|
const seenArrayFields = /* @__PURE__ */ new Set();
|
|
7329
|
+
const jsonFields = /* @__PURE__ */ new Set();
|
|
7325
7330
|
function takeNext(i2, flag) {
|
|
7326
7331
|
if (i2 + 1 >= argv.length) {
|
|
7327
7332
|
throw new FlagParseException(`--${flag} requires a value`);
|
|
@@ -7360,7 +7365,13 @@ function parseFlags(argv, schema) {
|
|
|
7360
7365
|
if (flag.endsWith("-json")) {
|
|
7361
7366
|
const fieldName = flag.slice(0, -"-json".length);
|
|
7362
7367
|
const { value: value2, nextIndex: nextIndex2 } = inlineValue !== void 0 ? { value: inlineValue, nextIndex: i2 } : takeNext(i2, flag);
|
|
7368
|
+
if (seenArrayFields.has(fieldName)) {
|
|
7369
|
+
throw new FlagParseException(
|
|
7370
|
+
`--${fieldName} and --${flag} cannot be mixed for the same field; pass it entirely as --${flag} '<json>' or --args '<json>'`
|
|
7371
|
+
);
|
|
7372
|
+
}
|
|
7363
7373
|
args[fieldName] = parseJsonOrThrow(value2, `--${flag}`);
|
|
7374
|
+
jsonFields.add(fieldName);
|
|
7364
7375
|
i2 = nextIndex2;
|
|
7365
7376
|
continue;
|
|
7366
7377
|
}
|
|
@@ -7392,6 +7403,11 @@ function parseFlags(argv, schema) {
|
|
|
7392
7403
|
);
|
|
7393
7404
|
}
|
|
7394
7405
|
const { value: value2, nextIndex: nextIndex2 } = inlineValue !== void 0 ? { value: inlineValue, nextIndex: i2 } : takeNext(i2, flag);
|
|
7406
|
+
if (jsonFields.has(flag)) {
|
|
7407
|
+
throw new FlagParseException(
|
|
7408
|
+
`--${flag} and --${flag}-json cannot be mixed for the same field; pass it entirely as --${flag}-json '<json>' or --args '<json>'`
|
|
7409
|
+
);
|
|
7410
|
+
}
|
|
7395
7411
|
const coerced = coerceScalar(value2, itemType, flag);
|
|
7396
7412
|
if (!seenArrayFields.has(flag)) {
|
|
7397
7413
|
args[flag] = [coerced];
|
package/dist/tool-server.cjs
CHANGED
|
@@ -111642,6 +111642,9 @@ Booted/ready devices are listed first. Platforms whose CLI is unavailable are si
|
|
|
111642
111642
|
// ../tool-server/src/utils/variant-proposals.ts
|
|
111643
111643
|
init_src();
|
|
111644
111644
|
var MAX_COMMENT_LENGTH = 2e3;
|
|
111645
|
+
var MAX_PENDING_OUTCOMES = 32;
|
|
111646
|
+
var MAX_MATCH_VALUE_LENGTH = 200;
|
|
111647
|
+
var MAX_ANNOTATIONS = 200;
|
|
111645
111648
|
function slug(s) {
|
|
111646
111649
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
111647
111650
|
}
|
|
@@ -111695,6 +111698,18 @@ var VariantProposalStore = class {
|
|
|
111695
111698
|
waitersList = [];
|
|
111696
111699
|
/** Frozen result of the current round once the user submits. */
|
|
111697
111700
|
lastOutcome = null;
|
|
111701
|
+
/**
|
|
111702
|
+
* Completed outcomes that finished with no `await_user_selection` parked to
|
|
111703
|
+
* receive them directly (submitSelection's "no waiter" branch), queued in
|
|
111704
|
+
* completion order. `autoRollIfCompleted` rolls into a fresh round on the
|
|
111705
|
+
* very next `propose_variant` regardless of whether the outcome was ever
|
|
111706
|
+
* retrieved — so this queue, unlike `lastOutcome`/`completed`/`consumed`
|
|
111707
|
+
* (which describe only the CURRENT round), survives `reset()` and is
|
|
111708
|
+
* drained first by `awaitSelection`, oldest first. Without it, a human's
|
|
111709
|
+
* already-submitted selection is destroyed the moment the next
|
|
111710
|
+
* `propose_variant` call rolls the round out from under it.
|
|
111711
|
+
*/
|
|
111712
|
+
pendingOutcomes = [];
|
|
111698
111713
|
/** Begin a fresh round, discarding the previous one's proposals/selections. */
|
|
111699
111714
|
reset() {
|
|
111700
111715
|
const superseded = this.waitersList.filter((w) => !w.settled);
|
|
@@ -111750,11 +111765,11 @@ var VariantProposalStore = class {
|
|
|
111750
111765
|
});
|
|
111751
111766
|
}
|
|
111752
111767
|
}
|
|
111753
|
-
|
|
111754
|
-
if (this.completed
|
|
111768
|
+
autoRollIfCompleted() {
|
|
111769
|
+
if (this.completed) this.reset();
|
|
111755
111770
|
}
|
|
111756
111771
|
proposeVariant(input) {
|
|
111757
|
-
this.
|
|
111772
|
+
this.autoRollIfCompleted();
|
|
111758
111773
|
if (input.udid && input.udid.trim()) this.device = input.udid.trim();
|
|
111759
111774
|
const match = input.match ?? { by: "text", value: input.element };
|
|
111760
111775
|
const key = `${match.by}:${match.value.trim().toLowerCase()}`;
|
|
@@ -111817,7 +111832,10 @@ var VariantProposalStore = class {
|
|
|
111817
111832
|
*/
|
|
111818
111833
|
setCliSession(active, agents = []) {
|
|
111819
111834
|
const transitioned = this.cliSession !== active;
|
|
111820
|
-
if (transitioned
|
|
111835
|
+
if (transitioned) {
|
|
111836
|
+
if (this.completed || this.proposals.length > 0) this.reset();
|
|
111837
|
+
this.pendingOutcomes = [];
|
|
111838
|
+
}
|
|
111821
111839
|
this.cliSession = active;
|
|
111822
111840
|
this.lensAgents = active ? agents.map((a) => ({ ...a })) : [];
|
|
111823
111841
|
this.lensAgentChoice = null;
|
|
@@ -111882,30 +111900,51 @@ var VariantProposalStore = class {
|
|
|
111882
111900
|
}
|
|
111883
111901
|
/** Called by the preview UI when the human presses "Complete selection". */
|
|
111884
111902
|
submitSelection(input) {
|
|
111885
|
-
const cleanAnnotations = (input.annotations ?? []).filter((a) => a && typeof a.comment === "string" && a.comment.trim()).map((a) => ({
|
|
111903
|
+
const cleanAnnotations = (input.annotations ?? []).filter((a) => a && typeof a.comment === "string" && a.comment.trim()).slice(0, MAX_ANNOTATIONS).map((a) => ({
|
|
111886
111904
|
target: String(a.target ?? "").slice(0, 200) || "(element)",
|
|
111887
|
-
|
|
111905
|
+
// Cap the matcher value too — it is caller-supplied and, unlike the
|
|
111906
|
+
// comment, was previously ingested uncapped.
|
|
111907
|
+
match: {
|
|
111908
|
+
by: a.match?.by ?? "text",
|
|
111909
|
+
value: String(a.match?.value ?? "").slice(0, MAX_MATCH_VALUE_LENGTH)
|
|
111910
|
+
},
|
|
111888
111911
|
comment: a.comment.trim().slice(0, MAX_COMMENT_LENGTH)
|
|
111889
111912
|
}));
|
|
111890
111913
|
if (this.proposals.length === 0 && cleanAnnotations.length === 0) {
|
|
111891
111914
|
throw new Error("Nothing to submit \u2014 no proposals and no comments.");
|
|
111892
111915
|
}
|
|
111893
|
-
|
|
111894
|
-
|
|
111895
|
-
|
|
111916
|
+
const seenElementIds = /* @__PURE__ */ new Set();
|
|
111917
|
+
this.submitted = input.selections.filter((s) => this.proposals.some((p) => p.id === s.elementId)).filter((s) => {
|
|
111918
|
+
if (seenElementIds.has(s.elementId)) return false;
|
|
111919
|
+
seenElementIds.add(s.elementId);
|
|
111920
|
+
return true;
|
|
111921
|
+
}).map((s) => {
|
|
111922
|
+
const capped = s.comment === void 0 ? s : { ...s, comment: s.comment.slice(0, MAX_COMMENT_LENGTH) };
|
|
111923
|
+
return capped.variantId == null ? capped : { ...capped, variantId: capped.variantId.slice(0, MAX_MATCH_VALUE_LENGTH) };
|
|
111924
|
+
});
|
|
111896
111925
|
this.submittedAnnotations = cleanAnnotations;
|
|
111897
111926
|
this.globalComment = (input.globalComment ?? "").trim().slice(0, MAX_COMMENT_LENGTH);
|
|
111927
|
+
const wasResubmit = this.completed;
|
|
111898
111928
|
this.completed = true;
|
|
111899
|
-
this.consumed = false;
|
|
111929
|
+
if (!wasResubmit) this.consumed = false;
|
|
111900
111930
|
this.lastOutcome = this.buildOutcome();
|
|
111901
111931
|
const round2 = this.round;
|
|
111902
111932
|
const toSettle = this.waitersList.filter((w) => !w.settled && w.round === round2);
|
|
111903
111933
|
this.waitersList = this.waitersList.filter((w) => w.round !== round2 || w.settled);
|
|
111904
|
-
if (toSettle.length > 0)
|
|
111905
|
-
|
|
111906
|
-
|
|
111907
|
-
|
|
111908
|
-
|
|
111934
|
+
if (toSettle.length > 0) {
|
|
111935
|
+
this.consumed = true;
|
|
111936
|
+
for (const w of toSettle) {
|
|
111937
|
+
w.settled = true;
|
|
111938
|
+
w.settle(this.lastOutcome);
|
|
111939
|
+
}
|
|
111940
|
+
} else if (this.cliSession) {
|
|
111941
|
+
this.consumed = true;
|
|
111942
|
+
} else if (!this.consumed) {
|
|
111943
|
+
this.pendingOutcomes = this.pendingOutcomes.filter((o) => o.round !== round2);
|
|
111944
|
+
this.pendingOutcomes.push(this.lastOutcome);
|
|
111945
|
+
if (this.pendingOutcomes.length > MAX_PENDING_OUTCOMES) {
|
|
111946
|
+
this.pendingOutcomes.shift();
|
|
111947
|
+
}
|
|
111909
111948
|
}
|
|
111910
111949
|
this.events.emit("changed");
|
|
111911
111950
|
this.events.emit("selectionSubmitted");
|
|
@@ -111969,16 +112008,23 @@ var VariantProposalStore = class {
|
|
|
111969
112008
|
* round is superseded), so concurrent / re-entrant awaits never strand.
|
|
111970
112009
|
*/
|
|
111971
112010
|
awaitSelection(opts) {
|
|
112011
|
+
if (opts.signal?.aborted) {
|
|
112012
|
+
const err = new Error("await_user_selection aborted (client disconnected)");
|
|
112013
|
+
err.name = "AbortError";
|
|
112014
|
+
return Promise.reject(err);
|
|
112015
|
+
}
|
|
112016
|
+
if (this.pendingOutcomes.length > 0) {
|
|
112017
|
+
const outcome = this.pendingOutcomes.shift();
|
|
112018
|
+
if (outcome.round === this.round) this.consumed = true;
|
|
112019
|
+
const morePending = this.pendingOutcomes.length > 0 || outcome.round !== this.round && this.proposals.length > 0;
|
|
112020
|
+
return Promise.resolve(morePending ? { ...outcome, morePending: true } : outcome);
|
|
112021
|
+
}
|
|
111972
112022
|
if (this.completed && this.consumed) {
|
|
111973
112023
|
return Promise.resolve({
|
|
111974
112024
|
status: "no_proposals",
|
|
111975
112025
|
message: "The previous selection round was already returned. Call propose_variant to stage new variants before awaiting again."
|
|
111976
112026
|
});
|
|
111977
112027
|
}
|
|
111978
|
-
if (this.completed && !this.consumed) {
|
|
111979
|
-
this.consumed = true;
|
|
111980
|
-
return Promise.resolve(this.lastOutcome ?? this.buildOutcome());
|
|
111981
|
-
}
|
|
111982
112028
|
if (this.proposals.length === 0) {
|
|
111983
112029
|
return Promise.resolve({
|
|
111984
112030
|
status: "no_proposals",
|
|
@@ -112027,10 +112073,7 @@ var VariantProposalStore = class {
|
|
|
112027
112073
|
this.waitersList.push(waiter);
|
|
112028
112074
|
this.events.emit("changed");
|
|
112029
112075
|
this.events.emit("awaitParked");
|
|
112030
|
-
if (opts.signal) {
|
|
112031
|
-
if (opts.signal.aborted) return onAbort();
|
|
112032
|
-
opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
112033
|
-
}
|
|
112076
|
+
if (opts.signal) opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
112034
112077
|
});
|
|
112035
112078
|
}
|
|
112036
112079
|
};
|
|
@@ -112910,6 +112953,13 @@ function descendantText(parsed, maxChars = 120) {
|
|
|
112910
112953
|
const stack = [parsed];
|
|
112911
112954
|
while (stack.length > 0) {
|
|
112912
112955
|
const x = stack.pop();
|
|
112956
|
+
if (attrIsTrue(x.attrs, "password")) {
|
|
112957
|
+
if (!seen.has("[password]")) {
|
|
112958
|
+
seen.add("[password]");
|
|
112959
|
+
parts.push("[password]");
|
|
112960
|
+
}
|
|
112961
|
+
continue;
|
|
112962
|
+
}
|
|
112913
112963
|
for (const k of ["text", "content-desc"]) {
|
|
112914
112964
|
const v = (x.attrs[k] ?? "").trim();
|
|
112915
112965
|
if (v && !seen.has(v)) {
|
|
@@ -113001,6 +113051,9 @@ function computeNodeOutput(parsed, scrollClip, outputs, opts) {
|
|
|
113001
113051
|
}
|
|
113002
113052
|
const interactive = isInteractive(attrs);
|
|
113003
113053
|
let label = labelOf(attrs);
|
|
113054
|
+
if (attrIsTrue(attrs, "password")) {
|
|
113055
|
+
label = "[password]";
|
|
113056
|
+
}
|
|
113004
113057
|
if (cls.endsWith(".ImageView") && !interactive && !label) {
|
|
113005
113058
|
return keptChildren;
|
|
113006
113059
|
}
|
|
@@ -113015,6 +113068,9 @@ function computeNodeOutput(parsed, scrollClip, outputs, opts) {
|
|
|
113015
113068
|
if (interactive && bounds && keptChildren.length === 1) {
|
|
113016
113069
|
const c = keptChildren[0];
|
|
113017
113070
|
if (c.clickable && c.pixelBounds && rectsEqual(c.pixelBounds, bounds)) {
|
|
113071
|
+
if (!c.label && label) c.label = label;
|
|
113072
|
+
const rid = attrs["resource-id"];
|
|
113073
|
+
if (!c.identifier && rid) c.identifier = rid;
|
|
113018
113074
|
return [c];
|
|
113019
113075
|
}
|
|
113020
113076
|
}
|
|
@@ -113024,9 +113080,6 @@ function computeNodeOutput(parsed, scrollClip, outputs, opts) {
|
|
|
113024
113080
|
(c) => !(c.role === "StaticText" && c.label && lower.includes(c.label.toLowerCase()) && !c.clickable)
|
|
113025
113081
|
);
|
|
113026
113082
|
}
|
|
113027
|
-
if (attrIsTrue(attrs, "password")) {
|
|
113028
|
-
label = "[password]";
|
|
113029
|
-
}
|
|
113030
113083
|
const node = makeUiNode(attrs, deriveUiAutomatorRole(cls), bounds, label, keptChildren);
|
|
113031
113084
|
if (hiddenInScroll > 0) node.scrollHidden = hiddenInScroll;
|
|
113032
113085
|
return [node];
|
|
@@ -113065,7 +113118,7 @@ function finalizeUiNode(n, children, sw, sh) {
|
|
|
113065
113118
|
};
|
|
113066
113119
|
} else {
|
|
113067
113120
|
if (children.length === 0) return null;
|
|
113068
|
-
if (children.length === 1) return children[0];
|
|
113121
|
+
if (children.length === 1 && !n.label && !n.identifier) return children[0];
|
|
113069
113122
|
const x1 = Math.min(...children.map((c) => c.frame.x));
|
|
113070
113123
|
const y1 = Math.min(...children.map((c) => c.frame.y));
|
|
113071
113124
|
const x2 = Math.max(...children.map((c) => c.frame.x + c.frame.width));
|
|
@@ -115430,7 +115483,7 @@ var LogFileWriter = class {
|
|
|
115430
115483
|
const sourceFile = sourceUrl ? cleanSourceUrl(sourceUrl) ?? void 0 : void 0;
|
|
115431
115484
|
const source = sourceFile !== void 0 && sourceLine !== void 0 ? `${sourceFile}:${sourceLine}` : "-";
|
|
115432
115485
|
const flatMessage = entry.message.replace(/\n/g, " ");
|
|
115433
|
-
const levelDisplay = LEVEL_DISPLAY[entry.level] ?? entry.level.toUpperCase().padEnd(5)
|
|
115486
|
+
const levelDisplay = LEVEL_DISPLAY[entry.level] ?? entry.level.toUpperCase().padEnd(5);
|
|
115434
115487
|
const line = `[L:${entry.id}] ${entry.timestamp} ${levelDisplay} ${source} | ${flatMessage}
|
|
115435
115488
|
`;
|
|
115436
115489
|
if (this.ready && this.fd !== null) {
|
|
@@ -115543,6 +115596,13 @@ function parseFlatLine(line) {
|
|
|
115543
115596
|
};
|
|
115544
115597
|
}
|
|
115545
115598
|
|
|
115599
|
+
// ../tool-server/src/utils/debugger/console-timestamp.ts
|
|
115600
|
+
var MAX_TIMESTAMP_MS = 864e13;
|
|
115601
|
+
function consoleTimestampToIso(rawTimestampMs) {
|
|
115602
|
+
const usable = Number.isFinite(rawTimestampMs) && Math.abs(rawTimestampMs) <= MAX_TIMESTAMP_MS;
|
|
115603
|
+
return new Date(usable ? rawTimestampMs : Date.now()).toISOString();
|
|
115604
|
+
}
|
|
115605
|
+
|
|
115546
115606
|
// ../tool-server/src/blueprints/chromium-js-runtime-debugger.ts
|
|
115547
115607
|
var CHROMIUM_JS_RUNTIME_DEBUGGER_NAMESPACE = "ChromiumJsRuntimeDebugger";
|
|
115548
115608
|
function chromiumJsRuntimeDebuggerRef(device) {
|
|
@@ -115669,7 +115729,7 @@ var chromiumJsRuntimeDebuggerBlueprint = {
|
|
|
115669
115729
|
};
|
|
115670
115730
|
logWriter.write({
|
|
115671
115731
|
id: entry.id,
|
|
115672
|
-
timestamp:
|
|
115732
|
+
timestamp: consoleTimestampToIso(ts),
|
|
115673
115733
|
level: entry.level,
|
|
115674
115734
|
message: entry.message,
|
|
115675
115735
|
stackTrace: entry.stackTrace
|
|
@@ -117132,7 +117192,7 @@ var jsRuntimeDebuggerBlueprint = {
|
|
|
117132
117192
|
};
|
|
117133
117193
|
logWriter.write({
|
|
117134
117194
|
id: entry.id,
|
|
117135
|
-
timestamp:
|
|
117195
|
+
timestamp: consoleTimestampToIso(entry.timestamp),
|
|
117136
117196
|
level: entry.level,
|
|
117137
117197
|
message: entry.message,
|
|
117138
117198
|
stackTrace: entry.stackTrace
|
|
@@ -122513,8 +122573,21 @@ function makeComponentTreeScript(opts) {
|
|
|
122513
122573
|
return `(async function() {
|
|
122514
122574
|
var REQUEST_ID = ${requestId};
|
|
122515
122575
|
var TRACK_SKIPPED = ${trackSkipped};
|
|
122576
|
+
// Deliver errors through the SAME binding channel as the success path. The
|
|
122577
|
+
// consumer (evaluateWithBinding) runs Runtime.evaluate WITHOUT returnByValue/
|
|
122578
|
+
// awaitPromise, so the IIFE's return value is discarded \u2014 a 'return' here never
|
|
122579
|
+
// settles the promise and the tool hangs until the 15s binding timeout. Route
|
|
122580
|
+
// every error through __argent_callback with result = JSON.stringify({ error }),
|
|
122581
|
+
// matching the shape the tool parses (response.result \u2192 JSON.parse \u2192 .error).
|
|
122582
|
+
function __argent_fail(msg) {
|
|
122583
|
+
__argent_callback(JSON.stringify({ requestId: REQUEST_ID, result: JSON.stringify({ error: msg }) }));
|
|
122584
|
+
}
|
|
122585
|
+
// Route any UNEXPECTED throw (outside the named guards below) through the same
|
|
122586
|
+
// binding, so a crash still settles immediately instead of hanging to the 15s
|
|
122587
|
+
// binding timeout. Mirrors inspect-at-point.ts's top-level try/catch.
|
|
122588
|
+
try {
|
|
122516
122589
|
var hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
122517
|
-
if (!hook)
|
|
122590
|
+
if (!hook) { __argent_fail('No DevTools hook'); return; }
|
|
122518
122591
|
// Collect fiber roots across ALL renderers. A single React renderer id is not
|
|
122519
122592
|
// safe to assume: secondary reconcilers (e.g. react-native-skia) frequently
|
|
122520
122593
|
// register first and own renderer id 1, whose roots contain only that library's
|
|
@@ -122532,7 +122605,7 @@ function makeComponentTreeScript(opts) {
|
|
|
122532
122605
|
var _legacy = hook.getFiberRoots(1);
|
|
122533
122606
|
if (_legacy) _legacy.forEach(function(_rt) { _allRoots.push(_rt); });
|
|
122534
122607
|
}
|
|
122535
|
-
if (_allRoots.length === 0)
|
|
122608
|
+
if (_allRoots.length === 0) { __argent_fail('No fiber roots'); return; }
|
|
122536
122609
|
// Pick the mounted root with the largest fiber subtree \u2014 i.e. the real app UI.
|
|
122537
122610
|
var root = _allRoots[0];
|
|
122538
122611
|
var _bestSize = -1;
|
|
@@ -122562,7 +122635,7 @@ function makeComponentTreeScript(opts) {
|
|
|
122562
122635
|
try { var m = __r(i); if (m && m.UIManager) { UIManagerMod = m.UIManager; break; } } catch(e) {}
|
|
122563
122636
|
}
|
|
122564
122637
|
}
|
|
122565
|
-
if (!UIManagerMod)
|
|
122638
|
+
if (!UIManagerMod) { __argent_fail('Could not find UIManager'); return; }
|
|
122566
122639
|
}
|
|
122567
122640
|
|
|
122568
122641
|
var SKIP = new Set([
|
|
@@ -122910,6 +122983,9 @@ function makeComponentTreeScript(opts) {
|
|
|
122910
122983
|
result.skippedCounts = skippedCounts;
|
|
122911
122984
|
}
|
|
122912
122985
|
__argent_callback(JSON.stringify({ requestId: REQUEST_ID, result: JSON.stringify(result) }));
|
|
122986
|
+
} catch (e) {
|
|
122987
|
+
__argent_fail('Component-tree script crashed: ' + (e && e.message ? e.message : String(e)));
|
|
122988
|
+
}
|
|
122913
122989
|
})()`;
|
|
122914
122990
|
}
|
|
122915
122991
|
|
|
@@ -131110,7 +131186,7 @@ function enrich(input) {
|
|
|
131110
131186
|
}
|
|
131111
131187
|
|
|
131112
131188
|
// ../tool-server/src/utils/react-profiler/pipeline/03-tag.ts
|
|
131113
|
-
var ANIMATED_PATTERN = /(Animated|Animation|Transition|Motion)
|
|
131189
|
+
var ANIMATED_PATTERN = /(?<![A-Z0-9])(Animated|Animation|Transition|Motion)(?=[A-Z0-9_(.]|$)/;
|
|
131114
131190
|
var RECYCLER_CHILD_PATTERN = /(ListItem|CellItem|Cell|Row|Item)$/i;
|
|
131115
131191
|
var RECYCLER_PARENT_PATTERN = /^(FlatList|SectionList|VirtualizedList|FlashList|RecyclerListView)/i;
|
|
131116
131192
|
function tag(input) {
|
|
@@ -132832,26 +132908,29 @@ function waitForXctraceReady(child, { notify, timeoutMs }) {
|
|
|
132832
132908
|
});
|
|
132833
132909
|
}
|
|
132834
132910
|
|
|
132835
|
-
// ../tool-server/src/utils/ios-profiler/export.ts
|
|
132836
|
-
var path20 = __toESM(require("path"));
|
|
132837
|
-
|
|
132838
132911
|
// ../tool-server/src/utils/ios-profiler/run-with-timeout.ts
|
|
132839
132912
|
var import_child_process2 = require("child_process");
|
|
132840
132913
|
var import_util6 = require("util");
|
|
132841
132914
|
var DEFAULT_EXEC_TIMEOUT_MS = 6e4;
|
|
132842
132915
|
var DEFAULT_EXEC_MAX_BUFFER = 256 * 1024 * 1024;
|
|
132843
|
-
async function
|
|
132844
|
-
const
|
|
132845
|
-
const { stdout, stderr } = await
|
|
132846
|
-
timeout: DEFAULT_EXEC_TIMEOUT_MS,
|
|
132847
|
-
maxBuffer: DEFAULT_EXEC_MAX_BUFFER,
|
|
132916
|
+
async function execFileAsyncWithTimeout(file2, args, options = {}) {
|
|
132917
|
+
const execFileAsync20 = (0, import_util6.promisify)(import_child_process2.execFile);
|
|
132918
|
+
const { stdout, stderr } = await execFileAsync20(file2, args, {
|
|
132848
132919
|
encoding: "utf-8",
|
|
132849
|
-
...options
|
|
132920
|
+
...options,
|
|
132921
|
+
// The timeout and maxBuffer are this wrapper's whole purpose (the
|
|
132922
|
+
// event-loop-freeze and ENOBUFS guards documented above), so they are
|
|
132923
|
+
// applied AFTER ...options — a caller can never silently weaken them by
|
|
132924
|
+
// passing its own. maxBuffer stays a floor: a caller may raise it for an
|
|
132925
|
+
// even larger capture, but never drop below the 256 MiB guard.
|
|
132926
|
+
timeout: DEFAULT_EXEC_TIMEOUT_MS,
|
|
132927
|
+
maxBuffer: Math.max(options.maxBuffer ?? 0, DEFAULT_EXEC_MAX_BUFFER)
|
|
132850
132928
|
});
|
|
132851
132929
|
return { stdout, stderr };
|
|
132852
132930
|
}
|
|
132853
132931
|
|
|
132854
132932
|
// ../tool-server/src/utils/ios-profiler/export.ts
|
|
132933
|
+
var path20 = __toESM(require("path"));
|
|
132855
132934
|
var CPU_SCHEMA_CANDIDATES = ["time-profile", "cpu-profile", "time-sample"];
|
|
132856
132935
|
var EXPORTS = {
|
|
132857
132936
|
cpu: {
|
|
@@ -132869,9 +132948,12 @@ var EXPORTS = {
|
|
|
132869
132948
|
};
|
|
132870
132949
|
async function discoverTraceSchemas(traceFile, diagnostics) {
|
|
132871
132950
|
try {
|
|
132872
|
-
const { stdout: toc } = await
|
|
132873
|
-
|
|
132874
|
-
|
|
132951
|
+
const { stdout: toc } = await execFileAsyncWithTimeout("xctrace", [
|
|
132952
|
+
"export",
|
|
132953
|
+
"--input",
|
|
132954
|
+
traceFile,
|
|
132955
|
+
"--toc"
|
|
132956
|
+
]);
|
|
132875
132957
|
const schemas = [];
|
|
132876
132958
|
const schemaRe = /schema="([^"]+)"/g;
|
|
132877
132959
|
let m;
|
|
@@ -132906,9 +132988,15 @@ async function tryCpuExportFallback(traceFile, outPath, diagnostics) {
|
|
|
132906
132988
|
for (const candidate of CPU_SCHEMA_CANDIDATES) {
|
|
132907
132989
|
const xpath = `/trace-toc/run[@number="1"]/data/table[@schema="${candidate}"]`;
|
|
132908
132990
|
try {
|
|
132909
|
-
await
|
|
132910
|
-
|
|
132911
|
-
|
|
132991
|
+
await execFileAsyncWithTimeout("xctrace", [
|
|
132992
|
+
"export",
|
|
132993
|
+
"--input",
|
|
132994
|
+
traceFile,
|
|
132995
|
+
"--output",
|
|
132996
|
+
outPath,
|
|
132997
|
+
"--xpath",
|
|
132998
|
+
xpath
|
|
132999
|
+
]);
|
|
132912
133000
|
diagnostics.cpuSchemaUsed = candidate;
|
|
132913
133001
|
return true;
|
|
132914
133002
|
} catch {
|
|
@@ -132933,9 +133021,15 @@ async function exportIosTraceData(traceFile) {
|
|
|
132933
133021
|
const resolvedXpath = await resolveCpuXpath(traceFile, diagnostics);
|
|
132934
133022
|
if (resolvedXpath) {
|
|
132935
133023
|
try {
|
|
132936
|
-
await
|
|
132937
|
-
|
|
132938
|
-
|
|
133024
|
+
await execFileAsyncWithTimeout("xctrace", [
|
|
133025
|
+
"export",
|
|
133026
|
+
"--input",
|
|
133027
|
+
traceFile,
|
|
133028
|
+
"--output",
|
|
133029
|
+
outPath,
|
|
133030
|
+
"--xpath",
|
|
133031
|
+
resolvedXpath
|
|
133032
|
+
]);
|
|
132939
133033
|
exportedFiles[key] = outPath;
|
|
132940
133034
|
continue;
|
|
132941
133035
|
} catch (err) {
|
|
@@ -132952,9 +133046,15 @@ async function exportIosTraceData(traceFile) {
|
|
|
132952
133046
|
continue;
|
|
132953
133047
|
}
|
|
132954
133048
|
try {
|
|
132955
|
-
await
|
|
132956
|
-
|
|
132957
|
-
|
|
133049
|
+
await execFileAsyncWithTimeout("xctrace", [
|
|
133050
|
+
"export",
|
|
133051
|
+
"--input",
|
|
133052
|
+
traceFile,
|
|
133053
|
+
"--output",
|
|
133054
|
+
outPath,
|
|
133055
|
+
"--xpath",
|
|
133056
|
+
config2.xpath
|
|
133057
|
+
]);
|
|
132958
133058
|
exportedFiles[key] = outPath;
|
|
132959
133059
|
} catch (err) {
|
|
132960
133060
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -133608,7 +133708,7 @@ var import_child_process3 = require("child_process");
|
|
|
133608
133708
|
var ENV_OVERRIDE = "ARGENT_IOS_CAPTURE";
|
|
133609
133709
|
function readActiveXcodeVersion() {
|
|
133610
133710
|
try {
|
|
133611
|
-
const out = (0, import_child_process3.
|
|
133711
|
+
const out = (0, import_child_process3.execFileSync)("xcodebuild", ["-version"], {
|
|
133612
133712
|
encoding: "utf-8",
|
|
133613
133713
|
timeout: 5e3,
|
|
133614
133714
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -134269,9 +134369,10 @@ var STOP_KILL_MS = 5e3;
|
|
|
134269
134369
|
function enumerateRunningUserApps(udid) {
|
|
134270
134370
|
let launchctlOutput;
|
|
134271
134371
|
try {
|
|
134272
|
-
launchctlOutput = (0, import_child_process4.
|
|
134372
|
+
launchctlOutput = (0, import_child_process4.execFileSync)("xcrun", ["simctl", "spawn", udid, "launchctl", "list"], {
|
|
134273
134373
|
encoding: "utf-8",
|
|
134274
|
-
timeout: DETECT_RUNNING_APP_TIMEOUT_MS
|
|
134374
|
+
timeout: DETECT_RUNNING_APP_TIMEOUT_MS,
|
|
134375
|
+
maxBuffer: DEFAULT_EXEC_MAX_BUFFER
|
|
134275
134376
|
});
|
|
134276
134377
|
} catch (err) {
|
|
134277
134378
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -134307,9 +134408,16 @@ function enumerateRunningUserApps(udid) {
|
|
|
134307
134408
|
}
|
|
134308
134409
|
let listAppsOutput;
|
|
134309
134410
|
try {
|
|
134310
|
-
|
|
134411
|
+
const rawPlist = (0, import_child_process4.execFileSync)("xcrun", ["simctl", "listapps", udid], {
|
|
134311
134412
|
encoding: "utf-8",
|
|
134312
|
-
timeout: DETECT_RUNNING_APP_TIMEOUT_MS
|
|
134413
|
+
timeout: DETECT_RUNNING_APP_TIMEOUT_MS,
|
|
134414
|
+
maxBuffer: DEFAULT_EXEC_MAX_BUFFER
|
|
134415
|
+
});
|
|
134416
|
+
listAppsOutput = (0, import_child_process4.execFileSync)("plutil", ["-convert", "json", "-o", "-", "--", "-"], {
|
|
134417
|
+
encoding: "utf-8",
|
|
134418
|
+
input: rawPlist,
|
|
134419
|
+
timeout: DETECT_RUNNING_APP_TIMEOUT_MS,
|
|
134420
|
+
maxBuffer: DEFAULT_EXEC_MAX_BUFFER
|
|
134313
134421
|
});
|
|
134314
134422
|
} catch (err) {
|
|
134315
134423
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -135202,8 +135310,9 @@ async function renderHangStacksAndroid(opts, target) {
|
|
|
135202
135310
|
return `_Invalid hang_index ${opts.hangIndex}. There are ${hangRows.length} hangs (0-indexed)._`;
|
|
135203
135311
|
}
|
|
135204
135312
|
const hang = hangRows[opts.hangIndex];
|
|
135205
|
-
const startNs = hang.ts_ns;
|
|
135206
|
-
const
|
|
135313
|
+
const startNs = Number(hang.ts_ns);
|
|
135314
|
+
const durNs = Number(hang.dur_ns);
|
|
135315
|
+
const endNs = startNs + durNs;
|
|
135207
135316
|
const [stateRows, sampleRows] = await Promise.all([
|
|
135208
135317
|
runTpQuery({
|
|
135209
135318
|
tracePath: opts.tracePath,
|
|
@@ -135224,18 +135333,22 @@ async function renderHangStacksAndroid(opts, target) {
|
|
|
135224
135333
|
}
|
|
135225
135334
|
}).catch(() => [])
|
|
135226
135335
|
]);
|
|
135227
|
-
const durationMs = Math.round(
|
|
135336
|
+
const durationMs = Math.round(durNs / 1e6);
|
|
135337
|
+
const stateBreakdown = stateRows.map((r) => ({
|
|
135338
|
+
state: r.state,
|
|
135339
|
+
blockedFunction: r.blocked_function,
|
|
135340
|
+
durationMs: Math.round(Number(r.total_dur_ns) / 1e6)
|
|
135341
|
+
}));
|
|
135228
135342
|
const lines = [
|
|
135229
135343
|
`## Hang #${opts.hangIndex} \u2014 ${hang.kind} (${durationMs}ms)` + (hang.reason ? ` \u2014 reason: \`${hang.reason}\`` : ""),
|
|
135230
135344
|
""
|
|
135231
135345
|
];
|
|
135232
|
-
if (
|
|
135346
|
+
if (stateBreakdown.length > 0) {
|
|
135233
135347
|
lines.push("### Main-thread State Breakdown", "");
|
|
135234
135348
|
lines.push("| State | Blocked on | Duration |", "|---|---|---|");
|
|
135235
|
-
for (const
|
|
135236
|
-
const ms = Math.round(row.total_dur_ns / 1e6);
|
|
135349
|
+
for (const entry of stateBreakdown) {
|
|
135237
135350
|
lines.push(
|
|
135238
|
-
`| ${
|
|
135351
|
+
`| ${entry.state} | ${entry.blockedFunction ? `\`${entry.blockedFunction}\`` : "\u2014"} | ${entry.durationMs}ms |`
|
|
135239
135352
|
);
|
|
135240
135353
|
}
|
|
135241
135354
|
lines.push("");
|
|
@@ -135258,13 +135371,7 @@ async function renderHangStacksAndroid(opts, target) {
|
|
|
135258
135371
|
lines.push("```");
|
|
135259
135372
|
}
|
|
135260
135373
|
} else {
|
|
135261
|
-
const blocking = summarizeHangBlocking(
|
|
135262
|
-
stateRows.map((r) => ({
|
|
135263
|
-
state: r.state,
|
|
135264
|
-
blockedFunction: r.blocked_function,
|
|
135265
|
-
durationMs: Math.round(r.total_dur_ns / 1e6)
|
|
135266
|
-
}))
|
|
135267
|
-
);
|
|
135374
|
+
const blocking = summarizeHangBlocking(stateBreakdown);
|
|
135268
135375
|
lines.push("### Main-thread Samples During Hang", "");
|
|
135269
135376
|
if (blocking && blocking.kind === "blocked") {
|
|
135270
135377
|
lines.push(
|
|
@@ -135274,7 +135381,7 @@ async function renderHangStacksAndroid(opts, target) {
|
|
|
135274
135381
|
lines.push(
|
|
135275
135382
|
`_No usable on-CPU stack samples were captured during this hang, even though the main thread was on-CPU (state \`${blocking.dominantState}\`, executing) for most of the window \u2014 the sampler could not unwind a call stack (commonly stripped or missing frame symbols). This is genuine main-thread CPU work, not a wait; see the state breakdown above._`
|
|
135276
135383
|
);
|
|
135277
|
-
} else if (
|
|
135384
|
+
} else if (stateBreakdown.length > 0) {
|
|
135278
135385
|
lines.push(
|
|
135279
135386
|
`_No on-CPU stack samples were captured during this hang. The main thread spent the window off-CPU or runnable-but-not-scheduled, so there is no CPU call stack to show; see the state breakdown above._`
|
|
135280
135387
|
);
|
|
@@ -135405,8 +135512,12 @@ function cpuRowsToAggregatorRows(rows, traceStartNs) {
|
|
|
135405
135512
|
timestampsNs: [],
|
|
135406
135513
|
callChains: [{ chain: [dominant], count: row.sample_count }],
|
|
135407
135514
|
precomputedBursts: parseBurstWindows(row.burst_windows, traceStartMs),
|
|
135408
|
-
|
|
135409
|
-
|
|
135515
|
+
// first/last_ts_ns are absolute CLOCK_MONOTONIC ns: they exceed 2^53 after
|
|
135516
|
+
// ~104 days of device uptime, so the WASM decoder hands them back as bigint
|
|
135517
|
+
// (see readCell). traceStartNs is already a plain Number, so coerce here to
|
|
135518
|
+
// avoid "Cannot mix BigInt and other types" — values stay integral.
|
|
135519
|
+
firstMs: Math.round((Number(row.first_ts_ns) - traceStartNs) / 1e6),
|
|
135520
|
+
lastMs: Math.round((Number(row.last_ts_ns) - traceStartNs) / 1e6),
|
|
135410
135521
|
sampleCount: row.sample_count
|
|
135411
135522
|
});
|
|
135412
135523
|
}
|
|
@@ -135414,16 +135525,16 @@ function cpuRowsToAggregatorRows(rows, traceStartNs) {
|
|
|
135414
135525
|
}
|
|
135415
135526
|
function hangRowsToBottlenecks(rows, traceStartNs) {
|
|
135416
135527
|
return rows.map((row) => {
|
|
135417
|
-
const
|
|
135418
|
-
const startNs = row.ts_ns - traceStartNs;
|
|
135528
|
+
const durNs = Number(row.dur_ns);
|
|
135529
|
+
const startNs = Number(row.ts_ns) - traceStartNs;
|
|
135419
135530
|
return {
|
|
135420
135531
|
type: "ui_hang",
|
|
135421
135532
|
platform: "android",
|
|
135422
135533
|
hangType: row.kind,
|
|
135423
|
-
durationMs,
|
|
135534
|
+
durationMs: Math.round(durNs / 1e6),
|
|
135424
135535
|
startTimeFormatted: formatTraceTime(startNs),
|
|
135425
135536
|
startNs,
|
|
135426
|
-
endNs: startNs +
|
|
135537
|
+
endNs: startNs + durNs,
|
|
135427
135538
|
suspectedFunctions: [],
|
|
135428
135539
|
appCallChains: [],
|
|
135429
135540
|
severity: classifyAndroidHangSeverity(row),
|
|
@@ -135473,7 +135584,7 @@ function formatTraceTime(ns) {
|
|
|
135473
135584
|
function classifyAndroidHangSeverity(row) {
|
|
135474
135585
|
if (row.kind === "anr") return "RED";
|
|
135475
135586
|
if (row.reason === "App Deadline Missed") return "RED";
|
|
135476
|
-
const durationMs = row.dur_ns / 1e6;
|
|
135587
|
+
const durationMs = Number(row.dur_ns) / 1e6;
|
|
135477
135588
|
if (durationMs > 500) return "RED";
|
|
135478
135589
|
return "YELLOW";
|
|
135479
135590
|
}
|
|
@@ -140825,11 +140936,14 @@ It parks until the user presses "Complete selection" in the Argent Lens window (
|
|
|
140825
140936
|
that opens automatically on the user's screen), then returns their choices and any comments.
|
|
140826
140937
|
|
|
140827
140938
|
Returns one of:
|
|
140828
|
-
\u2022 { status: "completed", selections: [{ element, chosenVariant, comment? }], unselected,
|
|
140829
|
-
annotations: [{ target, match, comment }], globalComment }
|
|
140830
|
-
\u2014 the user
|
|
140831
|
-
\`annotations\` are free-form comments the user pinned to specific on-screen
|
|
140832
|
-
the inspector \u2014 treat each as a change request for that element.
|
|
140939
|
+
\u2022 { status: "completed", round, selections: [{ element, chosenVariant, comment? }], unselected,
|
|
140940
|
+
annotations: [{ target, match, comment }], globalComment, morePending? }
|
|
140941
|
+
\u2014 the user finished this round; apply chosenVariant for each element (skip ones in
|
|
140942
|
+
\`unselected\`). \`annotations\` are free-form comments the user pinned to specific on-screen
|
|
140943
|
+
elements via the inspector \u2014 treat each as a change request for that element.
|
|
140944
|
+
If \`morePending\` is true, another already-decided round or a freshly-staged round is
|
|
140945
|
+
still waiting \u2014 call await_user_selection AGAIN (repeat until you get a completed result
|
|
140946
|
+
without \`morePending\`, a \`pending\`, or \`no_proposals\`); do not stop on this result alone.
|
|
140833
140947
|
\u2022 { status: "pending", message, proposedElements } \u2014 timeoutSeconds elapsed with no submission.
|
|
140834
140948
|
Expected, not an error: the proposals are still live; call await_user_selection AGAIN.
|
|
140835
140949
|
\u2022 { status: "no_proposals" } \u2014 you called this before propose_variant.
|