@swmansion/argent 0.24.0 → 0.24.1-next.1

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
@@ -7253,7 +7253,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
7253
7253
  var SESSION_ID2 = randomUUID5();
7254
7254
  function readCliVersion() {
7255
7255
  if (true) {
7256
- return "0.24.0";
7256
+ return "0.24.1-next.1";
7257
7257
  }
7258
7258
  return "0.0.0";
7259
7259
  }
@@ -8588,10 +8588,13 @@ chromium (a lone \`{ chromium: ... }\` target, or --platform chromium); a
8588
8588
  multi-platform launch auto-detects a device instead. Pass --device to attach to
8589
8589
  a running instance.
8590
8590
 
8591
- A directory run prints only failing steps plus a final flow summary;
8592
- --recursive walks subdirectories too (dot-directories and node_modules are
8593
- skipped). An invalid flow file fails alone and the batch continues; an infra
8594
- error stops the batch and counts the remaining flows skipped.
8591
+ A directory run prints each flow's failing steps and warnings, then its outcome,
8592
+ then a final flow summary; --recursive walks subdirectories too (dot-directories
8593
+ and node_modules are skipped). A flow that fails its steps keeps the batch
8594
+ running, as does one the server rejects up front \u2014 an invalid file, or a device
8595
+ it cannot resolve. A transport failure, a rejection the server does not mark as
8596
+ validation, or a reply that is not a report stops the batch and counts the
8597
+ remaining flows skipped.
8595
8598
 
8596
8599
  Runs require the auto-started local tool server;
8597
8600
  ARGENT_TOOLS_URL and \`argent link\` routing are not supported.
@@ -8614,8 +8617,10 @@ Options (run):
8614
8617
  instead (with a warning), so no flow's evidence is
8615
8618
  overwritten
8616
8619
  -r, --recursive With a directory path, also run flows in subdirectories
8617
- --json Print the raw JSON report
8618
- --json-stream Print progress and the final report as NDJSON (single flow only)
8620
+ --json Print the flow's JSON report, or a directory run's JSON
8621
+ aggregate
8622
+ --json-stream Print each step and the final report as NDJSON (single
8623
+ flow only, never with --json)
8619
8624
  --help, -h Show this help
8620
8625
  -- End of options \u2014 only needed for a flow whose name
8621
8626
  starts with "-" (\`argent flow run -- -nightly\`)
@@ -8981,14 +8986,16 @@ function buildRunPayload(flowPath, projectRoot, args) {
8981
8986
  function writeJsonStreamRecord(record) {
8982
8987
  console.log(JSON.stringify(record));
8983
8988
  }
8989
+ function failureSignal2(err) {
8990
+ if (!(err instanceof ToolInvocationError)) return {};
8991
+ return {
8992
+ ...err.errorCode ? { error_code: err.errorCode } : {},
8993
+ ...err.errorKind ? { error_kind: err.errorKind } : {}
8994
+ };
8995
+ }
8984
8996
  function writeJsonStreamError(err) {
8985
8997
  const message = err instanceof Error ? err.message : String(err);
8986
- writeJsonStreamRecord({
8987
- event: "error",
8988
- error: message,
8989
- ...err instanceof ToolInvocationError && err.errorCode ? { error_code: err.errorCode } : {},
8990
- ...err instanceof ToolInvocationError && err.errorKind ? { error_kind: err.errorKind } : {}
8991
- });
8998
+ writeJsonStreamRecord({ event: "error", error: message, ...failureSignal2(err) });
8992
8999
  }
8993
9000
  async function exportAndResolveArtifacts(report, outputDir, flowPath, baseUrl) {
8994
9001
  if (outputDir) {
@@ -8997,6 +9004,22 @@ async function exportAndResolveArtifacts(report, outputDir, flowPath, baseUrl) {
8997
9004
  }
8998
9005
  resolveArtifactDisplayPaths(report);
8999
9006
  }
9007
+ function rejectionVerdict(code) {
9008
+ switch (code) {
9009
+ case FAILURE_CODES.FLOW_FILE_INVALID:
9010
+ case FAILURE_CODES.FLOW_ENTRY_UNRECOGNIZED:
9011
+ case FAILURE_CODES.FLOW_E2E_HAS_PREREQUISITE:
9012
+ return "not run (invalid flow)";
9013
+ case FAILURE_CODES.FLOW_DEVICE_RESOLUTION:
9014
+ return "not run (no device resolved)";
9015
+ default:
9016
+ return "not run (rejected)";
9017
+ }
9018
+ }
9019
+ function isFlowReport(data) {
9020
+ const steps = data?.steps;
9021
+ return Array.isArray(steps) && steps.every((step) => !!step && typeof step === "object");
9022
+ }
9000
9023
  async function runFlowDirectory(dir, args, projectRoot, options) {
9001
9024
  let flows;
9002
9025
  try {
@@ -9032,18 +9055,24 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
9032
9055
  "flow-execute",
9033
9056
  buildRunPayload(path14.join(dir, rel), projectRoot, args)
9034
9057
  );
9035
- const data = resp.data;
9036
- if (data && typeof data === "object" && "steps" in data) report = data;
9058
+ if (isFlowReport(resp.data)) report = resp.data;
9037
9059
  } catch (err) {
9038
9060
  const message = err instanceof Error ? err.message : String(err);
9061
+ const toolErr = err instanceof ToolInvocationError ? err : void 0;
9062
+ const rejectedThisFlowOnly = toolErr?.errorKind === "validation";
9063
+ if (!args.json) {
9064
+ console.log(
9065
+ ` ${STATUS_GLYPH.error} ` + (rejectedThisFlowOnly ? rejectionVerdict(toolErr?.errorCode) : "did not finish (run error)")
9066
+ );
9067
+ }
9039
9068
  console.error(message);
9040
- results.push({ path: rel, status: "fail", error: message });
9041
- const rejectedThisFlowOnly = err instanceof ToolInvocationError && err.errorKind === "validation";
9069
+ results.push({ path: rel, status: "fail", error: message, ...failureSignal2(err) });
9042
9070
  if (!rejectedThisFlowOnly) stopped = true;
9043
9071
  continue;
9044
9072
  }
9045
9073
  if (!report) {
9046
9074
  const message = `"${rel}" did not produce a run report.`;
9075
+ if (!args.json) console.log(` ${STATUS_GLYPH.error} did not finish (no run report)`);
9047
9076
  console.error(message);
9048
9077
  results.push({ path: rel, status: "fail", error: message });
9049
9078
  stopped = true;
@@ -9268,9 +9297,19 @@ ${recovery}`,
9268
9297
  );
9269
9298
  report = resp.data;
9270
9299
  } catch (err) {
9300
+ if (!args.json && !args.jsonStream) {
9301
+ if (liveSteps === 0) console.log(`Flow "${flowName}"`);
9302
+ console.log(
9303
+ ` ${STATUS_GLYPH.error} ` + (err instanceof ToolInvocationError && err.errorKind === "validation" ? rejectionVerdict(err.errorCode) : "did not finish (run error)")
9304
+ );
9305
+ }
9271
9306
  return fail(err instanceof Error ? err.message : String(err), 1, err);
9272
9307
  }
9273
- if (!report || typeof report !== "object" || !("steps" in report)) {
9308
+ if (!isFlowReport(report)) {
9309
+ if (!args.json && !args.jsonStream) {
9310
+ if (liveSteps === 0) console.log(`Flow "${flowName}"`);
9311
+ console.log(` ${STATUS_GLYPH.error} did not finish (no run report)`);
9312
+ }
9274
9313
  return fail(`"${flowName}" did not produce a run report.`, 2);
9275
9314
  }
9276
9315
  try {
@@ -16625,7 +16625,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
16625
16625
  var SESSION_ID = randomUUID4();
16626
16626
  function readCliVersion() {
16627
16627
  if (true) {
16628
- return "0.24.0";
16628
+ return "0.24.1-next.1";
16629
16629
  }
16630
16630
  return "0.0.0";
16631
16631
  }
@@ -93916,7 +93916,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
93916
93916
  var SESSION_ID = (0, import_node_crypto3.randomUUID)();
93917
93917
  function readCliVersion() {
93918
93918
  if (true) {
93919
- return "0.24.0";
93919
+ return "0.24.1-next.1";
93920
93920
  }
93921
93921
  return "0.0.0";
93922
93922
  }
@@ -143956,11 +143956,25 @@ function selectorToYaml(sel) {
143956
143956
  }
143957
143957
  return out;
143958
143958
  }
143959
+ var INLINE_UNSAFE = /[\u0000-\u001f\u007f-\u009f]/g;
143960
+ var INLINE_SHORT = {
143961
+ "\b": "\\b",
143962
+ " ": "\\t",
143963
+ "\n": "\\n",
143964
+ "\f": "\\f",
143965
+ "\r": "\\r"
143966
+ };
143967
+ function escapeInline(value) {
143968
+ return value.replace(
143969
+ INLINE_UNSAFE,
143970
+ (c) => INLINE_SHORT[c] ?? `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
143971
+ );
143972
+ }
143959
143973
  function describeSelector(s) {
143960
143974
  const { loose: _loose, any: any2, within, after, next, ...rest } = s;
143961
143975
  const scopes = { within, after, next };
143962
143976
  const fields = Object.entries(rest).map(
143963
- ([k, v]) => k === "textMatches" ? `text=/${v}/` : `${k === "identifier" ? "id" : k}="${v}"`
143977
+ ([k, v]) => k === "textMatches" ? `text=/${escapeInline(String(v))}/` : `${k === "identifier" ? "id" : k}=${JSON.stringify(String(v))}`
143964
143978
  ).join(" ");
143965
143979
  const parts2 = [any2 ? "*" : void 0, fields || void 0].filter((p) => p !== void 0);
143966
143980
  for (const relation of SELECTOR_RELATIONS) {
@@ -145612,7 +145626,7 @@ costs the finish the cross-tree verdicts anchored to them.`,
145612
145626
 
145613
145627
  // ../tool-server/src/tools/flows/flow-add-step.ts
145614
145628
  init_zod();
145615
- var fs54 = __toESM(require("node:fs/promises"));
145629
+ var fs53 = __toESM(require("node:fs/promises"));
145616
145630
  var path38 = __toESM(require("node:path"));
145617
145631
  init_src();
145618
145632
 
@@ -147407,10 +147421,8 @@ function assertReason(condition, selector, expectedText, textMatch, matches2) {
147407
147421
  }
147408
147422
  }
147409
147423
 
147410
- // ../tool-server/src/tools/flows/flow-finish-recording.ts
147411
- init_zod();
147412
- var fs53 = __toESM(require("node:fs/promises"));
147413
- function selectorLabel(sel) {
147424
+ // ../tool-server/src/tools/flows/flow-step-definitions.ts
147425
+ function yamlSelectorLabel(sel) {
147414
147426
  const yaml = selectorToYaml(sel);
147415
147427
  if (typeof yaml !== "object" || yaml === null) return JSON.stringify(yaml);
147416
147428
  const sorted = Object.fromEntries(
@@ -147418,116 +147430,54 @@ function selectorLabel(sel) {
147418
147430
  );
147419
147431
  return JSON.stringify(sorted);
147420
147432
  }
147421
- function textConditionLabel(sel, expectedText, textMatch) {
147422
- const selector = selectorLabel(sel);
147433
+ function yamlTextConditionLabel(sel, expectedText, textMatch) {
147434
+ const selector = yamlSelectorLabel(sel);
147423
147435
  const expected = expectedText ?? "";
147424
147436
  return textMatch === "matches" ? `text ${selector} matches /${expected}/` : textMatch === "equals" ? `text ${selector} == ${JSON.stringify(expected)}` : `text ${selector} contains ${JSON.stringify(expected)}`;
147425
147437
  }
147426
- function targetLabel(target) {
147427
- return "selector" in target ? selectorLabel(target.selector) : `(${target.x}, ${target.y})`;
147428
- }
147429
- var zodSchema62 = external_exports.object({
147430
- name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
147431
- project_root: external_exports.string().describe(
147432
- "Absolute path to the project root of the flow being recorded \u2014 the same value passed to flow-start-recording. Together with `name` it identifies which recording to finish."
147433
- )
147434
- });
147435
- function attachStepWarnings(summary, warnings) {
147436
- if (warnings.size === 0) return summary;
147437
- return summary.flatMap((line, i) => {
147438
- const recorded = warnings.get(i + 1);
147439
- return recorded ? [line, ` warning: ${recorded.warning}`] : [line];
147440
- });
147438
+ function yamlConditionLabel(cond) {
147439
+ return cond.condition === "text" ? yamlTextConditionLabel(cond.selector, cond.expectedText, cond.textMatch) : `${cond.condition} ${yamlSelectorLabel(cond.selector)}`;
147441
147440
  }
147442
- function warningHeadline(warnings, discarded) {
147443
- const counts = { conversion: 0, wait: 0 };
147444
- for (const { kind } of warnings.values()) counts[kind] += 1;
147445
- const clauses = [];
147446
- if (counts.conversion > 0) {
147447
- clauses.push(
147448
- `${counts.conversion} ${counts.conversion === 1 ? "step carries" : "steps carry"} a cross-tree warning about converting a recorded wait`
147449
- );
147450
- }
147451
- if (counts.wait > 0) {
147452
- clauses.push(
147453
- `${counts.wait} ${counts.wait === 1 ? "step" : "steps"} recorded a wait that did not pass`
147454
- );
147441
+ function selectorLabel(sel) {
147442
+ const parts2 = [];
147443
+ if (sel.any) parts2.push("*");
147444
+ if (sel.text !== void 0) parts2.push(JSON.stringify(sel.text));
147445
+ if (sel.textMatches !== void 0) parts2.push(`/${escapeInline(sel.textMatches)}/`);
147446
+ if (sel.identifier) parts2.push(`id=${escapeInline(sel.identifier)}`);
147447
+ if (sel.role) parts2.push(`role=${escapeInline(sel.role)}`);
147448
+ for (const relation of SELECTOR_RELATIONS) {
147449
+ const scope = sel[relation];
147450
+ if (scope !== void 0) parts2.push(`${relation} (${selectorLabel(scope)})`);
147455
147451
  }
147456
- const carried = clauses.length === 0 ? "" : ` \u2014 ${clauses.join(", and ")}; read \`summary\` before converting or replaying`;
147457
- if (discarded === 0) return carried;
147458
- const one = discarded === 1;
147459
- const drop = `${discarded} ${one ? "warning" : "warnings"} raised during this recording ${one ? "is" : "are"} NOT in \`summary\`: a hand edit to the .yaml moved the ${one ? "step it judged" : "steps they judged"}, so which step ${one ? "it belongs" : "they belong"} to is no longer knowable \u2014 re-record ${one ? "that wait" : "those waits"} to see ${one ? "it" : "them"} again`;
147460
- return carried === "" ? ` \u2014 ${drop}` : `${carried}. ${drop}`;
147452
+ return parts2.join(" ");
147461
147453
  }
147462
- function anchoredWarnings(session, steps) {
147463
- const kept = /* @__PURE__ */ new Map();
147464
- const recorded = session.flow.steps;
147465
- if (recorded.length !== steps.length) return kept;
147466
- if (!steps.every((step, i) => stepAnchor(step) === stepAnchor(recorded[i]))) return kept;
147467
- for (const [n, verdict] of session.stepWarnings ?? []) {
147468
- const step = steps[n - 1];
147469
- if (step !== void 0 && stepAnchor(step) === verdict.step) kept.set(n, verdict);
147454
+ function conditionLabel(cond, renderSelector) {
147455
+ const sel = renderSelector(cond.selector);
147456
+ if (cond.condition === "text") {
147457
+ return `${sel} ${describeTextExpectation(cond.expectedText, cond.textMatch)}`;
147470
147458
  }
147471
- return kept;
147459
+ return `${cond.condition} ${sel}`;
147460
+ }
147461
+ function gestureTargetLabel(target, renderSelector) {
147462
+ return "selector" in target ? renderSelector(target.selector) : `(${target.x}, ${target.y})`;
147463
+ }
147464
+ function swipeLabel(step, renderSelector) {
147465
+ let travel;
147466
+ if (step.direction !== void 0) travel = step.direction;
147467
+ else if (step.by !== void 0) travel = `by ${swipeByLabel(step.by)}`;
147468
+ else if (step.to !== void 0) travel = `to ${gestureTargetLabel(step.to, renderSelector)}`;
147469
+ else return void 0;
147470
+ return `${travel}${step.from ? ` from ${gestureTargetLabel(step.from, renderSelector)}` : ""}`;
147471
+ }
147472
+ function whenLabel(cond, renderUi) {
147473
+ return cond.kind === "platform" ? `platform ${cond.platform}` : renderUi(cond);
147474
+ }
147475
+ function describeWhenCondition(cond) {
147476
+ return whenLabel(cond, (ui) => conditionLabel(ui, describeSelector));
147472
147477
  }
147473
- var flowFinishRecordingTool = {
147474
- id: "flow-finish-recording",
147475
- interaction: {
147476
- // Name the flow: other recordings stay live, so an unqualified message would
147477
- // not identify which one.
147478
- startedMsg: ({ params }) => `Finishing recording of flow ${params.name}`,
147479
- // `params.name` equals the basename of `result.path` on every branch
147480
- // (`assertSafeFlowName` admits no dots or separators), and matches the two
147481
- // formatters either side.
147482
- completedMsg: ({ params }) => `Saved recorded flow ${params.name}`,
147483
- failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to finish recording of flow ${params.name}: ${failureSignal2.error_code}`
147484
- },
147485
- description: `Finish recording the flow named by \`name\` + \`project_root\`, leaving recordings under any other key untouched. Returns { message, path, executionPrerequisite, steps, summary, flowFile, savedTo } - a summary of all recorded steps plus the final YAML. Use when you have added all desired steps and want to finalize the flow file. Fails if that flow has no recording in progress.
147486
- A warning flow-add-step raised on a recorded \`await-ui-element\` is repeated in \`summary\` as a \`warning:\` line of its own, right below the step it judges, and \`message\` counts them by kind. A warning is repeated only while the step it judges is still identifiable by its number: hand-editing the .yaml during the recording moves the steps, so those warnings are DROPPED rather than pinned on whichever step inherited the number, and \`message\` says how many were dropped. A step that carries a cross-tree warning was re-probed against the runner's tree: read it before converting that wait to \`await:\`/\`assert:\`, which is what the verdict is about and what this moment is for. A step that recorded a wait which did not pass was never probed at all, and its own warning names the CAUSE, because only one of them judges the condition: an unmet wait was read and found false, and it stops the run at replay; a wait whose tree source could not be read, or one that was cancelled, observed nothing and leaves the condition UNKNOWN rather than known-bad. Read those before replaying.
147487
- You can still edit the .yaml file directly afterwards to remove or reorder steps.`,
147488
- zodSchema: zodSchema62,
147489
- services: () => ({}),
147490
- async execute(_services, params) {
147491
- const { filePath, flowFile, savedTo, flow, summary, headline } = await withFlowFileLock(
147492
- params.project_root,
147493
- params.name,
147494
- async () => {
147495
- const session = await requireRecordingSession(params.project_root, params.name);
147496
- const filePath2 = session.filePath;
147497
- let flowFile2;
147498
- let savedTo2;
147499
- if (session.persist === "client") {
147500
- flowFile2 = serializeFlow(session.flow);
147501
- savedTo2 = clientFileDirective(filePath2, flowFile2);
147502
- } else {
147503
- flowFile2 = await fs53.readFile(filePath2, "utf8");
147504
- savedTo2 = filePath2;
147505
- }
147506
- const flow2 = parseFlow(flowFile2);
147507
- const anchored = anchoredWarnings(session, flow2.steps);
147508
- const summary2 = attachStepWarnings(summarizeSteps(flow2), anchored);
147509
- const discarded = (session.discardedWarnings ?? 0) + (session.stepWarnings?.size ?? 0) - anchored.size;
147510
- const headline2 = warningHeadline(anchored, discarded);
147511
- clearRecordingSession(session);
147512
- return { filePath: filePath2, flowFile: flowFile2, savedTo: savedTo2, flow: flow2, summary: summary2, headline: headline2 };
147513
- }
147514
- );
147515
- return {
147516
- // Name the counts in `message` as well. A caller that reads only
147517
- // `message` would otherwise polish blind.
147518
- message: `Finished recording "${params.name}" flow (${flow.steps.length} steps)` + headline,
147519
- path: filePath,
147520
- executionPrerequisite: flow.executionPrerequisite,
147521
- steps: flow.steps.length,
147522
- summary,
147523
- flowFile,
147524
- savedTo
147525
- };
147526
- }
147527
- };
147528
147478
  function renderToolArgs(args) {
147529
147479
  try {
147530
- return `${JSON.stringify(args)}`;
147480
+ return JSON.stringify(args);
147531
147481
  } catch {
147532
147482
  return "[cyclic args]";
147533
147483
  }
@@ -147535,77 +147485,162 @@ function renderToolArgs(args) {
147535
147485
  function delayLabel(step) {
147536
147486
  if (!step.delayMs) return "";
147537
147487
  const ms = Number(step.delayMs);
147538
- return Number.isFinite(ms) && ms >= 1 ? ` (after ${ms}ms)` : "";
147539
- }
147540
- function summarizeSteps(flow) {
147541
- return flow.steps.map((step, i) => summarizeStep(step, i + 1));
147542
- }
147543
- function stepAnchor(step) {
147544
- return summarizeStep(step, 0);
147545
- }
147546
- function summarizeStep(step, n) {
147547
- switch (step.kind) {
147548
- case "echo":
147549
- return `${n}. echo: ${step.message}`;
147550
- case "launch":
147551
- return `${n}. launch: ${typeof step.app === "string" ? step.app : JSON.stringify(step.app)}`;
147552
- case "run":
147553
- return `${n}. run: ${step.flow}`;
147554
- case "tap":
147555
- case "long-press": {
147556
- const target = targetLabel(
147557
- step.selector ? { selector: step.selector } : { x: step.x, y: step.y }
147558
- );
147559
- const times = step.kind === "tap" && step.times !== void 0 && step.times > 1 ? ` \xD7${step.times}` : "";
147560
- const held = step.kind === "long-press" && step.duration !== void 0 ? ` for ${step.duration}ms` : "";
147561
- return `${n}. ${step.kind}: ${target}${times}${held}`;
147562
- }
147563
- case "swipe": {
147564
- const travel = step.direction ?? (step.by ? `by ${swipeByLabel(step.by)}` : `to ${targetLabel(step.to)}`);
147565
- const from2 = step.from ? ` from ${targetLabel(step.from)}` : "";
147488
+ return ms >= 1 && ms <= 2 ** 31 - 1 ? ` (after ${ms}ms)` : "";
147489
+ }
147490
+ var MAX_TARGET_TEXT_CHARS = 200;
147491
+ function typedTextLabel(text) {
147492
+ const chars = Array.from(text);
147493
+ if (chars.length <= MAX_TARGET_TEXT_CHARS) return JSON.stringify(text);
147494
+ const elided = chars.length - MAX_TARGET_TEXT_CHARS;
147495
+ return `${JSON.stringify(chars.slice(0, MAX_TARGET_TEXT_CHARS).join(""))}\u2026(+${elided} chars)`;
147496
+ }
147497
+ var POINT_GESTURE_STEP = {
147498
+ // `times` (tap) and `duration` (long-press) change what replays, so a summary
147499
+ // line that drops them misdescribes the file. `times` has a second reason:
147500
+ // `tap` is one of the kinds the recorder builds, and the recorder echoes this
147501
+ // line alone rather than the growing YAML, so it is the author's only per-step
147502
+ // view of what was appended. `long-press` has no recorder path, so it reaches
147503
+ // an author only through flow-finish-recording's `summary`, which returns
147504
+ // `flowFile` beside it. Neither kind carries a `delayMs` (only `tool` steps
147505
+ // do), so no delayLabel here.
147506
+ //
147507
+ // Four replay-affecting fields render on neither surface `type.submit`,
147508
+ // `await.timeout`, `idle.timeout`, `idle.stableFor` — so a summary line alone
147509
+ // does not distinguish two steps differing only in those.
147510
+ summary: (step) => {
147511
+ const target = step.selector ? yamlSelectorLabel(step.selector) : `(${step.x}, ${step.y})`;
147512
+ const times = step.kind === "tap" && step.times !== void 0 && step.times > 1 ? ` \xD7${step.times}` : "";
147513
+ const held = step.kind === "long-press" && step.duration !== void 0 ? ` for ${step.duration}ms` : "";
147514
+ return `${target}${times}${held}`;
147515
+ },
147516
+ target: (step) => {
147517
+ if (step.selector) return selectorLabel(step.selector);
147518
+ if (step.x !== void 0 && step.y !== void 0) return `(${step.x}, ${step.y})`;
147519
+ return void 0;
147520
+ }
147521
+ };
147522
+ var UI_CONDITION_STEP = {
147523
+ summary: (step) => yamlConditionLabel(step),
147524
+ target: (step) => conditionLabel(step, selectorLabel)
147525
+ };
147526
+ var FLOW_STEP_DEFINITIONS = {
147527
+ "tool": {
147528
+ summary: (step) => `${step.name} ${renderToolArgs(step.args)}${delayLabel(step)}`,
147529
+ // Carries its subject in a report field of its own (`tool`) that renderers
147530
+ // print in the target's place.
147531
+ target: () => void 0
147532
+ },
147533
+ "echo": {
147534
+ summary: (step) => step.message,
147535
+ // As for `tool`, but the field is `message`.
147536
+ target: () => void 0
147537
+ },
147538
+ "launch": {
147539
+ summary: (step) => typeof step.app === "string" ? step.app : JSON.stringify(step.app),
147540
+ // A launch's app id may be per-platform (`appIdForPlatform`), and a step
147541
+ // alone does not know the run device.
147542
+ target: () => void 0
147543
+ },
147544
+ "run": {
147545
+ summary: (step) => step.flow,
147546
+ // The as-written path, so a report line shows exactly what the flow
147547
+ // references (`run ../shared/login.yaml`), not just the attribution stem.
147548
+ target: (step) => step.flow
147549
+ },
147550
+ "when": {
147551
+ summary: (step) => {
147552
+ const count2 = step.steps.length;
147553
+ const cond = whenLabel(step.condition, yamlConditionLabel);
147554
+ return `${cond} (${count2} step${count2 === 1 ? "" : "s"})`;
147555
+ },
147556
+ target: (step) => whenLabel(step.condition, (ui) => conditionLabel(ui, selectorLabel))
147557
+ },
147558
+ "tap": POINT_GESTURE_STEP,
147559
+ "long-press": POINT_GESTURE_STEP,
147560
+ "swipe": {
147561
+ // `momentum` and `duration` change what replays, so the summary spells them
147562
+ // as it spells tap's `times`. A report target names what the step acts on,
147563
+ // so they ride the summary alone.
147564
+ summary: (step) => {
147566
147565
  const options = [
147567
147566
  ...step.momentum === false ? ["momentum-free"] : [],
147568
147567
  ...step.duration !== void 0 ? [`${step.duration}ms`] : []
147569
147568
  ];
147570
147569
  const tail = options.length > 0 ? ` (${options.join(", ")})` : "";
147571
- return `${n}. swipe: ${travel}${from2}${tail}`;
147570
+ return `${swipeLabel(step, yamlSelectorLabel)}${tail}`;
147571
+ },
147572
+ target: (step) => swipeLabel(step, selectorLabel)
147573
+ },
147574
+ "type": {
147575
+ summary: (step) => `${yamlSelectorLabel(step.into)} \u2190 ${JSON.stringify(step.text)}`,
147576
+ // The typed text rides along, the way an await/assert target carries its
147577
+ // expectation: two steps into the same field with different text would
147578
+ // otherwise render identical targets.
147579
+ target: (step) => `into ${selectorLabel(step.into)} \u2190 ${typedTextLabel(step.text)}`
147580
+ },
147581
+ "await": UI_CONDITION_STEP,
147582
+ "assert": UI_CONDITION_STEP,
147583
+ "idle": {
147584
+ summaryKind: "await",
147585
+ summary: () => "screen idle",
147586
+ // The report already prints the kind, and this step addresses nothing
147587
+ // beyond the screen itself: a target would render as "idle screen idle".
147588
+ target: () => void 0
147589
+ },
147590
+ "wait": {
147591
+ summary: (step) => `${step.ms}ms`,
147592
+ target: () => void 0
147593
+ },
147594
+ "scroll-to": {
147595
+ summary: (step) => `${yamlSelectorLabel(step.target)} (${step.direction})` + (step.within ? ` within ${yamlSelectorLabel(step.within)}` : ""),
147596
+ target: (step) => {
147597
+ const dir = step.direction !== "down" ? ` (${step.direction})` : "";
147598
+ const container = step.within ? ` in scroll container (${selectorLabel(step.within)})` : "";
147599
+ return `${selectorLabel(step.target)}${dir}${container}`;
147572
147600
  }
147573
- case "type":
147574
- return `${n}. type: ${selectorLabel(step.into)} \u2190 "${step.text}"`;
147575
- case "await":
147576
- case "assert": {
147577
- const tail = step.condition === "text" ? textConditionLabel(step.selector, step.expectedText, step.textMatch) : `${step.condition} ${selectorLabel(step.selector)}`;
147578
- return `${n}. ${step.kind}: ${tail}`;
147601
+ },
147602
+ "pinch": {
147603
+ summary: (step) => `scale ${step.scale}${step.selector ? ` on ${yamlSelectorLabel(step.selector)}` : ""}`,
147604
+ target: (step) => {
147605
+ const scale = `scale ${step.scale}`;
147606
+ return step.selector ? `${selectorLabel(step.selector)} (${scale})` : scale;
147579
147607
  }
147580
- case "wait":
147581
- return `${n}. wait: ${step.ms}ms`;
147582
- case "when": {
147583
- const cond = step.condition.kind === "platform" ? `platform ${step.condition.platform}` : step.condition.condition === "text" ? textConditionLabel(
147584
- step.condition.selector,
147585
- step.condition.expectedText,
147586
- step.condition.textMatch
147587
- ) : `${step.condition.condition} ${selectorLabel(step.condition.selector)}`;
147588
- const count2 = step.steps.length;
147589
- return `${n}. when: ${cond} (${count2} step${count2 === 1 ? "" : "s"})`;
147608
+ },
147609
+ "rotate": {
147610
+ summary: (step) => `by ${step.by}\xB0${step.selector ? ` on ${yamlSelectorLabel(step.selector)}` : ""}`,
147611
+ target: (step) => {
147612
+ const by = `by ${step.by}\xB0`;
147613
+ return step.selector ? `${selectorLabel(step.selector)} (${by})` : by;
147590
147614
  }
147591
- case "scroll-to":
147592
- return `${n}. scroll-to: ${selectorLabel(step.target)} (${step.direction})`;
147593
- case "pinch":
147594
- return `${n}. pinch: scale ${step.scale}${step.selector ? ` on ${selectorLabel(step.selector)}` : ""}`;
147595
- case "rotate":
147596
- return `${n}. rotate: by ${step.by}\xB0${step.selector ? ` on ${selectorLabel(step.selector)}` : ""}`;
147597
- case "snapshot":
147598
- return `${n}. snapshot: ${step.name}`;
147599
- case "idle":
147600
- return `${n}. await: screen idle`;
147601
- case "tool":
147602
- default:
147603
- return `${n}. tool: ${step.name} ${renderToolArgs(step.args)}${delayLabel(step)}`;
147615
+ },
147616
+ "snapshot": {
147617
+ // `name` interpolates raw on both surfaces. It becomes a baseline filename,
147618
+ // so `parseFlow` gates it on FLOW_NAME_PATTERN (letters, digits, `_`, `-`)
147619
+ // — and that parse is the only thing that builds a snapshot step, so no
147620
+ // quote, backslash or newline reaches here to escape.
147621
+ summary: (step) => step.name + (step.cropOn ? ` cropOn ${yamlSelectorLabel(step.cropOn)}` : "") + (step.maxMismatch !== void 0 ? ` maxMismatch ${step.maxMismatch}` : ""),
147622
+ target: (step) => step.cropOn ? `"${step.name}" cropOn ${selectorLabel(step.cropOn)}` : `"${step.name}"`
147604
147623
  }
147624
+ };
147625
+ function definitionOf(step) {
147626
+ return FLOW_STEP_DEFINITIONS[step.kind];
147627
+ }
147628
+ function stepTarget(step) {
147629
+ return definitionOf(step).target(step);
147630
+ }
147631
+ function summarizeStep(step, n) {
147632
+ const def = definitionOf(step);
147633
+ return `${n}. ${def.summaryKind ?? step.kind}: ${def.summary(step)}`;
147634
+ }
147635
+ function summarizeSteps(flow) {
147636
+ return flow.steps.map((step, i) => summarizeStep(step, i + 1));
147637
+ }
147638
+ function stepAnchor(step) {
147639
+ return summarizeStep(step, 0);
147605
147640
  }
147606
147641
 
147607
147642
  // ../tool-server/src/tools/flows/flow-add-step.ts
147608
- var zodSchema63 = external_exports.object({
147643
+ var zodSchema62 = external_exports.object({
147609
147644
  name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
147610
147645
  project_root: external_exports.string().describe(
147611
147646
  "Absolute path to the project root of the flow being recorded \u2014 the same value passed to flow-start-recording. Together with `name` it identifies which recording this step belongs to."
@@ -147819,7 +147854,7 @@ async function captureTapSelector(registry2, session, udid, point) {
147819
147854
  async function activeFlowState(session) {
147820
147855
  if (session.persist === "host") {
147821
147856
  try {
147822
- session.flow = parseFlow(await fs54.readFile(session.filePath, "utf8"));
147857
+ session.flow = parseFlow(await fs53.readFile(session.filePath, "utf8"));
147823
147858
  } catch (err) {
147824
147859
  return {
147825
147860
  stepCount: session.flow.steps.length,
@@ -147960,7 +147995,7 @@ async function captureRunTarget(session, args) {
147960
147995
  }
147961
147996
  try {
147962
147997
  assertSafeFlowName(name);
147963
- const realFlowPath = await fs54.realpath(session.filePath);
147998
+ const realFlowPath = await fs53.realpath(session.filePath);
147964
147999
  const flowsDir = path38.dirname(realFlowPath);
147965
148000
  const fragPath = path38.join(flowsDir, `${name}.yaml`);
147966
148001
  const projectRoot = args.project_root;
@@ -147976,10 +148011,10 @@ async function captureRunTarget(session, args) {
147976
148011
  warning: `kept the raw flow-execute step \u2014 no sibling is named "${name}.yaml" (this filesystem matched it case-insensitively to "${spelling.actual}"), so a run: ${name} step would name a flow no case-sensitive checkout can find \u2014 ${recovery}`
147977
148012
  };
147978
148013
  }
147979
- parseFlow(await fs54.readFile(fragPath, "utf8"));
148014
+ parseFlow(await fs53.readFile(fragPath, "utf8"));
147980
148015
  let executedPath;
147981
148016
  try {
147982
- executedPath = await fs54.realpath(path38.join(flowsDirFor(projectRoot), `${name}.yaml`));
148017
+ executedPath = await fs53.realpath(path38.join(flowsDirFor(projectRoot), `${name}.yaml`));
147983
148018
  } catch {
147984
148019
  executedPath = void 0;
147985
148020
  }
@@ -147988,7 +148023,7 @@ async function captureRunTarget(session, args) {
147988
148023
  warning: `kept the raw flow-execute step \u2014 could not verify which file the live flow-execute ran ("${name}" has no canonical file in project_root's flows dir to compare the sibling against)`
147989
148024
  };
147990
148025
  }
147991
- if (executedPath !== await fs54.realpath(fragPath)) {
148026
+ if (executedPath !== await fs53.realpath(fragPath)) {
147992
148027
  return {
147993
148028
  warning: `kept the raw flow-execute step \u2014 project_root "${projectRoot}" resolves "${name}" to "${executedPath}", not the recording's sibling "${fragPath}", so "${name}.yaml" beside the recording's real file is not the file the live flow-execute ran and a run: ${name} step would replay a different flow than the one that just ran`
147994
148029
  };
@@ -148020,7 +148055,7 @@ If a step was recorded by mistake, remove it from the .yaml after \`flow-finish-
148020
148055
  // more times — and every retry re-runs the action and appends another step,
148021
148056
  // because an aborted request still appends its first.
148022
148057
  longRunning: true,
148023
- zodSchema: zodSchema63,
148058
+ zodSchema: zodSchema62,
148024
148059
  services: () => ({}),
148025
148060
  async execute(_services, params, ctx) {
148026
148061
  const session = await requireRecordingSession(params.project_root, params.name);
@@ -148125,7 +148160,7 @@ If a step was recorded by mistake, remove it from the .yaml after \`flow-finish-
148125
148160
 
148126
148161
  // ../tool-server/src/tools/flows/flow-insert-echo.ts
148127
148162
  init_zod();
148128
- var zodSchema64 = external_exports.object({
148163
+ var zodSchema63 = external_exports.object({
148129
148164
  name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
148130
148165
  project_root: external_exports.string().describe(
148131
148166
  "Absolute path to the project root of the flow being recorded \u2014 the same value passed to flow-start-recording. Together with `name` it identifies which recording this echo belongs to."
@@ -148143,7 +148178,7 @@ var flowInsertEchoTool = {
148143
148178
  description: `Record an echo step in the flow named by \`name\` + \`project_root\`. Echo steps print a message when the flow is replayed \u2014 useful as labels between tool calls.
148144
148179
  Use when you want to annotate a recorded flow with a human-readable label or checkpoint message.
148145
148180
  Returns { message, stepCount, savedTo }. Fails if that flow has no recording in progress.`,
148146
- zodSchema: zodSchema64,
148181
+ zodSchema: zodSchema63,
148147
148182
  services: () => ({}),
148148
148183
  async execute(_services, params) {
148149
148184
  const session = await requireRecordingSession(params.project_root, params.name);
@@ -148159,6 +148194,109 @@ Returns { message, stepCount, savedTo }. Fails if that flow has no recording in
148159
148194
  }
148160
148195
  };
148161
148196
 
148197
+ // ../tool-server/src/tools/flows/flow-finish-recording.ts
148198
+ init_zod();
148199
+ var fs54 = __toESM(require("node:fs/promises"));
148200
+ var zodSchema64 = external_exports.object({
148201
+ name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
148202
+ project_root: external_exports.string().describe(
148203
+ "Absolute path to the project root of the flow being recorded \u2014 the same value passed to flow-start-recording. Together with `name` it identifies which recording to finish."
148204
+ )
148205
+ });
148206
+ function attachStepWarnings(summary, warnings) {
148207
+ if (warnings.size === 0) return summary;
148208
+ return summary.flatMap((line, i) => {
148209
+ const recorded = warnings.get(i + 1);
148210
+ return recorded ? [line, ` warning: ${recorded.warning}`] : [line];
148211
+ });
148212
+ }
148213
+ function warningHeadline(warnings, discarded) {
148214
+ const counts = { conversion: 0, wait: 0 };
148215
+ for (const { kind } of warnings.values()) counts[kind] += 1;
148216
+ const clauses = [];
148217
+ if (counts.conversion > 0) {
148218
+ clauses.push(
148219
+ `${counts.conversion} ${counts.conversion === 1 ? "step carries" : "steps carry"} a cross-tree warning about converting a recorded wait`
148220
+ );
148221
+ }
148222
+ if (counts.wait > 0) {
148223
+ clauses.push(
148224
+ `${counts.wait} ${counts.wait === 1 ? "step" : "steps"} recorded a wait that did not pass`
148225
+ );
148226
+ }
148227
+ const carried = clauses.length === 0 ? "" : ` \u2014 ${clauses.join(", and ")}; read \`summary\` before converting or replaying`;
148228
+ if (discarded === 0) return carried;
148229
+ const one = discarded === 1;
148230
+ const drop = `${discarded} ${one ? "warning" : "warnings"} raised during this recording ${one ? "is" : "are"} NOT in \`summary\`: a hand edit to the .yaml moved the ${one ? "step it judged" : "steps they judged"}, so which step ${one ? "it belongs" : "they belong"} to is no longer knowable \u2014 re-record ${one ? "that wait" : "those waits"} to see ${one ? "it" : "them"} again`;
148231
+ return carried === "" ? ` \u2014 ${drop}` : `${carried}. ${drop}`;
148232
+ }
148233
+ function anchoredWarnings(session, steps) {
148234
+ const kept = /* @__PURE__ */ new Map();
148235
+ const recorded = session.flow.steps;
148236
+ if (recorded.length !== steps.length) return kept;
148237
+ if (!steps.every((step, i) => stepAnchor(step) === stepAnchor(recorded[i]))) return kept;
148238
+ for (const [n, verdict] of session.stepWarnings ?? []) {
148239
+ const step = steps[n - 1];
148240
+ if (step !== void 0 && stepAnchor(step) === verdict.step) kept.set(n, verdict);
148241
+ }
148242
+ return kept;
148243
+ }
148244
+ var flowFinishRecordingTool = {
148245
+ id: "flow-finish-recording",
148246
+ interaction: {
148247
+ // Name the flow: other recordings stay live, so an unqualified message would
148248
+ // not identify which one.
148249
+ startedMsg: ({ params }) => `Finishing recording of flow ${params.name}`,
148250
+ // `params.name` equals the basename of `result.path` on every branch
148251
+ // (`assertSafeFlowName` admits no dots or separators), and matches the two
148252
+ // formatters either side.
148253
+ completedMsg: ({ params }) => `Saved recorded flow ${params.name}`,
148254
+ failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to finish recording of flow ${params.name}: ${failureSignal2.error_code}`
148255
+ },
148256
+ description: `Finish recording the flow named by \`name\` + \`project_root\`, leaving recordings under any other key untouched. Returns { message, path, executionPrerequisite, steps, summary, flowFile, savedTo } - a summary of all recorded steps plus the final YAML. Use when you have added all desired steps and want to finalize the flow file. Fails if that flow has no recording in progress.
148257
+ A warning flow-add-step raised on a recorded \`await-ui-element\` is repeated in \`summary\` as a \`warning:\` line of its own, right below the step it judges, and \`message\` counts them by kind. A warning is repeated only while the step it judges is still identifiable by its number: hand-editing the .yaml during the recording moves the steps, so those warnings are DROPPED rather than pinned on whichever step inherited the number, and \`message\` says how many were dropped. A step that carries a cross-tree warning was re-probed against the runner's tree: read it before converting that wait to \`await:\`/\`assert:\`, which is what the verdict is about and what this moment is for. A step that recorded a wait which did not pass was never probed at all, and its own warning names the CAUSE, because only one of them judges the condition: an unmet wait was read and found false, and it stops the run at replay; a wait whose tree source could not be read, or one that was cancelled, observed nothing and leaves the condition UNKNOWN rather than known-bad. Read those before replaying.
148258
+ You can still edit the .yaml file directly afterwards to remove or reorder steps.`,
148259
+ zodSchema: zodSchema64,
148260
+ services: () => ({}),
148261
+ async execute(_services, params) {
148262
+ const { filePath, flowFile, savedTo, flow, summary, headline } = await withFlowFileLock(
148263
+ params.project_root,
148264
+ params.name,
148265
+ async () => {
148266
+ const session = await requireRecordingSession(params.project_root, params.name);
148267
+ const filePath2 = session.filePath;
148268
+ let flowFile2;
148269
+ let savedTo2;
148270
+ if (session.persist === "client") {
148271
+ flowFile2 = serializeFlow(session.flow);
148272
+ savedTo2 = clientFileDirective(filePath2, flowFile2);
148273
+ } else {
148274
+ flowFile2 = await fs54.readFile(filePath2, "utf8");
148275
+ savedTo2 = filePath2;
148276
+ }
148277
+ const flow2 = parseFlow(flowFile2);
148278
+ const anchored = anchoredWarnings(session, flow2.steps);
148279
+ const summary2 = attachStepWarnings(summarizeSteps(flow2), anchored);
148280
+ const discarded = (session.discardedWarnings ?? 0) + (session.stepWarnings?.size ?? 0) - anchored.size;
148281
+ const headline2 = warningHeadline(anchored, discarded);
148282
+ clearRecordingSession(session);
148283
+ return { filePath: filePath2, flowFile: flowFile2, savedTo: savedTo2, flow: flow2, summary: summary2, headline: headline2 };
148284
+ }
148285
+ );
148286
+ return {
148287
+ // Name the counts in `message` as well. A caller that reads only
148288
+ // `message` would otherwise polish blind.
148289
+ message: `Finished recording "${params.name}" flow (${flow.steps.length} steps)` + headline,
148290
+ path: filePath,
148291
+ executionPrerequisite: flow.executionPrerequisite,
148292
+ steps: flow.steps.length,
148293
+ summary,
148294
+ flowFile,
148295
+ savedTo
148296
+ };
148297
+ }
148298
+ };
148299
+
148162
148300
  // ../tool-server/src/tools/flows/flow-run.ts
148163
148301
  init_zod();
148164
148302
  var fs57 = __toESM(require("node:fs/promises"));
@@ -151345,88 +151483,6 @@ function pushReport(state3, report) {
151345
151483
  state3.reports.push(report);
151346
151484
  state3.onStepReport?.(report);
151347
151485
  }
151348
- function selectorLabel2(sel) {
151349
- const parts2 = [];
151350
- if (sel.any) parts2.push("*");
151351
- if (sel.text !== void 0) parts2.push(`"${sel.text}"`);
151352
- if (sel.textMatches !== void 0) parts2.push(`/${sel.textMatches}/`);
151353
- if (sel.identifier) parts2.push(`id=${sel.identifier}`);
151354
- if (sel.role) parts2.push(`role=${sel.role}`);
151355
- for (const relation of SELECTOR_RELATIONS) {
151356
- const scope = sel[relation];
151357
- if (scope !== void 0) parts2.push(`${relation} (${selectorLabel2(scope)})`);
151358
- }
151359
- return parts2.join(" ");
151360
- }
151361
- function conditionLabel(cond, renderSelector) {
151362
- const sel = renderSelector(cond.selector);
151363
- if (cond.condition === "text") {
151364
- return `${sel} ${describeTextExpectation(cond.expectedText, cond.textMatch)}`;
151365
- }
151366
- return `${cond.condition} ${sel}`;
151367
- }
151368
- function gestureTargetLabel(target) {
151369
- return "selector" in target ? selectorLabel2(target.selector) : `(${target.x}, ${target.y})`;
151370
- }
151371
- function stepTarget(step) {
151372
- switch (step.kind) {
151373
- case "tap":
151374
- case "long-press":
151375
- if (step.selector) return selectorLabel2(step.selector);
151376
- if (step.x !== void 0 && step.y !== void 0) return `(${step.x}, ${step.y})`;
151377
- return void 0;
151378
- case "swipe": {
151379
- let travel;
151380
- if (step.direction !== void 0) {
151381
- travel = step.direction;
151382
- } else if (step.by !== void 0) {
151383
- travel = `by ${swipeByLabel(step.by)}`;
151384
- } else if (step.to !== void 0) {
151385
- travel = `to ${gestureTargetLabel(step.to)}`;
151386
- } else {
151387
- return void 0;
151388
- }
151389
- return `${travel}${step.from ? ` from ${gestureTargetLabel(step.from)}` : ""}`;
151390
- }
151391
- case "type":
151392
- return `into ${selectorLabel2(step.into)}`;
151393
- case "await":
151394
- case "assert":
151395
- return conditionLabel(step, selectorLabel2);
151396
- case "idle":
151397
- return void 0;
151398
- case "when":
151399
- return step.condition.kind === "platform" ? `platform ${step.condition.platform}` : conditionLabel(step.condition, selectorLabel2);
151400
- case "scroll-to": {
151401
- const dir = step.direction !== "down" ? ` (${step.direction})` : "";
151402
- return `${selectorLabel2(step.target)}${dir}`;
151403
- }
151404
- case "pinch": {
151405
- const scale = `scale ${step.scale}`;
151406
- return step.selector ? `${selectorLabel2(step.selector)} (${scale})` : scale;
151407
- }
151408
- case "rotate": {
151409
- const by = `by ${step.by}\xB0`;
151410
- return step.selector ? `${selectorLabel2(step.selector)} (${by})` : by;
151411
- }
151412
- case "snapshot":
151413
- return step.cropOn ? `"${step.name}" cropOn ${selectorLabel2(step.cropOn)}` : `"${step.name}"`;
151414
- case "run":
151415
- return step.flow;
151416
- case "echo":
151417
- case "tool":
151418
- return void 0;
151419
- case "launch":
151420
- return void 0;
151421
- case "wait":
151422
- return void 0;
151423
- default: {
151424
- const unclassified = step;
151425
- void unclassified;
151426
- return void 0;
151427
- }
151428
- }
151429
- }
151430
151486
  function scopeFlow(scope) {
151431
151487
  return scope.runStack[scope.runStack.length - 1].display;
151432
151488
  }
@@ -151514,10 +151570,6 @@ async function execSteps(state3, steps, scope) {
151514
151570
  if (report.status === "fail" || report.status === "error") state3.stopped = true;
151515
151571
  }
151516
151572
  }
151517
- function describeWhenCondition(cond) {
151518
- if (cond.kind === "platform") return `platform ${cond.platform}`;
151519
- return conditionLabel(cond, describeSelector);
151520
- }
151521
151573
  function reportBlockSkipped(state3, steps, scope, reason) {
151522
151574
  for (const step of steps) {
151523
151575
  pushReport(state3, {
@@ -152509,7 +152561,7 @@ var updateArgentTool = {
152509
152561
  });
152510
152562
  child.unref();
152511
152563
  }, 2e3);
152512
- const targetLabel2 = effectiveTarget === "both" ? "global and project-local installs" : `${effectiveTarget} install`;
152564
+ const targetLabel = effectiveTarget === "both" ? "global and project-local installs" : `${effectiveTarget} install`;
152513
152565
  const otherHint = requested === "auto" && resolved !== "both" ? resolved === "local" ? ` If you also have a global install, call this tool again with target "global" to update it too.` : ` If you also have a project-local install, run \`argent update --local\` in that project to update it too.` : "";
152514
152566
  const bothDegradedNote = resolved === "both" && effectiveTarget === "global" ? ` The project-local install was skipped: no project declaring ${PACKAGE_NAME2} could be located from this server \u2014 run \`argent update --local\` in the project directory for it.` : "";
152515
152567
  const versionInfo = targetsOnlyRunningInstall ? `(v${currentVersion} -> v${installableVersion}) ` : "";
@@ -152517,7 +152569,7 @@ var updateArgentTool = {
152517
152569
  const coversRunningInstall = targetsOnlyRunningInstall || effectiveTarget === "both";
152518
152570
  const restartNote = coversRunningInstall ? ` The tool server will stop and restart automatically once the update is installed. Subsequent tool calls will reconnect to the updated server.` : ` This session's tool server is not affected and keeps running; the update applies only to the targeted install.`;
152519
152571
  return {
152520
- message: `Argent update initiated ${versionInfo}for the ${targetLabel2}.` + crossTargetNote + restartNote + `${otherHint}${bothDegradedNote}`
152572
+ message: `Argent update initiated ${versionInfo}for the ${targetLabel}.` + crossTargetNote + restartNote + `${otherHint}${bothDegradedNote}`
152521
152573
  };
152522
152574
  }
152523
152575
  };
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.24.0",
3
+ "version": "0.24.1-next.1",
4
4
  "mcpName": "io.github.software-mansion/argent",
5
5
  "description": "MCP server for iOS Simulator and Android Emulator control",
6
6
  "license": "Apache-2.0",