@swmansion/argent 0.27.1-next.18 → 0.27.1-next.19

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
@@ -2026,228 +2026,10 @@ async function ensureToolsServer(paths) {
2026
2026
  }
2027
2027
  }
2028
2028
 
2029
- // ../argent-tools-client/src/link-config.ts
2030
- import * as path2 from "node:path";
2031
- import { homedir as homedir2 } from "node:os";
2032
- import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile2, unlink as unlink2, chmod as chmod2 } from "node:fs/promises";
2033
- var LINK_DIR = path2.join(homedir2(), ".argent");
2034
- var LINK_FILE = path2.join(LINK_DIR, "link.json");
2035
- async function readLinkConfig() {
2036
- try {
2037
- const raw = await readFile2(LINK_FILE, "utf8");
2038
- const parsed = JSON.parse(raw);
2039
- if (!parsed || typeof parsed.url !== "string" || typeof parsed.host !== "string" || typeof parsed.port !== "number" || typeof parsed.createdAt !== "string") {
2040
- return null;
2041
- }
2042
- return {
2043
- url: parsed.url,
2044
- host: parsed.host,
2045
- port: parsed.port,
2046
- createdAt: parsed.createdAt,
2047
- ...typeof parsed.token === "string" ? { token: parsed.token } : {}
2048
- };
2049
- } catch {
2050
- return null;
2051
- }
2052
- }
2053
- async function writeLinkConfig(cfg) {
2054
- await mkdir2(LINK_DIR, { recursive: true });
2055
- await writeFile2(LINK_FILE, JSON.stringify(cfg, null, 2) + "\n", {
2056
- encoding: "utf8",
2057
- mode: 384
2058
- });
2059
- await chmod2(LINK_FILE, 384);
2060
- }
2061
- async function clearLinkConfig() {
2062
- try {
2063
- await unlink2(LINK_FILE);
2064
- } catch {
2065
- }
2066
- }
2067
- async function getResolvedToolsUrl() {
2068
- const envUrl = process.env.ARGENT_TOOLS_URL;
2069
- if (envUrl) {
2070
- const link3 = await readLinkConfig();
2071
- const envToken = process.env[AUTH_TOKEN_ENV];
2072
- return {
2073
- url: envUrl,
2074
- source: "env",
2075
- ...envToken ? { token: envToken } : {},
2076
- ...link3 ? { shadowedLink: link3 } : {}
2077
- };
2078
- }
2079
- const link2 = await readLinkConfig();
2080
- if (link2) {
2081
- return { url: link2.url, source: "link", ...link2.token ? { token: link2.token } : {} };
2082
- }
2083
- return { url: null, source: "none" };
2084
- }
2085
- var LINK_URL_SCHEME = "argent:";
2086
- function formatLinkUrl(parts) {
2087
- const h2 = parts.host.includes(":") && !parts.host.startsWith("[") ? `[${parts.host}]` : parts.host;
2088
- const auth = parts.token ? `${encodeURIComponent(parts.token)}@` : "";
2089
- return `${LINK_URL_SCHEME}//${auth}${h2}:${parts.port}`;
2090
- }
2091
- function parseLinkUrl(input) {
2092
- if (!input.startsWith(`${LINK_URL_SCHEME}//`)) return null;
2093
- let u3;
2094
- try {
2095
- u3 = new URL(input);
2096
- } catch {
2097
- throw new Error(
2098
- `Invalid connection string "${input}" \u2014 expected argent://[<token>@]<host>:<port>`
2099
- );
2100
- }
2101
- const host = u3.hostname.startsWith("[") ? u3.hostname.slice(1, -1) : u3.hostname;
2102
- if (!host) throw new Error(`Connection string "${input}" is missing a host.`);
2103
- if (!u3.port) throw new Error(`Connection string "${input}" is missing a port.`);
2104
- const port = Number(u3.port);
2105
- const token = u3.username ? decodeURIComponent(u3.username) : void 0;
2106
- return { host, port, ...token ? { token } : {} };
2107
- }
2108
- function httpFromHostPort(host, port) {
2109
- const h2 = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
2110
- return `http://${h2}:${port}`;
2111
- }
2112
- function parseLinkTarget(input) {
2113
- const argent = parseLinkUrl(input);
2114
- if (argent) {
2115
- return {
2116
- url: httpFromHostPort(argent.host, argent.port),
2117
- host: argent.host,
2118
- port: argent.port,
2119
- ...argent.token ? { token: argent.token } : {}
2120
- };
2121
- }
2122
- if (!/^https?:\/\//i.test(input)) return null;
2123
- let u3;
2124
- try {
2125
- u3 = new URL(input);
2126
- } catch {
2127
- throw new Error(`Invalid URL "${input}" \u2014 expected http(s)://<host>[:<port>][/path].`);
2128
- }
2129
- const host = u3.hostname.startsWith("[") ? u3.hostname.slice(1, -1) : u3.hostname;
2130
- if (!host) throw new Error(`URL "${input}" is missing a host.`);
2131
- const port = u3.port ? Number(u3.port) : u3.protocol === "https:" ? 443 : 80;
2132
- const path21 = u3.pathname === "/" ? "" : u3.pathname.replace(/\/+$/, "");
2133
- const url2 = `${u3.protocol}//${u3.host}${path21}`;
2134
- const token = u3.username ? decodeURIComponent(u3.username) : void 0;
2135
- return { url: url2, host, port, ...token ? { token } : {} };
2136
- }
2137
-
2138
- // ../argent-tools-client/src/file-inputs.ts
2139
- import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
2140
- import { createReadStream } from "node:fs";
2141
- import { mkdir as mkdir3, readFile as readFile3, rm as rm2, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
2142
- import { tmpdir } from "node:os";
2143
- import * as path3 from "node:path";
2144
-
2145
- // ../archive/src/index.ts
2146
- import { execFile } from "node:child_process";
2147
- import { rm, readdir as readdir2 } from "node:fs/promises";
2148
- import { basename, dirname as dirname2, join as join3, posix, resolve as resolve2, sep } from "node:path";
2149
- import { promisify } from "node:util";
2150
- var execFileAsync = promisify(execFile);
2151
- var ArchiveError = class extends Error {
2152
- };
2153
- function createTarGzArgs(sourcePath, target) {
2154
- return ["-czf", target, "-C", dirname2(sourcePath), basename(sourcePath)];
2155
- }
2156
- async function createTarGzFile(sourcePath, tarPath) {
2157
- try {
2158
- await execFileAsync("tar", createTarGzArgs(sourcePath, tarPath));
2159
- } catch (err) {
2160
- await rm(tarPath, { force: true }).catch(() => {
2161
- });
2162
- throw err;
2163
- }
2164
- }
2165
- function normalizeTarMemberPath(memberPath) {
2166
- return memberPath.replace(/^\.\//, "").replace(/\\/g, "/");
2167
- }
2168
- function isSafeTarMember(memberPath, destDir) {
2169
- const normalized = normalizeTarMemberPath(memberPath);
2170
- if (!normalized || normalized === "." || normalized === "./") return false;
2171
- if (normalized.startsWith("/") || /^[A-Za-z]:[\\/]/.test(normalized)) return false;
2172
- const relative3 = posix.normalize(normalized);
2173
- if (relative3 === ".." || relative3.startsWith("../") || relative3.split("/").includes("..")) {
2174
- return false;
2175
- }
2176
- const root = resolve2(destDir);
2177
- const resolved = resolve2(destDir, relative3);
2178
- return resolved === root || resolved.startsWith(root + sep);
2179
- }
2180
- async function listTarMembers(tarPath) {
2181
- const { stdout: stdout2 } = await execFileAsync("tar", ["-tzf", tarPath]);
2182
- return stdout2.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
2183
- }
2184
- function isEscapingLinkTarget(target) {
2185
- if (target.startsWith("/") || /^[A-Za-z]:[\\/]/.test(target)) return true;
2186
- return posix.normalize(target.replace(/\\/g, "/")).split("/").includes("..");
2187
- }
2188
- async function assertSafeMemberTypes(tarPath) {
2189
- const { stdout: stdout2 } = await execFileAsync("tar", ["-tzvf", tarPath]);
2190
- for (const line of stdout2.split("\n")) {
2191
- if (!line.trim()) continue;
2192
- const type = line[0];
2193
- if (type === "-" || type === "d") continue;
2194
- if (type === "l") {
2195
- const parts = line.split(" -> ");
2196
- const target = parts.length === 2 ? parts[1].trim() : "";
2197
- if (parts.length !== 2 || !target || isEscapingLinkTarget(target)) {
2198
- throw new ArchiveError(
2199
- `Archive contains a symlink whose target could not be confirmed safe: "${line.trim()}".`
2200
- );
2201
- }
2202
- continue;
2203
- }
2204
- throw new ArchiveError(
2205
- `Archive contains an unsupported member type "${type}" (hardlink/device/\u2026) \u2014 refusing extraction.`
2206
- );
2207
- }
2208
- }
2209
- async function assertSafeArchive(tarPath, destDir) {
2210
- let members;
2211
- try {
2212
- members = await listTarMembers(tarPath);
2213
- } catch (err) {
2214
- throw new ArchiveError(
2215
- `Could not read archive: ${err instanceof Error ? err.message : String(err)}`
2216
- );
2217
- }
2218
- if (members.length === 0) {
2219
- throw new ArchiveError("Archive is empty.");
2220
- }
2221
- for (const member of members) {
2222
- if (!isSafeTarMember(member, destDir)) {
2223
- throw new ArchiveError(`Archive contains an unsafe path "${member}" \u2014 refusing extraction.`);
2224
- }
2225
- }
2226
- await assertSafeMemberTypes(tarPath);
2227
- }
2228
- async function resolveMember(destDir, expectedName) {
2229
- const entries = await readdir2(destDir);
2230
- if (entries.includes(expectedName)) {
2231
- return join3(destDir, expectedName);
2232
- }
2233
- const real = entries.filter((e) => !e.startsWith("._"));
2234
- if (real.length !== 1) {
2235
- throw new ArchiveError(
2236
- `Could not identify the extracted member (expected "${expectedName}", found ${real.length} entries).`
2237
- );
2238
- }
2239
- return join3(destDir, real[0]);
2240
- }
2241
- async function safeExtractTarGz(tarPath, destDir, expectedName) {
2242
- await assertSafeArchive(tarPath, destDir);
2243
- await execFileAsync("tar", ["-xzf", tarPath, "-C", destDir]);
2244
- return resolveMember(destDir, expectedName);
2245
- }
2246
-
2247
2029
  // ../registry/src/artifacts.ts
2248
2030
  import { stat } from "node:fs/promises";
2249
2031
  import { randomUUID } from "node:crypto";
2250
- import { basename as basename2, extname } from "node:path";
2032
+ import { basename, extname } from "node:path";
2251
2033
 
2252
2034
  // ../registry/src/file-inputs.ts
2253
2035
  var FLOW_NAME_CHARSET = "[A-Za-z0-9_-]+";
@@ -17125,6 +16907,282 @@ config(en_default());
17125
16907
  import { randomUUID as randomUUID2 } from "node:crypto";
17126
16908
  import { AsyncLocalStorage } from "node:async_hooks";
17127
16909
  var resolvedDuringInvocation = new AsyncLocalStorage();
16910
+ function valueAtPath(root, path21) {
16911
+ let current = root;
16912
+ for (const key of path21) {
16913
+ if (current === null || typeof current !== "object") return void 0;
16914
+ if (!Object.hasOwn(current, key)) return void 0;
16915
+ current = current[key];
16916
+ }
16917
+ return current;
16918
+ }
16919
+ var MAX_UNION_ALTERNATIVES = 12;
16920
+ function describeParamIssues(error52, params) {
16921
+ const allKeys = params !== null && typeof params === "object" && !Array.isArray(params) ? Object.keys(params) : [];
16922
+ const supplied = allKeys.slice(0, 24);
16923
+ const truncated = allKeys.length > supplied.length;
16924
+ const parts = error52.issues.map((issue2) => {
16925
+ const at = issue2.path.length > 0 ? issue2.path.join(".") : "(root)";
16926
+ if (issue2.code === "custom") {
16927
+ return issue2.path.length > 0 ? `\`${at}\`: ${issue2.message}` : issue2.message;
16928
+ }
16929
+ if (valueAtPath(params, issue2.path) === void 0) {
16930
+ const expected = issue2.expected;
16931
+ const kind = typeof expected === "string" ? ` (${expected})` : "";
16932
+ return `\`${at}\` is required${kind} and was not provided`;
16933
+ }
16934
+ if (issue2.code === "unrecognized_keys") {
16935
+ const keys = issue2.keys ?? [];
16936
+ const at2 = issue2.path.length > 0 ? `${issue2.path.join(".")}.` : "";
16937
+ return `unknown parameter${keys.length === 1 ? "" : "s"} ${keys.map((k) => `\`${at2}${k}\``).join(", ")}`;
16938
+ }
16939
+ if (issue2.code === "invalid_union") {
16940
+ const branches = issue2.errors ?? [];
16941
+ const alternatives = [];
16942
+ const seen = /* @__PURE__ */ new Set();
16943
+ let moreAlternatives = false;
16944
+ for (const branch of branches) {
16945
+ for (const inner of branch) {
16946
+ const innerAt = inner.path.length > 0 ? `${at}.${inner.path.join(".")}: ` : "";
16947
+ const text2 = `${innerAt}${inner.message}`;
16948
+ if (seen.has(text2)) continue;
16949
+ if (alternatives.length >= MAX_UNION_ALTERNATIVES) {
16950
+ moreAlternatives = true;
16951
+ break;
16952
+ }
16953
+ seen.add(text2);
16954
+ alternatives.push(text2);
16955
+ }
16956
+ if (moreAlternatives) break;
16957
+ }
16958
+ if (alternatives.length > 0) {
16959
+ return `\`${at}\`: ${alternatives.join("; or ")}${moreAlternatives ? "; or \u2026" : ""}`;
16960
+ }
16961
+ }
16962
+ return `\`${at}\`: ${issue2.message}`;
16963
+ });
16964
+ const sent = supplied.length > 0 ? ` You sent: ${supplied.map((k) => `\`${k}\``).join(", ")}${truncated ? ", \u2026" : ""}.` : "";
16965
+ const body = parts.length > 0 ? `${parts.map((p) => p.replace(/\.$/, "")).join("; ")}.` : "";
16966
+ return `${body}${sent}`.trim() || "invalid parameters";
16967
+ }
16968
+
16969
+ // ../argent-tools-client/src/link-config.ts
16970
+ import * as path2 from "node:path";
16971
+ import { homedir as homedir2 } from "node:os";
16972
+ import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile2, unlink as unlink2, chmod as chmod2 } from "node:fs/promises";
16973
+ var LINK_DIR = path2.join(homedir2(), ".argent");
16974
+ var LINK_FILE = path2.join(LINK_DIR, "link.json");
16975
+ async function readLinkConfig() {
16976
+ try {
16977
+ const raw = await readFile2(LINK_FILE, "utf8");
16978
+ const parsed = JSON.parse(raw);
16979
+ if (!parsed || typeof parsed.url !== "string" || typeof parsed.host !== "string" || typeof parsed.port !== "number" || typeof parsed.createdAt !== "string") {
16980
+ return null;
16981
+ }
16982
+ return {
16983
+ url: parsed.url,
16984
+ host: parsed.host,
16985
+ port: parsed.port,
16986
+ createdAt: parsed.createdAt,
16987
+ ...typeof parsed.token === "string" ? { token: parsed.token } : {}
16988
+ };
16989
+ } catch {
16990
+ return null;
16991
+ }
16992
+ }
16993
+ async function writeLinkConfig(cfg) {
16994
+ await mkdir2(LINK_DIR, { recursive: true });
16995
+ await writeFile2(LINK_FILE, JSON.stringify(cfg, null, 2) + "\n", {
16996
+ encoding: "utf8",
16997
+ mode: 384
16998
+ });
16999
+ await chmod2(LINK_FILE, 384);
17000
+ }
17001
+ async function clearLinkConfig() {
17002
+ try {
17003
+ await unlink2(LINK_FILE);
17004
+ } catch {
17005
+ }
17006
+ }
17007
+ async function getResolvedToolsUrl() {
17008
+ const envUrl = process.env.ARGENT_TOOLS_URL;
17009
+ if (envUrl) {
17010
+ const link3 = await readLinkConfig();
17011
+ const envToken = process.env[AUTH_TOKEN_ENV];
17012
+ return {
17013
+ url: envUrl,
17014
+ source: "env",
17015
+ ...envToken ? { token: envToken } : {},
17016
+ ...link3 ? { shadowedLink: link3 } : {}
17017
+ };
17018
+ }
17019
+ const link2 = await readLinkConfig();
17020
+ if (link2) {
17021
+ return { url: link2.url, source: "link", ...link2.token ? { token: link2.token } : {} };
17022
+ }
17023
+ return { url: null, source: "none" };
17024
+ }
17025
+ var LINK_URL_SCHEME = "argent:";
17026
+ function formatLinkUrl(parts) {
17027
+ const h2 = parts.host.includes(":") && !parts.host.startsWith("[") ? `[${parts.host}]` : parts.host;
17028
+ const auth = parts.token ? `${encodeURIComponent(parts.token)}@` : "";
17029
+ return `${LINK_URL_SCHEME}//${auth}${h2}:${parts.port}`;
17030
+ }
17031
+ function parseLinkUrl(input) {
17032
+ if (!input.startsWith(`${LINK_URL_SCHEME}//`)) return null;
17033
+ let u3;
17034
+ try {
17035
+ u3 = new URL(input);
17036
+ } catch {
17037
+ throw new Error(
17038
+ `Invalid connection string "${input}" \u2014 expected argent://[<token>@]<host>:<port>`
17039
+ );
17040
+ }
17041
+ const host = u3.hostname.startsWith("[") ? u3.hostname.slice(1, -1) : u3.hostname;
17042
+ if (!host) throw new Error(`Connection string "${input}" is missing a host.`);
17043
+ if (!u3.port) throw new Error(`Connection string "${input}" is missing a port.`);
17044
+ const port = Number(u3.port);
17045
+ const token = u3.username ? decodeURIComponent(u3.username) : void 0;
17046
+ return { host, port, ...token ? { token } : {} };
17047
+ }
17048
+ function httpFromHostPort(host, port) {
17049
+ const h2 = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
17050
+ return `http://${h2}:${port}`;
17051
+ }
17052
+ function parseLinkTarget(input) {
17053
+ const argent = parseLinkUrl(input);
17054
+ if (argent) {
17055
+ return {
17056
+ url: httpFromHostPort(argent.host, argent.port),
17057
+ host: argent.host,
17058
+ port: argent.port,
17059
+ ...argent.token ? { token: argent.token } : {}
17060
+ };
17061
+ }
17062
+ if (!/^https?:\/\//i.test(input)) return null;
17063
+ let u3;
17064
+ try {
17065
+ u3 = new URL(input);
17066
+ } catch {
17067
+ throw new Error(`Invalid URL "${input}" \u2014 expected http(s)://<host>[:<port>][/path].`);
17068
+ }
17069
+ const host = u3.hostname.startsWith("[") ? u3.hostname.slice(1, -1) : u3.hostname;
17070
+ if (!host) throw new Error(`URL "${input}" is missing a host.`);
17071
+ const port = u3.port ? Number(u3.port) : u3.protocol === "https:" ? 443 : 80;
17072
+ const path21 = u3.pathname === "/" ? "" : u3.pathname.replace(/\/+$/, "");
17073
+ const url2 = `${u3.protocol}//${u3.host}${path21}`;
17074
+ const token = u3.username ? decodeURIComponent(u3.username) : void 0;
17075
+ return { url: url2, host, port, ...token ? { token } : {} };
17076
+ }
17077
+
17078
+ // ../argent-tools-client/src/file-inputs.ts
17079
+ import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
17080
+ import { createReadStream, rmSync } from "node:fs";
17081
+ import { mkdir as mkdir3, readFile as readFile3, rm as rm2, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
17082
+ import { constants, tmpdir } from "node:os";
17083
+ import * as path3 from "node:path";
17084
+
17085
+ // ../archive/src/index.ts
17086
+ import { execFile } from "node:child_process";
17087
+ import { rm, readdir as readdir2 } from "node:fs/promises";
17088
+ import { basename as basename2, dirname as dirname2, join as join3, posix, resolve as resolve2, sep } from "node:path";
17089
+ import { promisify } from "node:util";
17090
+ var execFileAsync = promisify(execFile);
17091
+ var ArchiveError = class extends Error {
17092
+ };
17093
+ function createTarGzArgs(sourcePath, target) {
17094
+ return ["-czf", target, "-C", dirname2(sourcePath), basename2(sourcePath)];
17095
+ }
17096
+ async function createTarGzFile(sourcePath, tarPath) {
17097
+ try {
17098
+ await execFileAsync("tar", createTarGzArgs(sourcePath, tarPath));
17099
+ } catch (err) {
17100
+ await rm(tarPath, { force: true }).catch(() => {
17101
+ });
17102
+ throw err;
17103
+ }
17104
+ }
17105
+ function normalizeTarMemberPath(memberPath) {
17106
+ return memberPath.replace(/^\.\//, "").replace(/\\/g, "/");
17107
+ }
17108
+ function isSafeTarMember(memberPath, destDir) {
17109
+ const normalized = normalizeTarMemberPath(memberPath);
17110
+ if (!normalized || normalized === "." || normalized === "./") return false;
17111
+ if (normalized.startsWith("/") || /^[A-Za-z]:[\\/]/.test(normalized)) return false;
17112
+ const relative3 = posix.normalize(normalized);
17113
+ if (relative3 === ".." || relative3.startsWith("../") || relative3.split("/").includes("..")) {
17114
+ return false;
17115
+ }
17116
+ const root = resolve2(destDir);
17117
+ const resolved = resolve2(destDir, relative3);
17118
+ return resolved === root || resolved.startsWith(root + sep);
17119
+ }
17120
+ async function listTarMembers(tarPath) {
17121
+ const { stdout: stdout2 } = await execFileAsync("tar", ["-tzf", tarPath]);
17122
+ return stdout2.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
17123
+ }
17124
+ function isEscapingLinkTarget(target) {
17125
+ if (target.startsWith("/") || /^[A-Za-z]:[\\/]/.test(target)) return true;
17126
+ return posix.normalize(target.replace(/\\/g, "/")).split("/").includes("..");
17127
+ }
17128
+ async function assertSafeMemberTypes(tarPath) {
17129
+ const { stdout: stdout2 } = await execFileAsync("tar", ["-tzvf", tarPath]);
17130
+ for (const line of stdout2.split("\n")) {
17131
+ if (!line.trim()) continue;
17132
+ const type = line[0];
17133
+ if (type === "-" || type === "d") continue;
17134
+ if (type === "l") {
17135
+ const parts = line.split(" -> ");
17136
+ const target = parts.length === 2 ? parts[1].trim() : "";
17137
+ if (parts.length !== 2 || !target || isEscapingLinkTarget(target)) {
17138
+ throw new ArchiveError(
17139
+ `Archive contains a symlink whose target could not be confirmed safe: "${line.trim()}".`
17140
+ );
17141
+ }
17142
+ continue;
17143
+ }
17144
+ throw new ArchiveError(
17145
+ `Archive contains an unsupported member type "${type}" (hardlink/device/\u2026) \u2014 refusing extraction.`
17146
+ );
17147
+ }
17148
+ }
17149
+ async function assertSafeArchive(tarPath, destDir) {
17150
+ let members;
17151
+ try {
17152
+ members = await listTarMembers(tarPath);
17153
+ } catch (err) {
17154
+ throw new ArchiveError(
17155
+ `Could not read archive: ${err instanceof Error ? err.message : String(err)}`
17156
+ );
17157
+ }
17158
+ if (members.length === 0) {
17159
+ throw new ArchiveError("Archive is empty.");
17160
+ }
17161
+ for (const member of members) {
17162
+ if (!isSafeTarMember(member, destDir)) {
17163
+ throw new ArchiveError(`Archive contains an unsafe path "${member}" \u2014 refusing extraction.`);
17164
+ }
17165
+ }
17166
+ await assertSafeMemberTypes(tarPath);
17167
+ }
17168
+ async function resolveMember(destDir, expectedName) {
17169
+ const entries = await readdir2(destDir);
17170
+ if (entries.includes(expectedName)) {
17171
+ return join3(destDir, expectedName);
17172
+ }
17173
+ const real = entries.filter((e) => !e.startsWith("._"));
17174
+ if (real.length !== 1) {
17175
+ throw new ArchiveError(
17176
+ `Could not identify the extracted member (expected "${expectedName}", found ${real.length} entries).`
17177
+ );
17178
+ }
17179
+ return join3(destDir, real[0]);
17180
+ }
17181
+ async function safeExtractTarGz(tarPath, destDir, expectedName) {
17182
+ await assertSafeArchive(tarPath, destDir);
17183
+ await execFileAsync("tar", ["-xzf", tarPath, "-C", destDir]);
17184
+ return resolveMember(destDir, expectedName);
17185
+ }
17128
17186
 
17129
17187
  // ../argent-tools-client/src/file-inputs.ts
17130
17188
  var FILE_INPUT_MARKER2 = "__argentFileInput";
@@ -17142,10 +17200,39 @@ function interpolatePath(template, args) {
17142
17200
  });
17143
17201
  return missing ? null : out;
17144
17202
  }
17145
- async function tarball(sourcePath) {
17146
- const tarPath = path3.join(tmpdir(), `argent-upload-${randomUUID3()}.tar.gz`);
17147
- await createTarGzFile(sourcePath, tarPath);
17148
- return tarPath;
17203
+ var pendingArchives = /* @__PURE__ */ new Set();
17204
+ var ARCHIVE_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
17205
+ function removePendingArchives() {
17206
+ for (const archive of pendingArchives) {
17207
+ try {
17208
+ rmSync(archive, { force: true });
17209
+ } catch {
17210
+ }
17211
+ }
17212
+ pendingArchives.clear();
17213
+ for (const s of ARCHIVE_SIGNALS) process.removeListener(s, removeArchivesOnSignal);
17214
+ process.removeListener("exit", removePendingArchives);
17215
+ }
17216
+ function removeArchivesOnSignal(signal) {
17217
+ removePendingArchives();
17218
+ if (process.listenerCount(signal) > 0) return;
17219
+ try {
17220
+ process.kill(process.pid, signal);
17221
+ } catch {
17222
+ process.exit(128 + constants.signals[signal]);
17223
+ }
17224
+ }
17225
+ function trackArchive(archive) {
17226
+ if (pendingArchives.size === 0) {
17227
+ for (const s of ARCHIVE_SIGNALS) process.on(s, removeArchivesOnSignal);
17228
+ process.on("exit", removePendingArchives);
17229
+ }
17230
+ pendingArchives.add(archive);
17231
+ }
17232
+ function untrackArchive(archive) {
17233
+ if (!pendingArchives.delete(archive) || pendingArchives.size > 0) return;
17234
+ for (const s of ARCHIVE_SIGNALS) process.removeListener(s, removeArchivesOnSignal);
17235
+ process.removeListener("exit", removePendingArchives);
17149
17236
  }
17150
17237
  function sha256File(filePath) {
17151
17238
  return new Promise((resolve11, reject) => {
@@ -17206,17 +17293,19 @@ async function prepareFileInputs(specs, args, opts) {
17206
17293
  wire.mtimeMs = st.mtimeMs;
17207
17294
  }
17208
17295
  if (opts.uploadEndpoint && st) {
17209
- let tarPath = null;
17296
+ const tarPath = path3.join(tmpdir(), `argent-upload-${randomUUID3()}.tar.gz`);
17297
+ trackArchive(tarPath);
17210
17298
  try {
17211
17299
  process.stderr.write(
17212
17300
  `Uploading ${path3.basename(filePath)} to the remote tool-server...
17213
17301
  `
17214
17302
  );
17215
- tarPath = await tarball(filePath);
17303
+ await createTarGzFile(filePath, tarPath);
17216
17304
  wire.contentHash = await sha256File(tarPath);
17217
17305
  wire.uploadId = await uploadTar(tarPath, opts.uploadEndpoint, opts.signal);
17218
17306
  } finally {
17219
- if (tarPath) await rm2(tarPath, { force: true }).catch(() => {
17307
+ untrackArchive(tarPath);
17308
+ await rm2(tarPath, { force: true }).catch(() => {
17220
17309
  });
17221
17310
  }
17222
17311
  }
@@ -17331,29 +17420,65 @@ function errorBodyMessage(body) {
17331
17420
  if (Array.isArray(body.issues) && typeof body.message === "string") return body.message;
17332
17421
  return body.error ?? body.message;
17333
17422
  }
17423
+ function assertRequiredPresent(meta3, args) {
17424
+ const record2 = typeof args === "object" && args !== null ? args : {};
17425
+ const schema = meta3.inputSchema;
17426
+ const derived = new Set(
17427
+ (meta3.fileInputs ?? []).filter((spec) => spec.path !== `\${${spec.target}}`).map((spec) => spec.target)
17428
+ );
17429
+ const required2 = Array.isArray(schema.required) ? schema.required : [];
17430
+ const missing = required2.filter(
17431
+ (name) => typeof name === "string" && !derived.has(name) && record2[name] === void 0
17432
+ );
17433
+ if (missing.length === 0) return;
17434
+ const issues = missing.map((name) => {
17435
+ const property = schema.properties?.[name];
17436
+ const type = property?.enum === void 0 ? property?.type : void 0;
17437
+ const expected = type === "integer" ? "number" : typeof type === "string" ? type : void 0;
17438
+ return { code: "invalid_type", path: [name], message: "", expected };
17439
+ });
17440
+ throw new ToolInvocationError(
17441
+ describeParamIssues({ issues }, record2)
17442
+ );
17443
+ }
17444
+ function carriesUpload(args) {
17445
+ if (typeof args !== "object" || args === null) return false;
17446
+ return Object.values(args).some((value) => {
17447
+ const wire = value;
17448
+ return wire?.[FILE_INPUT_MARKER2] === true && typeof wire.uploadId === "string";
17449
+ });
17450
+ }
17334
17451
  function createToolsClient(options = {}) {
17335
17452
  let cached3 = null;
17336
- async function baseUrl() {
17453
+ const doFetch = options.fetchImpl ?? ((url2, init2) => fetch(url2, init2));
17454
+ async function route() {
17455
+ if (options.baseUrl) return options.baseUrl();
17337
17456
  const resolved = await getResolvedToolsUrl();
17338
17457
  if (resolved.url) {
17339
- return { url: resolved.url, token: resolved.token ?? "" };
17458
+ return { url: resolved.url, token: resolved.token ?? "", remote: true };
17340
17459
  }
17341
- if (cached3) return cached3;
17342
- if (!options.paths) {
17343
- throw new Error(
17344
- "tools-client: cannot spawn tool-server without `paths`; set ARGENT_TOOLS_URL or pass paths to createToolsClient()"
17345
- );
17460
+ if (!cached3) {
17461
+ if (!options.paths) {
17462
+ throw new Error(
17463
+ "tools-client: cannot spawn tool-server without `paths`; set ARGENT_TOOLS_URL or pass paths to createToolsClient()"
17464
+ );
17465
+ }
17466
+ cached3 = await ensureToolsServer(options.paths);
17346
17467
  }
17347
- cached3 = await ensureToolsServer(options.paths);
17348
- return cached3;
17468
+ return { ...cached3, remote: false };
17469
+ }
17470
+ async function baseUrl() {
17471
+ const { url: url2, token } = await route();
17472
+ return { url: url2, token };
17349
17473
  }
17350
17474
  async function fetchTools(opts) {
17351
17475
  opts?.signal?.throwIfAborted();
17352
17476
  const { url: url2, token } = await baseUrl();
17353
- const res = await fetch(`${url2}/tools`, {
17354
- headers: authHeaders2(token),
17355
- signal: opts?.signal
17356
- });
17477
+ const res = await doFetch(
17478
+ `${url2}/tools`,
17479
+ { headers: authHeaders2(token), signal: opts?.signal },
17480
+ { longRunning: false, carriesUpload: false }
17481
+ );
17357
17482
  if (!res.ok) throw new Error(`GET /tools failed: ${res.status} ${res.statusText}`);
17358
17483
  const json2 = await res.json();
17359
17484
  return json2.tools;
@@ -17364,36 +17489,50 @@ function createToolsClient(options = {}) {
17364
17489
  }
17365
17490
  async function callTool(name, args, opts) {
17366
17491
  opts?.signal?.throwIfAborted();
17367
- const { url: url2, token } = await baseUrl();
17492
+ const { url: url2, token, remote } = await route();
17368
17493
  let finalArgs = args;
17369
17494
  const meta3 = await fetchTool(name, { signal: opts?.signal });
17370
17495
  if (meta3?.fileInputs?.length) {
17371
- const { url: routedUrl } = await getResolvedToolsUrl();
17372
- const isRemote = routedUrl !== null;
17496
+ if (remote) assertRequiredPresent(meta3, args);
17373
17497
  finalArgs = await prepareFileInputs(meta3.fileInputs, args ?? {}, {
17374
- includeContent: isRemote,
17375
- uploadEndpoint: isRemote ? { url: url2, token } : void 0,
17498
+ includeContent: remote,
17499
+ uploadEndpoint: remote ? { url: url2, token } : void 0,
17376
17500
  signal: opts?.signal
17377
17501
  });
17378
17502
  }
17379
- const res = await fetch(`${url2}/tools/${encodeURIComponent(name)}`, {
17380
- method: "POST",
17381
- headers: {
17382
- "Content-Type": "application/json",
17383
- ...opts?.onProgress ? { Accept: "application/x-ndjson" } : {},
17384
- ...authHeaders2(token)
17503
+ const res = await doFetch(
17504
+ `${url2}/tools/${encodeURIComponent(name)}`,
17505
+ {
17506
+ method: "POST",
17507
+ headers: {
17508
+ "Content-Type": "application/json",
17509
+ ...opts?.onProgress ? { Accept: "application/x-ndjson" } : {},
17510
+ ...authHeaders2(token)
17511
+ },
17512
+ body: JSON.stringify(finalArgs ?? {}),
17513
+ signal: opts?.signal
17385
17514
  },
17386
- body: JSON.stringify(finalArgs ?? {}),
17387
- signal: opts?.signal
17388
- });
17515
+ { longRunning: meta3?.longRunning === true, carriesUpload: carriesUpload(finalArgs) }
17516
+ );
17389
17517
  const contentType = res.headers.get("content-type") ?? "";
17390
17518
  if (opts?.onProgress && res.ok && res.body && contentType.includes("application/x-ndjson")) {
17391
- return consumeToolStream(res.body, opts.onProgress, opts.signal);
17519
+ const streamed = await consumeToolStream(res.body, opts.onProgress, opts.signal);
17520
+ return { ...streamed, outputHint: meta3?.outputHint };
17392
17521
  }
17393
- const json2 = await res.json().catch(() => {
17522
+ let json2;
17523
+ try {
17524
+ json2 = await res.json();
17525
+ } catch (err) {
17394
17526
  opts?.signal?.throwIfAborted();
17395
- return {};
17396
- });
17527
+ if (res.ok) {
17528
+ const reason = err instanceof Error ? err.message : String(err);
17529
+ throw new Error(
17530
+ `The tool-server answered ${res.status} ${res.statusText} to ${name}, but the answer could not be read (${reason}). The tool may have run; check its effect before you run it again.`,
17531
+ { cause: err }
17532
+ );
17533
+ }
17534
+ json2 = {};
17535
+ }
17397
17536
  if (!res.ok) {
17398
17537
  throw new ToolInvocationError(errorBodyMessage(json2) ?? `${res.status} ${res.statusText}`, {
17399
17538
  errorCode: json2.error_code,
@@ -17403,7 +17542,7 @@ function createToolsClient(options = {}) {
17403
17542
  }
17404
17543
  opts?.signal?.throwIfAborted();
17405
17544
  const { result: data } = await applyClientFileDirectives(json2.data);
17406
- return { data, note: json2.note };
17545
+ return { data, note: json2.note, outputHint: meta3?.outputHint };
17407
17546
  }
17408
17547
  return { fetchTools, fetchTool, callTool, baseUrl };
17409
17548
  }
@@ -18258,14 +18397,14 @@ async function resolveLocalFile(handle) {
18258
18397
  }
18259
18398
  }
18260
18399
  async function downloadAndExtractArchive(handle, data, dir) {
18261
- const tarball2 = join9(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
18400
+ const tarball = join9(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
18262
18401
  try {
18263
- await writeFile4(tarball2, data);
18264
- return await safeExtractTarGz(tarball2, dir, handle.filename);
18402
+ await writeFile4(tarball, data);
18403
+ return await safeExtractTarGz(tarball, dir, handle.filename);
18265
18404
  } catch {
18266
18405
  return null;
18267
18406
  } finally {
18268
- await rm3(tarball2, { force: true }).catch(() => {
18407
+ await rm3(tarball, { force: true }).catch(() => {
18269
18408
  });
18270
18409
  }
18271
18410
  }
@@ -21916,7 +22055,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
21916
22055
  var SESSION_ID2 = randomUUID5();
21917
22056
  function readCliVersion() {
21918
22057
  if (true) {
21919
- return "0.27.1-next.18";
22058
+ return "0.27.1-next.19";
21920
22059
  }
21921
22060
  return "0.0.0";
21922
22061
  }