@swmansion/argent 0.25.3-next.2 → 0.25.3-next.4

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.
Binary file
Binary file
Binary file
Binary file
package/dist/cli-cmds.mjs CHANGED
@@ -2342,6 +2342,11 @@ var FAILURE_CODES = {
2342
2342
  IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
2343
2343
  IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
2344
2344
  ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
2345
+ // The hinge of a foldable iOS simulator: the server refused the request on a
2346
+ // foldable (a bad angle, a hinge that would not move) vs. nothing to fold —
2347
+ // a device that is not foldable, no hinge route, a remote simulator.
2348
+ IOS_FOLD_FAILED: "IOS_FOLD_FAILED",
2349
+ IOS_FOLD_UNSUPPORTED: "IOS_FOLD_UNSUPPORTED",
2345
2350
  PASTE_CLIPBOARD_SET_FAILED: "PASTE_CLIPBOARD_SET_FAILED",
2346
2351
  PASTE_CLIPBOARD_UNSUPPORTED: "PASTE_CLIPBOARD_UNSUPPORTED",
2347
2352
  SETTINGS_PERMISSION_UNSUPPORTED: "SETTINGS_PERMISSION_UNSUPPORTED",
@@ -21872,7 +21877,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
21872
21877
  var SESSION_ID2 = randomUUID5();
21873
21878
  function readCliVersion() {
21874
21879
  if (true) {
21875
- return "0.25.3-next.2";
21880
+ return "0.25.3-next.4";
21876
21881
  }
21877
21882
  return "0.0.0";
21878
21883
  }
@@ -23214,13 +23219,14 @@ multi-platform launch auto-detects a device instead. Pass --device to attach to
23214
23219
  a running instance.
23215
23220
 
23216
23221
  A directory run prints only the steps that need attention (each failure, each
23217
- warning, and each script step's output), then its outcome, then a final flow
23218
- summary; --recursive walks subdirectories too (dot-directories and node_modules
23219
- are skipped). A flow that fails its steps keeps the batch running, as does one
23220
- the server rejects up front \u2014 an invalid file, or a device it cannot resolve. A
23221
- transport failure, a rejection the server does not mark as validation, or a
23222
- reply that is not a report stops the batch and counts the remaining flows
23223
- skipped.
23222
+ warning, and each script step's output), then its outcome. After the last flow
23223
+ it lists every failed flow with its reason and a command that re-runs that flow
23224
+ alone, then a final flow summary; --recursive walks subdirectories too
23225
+ (dot-directories and node_modules are skipped). A flow that fails its steps
23226
+ keeps the batch running, as does one the server rejects up front \u2014 an invalid
23227
+ file, or a device it cannot resolve. A transport failure, a rejection the server
23228
+ does not mark as validation, or a reply that is not a report stops the batch and
23229
+ counts the remaining flows skipped.
23224
23230
 
23225
23231
  Runs require the auto-started local tool server;
23226
23232
  ARGENT_TOOLS_URL and \`argent link\` routing are not supported.
@@ -23306,13 +23312,15 @@ function renderEchoLine(s) {
23306
23312
  }
23307
23313
  return ` ${indent}\u203A ${s.message}`;
23308
23314
  }
23309
- function renderStepLine(s, n2, topFlow) {
23315
+ function stepLabel(s, topFlow) {
23310
23316
  const where = s.flow && s.flow !== topFlow ? ` [${s.flow}]` : "";
23311
23317
  const what = s.tool ?? s.target;
23312
- const label = what ? `${s.kind} ${what}` : s.kind;
23318
+ return `${what ? `${s.kind} ${what}` : s.kind}${where}`;
23319
+ }
23320
+ function renderStepLine(s, n2, topFlow) {
23313
23321
  const reason = s.reason ? ` \u2014 ${s.reason}` : "";
23314
23322
  const glyph = s.status === "pass" && s.warning ? "\u26A0" : STATUS_GLYPH[s.status];
23315
- return ` ${glyph} ${String(n2).padStart(2)} ${stepIndent(s.depth)}${label}${where}${durationSuffix(s.durationMs)}${reason}`;
23323
+ return ` ${glyph} ${String(n2).padStart(2)} ${stepIndent(s.depth)}${stepLabel(s, topFlow)}${durationSuffix(s.durationMs)}${reason}`;
23316
23324
  }
23317
23325
  function renderUnderStepLine(s, n2, text2) {
23318
23326
  return `${" ".repeat(5 + Math.max(2, String(n2).length))}${stepIndent(s.depth)}${text2}`;
@@ -23376,6 +23384,35 @@ function renderFailedSteps(report) {
23376
23384
  function renderBatchSummary(counts, durationMs) {
23377
23385
  return `${counts.failed === 0 ? "PASS" : "FAIL"} \u2014 ${counts.total} flow${counts.total === 1 ? "" : "s"}: ${counts.passed} passed, ${counts.failed} failed, ${counts.skipped} skipped${durationSuffix(durationMs)}`;
23378
23386
  }
23387
+ function summarizeFailure(report) {
23388
+ let n2 = 0;
23389
+ for (const s of report.steps) {
23390
+ if (s.kind === "echo") continue;
23391
+ n2++;
23392
+ if (s.status === "fail" || s.status === "error") {
23393
+ const detail = s.reason ? String(s.reason) : void 0;
23394
+ return { headline: `step ${n2} ${stepLabel(s, report.flow)}`, detail };
23395
+ }
23396
+ }
23397
+ return { headline: "failed with no failing step" };
23398
+ }
23399
+ function renderFailedFlow(f) {
23400
+ const lines = [` ${STATUS_GLYPH.fail} ${f.path ? `${f.path} \u203A ` : ""}${f.headline}`];
23401
+ for (const line of f.detail?.split("\n") ?? []) if (line) lines.push(` ${line}`);
23402
+ if (f.rerun) lines.push(` re-run: ${f.rerun}`);
23403
+ return lines;
23404
+ }
23405
+ function renderSingleFailure(report) {
23406
+ return report.ok ? [] : ["", ...renderFailedFlow(summarizeFailure(report))];
23407
+ }
23408
+ function renderFailedFlows(failed) {
23409
+ if (failed.length === 0) return [];
23410
+ return [
23411
+ "",
23412
+ `Failed flows (${failed.length})`,
23413
+ ...failed.flatMap((f) => ["", ...renderFailedFlow(f)])
23414
+ ];
23415
+ }
23379
23416
  var SAFE_ARTIFACT_NAME = FLOW_NAME_PATTERN;
23380
23417
  var SAFE_FLOW_NAME = FLOW_NAME_PATTERN;
23381
23418
  var FLOWS_DIR = path14.join(".argent", "flows");
@@ -23384,6 +23421,17 @@ function shellQuoteArg(arg) {
23384
23421
  if (SHELL_SAFE_ARG.test(arg)) return arg;
23385
23422
  return `'${arg.replaceAll("'", "'\\''")}'`;
23386
23423
  }
23424
+ function rerunCommand(flowPath, rel, projectRoot, args) {
23425
+ const pathArg = (p) => shellQuoteArg(p.startsWith("-") ? `.${path14.sep}${p}` : p);
23426
+ const fromCwd = path14.relative(projectRoot, flowPath);
23427
+ const shown = path14.isAbsolute(fromCwd) || fromCwd.split(/[\\/]+/).includes("..") ? flowPath : fromCwd;
23428
+ const parts = ["argent flow run", pathArg(shown)];
23429
+ if (args.device) parts.push("--device", shellQuoteArg(args.device));
23430
+ if (args.platform) parts.push("--platform", shellQuoteArg(args.platform));
23431
+ if (args.updateBaselines) parts.push("--update-baselines");
23432
+ if (args.output) parts.push("--output", pathArg(path14.join(args.output, path14.dirname(rel))));
23433
+ return parts.join(" ");
23434
+ }
23387
23435
  var EXPORT_SOURCE_MARKER = ".argent-flow-source";
23388
23436
  var MARKER_READ_RETRIES = 4;
23389
23437
  var MARKER_READ_DELAY_MS = 5;
@@ -23541,6 +23589,7 @@ function renderReport(report) {
23541
23589
  }
23542
23590
  }
23543
23591
  }
23592
+ lines.push(...renderSingleFailure(report));
23544
23593
  lines.push(`
23545
23594
  ${renderSummary(report)}`);
23546
23595
  return lines.join("\n");
@@ -23689,6 +23738,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
23689
23738
  const { callTool, baseUrl } = createToolsClient({ paths: options.paths });
23690
23739
  const outputBase = args.output ? path14.resolve(args.output) : void 0;
23691
23740
  const results = [];
23741
+ const failures = [];
23692
23742
  const batchStartedAt = Date.now();
23693
23743
  let stopped = false;
23694
23744
  for (const [i2, rel] of flows.entries()) {
@@ -23698,42 +23748,42 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
23698
23748
  if (!args.json) console.log(` ${STATUS_GLYPH.skip} not run (batch stopped)`);
23699
23749
  continue;
23700
23750
  }
23751
+ const flowPath = path14.join(dir, rel);
23752
+ const rerun = rerunCommand(flowPath, rel, projectRoot, args);
23701
23753
  let report;
23702
23754
  try {
23703
- const resp = await callTool(
23704
- "flow-execute",
23705
- buildRunPayload(path14.join(dir, rel), projectRoot, args)
23706
- );
23755
+ const resp = await callTool("flow-execute", buildRunPayload(flowPath, projectRoot, args));
23707
23756
  if (isFlowReport(resp.data)) report = resp.data;
23708
23757
  } catch (err) {
23709
23758
  const message = err instanceof Error ? err.message : String(err);
23710
23759
  const toolErr = err instanceof ToolInvocationError ? err : void 0;
23711
23760
  const rejectedThisFlowOnly = toolErr?.errorKind === "validation";
23712
- if (!args.json) {
23713
- console.log(
23714
- ` ${STATUS_GLYPH.error} ` + (rejectedThisFlowOnly ? rejectionVerdict(toolErr?.errorCode) : "did not finish (run error)")
23715
- );
23716
- }
23761
+ const verdict = rejectedThisFlowOnly ? rejectionVerdict(toolErr?.errorCode) : "did not finish (run error)";
23762
+ if (!args.json) console.log(` ${STATUS_GLYPH.error} ${verdict}`);
23717
23763
  console.error(message);
23718
23764
  results.push({ path: rel, status: "fail", error: message, ...failureSignal2(err) });
23765
+ failures.push({ path: rel, headline: verdict, detail: message, rerun });
23719
23766
  if (!rejectedThisFlowOnly) stopped = true;
23720
23767
  continue;
23721
23768
  }
23722
23769
  if (!report) {
23723
23770
  const message = `"${rel}" did not produce a run report.`;
23724
- if (!args.json) console.log(` ${STATUS_GLYPH.error} did not finish (no run report)`);
23771
+ const verdict = "did not finish (no run report)";
23772
+ if (!args.json) console.log(` ${STATUS_GLYPH.error} ${verdict}`);
23725
23773
  console.error(message);
23726
23774
  results.push({ path: rel, status: "fail", error: message });
23775
+ failures.push({ path: rel, headline: verdict, detail: message, rerun });
23727
23776
  stopped = true;
23728
23777
  continue;
23729
23778
  }
23730
23779
  await exportAndResolveArtifacts(
23731
23780
  report,
23732
23781
  outputBase ? path14.join(outputBase, path14.dirname(rel)) : void 0,
23733
- path14.join(dir, rel),
23782
+ flowPath,
23734
23783
  baseUrl
23735
23784
  );
23736
23785
  results.push({ path: rel, status: report.ok ? "pass" : "fail", report });
23786
+ if (!report.ok) failures.push({ path: rel, ...summarizeFailure(report), rerun });
23737
23787
  if (!args.json) {
23738
23788
  for (const line of renderFailedSteps(report)) console.log(line);
23739
23789
  console.log(` ${renderSummary(report, { withDevice: true })}`);
@@ -23751,6 +23801,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
23751
23801
  JSON.stringify({ ok: counts.failed === 0, ...counts, durationMs, flows: results }, null, 2)
23752
23802
  );
23753
23803
  } else {
23804
+ for (const line of renderFailedFlows(failures)) console.log(line);
23754
23805
  console.log(`
23755
23806
  ${renderBatchSummary(counts, durationMs)}`);
23756
23807
  }
@@ -23983,6 +24034,7 @@ ${recovery}`,
23983
24034
  } else if (liveSteps > 0) {
23984
24035
  if (report.executionPrerequisite) console.log(` assumes: ${report.executionPrerequisite}`);
23985
24036
  for (const line of renderArtifactLines(report)) console.log(line);
24037
+ for (const line of renderSingleFailure(report)) console.log(line);
23986
24038
  console.log(`
23987
24039
  ${renderSummary(report, { withDevice: true })}`);
23988
24040
  } else {
@@ -15727,6 +15727,11 @@ var FAILURE_CODES = {
15727
15727
  IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
15728
15728
  IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
15729
15729
  ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
15730
+ // The hinge of a foldable iOS simulator: the server refused the request on a
15731
+ // foldable (a bad angle, a hinge that would not move) vs. nothing to fold —
15732
+ // a device that is not foldable, no hinge route, a remote simulator.
15733
+ IOS_FOLD_FAILED: "IOS_FOLD_FAILED",
15734
+ IOS_FOLD_UNSUPPORTED: "IOS_FOLD_UNSUPPORTED",
15730
15735
  PASTE_CLIPBOARD_SET_FAILED: "PASTE_CLIPBOARD_SET_FAILED",
15731
15736
  PASTE_CLIPBOARD_UNSUPPORTED: "PASTE_CLIPBOARD_UNSUPPORTED",
15732
15737
  SETTINGS_PERMISSION_UNSUPPORTED: "SETTINGS_PERMISSION_UNSUPPORTED",
@@ -16725,7 +16730,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
16725
16730
  var SESSION_ID = randomUUID4();
16726
16731
  function readCliVersion() {
16727
16732
  if (true) {
16728
- return "0.25.3-next.2";
16733
+ return "0.25.3-next.4";
16729
16734
  }
16730
16735
  return "0.0.0";
16731
16736
  }
@@ -16522,6 +16522,11 @@ var FAILURE_CODES = {
16522
16522
  IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
16523
16523
  IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
16524
16524
  ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
16525
+ // The hinge of a foldable iOS simulator: the server refused the request on a
16526
+ // foldable (a bad angle, a hinge that would not move) vs. nothing to fold —
16527
+ // a device that is not foldable, no hinge route, a remote simulator.
16528
+ IOS_FOLD_FAILED: "IOS_FOLD_FAILED",
16529
+ IOS_FOLD_UNSUPPORTED: "IOS_FOLD_UNSUPPORTED",
16525
16530
  PASTE_CLIPBOARD_SET_FAILED: "PASTE_CLIPBOARD_SET_FAILED",
16526
16531
  PASTE_CLIPBOARD_UNSUPPORTED: "PASTE_CLIPBOARD_UNSUPPORTED",
16527
16532
  SETTINGS_PERMISSION_UNSUPPORTED: "SETTINGS_PERMISSION_UNSUPPORTED",
@@ -18639,6 +18644,7 @@ var AUTO_SCREENSHOT_TOOLS = /* @__PURE__ */ new Set([
18639
18644
  "keyboard",
18640
18645
  "paste",
18641
18646
  "rotate",
18647
+ "fold",
18642
18648
  "launch-app",
18643
18649
  "restart-app",
18644
18650
  "open-url",
@@ -18659,6 +18665,9 @@ var AUTO_SCREENSHOT_DELAY_MS_BY_TOOL = {
18659
18665
  "run-sequence": 15e3,
18660
18666
  "button": 1500,
18661
18667
  "rotate": 1e3,
18668
+ // The fold tool already waits for the panel hand-over; the cap covers the
18669
+ // repaint after it.
18670
+ "fold": 1500,
18662
18671
  "keyboard": 300,
18663
18672
  "paste": 300,
18664
18673
  "describe": 100
@@ -18679,6 +18688,7 @@ var AUTO_DESCRIBE_TOOLS = /* @__PURE__ */ new Set([
18679
18688
  "keyboard",
18680
18689
  "paste",
18681
18690
  "rotate",
18691
+ "fold",
18682
18692
  "launch-app",
18683
18693
  "restart-app",
18684
18694
  "open-url",
@@ -1976,6 +1976,16 @@
1976
1976
  let ws = null;
1977
1977
  let wsOpen = false;
1978
1978
  let currentUdid = null;
1979
+ // A foldable's panel: the CoreSimulator screen id its stream shows and
1980
+ // its touches name (1 the cover panel, 3 the inner one on the iPhone
1981
+ // Duo). null for a device with one panel, where commands name none.
1982
+ // This page's touches and wheels go to the simulator-server directly and
1983
+ // name this value, which the panel poll below refreshes every 1.5 s: for
1984
+ // up to that long after a fold, a preview touch can go to the panel that
1985
+ // went dark. An accepted limitation of the manual preview; the agent
1986
+ // tools resolve the panel on every touch.
1987
+ let activeScreen = null;
1988
+ let panelPollTimer = null;
1979
1989
  let img = null;
1980
1990
  let stage = null;
1981
1991
  // Auto-reconnect bookkeeping (see scheduleReconnect): the simulator-server
@@ -2021,7 +2031,14 @@
2021
2031
  // While the element-comment inspector is active the stream is a
2022
2032
  // read-only annotation surface — never drive the device.
2023
2033
  if (typeof vp !== "undefined" && vp.inspect) return;
2024
- ws.send(JSON.stringify({ id: nextCmdId(), ...obj }));
2034
+ const payload = { id: nextCmdId(), ...obj };
2035
+ // simulator-server captures every panel of a foldable and follows
2036
+ // none: a touch or wheel that names no screen goes to the cover panel,
2037
+ // black once the device is open.
2038
+ if (activeScreen !== null && (obj.cmd === "touch" || obj.cmd === "wheel")) {
2039
+ payload.screen = activeScreen;
2040
+ }
2041
+ ws.send(JSON.stringify(payload));
2025
2042
  // Every command (touch/scroll/key) likely moved the screen — wake the
2026
2043
  // describe loop *now* so connectors/pins track interaction, not just
2027
2044
  // the fixed cadence. Only when something is actually anchored to the
@@ -2311,6 +2328,8 @@
2311
2328
  // /preview/describe/<oldUdid> after teardown.
2312
2329
  setDeviceIndicator(null);
2313
2330
  currentUdid = null;
2331
+ stopPanelPoll();
2332
+ activeScreen = null;
2314
2333
  describeWarmupPending = false;
2315
2334
  // Explicitly clear the img src — otherwise the browser keeps the MJPEG
2316
2335
  // HTTP connection open after the element is detached, and re-selecting
@@ -2338,6 +2357,46 @@
2338
2357
  // route) heals it instead of stranding the user on a refresh. The
2339
2358
  // reconnectTimer guard collapses the simultaneous img.onerror + ws.onclose
2340
2359
  // into a single attempt; backoff resets on a successful ws.onopen.
2360
+ // A foldable's stream URL already carries `?screen=<id>`.
2361
+ function withCacheBuster(url) {
2362
+ return `${url}${url.includes("?") ? "&" : "?"}t=${Date.now()}`;
2363
+ }
2364
+
2365
+ function stopPanelPoll() {
2366
+ if (panelPollTimer) {
2367
+ clearInterval(panelPollTimer);
2368
+ panelPollTimer = null;
2369
+ }
2370
+ }
2371
+
2372
+ // Follow a foldable across folds: re-ask the tool-server which panel the
2373
+ // device renders to, and move the stream and the touches when it changes.
2374
+ function startPanelPoll(udid) {
2375
+ stopPanelPoll();
2376
+ let inFlight = false;
2377
+ panelPollTimer = setInterval(async () => {
2378
+ if (inFlight || currentUdid !== udid || !img) return;
2379
+ inFlight = true;
2380
+ try {
2381
+ const res = await fetch(
2382
+ `${TOOL_SERVER}/preview/simulator-server/${encodeURIComponent(udid)}`
2383
+ );
2384
+ if (!res.ok) return;
2385
+ const info = await res.json();
2386
+ if (currentUdid !== udid || !img || !info.foldable) return;
2387
+ if (info.activeScreen !== activeScreen) {
2388
+ activeScreen = info.activeScreen;
2389
+ img.src = withCacheBuster(info.streamUrl);
2390
+ setStatus("");
2391
+ }
2392
+ } catch {
2393
+ /* transient; the next tick asks again */
2394
+ } finally {
2395
+ inFlight = false;
2396
+ }
2397
+ }, 1500);
2398
+ }
2399
+
2341
2400
  function scheduleReconnect(udid) {
2342
2401
  if (currentUdid !== udid || reconnectTimer) return;
2343
2402
  const delay = Math.min(1000 * 2 ** reconnectAttempts, 8000);
@@ -2428,7 +2487,9 @@
2428
2487
  img.alt = `Simulator ${udid.slice(0, 8)}`;
2429
2488
  img.draggable = false;
2430
2489
  // Append a cache-buster so re-connects don't reuse a stale MJPEG stream.
2431
- img.src = `${info.streamUrl}?t=${Date.now()}`;
2490
+ img.src = withCacheBuster(info.streamUrl);
2491
+ activeScreen = info.foldable ? info.activeScreen : null;
2492
+ if (info.foldable) startPanelPoll(udid);
2432
2493
  img.onerror = () => {
2433
2494
  setStatus("stream error", "error");
2434
2495
  scheduleReconnect(udid);