@swmansion/argent 0.29.1-next.21 → 0.29.1-next.22

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/client.js CHANGED
@@ -504,17 +504,17 @@ var require_visit = __commonJS({
504
504
  visit.BREAK = BREAK;
505
505
  visit.SKIP = SKIP;
506
506
  visit.REMOVE = REMOVE;
507
- function visit_(key, node, visitor, path13) {
508
- const ctrl = callVisitor(key, node, visitor, path13);
507
+ function visit_(key, node, visitor, path14) {
508
+ const ctrl = callVisitor(key, node, visitor, path14);
509
509
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
510
- replaceNode(key, path13, ctrl);
511
- return visit_(key, ctrl, visitor, path13);
510
+ replaceNode(key, path14, ctrl);
511
+ return visit_(key, ctrl, visitor, path14);
512
512
  }
513
513
  if (typeof ctrl !== "symbol") {
514
514
  if (identity.isCollection(node)) {
515
- path13 = Object.freeze(path13.concat(node));
515
+ path14 = Object.freeze(path14.concat(node));
516
516
  for (let i = 0; i < node.items.length; ++i) {
517
- const ci = visit_(i, node.items[i], visitor, path13);
517
+ const ci = visit_(i, node.items[i], visitor, path14);
518
518
  if (typeof ci === "number")
519
519
  i = ci - 1;
520
520
  else if (ci === BREAK)
@@ -525,13 +525,13 @@ var require_visit = __commonJS({
525
525
  }
526
526
  }
527
527
  } else if (identity.isPair(node)) {
528
- path13 = Object.freeze(path13.concat(node));
529
- const ck = visit_("key", node.key, visitor, path13);
528
+ path14 = Object.freeze(path14.concat(node));
529
+ const ck = visit_("key", node.key, visitor, path14);
530
530
  if (ck === BREAK)
531
531
  return BREAK;
532
532
  else if (ck === REMOVE)
533
533
  node.key = null;
534
- const cv = visit_("value", node.value, visitor, path13);
534
+ const cv = visit_("value", node.value, visitor, path14);
535
535
  if (cv === BREAK)
536
536
  return BREAK;
537
537
  else if (cv === REMOVE)
@@ -552,17 +552,17 @@ var require_visit = __commonJS({
552
552
  visitAsync.BREAK = BREAK;
553
553
  visitAsync.SKIP = SKIP;
554
554
  visitAsync.REMOVE = REMOVE;
555
- async function visitAsync_(key, node, visitor, path13) {
556
- const ctrl = await callVisitor(key, node, visitor, path13);
555
+ async function visitAsync_(key, node, visitor, path14) {
556
+ const ctrl = await callVisitor(key, node, visitor, path14);
557
557
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
558
- replaceNode(key, path13, ctrl);
559
- return visitAsync_(key, ctrl, visitor, path13);
558
+ replaceNode(key, path14, ctrl);
559
+ return visitAsync_(key, ctrl, visitor, path14);
560
560
  }
561
561
  if (typeof ctrl !== "symbol") {
562
562
  if (identity.isCollection(node)) {
563
- path13 = Object.freeze(path13.concat(node));
563
+ path14 = Object.freeze(path14.concat(node));
564
564
  for (let i = 0; i < node.items.length; ++i) {
565
- const ci = await visitAsync_(i, node.items[i], visitor, path13);
565
+ const ci = await visitAsync_(i, node.items[i], visitor, path14);
566
566
  if (typeof ci === "number")
567
567
  i = ci - 1;
568
568
  else if (ci === BREAK)
@@ -573,13 +573,13 @@ var require_visit = __commonJS({
573
573
  }
574
574
  }
575
575
  } else if (identity.isPair(node)) {
576
- path13 = Object.freeze(path13.concat(node));
577
- const ck = await visitAsync_("key", node.key, visitor, path13);
576
+ path14 = Object.freeze(path14.concat(node));
577
+ const ck = await visitAsync_("key", node.key, visitor, path14);
578
578
  if (ck === BREAK)
579
579
  return BREAK;
580
580
  else if (ck === REMOVE)
581
581
  node.key = null;
582
- const cv = await visitAsync_("value", node.value, visitor, path13);
582
+ const cv = await visitAsync_("value", node.value, visitor, path14);
583
583
  if (cv === BREAK)
584
584
  return BREAK;
585
585
  else if (cv === REMOVE)
@@ -606,23 +606,23 @@ var require_visit = __commonJS({
606
606
  }
607
607
  return visitor;
608
608
  }
609
- function callVisitor(key, node, visitor, path13) {
609
+ function callVisitor(key, node, visitor, path14) {
610
610
  if (typeof visitor === "function")
611
- return visitor(key, node, path13);
611
+ return visitor(key, node, path14);
612
612
  if (identity.isMap(node))
613
- return visitor.Map?.(key, node, path13);
613
+ return visitor.Map?.(key, node, path14);
614
614
  if (identity.isSeq(node))
615
- return visitor.Seq?.(key, node, path13);
615
+ return visitor.Seq?.(key, node, path14);
616
616
  if (identity.isPair(node))
617
- return visitor.Pair?.(key, node, path13);
617
+ return visitor.Pair?.(key, node, path14);
618
618
  if (identity.isScalar(node))
619
- return visitor.Scalar?.(key, node, path13);
619
+ return visitor.Scalar?.(key, node, path14);
620
620
  if (identity.isAlias(node))
621
- return visitor.Alias?.(key, node, path13);
621
+ return visitor.Alias?.(key, node, path14);
622
622
  return void 0;
623
623
  }
624
- function replaceNode(key, path13, node) {
625
- const parent = path13[path13.length - 1];
624
+ function replaceNode(key, path14, node) {
625
+ const parent = path14[path14.length - 1];
626
626
  if (identity.isCollection(parent)) {
627
627
  parent.items[key] = node;
628
628
  } else if (identity.isPair(parent)) {
@@ -1234,10 +1234,10 @@ var require_Collection = __commonJS({
1234
1234
  var createNode = require_createNode();
1235
1235
  var identity = require_identity();
1236
1236
  var Node = require_Node();
1237
- function collectionFromPath(schema, path13, value) {
1237
+ function collectionFromPath(schema, path14, value) {
1238
1238
  let v = value;
1239
- for (let i = path13.length - 1; i >= 0; --i) {
1240
- const k = path13[i];
1239
+ for (let i = path14.length - 1; i >= 0; --i) {
1240
+ const k = path14[i];
1241
1241
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
1242
1242
  const a = [];
1243
1243
  a[k] = v;
@@ -1256,7 +1256,7 @@ var require_Collection = __commonJS({
1256
1256
  sourceObjects: /* @__PURE__ */ new Map()
1257
1257
  });
1258
1258
  }
1259
- var isEmptyPath = (path13) => path13 == null || typeof path13 === "object" && !!path13[Symbol.iterator]().next().done;
1259
+ var isEmptyPath = (path14) => path14 == null || typeof path14 === "object" && !!path14[Symbol.iterator]().next().done;
1260
1260
  var Collection = class extends Node.NodeBase {
1261
1261
  constructor(type, schema) {
1262
1262
  super(type);
@@ -1286,11 +1286,11 @@ var require_Collection = __commonJS({
1286
1286
  * be a Pair instance or a `{ key, value }` object, which may not have a key
1287
1287
  * that already exists in the map.
1288
1288
  */
1289
- addIn(path13, value) {
1290
- if (isEmptyPath(path13))
1289
+ addIn(path14, value) {
1290
+ if (isEmptyPath(path14))
1291
1291
  this.add(value);
1292
1292
  else {
1293
- const [key, ...rest] = path13;
1293
+ const [key, ...rest] = path14;
1294
1294
  const node = this.get(key, true);
1295
1295
  if (identity.isCollection(node))
1296
1296
  node.addIn(rest, value);
@@ -1304,8 +1304,8 @@ var require_Collection = __commonJS({
1304
1304
  * Removes a value from the collection.
1305
1305
  * @returns `true` if the item was found and removed.
1306
1306
  */
1307
- deleteIn(path13) {
1308
- const [key, ...rest] = path13;
1307
+ deleteIn(path14) {
1308
+ const [key, ...rest] = path14;
1309
1309
  if (rest.length === 0)
1310
1310
  return this.delete(key);
1311
1311
  const node = this.get(key, true);
@@ -1319,8 +1319,8 @@ var require_Collection = __commonJS({
1319
1319
  * scalar values from their surrounding node; to disable set `keepScalar` to
1320
1320
  * `true` (collections are always returned intact).
1321
1321
  */
1322
- getIn(path13, keepScalar) {
1323
- const [key, ...rest] = path13;
1322
+ getIn(path14, keepScalar) {
1323
+ const [key, ...rest] = path14;
1324
1324
  const node = this.get(key, true);
1325
1325
  if (rest.length === 0)
1326
1326
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -1338,8 +1338,8 @@ var require_Collection = __commonJS({
1338
1338
  /**
1339
1339
  * Checks if the collection includes a value with the key `key`.
1340
1340
  */
1341
- hasIn(path13) {
1342
- const [key, ...rest] = path13;
1341
+ hasIn(path14) {
1342
+ const [key, ...rest] = path14;
1343
1343
  if (rest.length === 0)
1344
1344
  return this.has(key);
1345
1345
  const node = this.get(key, true);
@@ -1349,8 +1349,8 @@ var require_Collection = __commonJS({
1349
1349
  * Sets a value in this collection. For `!!set`, `value` needs to be a
1350
1350
  * boolean to add/remove the item from the set.
1351
1351
  */
1352
- setIn(path13, value) {
1353
- const [key, ...rest] = path13;
1352
+ setIn(path14, value) {
1353
+ const [key, ...rest] = path14;
1354
1354
  if (rest.length === 0) {
1355
1355
  this.set(key, value);
1356
1356
  } else {
@@ -3865,9 +3865,9 @@ var require_Document = __commonJS({
3865
3865
  this.contents.add(value);
3866
3866
  }
3867
3867
  /** Adds a value to the document. */
3868
- addIn(path13, value) {
3868
+ addIn(path14, value) {
3869
3869
  if (assertCollection(this.contents))
3870
- this.contents.addIn(path13, value);
3870
+ this.contents.addIn(path14, value);
3871
3871
  }
3872
3872
  /**
3873
3873
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3942,14 +3942,14 @@ var require_Document = __commonJS({
3942
3942
  * Removes a value from the document.
3943
3943
  * @returns `true` if the item was found and removed.
3944
3944
  */
3945
- deleteIn(path13) {
3946
- if (Collection.isEmptyPath(path13)) {
3945
+ deleteIn(path14) {
3946
+ if (Collection.isEmptyPath(path14)) {
3947
3947
  if (this.contents == null)
3948
3948
  return false;
3949
3949
  this.contents = null;
3950
3950
  return true;
3951
3951
  }
3952
- return assertCollection(this.contents) ? this.contents.deleteIn(path13) : false;
3952
+ return assertCollection(this.contents) ? this.contents.deleteIn(path14) : false;
3953
3953
  }
3954
3954
  /**
3955
3955
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3964,10 +3964,10 @@ var require_Document = __commonJS({
3964
3964
  * scalar values from their surrounding node; to disable set `keepScalar` to
3965
3965
  * `true` (collections are always returned intact).
3966
3966
  */
3967
- getIn(path13, keepScalar) {
3968
- if (Collection.isEmptyPath(path13))
3967
+ getIn(path14, keepScalar) {
3968
+ if (Collection.isEmptyPath(path14))
3969
3969
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3970
- return identity.isCollection(this.contents) ? this.contents.getIn(path13, keepScalar) : void 0;
3970
+ return identity.isCollection(this.contents) ? this.contents.getIn(path14, keepScalar) : void 0;
3971
3971
  }
3972
3972
  /**
3973
3973
  * Checks if the document includes a value with the key `key`.
@@ -3978,10 +3978,10 @@ var require_Document = __commonJS({
3978
3978
  /**
3979
3979
  * Checks if the document includes a value at `path`.
3980
3980
  */
3981
- hasIn(path13) {
3982
- if (Collection.isEmptyPath(path13))
3981
+ hasIn(path14) {
3982
+ if (Collection.isEmptyPath(path14))
3983
3983
  return this.contents !== void 0;
3984
- return identity.isCollection(this.contents) ? this.contents.hasIn(path13) : false;
3984
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path14) : false;
3985
3985
  }
3986
3986
  /**
3987
3987
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3998,13 +3998,13 @@ var require_Document = __commonJS({
3998
3998
  * Sets a value in this document. For `!!set`, `value` needs to be a
3999
3999
  * boolean to add/remove the item from the set.
4000
4000
  */
4001
- setIn(path13, value) {
4002
- if (Collection.isEmptyPath(path13)) {
4001
+ setIn(path14, value) {
4002
+ if (Collection.isEmptyPath(path14)) {
4003
4003
  this.contents = value;
4004
4004
  } else if (this.contents == null) {
4005
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path13), value);
4005
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path14), value);
4006
4006
  } else if (assertCollection(this.contents)) {
4007
- this.contents.setIn(path13, value);
4007
+ this.contents.setIn(path14, value);
4008
4008
  }
4009
4009
  }
4010
4010
  /**
@@ -5965,9 +5965,9 @@ var require_cst_visit = __commonJS({
5965
5965
  visit.BREAK = BREAK;
5966
5966
  visit.SKIP = SKIP;
5967
5967
  visit.REMOVE = REMOVE;
5968
- visit.itemAtPath = (cst, path13) => {
5968
+ visit.itemAtPath = (cst, path14) => {
5969
5969
  let item = cst;
5970
- for (const [field, index] of path13) {
5970
+ for (const [field, index] of path14) {
5971
5971
  const tok = item?.[field];
5972
5972
  if (tok && "items" in tok) {
5973
5973
  item = tok.items[index];
@@ -5976,23 +5976,23 @@ var require_cst_visit = __commonJS({
5976
5976
  }
5977
5977
  return item;
5978
5978
  };
5979
- visit.parentCollection = (cst, path13) => {
5980
- const parent = visit.itemAtPath(cst, path13.slice(0, -1));
5981
- const field = path13[path13.length - 1][0];
5979
+ visit.parentCollection = (cst, path14) => {
5980
+ const parent = visit.itemAtPath(cst, path14.slice(0, -1));
5981
+ const field = path14[path14.length - 1][0];
5982
5982
  const coll = parent?.[field];
5983
5983
  if (coll && "items" in coll)
5984
5984
  return coll;
5985
5985
  throw new Error("Parent collection not found");
5986
5986
  };
5987
- function _visit(path13, item, visitor) {
5988
- let ctrl = visitor(item, path13);
5987
+ function _visit(path14, item, visitor) {
5988
+ let ctrl = visitor(item, path14);
5989
5989
  if (typeof ctrl === "symbol")
5990
5990
  return ctrl;
5991
5991
  for (const field of ["key", "value"]) {
5992
5992
  const token = item[field];
5993
5993
  if (token && "items" in token) {
5994
5994
  for (let i = 0; i < token.items.length; ++i) {
5995
- const ci = _visit(Object.freeze(path13.concat([[field, i]])), token.items[i], visitor);
5995
+ const ci = _visit(Object.freeze(path14.concat([[field, i]])), token.items[i], visitor);
5996
5996
  if (typeof ci === "number")
5997
5997
  i = ci - 1;
5998
5998
  else if (ci === BREAK)
@@ -6003,10 +6003,10 @@ var require_cst_visit = __commonJS({
6003
6003
  }
6004
6004
  }
6005
6005
  if (typeof ctrl === "function" && field === "key")
6006
- ctrl = ctrl(item, path13);
6006
+ ctrl = ctrl(item, path14);
6007
6007
  }
6008
6008
  }
6009
- return typeof ctrl === "function" ? ctrl(item, path13) : ctrl;
6009
+ return typeof ctrl === "function" ? ctrl(item, path14) : ctrl;
6010
6010
  }
6011
6011
  exports.visit = visit;
6012
6012
  }
@@ -7308,14 +7308,14 @@ var require_parser = __commonJS({
7308
7308
  case "scalar":
7309
7309
  case "single-quoted-scalar":
7310
7310
  case "double-quoted-scalar": {
7311
- const fs7 = this.flowScalar(this.type);
7311
+ const fs8 = this.flowScalar(this.type);
7312
7312
  if (atNextItem || it.value) {
7313
- map.items.push({ start, key: fs7, sep: [] });
7313
+ map.items.push({ start, key: fs8, sep: [] });
7314
7314
  this.onKeyLine = true;
7315
7315
  } else if (it.sep) {
7316
- this.stack.push(fs7);
7316
+ this.stack.push(fs8);
7317
7317
  } else {
7318
- Object.assign(it, { key: fs7, sep: [] });
7318
+ Object.assign(it, { key: fs8, sep: [] });
7319
7319
  this.onKeyLine = true;
7320
7320
  }
7321
7321
  return;
@@ -7443,13 +7443,13 @@ var require_parser = __commonJS({
7443
7443
  case "scalar":
7444
7444
  case "single-quoted-scalar":
7445
7445
  case "double-quoted-scalar": {
7446
- const fs7 = this.flowScalar(this.type);
7446
+ const fs8 = this.flowScalar(this.type);
7447
7447
  if (!it || it.value)
7448
- fc.items.push({ start: [], key: fs7, sep: [] });
7448
+ fc.items.push({ start: [], key: fs8, sep: [] });
7449
7449
  else if (it.sep)
7450
- this.stack.push(fs7);
7450
+ this.stack.push(fs8);
7451
7451
  else
7452
- Object.assign(it, { key: fs7, sep: [] });
7452
+ Object.assign(it, { key: fs8, sep: [] });
7453
7453
  return;
7454
7454
  }
7455
7455
  case "flow-map-end":
@@ -8075,7 +8075,7 @@ var CONFIG_SCHEMA = [
8075
8075
  // nominal here — the project scope of a global-only key is never read.
8076
8076
  {
8077
8077
  key: "scripts.maxTimeoutMs",
8078
- description: `Upper bound, in milliseconds, on the time limit a flow \`script\` step may ask for (default 300000 \u2014 five minutes). Bounds how long one script can occupy the host. Values below ${MIN_SCRIPT_TIMEOUT_MS} ms are refused: the step starts a Node process before the script runs, so a smaller ceiling ends a script that did nothing wrong.`,
8078
+ description: `Upper bound, in milliseconds, on the time limit an e2e test \`script\` step may ask for (default 300000 \u2014 five minutes). Bounds how long one script can occupy the host. Values below ${MIN_SCRIPT_TIMEOUT_MS} ms are refused: the step starts a Node process before the script runs, so a smaller ceiling ends a script that did nothing wrong.`,
8079
8079
  scopes: ["global"],
8080
8080
  parse: (raw) => {
8081
8081
  const value = asPositiveInteger(raw);
@@ -8088,7 +8088,7 @@ var CONFIG_SCHEMA = [
8088
8088
  },
8089
8089
  {
8090
8090
  key: "scripts.heapLimitMb",
8091
- description: `Old-space heap limit, in MiB, given to each flow \`script\` process (default 512). Values below ${MIN_SCRIPT_HEAP_LIMIT_MB} MiB are refused: that is already below what importing a real npm dependency needs, and under about 5 MiB the process dies inside V8's own startup before any script runs.`,
8091
+ description: `Old-space heap limit, in MiB, given to each e2e test \`script\` process (default 512). Values below ${MIN_SCRIPT_HEAP_LIMIT_MB} MiB are refused: that is already below what importing a real npm dependency needs, and under about 5 MiB the process dies inside V8's own startup before any script runs.`,
8092
8092
  scopes: ["global"],
8093
8093
  parse: (raw) => {
8094
8094
  const value = asPositiveInteger(raw);
@@ -8173,7 +8173,7 @@ function generateToken() {
8173
8173
  return randomBytes(AUTH_TOKEN_BYTES).toString("hex");
8174
8174
  }
8175
8175
  function findFreePort() {
8176
- return new Promise((resolve8, reject) => {
8176
+ return new Promise((resolve9, reject) => {
8177
8177
  const srv = net.createServer();
8178
8178
  srv.listen(0, "127.0.0.1", () => {
8179
8179
  const addr = srv.address();
@@ -8184,7 +8184,7 @@ function findFreePort() {
8184
8184
  const port = addr.port;
8185
8185
  srv.close((err) => {
8186
8186
  if (err) reject(err);
8187
- else resolve8(port);
8187
+ else resolve9(port);
8188
8188
  });
8189
8189
  });
8190
8190
  srv.on("error", reject);
@@ -8282,7 +8282,7 @@ function killSpawnedChild(child, pid) {
8282
8282
  }
8283
8283
  }
8284
8284
  function spawnToolsServer(paths, port, options = {}) {
8285
- return new Promise((resolve8, reject) => {
8285
+ return new Promise((resolve9, reject) => {
8286
8286
  let logFd;
8287
8287
  try {
8288
8288
  fs4.mkdirSync(STATE_DIR, { recursive: true });
@@ -8328,7 +8328,7 @@ function spawnToolsServer(paths, port, options = {}) {
8328
8328
  rl.close();
8329
8329
  child.stdout?.resume();
8330
8330
  child.stdout?.unref?.();
8331
- settle(() => resolve8({ port: actualPort, pid }));
8331
+ settle(() => resolve9({ port: actualPort, pid }));
8332
8332
  }
8333
8333
  });
8334
8334
  child.on("error", (err) => {
@@ -8633,10 +8633,11 @@ async function ensureToolsServer(paths) {
8633
8633
  }
8634
8634
 
8635
8635
  // ../argent-tools-client/src/tools-client.ts
8636
- import * as path11 from "node:path";
8636
+ import * as path12 from "node:path";
8637
8637
 
8638
8638
  // ../registry/src/types.ts
8639
8639
  var LINKED_CALL_HEADER = "x-argent-linked";
8640
+ var E2E_DIR_CLIENT_HEADER = "x-argent-e2e-dir";
8640
8641
 
8641
8642
  // ../registry/src/artifacts.ts
8642
8643
  import { stat } from "node:fs/promises";
@@ -8674,19 +8675,95 @@ function toolStepFiles(specs, args) {
8674
8675
  }
8675
8676
  return files;
8676
8677
  }
8677
- function isClientFileArgument({ spec, path: path13 }) {
8678
- return spec.kind === "file" && spec.path === `\${${spec.target}}` && path13.startsWith("/") && hasToolFileExtension(path13);
8678
+ function isClientFileArgument({ spec, path: path14 }) {
8679
+ return spec.kind === "file" && spec.path === `\${${spec.target}}` && path14.startsWith("/") && hasToolFileExtension(path14);
8679
8680
  }
8680
8681
 
8681
8682
  // ../registry/src/flow-file-refs.ts
8683
+ import * as fs6 from "node:fs/promises";
8684
+ import * as path8 from "node:path";
8685
+
8686
+ // ../registry/src/e2e-dirs.ts
8682
8687
  import * as fs5 from "node:fs/promises";
8683
8688
  import * as path7 from "node:path";
8689
+ var E2E_DIR = path7.join(".argent", "e2e");
8690
+ var LEGACY_E2E_DIRS = Object.freeze([path7.join(".argent", "flows")]);
8691
+ var E2E_DIRS = Object.freeze([E2E_DIR, ...LEGACY_E2E_DIRS]);
8692
+ function e2eDirFor(projectRoot) {
8693
+ return path7.join(projectRoot, E2E_DIR);
8694
+ }
8695
+ function e2eDirsFor(projectRoot) {
8696
+ return E2E_DIRS.map((dir) => path7.join(projectRoot, dir));
8697
+ }
8698
+ function e2eFileCandidates(projectRoot, name) {
8699
+ return e2eDirsFor(projectRoot).map((dir) => path7.join(dir, `${name}.yaml`));
8700
+ }
8701
+ async function exists(file) {
8702
+ return fs5.stat(file).then(
8703
+ () => true,
8704
+ () => false
8705
+ );
8706
+ }
8707
+ async function pickE2eFile(candidates) {
8708
+ for (let i = 0; i < candidates.length; i++) {
8709
+ if (!await exists(candidates[i])) continue;
8710
+ let shadowed;
8711
+ for (const later of candidates.slice(i + 1)) {
8712
+ if (await exists(later)) {
8713
+ shadowed = later;
8714
+ break;
8715
+ }
8716
+ }
8717
+ return {
8718
+ path: candidates[i],
8719
+ exists: true,
8720
+ legacy: i > 0,
8721
+ ...shadowed === void 0 ? {} : { shadowed }
8722
+ };
8723
+ }
8724
+ return { path: candidates[0], exists: false, legacy: false };
8725
+ }
8726
+ function e2eShadowWarning(used, shadowed) {
8727
+ return `${shadowed} is not used: ${used} has the same name and is read first.`;
8728
+ }
8729
+ var E2E_DIR_NAMES = E2E_DIRS.map((dir) => path7.basename(dir));
8730
+ function e2eDirProject(dir) {
8731
+ const trimmed = dir.length > 1 ? dir.replace(/[\\/]+$/, "") : dir;
8732
+ const argent = path7.dirname(trimmed);
8733
+ if (!E2E_DIR_NAMES.includes(path7.basename(trimmed)) || path7.basename(argent) !== ".argent") {
8734
+ return null;
8735
+ }
8736
+ return path7.dirname(argent);
8737
+ }
8738
+ function e2eRunFallbackDirs(anchorDir, target) {
8739
+ if (target.includes("/") || target.includes("\\")) return [];
8740
+ const project = e2eDirProject(anchorDir);
8741
+ if (project === null) return [];
8742
+ const anchor = path7.resolve(anchorDir);
8743
+ return e2eDirsFor(project).filter((dir) => path7.resolve(dir) !== anchor);
8744
+ }
8745
+
8746
+ // ../registry/src/tool-ids.ts
8747
+ var TOOL_ID_ALIASES = Object.freeze({
8748
+ "flow-start-recording": "e2e-start-recording",
8749
+ "flow-add-step": "e2e-add-step",
8750
+ "flow-add-echo": "e2e-add-echo",
8751
+ "flow-add-script": "e2e-add-script",
8752
+ "flow-finish-recording": "e2e-finish-recording",
8753
+ "flow-read-prerequisite": "e2e-read-prerequisite",
8754
+ "flow-execute": "e2e-execute"
8755
+ });
8756
+ function canonicalToolId(id) {
8757
+ return Object.hasOwn(TOOL_ID_ALIASES, id) ? TOOL_ID_ALIASES[id] : id;
8758
+ }
8759
+
8760
+ // ../registry/src/flow-file-refs.ts
8684
8761
  async function canonicalFlowPath(p) {
8685
8762
  try {
8686
- return await fs5.realpath(p);
8763
+ return await fs6.realpath(p);
8687
8764
  } catch {
8688
8765
  try {
8689
- return path7.join(await fs5.realpath(path7.dirname(p)), path7.basename(p));
8766
+ return path8.join(await fs6.realpath(path8.dirname(p)), path8.basename(p));
8690
8767
  } catch {
8691
8768
  return p;
8692
8769
  }
@@ -8695,7 +8772,7 @@ async function canonicalFlowPath(p) {
8695
8772
  function completeRunExtension(value) {
8696
8773
  if (value.endsWith(".yaml")) return value;
8697
8774
  const candidate = `${value}.yaml`;
8698
- return FLOW_FILE_NAME_PATTERN.test(path7.posix.basename(candidate)) ? candidate : value;
8775
+ return FLOW_FILE_NAME_PATTERN.test(path8.posix.basename(candidate)) ? candidate : value;
8699
8776
  }
8700
8777
  var MAX_RUN_DEPTH = 20;
8701
8778
  var MAX_BLOCK_NESTING = 64;
@@ -8714,16 +8791,16 @@ function collectFlowRequests(doc) {
8714
8791
  for (const step of steps) {
8715
8792
  if (!isRecord(step)) continue;
8716
8793
  const run = step.run;
8717
- if (typeof run === "string" && !run.includes("\\") && !path7.posix.isAbsolute(run) && !/^[A-Za-z]:/.test(run)) {
8794
+ if (typeof run === "string" && !run.includes("\\") && !path8.posix.isAbsolute(run) && !/^[A-Za-z]:/.test(run)) {
8718
8795
  const target = completeRunExtension(run);
8719
- if (FLOW_FILE_NAME_PATTERN.test(path7.posix.basename(target))) runTargets.add(target);
8796
+ if (FLOW_FILE_NAME_PATTERN.test(path8.posix.basename(target))) runTargets.add(target);
8720
8797
  }
8721
8798
  const snapshot = isRecord(step.snapshot) ? step.snapshot.name : step.snapshot;
8722
8799
  if (typeof snapshot === "string" && FLOW_NAME_PATTERN.test(snapshot)) snapshots.add(snapshot);
8723
8800
  if (typeof step.tool === "string") {
8724
8801
  const args = isRecord(step.args) ? step.args : {};
8725
8802
  toolSteps.push({ tool: step.tool, args });
8726
- const target = step.tool === "flow-execute" ? nestedFlowTarget(args) : void 0;
8803
+ const target = canonicalToolId(step.tool) === "e2e-execute" ? nestedFlowTarget(args) : void 0;
8727
8804
  if (target !== void 0) nested.push({ target, args });
8728
8805
  }
8729
8806
  visit(step.steps, depth + 1);
@@ -8733,14 +8810,14 @@ function collectFlowRequests(doc) {
8733
8810
  return { runTargets: [...runTargets], snapshots: [...snapshots], toolSteps, nested };
8734
8811
  }
8735
8812
  function baselineKeyFor(canonicalPath, flowName) {
8736
- const stem = path7.basename(canonicalPath, ".yaml");
8813
+ const stem = path8.basename(canonicalPath, ".yaml");
8737
8814
  return FLOW_NAME_PATTERN.test(stem) ? stem : flowName;
8738
8815
  }
8739
8816
  function flowMemberKey(anchorDir, target) {
8740
8817
  return `${anchorDir}\0${target}`;
8741
8818
  }
8742
8819
  async function classifyOnDiskSpelling(dir, base, addressable = FLOW_FILE_NAME_PATTERN) {
8743
- const entries = await fs5.readdir(dir).catch(() => null);
8820
+ const entries = await fs6.readdir(dir).catch(() => null);
8744
8821
  if (entries === null || entries.includes(base)) return { state: "listed" };
8745
8822
  const actual = entries.find((entry) => entry.toLowerCase() === base.toLowerCase());
8746
8823
  if (actual === void 0) return { state: "absent" };
@@ -8752,19 +8829,15 @@ function nestedFlowTarget(args) {
8752
8829
  if (flowPath === void 0) {
8753
8830
  if (typeof name !== "string" || !FLOW_NAME_PATTERN.test(name)) return void 0;
8754
8831
  if (!isResolvedAbsolute(projectRoot)) return void 0;
8755
- return {
8756
- kind: "name",
8757
- projectRoot,
8758
- name,
8759
- path: path7.join(projectRoot, ".argent", "flows", `${name}.yaml`)
8760
- };
8832
+ const paths = e2eFileCandidates(projectRoot, name);
8833
+ return { kind: "name", projectRoot, name, path: paths[0], paths };
8761
8834
  }
8762
8835
  if (name !== void 0 || !isResolvedAbsolute(flowPath)) return void 0;
8763
- if (!FLOW_FILE_NAME_PATTERN.test(path7.basename(flowPath))) return void 0;
8836
+ if (!FLOW_FILE_NAME_PATTERN.test(path8.basename(flowPath))) return void 0;
8764
8837
  return { kind: "flow_path", path: flowPath };
8765
8838
  }
8766
8839
  function isResolvedAbsolute(value) {
8767
- return typeof value === "string" && path7.isAbsolute(value) && !value.split(/[\\/]+/).includes("..");
8840
+ return typeof value === "string" && path8.isAbsolute(value) && !value.split(/[\\/]+/).includes("..");
8768
8841
  }
8769
8842
 
8770
8843
  // ../registry/src/failure-codes.ts
@@ -9094,9 +9167,9 @@ var FAILURE_SPAWN_CODE_SET = new Set(FAILURE_SPAWN_CODES);
9094
9167
  import { randomUUID as randomUUID3 } from "node:crypto";
9095
9168
  import { AsyncLocalStorage } from "node:async_hooks";
9096
9169
  var resolvedDuringInvocation = new AsyncLocalStorage();
9097
- function valueAtPath(root, path13) {
9170
+ function valueAtPath(root, path14) {
9098
9171
  let current = root;
9099
- for (const key of path13) {
9172
+ for (const key of path14) {
9100
9173
  if (current === null || typeof current !== "object") return void 0;
9101
9174
  if (!Object.hasOwn(current, key)) return void 0;
9102
9175
  current = current[key];
@@ -9154,11 +9227,11 @@ function describeParamIssues(error, params) {
9154
9227
  }
9155
9228
 
9156
9229
  // ../argent-tools-client/src/link-config.ts
9157
- import * as path8 from "node:path";
9230
+ import * as path9 from "node:path";
9158
9231
  import { homedir as homedir4 } from "node:os";
9159
9232
  import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile2, unlink as unlink2, chmod as chmod2 } from "node:fs/promises";
9160
- var LINK_DIR = path8.join(homedir4(), ".argent");
9161
- var LINK_FILE = path8.join(LINK_DIR, "link.json");
9233
+ var LINK_DIR = path9.join(homedir4(), ".argent");
9234
+ var LINK_FILE = path9.join(LINK_DIR, "link.json");
9162
9235
  async function readLinkConfig() {
9163
9236
  try {
9164
9237
  const raw = await readFile2(LINK_FILE, "utf8");
@@ -9207,22 +9280,22 @@ import {
9207
9280
  realpath as realpath2,
9208
9281
  rename as rename2,
9209
9282
  rm as rm2,
9210
- stat as stat2,
9283
+ stat as stat3,
9211
9284
  writeFile as writeFile3
9212
9285
  } from "node:fs/promises";
9213
9286
  import { constants, tmpdir } from "node:os";
9214
- import * as path9 from "node:path";
9287
+ import * as path10 from "node:path";
9215
9288
 
9216
9289
  // ../archive/src/index.ts
9217
9290
  import { execFile } from "node:child_process";
9218
9291
  import { rm, readdir as readdir3 } from "node:fs/promises";
9219
- import { basename as basename3, dirname as dirname4, join as join8, posix as posix2, resolve as resolve5, sep as sep2 } from "node:path";
9292
+ import { basename as basename4, dirname as dirname5, join as join9, posix as posix2, resolve as resolve6, sep as sep2 } from "node:path";
9220
9293
  import { promisify } from "node:util";
9221
9294
  var execFileAsync = promisify(execFile);
9222
9295
  var ArchiveError = class extends Error {
9223
9296
  };
9224
9297
  function createTarGzArgs(sourcePath, target) {
9225
- return ["-czf", target, "-C", dirname4(sourcePath), basename3(sourcePath)];
9298
+ return ["-czf", target, "-C", dirname5(sourcePath), basename4(sourcePath)];
9226
9299
  }
9227
9300
  async function createTarGzFile(sourcePath, tarPath) {
9228
9301
  try {
@@ -9244,8 +9317,8 @@ function isSafeTarMember(memberPath, destDir) {
9244
9317
  if (relative2 === ".." || relative2.startsWith("../") || relative2.split("/").includes("..")) {
9245
9318
  return false;
9246
9319
  }
9247
- const root = resolve5(destDir);
9248
- const resolved = resolve5(destDir, relative2);
9320
+ const root = resolve6(destDir);
9321
+ const resolved = resolve6(destDir, relative2);
9249
9322
  return resolved === root || resolved.startsWith(root + sep2);
9250
9323
  }
9251
9324
  async function listTarMembers(tarPath) {
@@ -9299,7 +9372,7 @@ async function assertSafeArchive(tarPath, destDir) {
9299
9372
  async function resolveMember(destDir, expectedName) {
9300
9373
  const entries = await readdir3(destDir);
9301
9374
  if (entries.includes(expectedName)) {
9302
- return join8(destDir, expectedName);
9375
+ return join9(destDir, expectedName);
9303
9376
  }
9304
9377
  const real = entries.filter((e) => !e.startsWith("._"));
9305
9378
  if (real.length !== 1) {
@@ -9307,7 +9380,7 @@ async function resolveMember(destDir, expectedName) {
9307
9380
  `Could not identify the extracted member (expected "${expectedName}", found ${real.length} entries).`
9308
9381
  );
9309
9382
  }
9310
- return join8(destDir, real[0]);
9383
+ return join9(destDir, real[0]);
9311
9384
  }
9312
9385
  async function safeExtractTarGz(tarPath, destDir, expectedName) {
9313
9386
  await assertSafeArchive(tarPath, destDir);
@@ -9345,6 +9418,16 @@ function interpolatePath(template, args) {
9345
9418
  });
9346
9419
  return missing ? null : out;
9347
9420
  }
9421
+ async function specPath(spec, args) {
9422
+ if (spec.kind !== "file" || !spec.paths?.length) return interpolatePath(spec.path, args);
9423
+ const candidates = [];
9424
+ for (const template of spec.paths) {
9425
+ const filled = interpolatePath(template, args);
9426
+ if (filled === null) return null;
9427
+ candidates.push(filled);
9428
+ }
9429
+ return (await pickE2eFile(candidates)).path;
9430
+ }
9348
9431
  var pendingArchives = /* @__PURE__ */ new Set();
9349
9432
  var ARCHIVE_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
9350
9433
  function removePendingArchives() {
@@ -9380,9 +9463,9 @@ function untrackArchive(archive) {
9380
9463
  process.removeListener("exit", removePendingArchives);
9381
9464
  }
9382
9465
  function sha256File(filePath) {
9383
- return new Promise((resolve8, reject) => {
9466
+ return new Promise((resolve9, reject) => {
9384
9467
  const hash = createHash2("sha256");
9385
- createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve8(hash.digest("hex"))).on("error", reject);
9468
+ createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve9(hash.digest("hex"))).on("error", reject);
9386
9469
  });
9387
9470
  }
9388
9471
  function toolServerError(text) {
@@ -9409,7 +9492,7 @@ function uploadFailure(url, res, text, bytes) {
9409
9492
  });
9410
9493
  }
9411
9494
  async function uploadTar(tarPath, endpoint, signal) {
9412
- const { size } = await stat2(tarPath);
9495
+ const { size } = await stat3(tarPath);
9413
9496
  const init = {
9414
9497
  method: "POST",
9415
9498
  headers: {
@@ -9433,7 +9516,7 @@ async function uploadTar(tarPath, endpoint, signal) {
9433
9516
  return json.uploadId;
9434
9517
  }
9435
9518
  async function uploadFile(sourcePath, endpoint, signal) {
9436
- const tarPath = path9.join(tmpdir(), `argent-upload-${randomUUID4()}.tar.gz`);
9519
+ const tarPath = path10.join(tmpdir(), `argent-upload-${randomUUID4()}.tar.gz`);
9437
9520
  trackArchive(tarPath);
9438
9521
  try {
9439
9522
  await createTarGzFile(await realpath2(sourcePath), tarPath);
@@ -9448,7 +9531,7 @@ async function uploadFile(sourcePath, endpoint, signal) {
9448
9531
  async function readFileInputWire(filePath, opts) {
9449
9532
  let st;
9450
9533
  try {
9451
- st = await stat2(filePath);
9534
+ st = await stat3(filePath);
9452
9535
  } catch {
9453
9536
  return null;
9454
9537
  }
@@ -9476,7 +9559,7 @@ async function prepareFileInputs(specs, args, opts) {
9476
9559
  for (const spec of specs) {
9477
9560
  if (spec.skipWhenSet && record[spec.skipWhenSet] !== void 0) continue;
9478
9561
  if (spec.target in record && typeof record[spec.target] !== "string") continue;
9479
- const filePath = interpolatePath(spec.path, record);
9562
+ const filePath = await specPath(spec, record);
9480
9563
  if (filePath === null) continue;
9481
9564
  if (spec.target in record && record[spec.target] !== filePath) continue;
9482
9565
  const wire = { [FILE_INPUT_MARKER2]: true, path: filePath };
@@ -9494,13 +9577,13 @@ async function prepareFileInputs(specs, args, opts) {
9494
9577
  wire.members = await opts.collectStepMembers(record, opts);
9495
9578
  }
9496
9579
  if (spec.kind === "tar-upload") {
9497
- const st = await stat2(filePath).catch(() => null);
9580
+ const st = await stat3(filePath).catch(() => null);
9498
9581
  if (st) {
9499
9582
  wire.size = st.size;
9500
9583
  wire.mtimeMs = st.mtimeMs;
9501
9584
  }
9502
9585
  if (opts.uploadEndpoint && st) {
9503
- process.stderr.write(`Uploading ${path9.basename(filePath)} to the remote tool-server...
9586
+ process.stderr.write(`Uploading ${path10.basename(filePath)} to the remote tool-server...
9504
9587
  `);
9505
9588
  Object.assign(wire, await uploadFile(filePath, opts.uploadEndpoint, opts.signal));
9506
9589
  }
@@ -9511,18 +9594,18 @@ async function prepareFileInputs(specs, args, opts) {
9511
9594
  return out ?? args;
9512
9595
  }
9513
9596
  function isAllowedClientFilePath(p) {
9514
- if (!path9.isAbsolute(p)) return false;
9597
+ if (!path10.isAbsolute(p)) return false;
9515
9598
  const segments = p.split(/[\\/]+/);
9516
9599
  if (segments.includes("..")) return false;
9517
9600
  const file = segments[segments.length - 1] ?? "";
9518
9601
  if (!FLOW_FILE_NAME_PATTERN.test(file)) return false;
9519
- return segments[segments.length - 3] === ".argent" && segments[segments.length - 2] === "flows";
9602
+ return e2eDirProject(segments.slice(0, -1).join("/")) !== null;
9520
9603
  }
9521
9604
  function isClientFileDirective2(value) {
9522
9605
  return !!value && typeof value === "object" && value[CLIENT_FILE_MARKER2] === true && typeof value.path === "string" && typeof value.content === "string";
9523
9606
  }
9524
9607
  async function replaceFile(target, bytes, mode) {
9525
- const temp = path9.join(path9.dirname(target), `.baseline-${randomUUID4()}.tmp`);
9608
+ const temp = path10.join(path10.dirname(target), `.baseline-${randomUUID4()}.tmp`);
9526
9609
  try {
9527
9610
  await writeFile3(temp, bytes, { flag: "wx" });
9528
9611
  if (mode !== void 0) await chmod3(temp, mode & 511);
@@ -9533,27 +9616,27 @@ async function replaceFile(target, bytes, mode) {
9533
9616
  }
9534
9617
  }
9535
9618
  async function writeBaselineFile(file, bytes, allowedDirs) {
9536
- if (!path9.isAbsolute(file) || path9.normalize(file) !== file || file.split(/[\\/]/).includes("..") || !file.endsWith(".png") || !allowedDirs.includes(path9.dirname(file))) {
9619
+ if (!path10.isAbsolute(file) || path10.normalize(file) !== file || file.split(/[\\/]/).includes("..") || !file.endsWith(".png") || !allowedDirs.includes(path10.dirname(file))) {
9537
9620
  return allowedDirs.length === 0 ? "this call writes no baselines" : `${file} is not a baseline of this call (${allowedDirs.map((d) => `${d}/<name>.png`).join(", ")})`;
9538
9621
  }
9539
9622
  if (bytes.length > MAX_CONTENT_BYTES) {
9540
9623
  return `${file}: the baseline is larger than the 32 MiB cap on a file this client writes`;
9541
9624
  }
9542
- const dir = path9.dirname(file);
9625
+ const dir = path10.dirname(file);
9543
9626
  await mkdir3(dir, { recursive: true });
9544
9627
  const link = await lstat(file).catch(() => null);
9545
9628
  const real = link === null ? null : await realpath2(file).catch(() => null);
9546
9629
  if (link !== null && real === null) return `${file} is a symbolic link to a missing file`;
9547
9630
  if (real !== null) {
9548
9631
  if (!real.endsWith(".png")) return `${file} links to a file that is not a PNG file`;
9549
- if (path9.dirname(real) !== await realpath2(dir)) {
9632
+ if (path10.dirname(real) !== await realpath2(dir)) {
9550
9633
  return `${file} links outside its baseline directory`;
9551
9634
  }
9552
9635
  }
9553
- const existing = real === null ? null : await stat2(real);
9636
+ const existing = real === null ? null : await stat3(real);
9554
9637
  if (existing !== null && !existing.isFile()) return `${file} is not a regular file`;
9555
9638
  await replaceFile(
9556
- real ?? path9.join(await realpath2(dir), path9.basename(file)),
9639
+ real ?? path10.join(await realpath2(dir), path10.basename(file)),
9557
9640
  bytes,
9558
9641
  existing?.mode
9559
9642
  );
@@ -9579,7 +9662,7 @@ async function applyClientFileDirectives(result, opts = {}) {
9579
9662
  if (isClientFileDirective2(value)) {
9580
9663
  if (!isAllowedClientFilePath(value.path)) return null;
9581
9664
  try {
9582
- await mkdir3(path9.dirname(value.path), { recursive: true });
9665
+ await mkdir3(path10.dirname(value.path), { recursive: true });
9583
9666
  await writeFile3(value.path, value.content, "utf8");
9584
9667
  written.push(value.path);
9585
9668
  return value.path;
@@ -9607,12 +9690,14 @@ async function applyClientFileDirectives(result, opts = {}) {
9607
9690
 
9608
9691
  // ../argent-tools-client/src/flow-files.ts
9609
9692
  var import_yaml = __toESM(require_dist2(), 1);
9610
- import { readdir as readdir4, readFile as readFile4, realpath as realpath3, stat as stat3 } from "node:fs/promises";
9611
- import * as path10 from "node:path";
9693
+ import { readdir as readdir4, readFile as readFile4, realpath as realpath3, stat as stat4 } from "node:fs/promises";
9694
+ import * as path11 from "node:path";
9612
9695
  var INLINE_MEMBERS_BYTES = 256 * 1024;
9613
- var FLOW_FILES_LOG_ENV = "ARGENT_FLOW_FILES_LOG";
9696
+ function filesLogEnabled() {
9697
+ return (process.env.ARGENT_E2E_FILES_LOG ?? process.env.ARGENT_FLOW_FILES_LOG) === "1";
9698
+ }
9614
9699
  function isWithin(inner, outer) {
9615
- return inner === outer || inner.startsWith(outer.endsWith(path10.sep) ? outer : outer + path10.sep);
9700
+ return inner === outer || inner.startsWith(outer.endsWith(path11.sep) ? outer : outer + path11.sep);
9616
9701
  }
9617
9702
  function printable(text) {
9618
9703
  return [...text].map(
@@ -9620,23 +9705,21 @@ function printable(text) {
9620
9705
  ).join("");
9621
9706
  }
9622
9707
  function isResolvedAbsolute2(value) {
9623
- return typeof value === "string" && path10.isAbsolute(value) && !value.split(/[\\/]+/).includes("..");
9708
+ return typeof value === "string" && path11.isAbsolute(value) && !value.split(/[\\/]+/).includes("..");
9624
9709
  }
9625
9710
  function namesValidFlow(args) {
9626
9711
  const { project_root, flow_path, name } = args;
9627
9712
  if (!isResolvedAbsolute2(project_root)) return false;
9628
9713
  if (name === void 0) {
9629
- return isResolvedAbsolute2(flow_path) && FLOW_FILE_NAME_PATTERN.test(path10.basename(flow_path));
9714
+ return isResolvedAbsolute2(flow_path) && FLOW_FILE_NAME_PATTERN.test(path11.basename(flow_path));
9630
9715
  }
9631
9716
  return flow_path === void 0 && typeof name === "string" && FLOW_NAME_PATTERN.test(name);
9632
9717
  }
9633
9718
  function savedFlowProject(file) {
9634
- if (!path10.isAbsolute(file)) return null;
9635
- const parts = file.split(path10.sep);
9636
- for (let i = parts.length - 3; i >= 0; i--) {
9637
- if (parts[i] === ".argent" && parts[i + 1] === "flows") {
9638
- return parts.slice(0, i).join(path10.sep) || path10.sep;
9639
- }
9719
+ if (!path11.isAbsolute(file)) return null;
9720
+ for (let dir = path11.dirname(file); dir !== path11.dirname(dir); dir = path11.dirname(dir)) {
9721
+ const project = e2eDirProject(dir);
9722
+ if (project !== null) return project;
9640
9723
  }
9641
9724
  return null;
9642
9725
  }
@@ -9649,11 +9732,11 @@ async function landing(spelled) {
9649
9732
  const canonical = await canonicalFlowPath(spelled);
9650
9733
  let at = spelled;
9651
9734
  for (; ; ) {
9652
- const parent = path10.dirname(at);
9735
+ const parent = path11.dirname(at);
9653
9736
  if (parent === at) return { canonical, fence: spelled, ...failure };
9654
9737
  const real = await realpath3(parent).catch(() => null);
9655
9738
  if (real !== null) {
9656
- return { canonical, fence: path10.join(real, path10.basename(at)), ...failure };
9739
+ return { canonical, fence: path11.join(real, path11.basename(at)), ...failure };
9657
9740
  }
9658
9741
  at = parent;
9659
9742
  }
@@ -9661,10 +9744,10 @@ async function landing(spelled) {
9661
9744
  }
9662
9745
  async function closureRoots(rootPath, rootCanonical, projectRoot) {
9663
9746
  const candidates = [];
9664
- if (typeof projectRoot === "string" && path10.isAbsolute(projectRoot)) {
9665
- candidates.push(projectRoot, path10.join(projectRoot, ".argent", "flows"));
9747
+ if (typeof projectRoot === "string" && path11.isAbsolute(projectRoot)) {
9748
+ candidates.push(projectRoot, ...e2eDirsFor(projectRoot));
9666
9749
  }
9667
- candidates.push(path10.dirname(rootPath), path10.dirname(rootCanonical));
9750
+ candidates.push(path11.dirname(rootPath), path11.dirname(rootCanonical));
9668
9751
  for (const file of [rootPath, rootCanonical]) {
9669
9752
  const project = savedFlowProject(file);
9670
9753
  if (project !== null) candidates.push(project);
@@ -9677,11 +9760,11 @@ async function closureRoots(rootPath, rootCanonical, projectRoot) {
9677
9760
  return real.filter((root) => !real.some((other) => other !== root && isWithin(root, other)));
9678
9761
  }
9679
9762
  async function readFlowMember(anchorDir, target, roots, budget, opts) {
9680
- const spelled = anchorDir + path10.sep + target;
9763
+ const spelled = anchorDir + path11.sep + target;
9681
9764
  const { canonical, fence, missing, error } = await landing(spelled);
9682
9765
  const spelling = await classifyOnDiskSpelling(
9683
- path10.dirname(spelled),
9684
- path10.posix.basename(target),
9766
+ path11.dirname(spelled),
9767
+ path11.posix.basename(target),
9685
9768
  FLOW_FILE_NAME_PATTERN
9686
9769
  );
9687
9770
  const member = {
@@ -9700,13 +9783,13 @@ async function readFlowMember(anchorDir, target, roots, budget, opts) {
9700
9783
  }
9701
9784
  if (error !== void 0) return refuse(error);
9702
9785
  if (missing) return { member: { ...member, state: "missing" }, sent: "missing" };
9703
- const st = await stat3(canonical).catch((err) => err);
9786
+ const st = await stat4(canonical).catch((err) => err);
9704
9787
  if (st instanceof Error) {
9705
9788
  if (st.code !== "ENOENT") return refuse(st.message);
9706
9789
  return { member: { ...member, state: "missing" }, sent: "missing" };
9707
9790
  }
9708
9791
  if (st.isDirectory()) return refuse("EISDIR: illegal operation on a directory, read");
9709
- if (!/\.ya?ml$/i.test(path10.basename(canonical))) {
9792
+ if (!/\.ya?ml$/i.test(path11.basename(canonical))) {
9710
9793
  return refuse(`${target} links to a file that is not a YAML file`);
9711
9794
  }
9712
9795
  const sent = await sendBytes(member, canonical, budget, opts);
@@ -9725,7 +9808,7 @@ async function readToolMember(file, roots, budget, opts) {
9725
9808
  if (!hasToolFileExtension(canonical)) {
9726
9809
  return refuse(`${file} links to a file that is not one of ${TOOL_FILE_EXTENSIONS.join(", ")}`);
9727
9810
  }
9728
- const st = await stat3(canonical).catch((err) => err);
9811
+ const st = await stat4(canonical).catch((err) => err);
9729
9812
  if (st instanceof Error) {
9730
9813
  if (st.code === "ENOENT" || st.code === "ENOTDIR") {
9731
9814
  return { member: { ...member, state: "missing" }, sent: "missing" };
@@ -9749,7 +9832,7 @@ async function baselineEntry(file, roots, forWrite) {
9749
9832
  };
9750
9833
  }
9751
9834
  if (error !== void 0) return { state: "refused", error };
9752
- const st = await stat3(canonical).catch((err) => err);
9835
+ const st = await stat4(canonical).catch((err) => err);
9753
9836
  if (st instanceof Error) {
9754
9837
  if (st.code !== "ENOENT") return { state: "refused", error: st.message };
9755
9838
  return forWrite ? { state: "refused", error: `${file} is a symbolic link to a missing file` } : { state: "missing" };
@@ -9799,7 +9882,7 @@ function memberCollector(roots, opts) {
9799
9882
  const runs = /* @__PURE__ */ new Set();
9800
9883
  const baselineDirs = /* @__PURE__ */ new Map();
9801
9884
  const budget = { inline: 0 };
9802
- const logging = process.env[FLOW_FILES_LOG_ENV] === "1";
9885
+ const logging = filesLogEnabled();
9803
9886
  const log = opts.log ?? ((line) => void process.stderr.write(`${line}
9804
9887
  `));
9805
9888
  const emit = (member, sent) => {
@@ -9807,18 +9890,19 @@ function memberCollector(roots, opts) {
9807
9890
  const subject = member.role === "flow" ? member.canonical : member.key;
9808
9891
  if (logging) log(printable(`[flow-files] ${member.role} ${subject}: ${sent}`));
9809
9892
  };
9810
- async function flow(anchorDir, target) {
9893
+ async function flow(anchorDir, target, onlyPresent) {
9811
9894
  const key = flowMemberKey(anchorDir, target);
9812
9895
  const known = flows.get(key);
9813
- if (known !== void 0) return known;
9896
+ if (known !== void 0) return onlyPresent && known.text === void 0 ? void 0 : known;
9814
9897
  const { member, text, sent } = await readFlowMember(anchorDir, target, roots, budget, opts);
9898
+ if (onlyPresent && text === void 0) return void 0;
9815
9899
  const entry = { member, ...text === void 0 ? {} : { text } };
9816
9900
  flows.set(key, entry);
9817
9901
  emit(member, sent);
9818
9902
  return entry;
9819
9903
  }
9820
9904
  async function toolFiles(step) {
9821
- if (step.tool === "flow-execute") return;
9905
+ if (canonicalToolId(step.tool) === "e2e-execute") return;
9822
9906
  for (const file of toolStepFiles(opts.toolFileInputs?.(step.tool), step.args)) {
9823
9907
  const { unwrapWhenSet } = file.spec;
9824
9908
  if (unwrapWhenSet !== void 0 && step.args[unwrapWhenSet] !== void 0) continue;
@@ -9828,11 +9912,31 @@ function memberCollector(roots, opts) {
9828
9912
  emit(read.member, read.sent);
9829
9913
  }
9830
9914
  }
9915
+ async function savedTest(target) {
9916
+ for (const candidate of target.paths) {
9917
+ const found = await flow(path11.dirname(candidate), path11.basename(candidate), true);
9918
+ if (found !== void 0) return found;
9919
+ }
9920
+ let first;
9921
+ for (const candidate of target.paths) {
9922
+ first ??= await flow(path11.dirname(candidate), path11.basename(candidate));
9923
+ }
9924
+ return first;
9925
+ }
9831
9926
  async function nestedRun(target, hop, updates, platform) {
9832
- const { member, text } = await flow(path10.dirname(target.path), `${target.name}.yaml`);
9927
+ const { member, text } = await savedTest(target);
9833
9928
  if (text === void 0 || hop >= MAX_RUN_DEPTH) return void 0;
9834
9929
  return { canonical: member.canonical, text, flowName: target.name, hop, updates, platform };
9835
9930
  }
9931
+ async function runTarget(anchorDir, target) {
9932
+ const found = await flow(anchorDir, target);
9933
+ if (found.member.spelling?.state !== "absent") return found;
9934
+ for (const dir of e2eRunFallbackDirs(anchorDir, target)) {
9935
+ const other = await flow(dir, target, true);
9936
+ if (other !== void 0) return other;
9937
+ }
9938
+ return found;
9939
+ }
9836
9940
  async function walk(start) {
9837
9941
  const queue = [...start];
9838
9942
  for (let run = queue.shift(); run !== void 0; run = queue.shift()) {
@@ -9852,12 +9956,12 @@ function memberCollector(roots, opts) {
9852
9956
  const requests = collectFlowRequests(doc);
9853
9957
  for (const name of requests.snapshots) snapshots.add(name);
9854
9958
  for (const step of requests.toolSteps) await toolFiles(step);
9855
- const anchorDir = path10.dirname(file.canonical);
9959
+ const anchorDir = path11.dirname(file.canonical);
9856
9960
  for (const target of requests.runTargets) {
9857
9961
  const key = flowMemberKey(anchorDir, target);
9858
9962
  if (visited.has(key)) continue;
9859
9963
  visited.add(key);
9860
- const { member, text } = await flow(anchorDir, target);
9964
+ const { member, text } = await runTarget(anchorDir, target);
9861
9965
  if (text !== void 0 && file.hop + 1 < MAX_RUN_DEPTH) {
9862
9966
  files.push({ canonical: member.canonical, text, hop: file.hop + 1 });
9863
9967
  }
@@ -9874,8 +9978,8 @@ function memberCollector(roots, opts) {
9874
9978
  }
9875
9979
  }
9876
9980
  if (snapshots.size === 0) continue;
9877
- const dir = path10.join(
9878
- path10.dirname(run.canonical),
9981
+ const dir = path11.join(
9982
+ path11.dirname(run.canonical),
9879
9983
  "__baselines__",
9880
9984
  baselineKeyFor(run.canonical, run.flowName)
9881
9985
  );
@@ -9899,7 +10003,7 @@ function memberCollector(roots, opts) {
9899
10003
  if (!name.endsWith(".png")) continue;
9900
10004
  const compared = [...prefixes].some((prefix) => name.startsWith(prefix));
9901
10005
  if (!updates && !compared) continue;
9902
- const file = path10.join(dir, name);
10006
+ const file = path11.join(dir, name);
9903
10007
  if (tools.has(file)) continue;
9904
10008
  const member = { role: "baseline", key: file, path: file };
9905
10009
  const entry = await baselineEntry(file, roots, updates && !compared);
@@ -9922,8 +10026,8 @@ async function collectFlowMembers(rootPath, rootBytes, args, opts) {
9922
10026
  if (!namesValidFlow(args)) return {};
9923
10027
  const canonical = await canonicalFlowPath(rootPath);
9924
10028
  const spelling = await classifyOnDiskSpelling(
9925
- path10.dirname(rootPath),
9926
- path10.basename(rootPath),
10029
+ path11.dirname(rootPath),
10030
+ path11.basename(rootPath),
9927
10031
  FLOW_FILE_NAME_PATTERN
9928
10032
  );
9929
10033
  const collector = memberCollector(
@@ -9934,7 +10038,7 @@ async function collectFlowMembers(rootPath, rootBytes, args, opts) {
9934
10038
  {
9935
10039
  canonical,
9936
10040
  text: rootBytes.toString("utf8"),
9937
- flowName: path10.basename(rootPath, ".yaml"),
10041
+ flowName: path11.basename(rootPath, ".yaml"),
9938
10042
  hop: 0,
9939
10043
  updates: args.updateBaselines === true,
9940
10044
  platform: callPlatform(args)
@@ -9957,33 +10061,37 @@ function recordedStep(args) {
9957
10061
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
9958
10062
  return { tool: command, args: parsed };
9959
10063
  }
9960
- async function collectStepMembers(args, opts) {
10064
+ async function collectStepMembers(args, opts, recordingDirFor = e2eDirFor) {
9961
10065
  const { name, project_root: projectRoot } = args;
9962
10066
  const step = recordedStep(args);
9963
- if (typeof name !== "string" || !FLOW_NAME_PATTERN.test(name) || typeof projectRoot !== "string" || !path10.isAbsolute(projectRoot) || step === void 0) {
10067
+ if (typeof name !== "string" || !FLOW_NAME_PATTERN.test(name) || typeof projectRoot !== "string" || !path11.isAbsolute(projectRoot) || step === void 0) {
9964
10068
  return [];
9965
10069
  }
9966
- const recording = path10.join(projectRoot, ".argent", "flows", `${name}.yaml`);
10070
+ const recording = path11.join(recordingDirFor(projectRoot), `${name}.yaml`);
9967
10071
  const collector = memberCollector(
9968
10072
  await closureRoots(recording, (await landing(recording)).canonical, projectRoot),
9969
10073
  opts
9970
10074
  );
9971
10075
  await collector.toolFiles(step);
9972
- if (step.tool === "flow-execute") {
9973
- const self = await collector.flow(path10.dirname(recording), path10.basename(recording));
10076
+ if (canonicalToolId(step.tool) === "e2e-execute") {
10077
+ const self = await collector.flow(path11.dirname(recording), path11.basename(recording));
9974
10078
  let runArgs = step.args;
9975
10079
  const named = nestedFlowTarget(runArgs);
9976
10080
  if (named?.kind === "flow_path") {
9977
- const stem = path10.basename(named.path, ".yaml");
9978
- if (path10.resolve(path10.dirname(named.path)) === path10.resolve(path10.dirname(recording))) {
9979
- await collector.flow(path10.dirname(recording), path10.basename(named.path));
10081
+ const stem = path11.basename(named.path, ".yaml");
10082
+ const base = path11.basename(named.path);
10083
+ const dir = path11.resolve(path11.dirname(named.path));
10084
+ const recordingDir = path11.dirname(recording);
10085
+ const dirs = [recordingDir, ...e2eRunFallbackDirs(recordingDir, base)];
10086
+ if (dirs.some((d) => path11.resolve(d) === dir)) {
10087
+ await collector.flow(path11.dirname(named.path), base);
9980
10088
  runArgs = { ...runArgs, name: stem };
9981
10089
  delete runArgs.flow_path;
9982
10090
  }
9983
10091
  }
9984
10092
  const target = nestedFlowTarget(runArgs);
9985
10093
  if (target?.kind === "name") {
9986
- await collector.flow(path10.dirname(self.member.canonical), `${target.name}.yaml`);
10094
+ await collector.flow(path11.dirname(self.member.canonical), `${target.name}.yaml`);
9987
10095
  const run = await collector.nestedRun(
9988
10096
  target,
9989
10097
  0,
@@ -9996,6 +10104,43 @@ async function collectStepMembers(args, opts) {
9996
10104
  await collector.sendBaselines();
9997
10105
  return collector.members;
9998
10106
  }
10107
+ async function nameToE2ePathForOlderServer(tool, fileInputs, args) {
10108
+ const id = canonicalToolId(tool);
10109
+ if (id !== "e2e-execute" && id !== "e2e-read-prerequisite") return args;
10110
+ const spec = fileInputs?.find((s) => s.target === "flow_file");
10111
+ if (spec === void 0 || spec.kind !== "file" || spec.paths?.length) return args;
10112
+ const target = nestedFlowTarget(args);
10113
+ if (target?.kind !== "name") return args;
10114
+ const picked = await pickE2eFile(target.paths);
10115
+ if (!picked.exists || picked.legacy) return args;
10116
+ const { name: _name, ...rest } = args;
10117
+ return { ...rest, flow_path: picked.path };
10118
+ }
10119
+ async function stepForOlderServer(args, listedId) {
10120
+ if (typeof args !== "object" || args === null || Array.isArray(args)) return args;
10121
+ const record = args;
10122
+ if (typeof record.command !== "string") return args;
10123
+ const command = listedId(record.command) ?? record.command;
10124
+ const step = recordedStep({ ...record, command });
10125
+ const target = step && canonicalToolId(step.tool) === "e2e-execute" && nestedFlowTarget(step.args);
10126
+ if (target && target.kind === "name") {
10127
+ const picked = await pickE2eFile(target.paths);
10128
+ if (picked.exists && !picked.legacy) {
10129
+ throw new Error(
10130
+ `Cannot record a nested ${record.command} of "${target.name}": the tool-server runs an older argent that records and runs nested e2e tests only from .argent/flows/, and "${target.name}" is ${picked.path}. Upgrade the tool-server to record it, or run it with e2e-execute outside the recording.`
10131
+ );
10132
+ }
10133
+ }
10134
+ return command === record.command ? args : { ...record, command };
10135
+ }
10136
+ async function e2eShadowWarningFor(tool, args) {
10137
+ const id = canonicalToolId(tool);
10138
+ if (id !== "e2e-execute" && id !== "e2e-read-prerequisite") return void 0;
10139
+ const target = nestedFlowTarget(args);
10140
+ if (target?.kind !== "name") return void 0;
10141
+ const picked = await pickE2eFile(target.paths);
10142
+ return picked.shadowed === void 0 ? void 0 : e2eShadowWarning(picked.path, picked.shadowed);
10143
+ }
9999
10144
 
10000
10145
  // ../argent-tools-client/src/tools-client.ts
10001
10146
  function authHeaders2(token) {
@@ -10073,6 +10218,10 @@ function errorBodyMessage(body) {
10073
10218
  if (Array.isArray(body.issues) && typeof body.message === "string") return body.message;
10074
10219
  return body.error ?? body.message;
10075
10220
  }
10221
+ function findTool(tools, name) {
10222
+ const id = canonicalToolId(name);
10223
+ return tools.find((t) => t.name === name) ?? tools.find((t) => canonicalToolId(t.name) === id) ?? null;
10224
+ }
10076
10225
  function assertRequiredPresent(meta, args) {
10077
10226
  const record = typeof args === "object" && args !== null ? args : {};
10078
10227
  const schema = meta.inputSchema;
@@ -10148,26 +10297,33 @@ function createToolsClient(options = {}) {
10148
10297
  return json.tools;
10149
10298
  }
10150
10299
  async function fetchTool(name, opts) {
10151
- const tools = await fetchTools(opts);
10152
- return tools.find((t) => t.name === name) ?? null;
10300
+ return findTool(await fetchTools(opts), name);
10153
10301
  }
10154
10302
  async function callTool(name, args, opts) {
10155
10303
  opts?.signal?.throwIfAborted();
10156
10304
  const { url, token, remote } = await route();
10157
10305
  let finalArgs = args;
10158
10306
  const tools = await fetchTools({ signal: opts?.signal });
10159
- const meta = tools.find((t) => t.name === name) ?? null;
10307
+ const meta = findTool(tools, name);
10308
+ const olderServer = meta !== null && !tools.some((t) => t.name === canonicalToolId(meta.name));
10309
+ if (meta) {
10310
+ finalArgs = await nameToE2ePathForOlderServer(meta.name, meta.fileInputs, args);
10311
+ }
10312
+ if (olderServer && canonicalToolId(meta.name) === "e2e-add-step") {
10313
+ finalArgs = await stepForOlderServer(finalArgs, (tool) => findTool(tools, tool)?.name);
10314
+ }
10315
+ const shadowWarning = await e2eShadowWarningFor(name, args);
10160
10316
  const baselineDirs = [];
10161
10317
  if (meta?.fileInputs?.length) {
10162
- if (remote) assertRequiredPresent(meta, args);
10163
- finalArgs = await prepareFileInputs(meta.fileInputs, args ?? {}, {
10318
+ if (remote) assertRequiredPresent(meta, finalArgs);
10319
+ finalArgs = await prepareFileInputs(meta.fileInputs, finalArgs ?? {}, {
10164
10320
  includeContent: remote,
10165
10321
  uploadEndpoint: remote ? { url, token } : void 0,
10166
10322
  log: diagnose,
10167
10323
  baselineDirs,
10168
10324
  collectMembers: collectFlowMembers,
10169
- collectStepMembers,
10170
- toolFileInputs: (tool) => tools.find((t) => t.name === tool)?.fileInputs,
10325
+ collectStepMembers: olderServer ? (record, o) => collectStepMembers(record, o, (root) => path12.join(root, LEGACY_E2E_DIRS[0])) : collectStepMembers,
10326
+ toolFileInputs: (tool) => findTool(tools, tool)?.fileInputs,
10171
10327
  signal: opts?.signal
10172
10328
  });
10173
10329
  }
@@ -10176,19 +10332,23 @@ function createToolsClient(options = {}) {
10176
10332
  for (const { path: file, error } of applied.failed) {
10177
10333
  diagnose(`The baseline ${file} was not written on this client: ${error}`);
10178
10334
  }
10179
- if (process.env.ARGENT_FLOW_FILES_LOG === "1") {
10335
+ if (filesLogEnabled()) {
10180
10336
  for (const file of applied.written) {
10181
- if (baselineDirs.includes(path11.dirname(file))) {
10337
+ if (baselineDirs.includes(path12.dirname(file))) {
10182
10338
  diagnose(`[flow-files] baseline ${file}: written`);
10183
10339
  }
10184
10340
  }
10185
10341
  }
10186
- return applied.result;
10342
+ const result = applied.result;
10343
+ if (shadowWarning === void 0 || typeof result !== "object" || result === null || Array.isArray(result) || typeof result.warning === "string") {
10344
+ return result;
10345
+ }
10346
+ return { ...result, warning: shadowWarning };
10187
10347
  };
10188
10348
  const stream = opts?.onProgress !== void 0 || carriesMembers(finalArgs);
10189
10349
  const sentOnce = carriesUpload(finalArgs);
10190
10350
  const res = await doFetch(
10191
- `${url}/tools/${encodeURIComponent(name)}`,
10351
+ `${url}/tools/${encodeURIComponent(meta?.name ?? name)}`,
10192
10352
  {
10193
10353
  method: "POST",
10194
10354
  headers: {
@@ -10196,6 +10356,9 @@ function createToolsClient(options = {}) {
10196
10356
  // Tells the tool-server the call came over a link, a link to
10197
10357
  // 127.0.0.1 included, which nothing else in the request shows.
10198
10358
  ...remote ? { [LINKED_CALL_HEADER]: "1" } : {},
10359
+ // Tells the tool-server this client writes recordings under
10360
+ // `.argent/e2e/`; an older client writes only `.argent/flows/`.
10361
+ [E2E_DIR_CLIENT_HEADER]: "1",
10199
10362
  // A proxy that compresses the stream holds each line until its buffer
10200
10363
  // fills. `identity` keeps the stream uncompressed end to end.
10201
10364
  ...stream ? { "Accept": "application/x-ndjson", "Accept-Encoding": "identity" } : {},
@@ -10253,10 +10416,10 @@ function createToolsClient(options = {}) {
10253
10416
  }
10254
10417
 
10255
10418
  // ../argent-tools-client/src/artifacts.ts
10256
- import { copyFile, mkdir as mkdir4, readFile as readFile5, realpath as realpath4, rm as rm3, stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
10419
+ import { copyFile, mkdir as mkdir4, readFile as readFile5, realpath as realpath4, rm as rm3, stat as stat5, writeFile as writeFile4 } from "node:fs/promises";
10257
10420
  import { constants as fsConstants } from "node:fs";
10258
10421
  import { tmpdir as tmpdir2 } from "node:os";
10259
- import { basename as basename6, dirname as dirname8, extname as extname2, isAbsolute as isAbsolute6, join as join11, normalize as normalize2, resolve as resolve7, sep as sep4 } from "node:path";
10422
+ import { basename as basename7, dirname as dirname9, extname as extname2, isAbsolute as isAbsolute6, join as join13, normalize as normalize2, resolve as resolve8, sep as sep4 } from "node:path";
10260
10423
  import { createHash as createHash3 } from "node:crypto";
10261
10424
  var ARTIFACT_MARKER2 = "__argentArtifact";
10262
10425
  function isArtifactHandle(value) {
@@ -10276,20 +10439,20 @@ function sanitizeSegment(segment) {
10276
10439
  function projectSlug() {
10277
10440
  const cwd = process.cwd();
10278
10441
  const hash = createHash3("sha1").update(cwd).digest("hex").slice(0, 6);
10279
- const name = sanitizeSegment(basename6(cwd)) || "root";
10442
+ const name = sanitizeSegment(basename7(cwd)) || "root";
10280
10443
  return `${name}-${hash}`;
10281
10444
  }
10282
10445
  function artifactsRoot() {
10283
- return process.env.ARGENT_ARTIFACTS_DIR ?? join11(tmpdir2(), "argent-artifacts");
10446
+ return process.env.ARGENT_ARTIFACTS_DIR ?? join13(tmpdir2(), "argent-artifacts");
10284
10447
  }
10285
10448
  function artifactDir(deviceId) {
10286
10449
  const parts = [artifactsRoot(), projectSlug(), sessionId()];
10287
10450
  if (deviceId) parts.push(sanitizeSegment(deviceId));
10288
- return join11(...parts);
10451
+ return join13(...parts);
10289
10452
  }
10290
10453
  function durableBaseDir() {
10291
10454
  const projectRoot = findProjectRoot(process.cwd());
10292
- return projectRoot ?? dirname8(argentHomeDir());
10455
+ return projectRoot ?? dirname9(argentHomeDir());
10293
10456
  }
10294
10457
  var ALLOWED_SAVE_DIRS = /* @__PURE__ */ new Set([normalize2(".argent/recordings")]);
10295
10458
  var RECORDINGS_SAVE_DIR = normalize2(".argent/recordings");
@@ -10303,9 +10466,9 @@ function configuredRecordingsDir() {
10303
10466
  if (typeof value !== "string") return null;
10304
10467
  const trimmed = value.trim();
10305
10468
  if (trimmed === "") return null;
10306
- const home = dirname8(argentHomeDir());
10307
- const expanded = trimmed === "~" ? home : trimmed.startsWith("~/") || trimmed.startsWith(`~${sep4}`) ? join11(home, trimmed.slice(2)) : trimmed;
10308
- return resolve7(durableBaseDir(), expanded);
10469
+ const home = dirname9(argentHomeDir());
10470
+ const expanded = trimmed === "~" ? home : trimmed.startsWith("~/") || trimmed.startsWith(`~${sep4}`) ? join13(home, trimmed.slice(2)) : trimmed;
10471
+ return resolve8(durableBaseDir(), expanded);
10309
10472
  }
10310
10473
  var MAX_DURABLE_BYTES = 2 * 1024 * 1024 * 1024;
10311
10474
  async function readCapped(res, cap) {
@@ -10338,10 +10501,10 @@ async function writeDurableUnique(dir, filename, write) {
10338
10501
  const stem = filename.slice(0, filename.length - ext.length);
10339
10502
  for (let i = 1; i <= 1e3; i++) {
10340
10503
  const candidate = i === 1 ? filename : `${stem} (${i})${ext}`;
10341
- const path13 = join11(dir, candidate);
10504
+ const path14 = join13(dir, candidate);
10342
10505
  try {
10343
- await write(path13);
10344
- return path13;
10506
+ await write(path14);
10507
+ return path14;
10345
10508
  } catch (err) {
10346
10509
  if (err?.code === "EEXIST") continue;
10347
10510
  throw err;
@@ -10361,21 +10524,21 @@ function durableSaveTarget(handle) {
10361
10524
  if (configured) {
10362
10525
  return {
10363
10526
  dir: configured,
10364
- path: join11(configured, sanitizeSegment(handle.filename)),
10527
+ path: join13(configured, sanitizeSegment(handle.filename)),
10365
10528
  base: configured,
10366
10529
  rel: ""
10367
10530
  };
10368
10531
  }
10369
10532
  }
10370
10533
  const base = durableBaseDir();
10371
- const dir = join11(base, rel);
10372
- return { dir, path: join11(dir, sanitizeSegment(handle.filename)), base, rel };
10534
+ const dir = join13(base, rel);
10535
+ return { dir, path: join13(dir, sanitizeSegment(handle.filename)), base, rel };
10373
10536
  }
10374
10537
  async function confineToRealBase(dir, base, rel) {
10375
10538
  try {
10376
10539
  const realDir = await realpath4(dir);
10377
10540
  const realBase = await realpath4(base);
10378
- return realDir === join11(realBase, rel);
10541
+ return realDir === join13(realBase, rel);
10379
10542
  } catch {
10380
10543
  return false;
10381
10544
  }
@@ -10383,7 +10546,7 @@ async function confineToRealBase(dir, base, rel) {
10383
10546
  async function resolveLocalFile(handle) {
10384
10547
  if (!handle.hostPath) return null;
10385
10548
  try {
10386
- const st = await stat4(handle.hostPath);
10549
+ const st = await stat5(handle.hostPath);
10387
10550
  if (handle.archive) {
10388
10551
  return st.isDirectory() ? handle.hostPath : null;
10389
10552
  }
@@ -10398,7 +10561,7 @@ async function resolveLocalFile(handle) {
10398
10561
  }
10399
10562
  }
10400
10563
  async function downloadAndExtractArchive(handle, data, dir) {
10401
- const tarball = join11(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
10564
+ const tarball = join13(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
10402
10565
  try {
10403
10566
  await writeFile4(tarball, data);
10404
10567
  return await safeExtractTarGz(tarball, dir, handle.filename);
@@ -10426,7 +10589,7 @@ async function materializeArtifacts(result, ctx) {
10426
10589
  const localPath = await resolveLocalFile(value);
10427
10590
  const saveTarget = durableSaveTarget(value);
10428
10591
  if (saveTarget) {
10429
- const filename = basename6(saveTarget.path);
10592
+ const filename = basename7(saveTarget.path);
10430
10593
  try {
10431
10594
  await mkdir4(saveTarget.dir, { recursive: true });
10432
10595
  if (!await confineToRealBase(saveTarget.dir, saveTarget.base, saveTarget.rel)) {
@@ -10490,7 +10653,7 @@ async function materializeArtifacts(result, ctx) {
10490
10653
  return await downloadAndExtractArchive(value, data, dir);
10491
10654
  }
10492
10655
  if (value.size > 0 && data.length !== value.size) return null;
10493
- const downloadedPath = join11(dir, sanitizeSegment(value.filename));
10656
+ const downloadedPath = join13(dir, sanitizeSegment(value.filename));
10494
10657
  await writeFile4(downloadedPath, data);
10495
10658
  if (value.mimeType.startsWith("image/")) {
10496
10659
  images.push({ localPath: downloadedPath, data, mimeType: value.mimeType });
@@ -10524,12 +10687,12 @@ function getDeviceIdFromArgs(args) {
10524
10687
  }
10525
10688
 
10526
10689
  // src/bundled-paths.ts
10527
- import * as fs6 from "node:fs";
10528
- import * as path12 from "node:path";
10690
+ import * as fs7 from "node:fs";
10691
+ import * as path13 from "node:path";
10529
10692
  function readPackageVersion() {
10530
10693
  try {
10531
10694
  const pkg = JSON.parse(
10532
- fs6.readFileSync(path12.join(import.meta.dirname, "..", "package.json"), "utf8")
10695
+ fs7.readFileSync(path13.join(import.meta.dirname, "..", "package.json"), "utf8")
10533
10696
  );
10534
10697
  return pkg.version;
10535
10698
  } catch {
@@ -10540,15 +10703,15 @@ var PACKAGE_NAME = "@swmansion/argent";
10540
10703
  function findDeclaringRoot(startDir) {
10541
10704
  let dir = startDir;
10542
10705
  for (; ; ) {
10543
- if (fs6.existsSync(path12.join(dir, ".argent", "install.json"))) return dir;
10706
+ if (fs7.existsSync(path13.join(dir, ".argent", "install.json"))) return dir;
10544
10707
  try {
10545
- const manifest = JSON.parse(fs6.readFileSync(path12.join(dir, "package.json"), "utf8"));
10708
+ const manifest = JSON.parse(fs7.readFileSync(path13.join(dir, "package.json"), "utf8"));
10546
10709
  if (manifest.devDependencies?.[PACKAGE_NAME] || manifest.dependencies?.[PACKAGE_NAME] || manifest.optionalDependencies?.[PACKAGE_NAME]) {
10547
10710
  return dir;
10548
10711
  }
10549
10712
  } catch {
10550
10713
  }
10551
- const parent = path12.dirname(dir);
10714
+ const parent = path13.dirname(dir);
10552
10715
  if (parent === dir) return null;
10553
10716
  dir = parent;
10554
10717
  }
@@ -10556,12 +10719,12 @@ function findDeclaringRoot(startDir) {
10556
10719
  function findStablePackageDir(startDir, packageRoot) {
10557
10720
  let dir = startDir;
10558
10721
  for (; ; ) {
10559
- const candidate = path12.join(dir, "node_modules", PACKAGE_NAME);
10722
+ const candidate = path13.join(dir, "node_modules", PACKAGE_NAME);
10560
10723
  try {
10561
- if (fs6.realpathSync(candidate) === packageRoot) return candidate;
10724
+ if (fs7.realpathSync(candidate) === packageRoot) return candidate;
10562
10725
  } catch {
10563
10726
  }
10564
- const parent = path12.dirname(dir);
10727
+ const parent = path13.dirname(dir);
10565
10728
  if (parent === dir) return void 0;
10566
10729
  dir = parent;
10567
10730
  }
@@ -10571,7 +10734,7 @@ function classifyInstall() {
10571
10734
  let dir;
10572
10735
  let cwd;
10573
10736
  try {
10574
- packageRoot = fs6.realpathSync(path12.join(import.meta.dirname, ".."));
10737
+ packageRoot = fs7.realpathSync(path13.join(import.meta.dirname, ".."));
10575
10738
  cwd = process.cwd();
10576
10739
  dir = cwd;
10577
10740
  } catch {
@@ -10579,8 +10742,8 @@ function classifyInstall() {
10579
10742
  }
10580
10743
  for (; ; ) {
10581
10744
  try {
10582
- const nmReal = fs6.realpathSync(path12.join(dir, "node_modules"));
10583
- if (packageRoot === nmReal || packageRoot.startsWith(nmReal + path12.sep)) {
10745
+ const nmReal = fs7.realpathSync(path13.join(dir, "node_modules"));
10746
+ if (packageRoot === nmReal || packageRoot.startsWith(nmReal + path13.sep)) {
10584
10747
  return {
10585
10748
  kind: "local",
10586
10749
  projectRoot: findDeclaringRoot(cwd) ?? dir,
@@ -10589,22 +10752,22 @@ function classifyInstall() {
10589
10752
  }
10590
10753
  } catch {
10591
10754
  }
10592
- const parent = path12.dirname(dir);
10755
+ const parent = path13.dirname(dir);
10593
10756
  if (parent === dir) break;
10594
10757
  dir = parent;
10595
10758
  }
10596
- if (packageRoot.includes(`${path12.sep}.yarn${path12.sep}`)) {
10759
+ if (packageRoot.includes(`${path13.sep}.yarn${path13.sep}`)) {
10597
10760
  const declRoot = findDeclaringRoot(cwd);
10598
10761
  if (declRoot) return { kind: "local", projectRoot: declRoot };
10599
10762
  }
10600
10763
  return { kind: "global" };
10601
10764
  }
10602
10765
  var classifiedInstall = classifyInstall();
10603
- var packageDir = classifiedInstall.stablePackageDir ?? path12.join(import.meta.dirname, "..");
10766
+ var packageDir = classifiedInstall.stablePackageDir ?? path13.join(import.meta.dirname, "..");
10604
10767
  var BUNDLED_RUNTIME_PATHS = {
10605
- bundlePath: path12.join(packageDir, "dist", "tool-server.cjs"),
10606
- simulatorServerDir: path12.join(packageDir, "bin"),
10607
- nativeDevtoolsDir: path12.join(packageDir, "dylibs"),
10768
+ bundlePath: path13.join(packageDir, "dist", "tool-server.cjs"),
10769
+ simulatorServerDir: path13.join(packageDir, "bin"),
10770
+ nativeDevtoolsDir: path13.join(packageDir, "dylibs"),
10608
10771
  version: readPackageVersion(),
10609
10772
  installKind: classifiedInstall.kind,
10610
10773
  installProjectRoot: classifiedInstall.projectRoot
@@ -10642,7 +10805,7 @@ function createArgentClient() {
10642
10805
  }
10643
10806
  async function listTools(options) {
10644
10807
  const tools = await client.fetchTools({ signal: options?.signal });
10645
- return tools.map(({ name, description, inputSchema }) => ({ name, description, inputSchema }));
10808
+ return tools.filter((tool) => tool.aliasOf === void 0).map(({ name, description, inputSchema }) => ({ name, description, inputSchema }));
10646
10809
  }
10647
10810
  async function callTool(name, args = {}, options) {
10648
10811
  try {