@swmansion/argent 0.15.0 → 0.15.1-next.0

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 = [
@@ -6392,6 +6600,39 @@ var ALLOWED = {
6392
6600
  uptime_ms: DURATION_MS,
6393
6601
  total_tool_calls: COUNT,
6394
6602
  ...FAILURE_SIGNAL
6603
+ },
6604
+ "lens:preview_opened": {
6605
+ round: COUNT,
6606
+ element_count: COUNT,
6607
+ variant_count: COUNT,
6608
+ is_cli_session: bool,
6609
+ platform: PLATFORM
6610
+ },
6611
+ "lens:round_completed": {
6612
+ round: COUNT,
6613
+ element_count: COUNT,
6614
+ variant_count: COUNT,
6615
+ annotation_count: COUNT,
6616
+ element_comment_count: COUNT,
6617
+ skipped_comment_count: COUNT,
6618
+ has_global_comment: bool,
6619
+ inspector_used: bool,
6620
+ offscreen_revealed: bool,
6621
+ is_cli_session: bool,
6622
+ had_parked_await: bool,
6623
+ round_duration_ms: DURATION_MS,
6624
+ platform: PLATFORM
6625
+ },
6626
+ "lens:round_abandoned": {
6627
+ round: COUNT,
6628
+ element_count: COUNT,
6629
+ variant_count: COUNT,
6630
+ had_parked_await: bool,
6631
+ is_cli_session: bool,
6632
+ platform: PLATFORM
6633
+ },
6634
+ "lens:cli_session_started": {
6635
+ agent_choice_count: COUNT
6395
6636
  }
6396
6637
  };
6397
6638
  function sanitize(event, raw) {
@@ -6408,7 +6649,7 @@ function sanitize(event, raw) {
6408
6649
  }
6409
6650
 
6410
6651
  // ../telemetry/src/base-props.ts
6411
- import { randomUUID as randomUUID3 } from "node:crypto";
6652
+ import { randomUUID as randomUUID4 } from "node:crypto";
6412
6653
 
6413
6654
  // ../telemetry/src/cloud-agent-detect.ts
6414
6655
  import { existsSync as existsSync2 } from "node:fs";
@@ -6442,9 +6683,9 @@ function isReplitAgent(env) {
6442
6683
  }
6443
6684
  var DEVIN_MARKER_PATH = "/opt/.devin";
6444
6685
  var JULES_MARKER_PATH = "/opt/environment_summary.sh";
6445
- function safeExists(fileExists, path13) {
6686
+ function safeExists(fileExists, path14) {
6446
6687
  try {
6447
- return fileExists(path13);
6688
+ return fileExists(path14);
6448
6689
  } catch {
6449
6690
  return false;
6450
6691
  }
@@ -6862,7 +7103,7 @@ function isCi(env = process.env) {
6862
7103
  var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
6863
7104
 
6864
7105
  // ../telemetry/src/base-props.ts
6865
- var SESSION_ID2 = randomUUID3();
7106
+ var SESSION_ID2 = randomUUID4();
6866
7107
  function readCliVersion() {
6867
7108
  if (true) {
6868
7109
  return "0.15.0";
@@ -6921,6 +7162,10 @@ var FLAG_REGISTRY = [
6921
7162
  {
6922
7163
  name: "artifacts-list-endpoint",
6923
7164
  description: "Expose GET /artifacts for remote artifact inventory consumers."
7165
+ },
7166
+ {
7167
+ name: "tool-server-event-log",
7168
+ description: "Write structured tool-server lifecycle events to a JSONL file."
6924
7169
  }
6925
7170
  ];
6926
7171
  function getFlagDefinition(name, registry = FLAG_REGISTRY) {
@@ -7419,12 +7664,12 @@ function resolveHostFingerprint() {
7419
7664
  }
7420
7665
  }
7421
7666
  function resolveHostFingerprintAsync() {
7422
- return new Promise((resolve4) => {
7667
+ return new Promise((resolve6) => {
7423
7668
  let binary;
7424
7669
  try {
7425
7670
  binary = simulatorServerBinaryPath();
7426
7671
  } catch {
7427
- resolve4(null);
7672
+ resolve6(null);
7428
7673
  return;
7429
7674
  }
7430
7675
  let settled = false;
@@ -7437,7 +7682,7 @@ function resolveHostFingerprintAsync() {
7437
7682
  child?.kill("SIGKILL");
7438
7683
  } catch {
7439
7684
  }
7440
- resolve4(value);
7685
+ resolve6(value);
7441
7686
  };
7442
7687
  const watchdog = setTimeout(() => finish(null), FINGERPRINT_TIMEOUT_MS);
7443
7688
  watchdog.unref?.();
@@ -7676,7 +7921,7 @@ async function shutdown(timeoutMs = SHORT_FLUSH_TIMEOUT_MS) {
7676
7921
  try {
7677
7922
  await Promise.race([
7678
7923
  client2.shutdown(timeoutMs),
7679
- new Promise((resolve4) => setTimeout(resolve4, timeoutMs + 250).unref())
7924
+ new Promise((resolve6) => setTimeout(resolve6, timeoutMs + 250).unref())
7680
7925
  ]);
7681
7926
  } catch (err) {
7682
7927
  emitDebugError("shutdown failed", err);
@@ -7696,7 +7941,7 @@ async function markDisabled() {
7696
7941
  try {
7697
7942
  await Promise.race([
7698
7943
  client2.shutdown(SHORT_FLUSH_TIMEOUT_MS),
7699
- new Promise((resolve4) => setTimeout(resolve4, SHORT_FLUSH_TIMEOUT_MS).unref())
7944
+ new Promise((resolve6) => setTimeout(resolve6, SHORT_FLUSH_TIMEOUT_MS).unref())
7700
7945
  ]);
7701
7946
  } catch {
7702
7947
  }
@@ -7938,13 +8183,13 @@ function splitOptions(argv) {
7938
8183
  return { json, outPath, argvForFlags: rest };
7939
8184
  }
7940
8185
  async function readStdin() {
7941
- return new Promise((resolve4, reject) => {
8186
+ return new Promise((resolve6, reject) => {
7942
8187
  let data = "";
7943
8188
  process.stdin.setEncoding("utf8");
7944
8189
  process.stdin.on("data", (chunk) => {
7945
8190
  data += chunk;
7946
8191
  });
7947
- process.stdin.on("end", () => resolve4(data));
8192
+ process.stdin.on("end", () => resolve6(data));
7948
8193
  process.stdin.on("error", reject);
7949
8194
  });
7950
8195
  }
@@ -8139,6 +8384,289 @@ Examples:
8139
8384
  }
8140
8385
  }
8141
8386
 
8387
+ // ../argent-cli/src/flow.ts
8388
+ import * as fsp from "node:fs/promises";
8389
+ import * as path11 from "node:path";
8390
+ var STATUS_GLYPH = {
8391
+ pass: "\u2713",
8392
+ fail: "\u2717",
8393
+ error: "\u2717",
8394
+ skip: "\xB7"
8395
+ };
8396
+ function printHelp() {
8397
+ console.log(`Usage: argent flow <subcommand> [options]
8398
+
8399
+ Run a saved flow without an LLM in the loop. Flows live in
8400
+ \`.argent/flows/<name>.yaml\` under the current working directory. A flow that
8401
+ begins with a \`launch\` step runs its app from scratch; any other flow (a
8402
+ fragment) runs against the device's current state \u2014 handy while authoring one.
8403
+
8404
+ Subcommands:
8405
+ run <name> Run a flow and report pass/fail (exit code reflects result)
8406
+ list List flows in .argent/flows
8407
+
8408
+ Options (run):
8409
+ --device <id> Device id to run against (auto-detected when omitted)
8410
+ --platform <p> ios | android | chromium | vega \u2014 narrow auto-detection
8411
+ --update-baselines Write/refresh screenshot baselines instead of diffing
8412
+ --output <dir> Also write failed snapshot images (baseline/current/diff)
8413
+ under <dir>/<flow>/ \u2014 a stable path for CI artifact upload
8414
+ --json Print the raw JSON report
8415
+ --help, -h Show this help
8416
+
8417
+ Examples:
8418
+ argent flow run checkout --platform ios
8419
+ argent flow run checkout --device <UDID> --update-baselines
8420
+ argent flow run checkout --output flow-artifacts --json
8421
+ `);
8422
+ }
8423
+ function parseRunArgs(argv) {
8424
+ const out = { updateBaselines: false, json: false };
8425
+ for (let i2 = 0; i2 < argv.length; i2++) {
8426
+ const tok = argv[i2];
8427
+ if (!tok.startsWith("-")) {
8428
+ if (!out.name) out.name = tok;
8429
+ continue;
8430
+ }
8431
+ const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
8432
+ const flag = eq === -1 ? tok : tok.slice(0, eq);
8433
+ const inline = eq === -1 ? void 0 : tok.slice(eq + 1);
8434
+ const takeValue = (name) => {
8435
+ if (inline !== void 0) {
8436
+ if (inline === "") throw new FlagParseException(`${name} requires a value`);
8437
+ return inline;
8438
+ }
8439
+ const v = argv[i2 + 1];
8440
+ if (v === void 0 || v.startsWith("-")) {
8441
+ throw new FlagParseException(`${name} requires a value`);
8442
+ }
8443
+ i2 += 1;
8444
+ return v;
8445
+ };
8446
+ const noValue = (name) => {
8447
+ if (inline !== void 0) throw new FlagParseException(`${name} does not take a value`);
8448
+ };
8449
+ if (flag === "--update-baselines") {
8450
+ noValue("--update-baselines");
8451
+ out.updateBaselines = true;
8452
+ } else if (flag === "--json") {
8453
+ noValue("--json");
8454
+ out.json = true;
8455
+ } else if (flag === "--device") out.device = takeValue("--device");
8456
+ else if (flag === "--platform") out.platform = takeValue("--platform");
8457
+ else if (flag === "--output") out.output = takeValue("--output");
8458
+ else throw new FlagParseException(`unknown flag ${tok}`);
8459
+ }
8460
+ return out;
8461
+ }
8462
+ function renderStepLine(s, n2, topFlow) {
8463
+ const where = s.flow && s.flow !== topFlow ? ` [${s.flow}]` : "";
8464
+ const what = s.tool ?? s.target;
8465
+ const label = what ? `${s.kind} ${what}` : s.kind;
8466
+ const reason = s.reason ? ` \u2014 ${s.reason}` : "";
8467
+ const glyph = s.status === "pass" && s.warning ? "\u26A0" : STATUS_GLYPH[s.status];
8468
+ return ` ${glyph} ${String(n2).padStart(2)} ${label}${where}${reason}`;
8469
+ }
8470
+ function renderSummary(report, opts = {}) {
8471
+ const warnings = report.steps.filter((s) => s.warning).length;
8472
+ const warningsNote = warnings ? `, ${warnings} warning${warnings === 1 ? "" : "s"}` : "";
8473
+ const where = opts.withDevice ? ` on ${report.device}` : "";
8474
+ return `${report.ok ? "PASS" : "FAIL"}${where} \u2014 ${report.passed} passed, ${report.failed} failed, ${report.errored} errored, ${report.skipped} skipped${warningsNote}`;
8475
+ }
8476
+ function renderArtifactLines(report) {
8477
+ const lines = [];
8478
+ let n2 = 0;
8479
+ for (const s of report.steps) {
8480
+ if (s.kind === "echo") continue;
8481
+ n2++;
8482
+ if (!s.artifacts || typeof s.artifacts !== "object") continue;
8483
+ const entries = Object.entries(s.artifacts).filter(([, v]) => typeof v === "string");
8484
+ if (entries.length === 0) continue;
8485
+ lines.push(` ${s.kind} (step ${n2}):`);
8486
+ for (const [k, v] of entries) lines.push(` ${k}: ${v}`);
8487
+ }
8488
+ return lines;
8489
+ }
8490
+ var SAFE_ARTIFACT_NAME = /^[A-Za-z0-9_-]+$/;
8491
+ async function exportFailureArtifacts(report, outputDir, ctx) {
8492
+ if (!SAFE_ARTIFACT_NAME.test(report.flow)) {
8493
+ console.error(
8494
+ `warning: skipping artifact export for unsafe flow name ${JSON.stringify(report.flow)}`
8495
+ );
8496
+ return;
8497
+ }
8498
+ for (const s of report.steps) {
8499
+ if (s.kind !== "snapshot" || s.status !== "fail" || !s.artifacts) continue;
8500
+ const key = s.snapshotKey ?? keyFromBaselinePath(s.artifacts);
8501
+ if (!key || !SAFE_ARTIFACT_NAME.test(key)) continue;
8502
+ const { result } = await materializeArtifacts(s.artifacts, ctx);
8503
+ s.artifacts = result;
8504
+ const dir = path11.join(outputDir, report.flow);
8505
+ for (const [role, value] of Object.entries(s.artifacts)) {
8506
+ if (typeof value !== "string") continue;
8507
+ const dest = path11.join(dir, `${key}-${role}.png`);
8508
+ const rel = path11.relative(outputDir, dest);
8509
+ if (rel.startsWith("..") || path11.isAbsolute(rel)) continue;
8510
+ try {
8511
+ await fsp.mkdir(dir, { recursive: true });
8512
+ await fsp.copyFile(value, dest);
8513
+ s.artifacts[role] = dest;
8514
+ } catch (err) {
8515
+ console.error(
8516
+ `warning: could not write ${dest}: ${err instanceof Error ? err.message : String(err)}`
8517
+ );
8518
+ }
8519
+ }
8520
+ }
8521
+ }
8522
+ function keyFromBaselinePath(artifacts) {
8523
+ const baseline = artifacts.baseline;
8524
+ if (typeof baseline !== "string") return null;
8525
+ return path11.basename(baseline).replace(/\.png$/, "");
8526
+ }
8527
+ function resolveArtifactDisplayPaths(report) {
8528
+ for (const s of report.steps) {
8529
+ if (!s.artifacts || typeof s.artifacts !== "object") continue;
8530
+ for (const [role, value] of Object.entries(s.artifacts)) {
8531
+ if (isArtifactHandle(value)) s.artifacts[role] = value.hostPath ?? value.filename;
8532
+ }
8533
+ }
8534
+ }
8535
+ function exitAfterFlush(code, streams = [process.stdout, process.stderr]) {
8536
+ return Promise.all(
8537
+ streams.map((s) => new Promise((resolve6) => s.write("", () => resolve6())))
8538
+ ).then(() => process.exit(code));
8539
+ }
8540
+ function renderReport(report) {
8541
+ const lines = [];
8542
+ lines.push(`Flow "${report.flow}" on ${report.device}`);
8543
+ if (report.executionPrerequisite) {
8544
+ lines.push(` assumes: ${report.executionPrerequisite}`);
8545
+ }
8546
+ let n2 = 0;
8547
+ for (const s of report.steps) {
8548
+ if (s.kind === "echo") {
8549
+ if (s.message) lines.push(` \u203A ${s.message}`);
8550
+ continue;
8551
+ }
8552
+ n2++;
8553
+ lines.push(renderStepLine(s, n2, report.flow));
8554
+ if (s.warning) lines.push(` \u26A0 ${s.warning}`);
8555
+ if (s.artifacts && typeof s.artifacts === "object") {
8556
+ for (const [k, v] of Object.entries(s.artifacts)) {
8557
+ if (typeof v === "string") lines.push(` ${k}: ${v}`);
8558
+ }
8559
+ }
8560
+ }
8561
+ lines.push(`
8562
+ ${renderSummary(report)}`);
8563
+ return lines.join("\n");
8564
+ }
8565
+ async function flow(argv, options) {
8566
+ const [sub, ...rest] = argv;
8567
+ if (!sub || sub === "--help" || sub === "-h") {
8568
+ printHelp();
8569
+ return;
8570
+ }
8571
+ const { callTool, baseUrl } = createToolsClient({ paths: options.paths });
8572
+ if (sub === "list") {
8573
+ const dir = path11.join(process.cwd(), ".argent", "flows");
8574
+ try {
8575
+ const entries = await fsp.readdir(dir);
8576
+ const names = entries.filter((f) => f.endsWith(".yaml")).map((f) => f.replace(/\.yaml$/, ""));
8577
+ if (names.length === 0) console.log("No flows found in .argent/flows");
8578
+ else console.log(names.join("\n"));
8579
+ } catch {
8580
+ console.log("No .argent/flows directory in the current working directory.");
8581
+ }
8582
+ return;
8583
+ }
8584
+ if (sub !== "run") {
8585
+ console.error(`Unknown flow subcommand "${sub}". Run \`argent flow --help\`.`);
8586
+ return exitAfterFlush(2);
8587
+ }
8588
+ if (rest.includes("--help") || rest.includes("-h")) {
8589
+ printHelp();
8590
+ return;
8591
+ }
8592
+ let args;
8593
+ try {
8594
+ args = parseRunArgs(rest);
8595
+ } catch (err) {
8596
+ if (err instanceof FlagParseException) {
8597
+ console.error(`Error: ${err.message}
8598
+ `);
8599
+ printHelp();
8600
+ return exitAfterFlush(2);
8601
+ }
8602
+ throw err;
8603
+ }
8604
+ if (!args.name) {
8605
+ console.error("argent flow run <name> requires a flow name.");
8606
+ printHelp();
8607
+ return exitAfterFlush(2);
8608
+ }
8609
+ const flowName = args.name;
8610
+ const payload = {
8611
+ name: flowName,
8612
+ project_root: process.cwd(),
8613
+ // Headless runs never block on the LLM prerequisite handshake.
8614
+ prerequisiteAcknowledged: true
8615
+ };
8616
+ if (args.device) payload.device = args.device;
8617
+ if (args.platform) payload.platform = args.platform;
8618
+ if (args.updateBaselines) payload.updateBaselines = true;
8619
+ let liveSteps = 0;
8620
+ let liveIndex = 0;
8621
+ const onStepReport = (event) => {
8622
+ const s = event;
8623
+ if (liveSteps === 0) console.log(`Flow "${flowName}"`);
8624
+ liveSteps++;
8625
+ if (s.kind === "echo") {
8626
+ if (s.message) console.log(` \u203A ${s.message}`);
8627
+ return;
8628
+ }
8629
+ liveIndex++;
8630
+ console.log(renderStepLine(s, liveIndex, flowName));
8631
+ if (s.warning) console.log(` \u26A0 ${s.warning}`);
8632
+ };
8633
+ let report;
8634
+ try {
8635
+ const resp = await callTool(
8636
+ "flow-execute",
8637
+ payload,
8638
+ args.json ? void 0 : { onProgress: onStepReport }
8639
+ );
8640
+ report = resp.data;
8641
+ } catch (err) {
8642
+ console.error(err instanceof Error ? err.message : String(err));
8643
+ return exitAfterFlush(1);
8644
+ }
8645
+ if (!report || !("steps" in report)) {
8646
+ console.error(`"${flowName}" did not produce a run report.`);
8647
+ return exitAfterFlush(2);
8648
+ }
8649
+ if (args.output) {
8650
+ const { url, token } = await baseUrl();
8651
+ await exportFailureArtifacts(report, path11.resolve(args.output), {
8652
+ toolsUrl: url,
8653
+ authToken: token
8654
+ });
8655
+ }
8656
+ resolveArtifactDisplayPaths(report);
8657
+ if (args.json) {
8658
+ console.log(JSON.stringify(report, null, 2));
8659
+ } else if (liveSteps > 0) {
8660
+ if (report.executionPrerequisite) console.log(` assumes: ${report.executionPrerequisite}`);
8661
+ for (const line of renderArtifactLines(report)) console.log(line);
8662
+ console.log(`
8663
+ ${renderSummary(report, { withDevice: true })}`);
8664
+ } else {
8665
+ console.log(renderReport(report));
8666
+ }
8667
+ return exitAfterFlush(report.ok ? 0 : 1);
8668
+ }
8669
+
8142
8670
  // ../argent-cli/src/tools.ts
8143
8671
  function summarize(description, max = 80) {
8144
8672
  if (!description) return "";
@@ -8218,11 +8746,11 @@ Options:
8218
8746
 
8219
8747
  // ../argent-cli/src/server.ts
8220
8748
  import * as fs9 from "node:fs";
8221
- import * as path11 from "node:path";
8749
+ import * as path12 from "node:path";
8222
8750
  import { homedir as homedir5, networkInterfaces } from "node:os";
8223
8751
  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");
8752
+ var STATE_DIR2 = path12.join(homedir5(), ".argent");
8753
+ var LOG_FILE2 = path12.join(STATE_DIR2, "tool-server.log");
8226
8754
  async function describeForeignServers(ownBundlePath) {
8227
8755
  const others = (await readAllToolsServerStates()).filter(
8228
8756
  ({ state: state2 }) => state2.bundlePath !== ownBundlePath && isToolsServerProcessAlive(state2.pid)
@@ -8631,7 +9159,7 @@ async function server(argv, options) {
8631
9159
  // ../argent-cli/src/lens.ts
8632
9160
  import * as fs10 from "node:fs";
8633
9161
  import * as os2 from "node:os";
8634
- import * as path12 from "node:path";
9162
+ import * as path13 from "node:path";
8635
9163
 
8636
9164
  // ../argent-cli/src/lens-terminal.ts
8637
9165
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -8872,7 +9400,7 @@ function ptyInjectBeats(text2) {
8872
9400
  ];
8873
9401
  }
8874
9402
  function sleep(ms) {
8875
- return new Promise((resolve4) => setTimeout(resolve4, ms));
9403
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
8876
9404
  }
8877
9405
  var DEFAULT_COLS = 80;
8878
9406
  var DEFAULT_ROWS = 24;
@@ -8982,10 +9510,10 @@ function parseSseBuffer(buffer) {
8982
9510
  const events = [];
8983
9511
  let rest = normalised;
8984
9512
  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);
9513
+ const sep4 = rest.indexOf("\n\n");
9514
+ if (sep4 === -1) break;
9515
+ const rawFrame = rest.slice(0, sep4);
9516
+ rest = rest.slice(sep4 + 2);
8989
9517
  let event = "message";
8990
9518
  const dataLines = [];
8991
9519
  for (const line of rawFrame.split("\n")) {
@@ -9093,7 +9621,7 @@ var SPAWN_GRACE_MS = 8e3;
9093
9621
  var DEATH_CONFIRMATIONS = 3;
9094
9622
  var SSE_RECONNECT_MS = 1e3;
9095
9623
  function sleep2(ms) {
9096
- return new Promise((resolve4) => setTimeout(resolve4, ms));
9624
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
9097
9625
  }
9098
9626
  var TRUST_PROMPT_RE = /trust this folder|do you trust|yes,? i trust|trust the files in this/i;
9099
9627
  async function dismissTrustPrompt(session) {
@@ -9269,7 +9797,7 @@ function parseArgs(argv) {
9269
9797
  }
9270
9798
  return { terminal, agent, help, forget };
9271
9799
  }
9272
- function printHelp() {
9800
+ function printHelp2() {
9273
9801
  process.stdout.write(
9274
9802
  `Usage: argent lens [--agent <id>] [--terminal iterm|terminal]
9275
9803
 
@@ -9296,7 +9824,7 @@ Options:
9296
9824
  async function lens(argv, options) {
9297
9825
  const { terminal: preferred, agent: agentId, help, forget } = parseArgs(argv);
9298
9826
  if (help) {
9299
- printHelp();
9827
+ printHelp2();
9300
9828
  return;
9301
9829
  }
9302
9830
  if (forget) {
@@ -9366,7 +9894,7 @@ async function lens(argv, options) {
9366
9894
  await endSession(baseUrl);
9367
9895
  process.exit(1);
9368
9896
  }
9369
- const seedFile = path12.join(os2.tmpdir(), `argent-lens-seed-${process.pid}-${Date.now()}.txt`);
9897
+ const seedFile = path13.join(os2.tmpdir(), `argent-lens-seed-${process.pid}-${Date.now()}.txt`);
9370
9898
  fs10.writeFileSync(seedFile, buildSeedPrompt(), "utf8");
9371
9899
  const launchCmd = agent.launch(shellQuote(process.cwd()), shellQuote(seedFile));
9372
9900
  const removeSeedFile = () => {
@@ -10476,7 +11004,7 @@ import { styleText as styleText2, stripVTControlCharacters } from "node:util";
10476
11004
  import process$1 from "node:process";
10477
11005
  var import_sisteransi2 = __toESM(require_src(), 1);
10478
11006
  import { existsSync as existsSync7, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
10479
- import { dirname as dirname6, join as join12 } from "node:path";
11007
+ import { dirname as dirname7, join as join15 } from "node:path";
10480
11008
  function isUnicodeSupported() {
10481
11009
  if (process$1.platform !== "win32") {
10482
11010
  return process$1.env.TERM !== "linux";
@@ -11445,6 +11973,7 @@ export {
11445
11973
  disable,
11446
11974
  enable,
11447
11975
  flags,
11976
+ flow,
11448
11977
  getFlagDefinition,
11449
11978
  isFlagEnabled,
11450
11979
  lens,