@swmansion/argent 0.27.1-next.20 → 0.27.1-next.21

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
@@ -8593,6 +8593,7 @@ function isRecord(value) {
8593
8593
  }
8594
8594
  function collectFlowRequests(doc) {
8595
8595
  const runTargets = /* @__PURE__ */ new Set();
8596
+ const snapshots = /* @__PURE__ */ new Set();
8596
8597
  const seen = /* @__PURE__ */ new Set();
8597
8598
  const visit = (steps, depth) => {
8598
8599
  if (!Array.isArray(steps) || depth > MAX_BLOCK_NESTING || seen.has(steps)) return;
@@ -8604,11 +8605,17 @@ function collectFlowRequests(doc) {
8604
8605
  const target = completeRunExtension(run);
8605
8606
  if (FLOW_FILE_NAME_PATTERN.test(path7.posix.basename(target))) runTargets.add(target);
8606
8607
  }
8608
+ const snapshot = isRecord(step.snapshot) ? step.snapshot.name : step.snapshot;
8609
+ if (typeof snapshot === "string" && FLOW_NAME_PATTERN.test(snapshot)) snapshots.add(snapshot);
8607
8610
  visit(step.steps, depth + 1);
8608
8611
  }
8609
8612
  };
8610
8613
  if (isRecord(doc)) visit(doc.steps, 0);
8611
- return { runTargets: [...runTargets] };
8614
+ return { runTargets: [...runTargets], snapshots: [...snapshots] };
8615
+ }
8616
+ function baselineKeyFor(canonicalPath, flowName) {
8617
+ const stem = path7.basename(canonicalPath, ".yaml");
8618
+ return FLOW_NAME_PATTERN.test(stem) ? stem : flowName;
8612
8619
  }
8613
8620
  function flowMemberKey(anchorDir, target) {
8614
8621
  return `${anchorDir}\0${target}`;
@@ -9045,7 +9052,17 @@ async function getResolvedToolsUrl() {
9045
9052
  // ../argent-tools-client/src/file-inputs.ts
9046
9053
  import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
9047
9054
  import { createReadStream, rmSync as rmSync2 } from "node:fs";
9048
- import { mkdir as mkdir3, readFile as readFile3, rm as rm2, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
9055
+ import {
9056
+ chmod as chmod3,
9057
+ lstat,
9058
+ mkdir as mkdir3,
9059
+ readFile as readFile3,
9060
+ realpath as realpath2,
9061
+ rename as rename2,
9062
+ rm as rm2,
9063
+ stat as stat2,
9064
+ writeFile as writeFile3
9065
+ } from "node:fs/promises";
9049
9066
  import { constants, tmpdir } from "node:os";
9050
9067
  import * as path9 from "node:path";
9051
9068
 
@@ -9354,9 +9371,61 @@ function isAllowedClientFilePath(p) {
9354
9371
  function isClientFileDirective2(value) {
9355
9372
  return !!value && typeof value === "object" && value[CLIENT_FILE_MARKER2] === true && typeof value.path === "string" && typeof value.content === "string";
9356
9373
  }
9357
- async function applyClientFileDirectives(result) {
9374
+ async function replaceFile(target, bytes, mode) {
9375
+ const temp = path9.join(path9.dirname(target), `.baseline-${randomUUID4()}.tmp`);
9376
+ try {
9377
+ await writeFile3(temp, bytes, { flag: "wx" });
9378
+ if (mode !== void 0) await chmod3(temp, mode & 511);
9379
+ await rename2(temp, target);
9380
+ } catch (err) {
9381
+ await rm2(temp, { force: true });
9382
+ throw err;
9383
+ }
9384
+ }
9385
+ async function writeBaselineFile(file, bytes, allowedDirs) {
9386
+ if (!path9.isAbsolute(file) || path9.normalize(file) !== file || file.split(/[\\/]/).includes("..") || !file.endsWith(".png") || !allowedDirs.includes(path9.dirname(file))) {
9387
+ return allowedDirs.length === 0 ? "this call writes no baselines" : `${file} is not a baseline of this call (${allowedDirs.map((d) => `${d}/<name>.png`).join(", ")})`;
9388
+ }
9389
+ if (bytes.length > MAX_CONTENT_BYTES) {
9390
+ return `${file}: the baseline is larger than the 32 MiB cap on a file this client writes`;
9391
+ }
9392
+ const dir = path9.dirname(file);
9393
+ await mkdir3(dir, { recursive: true });
9394
+ const link = await lstat(file).catch(() => null);
9395
+ const real = link === null ? null : await realpath2(file).catch(() => null);
9396
+ if (link !== null && real === null) return `${file} is a symbolic link to a missing file`;
9397
+ if (real !== null) {
9398
+ if (!real.endsWith(".png")) return `${file} links to a file that is not a PNG file`;
9399
+ if (path9.dirname(real) !== await realpath2(dir)) {
9400
+ return `${file} links outside its baseline directory`;
9401
+ }
9402
+ }
9403
+ const existing = real === null ? null : await stat2(real);
9404
+ if (existing !== null && !existing.isFile()) return `${file} is not a regular file`;
9405
+ await replaceFile(
9406
+ real ?? path9.join(await realpath2(dir), path9.basename(file)),
9407
+ bytes,
9408
+ existing?.mode
9409
+ );
9410
+ return null;
9411
+ }
9412
+ async function applyClientFileDirectives(result, opts = {}) {
9358
9413
  const written = [];
9414
+ const failed = [];
9359
9415
  async function walk(value) {
9416
+ if (isClientFileDirective2(value) && value.encoding === "base64") {
9417
+ const error = await writeBaselineFile(
9418
+ value.path,
9419
+ Buffer.from(value.content, "base64"),
9420
+ opts.allowedDirs ?? []
9421
+ ).catch((err) => err instanceof Error ? err.message : String(err));
9422
+ if (error !== null) {
9423
+ failed.push({ path: value.path, error });
9424
+ return { path: value.path, error };
9425
+ }
9426
+ written.push(value.path);
9427
+ return value.path;
9428
+ }
9360
9429
  if (isClientFileDirective2(value)) {
9361
9430
  if (!isAllowedClientFilePath(value.path)) return null;
9362
9431
  try {
@@ -9369,7 +9438,9 @@ async function applyClientFileDirectives(result) {
9369
9438
  }
9370
9439
  }
9371
9440
  if (Array.isArray(value)) {
9372
- return Promise.all(value.map(walk));
9441
+ const out = [];
9442
+ for (const item of value) out.push(await walk(item));
9443
+ return out;
9373
9444
  }
9374
9445
  if (value && typeof value === "object") {
9375
9446
  const out = {};
@@ -9381,12 +9452,12 @@ async function applyClientFileDirectives(result) {
9381
9452
  return value;
9382
9453
  }
9383
9454
  const rewritten = await walk(result);
9384
- return { result: rewritten, written };
9455
+ return { result: rewritten, written, failed };
9385
9456
  }
9386
9457
 
9387
9458
  // ../argent-tools-client/src/flow-files.ts
9388
9459
  var import_yaml = __toESM(require_dist(), 1);
9389
- import { readFile as readFile4, realpath as realpath2, stat as stat3 } from "node:fs/promises";
9460
+ import { readdir as readdir4, readFile as readFile4, realpath as realpath3, stat as stat3 } from "node:fs/promises";
9390
9461
  import * as path10 from "node:path";
9391
9462
  var INLINE_MEMBERS_BYTES = 256 * 1024;
9392
9463
  var FLOW_FILES_LOG_ENV = "ARGENT_FLOW_FILES_LOG";
@@ -9421,7 +9492,7 @@ function savedFlowProject(file) {
9421
9492
  }
9422
9493
  async function landing(spelled) {
9423
9494
  try {
9424
- const canonical = await realpath2(spelled);
9495
+ const canonical = await realpath3(spelled);
9425
9496
  return { canonical, fence: canonical };
9426
9497
  } catch (err) {
9427
9498
  const failure = err.code === "ENOENT" ? { missing: true } : { error: err.message };
@@ -9430,7 +9501,7 @@ async function landing(spelled) {
9430
9501
  for (; ; ) {
9431
9502
  const parent = path10.dirname(at);
9432
9503
  if (parent === at) return { canonical, fence: spelled, ...failure };
9433
- const real = await realpath2(parent).catch(() => null);
9504
+ const real = await realpath3(parent).catch(() => null);
9434
9505
  if (real !== null) {
9435
9506
  return { canonical, fence: path10.join(real, path10.basename(at)), ...failure };
9436
9507
  }
@@ -9450,7 +9521,7 @@ async function closureRoots(rootPath, rootCanonical, projectRoot) {
9450
9521
  }
9451
9522
  const real = [];
9452
9523
  for (const candidate of candidates) {
9453
- const resolved = await realpath2(candidate).catch(() => null);
9524
+ const resolved = await realpath3(candidate).catch(() => null);
9454
9525
  if (resolved !== null && !real.includes(resolved)) real.push(resolved);
9455
9526
  }
9456
9527
  return real.filter((root) => !real.some((other) => other !== root && isWithin(root, other)));
@@ -9488,31 +9559,96 @@ async function readFlowMember(anchorDir, target, roots, budget, opts) {
9488
9559
  if (!/\.ya?ml$/i.test(path10.basename(canonical))) {
9489
9560
  return refuse(`${target} links to a file that is not a YAML file`);
9490
9561
  }
9491
- const read = await readFileInputWire(canonical, { includeContent: true });
9562
+ const sent = await sendBytes(member, canonical, budget, opts);
9563
+ return { ...sent, text: sent.bytes?.toString("utf8") };
9564
+ }
9565
+ function callPlatform(args) {
9566
+ if (typeof args.device === "string" && args.device.startsWith("chromium-cdp-")) return "chromium";
9567
+ if (typeof args.platform !== "string") return void 0;
9568
+ return args.platform === "ios-remote" ? "ios" : args.platform;
9569
+ }
9570
+ async function baselineEntry(file, roots, forWrite) {
9571
+ const { canonical, error } = await landing(file);
9572
+ if (!roots.some((root) => isWithin(canonical, root))) {
9573
+ return {
9574
+ state: "refused",
9575
+ error: `${file} is outside every root this client serves (${roots.join(", ")})`
9576
+ };
9577
+ }
9578
+ if (error !== void 0) return { state: "refused", error };
9579
+ const st = await stat3(canonical).catch((err) => err);
9580
+ if (st instanceof Error) {
9581
+ if (st.code !== "ENOENT") return { state: "refused", error: st.message };
9582
+ return forWrite ? { state: "refused", error: `${file} is a symbolic link to a missing file` } : { state: "missing" };
9583
+ }
9584
+ if (!canonical.endsWith(".png")) {
9585
+ return { state: "refused", error: `${file} links to a file that is not a PNG file` };
9586
+ }
9587
+ if (forWrite && !st.isFile()) return { state: "refused", error: `${file} is not a regular file` };
9588
+ if (st.isDirectory()) {
9589
+ return { state: "refused", error: "EISDIR: illegal operation on a directory, read" };
9590
+ }
9591
+ return st.isFile() ? { state: "ok", real: canonical } : { state: "missing" };
9592
+ }
9593
+ async function sendBytes(member, real, budget, opts) {
9594
+ const read = await readFileInputWire(real, { includeContent: true });
9492
9595
  if (read?.contentOmitted) {
9493
- return refuse(`${canonical} is larger than the 32 MiB cap on a file sent to the tool-server`);
9596
+ const error = `${real} is larger than the 32 MiB cap on a file sent to the tool-server`;
9597
+ return { member: { ...member, state: "refused", error }, sent: `refused (${error})` };
9494
9598
  }
9495
9599
  if (read?.content === void 0) {
9496
- return refuse(
9497
- await readFile4(canonical).then(
9498
- () => `${canonical} could not be read on this client`,
9499
- (err) => err instanceof Error ? err.message : String(err)
9500
- )
9600
+ const error = await readFile4(real).then(
9601
+ () => `${real} could not be read on this client`,
9602
+ (err) => err instanceof Error ? err.message : String(err)
9501
9603
  );
9604
+ return { member: { ...member, state: "refused", error }, sent: `refused (${error})` };
9502
9605
  }
9503
- const text = Buffer.from(read.content, "base64").toString("utf8");
9606
+ const bytes = Buffer.from(read.content, "base64");
9504
9607
  const size = read.size ?? 0;
9505
9608
  if (budget.inline + size <= INLINE_MEMBERS_BYTES || !opts.uploadEndpoint) {
9506
9609
  budget.inline += size;
9507
- return { member: { ...member, ...read }, text, sent: `inline ${size}` };
9610
+ return { member: { ...member, ...read }, sent: `inline ${size}`, bytes };
9508
9611
  }
9509
- const uploaded = await uploadFile(canonical, opts.uploadEndpoint, opts.signal);
9612
+ const uploaded = await uploadFile(real, opts.uploadEndpoint, opts.signal);
9510
9613
  return {
9511
9614
  member: { ...member, size: read.size, mtimeMs: read.mtimeMs, ...uploaded },
9512
- text,
9513
- sent: `upload ${size}`
9615
+ sent: `upload ${size}`,
9616
+ bytes
9514
9617
  };
9515
9618
  }
9619
+ async function collectBaselineMembers(canonical, flowName, snapshots, args, roots, budget, opts, emit) {
9620
+ const dir = path10.join(
9621
+ path10.dirname(canonical),
9622
+ "__baselines__",
9623
+ baselineKeyFor(canonical, flowName)
9624
+ );
9625
+ const real = (await landing(dir)).canonical;
9626
+ if (!roots.some((root) => isWithin(real, root))) return;
9627
+ const updates = args.updateBaselines === true;
9628
+ if (updates) opts.baselineDirs?.push(dir);
9629
+ const platform = callPlatform(args);
9630
+ const prefixes = snapshots.map(
9631
+ (name) => `${name}__${platform === void 0 ? "" : `${platform}-`}`
9632
+ );
9633
+ const names = await readdir4(dir).catch(() => []);
9634
+ for (const name of names.sort()) {
9635
+ if (!name.endsWith(".png")) continue;
9636
+ if (!updates && !prefixes.some((prefix) => name.startsWith(prefix))) continue;
9637
+ const file = path10.join(dir, name);
9638
+ const member = { role: "baseline", key: file, path: file };
9639
+ const entry = await baselineEntry(file, roots, updates);
9640
+ if (entry.state === "refused") {
9641
+ emit({ ...member, state: "refused", error: entry.error }, `refused (${entry.error})`);
9642
+ } else if (entry.state === "missing") {
9643
+ emit({ ...member, state: "missing" }, "missing");
9644
+ } else if (updates) {
9645
+ emit({ ...member, state: "listed" }, "listed");
9646
+ } else {
9647
+ const sent = await sendBytes(member, entry.real, budget, opts);
9648
+ emit(sent.member, sent.sent);
9649
+ }
9650
+ }
9651
+ }
9516
9652
  async function collectFlowMembers(rootPath, rootBytes, args, opts) {
9517
9653
  if (!namesValidFlow(args)) return {};
9518
9654
  const canonical = await canonicalFlowPath(rootPath);
@@ -9524,10 +9660,16 @@ async function collectFlowMembers(rootPath, rootBytes, args, opts) {
9524
9660
  const roots = await closureRoots(rootPath, canonical, args.project_root);
9525
9661
  const members = [];
9526
9662
  const seen = /* @__PURE__ */ new Set();
9663
+ const snapshots = /* @__PURE__ */ new Set();
9527
9664
  const budget = { inline: 0 };
9528
9665
  const logging = process.env[FLOW_FILES_LOG_ENV] === "1";
9529
9666
  const log = opts.log ?? ((line) => void process.stderr.write(`${line}
9530
9667
  `));
9668
+ const emit = (member, sent) => {
9669
+ members.push(member);
9670
+ const subject = member.role === "flow" ? member.canonical : member.key;
9671
+ if (logging) log(printable(`[flow-files] ${member.role} ${subject}: ${sent}`));
9672
+ };
9531
9673
  const queue = [{ canonical, text: rootBytes.toString("utf8"), hop: 0 }];
9532
9674
  for (let file = queue.shift(); file !== void 0; file = queue.shift()) {
9533
9675
  let doc;
@@ -9536,19 +9678,33 @@ async function collectFlowMembers(rootPath, rootBytes, args, opts) {
9536
9678
  } catch {
9537
9679
  continue;
9538
9680
  }
9681
+ const requests = collectFlowRequests(doc);
9682
+ for (const name of requests.snapshots) snapshots.add(name);
9539
9683
  const anchorDir = path10.dirname(file.canonical);
9540
- for (const target of collectFlowRequests(doc).runTargets) {
9684
+ for (const target of requests.runTargets) {
9541
9685
  const key = flowMemberKey(anchorDir, target);
9542
9686
  if (seen.has(key)) continue;
9543
9687
  seen.add(key);
9544
9688
  const { member, text, sent } = await readFlowMember(anchorDir, target, roots, budget, opts);
9545
- members.push(member);
9546
- if (logging) log(printable(`[flow-files] flow ${member.canonical}: ${sent}`));
9689
+ emit(member, sent);
9547
9690
  if (text !== void 0 && file.hop + 1 < MAX_RUN_DEPTH) {
9548
9691
  queue.push({ canonical: member.canonical, text, hop: file.hop + 1 });
9549
9692
  }
9550
9693
  }
9551
9694
  }
9695
+ if (snapshots.size > 0) {
9696
+ const flowName = path10.basename(rootPath, ".yaml");
9697
+ await collectBaselineMembers(
9698
+ canonical,
9699
+ flowName,
9700
+ [...snapshots],
9701
+ args,
9702
+ roots,
9703
+ budget,
9704
+ opts,
9705
+ emit
9706
+ );
9707
+ }
9552
9708
  return { canonical, spelling, members };
9553
9709
  }
9554
9710
 
@@ -9583,7 +9739,20 @@ async function consumeToolStream(name, body, onProgress, signal) {
9583
9739
  }
9584
9740
  };
9585
9741
  const decoder = new TextDecoder();
9586
- let buffered = "";
9742
+ let pieces = [];
9743
+ const take = (text) => {
9744
+ let start = 0;
9745
+ let newline;
9746
+ while ((newline = text.indexOf("\n", start)) !== -1) {
9747
+ signal?.throwIfAborted();
9748
+ pieces.push(text.slice(start, newline));
9749
+ const line = pieces.join("");
9750
+ pieces = [];
9751
+ start = newline + 1;
9752
+ handleLine(line);
9753
+ }
9754
+ if (start < text.length) pieces.push(text.slice(start));
9755
+ };
9587
9756
  try {
9588
9757
  for (; ; ) {
9589
9758
  let chunk;
@@ -9595,17 +9764,11 @@ async function consumeToolStream(name, body, onProgress, signal) {
9595
9764
  }
9596
9765
  const { done, value } = chunk;
9597
9766
  if (done) break;
9598
- buffered += decoder.decode(value, { stream: true });
9599
- let newline;
9600
- while ((newline = buffered.indexOf("\n")) !== -1) {
9601
- signal?.throwIfAborted();
9602
- const line = buffered.slice(0, newline);
9603
- buffered = buffered.slice(newline + 1);
9604
- handleLine(line);
9605
- }
9767
+ take(decoder.decode(value, { stream: true }));
9606
9768
  }
9607
- buffered += decoder.decode();
9608
- if (buffered.trim()) handleLine(buffered);
9769
+ take(decoder.decode());
9770
+ const last = pieces.join("");
9771
+ if (last.trim()) handleLine(last);
9609
9772
  } catch (err) {
9610
9773
  void reader.cancel().catch(() => {
9611
9774
  });
@@ -9615,8 +9778,7 @@ async function consumeToolStream(name, body, onProgress, signal) {
9615
9778
  if (!final) {
9616
9779
  throw brokenStream(name, "the stream ended without a result", progress);
9617
9780
  }
9618
- const { result: data } = await applyClientFileDirectives(final.data);
9619
- return { data, note: final.note };
9781
+ return { data: final.data, note: final.note };
9620
9782
  }
9621
9783
  function errorBodyMessage(body) {
9622
9784
  if (Array.isArray(body.issues) && typeof body.message === "string") return body.message;
@@ -9705,16 +9867,28 @@ function createToolsClient(options = {}) {
9705
9867
  const { url, token, remote } = await route();
9706
9868
  let finalArgs = args;
9707
9869
  const meta = await fetchTool(name, { signal: opts?.signal });
9870
+ const baselineDirs = [];
9708
9871
  if (meta?.fileInputs?.length) {
9709
9872
  if (remote) assertRequiredPresent(meta, args);
9710
9873
  finalArgs = await prepareFileInputs(meta.fileInputs, args ?? {}, {
9711
9874
  includeContent: remote,
9712
9875
  uploadEndpoint: remote ? { url, token } : void 0,
9713
9876
  log: diagnose,
9877
+ baselineDirs,
9714
9878
  collectMembers: collectFlowMembers,
9715
9879
  signal: opts?.signal
9716
9880
  });
9717
9881
  }
9882
+ const settle = async (data) => {
9883
+ const applied = await applyClientFileDirectives(data, { allowedDirs: baselineDirs });
9884
+ for (const { path: file, error } of applied.failed) {
9885
+ diagnose(`The baseline ${file} was not written on this client: ${error}`);
9886
+ }
9887
+ if (process.env.ARGENT_FLOW_FILES_LOG === "1") {
9888
+ for (const file of applied.written) diagnose(`[flow-files] baseline ${file}: written`);
9889
+ }
9890
+ return applied.result;
9891
+ };
9718
9892
  const stream = opts?.onProgress !== void 0 || carriesMembers(finalArgs);
9719
9893
  const sentOnce = carriesUpload(finalArgs);
9720
9894
  const res = await doFetch(
@@ -9746,7 +9920,11 @@ function createToolsClient(options = {}) {
9746
9920
  }),
9747
9921
  opts?.signal
9748
9922
  );
9749
- return { ...streamed, outputHint: meta?.outputHint };
9923
+ return {
9924
+ data: await settle(streamed.data),
9925
+ note: streamed.note,
9926
+ outputHint: meta?.outputHint
9927
+ };
9750
9928
  }
9751
9929
  let json;
9752
9930
  try {
@@ -9770,17 +9948,16 @@ function createToolsClient(options = {}) {
9770
9948
  });
9771
9949
  }
9772
9950
  opts?.signal?.throwIfAborted();
9773
- const { result: data } = await applyClientFileDirectives(json.data);
9774
- return { data, note: json.note, outputHint: meta?.outputHint };
9951
+ return { data: await settle(json.data), note: json.note, outputHint: meta?.outputHint };
9775
9952
  }
9776
9953
  return { fetchTools, fetchTool, callTool, baseUrl };
9777
9954
  }
9778
9955
 
9779
9956
  // ../argent-tools-client/src/artifacts.ts
9780
- import { copyFile, mkdir as mkdir4, readFile as readFile5, realpath as realpath3, rm as rm3, stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
9957
+ import { copyFile, mkdir as mkdir4, readFile as readFile5, realpath as realpath4, rm as rm3, stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
9781
9958
  import { constants as fsConstants } from "node:fs";
9782
9959
  import { tmpdir as tmpdir2 } from "node:os";
9783
- import { basename as basename6, dirname as dirname7, extname as extname2, isAbsolute as isAbsolute5, join as join11, normalize, resolve as resolve6, sep as sep4 } from "node:path";
9960
+ import { basename as basename6, dirname as dirname7, extname as extname2, isAbsolute as isAbsolute5, join as join11, normalize as normalize2, resolve as resolve6, sep as sep4 } from "node:path";
9784
9961
  import { createHash as createHash3 } from "node:crypto";
9785
9962
  var ARTIFACT_MARKER2 = "__argentArtifact";
9786
9963
  function isArtifactHandle(value) {
@@ -9815,8 +9992,8 @@ function durableBaseDir() {
9815
9992
  const projectRoot = findProjectRoot(process.cwd());
9816
9993
  return projectRoot ?? dirname7(argentHomeDir());
9817
9994
  }
9818
- var ALLOWED_SAVE_DIRS = /* @__PURE__ */ new Set([normalize(".argent/recordings")]);
9819
- var RECORDINGS_SAVE_DIR = normalize(".argent/recordings");
9995
+ var ALLOWED_SAVE_DIRS = /* @__PURE__ */ new Set([normalize2(".argent/recordings")]);
9996
+ var RECORDINGS_SAVE_DIR = normalize2(".argent/recordings");
9820
9997
  function configuredRecordingsDir() {
9821
9998
  let value;
9822
9999
  try {
@@ -9875,7 +10052,7 @@ async function writeDurableUnique(dir, filename, write) {
9875
10052
  }
9876
10053
  function durableSaveTarget(handle) {
9877
10054
  if (typeof handle.saveDir !== "string" || !handle.saveDir || handle.archive) return null;
9878
- const rel = normalize(handle.saveDir);
10055
+ const rel = normalize2(handle.saveDir);
9879
10056
  if (isAbsolute5(rel) || rel === ".." || rel.startsWith(`..${sep4}`) || rel.split(sep4).includes("..")) {
9880
10057
  return null;
9881
10058
  }
@@ -9897,8 +10074,8 @@ function durableSaveTarget(handle) {
9897
10074
  }
9898
10075
  async function confineToRealBase(dir, base, rel) {
9899
10076
  try {
9900
- const realDir = await realpath3(dir);
9901
- const realBase = await realpath3(base);
10077
+ const realDir = await realpath4(dir);
10078
+ const realBase = await realpath4(base);
9902
10079
  return realDir === join11(realBase, rel);
9903
10080
  } catch {
9904
10081
  return false;
@@ -16736,7 +16736,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
16736
16736
  var SESSION_ID = randomUUID4();
16737
16737
  function readCliVersion() {
16738
16738
  if (true) {
16739
- return "0.27.1-next.20";
16739
+ return "0.27.1-next.21";
16740
16740
  }
16741
16741
  return "0.0.0";
16742
16742
  }
@@ -23323,7 +23323,17 @@ var LINK_FILE = path20.join(LINK_DIR, "link.json");
23323
23323
  // ../argent-tools-client/src/file-inputs.ts
23324
23324
  import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
23325
23325
  import { createReadStream, rmSync as rmSync6 } from "node:fs";
23326
- import { mkdir as mkdir3, readFile as readFile3, rm as rm2, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
23326
+ import {
23327
+ chmod as chmod3,
23328
+ lstat,
23329
+ mkdir as mkdir3,
23330
+ readFile as readFile3,
23331
+ realpath as realpath2,
23332
+ rename as rename2,
23333
+ rm as rm2,
23334
+ stat as stat2,
23335
+ writeFile as writeFile3
23336
+ } from "node:fs/promises";
23327
23337
  import { constants, tmpdir } from "node:os";
23328
23338
  import * as path21 from "node:path";
23329
23339
 
@@ -23339,18 +23349,18 @@ var MAX_CONTENT_BYTES = 32 * 1024 * 1024;
23339
23349
 
23340
23350
  // ../argent-tools-client/src/flow-files.ts
23341
23351
  var import_yaml3 = __toESM(require_dist(), 1);
23342
- import { readFile as readFile4, realpath as realpath2, stat as stat3 } from "node:fs/promises";
23352
+ import { readdir as readdir4, readFile as readFile4, realpath as realpath3, stat as stat3 } from "node:fs/promises";
23343
23353
  import * as path22 from "node:path";
23344
23354
  var INLINE_MEMBERS_BYTES = 256 * 1024;
23345
23355
 
23346
23356
  // ../argent-tools-client/src/artifacts.ts
23347
- import { copyFile, mkdir as mkdir4, readFile as readFile5, realpath as realpath3, rm as rm3, stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
23357
+ import { copyFile, mkdir as mkdir4, readFile as readFile5, realpath as realpath4, rm as rm3, stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
23348
23358
  import { constants as fsConstants } from "node:fs";
23349
23359
  import { tmpdir as tmpdir2 } from "node:os";
23350
- import { basename as basename6, dirname as dirname15, extname as extname2, isAbsolute as isAbsolute7, join as join23, normalize, resolve as resolve13, sep as sep6 } from "node:path";
23360
+ import { basename as basename6, dirname as dirname15, extname as extname2, isAbsolute as isAbsolute7, join as join23, normalize as normalize2, resolve as resolve13, sep as sep6 } from "node:path";
23351
23361
  import { createHash as createHash4 } from "node:crypto";
23352
- var ALLOWED_SAVE_DIRS = /* @__PURE__ */ new Set([normalize(".argent/recordings")]);
23353
- var RECORDINGS_SAVE_DIR = normalize(".argent/recordings");
23362
+ var ALLOWED_SAVE_DIRS = /* @__PURE__ */ new Set([normalize2(".argent/recordings")]);
23363
+ var RECORDINGS_SAVE_DIR = normalize2(".argent/recordings");
23354
23364
  var MAX_DURABLE_BYTES = 2 * 1024 * 1024 * 1024;
23355
23365
 
23356
23366
  // ../argent-installer/src/update.ts