@swmansion/argent 0.15.0 → 0.15.1-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli-cmds.mjs CHANGED
@@ -204,7 +204,7 @@ function generateAuthToken() {
204
204
  return generateToken();
205
205
  }
206
206
  function findFreePort() {
207
- return new Promise((resolve4, reject) => {
207
+ return new Promise((resolve6, reject) => {
208
208
  const srv = net.createServer();
209
209
  srv.listen(0, "127.0.0.1", () => {
210
210
  const addr = srv.address();
@@ -215,7 +215,7 @@ function findFreePort() {
215
215
  const port = addr.port;
216
216
  srv.close((err) => {
217
217
  if (err) reject(err);
218
- else resolve4(port);
218
+ else resolve6(port);
219
219
  });
220
220
  });
221
221
  srv.on("error", reject);
@@ -316,7 +316,7 @@ function killSpawnedChild(child, pid) {
316
316
  }
317
317
  }
318
318
  function spawnToolsServer(paths, port, options = {}) {
319
- return new Promise((resolve4, reject) => {
319
+ return new Promise((resolve6, reject) => {
320
320
  let logFd;
321
321
  try {
322
322
  fs.mkdirSync(STATE_DIR, { recursive: true });
@@ -353,7 +353,7 @@ function spawnToolsServer(paths, port, options = {}) {
353
353
  rl.close();
354
354
  child.stdout?.resume();
355
355
  child.stdout?.unref?.();
356
- settle(() => resolve4({ port: actualPort, pid }));
356
+ settle(() => resolve6({ port: actualPort, pid }));
357
357
  }
358
358
  });
359
359
  child.on("error", (err) => {
@@ -729,16 +729,122 @@ function parseLinkTarget(input) {
729
729
  const host = u3.hostname.startsWith("[") ? u3.hostname.slice(1, -1) : u3.hostname;
730
730
  if (!host) throw new Error(`URL "${input}" is missing a host.`);
731
731
  const port = u3.port ? Number(u3.port) : u3.protocol === "https:" ? 443 : 80;
732
- const path13 = u3.pathname === "/" ? "" : u3.pathname.replace(/\/+$/, "");
733
- const url = `${u3.protocol}//${u3.host}${path13}`;
732
+ const path14 = u3.pathname === "/" ? "" : u3.pathname.replace(/\/+$/, "");
733
+ const url = `${u3.protocol}//${u3.host}${path14}`;
734
734
  const token = u3.username ? decodeURIComponent(u3.username) : void 0;
735
735
  return { url, host, port, ...token ? { token } : {} };
736
736
  }
737
737
 
738
738
  // ../argent-tools-client/src/file-inputs.ts
739
- import { mkdir as mkdir3, stat, writeFile as writeFile3 } from "node:fs/promises";
740
- import { readFile as readFile3 } from "node:fs/promises";
739
+ import { createHash as createHash2, randomUUID } from "node:crypto";
740
+ import { createReadStream } from "node:fs";
741
+ import { mkdir as mkdir3, readFile as readFile3, rm as rm2, stat, writeFile as writeFile3 } from "node:fs/promises";
742
+ import { tmpdir } from "node:os";
741
743
  import * as path3 from "node:path";
744
+
745
+ // ../archive/src/index.ts
746
+ import { execFile } from "node:child_process";
747
+ import { rm, readdir as readdir2 } from "node:fs/promises";
748
+ import { basename, dirname as dirname2, join as join3, posix, resolve as resolve2, sep } from "node:path";
749
+ import { promisify } from "node:util";
750
+ var execFileAsync = promisify(execFile);
751
+ var ArchiveError = class extends Error {
752
+ };
753
+ function createTarGzArgs(sourcePath, target) {
754
+ return ["-czf", target, "-C", dirname2(sourcePath), basename(sourcePath)];
755
+ }
756
+ async function createTarGzFile(sourcePath, tarPath) {
757
+ try {
758
+ await execFileAsync("tar", createTarGzArgs(sourcePath, tarPath));
759
+ } catch (err) {
760
+ await rm(tarPath, { force: true }).catch(() => {
761
+ });
762
+ throw err;
763
+ }
764
+ }
765
+ function normalizeTarMemberPath(memberPath) {
766
+ return memberPath.replace(/^\.\//, "").replace(/\\/g, "/");
767
+ }
768
+ function isSafeTarMember(memberPath, destDir) {
769
+ const normalized = normalizeTarMemberPath(memberPath);
770
+ if (!normalized || normalized === "." || normalized === "./") return false;
771
+ if (normalized.startsWith("/") || /^[A-Za-z]:[\\/]/.test(normalized)) return false;
772
+ const relative4 = posix.normalize(normalized);
773
+ if (relative4 === ".." || relative4.startsWith("../") || relative4.split("/").includes("..")) {
774
+ return false;
775
+ }
776
+ const root = resolve2(destDir);
777
+ const resolved = resolve2(destDir, relative4);
778
+ return resolved === root || resolved.startsWith(root + sep);
779
+ }
780
+ async function listTarMembers(tarPath) {
781
+ const { stdout: stdout2 } = await execFileAsync("tar", ["-tzf", tarPath]);
782
+ return stdout2.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
783
+ }
784
+ function isEscapingLinkTarget(target) {
785
+ if (target.startsWith("/") || /^[A-Za-z]:[\\/]/.test(target)) return true;
786
+ return posix.normalize(target.replace(/\\/g, "/")).split("/").includes("..");
787
+ }
788
+ async function assertSafeMemberTypes(tarPath) {
789
+ const { stdout: stdout2 } = await execFileAsync("tar", ["-tzvf", tarPath]);
790
+ for (const line of stdout2.split("\n")) {
791
+ if (!line.trim()) continue;
792
+ const type = line[0];
793
+ if (type === "-" || type === "d") continue;
794
+ if (type === "l") {
795
+ const parts = line.split(" -> ");
796
+ const target = parts.length === 2 ? parts[1].trim() : "";
797
+ if (parts.length !== 2 || !target || isEscapingLinkTarget(target)) {
798
+ throw new ArchiveError(
799
+ `Archive contains a symlink whose target could not be confirmed safe: "${line.trim()}".`
800
+ );
801
+ }
802
+ continue;
803
+ }
804
+ throw new ArchiveError(
805
+ `Archive contains an unsupported member type "${type}" (hardlink/device/\u2026) \u2014 refusing extraction.`
806
+ );
807
+ }
808
+ }
809
+ async function assertSafeArchive(tarPath, destDir) {
810
+ let members;
811
+ try {
812
+ members = await listTarMembers(tarPath);
813
+ } catch (err) {
814
+ throw new ArchiveError(
815
+ `Could not read archive: ${err instanceof Error ? err.message : String(err)}`
816
+ );
817
+ }
818
+ if (members.length === 0) {
819
+ throw new ArchiveError("Archive is empty.");
820
+ }
821
+ for (const member of members) {
822
+ if (!isSafeTarMember(member, destDir)) {
823
+ throw new ArchiveError(`Archive contains an unsafe path "${member}" \u2014 refusing extraction.`);
824
+ }
825
+ }
826
+ await assertSafeMemberTypes(tarPath);
827
+ }
828
+ async function resolveMember(destDir, expectedName) {
829
+ const entries = await readdir2(destDir);
830
+ if (entries.includes(expectedName)) {
831
+ return join3(destDir, expectedName);
832
+ }
833
+ const real = entries.filter((e) => !e.startsWith("._"));
834
+ if (real.length !== 1) {
835
+ throw new ArchiveError(
836
+ `Could not identify the extracted member (expected "${expectedName}", found ${real.length} entries).`
837
+ );
838
+ }
839
+ return join3(destDir, real[0]);
840
+ }
841
+ async function safeExtractTarGz(tarPath, destDir, expectedName) {
842
+ await assertSafeArchive(tarPath, destDir);
843
+ await execFileAsync("tar", ["-xzf", tarPath, "-C", destDir]);
844
+ return resolveMember(destDir, expectedName);
845
+ }
846
+
847
+ // ../argent-tools-client/src/file-inputs.ts
742
848
  var FILE_INPUT_MARKER = "__argentFileInput";
743
849
  var CLIENT_FILE_MARKER = "__argentClientFile";
744
850
  var MAX_CONTENT_BYTES = 32 * 1024 * 1024;
@@ -754,6 +860,34 @@ function interpolatePath(template, args) {
754
860
  });
755
861
  return missing ? null : out;
756
862
  }
863
+ async function tarball(sourcePath) {
864
+ const tarPath = path3.join(tmpdir(), `argent-upload-${randomUUID()}.tar.gz`);
865
+ await createTarGzFile(sourcePath, tarPath);
866
+ return tarPath;
867
+ }
868
+ function sha256File(filePath) {
869
+ return new Promise((resolve6, reject) => {
870
+ const hash = createHash2("sha256");
871
+ createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve6(hash.digest("hex"))).on("error", reject);
872
+ });
873
+ }
874
+ async function uploadTar(tarPath, endpoint) {
875
+ const init2 = {
876
+ method: "POST",
877
+ headers: {
878
+ "content-type": "application/gzip",
879
+ ...endpoint.token ? { Authorization: `Bearer ${endpoint.token}` } : {}
880
+ },
881
+ body: createReadStream(tarPath),
882
+ duplex: "half"
883
+ };
884
+ const res = await fetch(`${endpoint.url}/upload`, init2);
885
+ if (!res.ok) {
886
+ throw new Error(`Upload to ${endpoint.url}/upload failed: ${res.status} ${res.statusText}`);
887
+ }
888
+ const json = await res.json();
889
+ return json.uploadId;
890
+ }
757
891
  async function prepareFileInputs(specs, args, opts) {
758
892
  if (!specs || specs.length === 0 || typeof args !== "object" || args === null) {
759
893
  return args;
@@ -781,6 +915,28 @@ async function prepareFileInputs(specs, args, opts) {
781
915
  } catch {
782
916
  }
783
917
  }
918
+ if (spec.kind === "tar-upload") {
919
+ const st = await stat(filePath).catch(() => null);
920
+ if (st) {
921
+ wire.size = st.size;
922
+ wire.mtimeMs = st.mtimeMs;
923
+ }
924
+ if (opts.uploadEndpoint && st) {
925
+ let tarPath = null;
926
+ try {
927
+ process.stderr.write(
928
+ `Uploading ${path3.basename(filePath)} to the remote tool-server...
929
+ `
930
+ );
931
+ tarPath = await tarball(filePath);
932
+ wire.contentHash = await sha256File(tarPath);
933
+ wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint);
934
+ } finally {
935
+ if (tarPath) await rm2(tarPath, { force: true }).catch(() => {
936
+ });
937
+ }
938
+ }
939
+ }
784
940
  out = out ?? { ...record };
785
941
  out[spec.target] = wire;
786
942
  }
@@ -831,6 +987,43 @@ async function applyClientFileDirectives(result) {
831
987
  function authHeaders2(token) {
832
988
  return token ? { Authorization: `Bearer ${token}` } : {};
833
989
  }
990
+ async function consumeToolStream(body, onProgress) {
991
+ let final;
992
+ const handleLine = (line) => {
993
+ if (!line.trim()) return;
994
+ const msg = JSON.parse(line);
995
+ if (msg.event === "progress") onProgress(msg.data);
996
+ else if (msg.event === "result") final = { data: msg.data, note: msg.note };
997
+ else if (msg.event === "error") throw new Error(msg.error ?? "tool invocation failed");
998
+ };
999
+ const reader = body.getReader();
1000
+ const decoder = new TextDecoder();
1001
+ let buffered = "";
1002
+ try {
1003
+ for (; ; ) {
1004
+ const { done, value } = await reader.read();
1005
+ if (done) break;
1006
+ buffered += decoder.decode(value, { stream: true });
1007
+ let newline;
1008
+ while ((newline = buffered.indexOf("\n")) !== -1) {
1009
+ const line = buffered.slice(0, newline);
1010
+ buffered = buffered.slice(newline + 1);
1011
+ handleLine(line);
1012
+ }
1013
+ }
1014
+ buffered += decoder.decode();
1015
+ if (buffered.trim()) handleLine(buffered);
1016
+ } catch (err) {
1017
+ void reader.cancel().catch(() => {
1018
+ });
1019
+ throw err;
1020
+ }
1021
+ if (!final) {
1022
+ throw new Error("tool stream ended without a result \u2014 connection lost mid-run?");
1023
+ }
1024
+ const { result: data } = await applyClientFileDirectives(final.data);
1025
+ return { data, note: final.note };
1026
+ }
834
1027
  function createToolsClient(options = {}) {
835
1028
  let cached2 = null;
836
1029
  async function baseUrl() {
@@ -858,21 +1051,31 @@ function createToolsClient(options = {}) {
858
1051
  const tools2 = await fetchTools();
859
1052
  return tools2.find((t2) => t2.name === name) ?? null;
860
1053
  }
861
- async function callTool(name, args) {
1054
+ async function callTool(name, args, opts) {
862
1055
  const { url, token } = await baseUrl();
863
1056
  let finalArgs = args;
864
1057
  const meta = await fetchTool(name);
865
1058
  if (meta?.fileInputs?.length) {
866
1059
  const { url: routedUrl } = await getResolvedToolsUrl();
1060
+ const isRemote = routedUrl !== null;
867
1061
  finalArgs = await prepareFileInputs(meta.fileInputs, args ?? {}, {
868
- includeContent: routedUrl !== null
1062
+ includeContent: isRemote,
1063
+ uploadEndpoint: isRemote ? { url, token } : void 0
869
1064
  });
870
1065
  }
871
1066
  const res = await fetch(`${url}/tools/${encodeURIComponent(name)}`, {
872
1067
  method: "POST",
873
- headers: { "Content-Type": "application/json", ...authHeaders2(token) },
1068
+ headers: {
1069
+ "Content-Type": "application/json",
1070
+ ...opts?.onProgress ? { Accept: "application/x-ndjson" } : {},
1071
+ ...authHeaders2(token)
1072
+ },
874
1073
  body: JSON.stringify(finalArgs ?? {})
875
1074
  });
1075
+ const contentType = res.headers.get("content-type") ?? "";
1076
+ if (opts?.onProgress && res.ok && res.body && contentType.includes("application/x-ndjson")) {
1077
+ return consumeToolStream(res.body, opts.onProgress);
1078
+ }
876
1079
  const json = await res.json().catch(() => ({}));
877
1080
  if (!res.ok) {
878
1081
  throw new Error(json.error ?? json.message ?? `${res.status} ${res.statusText}`);
@@ -884,13 +1087,10 @@ function createToolsClient(options = {}) {
884
1087
  }
885
1088
 
886
1089
  // ../argent-tools-client/src/artifacts.ts
887
- import { mkdir as mkdir4, readFile as readFile4, rm, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
888
- import { tmpdir } from "node:os";
889
- import { basename, join as join3 } from "node:path";
890
- import { createHash as createHash2 } from "node:crypto";
891
- import { execFile } from "node:child_process";
892
- import { promisify } from "node:util";
893
- var execFileAsync = promisify(execFile);
1090
+ import { mkdir as mkdir4, readFile as readFile4, rm as rm3, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
1091
+ import { tmpdir as tmpdir2 } from "node:os";
1092
+ import { basename as basename3, join as join5 } from "node:path";
1093
+ import { createHash as createHash3 } from "node:crypto";
894
1094
  var ARTIFACT_MARKER = "__argentArtifact";
895
1095
  function isArtifactHandle(value) {
896
1096
  return !!value && typeof value === "object" && value[ARTIFACT_MARKER] === true && typeof value.id === "string" && typeof value.filename === "string";
@@ -908,17 +1108,17 @@ function sanitizeSegment(segment) {
908
1108
  }
909
1109
  function projectSlug() {
910
1110
  const cwd = process.cwd();
911
- const hash = createHash2("sha1").update(cwd).digest("hex").slice(0, 6);
912
- const name = sanitizeSegment(basename(cwd)) || "root";
1111
+ const hash = createHash3("sha1").update(cwd).digest("hex").slice(0, 6);
1112
+ const name = sanitizeSegment(basename3(cwd)) || "root";
913
1113
  return `${name}-${hash}`;
914
1114
  }
915
1115
  function artifactsRoot() {
916
- return process.env.ARGENT_ARTIFACTS_DIR ?? join3(tmpdir(), "argent-artifacts");
1116
+ return process.env.ARGENT_ARTIFACTS_DIR ?? join5(tmpdir2(), "argent-artifacts");
917
1117
  }
918
1118
  function artifactDir(deviceId) {
919
1119
  const parts = [artifactsRoot(), projectSlug(), sessionId()];
920
1120
  if (deviceId) parts.push(sanitizeSegment(deviceId));
921
- return join3(...parts);
1121
+ return join5(...parts);
922
1122
  }
923
1123
  async function resolveLocalFile(handle) {
924
1124
  if (!handle.hostPath) return null;
@@ -938,15 +1138,14 @@ async function resolveLocalFile(handle) {
938
1138
  }
939
1139
  }
940
1140
  async function downloadAndExtractArchive(handle, data, dir) {
941
- const tarball = join3(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
1141
+ const tarball2 = join5(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
942
1142
  try {
943
- await writeFile4(tarball, data);
944
- await execFileAsync("tar", ["-xzf", tarball, "-C", dir]);
945
- return join3(dir, handle.filename);
1143
+ await writeFile4(tarball2, data);
1144
+ return await safeExtractTarGz(tarball2, dir, handle.filename);
946
1145
  } catch {
947
1146
  return null;
948
1147
  } finally {
949
- await rm(tarball, { force: true }).catch(() => {
1148
+ await rm3(tarball2, { force: true }).catch(() => {
950
1149
  });
951
1150
  }
952
1151
  }
@@ -982,7 +1181,7 @@ async function materializeArtifacts(result, ctx) {
982
1181
  return await downloadAndExtractArchive(value, data, dir);
983
1182
  }
984
1183
  if (value.size > 0 && data.length !== value.size) return null;
985
- const downloadedPath = join3(dir, sanitizeSegment(value.filename));
1184
+ const downloadedPath = join5(dir, sanitizeSegment(value.filename));
986
1185
  await writeFile4(downloadedPath, data);
987
1186
  if (value.mimeType.startsWith("image/")) {
988
1187
  images.push({ localPath: downloadedPath, data, mimeType: value.mimeType });
@@ -1016,7 +1215,7 @@ function getDeviceIdFromArgs(args) {
1016
1215
  }
1017
1216
 
1018
1217
  // ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
1019
- import { dirname as dirname3, posix, sep } from "path";
1218
+ import { dirname as dirname4, posix as posix2, sep as sep2 } from "path";
1020
1219
  function createModulerModifier() {
1021
1220
  const getModuleFromFileName = createGetModuleFromFilename();
1022
1221
  return async (frames) => {
@@ -1024,12 +1223,12 @@ function createModulerModifier() {
1024
1223
  return frames;
1025
1224
  };
1026
1225
  }
1027
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname3(process.argv[1]) : process.cwd(), isWindows = "\\" === sep) {
1226
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname4(process.argv[1]) : process.cwd(), isWindows = "\\" === sep2) {
1028
1227
  const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
1029
1228
  return (filename) => {
1030
1229
  if (!filename) return;
1031
1230
  const normalizedFilename = isWindows ? normalizeWindowsPath(filename) : filename;
1032
- let { dir, base: file, ext } = posix.parse(normalizedFilename);
1231
+ let { dir, base: file, ext } = posix2.parse(normalizedFilename);
1033
1232
  if (".js" === ext || ".mjs" === ext || ".cjs" === ext) file = file.slice(0, -1 * ext.length);
1034
1233
  const decodedFile = decodeURIComponent(file);
1035
1234
  if (!dir) dir = ".";
@@ -1042,8 +1241,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname3(proce
1042
1241
  return decodedFile;
1043
1242
  };
1044
1243
  }
1045
- function normalizeWindowsPath(path13) {
1046
- return path13.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1244
+ function normalizeWindowsPath(path14) {
1245
+ return path14.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1047
1246
  }
1048
1247
 
1049
1248
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3559,7 +3758,7 @@ var PostHogCoreStateless = class {
3559
3758
  };
3560
3759
 
3561
3760
  // ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs
3562
- import { createReadStream } from "node:fs";
3761
+ import { createReadStream as createReadStream2 } from "node:fs";
3563
3762
  import { createInterface as createInterface2 } from "node:readline";
3564
3763
  var LRU_FILE_CONTENTS_CACHE = new error_tracking_exports.ReduceableCache(25);
3565
3764
  var LRU_FILE_CONTENTS_FS_READ_FAILED = new error_tracking_exports.ReduceableCache(20);
@@ -3595,15 +3794,15 @@ async function addSourceContext(frames) {
3595
3794
  LRU_FILE_CONTENTS_CACHE.reduce();
3596
3795
  return frames;
3597
3796
  }
3598
- function getContextLinesFromFile(path13, ranges, output) {
3599
- return new Promise((resolve4) => {
3600
- const stream = createReadStream(path13);
3797
+ function getContextLinesFromFile(path14, ranges, output) {
3798
+ return new Promise((resolve6) => {
3799
+ const stream = createReadStream2(path14);
3601
3800
  const lineReaded = createInterface2({
3602
3801
  input: stream
3603
3802
  });
3604
3803
  function destroyStreamAndResolve() {
3605
3804
  stream.destroy();
3606
- resolve4();
3805
+ resolve6();
3607
3806
  }
3608
3807
  let lineNumber = 0;
3609
3808
  let currentRangeIndex = 0;
@@ -3612,7 +3811,7 @@ function getContextLinesFromFile(path13, ranges, output) {
3612
3811
  let rangeStart = range[0];
3613
3812
  let rangeEnd = range[1];
3614
3813
  function onStreamError() {
3615
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path13, 1);
3814
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path14, 1);
3616
3815
  lineReaded.close();
3617
3816
  lineReaded.removeAllListeners();
3618
3817
  destroyStreamAndResolve();
@@ -3673,8 +3872,8 @@ function clearLineContext(frame) {
3673
3872
  delete frame.context_line;
3674
3873
  delete frame.post_context;
3675
3874
  }
3676
- function shouldSkipContextLinesForFile(path13) {
3677
- return path13.startsWith("node:") || path13.endsWith(".min.js") || path13.endsWith(".min.cjs") || path13.endsWith(".min.mjs") || path13.startsWith("data:");
3875
+ function shouldSkipContextLinesForFile(path14) {
3876
+ return path14.startsWith("node:") || path14.endsWith(".min.js") || path14.endsWith(".min.cjs") || path14.endsWith(".min.mjs") || path14.startsWith("data:");
3678
3877
  }
3679
3878
  function shouldSkipContextLinesForFrame(frame) {
3680
3879
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -3747,9 +3946,9 @@ function snipLine(line, colno) {
3747
3946
  }
3748
3947
 
3749
3948
  // ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs
3750
- import { isAbsolute as isAbsolute3, relative as relative2, sep as sep2 } from "path";
3949
+ import { isAbsolute as isAbsolute3, relative as relative2, sep as sep3 } from "path";
3751
3950
  function createRelativePathModifier(basePath = process.cwd()) {
3752
- const isWindows = "\\" === sep2;
3951
+ const isWindows = "\\" === sep3;
3753
3952
  const toUnix = (p) => isWindows ? p.replace(/\\/g, "/") : p;
3754
3953
  const normalizedBase = toUnix(basePath);
3755
3954
  return async (frames) => {
@@ -4900,9 +5099,9 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4900
5099
  if (!waitUntil) return;
4901
5100
  if (this.disabled || this.optedOut) return;
4902
5101
  if (!this._waitUntilCycle) {
4903
- let resolve4;
5102
+ let resolve6;
4904
5103
  const promise = new Promise((r2) => {
4905
- resolve4 = r2;
5104
+ resolve6 = r2;
4906
5105
  });
4907
5106
  try {
4908
5107
  waitUntil(promise);
@@ -4910,7 +5109,7 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4910
5109
  return;
4911
5110
  }
4912
5111
  this._waitUntilCycle = {
4913
- resolve: resolve4,
5112
+ resolve: resolve6,
4914
5113
  startedAt: Date.now(),
4915
5114
  timer: void 0
4916
5115
  };
@@ -4934,12 +5133,12 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4934
5133
  return cycle?.resolve;
4935
5134
  }
4936
5135
  async resolveWaitUntilFlush() {
4937
- const resolve4 = this._consumeWaitUntilCycle();
5136
+ const resolve6 = this._consumeWaitUntilCycle();
4938
5137
  try {
4939
5138
  await super.flush();
4940
5139
  } catch {
4941
5140
  } finally {
4942
- resolve4?.();
5141
+ resolve6?.();
4943
5142
  }
4944
5143
  }
4945
5144
  getPersistedProperty(key) {
@@ -5060,15 +5259,15 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
5060
5259
  async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
5061
5260
  if (this.isLocalEvaluationReady()) return true;
5062
5261
  if (void 0 === this.featureFlagsPoller) return false;
5063
- return new Promise((resolve4) => {
5262
+ return new Promise((resolve6) => {
5064
5263
  const timeout = setTimeout(() => {
5065
5264
  cleanup();
5066
- resolve4(false);
5265
+ resolve6(false);
5067
5266
  }, timeoutMs);
5068
5267
  const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
5069
5268
  clearTimeout(timeout);
5070
5269
  cleanup();
5071
- resolve4(count > 0);
5270
+ resolve6(count > 0);
5072
5271
  });
5073
5272
  });
5074
5273
  }
@@ -5523,14 +5722,14 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
5523
5722
  this.context?.enter(data, options);
5524
5723
  }
5525
5724
  async _shutdown(shutdownTimeoutMs) {
5526
- const resolve4 = this._consumeWaitUntilCycle();
5725
+ const resolve6 = this._consumeWaitUntilCycle();
5527
5726
  await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
5528
5727
  this.errorTracking.shutdown();
5529
5728
  try {
5530
5729
  return await super._shutdown(shutdownTimeoutMs);
5531
5730
  } finally {
5532
5731
  this.distinctIdHasSentFlagCalls = {};
5533
- resolve4?.();
5732
+ resolve6?.();
5534
5733
  }
5535
5734
  }
5536
5735
  async _requestRemoteConfigPayload(flagKey) {
@@ -5908,8 +6107,8 @@ function resetClient() {
5908
6107
 
5909
6108
  // ../registry/src/artifacts.ts
5910
6109
  import { stat as stat3 } from "node:fs/promises";
5911
- import { randomUUID } from "node:crypto";
5912
- import { basename as basename2, extname } from "node:path";
6110
+ import { randomUUID as randomUUID2 } from "node:crypto";
6111
+ import { basename as basename4, extname } from "node:path";
5913
6112
 
5914
6113
  // ../registry/src/failure-codes.ts
5915
6114
  var FAILURE_CODES = {
@@ -5933,6 +6132,7 @@ var FAILURE_CODES = {
5933
6132
  TOOL_CAPABILITY_UNSUPPORTED_OPERATION: "TOOL_CAPABILITY_UNSUPPORTED_OPERATION",
5934
6133
  TOOL_PLATFORM_NOT_IMPLEMENTED: "TOOL_PLATFORM_NOT_IMPLEMENTED",
5935
6134
  TOOL_DEPENDENCY_MISSING: "TOOL_DEPENDENCY_MISSING",
6135
+ TOOL_INPUT_INVALID: "TOOL_INPUT_INVALID",
5936
6136
  TOOLSERVER_UNHANDLED_REJECTION: "TOOLSERVER_UNHANDLED_REJECTION",
5937
6137
  TOOLSERVER_UNCAUGHT_EXCEPTION: "TOOLSERVER_UNCAUGHT_EXCEPTION",
5938
6138
  INSTALL_GLOBAL_PACKAGE_FAILED: "INSTALL_GLOBAL_PACKAGE_FAILED",
@@ -6005,6 +6205,7 @@ var FAILURE_CODES = {
6005
6205
  NATIVE_DEVTOOLS_FIND_VIEWS_ERROR: "NATIVE_DEVTOOLS_FIND_VIEWS_ERROR",
6006
6206
  NATIVE_DEVTOOLS_FACTORY_OPTIONS_MISSING: "NATIVE_DEVTOOLS_FACTORY_OPTIONS_MISSING",
6007
6207
  NATIVE_DEVTOOLS_WRONG_PLATFORM: "NATIVE_DEVTOOLS_WRONG_PLATFORM",
6208
+ NATIVE_DEVTOOLS_NOT_INJECTABLE: "NATIVE_DEVTOOLS_NOT_INJECTABLE",
6008
6209
  NATIVE_DEVTOOLS_NOT_CONNECTED: "NATIVE_DEVTOOLS_NOT_CONNECTED",
6009
6210
  NATIVE_DEVTOOLS_RPC_TIMEOUT: "NATIVE_DEVTOOLS_RPC_TIMEOUT",
6010
6211
  NATIVE_DEVTOOLS_RPC_ERROR: "NATIVE_DEVTOOLS_RPC_ERROR",
@@ -6067,6 +6268,11 @@ var FAILURE_CODES = {
6067
6268
  NATIVE_PROFILER_NO_RUNNING_APPS: "NATIVE_PROFILER_NO_RUNNING_APPS",
6068
6269
  NATIVE_PROFILER_NO_RUNNING_USER_APPS: "NATIVE_PROFILER_NO_RUNNING_USER_APPS",
6069
6270
  NATIVE_PROFILER_MULTIPLE_RUNNING_USER_APPS: "NATIVE_PROFILER_MULTIPLE_RUNNING_USER_APPS",
6271
+ NATIVE_PROFILER_MALLOC_DEGRADED_XCODE: "NATIVE_PROFILER_MALLOC_DEGRADED_XCODE",
6272
+ NATIVE_PROFILER_MALLOC_STRATEGY_OVERRIDE: "NATIVE_PROFILER_MALLOC_STRATEGY_OVERRIDE",
6273
+ NATIVE_PROFILER_APP_BUNDLE_PATH_FAILED: "NATIVE_PROFILER_APP_BUNDLE_PATH_FAILED",
6274
+ NATIVE_PROFILER_LAUNCH_APP_NOT_FOUND: "NATIVE_PROFILER_LAUNCH_APP_NOT_FOUND",
6275
+ NATIVE_PROFILER_LAUNCH_APP_AMBIGUOUS: "NATIVE_PROFILER_LAUNCH_APP_AMBIGUOUS",
6070
6276
  NATIVE_PROFILER_SESSION_ALREADY_RUNNING: "NATIVE_PROFILER_SESSION_ALREADY_RUNNING",
6071
6277
  NATIVE_PROFILER_XCTRACE_NO_PID: "NATIVE_PROFILER_XCTRACE_NO_PID",
6072
6278
  NATIVE_PROFILER_XCTRACE_PROCESS_NOT_FOUND: "NATIVE_PROFILER_XCTRACE_PROCESS_NOT_FOUND",
@@ -6089,6 +6295,8 @@ var FAILURE_CODES = {
6089
6295
  FLOW_NO_ACTIVE_RECORDING: "FLOW_NO_ACTIVE_RECORDING",
6090
6296
  FLOW_FILE_INVALID: "FLOW_FILE_INVALID",
6091
6297
  FLOW_ENTRY_UNRECOGNIZED: "FLOW_ENTRY_UNRECOGNIZED",
6298
+ FLOW_E2E_HAS_PREREQUISITE: "FLOW_E2E_HAS_PREREQUISITE",
6299
+ FLOW_DEVICE_RESOLUTION: "FLOW_DEVICE_RESOLUTION",
6092
6300
  PROFILER_QUERY_MODE_INVALID: "PROFILER_QUERY_MODE_INVALID",
6093
6301
  PROFILER_QUERY_REQUIRED_PARAM_MISSING: "PROFILER_QUERY_REQUIRED_PARAM_MISSING",
6094
6302
  PROFILER_DATA_NOT_LOADED: "PROFILER_DATA_NOT_LOADED",
@@ -6183,7 +6391,7 @@ var FAILURE_SIGNAL_NAME_SET = new Set(FAILURE_SIGNAL_NAMES);
6183
6391
  var FAILURE_SPAWN_CODE_SET = new Set(FAILURE_SPAWN_CODES);
6184
6392
 
6185
6393
  // ../registry/src/registry.ts
6186
- import { randomUUID as randomUUID2 } from "node:crypto";
6394
+ import { randomUUID as randomUUID3 } from "node:crypto";
6187
6395
 
6188
6396
  // ../telemetry/src/events.ts
6189
6397
  var PLATFORMS = [
@@ -6261,6 +6469,10 @@ var FAILURE_SPAWN_CODE = oneOf(FAILURE_SPAWN_CODES);
6261
6469
  var NETWORK_FAILURE = oneOf(NETWORK_FAILURES);
6262
6470
  var AI_CLIENT = oneOf(AI_CLIENTS);
6263
6471
  var INSTALL_MODE = oneOf(["global", "local"]);
6472
+ var ERROR_NAME = matches(/^[A-Za-z][A-Za-z0-9_]{0,63}$/, 64);
6473
+ var ERROR_SYSCALL = matches(/^E[A-Z0-9_]{1,31}$/, 32);
6474
+ var CRASH_FINGERPRINT = matches(/^[0-9a-f]{16}$/, 16);
6475
+ var CRASH_PHASE = oneOf(["startup", "serving"]);
6264
6476
  var AI_TELEMETRY = {
6265
6477
  ai_client: AI_CLIENT
6266
6478
  };
@@ -6391,7 +6603,44 @@ var ALLOWED = {
6391
6603
  reason: oneOf(["idle", "signal", "crash"]),
6392
6604
  uptime_ms: DURATION_MS,
6393
6605
  total_tool_calls: COUNT,
6394
- ...FAILURE_SIGNAL
6606
+ ...FAILURE_SIGNAL,
6607
+ error_name: ERROR_NAME,
6608
+ error_syscall: ERROR_SYSCALL,
6609
+ crash_fingerprint: CRASH_FINGERPRINT,
6610
+ crash_phase: CRASH_PHASE
6611
+ },
6612
+ "lens:preview_opened": {
6613
+ round: COUNT,
6614
+ element_count: COUNT,
6615
+ variant_count: COUNT,
6616
+ is_cli_session: bool,
6617
+ platform: PLATFORM
6618
+ },
6619
+ "lens:round_completed": {
6620
+ round: COUNT,
6621
+ element_count: COUNT,
6622
+ variant_count: COUNT,
6623
+ annotation_count: COUNT,
6624
+ element_comment_count: COUNT,
6625
+ skipped_comment_count: COUNT,
6626
+ has_global_comment: bool,
6627
+ inspector_used: bool,
6628
+ offscreen_revealed: bool,
6629
+ is_cli_session: bool,
6630
+ had_parked_await: bool,
6631
+ round_duration_ms: DURATION_MS,
6632
+ platform: PLATFORM
6633
+ },
6634
+ "lens:round_abandoned": {
6635
+ round: COUNT,
6636
+ element_count: COUNT,
6637
+ variant_count: COUNT,
6638
+ had_parked_await: bool,
6639
+ is_cli_session: bool,
6640
+ platform: PLATFORM
6641
+ },
6642
+ "lens:cli_session_started": {
6643
+ agent_choice_count: COUNT
6395
6644
  }
6396
6645
  };
6397
6646
  function sanitize(event, raw) {
@@ -6408,7 +6657,7 @@ function sanitize(event, raw) {
6408
6657
  }
6409
6658
 
6410
6659
  // ../telemetry/src/base-props.ts
6411
- import { randomUUID as randomUUID3 } from "node:crypto";
6660
+ import { randomUUID as randomUUID4 } from "node:crypto";
6412
6661
 
6413
6662
  // ../telemetry/src/cloud-agent-detect.ts
6414
6663
  import { existsSync as existsSync2 } from "node:fs";
@@ -6442,9 +6691,9 @@ function isReplitAgent(env) {
6442
6691
  }
6443
6692
  var DEVIN_MARKER_PATH = "/opt/.devin";
6444
6693
  var JULES_MARKER_PATH = "/opt/environment_summary.sh";
6445
- function safeExists(fileExists, path13) {
6694
+ function safeExists(fileExists, path14) {
6446
6695
  try {
6447
- return fileExists(path13);
6696
+ return fileExists(path14);
6448
6697
  } catch {
6449
6698
  return false;
6450
6699
  }
@@ -6862,7 +7111,7 @@ function isCi(env = process.env) {
6862
7111
  var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
6863
7112
 
6864
7113
  // ../telemetry/src/base-props.ts
6865
- var SESSION_ID2 = randomUUID3();
7114
+ var SESSION_ID2 = randomUUID4();
6866
7115
  function readCliVersion() {
6867
7116
  if (true) {
6868
7117
  return "0.15.0";
@@ -6921,6 +7170,10 @@ var FLAG_REGISTRY = [
6921
7170
  {
6922
7171
  name: "artifacts-list-endpoint",
6923
7172
  description: "Expose GET /artifacts for remote artifact inventory consumers."
7173
+ },
7174
+ {
7175
+ name: "tool-server-event-log",
7176
+ description: "Write structured tool-server lifecycle events to a JSONL file."
6924
7177
  }
6925
7178
  ];
6926
7179
  function getFlagDefinition(name, registry = FLAG_REGISTRY) {
@@ -7419,12 +7672,12 @@ function resolveHostFingerprint() {
7419
7672
  }
7420
7673
  }
7421
7674
  function resolveHostFingerprintAsync() {
7422
- return new Promise((resolve4) => {
7675
+ return new Promise((resolve6) => {
7423
7676
  let binary;
7424
7677
  try {
7425
7678
  binary = simulatorServerBinaryPath();
7426
7679
  } catch {
7427
- resolve4(null);
7680
+ resolve6(null);
7428
7681
  return;
7429
7682
  }
7430
7683
  let settled = false;
@@ -7437,7 +7690,7 @@ function resolveHostFingerprintAsync() {
7437
7690
  child?.kill("SIGKILL");
7438
7691
  } catch {
7439
7692
  }
7440
- resolve4(value);
7693
+ resolve6(value);
7441
7694
  };
7442
7695
  const watchdog = setTimeout(() => finish(null), FINGERPRINT_TIMEOUT_MS);
7443
7696
  watchdog.unref?.();
@@ -7612,6 +7865,9 @@ var FIRST_RUN_NOTICE = [
7612
7865
  `Details: ${TELEMETRY_DETAILS_URL}`
7613
7866
  ].join("\n");
7614
7867
 
7868
+ // ../telemetry/src/crash-diagnostics.ts
7869
+ import { createHash as createHash4 } from "node:crypto";
7870
+
7615
7871
  // ../telemetry/src/index.ts
7616
7872
  var SHORT_FLUSH_TIMEOUT_MS = 1500;
7617
7873
  var state = null;
@@ -7676,7 +7932,7 @@ async function shutdown(timeoutMs = SHORT_FLUSH_TIMEOUT_MS) {
7676
7932
  try {
7677
7933
  await Promise.race([
7678
7934
  client2.shutdown(timeoutMs),
7679
- new Promise((resolve4) => setTimeout(resolve4, timeoutMs + 250).unref())
7935
+ new Promise((resolve6) => setTimeout(resolve6, timeoutMs + 250).unref())
7680
7936
  ]);
7681
7937
  } catch (err) {
7682
7938
  emitDebugError("shutdown failed", err);
@@ -7696,7 +7952,7 @@ async function markDisabled() {
7696
7952
  try {
7697
7953
  await Promise.race([
7698
7954
  client2.shutdown(SHORT_FLUSH_TIMEOUT_MS),
7699
- new Promise((resolve4) => setTimeout(resolve4, SHORT_FLUSH_TIMEOUT_MS).unref())
7955
+ new Promise((resolve6) => setTimeout(resolve6, SHORT_FLUSH_TIMEOUT_MS).unref())
7700
7956
  ]);
7701
7957
  } catch {
7702
7958
  }
@@ -7938,13 +8194,13 @@ function splitOptions(argv) {
7938
8194
  return { json, outPath, argvForFlags: rest };
7939
8195
  }
7940
8196
  async function readStdin() {
7941
- return new Promise((resolve4, reject) => {
8197
+ return new Promise((resolve6, reject) => {
7942
8198
  let data = "";
7943
8199
  process.stdin.setEncoding("utf8");
7944
8200
  process.stdin.on("data", (chunk) => {
7945
8201
  data += chunk;
7946
8202
  });
7947
- process.stdin.on("end", () => resolve4(data));
8203
+ process.stdin.on("end", () => resolve6(data));
7948
8204
  process.stdin.on("error", reject);
7949
8205
  });
7950
8206
  }
@@ -8139,6 +8395,289 @@ Examples:
8139
8395
  }
8140
8396
  }
8141
8397
 
8398
+ // ../argent-cli/src/flow.ts
8399
+ import * as fsp from "node:fs/promises";
8400
+ import * as path11 from "node:path";
8401
+ var STATUS_GLYPH = {
8402
+ pass: "\u2713",
8403
+ fail: "\u2717",
8404
+ error: "\u2717",
8405
+ skip: "\xB7"
8406
+ };
8407
+ function printHelp() {
8408
+ console.log(`Usage: argent flow <subcommand> [options]
8409
+
8410
+ Run a saved flow without an LLM in the loop. Flows live in
8411
+ \`.argent/flows/<name>.yaml\` under the current working directory. A flow that
8412
+ begins with a \`launch\` step runs its app from scratch; any other flow (a
8413
+ fragment) runs against the device's current state \u2014 handy while authoring one.
8414
+
8415
+ Subcommands:
8416
+ run <name> Run a flow and report pass/fail (exit code reflects result)
8417
+ list List flows in .argent/flows
8418
+
8419
+ Options (run):
8420
+ --device <id> Device id to run against (auto-detected when omitted)
8421
+ --platform <p> ios | android | chromium | vega \u2014 narrow auto-detection
8422
+ --update-baselines Write/refresh screenshot baselines instead of diffing
8423
+ --output <dir> Also write failed snapshot images (baseline/current/diff)
8424
+ under <dir>/<flow>/ \u2014 a stable path for CI artifact upload
8425
+ --json Print the raw JSON report
8426
+ --help, -h Show this help
8427
+
8428
+ Examples:
8429
+ argent flow run checkout --platform ios
8430
+ argent flow run checkout --device <UDID> --update-baselines
8431
+ argent flow run checkout --output flow-artifacts --json
8432
+ `);
8433
+ }
8434
+ function parseRunArgs(argv) {
8435
+ const out = { updateBaselines: false, json: false };
8436
+ for (let i2 = 0; i2 < argv.length; i2++) {
8437
+ const tok = argv[i2];
8438
+ if (!tok.startsWith("-")) {
8439
+ if (!out.name) out.name = tok;
8440
+ continue;
8441
+ }
8442
+ const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
8443
+ const flag = eq === -1 ? tok : tok.slice(0, eq);
8444
+ const inline = eq === -1 ? void 0 : tok.slice(eq + 1);
8445
+ const takeValue = (name) => {
8446
+ if (inline !== void 0) {
8447
+ if (inline === "") throw new FlagParseException(`${name} requires a value`);
8448
+ return inline;
8449
+ }
8450
+ const v = argv[i2 + 1];
8451
+ if (v === void 0 || v.startsWith("-")) {
8452
+ throw new FlagParseException(`${name} requires a value`);
8453
+ }
8454
+ i2 += 1;
8455
+ return v;
8456
+ };
8457
+ const noValue = (name) => {
8458
+ if (inline !== void 0) throw new FlagParseException(`${name} does not take a value`);
8459
+ };
8460
+ if (flag === "--update-baselines") {
8461
+ noValue("--update-baselines");
8462
+ out.updateBaselines = true;
8463
+ } else if (flag === "--json") {
8464
+ noValue("--json");
8465
+ out.json = true;
8466
+ } else if (flag === "--device") out.device = takeValue("--device");
8467
+ else if (flag === "--platform") out.platform = takeValue("--platform");
8468
+ else if (flag === "--output") out.output = takeValue("--output");
8469
+ else throw new FlagParseException(`unknown flag ${tok}`);
8470
+ }
8471
+ return out;
8472
+ }
8473
+ function renderStepLine(s, n2, topFlow) {
8474
+ const where = s.flow && s.flow !== topFlow ? ` [${s.flow}]` : "";
8475
+ const what = s.tool ?? s.target;
8476
+ const label = what ? `${s.kind} ${what}` : s.kind;
8477
+ const reason = s.reason ? ` \u2014 ${s.reason}` : "";
8478
+ const glyph = s.status === "pass" && s.warning ? "\u26A0" : STATUS_GLYPH[s.status];
8479
+ return ` ${glyph} ${String(n2).padStart(2)} ${label}${where}${reason}`;
8480
+ }
8481
+ function renderSummary(report, opts = {}) {
8482
+ const warnings = report.steps.filter((s) => s.warning).length;
8483
+ const warningsNote = warnings ? `, ${warnings} warning${warnings === 1 ? "" : "s"}` : "";
8484
+ const where = opts.withDevice ? ` on ${report.device}` : "";
8485
+ return `${report.ok ? "PASS" : "FAIL"}${where} \u2014 ${report.passed} passed, ${report.failed} failed, ${report.errored} errored, ${report.skipped} skipped${warningsNote}`;
8486
+ }
8487
+ function renderArtifactLines(report) {
8488
+ const lines = [];
8489
+ let n2 = 0;
8490
+ for (const s of report.steps) {
8491
+ if (s.kind === "echo") continue;
8492
+ n2++;
8493
+ if (!s.artifacts || typeof s.artifacts !== "object") continue;
8494
+ const entries = Object.entries(s.artifacts).filter(([, v]) => typeof v === "string");
8495
+ if (entries.length === 0) continue;
8496
+ lines.push(` ${s.kind} (step ${n2}):`);
8497
+ for (const [k, v] of entries) lines.push(` ${k}: ${v}`);
8498
+ }
8499
+ return lines;
8500
+ }
8501
+ var SAFE_ARTIFACT_NAME = /^[A-Za-z0-9_-]+$/;
8502
+ async function exportFailureArtifacts(report, outputDir, ctx) {
8503
+ if (!SAFE_ARTIFACT_NAME.test(report.flow)) {
8504
+ console.error(
8505
+ `warning: skipping artifact export for unsafe flow name ${JSON.stringify(report.flow)}`
8506
+ );
8507
+ return;
8508
+ }
8509
+ for (const s of report.steps) {
8510
+ if (s.kind !== "snapshot" || s.status !== "fail" || !s.artifacts) continue;
8511
+ const key = s.snapshotKey ?? keyFromBaselinePath(s.artifacts);
8512
+ if (!key || !SAFE_ARTIFACT_NAME.test(key)) continue;
8513
+ const { result } = await materializeArtifacts(s.artifacts, ctx);
8514
+ s.artifacts = result;
8515
+ const dir = path11.join(outputDir, report.flow);
8516
+ for (const [role, value] of Object.entries(s.artifacts)) {
8517
+ if (typeof value !== "string") continue;
8518
+ const dest = path11.join(dir, `${key}-${role}.png`);
8519
+ const rel = path11.relative(outputDir, dest);
8520
+ if (rel.startsWith("..") || path11.isAbsolute(rel)) continue;
8521
+ try {
8522
+ await fsp.mkdir(dir, { recursive: true });
8523
+ await fsp.copyFile(value, dest);
8524
+ s.artifacts[role] = dest;
8525
+ } catch (err) {
8526
+ console.error(
8527
+ `warning: could not write ${dest}: ${err instanceof Error ? err.message : String(err)}`
8528
+ );
8529
+ }
8530
+ }
8531
+ }
8532
+ }
8533
+ function keyFromBaselinePath(artifacts) {
8534
+ const baseline = artifacts.baseline;
8535
+ if (typeof baseline !== "string") return null;
8536
+ return path11.basename(baseline).replace(/\.png$/, "");
8537
+ }
8538
+ function resolveArtifactDisplayPaths(report) {
8539
+ for (const s of report.steps) {
8540
+ if (!s.artifacts || typeof s.artifacts !== "object") continue;
8541
+ for (const [role, value] of Object.entries(s.artifacts)) {
8542
+ if (isArtifactHandle(value)) s.artifacts[role] = value.hostPath ?? value.filename;
8543
+ }
8544
+ }
8545
+ }
8546
+ function exitAfterFlush(code, streams = [process.stdout, process.stderr]) {
8547
+ return Promise.all(
8548
+ streams.map((s) => new Promise((resolve6) => s.write("", () => resolve6())))
8549
+ ).then(() => process.exit(code));
8550
+ }
8551
+ function renderReport(report) {
8552
+ const lines = [];
8553
+ lines.push(`Flow "${report.flow}" on ${report.device}`);
8554
+ if (report.executionPrerequisite) {
8555
+ lines.push(` assumes: ${report.executionPrerequisite}`);
8556
+ }
8557
+ let n2 = 0;
8558
+ for (const s of report.steps) {
8559
+ if (s.kind === "echo") {
8560
+ if (s.message) lines.push(` \u203A ${s.message}`);
8561
+ continue;
8562
+ }
8563
+ n2++;
8564
+ lines.push(renderStepLine(s, n2, report.flow));
8565
+ if (s.warning) lines.push(` \u26A0 ${s.warning}`);
8566
+ if (s.artifacts && typeof s.artifacts === "object") {
8567
+ for (const [k, v] of Object.entries(s.artifacts)) {
8568
+ if (typeof v === "string") lines.push(` ${k}: ${v}`);
8569
+ }
8570
+ }
8571
+ }
8572
+ lines.push(`
8573
+ ${renderSummary(report)}`);
8574
+ return lines.join("\n");
8575
+ }
8576
+ async function flow(argv, options) {
8577
+ const [sub, ...rest] = argv;
8578
+ if (!sub || sub === "--help" || sub === "-h") {
8579
+ printHelp();
8580
+ return;
8581
+ }
8582
+ const { callTool, baseUrl } = createToolsClient({ paths: options.paths });
8583
+ if (sub === "list") {
8584
+ const dir = path11.join(process.cwd(), ".argent", "flows");
8585
+ try {
8586
+ const entries = await fsp.readdir(dir);
8587
+ const names = entries.filter((f) => f.endsWith(".yaml")).map((f) => f.replace(/\.yaml$/, ""));
8588
+ if (names.length === 0) console.log("No flows found in .argent/flows");
8589
+ else console.log(names.join("\n"));
8590
+ } catch {
8591
+ console.log("No .argent/flows directory in the current working directory.");
8592
+ }
8593
+ return;
8594
+ }
8595
+ if (sub !== "run") {
8596
+ console.error(`Unknown flow subcommand "${sub}". Run \`argent flow --help\`.`);
8597
+ return exitAfterFlush(2);
8598
+ }
8599
+ if (rest.includes("--help") || rest.includes("-h")) {
8600
+ printHelp();
8601
+ return;
8602
+ }
8603
+ let args;
8604
+ try {
8605
+ args = parseRunArgs(rest);
8606
+ } catch (err) {
8607
+ if (err instanceof FlagParseException) {
8608
+ console.error(`Error: ${err.message}
8609
+ `);
8610
+ printHelp();
8611
+ return exitAfterFlush(2);
8612
+ }
8613
+ throw err;
8614
+ }
8615
+ if (!args.name) {
8616
+ console.error("argent flow run <name> requires a flow name.");
8617
+ printHelp();
8618
+ return exitAfterFlush(2);
8619
+ }
8620
+ const flowName = args.name;
8621
+ const payload = {
8622
+ name: flowName,
8623
+ project_root: process.cwd(),
8624
+ // Headless runs never block on the LLM prerequisite handshake.
8625
+ prerequisiteAcknowledged: true
8626
+ };
8627
+ if (args.device) payload.device = args.device;
8628
+ if (args.platform) payload.platform = args.platform;
8629
+ if (args.updateBaselines) payload.updateBaselines = true;
8630
+ let liveSteps = 0;
8631
+ let liveIndex = 0;
8632
+ const onStepReport = (event) => {
8633
+ const s = event;
8634
+ if (liveSteps === 0) console.log(`Flow "${flowName}"`);
8635
+ liveSteps++;
8636
+ if (s.kind === "echo") {
8637
+ if (s.message) console.log(` \u203A ${s.message}`);
8638
+ return;
8639
+ }
8640
+ liveIndex++;
8641
+ console.log(renderStepLine(s, liveIndex, flowName));
8642
+ if (s.warning) console.log(` \u26A0 ${s.warning}`);
8643
+ };
8644
+ let report;
8645
+ try {
8646
+ const resp = await callTool(
8647
+ "flow-execute",
8648
+ payload,
8649
+ args.json ? void 0 : { onProgress: onStepReport }
8650
+ );
8651
+ report = resp.data;
8652
+ } catch (err) {
8653
+ console.error(err instanceof Error ? err.message : String(err));
8654
+ return exitAfterFlush(1);
8655
+ }
8656
+ if (!report || !("steps" in report)) {
8657
+ console.error(`"${flowName}" did not produce a run report.`);
8658
+ return exitAfterFlush(2);
8659
+ }
8660
+ if (args.output) {
8661
+ const { url, token } = await baseUrl();
8662
+ await exportFailureArtifacts(report, path11.resolve(args.output), {
8663
+ toolsUrl: url,
8664
+ authToken: token
8665
+ });
8666
+ }
8667
+ resolveArtifactDisplayPaths(report);
8668
+ if (args.json) {
8669
+ console.log(JSON.stringify(report, null, 2));
8670
+ } else if (liveSteps > 0) {
8671
+ if (report.executionPrerequisite) console.log(` assumes: ${report.executionPrerequisite}`);
8672
+ for (const line of renderArtifactLines(report)) console.log(line);
8673
+ console.log(`
8674
+ ${renderSummary(report, { withDevice: true })}`);
8675
+ } else {
8676
+ console.log(renderReport(report));
8677
+ }
8678
+ return exitAfterFlush(report.ok ? 0 : 1);
8679
+ }
8680
+
8142
8681
  // ../argent-cli/src/tools.ts
8143
8682
  function summarize(description, max = 80) {
8144
8683
  if (!description) return "";
@@ -8218,11 +8757,11 @@ Options:
8218
8757
 
8219
8758
  // ../argent-cli/src/server.ts
8220
8759
  import * as fs9 from "node:fs";
8221
- import * as path11 from "node:path";
8760
+ import * as path12 from "node:path";
8222
8761
  import { homedir as homedir5, networkInterfaces } from "node:os";
8223
8762
  import { spawn as spawn3 } from "node:child_process";
8224
- var STATE_DIR2 = path11.join(homedir5(), ".argent");
8225
- var LOG_FILE2 = path11.join(STATE_DIR2, "tool-server.log");
8763
+ var STATE_DIR2 = path12.join(homedir5(), ".argent");
8764
+ var LOG_FILE2 = path12.join(STATE_DIR2, "tool-server.log");
8226
8765
  async function describeForeignServers(ownBundlePath) {
8227
8766
  const others = (await readAllToolsServerStates()).filter(
8228
8767
  ({ state: state2 }) => state2.bundlePath !== ownBundlePath && isToolsServerProcessAlive(state2.pid)
@@ -8631,7 +9170,7 @@ async function server(argv, options) {
8631
9170
  // ../argent-cli/src/lens.ts
8632
9171
  import * as fs10 from "node:fs";
8633
9172
  import * as os2 from "node:os";
8634
- import * as path12 from "node:path";
9173
+ import * as path13 from "node:path";
8635
9174
 
8636
9175
  // ../argent-cli/src/lens-terminal.ts
8637
9176
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -8872,7 +9411,7 @@ function ptyInjectBeats(text2) {
8872
9411
  ];
8873
9412
  }
8874
9413
  function sleep(ms) {
8875
- return new Promise((resolve4) => setTimeout(resolve4, ms));
9414
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
8876
9415
  }
8877
9416
  var DEFAULT_COLS = 80;
8878
9417
  var DEFAULT_ROWS = 24;
@@ -8982,10 +9521,10 @@ function parseSseBuffer(buffer) {
8982
9521
  const events = [];
8983
9522
  let rest = normalised;
8984
9523
  for (; ; ) {
8985
- const sep3 = rest.indexOf("\n\n");
8986
- if (sep3 === -1) break;
8987
- const rawFrame = rest.slice(0, sep3);
8988
- rest = rest.slice(sep3 + 2);
9524
+ const sep4 = rest.indexOf("\n\n");
9525
+ if (sep4 === -1) break;
9526
+ const rawFrame = rest.slice(0, sep4);
9527
+ rest = rest.slice(sep4 + 2);
8989
9528
  let event = "message";
8990
9529
  const dataLines = [];
8991
9530
  for (const line of rawFrame.split("\n")) {
@@ -9093,7 +9632,7 @@ var SPAWN_GRACE_MS = 8e3;
9093
9632
  var DEATH_CONFIRMATIONS = 3;
9094
9633
  var SSE_RECONNECT_MS = 1e3;
9095
9634
  function sleep2(ms) {
9096
- return new Promise((resolve4) => setTimeout(resolve4, ms));
9635
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
9097
9636
  }
9098
9637
  var TRUST_PROMPT_RE = /trust this folder|do you trust|yes,? i trust|trust the files in this/i;
9099
9638
  async function dismissTrustPrompt(session) {
@@ -9269,7 +9808,7 @@ function parseArgs(argv) {
9269
9808
  }
9270
9809
  return { terminal, agent, help, forget };
9271
9810
  }
9272
- function printHelp() {
9811
+ function printHelp2() {
9273
9812
  process.stdout.write(
9274
9813
  `Usage: argent lens [--agent <id>] [--terminal iterm|terminal]
9275
9814
 
@@ -9296,7 +9835,7 @@ Options:
9296
9835
  async function lens(argv, options) {
9297
9836
  const { terminal: preferred, agent: agentId, help, forget } = parseArgs(argv);
9298
9837
  if (help) {
9299
- printHelp();
9838
+ printHelp2();
9300
9839
  return;
9301
9840
  }
9302
9841
  if (forget) {
@@ -9366,7 +9905,7 @@ async function lens(argv, options) {
9366
9905
  await endSession(baseUrl);
9367
9906
  process.exit(1);
9368
9907
  }
9369
- const seedFile = path12.join(os2.tmpdir(), `argent-lens-seed-${process.pid}-${Date.now()}.txt`);
9908
+ const seedFile = path13.join(os2.tmpdir(), `argent-lens-seed-${process.pid}-${Date.now()}.txt`);
9370
9909
  fs10.writeFileSync(seedFile, buildSeedPrompt(), "utf8");
9371
9910
  const launchCmd = agent.launch(shellQuote(process.cwd()), shellQuote(seedFile));
9372
9911
  const removeSeedFile = () => {
@@ -10476,7 +11015,7 @@ import { styleText as styleText2, stripVTControlCharacters } from "node:util";
10476
11015
  import process$1 from "node:process";
10477
11016
  var import_sisteransi2 = __toESM(require_src(), 1);
10478
11017
  import { existsSync as existsSync7, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
10479
- import { dirname as dirname6, join as join12 } from "node:path";
11018
+ import { dirname as dirname7, join as join15 } from "node:path";
10480
11019
  function isUnicodeSupported() {
10481
11020
  if (process$1.platform !== "win32") {
10482
11021
  return process$1.env.TERM !== "linux";
@@ -11445,6 +11984,7 @@ export {
11445
11984
  disable,
11446
11985
  enable,
11447
11986
  flags,
11987
+ flow,
11448
11988
  getFlagDefinition,
11449
11989
  isFlagEnabled,
11450
11990
  lens,