@swmansion/argent 0.21.1-next.12 → 0.21.1-next.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli-cmds.mjs CHANGED
@@ -7214,7 +7214,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
7214
7214
  var SESSION_ID2 = randomUUID5();
7215
7215
  function readCliVersion() {
7216
7216
  if (true) {
7217
- return "0.21.1-next.12";
7217
+ return "0.21.1-next.13";
7218
7218
  }
7219
7219
  return "0.0.0";
7220
7220
  }
@@ -8400,8 +8400,9 @@ function stepIndent(depth) {
8400
8400
  if (typeof depth !== "number" || !Number.isInteger(depth) || depth <= 0) return "";
8401
8401
  return " ".repeat(Math.min(depth, MAX_RENDER_DEPTH));
8402
8402
  }
8403
- function printHelp() {
8404
- console.log(`Usage: argent flow <subcommand> [options]
8403
+ function printHelp(toStderr = false) {
8404
+ const print = toStderr ? console.error : console.log;
8405
+ print(`Usage: argent flow <subcommand> [options]
8405
8406
 
8406
8407
  Run a YAML flow without an LLM in the loop. \`run\` takes any of these forms:
8407
8408
 
@@ -8451,6 +8452,7 @@ Options (run):
8451
8452
  overwritten
8452
8453
  -r, --recursive With a directory path, also run flows in subdirectories
8453
8454
  --json Print the raw JSON report
8455
+ --json-stream Print progress and the final report as NDJSON (single flow only)
8454
8456
  --help, -h Show this help
8455
8457
  -- End of options \u2014 only needed for a flow whose name
8456
8458
  starts with "-" (\`argent flow run -- -nightly\`)
@@ -8466,7 +8468,8 @@ function parseRunArgs(argv) {
8466
8468
  const out = {
8467
8469
  updateBaselines: false,
8468
8470
  recursive: false,
8469
- json: false
8471
+ json: false,
8472
+ jsonStream: false
8470
8473
  };
8471
8474
  const takePositional = (tok) => {
8472
8475
  if (out.flowRef !== void 0) {
@@ -8516,6 +8519,9 @@ function parseRunArgs(argv) {
8516
8519
  } else if (flag === "--json") {
8517
8520
  noValue("--json");
8518
8521
  out.json = true;
8522
+ } else if (flag === "--json-stream") {
8523
+ noValue("--json-stream");
8524
+ out.jsonStream = true;
8519
8525
  } else if (flag === "--recursive" || flag === "-r") {
8520
8526
  noValue("--recursive");
8521
8527
  out.recursive = true;
@@ -8524,6 +8530,9 @@ function parseRunArgs(argv) {
8524
8530
  else if (flag === "--output") out.output = takeValue("--output");
8525
8531
  else throw new FlagParseException(`unknown flag ${tok}`);
8526
8532
  }
8533
+ if (out.json && out.jsonStream) {
8534
+ throw new FlagParseException("--json and --json-stream cannot be combined");
8535
+ }
8527
8536
  return out;
8528
8537
  }
8529
8538
  function renderEchoLine(s) {
@@ -8822,13 +8831,10 @@ async function collectFlowFiles(dir, recursive) {
8822
8831
  }
8823
8832
  async function requireLocalToolServer() {
8824
8833
  const routing = await getResolvedToolsUrl();
8825
- if (routing.source === "none") return true;
8834
+ if (routing.source === "none") return void 0;
8826
8835
  const recovery = routing.source === "env" ? routing.shadowedLink ? `Unset ARGENT_TOOLS_URL and run \`argent unlink\`, then try again \u2014 a link to ${routing.shadowedLink.url} is also configured and takes over once the env var is unset.` : "Unset ARGENT_TOOLS_URL and try again." : "Run `argent unlink` and try again.";
8827
- console.error(
8828
- `argent flow run requires the auto-started local tool server; ${routing.source} routing is configured.
8829
- ${recovery}`
8830
- );
8831
- return false;
8836
+ return `argent flow run requires the auto-started local tool server; ${routing.source} routing is configured.
8837
+ ${recovery}`;
8832
8838
  }
8833
8839
  function buildRunPayload(flowPath, projectRoot, args) {
8834
8840
  const payload = {
@@ -8842,6 +8848,18 @@ function buildRunPayload(flowPath, projectRoot, args) {
8842
8848
  if (args.updateBaselines) payload.updateBaselines = true;
8843
8849
  return payload;
8844
8850
  }
8851
+ function writeJsonStreamRecord(record) {
8852
+ console.log(JSON.stringify(record));
8853
+ }
8854
+ function writeJsonStreamError(err) {
8855
+ const message = err instanceof Error ? err.message : String(err);
8856
+ writeJsonStreamRecord({
8857
+ event: "error",
8858
+ error: message,
8859
+ ...err instanceof ToolInvocationError && err.errorCode ? { error_code: err.errorCode } : {},
8860
+ ...err instanceof ToolInvocationError && err.errorKind ? { error_kind: err.errorKind } : {}
8861
+ });
8862
+ }
8845
8863
  async function exportAndResolveArtifacts(report, outputDir, flowPath, baseUrl) {
8846
8864
  if (outputDir) {
8847
8865
  const { url, token } = await baseUrl();
@@ -8862,7 +8880,11 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
8862
8880
  if (!args.recursive) console.error("Pass -r/--recursive to include subdirectories.");
8863
8881
  return exitAfterFlush(2);
8864
8882
  }
8865
- if (!await requireLocalToolServer()) return exitAfterFlush(2);
8883
+ const refusal = await requireLocalToolServer();
8884
+ if (refusal) {
8885
+ console.error(refusal);
8886
+ return exitAfterFlush(2);
8887
+ }
8866
8888
  const { callTool, baseUrl } = createToolsClient({ paths: options.paths });
8867
8889
  const outputBase = args.output ? path14.resolve(args.output) : void 0;
8868
8890
  const results = [];
@@ -8944,27 +8966,36 @@ async function flow(argv, options) {
8944
8966
  console.error(`Unknown flow subcommand "${sub}". Run \`argent flow --help\`.`);
8945
8967
  return exitAfterFlush(2);
8946
8968
  }
8969
+ const jsonStream = rest.some(
8970
+ (tok) => tok === "--json-stream" || tok.startsWith("--json-stream=")
8971
+ );
8947
8972
  if (rest.includes("--help") || rest.includes("-h")) {
8948
- printHelp();
8973
+ printHelp(jsonStream);
8949
8974
  return;
8950
8975
  }
8976
+ const fail = (message, code, err = message) => {
8977
+ if (jsonStream) writeJsonStreamError(err);
8978
+ console.error(message);
8979
+ return exitAfterFlush(code);
8980
+ };
8951
8981
  let args;
8952
8982
  try {
8953
8983
  args = parseRunArgs(rest);
8954
8984
  } catch (err) {
8955
8985
  if (err instanceof FlagParseException) {
8986
+ if (jsonStream) writeJsonStreamError(err);
8956
8987
  console.error(`Error: ${err.message}
8957
8988
  `);
8958
- printHelp();
8989
+ printHelp(jsonStream);
8959
8990
  return exitAfterFlush(2);
8960
8991
  }
8961
8992
  throw err;
8962
8993
  }
8963
8994
  if (!args.flowRef) {
8964
- console.error(
8965
- "argent flow run <flow|flow.yaml|dir> requires a flow name, a YAML file path, or a directory path."
8966
- );
8967
- printHelp();
8995
+ const message = "argent flow run <flow|flow.yaml|dir> requires a flow name, a YAML file path, or a directory path.";
8996
+ if (jsonStream) writeJsonStreamError(message);
8997
+ console.error(message);
8998
+ printHelp(jsonStream);
8968
8999
  return exitAfterFlush(2);
8969
9000
  }
8970
9001
  const projectRoot = process.cwd();
@@ -8980,11 +9011,11 @@ async function flow(argv, options) {
8980
9011
  } catch {
8981
9012
  }
8982
9013
  }
8983
- console.error(
9014
+ return fail(
8984
9015
  `Flow path must not contain ".." segments \u2014 they are collapsed without following symlinks, so the path can name a different file than the one your shell opens: ${suppliedPath}
8985
- ` + recovery
9016
+ ` + recovery,
9017
+ 2
8986
9018
  );
8987
- return exitAfterFlush(2);
8988
9019
  }
8989
9020
  const resolvedPath = path14.resolve(projectRoot, suppliedPath);
8990
9021
  let isDirectory = false;
@@ -8992,61 +9023,65 @@ async function flow(argv, options) {
8992
9023
  isDirectory = (await fsp.stat(resolvedPath)).isDirectory();
8993
9024
  } catch {
8994
9025
  if (args.recursive && !fromName) {
8995
- console.error(`Flow directory not found: ${resolvedPath}`);
8996
- return exitAfterFlush(2);
9026
+ return fail(`Flow directory not found: ${resolvedPath}`, 2);
8997
9027
  }
8998
9028
  }
8999
9029
  if (isDirectory) {
9030
+ if (args.jsonStream) {
9031
+ return fail("--json-stream supports a single flow; directory runs are not supported.", 2);
9032
+ }
9000
9033
  return runFlowDirectory(resolvedPath, args, projectRoot, options);
9001
9034
  }
9002
9035
  if (args.recursive) {
9003
- console.error(
9004
- fromName ? `flow run --recursive requires a directory path; "${args.flowRef}" is a saved-flow name, which always addresses the single file ${suppliedPath}.` : `flow run --recursive requires a directory path: ${suppliedPath}`
9036
+ return fail(
9037
+ fromName ? `flow run --recursive requires a directory path; "${args.flowRef}" is a saved-flow name, which always addresses the single file ${suppliedPath}.` : `flow run --recursive requires a directory path: ${suppliedPath}`,
9038
+ 2
9005
9039
  );
9006
- return exitAfterFlush(2);
9007
9040
  }
9008
9041
  const separatorTrimmedPath = suppliedPath.replace(/[\\/]+$/, "");
9009
9042
  if (separatorTrimmedPath !== suppliedPath && separatorTrimmedPath !== "") {
9010
9043
  const hint = SAFE_FLOW_NAME.test(separatorTrimmedPath) ? `.${path14.sep}${separatorTrimmedPath}` : separatorTrimmedPath;
9011
- console.error(
9044
+ return fail(
9012
9045
  `Flow path must not end in a path separator \u2014 the separator claims a directory, which the kernel would refuse to open as a file, so the CLI would run a file this string does not name: ${suppliedPath}
9013
- Did you mean: argent flow run ${shellQuoteArg(hint)}`
9046
+ Did you mean: argent flow run ${shellQuoteArg(hint)}`,
9047
+ 2
9014
9048
  );
9015
- return exitAfterFlush(2);
9016
9049
  }
9017
9050
  if (path14.extname(suppliedPath) !== ".yaml") {
9018
9051
  const looksLikeName = !suppliedPath.includes("/") && !suppliedPath.includes("\\") && path14.extname(suppliedPath) === "";
9019
9052
  if (path14.basename(suppliedPath).toLowerCase() === ".yaml") {
9020
- console.error(
9021
- `Flow filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`
9053
+ return fail(
9054
+ `Flow filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
9055
+ 2
9022
9056
  );
9023
- } else if (looksLikeName) {
9024
- console.error(
9057
+ }
9058
+ if (looksLikeName) {
9059
+ return fail(
9025
9060
  `Flow name must contain only letters, numbers, "_", or "-": ${suppliedPath}
9026
- Names run \`${FLOWS_DIR}/<name>.yaml\`; pass a path ending in .yaml to run a flow file kept elsewhere.`
9061
+ Names run \`${FLOWS_DIR}/<name>.yaml\`; pass a path ending in .yaml to run a flow file kept elsewhere.`,
9062
+ 2
9027
9063
  );
9028
- } else if (path14.extname(suppliedPath).toLowerCase() === ".yaml") {
9029
- console.error(
9030
- `Flow extension must be lowercase .yaml, not ${path14.extname(suppliedPath)}: ${suppliedPath}`
9064
+ }
9065
+ if (path14.extname(suppliedPath).toLowerCase() === ".yaml") {
9066
+ return fail(
9067
+ `Flow extension must be lowercase .yaml, not ${path14.extname(suppliedPath)}: ${suppliedPath}`,
9068
+ 2
9031
9069
  );
9032
- } else {
9033
- console.error(`Flow path must end in .yaml: ${suppliedPath}`);
9034
9070
  }
9035
- return exitAfterFlush(2);
9071
+ return fail(`Flow path must end in .yaml: ${suppliedPath}`, 2);
9036
9072
  }
9037
9073
  const flowName = path14.basename(suppliedPath, ".yaml");
9038
9074
  if (!SAFE_FLOW_NAME.test(flowName)) {
9039
- console.error(
9040
- `Flow filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`
9075
+ return fail(
9076
+ `Flow filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
9077
+ 2
9041
9078
  );
9042
- return exitAfterFlush(2);
9043
9079
  }
9044
9080
  const flowPath = resolvedPath;
9045
9081
  try {
9046
9082
  const stat5 = await fsp.stat(flowPath);
9047
9083
  if (!stat5.isFile()) {
9048
- console.error(`Flow path is not a file: ${flowPath}`);
9049
- return exitAfterFlush(2);
9084
+ return fail(`Flow path is not a file: ${flowPath}`, 2);
9050
9085
  }
9051
9086
  await fsp.access(flowPath, fsConstants2.R_OK);
9052
9087
  } catch (err) {
@@ -9057,8 +9092,7 @@ Names run \`${FLOWS_DIR}/<name>.yaml\`; pass a path ending in .yaml to run a flo
9057
9092
  recovery = fromName ? `
9058
9093
  No flow named "${args.flowRef}" is saved there \u2014 run \`argent flow list\` to see the saved flows.` : await savedFlowHint(projectRoot, flowPath);
9059
9094
  }
9060
- console.error(`${detail}: ${flowPath}${recovery}`);
9061
- return exitAfterFlush(2);
9095
+ return fail(`${detail}: ${flowPath}${recovery}`, 2);
9062
9096
  }
9063
9097
  const suppliedBase = path14.basename(flowPath);
9064
9098
  const siblings = await fsp.readdir(path14.dirname(flowPath)).catch(() => null);
@@ -9066,19 +9100,24 @@ No flow named "${args.flowRef}" is saved there \u2014 run \`argent flow list\` t
9066
9100
  const actual = siblings.find((name) => name.toLowerCase() === suppliedBase.toLowerCase());
9067
9101
  const actualRunnable = actual !== void 0 && path14.extname(actual) === ".yaml" && SAFE_FLOW_NAME.test(path14.basename(actual, ".yaml"));
9068
9102
  const recovery = actualRunnable ? fromName ? `Did you mean: argent flow run ${path14.basename(actual, ".yaml")}` : `Did you mean: argent flow run ${shellQuoteArg(path14.join(path14.dirname(suppliedPath), actual))}` : actual !== void 0 ? `Rename ${actual} to ${suppliedBase} to run it \u2014 flow files must be lowercase .yaml.` : "Pass the flow file's name exactly as it appears on disk.";
9069
- console.error(
9103
+ return fail(
9070
9104
  `Flow path must name the file as it appears on disk \u2014 this filesystem matched ${JSON.stringify(suppliedBase)} case-insensitively${actual !== void 0 ? ` to ${JSON.stringify(actual)}` : ""}, so the flow name (which keys the report, __baselines__/, and --output) would be one no file carries: ${suppliedPath}
9071
- ${recovery}`
9105
+ ${recovery}`,
9106
+ 2
9072
9107
  );
9073
- return exitAfterFlush(2);
9074
9108
  }
9075
- if (!await requireLocalToolServer()) return exitAfterFlush(2);
9109
+ const refusal = await requireLocalToolServer();
9110
+ if (refusal) return fail(refusal, 2);
9076
9111
  const { callTool, baseUrl } = createToolsClient({ paths: options.paths });
9077
9112
  const payload = buildRunPayload(flowPath, projectRoot, args);
9078
9113
  let liveSteps = 0;
9079
9114
  let liveIndex = 0;
9080
9115
  const onStepReport = (event) => {
9081
9116
  const s = event;
9117
+ if (args.jsonStream) {
9118
+ writeJsonStreamRecord({ event: "progress", data: s });
9119
+ return;
9120
+ }
9082
9121
  if (liveSteps === 0) console.log(`Flow "${flowName}"`);
9083
9122
  liveSteps++;
9084
9123
  if (s.kind === "echo") {
@@ -9099,20 +9138,25 @@ ${recovery}`
9099
9138
  );
9100
9139
  report = resp.data;
9101
9140
  } catch (err) {
9102
- console.error(err instanceof Error ? err.message : String(err));
9103
- return exitAfterFlush(1);
9141
+ return fail(err instanceof Error ? err.message : String(err), 1, err);
9104
9142
  }
9105
- if (!report || !("steps" in report)) {
9106
- console.error(`"${flowName}" did not produce a run report.`);
9107
- return exitAfterFlush(2);
9143
+ if (!report || typeof report !== "object" || !("steps" in report)) {
9144
+ return fail(`"${flowName}" did not produce a run report.`, 2);
9108
9145
  }
9109
- await exportAndResolveArtifacts(
9110
- report,
9111
- args.output ? path14.resolve(args.output) : void 0,
9112
- flowPath,
9113
- baseUrl
9114
- );
9115
- if (args.json) {
9146
+ try {
9147
+ await exportAndResolveArtifacts(
9148
+ report,
9149
+ args.output ? path14.resolve(args.output) : void 0,
9150
+ flowPath,
9151
+ baseUrl
9152
+ );
9153
+ } catch (err) {
9154
+ if (!args.jsonStream) throw err;
9155
+ return fail(err instanceof Error ? err.message : String(err), 2, err);
9156
+ }
9157
+ if (args.jsonStream) {
9158
+ writeJsonStreamRecord({ event: "result", data: report });
9159
+ } else if (args.json) {
9116
9160
  console.log(JSON.stringify(report, null, 2));
9117
9161
  } else if (liveSteps > 0) {
9118
9162
  if (report.executionPrerequisite) console.log(` assumes: ${report.executionPrerequisite}`);
@@ -16434,7 +16434,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
16434
16434
  var SESSION_ID = randomUUID4();
16435
16435
  function readCliVersion() {
16436
16436
  if (true) {
16437
- return "0.21.1-next.12";
16437
+ return "0.21.1-next.13";
16438
16438
  }
16439
16439
  return "0.0.0";
16440
16440
  }
@@ -95690,7 +95690,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
95690
95690
  var SESSION_ID = (0, import_node_crypto3.randomUUID)();
95691
95691
  function readCliVersion() {
95692
95692
  if (true) {
95693
- return "0.21.1-next.12";
95693
+ return "0.21.1-next.13";
95694
95694
  }
95695
95695
  return "0.0.0";
95696
95696
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.21.1-next.12",
3
+ "version": "0.21.1-next.13",
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",