@swmansion/argent 0.19.1-next.4 → 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.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -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"));
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.19.1-next.4",
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",
package/rules/argent.md CHANGED
@@ -76,6 +76,7 @@ Decision order:
76
76
  - Interaction tools (`gesture-tap`, `gesture-swipe`, `gesture-pinch`, `gesture-rotate`, `gesture-custom`, `launch-app`, etc.) return a screenshot automatically.
77
77
  Call `screenshot` separately only for a baseline before any action or after a delay.
78
78
  - Always open apps with `launch-app` or `open-url` — never tap home screen icons.
79
+ - If a task can require a saved flow, choose `argent-create-flow` or `argent-qa-flows` before the first launch or in-app action. Start the recorder before walking the path; recording is not retroactive.
79
80
  - Always use `run-sequence` when performing multiple sequential device actions where you don't need to observe the screen between steps. More in `argent-device-interact` skill.
80
81
  - When the session ends or the user says they are done: call `stop-all-simulator-servers` with `devices: [...]`
81
82
  naming the devices this session actually used. One tool-server is shared by every other agent using this
@@ -124,6 +125,7 @@ TV INTERACTION (APPLE TV / ANDROID TV / FIRE TV)
124
125
  Skill: `argent-tv-interact`
125
126
  When: Any TV target — a `list-devices` entry with `runtimeKind: "tv"` (Apple TV simulator or Android TV emulator) or `platform:"vega"` / `kind:"vvd"` (Amazon Fire TV / VVD), or the user mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV. A TV UI is focus-driven, not touch-driven: drive it with `describe` (read focus) + `tv-remote` (D-pad presses) + `keyboard` (type); `gesture-*` tools do NOT apply. Covers booting the target, app lifecycle, focus navigation, typing, screenshots, and (Vega) VVD lifecycle + Fast Refresh + JS-runtime debugging (evaluate, console logs, network inspector).
126
127
  Prompt keywords: apple tv, tvos, android tv, leanback, vega, fire tv, vvd, d-pad
128
+ Saved artifacts: on Vega, a replayable path is `argent-create-flow` and an acceptance-criteria regression test is `argent-qa-flows` — both record D-pad navigation as `tool: tv-remote` steps. Apple TV and Android TV have no saved-flow support; report that limitation.
127
129
 
128
130
  SCREENSHOT DIFF & VISUAL REGRESSION
129
131
  Skill: `argent-screenshot-diff`
@@ -131,7 +133,7 @@ When: Explicit visual regression, screenshot diff, compare screenshots, before/a
131
133
 
132
134
  SCREEN RECORDING (VIDEO CAPTURE)
133
135
  Skill: `argent-screen-recording`
134
- When: The user wants a video of the device screen — recording a flow, interaction, animation, or bug reproduction as a clip, or documenting app behavior beyond what a still screenshot shows. Covers the start interact → stop lifecycle, the reminder discipline that keeps a recording from being left running, and retrieving the mp4 artifact.
136
+ When: The user wants an mp4 of an interaction, animation, or bug reproduction. Use `argent-create-flow` instead for a replayable sequence.
135
137
  Prompt keywords: record, recording, screen recording, video, capture video, clip, mp4
136
138
 
137
139
  RUNNING / BUILDING / DEBUGGING REACT NATIVE APP
@@ -154,15 +156,21 @@ PERFORMANCE OPTIMIZATION
154
156
  Use skill: `argent-react-native-optimization`
155
157
  When: App feels slow, user asks to optimize, reducing bundle size, improving startup time, fixing re-renders, optimizing lists/images/navigation, or any performance-related task. This is the entry-point skill for all performance work — it delegates to `argent-react-native-profiler` for measurement.
156
158
 
157
- END-TO-END UI TESTING
159
+ INTERACTIVE UI TESTING (ONE-OFF, NOT SAVED)
158
160
  Skill: `argent-test-ui-flow`
159
- When: Verifying complete user flows, running interact → screenshot → verify loops, testing features by using the app, executing manual QA steps, or validating visible UI changes or visual behavior after implementation.
161
+ When: Running a one-off interact → screenshot → verify check with no saved regression artifact.
160
162
 
161
163
  RECORDING & REPLAYING FLOWS
162
164
  Use skill: `argent-create-flow`
163
- When: A multi-step interaction sequence needs to be repeated — re-profiling after a fix, A/B comparisons, regression checks, user says "again" / "run that flow", or you worked through a complex path worth saving. Also use proactively: if you are about to repeat steps you already performed, record first, then replay.
165
+ When: Saving or replaying a repeatable path for profiling, A/B comparison, retry, or reuse. For acceptance-driven regression tests, use `argent-qa-flows`.
164
166
  Prompt keywords: flow, repeat, test X times
165
167
 
168
+ GENERATED QA REGRESSION TESTS
169
+ Use skill: `argent-qa-flows`
170
+ When: Saving a test case, ticket, or acceptance criteria as a repeatable regression test. Requires stable evidence and two unchanged full passes. iOS, Android, Chromium, and Vega (D-pad navigation records as `tool: tv-remote` steps); not Apple TV or Android TV.
171
+ Prompt keywords: QA test, regression test, test case, automate this test, automate an e2e test, keep this e2e test, generate a test
172
+ Routing: one-off check → `argent-test-ui-flow`; saved path → `argent-create-flow`; saved acceptance test → `argent-qa-flows`.
173
+
166
174
  PROPOSING DESIGN VARIANTS FOR HUMAN SELECTION
167
175
  Use skill: `argent-lens`
168
176
  When: The user asks for design alternatives / options / A-B choices for a screen or component, or you have produced more than one candidate look for an element and want a human to pick before committing. Covers the build → navigate → screenshot → propose_variant loop and the single blocking await_user_selection call. (Gated behind the `argent-lens` flag, off by default — run `argent enable argent-lens` first.)