@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 +402 -263
- package/dist/client.js +335 -196
- package/dist/installer.mjs +8 -8
- package/dist/mcp-server.mjs +531 -232
- package/dist/tool-server.cjs +1 -1
- package/package.json +1 -1
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
|
|
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
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
17342
|
-
|
|
17343
|
-
|
|
17344
|
-
|
|
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
|
|
17348
|
-
|
|
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
|
|
17354
|
-
|
|
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
|
|
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
|
-
|
|
17372
|
-
const isRemote = routedUrl !== null;
|
|
17496
|
+
if (remote) assertRequiredPresent(meta3, args);
|
|
17373
17497
|
finalArgs = await prepareFileInputs(meta3.fileInputs, args ?? {}, {
|
|
17374
|
-
includeContent:
|
|
17375
|
-
uploadEndpoint:
|
|
17498
|
+
includeContent: remote,
|
|
17499
|
+
uploadEndpoint: remote ? { url: url2, token } : void 0,
|
|
17376
17500
|
signal: opts?.signal
|
|
17377
17501
|
});
|
|
17378
17502
|
}
|
|
17379
|
-
const res = await
|
|
17380
|
-
|
|
17381
|
-
|
|
17382
|
-
|
|
17383
|
-
|
|
17384
|
-
|
|
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
|
-
|
|
17387
|
-
|
|
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
|
-
|
|
17519
|
+
const streamed = await consumeToolStream(res.body, opts.onProgress, opts.signal);
|
|
17520
|
+
return { ...streamed, outputHint: meta3?.outputHint };
|
|
17392
17521
|
}
|
|
17393
|
-
|
|
17522
|
+
let json2;
|
|
17523
|
+
try {
|
|
17524
|
+
json2 = await res.json();
|
|
17525
|
+
} catch (err) {
|
|
17394
17526
|
opts?.signal?.throwIfAborted();
|
|
17395
|
-
|
|
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
|
|
18400
|
+
const tarball = join9(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
|
|
18262
18401
|
try {
|
|
18263
|
-
await writeFile4(
|
|
18264
|
-
return await safeExtractTarGz(
|
|
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(
|
|
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.
|
|
22058
|
+
return "0.27.1-next.19";
|
|
21920
22059
|
}
|
|
21921
22060
|
return "0.0.0";
|
|
21922
22061
|
}
|