@swmansion/argent 0.19.1-next.5 → 0.19.1-next.6

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.
@@ -143904,13 +143904,16 @@ async function appendStepToFlow(session, step) {
143904
143904
  if (session.persist === "host") {
143905
143905
  const flowFile = await appendStep(session.filePath, step);
143906
143906
  session.flow = parseFlow(flowFile);
143907
- return { flowFile, savedTo: session.filePath };
143907
+ return { savedTo: session.filePath, stepCount: session.flow.steps.length };
143908
143908
  }
143909
143909
  session.flow.steps.push(step);
143910
143910
  try {
143911
143911
  validateFlow(session.flow);
143912
143912
  const flowFile = serializeFlow(session.flow);
143913
- return { flowFile, savedTo: clientFileDirective(session.filePath, flowFile) };
143913
+ return {
143914
+ savedTo: clientFileDirective(session.filePath, flowFile),
143915
+ stepCount: session.flow.steps.length
143916
+ };
143914
143917
  } catch (err) {
143915
143918
  session.flow.steps.pop();
143916
143919
  throw err;
@@ -143964,7 +143967,9 @@ executionPrerequisite instead. Use flow-add-echo to add labels. Call
143964
143967
  flow-finish-recording when done.
143965
143968
 
143966
143969
  If a recorded step turns out to be wrong, you can edit the .yaml file directly
143967
- to remove or reorder steps.`,
143970
+ to remove or reorder steps. Against a remote client, only after
143971
+ flow-finish-recording: the in-memory copy is authoritative there, and every
143972
+ write serializes it over your edit.`,
143968
143973
  zodSchema: zodSchema61,
143969
143974
  fileInputs: fileInputs2,
143970
143975
  services: () => ({}),
@@ -144022,10 +144027,141 @@ to remove or reorder steps.`,
144022
144027
 
144023
144028
  // ../tool-server/src/tools/flows/flow-add-step.ts
144024
144029
  init_zod();
144025
- var fs44 = __toESM(require("node:fs/promises"));
144030
+ var fs45 = __toESM(require("node:fs/promises"));
144026
144031
  var path32 = __toESM(require("node:path"));
144027
144032
  init_src();
144028
144033
 
144034
+ // ../tool-server/src/tools/flows/flow-finish-recording.ts
144035
+ init_zod();
144036
+ var fs44 = __toESM(require("node:fs/promises"));
144037
+ function selectorLabel(sel) {
144038
+ return JSON.stringify(selectorToYaml(sel));
144039
+ }
144040
+ function textConditionLabel(sel, expectedText, textMatch) {
144041
+ const selector = selectorLabel(sel);
144042
+ const expected = expectedText ?? "";
144043
+ return textMatch === "matches" ? `text ${selector} matches /${expected}/` : textMatch === "equals" ? `text ${selector} == ${JSON.stringify(expected)}` : `text ${selector} contains ${JSON.stringify(expected)}`;
144044
+ }
144045
+ var zodSchema62 = external_exports.object({
144046
+ name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
144047
+ project_root: external_exports.string().describe(
144048
+ "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."
144049
+ )
144050
+ });
144051
+ var flowFinishRecordingTool = {
144052
+ id: "flow-finish-recording",
144053
+ interaction: {
144054
+ // Name the flow: other recordings stay live across this call, so an
144055
+ // unqualified "Finishing flow recording" would not identify which one.
144056
+ startedMsg: ({ params }) => `Finishing recording of flow ${params.name}`,
144057
+ // `params.name` rather than the basename of `result.path`: the two are the
144058
+ // same string on every branch — `assertSafeFlowName` admits no dots or
144059
+ // separators, so `getFlowPath` produces `<name>.yaml` and nothing else —
144060
+ // and this spelling matches the two formatters either side of it.
144061
+ completedMsg: ({ params }) => `Saved recorded flow ${params.name}`,
144062
+ failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to finish recording of flow ${params.name}: ${failureSignal2.error_code}`
144063
+ },
144064
+ 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.
144065
+ You can still edit the .yaml file directly afterwards to remove or reorder steps.`,
144066
+ zodSchema: zodSchema62,
144067
+ services: () => ({}),
144068
+ async execute(_services, params) {
144069
+ const { filePath, flowFile, savedTo, flow, summary } = await withFlowFileLock(
144070
+ params.project_root,
144071
+ params.name,
144072
+ async () => {
144073
+ const session = await requireRecordingSession(params.project_root, params.name);
144074
+ const filePath2 = session.filePath;
144075
+ let flowFile2;
144076
+ let savedTo2;
144077
+ if (session.persist === "client") {
144078
+ flowFile2 = serializeFlow(session.flow);
144079
+ savedTo2 = clientFileDirective(filePath2, flowFile2);
144080
+ } else {
144081
+ flowFile2 = await fs44.readFile(filePath2, "utf8");
144082
+ savedTo2 = filePath2;
144083
+ }
144084
+ const flow2 = parseFlow(flowFile2);
144085
+ const summary2 = summarizeSteps(flow2);
144086
+ clearRecordingSession(session);
144087
+ return { filePath: filePath2, flowFile: flowFile2, savedTo: savedTo2, flow: flow2, summary: summary2 };
144088
+ }
144089
+ );
144090
+ return {
144091
+ message: `Finished recording "${params.name}" flow (${flow.steps.length} steps)`,
144092
+ path: filePath,
144093
+ executionPrerequisite: flow.executionPrerequisite,
144094
+ steps: flow.steps.length,
144095
+ summary,
144096
+ flowFile,
144097
+ savedTo
144098
+ };
144099
+ }
144100
+ };
144101
+ function renderToolArgs(args) {
144102
+ try {
144103
+ return `${JSON.stringify(args)}`;
144104
+ } catch {
144105
+ return "[cyclic args]";
144106
+ }
144107
+ }
144108
+ function delayLabel(step) {
144109
+ if (!step.delayMs) return "";
144110
+ const ms = Number(step.delayMs);
144111
+ return Number.isFinite(ms) && ms >= 1 ? ` (after ${ms}ms)` : "";
144112
+ }
144113
+ function summarizeSteps(flow) {
144114
+ return flow.steps.map((step, i) => summarizeStep(step, i + 1));
144115
+ }
144116
+ function summarizeStep(step, n) {
144117
+ switch (step.kind) {
144118
+ case "echo":
144119
+ return `${n}. echo: ${step.message}`;
144120
+ case "launch":
144121
+ return `${n}. launch: ${typeof step.app === "string" ? step.app : JSON.stringify(step.app)}`;
144122
+ case "run":
144123
+ return `${n}. run: ${step.flow}`;
144124
+ case "tap":
144125
+ case "long-press": {
144126
+ const target = step.selector ? selectorLabel(step.selector) : `(${step.x}, ${step.y})`;
144127
+ const times = step.kind === "tap" && step.times !== void 0 && step.times > 1 ? ` \xD7${step.times}` : "";
144128
+ const held = step.kind === "long-press" && step.duration !== void 0 ? ` for ${step.duration}ms` : "";
144129
+ return `${n}. ${step.kind}: ${target}${times}${held}`;
144130
+ }
144131
+ case "type":
144132
+ return `${n}. type: ${selectorLabel(step.into)} \u2190 "${step.text}"`;
144133
+ case "await":
144134
+ case "assert": {
144135
+ const tail = step.condition === "text" ? textConditionLabel(step.selector, step.expectedText, step.textMatch) : `${step.condition} ${selectorLabel(step.selector)}`;
144136
+ return `${n}. ${step.kind}: ${tail}`;
144137
+ }
144138
+ case "wait":
144139
+ return `${n}. wait: ${step.ms}ms`;
144140
+ case "when": {
144141
+ const cond = step.condition.kind === "platform" ? `platform ${step.condition.platform}` : step.condition.condition === "text" ? textConditionLabel(
144142
+ step.condition.selector,
144143
+ step.condition.expectedText,
144144
+ step.condition.textMatch
144145
+ ) : `${step.condition.condition} ${selectorLabel(step.condition.selector)}`;
144146
+ const count2 = step.steps.length;
144147
+ return `${n}. when: ${cond} (${count2} step${count2 === 1 ? "" : "s"})`;
144148
+ }
144149
+ case "scroll-to":
144150
+ return `${n}. scroll-to: ${selectorLabel(step.target)} (${step.direction})`;
144151
+ case "pinch":
144152
+ return `${n}. pinch: scale ${step.scale}${step.selector ? ` on ${selectorLabel(step.selector)}` : ""}`;
144153
+ case "rotate":
144154
+ return `${n}. rotate: by ${step.by}\xB0${step.selector ? ` on ${selectorLabel(step.selector)}` : ""}`;
144155
+ case "snapshot":
144156
+ return `${n}. snapshot: ${step.name}`;
144157
+ case "idle":
144158
+ return `${n}. await: screen idle`;
144159
+ case "tool":
144160
+ default:
144161
+ return `${n}. tool: ${step.name} ${renderToolArgs(step.args)}${delayLabel(step)}`;
144162
+ }
144163
+ }
144164
+
144029
144165
  // ../tool-server/src/tools/flows/flow-device.ts
144030
144166
  init_src();
144031
144167
  var DEVICE_BIND_KEYS = ["udid", "device_id", "device"];
@@ -144585,7 +144721,7 @@ async function fetchFlowTree(registry2, device) {
144585
144721
  }
144586
144722
 
144587
144723
  // ../tool-server/src/tools/flows/flow-add-step.ts
144588
- var zodSchema62 = external_exports.object({
144724
+ var zodSchema63 = external_exports.object({
144589
144725
  name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
144590
144726
  project_root: external_exports.string().describe(
144591
144727
  "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."
@@ -144702,7 +144838,7 @@ async function captureRunTarget(session, args) {
144702
144838
  }
144703
144839
  try {
144704
144840
  assertSafeFlowName(name);
144705
- const realFlowPath = await fs44.realpath(session.filePath);
144841
+ const realFlowPath = await fs45.realpath(session.filePath);
144706
144842
  const flowsDir = path32.dirname(realFlowPath);
144707
144843
  const fragPath = path32.join(flowsDir, `${name}.yaml`);
144708
144844
  const projectRoot = args.project_root;
@@ -144718,10 +144854,10 @@ async function captureRunTarget(session, args) {
144718
144854
  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}`
144719
144855
  };
144720
144856
  }
144721
- parseFlow(await fs44.readFile(fragPath, "utf8"));
144857
+ parseFlow(await fs45.readFile(fragPath, "utf8"));
144722
144858
  let executedPath;
144723
144859
  try {
144724
- executedPath = await fs44.realpath(path32.join(flowsDirFor(projectRoot), `${name}.yaml`));
144860
+ executedPath = await fs45.realpath(path32.join(flowsDirFor(projectRoot), `${name}.yaml`));
144725
144861
  } catch {
144726
144862
  executedPath = void 0;
144727
144863
  }
@@ -144730,7 +144866,7 @@ async function captureRunTarget(session, args) {
144730
144866
  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)`
144731
144867
  };
144732
144868
  }
144733
- if (executedPath !== await fs44.realpath(fragPath)) {
144869
+ if (executedPath !== await fs45.realpath(fragPath)) {
144734
144870
  return {
144735
144871
  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`
144736
144872
  };
@@ -144752,9 +144888,10 @@ function createFlowAddStepTool(registry2) {
144752
144888
  completedMsg: ({ params }) => `Added ${params.command} step to flow ${params.name}`,
144753
144889
  failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to add ${params.command} step to flow ${params.name}: ${failureSignal2.error_code}`
144754
144890
  },
144755
- description: `Execute a tool call and record it as a step in the flow named by \`name\` + \`project_root\` (the recording must already be open \u2014 see flow-start-recording). Use when recording a flow and you want to run and capture each action. A coordinate \`gesture-tap\` is recorded as a portable \`tap: { selector }\` step when the tapped element has stable text/identifier (otherwise coordinates are kept with a warning); a \`restart-app\` is recorded as a \`launch\` step (record one FIRST to make the flow a self-contained e2e flow; restart-app has no chromium support, so a chromium flow records as a fragment \u2014 add the \`launch: { chromium: <app path> }\` line to the YAML afterward, deleting the executionPrerequisite line if one was recorded: a flow that starts with a launch must not declare it). Returns { message, toolResult, flowFile, savedTo } on success. If it fails an error is returned and nothing is recorded.
144756
- If a step was recorded by mistake, edit the .yaml file directly to remove it.`,
144757
- zodSchema: zodSchema62,
144891
+ description: `Execute a tool call and record it as a step in the flow named by \`name\` + \`project_root\` (the recording must already be open \u2014 see flow-start-recording). Use when recording a flow and you want to run and capture each action. A coordinate \`gesture-tap\` is recorded as a portable \`tap: { selector }\` step when the tapped element has stable text/identifier (otherwise coordinates are kept with a warning); a \`restart-app\` is recorded as a \`launch\` step (record one FIRST to make the flow a self-contained e2e flow; restart-app has no chromium support, so a chromium flow records as a fragment \u2014 add the \`launch: { chromium: <app path> }\` line to the YAML afterward, deleting the executionPrerequisite line if one was recorded: a flow that starts with a launch must not declare it).
144892
+ Returns { message, toolResult, stepCount, recorded, savedTo } on success. If it fails an error is returned and nothing is recorded.
144893
+ If a step was recorded by mistake, edit the .yaml to remove it \u2014 against a remote client, only after \`flow-finish-recording\`: the in-memory copy is authoritative there, and every write serializes it over your edit.`,
144894
+ zodSchema: zodSchema63,
144758
144895
  services: () => ({}),
144759
144896
  async execute(_services, params, ctx) {
144760
144897
  const session = await requireRecordingSession(params.project_root, params.name);
@@ -144795,11 +144932,15 @@ If a step was recorded by mistake, edit the .yaml file directly to remove it.`,
144795
144932
  delayMs: params.delayMs
144796
144933
  };
144797
144934
  }
144798
- const { flowFile, savedTo } = await appendStepToFlow(session, step);
144935
+ const { savedTo, stepCount } = await appendStepToFlow(session, step);
144799
144936
  return {
144800
144937
  message: `Step added to "${params.name}" flow${warning ? ` \u2014 ${warning}` : ""}`,
144801
144938
  toolResult,
144802
- flowFile,
144939
+ stepCount,
144940
+ recorded: summarizeStep(step, stepCount),
144941
+ // Host mode: a path. Client mode: the directive that carries the YAML
144942
+ // to the client, which IS the persistence mechanism there — the one
144943
+ // place the full file still has to travel per step.
144803
144944
  savedTo
144804
144945
  };
144805
144946
  }
@@ -144808,7 +144949,7 @@ If a step was recorded by mistake, edit the .yaml file directly to remove it.`,
144808
144949
 
144809
144950
  // ../tool-server/src/tools/flows/flow-insert-echo.ts
144810
144951
  init_zod();
144811
- var zodSchema63 = external_exports.object({
144952
+ var zodSchema64 = external_exports.object({
144812
144953
  name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
144813
144954
  project_root: external_exports.string().describe(
144814
144955
  "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."
@@ -144826,145 +144967,23 @@ var flowInsertEchoTool = {
144826
144967
  },
144827
144968
  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.
144828
144969
  Use when you want to annotate a recorded flow with a human-readable label or checkpoint message.
144829
- Returns { message, flowFile, savedTo }. Fails if that flow has no recording in progress.`,
144830
- zodSchema: zodSchema63,
144970
+ Returns { message, stepCount, savedTo }. Fails if that flow has no recording in progress.`,
144971
+ zodSchema: zodSchema64,
144831
144972
  services: () => ({}),
144832
144973
  async execute(_services, params) {
144833
144974
  const session = await requireRecordingSession(params.project_root, params.name);
144834
- const { flowFile, savedTo } = await appendStepToFlow(session, {
144975
+ const { savedTo, stepCount } = await appendStepToFlow(session, {
144835
144976
  kind: "echo",
144836
144977
  message: params.message
144837
144978
  });
144838
144979
  return {
144839
144980
  message: `Echo added to "${params.name}" flow`,
144840
- flowFile,
144981
+ stepCount,
144841
144982
  savedTo
144842
144983
  };
144843
144984
  }
144844
144985
  };
144845
144986
 
144846
- // ../tool-server/src/tools/flows/flow-finish-recording.ts
144847
- init_zod();
144848
- var fs45 = __toESM(require("node:fs/promises"));
144849
- function selectorLabel(sel) {
144850
- return JSON.stringify(selectorToYaml(sel));
144851
- }
144852
- function textConditionLabel(sel, expectedText, textMatch) {
144853
- const selector = selectorLabel(sel);
144854
- const expected = expectedText ?? "";
144855
- return textMatch === "matches" ? `text ${selector} matches /${expected}/` : textMatch === "equals" ? `text ${selector} == ${JSON.stringify(expected)}` : `text ${selector} contains ${JSON.stringify(expected)}`;
144856
- }
144857
- var zodSchema64 = external_exports.object({
144858
- name: external_exports.string().describe("Name of the flow being recorded \u2014 the one passed to flow-start-recording."),
144859
- project_root: external_exports.string().describe(
144860
- "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."
144861
- )
144862
- });
144863
- var flowFinishRecordingTool = {
144864
- id: "flow-finish-recording",
144865
- interaction: {
144866
- // Name the flow: other recordings stay live across this call, so an
144867
- // unqualified "Finishing flow recording" would not identify which one.
144868
- startedMsg: ({ params }) => `Finishing recording of flow ${params.name}`,
144869
- // `params.name` rather than the basename of `result.path`: the two are the
144870
- // same string on every branch — `assertSafeFlowName` admits no dots or
144871
- // separators, so `getFlowPath` produces `<name>.yaml` and nothing else —
144872
- // and this spelling matches the two formatters either side of it.
144873
- completedMsg: ({ params }) => `Saved recorded flow ${params.name}`,
144874
- failedMsg: ({ params, failureSignal: failureSignal2 }) => `Failed to finish recording of flow ${params.name}: ${failureSignal2.error_code}`
144875
- },
144876
- 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.
144877
- You can still edit the .yaml file directly afterwards to remove or reorder steps.`,
144878
- zodSchema: zodSchema64,
144879
- services: () => ({}),
144880
- async execute(_services, params) {
144881
- const { filePath, flowFile, savedTo, flow, summary } = await withFlowFileLock(
144882
- params.project_root,
144883
- params.name,
144884
- async () => {
144885
- const session = await requireRecordingSession(params.project_root, params.name);
144886
- const filePath2 = session.filePath;
144887
- let flowFile2;
144888
- let savedTo2;
144889
- if (session.persist === "client") {
144890
- flowFile2 = serializeFlow(session.flow);
144891
- savedTo2 = clientFileDirective(filePath2, flowFile2);
144892
- } else {
144893
- flowFile2 = await fs45.readFile(filePath2, "utf8");
144894
- savedTo2 = filePath2;
144895
- }
144896
- const flow2 = parseFlow(flowFile2);
144897
- const summary2 = summarizeSteps(flow2);
144898
- clearRecordingSession(session);
144899
- return { filePath: filePath2, flowFile: flowFile2, savedTo: savedTo2, flow: flow2, summary: summary2 };
144900
- }
144901
- );
144902
- return {
144903
- message: `Finished recording "${params.name}" flow (${flow.steps.length} steps)`,
144904
- path: filePath,
144905
- executionPrerequisite: flow.executionPrerequisite,
144906
- steps: flow.steps.length,
144907
- summary,
144908
- flowFile,
144909
- savedTo
144910
- };
144911
- }
144912
- };
144913
- function renderToolArgs(args) {
144914
- try {
144915
- return `${JSON.stringify(args)}`;
144916
- } catch {
144917
- return "[cyclic args]";
144918
- }
144919
- }
144920
- function summarizeSteps(flow) {
144921
- return flow.steps.map((step, i) => {
144922
- const n = i + 1;
144923
- switch (step.kind) {
144924
- case "echo":
144925
- return `${n}. echo: ${step.message}`;
144926
- case "launch":
144927
- return `${n}. launch: ${typeof step.app === "string" ? step.app : JSON.stringify(step.app)}`;
144928
- case "run":
144929
- return `${n}. run: ${step.flow}`;
144930
- case "tap":
144931
- case "long-press":
144932
- return `${n}. ${step.kind}: ${step.selector ? selectorLabel(step.selector) : `(${step.x}, ${step.y})`}`;
144933
- case "type":
144934
- return `${n}. type: ${selectorLabel(step.into)} \u2190 "${step.text}"`;
144935
- case "await":
144936
- case "assert": {
144937
- const tail = step.condition === "text" ? textConditionLabel(step.selector, step.expectedText, step.textMatch) : `${step.condition} ${selectorLabel(step.selector)}`;
144938
- return `${n}. ${step.kind}: ${tail}`;
144939
- }
144940
- case "wait":
144941
- return `${n}. wait: ${step.ms}ms`;
144942
- case "when": {
144943
- const cond = step.condition.kind === "platform" ? `platform ${step.condition.platform}` : step.condition.condition === "text" ? textConditionLabel(
144944
- step.condition.selector,
144945
- step.condition.expectedText,
144946
- step.condition.textMatch
144947
- ) : `${step.condition.condition} ${selectorLabel(step.condition.selector)}`;
144948
- const count2 = step.steps.length;
144949
- return `${n}. when: ${cond} (${count2} step${count2 === 1 ? "" : "s"})`;
144950
- }
144951
- case "scroll-to":
144952
- return `${n}. scroll-to: ${selectorLabel(step.target)} (${step.direction})`;
144953
- case "pinch":
144954
- return `${n}. pinch: scale ${step.scale}${step.selector ? ` on ${selectorLabel(step.selector)}` : ""}`;
144955
- case "rotate":
144956
- return `${n}. rotate: by ${step.by}\xB0${step.selector ? ` on ${selectorLabel(step.selector)}` : ""}`;
144957
- case "snapshot":
144958
- return `${n}. snapshot: ${step.name}`;
144959
- case "idle":
144960
- return `${n}. await: screen idle`;
144961
- case "tool":
144962
- default:
144963
- return `${n}. tool: ${step.name} ${renderToolArgs(step.args)}`;
144964
- }
144965
- });
144966
- }
144967
-
144968
144987
  // ../tool-server/src/tools/flows/flow-run.ts
144969
144988
  init_zod();
144970
144989
  var fs49 = __toESM(require("node:fs/promises"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.19.1-next.5",
3
+ "version": "0.19.1-next.6",
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",
@@ -28,7 +28,7 @@ Obey these lifecycle rules:
28
28
  3. Give concurrent recordings separate devices. Their files are isolated, but their live device actions are not.
29
29
  4. Treat `flow-start-recording` as destructive. It always truncates the named YAML, including a finished or committed flow. `restarted` reports only a displaced live take.
30
30
  5. If a call says the recording is inactive, do not restart under that name. The completed take can still be on disk. Copy it aside or record under a fresh name.
31
- 6. Inspect `toolResult`, `message`, and `flowFile` after each call. A call that errors records nothing, but a call that returns normally while reporting an unmet condition **does** append the step, and `message` says the step was added either way. `await-ui-element` is the case that turns up in practice (see [Live waits and checks](#live-waits-and-checks)).
31
+ 6. Inspect `toolResult`, `message`, and `recorded` after each call. A call that errors records nothing, but a call that returns normally while reporting an unmet condition **does** append the step, and `message` says the step was added either way. `await-ui-element` is the case that turns up in practice (see [Live waits and checks](#live-waits-and-checks)). Only `flow-start-recording` and `flow-finish-recording` return the whole YAML as `flowFile`. A step call returns `recorded` — one summary line for the step it appended — plus a running `stepCount`. Read `recorded`: the recorder does not always store the tool call you made, and that line is where a rewrite shows up. To see the whole file mid-recording, read it at `savedTo`. A `savedTo` that comes back `null` means the write failed on your side. The step is still in the recording, so continue: the next step rewrites the whole file, and `flow-finish-recording` returns `flowFile` regardless.
32
32
  7. Edit or reorder the YAML only after `flow-finish-recording`. An active remote recording can overwrite mid-recording edits.
33
33
 
34
34
  ## Start in the correct order
@@ -76,7 +76,7 @@ For every action:
76
76
  1. **Discover without mutation.** Use `describe`, iOS native discovery, `debugger-component-tree`, or `screenshot`. Do not record discovery or `debugger-*` calls: `port` is not a device-bind key, so a recorded one replays against whatever Metro owns that port.
77
77
  2. **Choose a durable target.** Prefer a stable id, then stable text or an accessibility label. On iOS, use native discovery for ids that trimmed accessibility output omits.
78
78
  3. **Add an echo.** Name the current state, action, and expected outcome before the action can fail.
79
- 4. **Execute through `flow-add-step`.** Inspect the result and returned YAML immediately.
79
+ 4. **Execute through `flow-add-step`.** Inspect the result and the `recorded` line immediately.
80
80
  5. **Verify immediately.** Record outcome checks when their states first appear. After navigation, prove identity then readiness: record the identity check live, and add the readiness gate during polish.
81
81
 
82
82
  ### Record identity, then readiness, after every navigation
@@ -99,7 +99,7 @@ Without step 1, `hidden` also passes for a typo or an element that never existed
99
99
 
100
100
  ### Taps
101
101
 
102
- `flow-add-step` cannot receive a flow selector directly. Discover the element first, then record `gesture-tap` at its frame center; the live coordinates are transport for the gesture, not a final locator. The recorder reads the pre-tap tree and derives the selector in a fixed order — `id`, then `text`, then `role` — giving three outcomes. Read the returned flow file after every tap, because only two of them warn:
102
+ `flow-add-step` cannot receive a flow selector directly. Discover the element first, then record `gesture-tap` at its frame center; the live coordinates are transport for the gesture, not a final locator. The recorder reads the pre-tap tree and derives the selector in a fixed order — `id`, then `text`, then `role` — giving three outcomes. Read the `recorded` line after every tap, because only two of them warn. It names the derived form — a selector map, or the kept point:
103
103
 
104
104
  1. **`tap: { id: ... }` or `tap: { text: ... }`** — the good case.
105
105
  2. **`tap: { role: ... }`, appended with no warning.** An icon-only button with neither id nor visible label lands here. `role` matches as a case-insensitive substring, so a replay screen holding a second control of that role can win the [ranking](flow-yaml.md#the-runner-tree-is-not-the-discovery-tree) and the tap reports a pass on the wrong control.