@easynet/agent-tool-buildin 0.0.3 → 0.0.4
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/CoreToolsModule.d.ts +1 -1
- package/dist/CoreToolsModule.d.ts.map +1 -1
- package/dist/http/downloadFile.d.ts.map +1 -1
- package/dist/http/duckduckgoSearch.d.ts.map +1 -1
- package/dist/http/fetchJson.d.ts.map +1 -1
- package/dist/http/fetchPageMainContent.d.ts.map +1 -1
- package/dist/http/fetchText.d.ts.map +1 -1
- package/dist/http/head.d.ts.map +1 -1
- package/dist/http/yahooFinance.d.ts.map +1 -1
- package/dist/index.cjs +156 -309
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +130 -283
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +5 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/security/sandbox.d.ts +0 -9
- package/dist/security/sandbox.d.ts.map +0 -1
- package/dist/security/ssrf.d.ts +0 -12
- package/dist/security/ssrf.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1801,7 +1801,7 @@ var init_mustache = __esm({
|
|
|
1801
1801
|
Context.prototype.push = function push(view) {
|
|
1802
1802
|
return new Context(view, this);
|
|
1803
1803
|
};
|
|
1804
|
-
Context.prototype.lookup = function
|
|
1804
|
+
Context.prototype.lookup = function lookup(name) {
|
|
1805
1805
|
var cache = this.cache;
|
|
1806
1806
|
var value;
|
|
1807
1807
|
if (cache.hasOwnProperty(name)) {
|
|
@@ -2021,21 +2021,21 @@ __export(index_exports, {
|
|
|
2021
2021
|
getBuiltinContext: () => getBuiltinContext,
|
|
2022
2022
|
hashTextSpec: () => hashTextSpec,
|
|
2023
2023
|
headSpec: () => headSpec,
|
|
2024
|
-
isIpInBlockedCidrs: () => isIpInBlockedCidrs,
|
|
2024
|
+
isIpInBlockedCidrs: () => import_agent_tool25.isIpInBlockedCidrs,
|
|
2025
2025
|
jsonSelectSpec: () => jsonSelectSpec,
|
|
2026
2026
|
listDirSpec: () => listDirSpec,
|
|
2027
2027
|
nowHandler: () => nowHandler,
|
|
2028
2028
|
nowSpec: () => nowSpec,
|
|
2029
2029
|
readTextSpec: () => readTextSpec,
|
|
2030
2030
|
registerCoreTools: () => registerCoreTools,
|
|
2031
|
-
resolveSandboxedPath: () => resolveSandboxedPath,
|
|
2031
|
+
resolveSandboxedPath: () => import_agent_tool25.resolveSandboxedPath,
|
|
2032
2032
|
runCommandSpec: () => runCommandSpec,
|
|
2033
2033
|
runWithBuiltinContext: () => runWithBuiltinContext,
|
|
2034
2034
|
searchTextSpec: () => searchTextSpec,
|
|
2035
2035
|
sha256Spec: () => sha256Spec,
|
|
2036
2036
|
templateRenderSpec: () => templateRenderSpec,
|
|
2037
2037
|
truncateSpec: () => truncateSpec,
|
|
2038
|
-
validateUrl: () => validateUrl,
|
|
2038
|
+
validateUrl: () => import_agent_tool25.validateUrl,
|
|
2039
2039
|
writeTextSpec: () => writeTextSpec,
|
|
2040
2040
|
yahooFinanceQuoteSpec: () => yahooFinanceQuoteSpec
|
|
2041
2041
|
});
|
|
@@ -2143,51 +2143,8 @@ var DEFAULT_CORE_TOOLS_CONFIG = {
|
|
|
2143
2143
|
};
|
|
2144
2144
|
|
|
2145
2145
|
// fs/readText.ts
|
|
2146
|
-
var import_promises2 = require("fs/promises");
|
|
2147
|
-
|
|
2148
|
-
// security/sandbox.ts
|
|
2149
|
-
var import_node_path = require("path");
|
|
2150
2146
|
var import_promises = require("fs/promises");
|
|
2151
2147
|
var import_agent_tool = require("@easynet/agent-tool");
|
|
2152
|
-
async function resolveSandboxedPath(inputPath, sandboxRoot) {
|
|
2153
|
-
let normalizedRoot;
|
|
2154
|
-
try {
|
|
2155
|
-
normalizedRoot = await (0, import_promises.realpath)((0, import_node_path.resolve)(sandboxRoot));
|
|
2156
|
-
} catch {
|
|
2157
|
-
normalizedRoot = (0, import_node_path.normalize)((0, import_node_path.resolve)(sandboxRoot));
|
|
2158
|
-
}
|
|
2159
|
-
const resolved = (0, import_node_path.resolve)(normalizedRoot, inputPath);
|
|
2160
|
-
let real;
|
|
2161
|
-
try {
|
|
2162
|
-
await (0, import_promises.access)(resolved);
|
|
2163
|
-
real = await (0, import_promises.realpath)(resolved);
|
|
2164
|
-
} catch {
|
|
2165
|
-
const parentDir = (0, import_node_path.dirname)(resolved);
|
|
2166
|
-
let realParent;
|
|
2167
|
-
try {
|
|
2168
|
-
await (0, import_promises.access)(parentDir);
|
|
2169
|
-
realParent = await (0, import_promises.realpath)(parentDir);
|
|
2170
|
-
} catch {
|
|
2171
|
-
realParent = (0, import_node_path.normalize)(parentDir);
|
|
2172
|
-
}
|
|
2173
|
-
real = (0, import_node_path.resolve)(realParent, (0, import_node_path.basename)(resolved));
|
|
2174
|
-
}
|
|
2175
|
-
if (!isWithinRoot(real, normalizedRoot)) {
|
|
2176
|
-
throw (0, import_agent_tool.createTaggedError)(
|
|
2177
|
-
"PATH_OUTSIDE_SANDBOX",
|
|
2178
|
-
`Path "${inputPath}" resolves to "${real}" which is outside sandbox "${normalizedRoot}"`,
|
|
2179
|
-
{ inputPath, resolvedPath: real, sandboxRoot: normalizedRoot }
|
|
2180
|
-
);
|
|
2181
|
-
}
|
|
2182
|
-
return real;
|
|
2183
|
-
}
|
|
2184
|
-
function isWithinRoot(path, root) {
|
|
2185
|
-
const normalizedPath = (0, import_node_path.normalize)(path);
|
|
2186
|
-
const normalizedRoot = (0, import_node_path.normalize)(root);
|
|
2187
|
-
return normalizedPath === normalizedRoot || normalizedPath.startsWith(normalizedRoot + "/");
|
|
2188
|
-
}
|
|
2189
|
-
|
|
2190
|
-
// fs/readText.ts
|
|
2191
2148
|
var import_agent_tool2 = require("@easynet/agent-tool");
|
|
2192
2149
|
var readTextHandler = (async (args) => {
|
|
2193
2150
|
const ctx = getBuiltinContext();
|
|
@@ -2196,8 +2153,8 @@ var readTextHandler = (async (args) => {
|
|
|
2196
2153
|
throw (0, import_agent_tool2.createTaggedError)("FS_INVALID", "path is required (pass 'path' or 'filePath')", {});
|
|
2197
2154
|
}
|
|
2198
2155
|
const maxBytes = args.maxBytes ?? ctx.config.maxReadBytes;
|
|
2199
|
-
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2200
|
-
const fileStat = await (0,
|
|
2156
|
+
const resolvedPath = await (0, import_agent_tool.resolveSandboxedPath)(inputPath, ctx.config.sandboxRoot);
|
|
2157
|
+
const fileStat = await (0, import_promises.stat)(resolvedPath);
|
|
2201
2158
|
if (fileStat.size > maxBytes) {
|
|
2202
2159
|
throw (0, import_agent_tool2.createTaggedError)(
|
|
2203
2160
|
"FILE_TOO_LARGE",
|
|
@@ -2205,7 +2162,7 @@ var readTextHandler = (async (args) => {
|
|
|
2205
2162
|
{ path: resolvedPath, size: fileStat.size, limit: maxBytes }
|
|
2206
2163
|
);
|
|
2207
2164
|
}
|
|
2208
|
-
const text = await (0,
|
|
2165
|
+
const text = await (0, import_promises.readFile)(resolvedPath, "utf-8");
|
|
2209
2166
|
return {
|
|
2210
2167
|
result: {
|
|
2211
2168
|
path: resolvedPath,
|
|
@@ -2224,9 +2181,10 @@ var readTextHandler = (async (args) => {
|
|
|
2224
2181
|
});
|
|
2225
2182
|
|
|
2226
2183
|
// fs/writeText.ts
|
|
2227
|
-
var
|
|
2184
|
+
var import_promises2 = require("fs/promises");
|
|
2228
2185
|
var import_node_crypto = require("crypto");
|
|
2229
|
-
var
|
|
2186
|
+
var import_node_path = require("path");
|
|
2187
|
+
var import_agent_tool3 = require("@easynet/agent-tool");
|
|
2230
2188
|
var writeTextHandler = (async (args) => {
|
|
2231
2189
|
const ctx = getBuiltinContext();
|
|
2232
2190
|
const inputPath = (args.path ?? args.filePath)?.trim();
|
|
@@ -2236,11 +2194,11 @@ var writeTextHandler = (async (args) => {
|
|
|
2236
2194
|
const text = args.text ?? args.content ?? "";
|
|
2237
2195
|
const overwrite = args.overwrite ?? false;
|
|
2238
2196
|
const mkdirp = args.mkdirp ?? true;
|
|
2239
|
-
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2197
|
+
const resolvedPath = await (0, import_agent_tool3.resolveSandboxedPath)(inputPath, ctx.config.sandboxRoot);
|
|
2240
2198
|
if (!overwrite) {
|
|
2241
|
-
const { access
|
|
2199
|
+
const { access } = await import("fs/promises");
|
|
2242
2200
|
try {
|
|
2243
|
-
await
|
|
2201
|
+
await access(resolvedPath);
|
|
2244
2202
|
throw new Error(
|
|
2245
2203
|
`File already exists: ${resolvedPath}. Set overwrite=true to allow overwriting.`
|
|
2246
2204
|
);
|
|
@@ -2252,9 +2210,9 @@ var writeTextHandler = (async (args) => {
|
|
|
2252
2210
|
}
|
|
2253
2211
|
}
|
|
2254
2212
|
if (mkdirp) {
|
|
2255
|
-
await (0,
|
|
2213
|
+
await (0, import_promises2.mkdir)((0, import_node_path.dirname)(resolvedPath), { recursive: true });
|
|
2256
2214
|
}
|
|
2257
|
-
await (0,
|
|
2215
|
+
await (0, import_promises2.writeFile)(resolvedPath, text, "utf-8");
|
|
2258
2216
|
const bytes = Buffer.byteLength(text, "utf-8");
|
|
2259
2217
|
const sha256 = (0, import_node_crypto.createHash)("sha256").update(text).digest("hex");
|
|
2260
2218
|
return {
|
|
@@ -2275,8 +2233,9 @@ var writeTextHandler = (async (args) => {
|
|
|
2275
2233
|
});
|
|
2276
2234
|
|
|
2277
2235
|
// fs/listDir.ts
|
|
2278
|
-
var
|
|
2279
|
-
var
|
|
2236
|
+
var import_promises3 = require("fs/promises");
|
|
2237
|
+
var import_node_path2 = require("path");
|
|
2238
|
+
var import_agent_tool4 = require("@easynet/agent-tool");
|
|
2280
2239
|
var listDirHandler = (async (args) => {
|
|
2281
2240
|
const ctx = getBuiltinContext();
|
|
2282
2241
|
const inputPath = (args.path ?? args.filePath ?? args.dir ?? args.directory)?.trim();
|
|
@@ -2287,7 +2246,7 @@ var listDirHandler = (async (args) => {
|
|
|
2287
2246
|
const includeHidden = args.includeHidden ?? false;
|
|
2288
2247
|
const recursive = args.recursive ?? false;
|
|
2289
2248
|
const maxDepth = args.maxDepth ?? 5;
|
|
2290
|
-
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2249
|
+
const resolvedPath = await (0, import_agent_tool4.resolveSandboxedPath)(inputPath, ctx.config.sandboxRoot);
|
|
2291
2250
|
const entries = [];
|
|
2292
2251
|
let truncated = false;
|
|
2293
2252
|
await walkDir(resolvedPath, "", entries, {
|
|
@@ -2322,8 +2281,8 @@ async function walkDir(basePath, relativePath, entries, options) {
|
|
|
2322
2281
|
options.onTruncate();
|
|
2323
2282
|
return;
|
|
2324
2283
|
}
|
|
2325
|
-
const fullPath = relativePath ? (0,
|
|
2326
|
-
const dirEntries = await (0,
|
|
2284
|
+
const fullPath = relativePath ? (0, import_node_path2.resolve)(basePath, relativePath) : basePath;
|
|
2285
|
+
const dirEntries = await (0, import_promises3.readdir)(fullPath, { withFileTypes: true });
|
|
2327
2286
|
for (const dirent of dirEntries) {
|
|
2328
2287
|
if (entries.length >= options.maxEntries) {
|
|
2329
2288
|
options.onTruncate();
|
|
@@ -2332,8 +2291,8 @@ async function walkDir(basePath, relativePath, entries, options) {
|
|
|
2332
2291
|
if (!options.includeHidden && dirent.name.startsWith(".")) {
|
|
2333
2292
|
continue;
|
|
2334
2293
|
}
|
|
2335
|
-
const entryPath = (0,
|
|
2336
|
-
const entryRelative = relativePath ? (0,
|
|
2294
|
+
const entryPath = (0, import_node_path2.join)(fullPath, dirent.name);
|
|
2295
|
+
const entryRelative = relativePath ? (0, import_node_path2.join)(relativePath, dirent.name) : dirent.name;
|
|
2337
2296
|
let entryType;
|
|
2338
2297
|
if (dirent.isSymbolicLink()) {
|
|
2339
2298
|
entryType = "symlink";
|
|
@@ -2347,7 +2306,7 @@ async function walkDir(basePath, relativePath, entries, options) {
|
|
|
2347
2306
|
let size = 0;
|
|
2348
2307
|
let mtime = "";
|
|
2349
2308
|
try {
|
|
2350
|
-
const entryStat = await (0,
|
|
2309
|
+
const entryStat = await (0, import_promises3.stat)(entryPath);
|
|
2351
2310
|
size = entryStat.size;
|
|
2352
2311
|
mtime = entryStat.mtime.toISOString();
|
|
2353
2312
|
} catch {
|
|
@@ -2368,10 +2327,11 @@ async function walkDir(basePath, relativePath, entries, options) {
|
|
|
2368
2327
|
}
|
|
2369
2328
|
|
|
2370
2329
|
// fs/searchText.ts
|
|
2371
|
-
var
|
|
2330
|
+
var import_promises4 = require("fs/promises");
|
|
2372
2331
|
var import_node_fs = require("fs");
|
|
2373
2332
|
var import_node_readline = require("readline");
|
|
2374
|
-
var
|
|
2333
|
+
var import_node_path3 = require("path");
|
|
2334
|
+
var import_agent_tool5 = require("@easynet/agent-tool");
|
|
2375
2335
|
var searchTextHandler = (async (args) => {
|
|
2376
2336
|
const ctx = getBuiltinContext();
|
|
2377
2337
|
const rootPath = (args.root ?? args.path ?? args.dir ?? args.directory)?.trim();
|
|
@@ -2385,7 +2345,7 @@ var searchTextHandler = (async (args) => {
|
|
|
2385
2345
|
const glob = args.glob ?? "**/*.{md,txt,log,json,ts,js,py,java,scala}";
|
|
2386
2346
|
const maxMatches = args.maxMatches ?? 100;
|
|
2387
2347
|
const maxFiles = args.maxFiles ?? 500;
|
|
2388
|
-
const resolvedRoot = await resolveSandboxedPath(rootPath, ctx.config.sandboxRoot);
|
|
2348
|
+
const resolvedRoot = await (0, import_agent_tool5.resolveSandboxedPath)(rootPath, ctx.config.sandboxRoot);
|
|
2389
2349
|
let regex;
|
|
2390
2350
|
try {
|
|
2391
2351
|
regex = new RegExp(query, "i");
|
|
@@ -2432,13 +2392,13 @@ async function collectFiles(dirPath, files, options) {
|
|
|
2432
2392
|
if (files.length >= options.maxFiles) return;
|
|
2433
2393
|
let entries;
|
|
2434
2394
|
try {
|
|
2435
|
-
entries = await (0,
|
|
2395
|
+
entries = await (0, import_promises4.readdir)(dirPath, { withFileTypes: true });
|
|
2436
2396
|
} catch {
|
|
2437
2397
|
return;
|
|
2438
2398
|
}
|
|
2439
2399
|
for (const entry of entries) {
|
|
2440
2400
|
if (files.length >= options.maxFiles) return;
|
|
2441
|
-
const fullPath = (0,
|
|
2401
|
+
const fullPath = (0, import_node_path3.join)(dirPath, entry.name);
|
|
2442
2402
|
if (entry.isDirectory()) {
|
|
2443
2403
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2444
2404
|
await collectFiles(fullPath, files, options);
|
|
@@ -2452,7 +2412,7 @@ async function collectFiles(dirPath, files, options) {
|
|
|
2452
2412
|
}
|
|
2453
2413
|
}
|
|
2454
2414
|
async function searchFile(filePath, root, regex, matches, maxMatches) {
|
|
2455
|
-
const fileStat = await (0,
|
|
2415
|
+
const fileStat = await (0, import_promises4.stat)(filePath).catch(() => null);
|
|
2456
2416
|
if (!fileStat || fileStat.size > 1024 * 1024) return;
|
|
2457
2417
|
const stream = (0, import_node_fs.createReadStream)(filePath, { encoding: "utf-8" });
|
|
2458
2418
|
const rl = (0, import_node_readline.createInterface)({ input: stream, crlfDelay: Infinity });
|
|
@@ -2465,7 +2425,7 @@ async function searchFile(filePath, root, regex, matches, maxMatches) {
|
|
|
2465
2425
|
}
|
|
2466
2426
|
if (regex.test(line)) {
|
|
2467
2427
|
matches.push({
|
|
2468
|
-
file: (0,
|
|
2428
|
+
file: (0, import_node_path3.relative)(root, filePath),
|
|
2469
2429
|
lineNo,
|
|
2470
2430
|
excerpt: line.slice(0, 200)
|
|
2471
2431
|
});
|
|
@@ -2498,22 +2458,23 @@ function escapeRegExp(str) {
|
|
|
2498
2458
|
|
|
2499
2459
|
// fs/sha256.ts
|
|
2500
2460
|
var import_node_fs2 = require("fs");
|
|
2501
|
-
var
|
|
2461
|
+
var import_promises5 = require("fs/promises");
|
|
2502
2462
|
var import_node_crypto2 = require("crypto");
|
|
2503
|
-
var
|
|
2463
|
+
var import_agent_tool6 = require("@easynet/agent-tool");
|
|
2464
|
+
var import_agent_tool7 = require("@easynet/agent-tool");
|
|
2504
2465
|
var sha256Handler = (async (args) => {
|
|
2505
2466
|
const ctx = getBuiltinContext();
|
|
2506
2467
|
const inputPath = (args.path ?? args.filePath)?.trim();
|
|
2507
2468
|
if (!inputPath) {
|
|
2508
|
-
throw (0,
|
|
2469
|
+
throw (0, import_agent_tool7.createTaggedError)("FS_INVALID", "path is required (pass 'path' or 'filePath')", {});
|
|
2509
2470
|
}
|
|
2510
|
-
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2511
|
-
const fileStat = await (0,
|
|
2512
|
-
const hash = await new Promise((
|
|
2471
|
+
const resolvedPath = await (0, import_agent_tool6.resolveSandboxedPath)(inputPath, ctx.config.sandboxRoot);
|
|
2472
|
+
const fileStat = await (0, import_promises5.stat)(resolvedPath);
|
|
2473
|
+
const hash = await new Promise((resolve2, reject) => {
|
|
2513
2474
|
const hasher = (0, import_node_crypto2.createHash)("sha256");
|
|
2514
2475
|
const stream = (0, import_node_fs2.createReadStream)(resolvedPath);
|
|
2515
2476
|
stream.on("data", (chunk) => hasher.update(chunk));
|
|
2516
|
-
stream.on("end", () =>
|
|
2477
|
+
stream.on("end", () => resolve2(hasher.digest("hex")));
|
|
2517
2478
|
stream.on("error", reject);
|
|
2518
2479
|
});
|
|
2519
2480
|
return {
|
|
@@ -2534,7 +2495,8 @@ var sha256Handler = (async (args) => {
|
|
|
2534
2495
|
});
|
|
2535
2496
|
|
|
2536
2497
|
// fs/deletePath.ts
|
|
2537
|
-
var
|
|
2498
|
+
var import_promises6 = require("fs/promises");
|
|
2499
|
+
var import_agent_tool8 = require("@easynet/agent-tool");
|
|
2538
2500
|
var deletePathHandler = (async (args) => {
|
|
2539
2501
|
const ctx = getBuiltinContext();
|
|
2540
2502
|
const inputPath = (args.path ?? args.filePath)?.trim();
|
|
@@ -2548,7 +2510,7 @@ var deletePathHandler = (async (args) => {
|
|
|
2548
2510
|
"Deletion not confirmed. Set confirm=true to proceed with deletion."
|
|
2549
2511
|
);
|
|
2550
2512
|
}
|
|
2551
|
-
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2513
|
+
const resolvedPath = await (0, import_agent_tool8.resolveSandboxedPath)(inputPath, ctx.config.sandboxRoot);
|
|
2552
2514
|
let realSandboxRoot;
|
|
2553
2515
|
try {
|
|
2554
2516
|
const { realpath: rp } = await import("fs/promises");
|
|
@@ -2559,16 +2521,16 @@ var deletePathHandler = (async (args) => {
|
|
|
2559
2521
|
if (resolvedPath === realSandboxRoot) {
|
|
2560
2522
|
throw new Error("Cannot delete the sandbox root directory.");
|
|
2561
2523
|
}
|
|
2562
|
-
const fileStat = await (0,
|
|
2524
|
+
const fileStat = await (0, import_promises6.stat)(resolvedPath);
|
|
2563
2525
|
const isDirectory = fileStat.isDirectory();
|
|
2564
2526
|
if (isDirectory) {
|
|
2565
2527
|
if (recursive) {
|
|
2566
|
-
await (0,
|
|
2528
|
+
await (0, import_promises6.rm)(resolvedPath, { recursive: true, force: true });
|
|
2567
2529
|
} else {
|
|
2568
|
-
await (0,
|
|
2530
|
+
await (0, import_promises6.rmdir)(resolvedPath);
|
|
2569
2531
|
}
|
|
2570
2532
|
} else {
|
|
2571
|
-
await (0,
|
|
2533
|
+
await (0, import_promises6.unlink)(resolvedPath);
|
|
2572
2534
|
}
|
|
2573
2535
|
return {
|
|
2574
2536
|
result: {
|
|
@@ -2587,175 +2549,25 @@ var deletePathHandler = (async (args) => {
|
|
|
2587
2549
|
};
|
|
2588
2550
|
});
|
|
2589
2551
|
|
|
2590
|
-
// security/ssrf.ts
|
|
2591
|
-
var import_promises8 = require("dns/promises");
|
|
2592
|
-
var import_agent_tool4 = require("@easynet/agent-tool");
|
|
2593
|
-
async function validateUrl(url, allowedHosts, blockedCidrs) {
|
|
2594
|
-
let parsed;
|
|
2595
|
-
try {
|
|
2596
|
-
parsed = new URL(url);
|
|
2597
|
-
} catch {
|
|
2598
|
-
throw (0, import_agent_tool4.createTaggedError)(
|
|
2599
|
-
"HTTP_DISALLOWED_HOST",
|
|
2600
|
-
`Invalid URL: ${url}`,
|
|
2601
|
-
{ url }
|
|
2602
|
-
);
|
|
2603
|
-
}
|
|
2604
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
2605
|
-
throw (0, import_agent_tool4.createTaggedError)(
|
|
2606
|
-
"HTTP_DISALLOWED_HOST",
|
|
2607
|
-
`Protocol not allowed: ${parsed.protocol}. Only http: and https: are supported.`,
|
|
2608
|
-
{ url, protocol: parsed.protocol }
|
|
2609
|
-
);
|
|
2610
|
-
}
|
|
2611
|
-
const hostname = parsed.hostname;
|
|
2612
|
-
if (!isHostAllowed(hostname, allowedHosts)) {
|
|
2613
|
-
throw (0, import_agent_tool4.createTaggedError)(
|
|
2614
|
-
"HTTP_DISALLOWED_HOST",
|
|
2615
|
-
`Host "${hostname}" is not in the allowed hosts list`,
|
|
2616
|
-
{ url, hostname, allowedHosts }
|
|
2617
|
-
);
|
|
2618
|
-
}
|
|
2619
|
-
try {
|
|
2620
|
-
const { address } = await (0, import_promises8.lookup)(hostname);
|
|
2621
|
-
if (isIpInBlockedCidrs(address, blockedCidrs)) {
|
|
2622
|
-
throw (0, import_agent_tool4.createTaggedError)(
|
|
2623
|
-
"HTTP_DISALLOWED_HOST",
|
|
2624
|
-
`Host "${hostname}" resolves to blocked IP: ${address}`,
|
|
2625
|
-
{ url, hostname, resolvedIp: address }
|
|
2626
|
-
);
|
|
2627
|
-
}
|
|
2628
|
-
} catch (err) {
|
|
2629
|
-
if (err instanceof Error && err.kind === "HTTP_DISALLOWED_HOST") {
|
|
2630
|
-
throw err;
|
|
2631
|
-
}
|
|
2632
|
-
throw (0, import_agent_tool4.createTaggedError)(
|
|
2633
|
-
"HTTP_DISALLOWED_HOST",
|
|
2634
|
-
`DNS resolution failed for host "${hostname}": ${err instanceof Error ? err.message : String(err)}`,
|
|
2635
|
-
{ url, hostname }
|
|
2636
|
-
);
|
|
2637
|
-
}
|
|
2638
|
-
return parsed;
|
|
2639
|
-
}
|
|
2640
|
-
function isHostAllowed(hostname, allowedHosts) {
|
|
2641
|
-
for (const pattern of allowedHosts) {
|
|
2642
|
-
if (pattern === "*") {
|
|
2643
|
-
return true;
|
|
2644
|
-
}
|
|
2645
|
-
if (pattern.startsWith("*.")) {
|
|
2646
|
-
const suffix = pattern.slice(1);
|
|
2647
|
-
if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {
|
|
2648
|
-
return true;
|
|
2649
|
-
}
|
|
2650
|
-
} else if (hostname === pattern) {
|
|
2651
|
-
return true;
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
return false;
|
|
2655
|
-
}
|
|
2656
|
-
function isIpInBlockedCidrs(ip, cidrs) {
|
|
2657
|
-
const normalizedIp = normalizeIp(ip);
|
|
2658
|
-
if (!normalizedIp) return false;
|
|
2659
|
-
for (const cidr of cidrs) {
|
|
2660
|
-
if (cidr.includes(":")) {
|
|
2661
|
-
if (!ip.includes(":")) continue;
|
|
2662
|
-
if (isIpv6InCidr(ip, cidr)) return true;
|
|
2663
|
-
} else {
|
|
2664
|
-
if (isIpv4InCidr(normalizedIp, cidr)) return true;
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
return false;
|
|
2668
|
-
}
|
|
2669
|
-
function normalizeIp(ip) {
|
|
2670
|
-
if (ip.startsWith("::ffff:")) {
|
|
2671
|
-
return ip.slice(7);
|
|
2672
|
-
}
|
|
2673
|
-
if (/^\d+\.\d+\.\d+\.\d+$/.test(ip)) {
|
|
2674
|
-
return ip;
|
|
2675
|
-
}
|
|
2676
|
-
return null;
|
|
2677
|
-
}
|
|
2678
|
-
function isIpv4InCidr(ip, cidr) {
|
|
2679
|
-
const [cidrIp, prefixStr] = cidr.split("/");
|
|
2680
|
-
if (!cidrIp || !prefixStr) return false;
|
|
2681
|
-
const prefix = parseInt(prefixStr, 10);
|
|
2682
|
-
if (isNaN(prefix) || prefix < 0 || prefix > 32) return false;
|
|
2683
|
-
const ipNum = ipv4ToNum(ip);
|
|
2684
|
-
const cidrNum = ipv4ToNum(cidrIp);
|
|
2685
|
-
if (ipNum === null || cidrNum === null) return false;
|
|
2686
|
-
const mask = prefix === 0 ? 0 : ~0 << 32 - prefix >>> 0;
|
|
2687
|
-
return (ipNum & mask) === (cidrNum & mask);
|
|
2688
|
-
}
|
|
2689
|
-
function ipv4ToNum(ip) {
|
|
2690
|
-
const parts = ip.split(".");
|
|
2691
|
-
if (parts.length !== 4) return null;
|
|
2692
|
-
let num = 0;
|
|
2693
|
-
for (const part of parts) {
|
|
2694
|
-
const n = parseInt(part, 10);
|
|
2695
|
-
if (isNaN(n) || n < 0 || n > 255) return null;
|
|
2696
|
-
num = num << 8 | n;
|
|
2697
|
-
}
|
|
2698
|
-
return num >>> 0;
|
|
2699
|
-
}
|
|
2700
|
-
function isIpv6InCidr(ip, cidr) {
|
|
2701
|
-
const [cidrIp, prefixStr] = cidr.split("/");
|
|
2702
|
-
if (!cidrIp || !prefixStr) return false;
|
|
2703
|
-
const prefix = parseInt(prefixStr, 10);
|
|
2704
|
-
if (isNaN(prefix)) return false;
|
|
2705
|
-
const ipBytes = expandIpv6(ip);
|
|
2706
|
-
const cidrBytes = expandIpv6(cidrIp);
|
|
2707
|
-
if (!ipBytes || !cidrBytes) return false;
|
|
2708
|
-
const fullBytes = Math.floor(prefix / 8);
|
|
2709
|
-
for (let i = 0; i < fullBytes && i < 16; i++) {
|
|
2710
|
-
if (ipBytes[i] !== cidrBytes[i]) return false;
|
|
2711
|
-
}
|
|
2712
|
-
const remainingBits = prefix % 8;
|
|
2713
|
-
if (remainingBits > 0 && fullBytes < 16) {
|
|
2714
|
-
const mask = ~0 << 8 - remainingBits & 255;
|
|
2715
|
-
if ((ipBytes[fullBytes] & mask) !== (cidrBytes[fullBytes] & mask)) return false;
|
|
2716
|
-
}
|
|
2717
|
-
return true;
|
|
2718
|
-
}
|
|
2719
|
-
function expandIpv6(ip) {
|
|
2720
|
-
const zoneIdx = ip.indexOf("%");
|
|
2721
|
-
if (zoneIdx !== -1) ip = ip.slice(0, zoneIdx);
|
|
2722
|
-
const parts = ip.split("::");
|
|
2723
|
-
if (parts.length > 2) return null;
|
|
2724
|
-
const bytes = new Array(16).fill(0);
|
|
2725
|
-
const expandGroup = (group) => {
|
|
2726
|
-
if (!group) return [];
|
|
2727
|
-
return group.split(":").flatMap((hex) => {
|
|
2728
|
-
const val = parseInt(hex || "0", 16);
|
|
2729
|
-
return [val >> 8 & 255, val & 255];
|
|
2730
|
-
});
|
|
2731
|
-
};
|
|
2732
|
-
if (parts.length === 1) {
|
|
2733
|
-
const expanded = expandGroup(parts[0]);
|
|
2734
|
-
if (expanded.length !== 16) return null;
|
|
2735
|
-
return expanded;
|
|
2736
|
-
}
|
|
2737
|
-
const left = expandGroup(parts[0]);
|
|
2738
|
-
const right = expandGroup(parts[1]);
|
|
2739
|
-
if (left.length + right.length > 16) return null;
|
|
2740
|
-
for (let i = 0; i < left.length; i++) bytes[i] = left[i];
|
|
2741
|
-
for (let i = 0; i < right.length; i++) bytes[16 - right.length + i] = right[i];
|
|
2742
|
-
return bytes;
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
2552
|
// http/fetchText.ts
|
|
2746
|
-
var
|
|
2553
|
+
var import_agent_tool9 = require("@easynet/agent-tool");
|
|
2554
|
+
var import_agent_tool10 = require("@easynet/agent-tool");
|
|
2747
2555
|
var fetchTextHandler = (async (args) => {
|
|
2748
2556
|
const ctx = getBuiltinContext();
|
|
2749
2557
|
const url = (args.url ?? args.uri)?.trim();
|
|
2750
2558
|
if (!url) {
|
|
2751
|
-
throw (0,
|
|
2559
|
+
throw (0, import_agent_tool10.createTaggedError)("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
|
|
2752
2560
|
}
|
|
2753
2561
|
const method = args.method ?? "GET";
|
|
2754
2562
|
const headers = args.headers ?? {};
|
|
2755
2563
|
const body = args.body ?? void 0;
|
|
2756
2564
|
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
2757
2565
|
const maxBytes = args.maxBytes ?? ctx.config.maxHttpBytes;
|
|
2758
|
-
await
|
|
2566
|
+
await (0, import_agent_tool9.validateUrl)(url, {
|
|
2567
|
+
allowedHosts: ctx.config.allowedHosts,
|
|
2568
|
+
blockedHosts: ctx.config.blockedHosts,
|
|
2569
|
+
blockedCidrs: ctx.config.blockedCidrs
|
|
2570
|
+
});
|
|
2759
2571
|
if (!headers["User-Agent"] && !headers["user-agent"]) {
|
|
2760
2572
|
headers["User-Agent"] = ctx.config.httpUserAgent;
|
|
2761
2573
|
}
|
|
@@ -2771,13 +2583,13 @@ var fetchTextHandler = (async (args) => {
|
|
|
2771
2583
|
});
|
|
2772
2584
|
} catch (err) {
|
|
2773
2585
|
if (err instanceof Error && err.name === "AbortError") {
|
|
2774
|
-
throw (0,
|
|
2586
|
+
throw (0, import_agent_tool10.createTaggedError)(
|
|
2775
2587
|
"HTTP_TIMEOUT",
|
|
2776
2588
|
`Request to ${url} timed out after ${timeoutMs}ms`,
|
|
2777
2589
|
{ url, timeoutMs }
|
|
2778
2590
|
);
|
|
2779
2591
|
}
|
|
2780
|
-
throw (0,
|
|
2592
|
+
throw (0, import_agent_tool10.createTaggedError)(
|
|
2781
2593
|
"UPSTREAM_ERROR",
|
|
2782
2594
|
`Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
2783
2595
|
{ url }
|
|
@@ -2787,7 +2599,7 @@ var fetchTextHandler = (async (args) => {
|
|
|
2787
2599
|
}
|
|
2788
2600
|
const contentLength = response.headers.get("content-length");
|
|
2789
2601
|
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
2790
|
-
throw (0,
|
|
2602
|
+
throw (0, import_agent_tool10.createTaggedError)(
|
|
2791
2603
|
"HTTP_TOO_LARGE",
|
|
2792
2604
|
`Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
2793
2605
|
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
@@ -2832,7 +2644,7 @@ async function readResponseWithLimit(response, maxBytes, url) {
|
|
|
2832
2644
|
totalBytes += value.byteLength;
|
|
2833
2645
|
if (totalBytes > maxBytes) {
|
|
2834
2646
|
reader.cancel();
|
|
2835
|
-
throw (0,
|
|
2647
|
+
throw (0, import_agent_tool10.createTaggedError)(
|
|
2836
2648
|
"HTTP_TOO_LARGE",
|
|
2837
2649
|
`Response body exceeded limit of ${maxBytes} bytes while reading from ${url}`,
|
|
2838
2650
|
{ url, bytesRead: totalBytes, limit: maxBytes }
|
|
@@ -2848,19 +2660,24 @@ async function readResponseWithLimit(response, maxBytes, url) {
|
|
|
2848
2660
|
}
|
|
2849
2661
|
|
|
2850
2662
|
// http/fetchJson.ts
|
|
2851
|
-
var
|
|
2663
|
+
var import_agent_tool11 = require("@easynet/agent-tool");
|
|
2664
|
+
var import_agent_tool12 = require("@easynet/agent-tool");
|
|
2852
2665
|
var fetchJsonHandler = (async (args) => {
|
|
2853
2666
|
const ctx = getBuiltinContext();
|
|
2854
2667
|
const url = (args.url ?? args.uri)?.trim();
|
|
2855
2668
|
if (!url) {
|
|
2856
|
-
throw (0,
|
|
2669
|
+
throw (0, import_agent_tool12.createTaggedError)("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
|
|
2857
2670
|
}
|
|
2858
2671
|
const method = args.method ?? "GET";
|
|
2859
2672
|
const headers = args.headers ?? {};
|
|
2860
2673
|
const body = args.body ?? void 0;
|
|
2861
2674
|
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
2862
2675
|
const maxBytes = args.maxBytes ?? ctx.config.maxHttpBytes;
|
|
2863
|
-
await
|
|
2676
|
+
await (0, import_agent_tool11.validateUrl)(url, {
|
|
2677
|
+
allowedHosts: ctx.config.allowedHosts,
|
|
2678
|
+
blockedHosts: ctx.config.blockedHosts,
|
|
2679
|
+
blockedCidrs: ctx.config.blockedCidrs
|
|
2680
|
+
});
|
|
2864
2681
|
if (!headers["Accept"] && !headers["accept"]) {
|
|
2865
2682
|
headers["Accept"] = "application/json";
|
|
2866
2683
|
}
|
|
@@ -2879,13 +2696,13 @@ var fetchJsonHandler = (async (args) => {
|
|
|
2879
2696
|
});
|
|
2880
2697
|
} catch (err) {
|
|
2881
2698
|
if (err instanceof Error && err.name === "AbortError") {
|
|
2882
|
-
throw (0,
|
|
2699
|
+
throw (0, import_agent_tool12.createTaggedError)(
|
|
2883
2700
|
"HTTP_TIMEOUT",
|
|
2884
2701
|
`Request to ${url} timed out after ${timeoutMs}ms`,
|
|
2885
2702
|
{ url, timeoutMs }
|
|
2886
2703
|
);
|
|
2887
2704
|
}
|
|
2888
|
-
throw (0,
|
|
2705
|
+
throw (0, import_agent_tool12.createTaggedError)(
|
|
2889
2706
|
"UPSTREAM_ERROR",
|
|
2890
2707
|
`Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
2891
2708
|
{ url }
|
|
@@ -2895,7 +2712,7 @@ var fetchJsonHandler = (async (args) => {
|
|
|
2895
2712
|
}
|
|
2896
2713
|
const contentLength = response.headers.get("content-length");
|
|
2897
2714
|
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
2898
|
-
throw (0,
|
|
2715
|
+
throw (0, import_agent_tool12.createTaggedError)(
|
|
2899
2716
|
"HTTP_TOO_LARGE",
|
|
2900
2717
|
`Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
2901
2718
|
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
@@ -2904,7 +2721,7 @@ var fetchJsonHandler = (async (args) => {
|
|
|
2904
2721
|
const text = await response.text();
|
|
2905
2722
|
const bytes = Buffer.byteLength(text, "utf-8");
|
|
2906
2723
|
if (bytes > maxBytes) {
|
|
2907
|
-
throw (0,
|
|
2724
|
+
throw (0, import_agent_tool12.createTaggedError)(
|
|
2908
2725
|
"HTTP_TOO_LARGE",
|
|
2909
2726
|
`Response body ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
|
|
2910
2727
|
{ url, bytes, limit: maxBytes }
|
|
@@ -2914,7 +2731,7 @@ var fetchJsonHandler = (async (args) => {
|
|
|
2914
2731
|
try {
|
|
2915
2732
|
json = JSON.parse(text);
|
|
2916
2733
|
} catch {
|
|
2917
|
-
throw (0,
|
|
2734
|
+
throw (0, import_agent_tool12.createTaggedError)(
|
|
2918
2735
|
"UPSTREAM_ERROR",
|
|
2919
2736
|
`Failed to parse JSON response from ${url}: ${text.slice(0, 200)}`,
|
|
2920
2737
|
{ url, status: response.status, textPreview: text.slice(0, 500) }
|
|
@@ -2939,30 +2756,35 @@ var fetchJsonHandler = (async (args) => {
|
|
|
2939
2756
|
});
|
|
2940
2757
|
|
|
2941
2758
|
// http/downloadFile.ts
|
|
2942
|
-
var
|
|
2759
|
+
var import_promises7 = require("fs/promises");
|
|
2943
2760
|
var import_node_crypto3 = require("crypto");
|
|
2944
|
-
var
|
|
2945
|
-
var
|
|
2761
|
+
var import_node_path4 = require("path");
|
|
2762
|
+
var import_agent_tool13 = require("@easynet/agent-tool");
|
|
2763
|
+
var import_agent_tool14 = require("@easynet/agent-tool");
|
|
2946
2764
|
var downloadFileHandler = (async (args) => {
|
|
2947
2765
|
const ctx = getBuiltinContext();
|
|
2948
2766
|
const url = (args.url ?? args.uri)?.trim();
|
|
2949
2767
|
if (!url) {
|
|
2950
|
-
throw (0,
|
|
2768
|
+
throw (0, import_agent_tool14.createTaggedError)("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
|
|
2951
2769
|
}
|
|
2952
2770
|
const destPath = (args.destPath ?? args.destination ?? args.filePath)?.trim();
|
|
2953
2771
|
if (!destPath) {
|
|
2954
|
-
throw (0,
|
|
2772
|
+
throw (0, import_agent_tool14.createTaggedError)("HTTP_INVALID", "destPath is required (pass 'destPath', 'destination', or 'filePath')", {});
|
|
2955
2773
|
}
|
|
2956
2774
|
const headers = args.headers ?? {};
|
|
2957
2775
|
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
2958
2776
|
const maxBytes = args.maxBytes ?? ctx.config.maxDownloadBytes;
|
|
2959
2777
|
const overwrite = args.overwrite ?? false;
|
|
2960
|
-
await
|
|
2961
|
-
|
|
2778
|
+
await (0, import_agent_tool13.validateUrl)(url, {
|
|
2779
|
+
allowedHosts: ctx.config.allowedHosts,
|
|
2780
|
+
blockedHosts: ctx.config.blockedHosts,
|
|
2781
|
+
blockedCidrs: ctx.config.blockedCidrs
|
|
2782
|
+
});
|
|
2783
|
+
const resolvedDest = await (0, import_agent_tool13.resolveSandboxedPath)(destPath, ctx.config.sandboxRoot);
|
|
2962
2784
|
if (!overwrite) {
|
|
2963
|
-
const { access
|
|
2785
|
+
const { access } = await import("fs/promises");
|
|
2964
2786
|
try {
|
|
2965
|
-
await
|
|
2787
|
+
await access(resolvedDest);
|
|
2966
2788
|
throw new Error(
|
|
2967
2789
|
`File already exists: ${resolvedDest}. Set overwrite=true to allow overwriting.`
|
|
2968
2790
|
);
|
|
@@ -2987,13 +2809,13 @@ var downloadFileHandler = (async (args) => {
|
|
|
2987
2809
|
});
|
|
2988
2810
|
} catch (err) {
|
|
2989
2811
|
if (err instanceof Error && err.name === "AbortError") {
|
|
2990
|
-
throw (0,
|
|
2812
|
+
throw (0, import_agent_tool14.createTaggedError)(
|
|
2991
2813
|
"HTTP_TIMEOUT",
|
|
2992
2814
|
`Download from ${url} timed out after ${timeoutMs}ms`,
|
|
2993
2815
|
{ url, timeoutMs }
|
|
2994
2816
|
);
|
|
2995
2817
|
}
|
|
2996
|
-
throw (0,
|
|
2818
|
+
throw (0, import_agent_tool14.createTaggedError)(
|
|
2997
2819
|
"UPSTREAM_ERROR",
|
|
2998
2820
|
`Download failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
2999
2821
|
{ url }
|
|
@@ -3003,14 +2825,14 @@ var downloadFileHandler = (async (args) => {
|
|
|
3003
2825
|
}
|
|
3004
2826
|
const contentLength = response.headers.get("content-length");
|
|
3005
2827
|
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
3006
|
-
throw (0,
|
|
2828
|
+
throw (0, import_agent_tool14.createTaggedError)(
|
|
3007
2829
|
"HTTP_TOO_LARGE",
|
|
3008
2830
|
`Download Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
3009
2831
|
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
3010
2832
|
);
|
|
3011
2833
|
}
|
|
3012
2834
|
if (!response.body) {
|
|
3013
|
-
throw (0,
|
|
2835
|
+
throw (0, import_agent_tool14.createTaggedError)("UPSTREAM_ERROR", `No response body from ${url}`, { url });
|
|
3014
2836
|
}
|
|
3015
2837
|
const reader = response.body.getReader();
|
|
3016
2838
|
const chunks = [];
|
|
@@ -3023,7 +2845,7 @@ var downloadFileHandler = (async (args) => {
|
|
|
3023
2845
|
totalBytes += value.byteLength;
|
|
3024
2846
|
if (totalBytes > maxBytes) {
|
|
3025
2847
|
reader.cancel();
|
|
3026
|
-
throw (0,
|
|
2848
|
+
throw (0, import_agent_tool14.createTaggedError)(
|
|
3027
2849
|
"HTTP_TOO_LARGE",
|
|
3028
2850
|
`Download from ${url} exceeded limit of ${maxBytes} bytes (received ${totalBytes})`,
|
|
3029
2851
|
{ url, bytesRead: totalBytes, limit: maxBytes }
|
|
@@ -3036,9 +2858,9 @@ var downloadFileHandler = (async (args) => {
|
|
|
3036
2858
|
reader.releaseLock();
|
|
3037
2859
|
}
|
|
3038
2860
|
const sha256 = hasher.digest("hex");
|
|
3039
|
-
await (0,
|
|
2861
|
+
await (0, import_promises7.mkdir)((0, import_node_path4.dirname)(resolvedDest), { recursive: true });
|
|
3040
2862
|
const buffer = Buffer.concat(chunks);
|
|
3041
|
-
await (0,
|
|
2863
|
+
await (0, import_promises7.writeFile)(resolvedDest, buffer);
|
|
3042
2864
|
return {
|
|
3043
2865
|
result: {
|
|
3044
2866
|
destPath: resolvedDest,
|
|
@@ -3065,16 +2887,21 @@ var downloadFileHandler = (async (args) => {
|
|
|
3065
2887
|
});
|
|
3066
2888
|
|
|
3067
2889
|
// http/head.ts
|
|
3068
|
-
var
|
|
2890
|
+
var import_agent_tool15 = require("@easynet/agent-tool");
|
|
2891
|
+
var import_agent_tool16 = require("@easynet/agent-tool");
|
|
3069
2892
|
var headHandler = (async (args) => {
|
|
3070
2893
|
const ctx = getBuiltinContext();
|
|
3071
2894
|
const url = (args.url ?? args.uri)?.trim();
|
|
3072
2895
|
if (!url) {
|
|
3073
|
-
throw (0,
|
|
2896
|
+
throw (0, import_agent_tool16.createTaggedError)("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
|
|
3074
2897
|
}
|
|
3075
2898
|
const headers = args.headers ?? {};
|
|
3076
2899
|
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
3077
|
-
await
|
|
2900
|
+
await (0, import_agent_tool15.validateUrl)(url, {
|
|
2901
|
+
allowedHosts: ctx.config.allowedHosts,
|
|
2902
|
+
blockedHosts: ctx.config.blockedHosts,
|
|
2903
|
+
blockedCidrs: ctx.config.blockedCidrs
|
|
2904
|
+
});
|
|
3078
2905
|
if (!headers["User-Agent"] && !headers["user-agent"]) {
|
|
3079
2906
|
headers["User-Agent"] = ctx.config.httpUserAgent;
|
|
3080
2907
|
}
|
|
@@ -3089,13 +2916,13 @@ var headHandler = (async (args) => {
|
|
|
3089
2916
|
});
|
|
3090
2917
|
} catch (err) {
|
|
3091
2918
|
if (err instanceof Error && err.name === "AbortError") {
|
|
3092
|
-
throw (0,
|
|
2919
|
+
throw (0, import_agent_tool16.createTaggedError)(
|
|
3093
2920
|
"HTTP_TIMEOUT",
|
|
3094
2921
|
`HEAD request to ${url} timed out after ${timeoutMs}ms`,
|
|
3095
2922
|
{ url, timeoutMs }
|
|
3096
2923
|
);
|
|
3097
2924
|
}
|
|
3098
|
-
throw (0,
|
|
2925
|
+
throw (0, import_agent_tool16.createTaggedError)(
|
|
3099
2926
|
"UPSTREAM_ERROR",
|
|
3100
2927
|
`HEAD request failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
3101
2928
|
{ url }
|
|
@@ -3125,18 +2952,23 @@ var headHandler = (async (args) => {
|
|
|
3125
2952
|
});
|
|
3126
2953
|
|
|
3127
2954
|
// http/duckduckgoSearch.ts
|
|
3128
|
-
var
|
|
2955
|
+
var import_agent_tool17 = require("@easynet/agent-tool");
|
|
2956
|
+
var import_agent_tool18 = require("@easynet/agent-tool");
|
|
3129
2957
|
var DUCKDUCKGO_API = "https://api.duckduckgo.com/";
|
|
3130
2958
|
var duckduckgoSearchHandler = (async (args) => {
|
|
3131
2959
|
const ctx = getBuiltinContext();
|
|
3132
2960
|
const query = (args.query ?? args.q)?.trim();
|
|
3133
2961
|
if (!query) {
|
|
3134
|
-
throw (0,
|
|
2962
|
+
throw (0, import_agent_tool18.createTaggedError)("DUCKDUCKGO_INVALID", "query is required (pass 'query' or 'q')", {});
|
|
3135
2963
|
}
|
|
3136
2964
|
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
3137
2965
|
const maxResults = args.maxResults ?? 10;
|
|
3138
2966
|
const url = `${DUCKDUCKGO_API}?q=${encodeURIComponent(query)}&format=json`;
|
|
3139
|
-
await
|
|
2967
|
+
await (0, import_agent_tool17.validateUrl)(url, {
|
|
2968
|
+
allowedHosts: ctx.config.allowedHosts,
|
|
2969
|
+
blockedHosts: ctx.config.blockedHosts,
|
|
2970
|
+
blockedCidrs: ctx.config.blockedCidrs
|
|
2971
|
+
});
|
|
3140
2972
|
const controller = new AbortController();
|
|
3141
2973
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3142
2974
|
let response;
|
|
@@ -3149,13 +2981,13 @@ var duckduckgoSearchHandler = (async (args) => {
|
|
|
3149
2981
|
} catch (err) {
|
|
3150
2982
|
clearTimeout(timer);
|
|
3151
2983
|
if (err instanceof Error && err.name === "AbortError") {
|
|
3152
|
-
throw (0,
|
|
2984
|
+
throw (0, import_agent_tool18.createTaggedError)(
|
|
3153
2985
|
"HTTP_TIMEOUT",
|
|
3154
2986
|
`DuckDuckGo search timed out after ${timeoutMs}ms`,
|
|
3155
2987
|
{ query, timeoutMs }
|
|
3156
2988
|
);
|
|
3157
2989
|
}
|
|
3158
|
-
throw (0,
|
|
2990
|
+
throw (0, import_agent_tool18.createTaggedError)(
|
|
3159
2991
|
"UPSTREAM_ERROR",
|
|
3160
2992
|
`DuckDuckGo search failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
3161
2993
|
{ query }
|
|
@@ -3166,7 +2998,7 @@ var duckduckgoSearchHandler = (async (args) => {
|
|
|
3166
2998
|
const text = await response.text();
|
|
3167
2999
|
const bytes = Buffer.byteLength(text, "utf-8");
|
|
3168
3000
|
if (bytes > maxBytes) {
|
|
3169
|
-
throw (0,
|
|
3001
|
+
throw (0, import_agent_tool18.createTaggedError)(
|
|
3170
3002
|
"HTTP_TOO_LARGE",
|
|
3171
3003
|
`DuckDuckGo response ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
|
|
3172
3004
|
{ query, bytes, limit: maxBytes }
|
|
@@ -3176,7 +3008,7 @@ var duckduckgoSearchHandler = (async (args) => {
|
|
|
3176
3008
|
try {
|
|
3177
3009
|
raw = JSON.parse(text);
|
|
3178
3010
|
} catch {
|
|
3179
|
-
throw (0,
|
|
3011
|
+
throw (0, import_agent_tool18.createTaggedError)(
|
|
3180
3012
|
"UPSTREAM_ERROR",
|
|
3181
3013
|
`DuckDuckGo returned invalid JSON`,
|
|
3182
3014
|
{ query, textPreview: text.slice(0, 200) }
|
|
@@ -3227,7 +3059,8 @@ var duckduckgoSearchHandler = (async (args) => {
|
|
|
3227
3059
|
|
|
3228
3060
|
// http/fetchPageMainContent.ts
|
|
3229
3061
|
var import_node_html_parser = require("node-html-parser");
|
|
3230
|
-
var
|
|
3062
|
+
var import_agent_tool19 = require("@easynet/agent-tool");
|
|
3063
|
+
var import_agent_tool20 = require("@easynet/agent-tool");
|
|
3231
3064
|
var MAIN_SELECTORS = [
|
|
3232
3065
|
"main",
|
|
3233
3066
|
"article",
|
|
@@ -3270,11 +3103,15 @@ var fetchPageMainContentHandler = (async (args) => {
|
|
|
3270
3103
|
const ctx = getBuiltinContext();
|
|
3271
3104
|
const url = (args.url ?? args.uri)?.trim();
|
|
3272
3105
|
if (!url) {
|
|
3273
|
-
throw (0,
|
|
3106
|
+
throw (0, import_agent_tool20.createTaggedError)("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
|
|
3274
3107
|
}
|
|
3275
3108
|
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
3276
3109
|
const maxBytes = args.maxBytes ?? ctx.config.maxHttpBytes;
|
|
3277
|
-
await
|
|
3110
|
+
await (0, import_agent_tool19.validateUrl)(url, {
|
|
3111
|
+
allowedHosts: ctx.config.allowedHosts,
|
|
3112
|
+
blockedHosts: ctx.config.blockedHosts,
|
|
3113
|
+
blockedCidrs: ctx.config.blockedCidrs
|
|
3114
|
+
});
|
|
3278
3115
|
const controller = new AbortController();
|
|
3279
3116
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3280
3117
|
let response;
|
|
@@ -3287,13 +3124,13 @@ var fetchPageMainContentHandler = (async (args) => {
|
|
|
3287
3124
|
} catch (err) {
|
|
3288
3125
|
clearTimeout(timer);
|
|
3289
3126
|
if (err instanceof Error && err.name === "AbortError") {
|
|
3290
|
-
throw (0,
|
|
3127
|
+
throw (0, import_agent_tool20.createTaggedError)(
|
|
3291
3128
|
"HTTP_TIMEOUT",
|
|
3292
3129
|
`Request to ${url} timed out after ${timeoutMs}ms`,
|
|
3293
3130
|
{ url, timeoutMs }
|
|
3294
3131
|
);
|
|
3295
3132
|
}
|
|
3296
|
-
throw (0,
|
|
3133
|
+
throw (0, import_agent_tool20.createTaggedError)(
|
|
3297
3134
|
"UPSTREAM_ERROR",
|
|
3298
3135
|
`Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
3299
3136
|
{ url }
|
|
@@ -3302,7 +3139,7 @@ var fetchPageMainContentHandler = (async (args) => {
|
|
|
3302
3139
|
clearTimeout(timer);
|
|
3303
3140
|
const contentLength = response.headers.get("content-length");
|
|
3304
3141
|
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
3305
|
-
throw (0,
|
|
3142
|
+
throw (0, import_agent_tool20.createTaggedError)(
|
|
3306
3143
|
"HTTP_TOO_LARGE",
|
|
3307
3144
|
`Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
3308
3145
|
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
@@ -3311,7 +3148,7 @@ var fetchPageMainContentHandler = (async (args) => {
|
|
|
3311
3148
|
const rawText = await response.text();
|
|
3312
3149
|
const rawBytes = Buffer.byteLength(rawText, "utf-8");
|
|
3313
3150
|
if (rawBytes > maxBytes) {
|
|
3314
|
-
throw (0,
|
|
3151
|
+
throw (0, import_agent_tool20.createTaggedError)(
|
|
3315
3152
|
"HTTP_TOO_LARGE",
|
|
3316
3153
|
`Response body ${rawBytes} bytes exceeds limit of ${maxBytes} bytes`,
|
|
3317
3154
|
{ url, bytes: rawBytes, limit: maxBytes }
|
|
@@ -3354,14 +3191,15 @@ var fetchPageMainContentHandler = (async (args) => {
|
|
|
3354
3191
|
});
|
|
3355
3192
|
|
|
3356
3193
|
// http/yahooFinance.ts
|
|
3357
|
-
var
|
|
3194
|
+
var import_agent_tool21 = require("@easynet/agent-tool");
|
|
3195
|
+
var import_agent_tool22 = require("@easynet/agent-tool");
|
|
3358
3196
|
var YAHOO_CHART_BASE = "https://query1.finance.yahoo.com/v8/finance/chart/";
|
|
3359
3197
|
var yahooFinanceQuoteHandler = (async (args) => {
|
|
3360
3198
|
const ctx = getBuiltinContext();
|
|
3361
3199
|
const rawSymbols = args.symbols ?? args.symbol ?? args.tickers;
|
|
3362
3200
|
const symbols = Array.isArray(rawSymbols) ? rawSymbols.map((s) => String(s).trim().toUpperCase()).filter(Boolean) : rawSymbols != null ? [String(rawSymbols).trim().toUpperCase()].filter(Boolean) : [];
|
|
3363
3201
|
if (symbols.length === 0) {
|
|
3364
|
-
throw (0,
|
|
3202
|
+
throw (0, import_agent_tool22.createTaggedError)(
|
|
3365
3203
|
"YAHOO_INVALID",
|
|
3366
3204
|
"At least one symbol is required",
|
|
3367
3205
|
{}
|
|
@@ -3373,7 +3211,11 @@ var yahooFinanceQuoteHandler = (async (args) => {
|
|
|
3373
3211
|
const quotes = [];
|
|
3374
3212
|
for (const symbol of symbols) {
|
|
3375
3213
|
const url2 = `${YAHOO_CHART_BASE}${encodeURIComponent(symbol)}?interval=1d&range=${range}`;
|
|
3376
|
-
await
|
|
3214
|
+
await (0, import_agent_tool21.validateUrl)(url2, {
|
|
3215
|
+
allowedHosts: ctx.config.allowedHosts,
|
|
3216
|
+
blockedHosts: ctx.config.blockedHosts,
|
|
3217
|
+
blockedCidrs: ctx.config.blockedCidrs
|
|
3218
|
+
});
|
|
3377
3219
|
const controller = new AbortController();
|
|
3378
3220
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3379
3221
|
let response;
|
|
@@ -3389,13 +3231,13 @@ var yahooFinanceQuoteHandler = (async (args) => {
|
|
|
3389
3231
|
} catch (err) {
|
|
3390
3232
|
clearTimeout(timer);
|
|
3391
3233
|
if (err instanceof Error && err.name === "AbortError") {
|
|
3392
|
-
throw (0,
|
|
3234
|
+
throw (0, import_agent_tool22.createTaggedError)(
|
|
3393
3235
|
"HTTP_TIMEOUT",
|
|
3394
3236
|
`Yahoo Finance request for ${symbol} timed out after ${timeoutMs}ms`,
|
|
3395
3237
|
{ symbol, timeoutMs }
|
|
3396
3238
|
);
|
|
3397
3239
|
}
|
|
3398
|
-
throw (0,
|
|
3240
|
+
throw (0, import_agent_tool22.createTaggedError)(
|
|
3399
3241
|
"UPSTREAM_ERROR",
|
|
3400
3242
|
`Yahoo Finance request failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
3401
3243
|
{ symbol }
|
|
@@ -3405,7 +3247,7 @@ var yahooFinanceQuoteHandler = (async (args) => {
|
|
|
3405
3247
|
const text = await response.text();
|
|
3406
3248
|
const bytes = Buffer.byteLength(text, "utf-8");
|
|
3407
3249
|
if (bytes > maxBytes) {
|
|
3408
|
-
throw (0,
|
|
3250
|
+
throw (0, import_agent_tool22.createTaggedError)(
|
|
3409
3251
|
"HTTP_TOO_LARGE",
|
|
3410
3252
|
`Yahoo Finance response ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
|
|
3411
3253
|
{ symbol, bytes, limit: maxBytes }
|
|
@@ -3415,7 +3257,7 @@ var yahooFinanceQuoteHandler = (async (args) => {
|
|
|
3415
3257
|
try {
|
|
3416
3258
|
data = JSON.parse(text);
|
|
3417
3259
|
} catch {
|
|
3418
|
-
throw (0,
|
|
3260
|
+
throw (0, import_agent_tool22.createTaggedError)(
|
|
3419
3261
|
"UPSTREAM_ERROR",
|
|
3420
3262
|
"Yahoo Finance returned invalid JSON",
|
|
3421
3263
|
{ symbol, textPreview: text.slice(0, 200) }
|
|
@@ -3423,7 +3265,7 @@ var yahooFinanceQuoteHandler = (async (args) => {
|
|
|
3423
3265
|
}
|
|
3424
3266
|
const error = data.chart?.error;
|
|
3425
3267
|
if (error?.description) {
|
|
3426
|
-
throw (0,
|
|
3268
|
+
throw (0, import_agent_tool22.createTaggedError)(
|
|
3427
3269
|
"YAHOO_ERROR",
|
|
3428
3270
|
`Yahoo Finance error for ${symbol}: ${error.description}`,
|
|
3429
3271
|
{ symbol, code: error.code }
|
|
@@ -3635,13 +3477,14 @@ var templateRenderHandler = (async (args) => {
|
|
|
3635
3477
|
|
|
3636
3478
|
// exec/runCommand.ts
|
|
3637
3479
|
var import_node_child_process = require("child_process");
|
|
3638
|
-
var
|
|
3639
|
-
var
|
|
3480
|
+
var import_node_path5 = require("path");
|
|
3481
|
+
var import_agent_tool23 = require("@easynet/agent-tool");
|
|
3482
|
+
var import_agent_tool24 = require("@easynet/agent-tool");
|
|
3640
3483
|
var runCommandHandler = (async (args) => {
|
|
3641
3484
|
const ctx = getBuiltinContext();
|
|
3642
3485
|
const { allowedCommands, maxCommandOutputBytes, commandTimeoutMs } = ctx.config;
|
|
3643
3486
|
if (!allowedCommands.length) {
|
|
3644
|
-
throw (0,
|
|
3487
|
+
throw (0, import_agent_tool24.createTaggedError)(
|
|
3645
3488
|
"EXEC_DISABLED",
|
|
3646
3489
|
"Exec is disabled: allowedCommands is empty",
|
|
3647
3490
|
{}
|
|
@@ -3649,18 +3492,18 @@ var runCommandHandler = (async (args) => {
|
|
|
3649
3492
|
}
|
|
3650
3493
|
const rawCommand = (args.command ?? args.cmd)?.trim();
|
|
3651
3494
|
if (!rawCommand) {
|
|
3652
|
-
throw (0,
|
|
3495
|
+
throw (0, import_agent_tool24.createTaggedError)("EXEC_INVALID", "command is required (pass 'command' or 'cmd')", {});
|
|
3653
3496
|
}
|
|
3654
3497
|
const baseName = rawCommand.replace(/^.*\//, "").trim();
|
|
3655
3498
|
if (baseName !== rawCommand || /[;&|$`\s]/.test(rawCommand)) {
|
|
3656
|
-
throw (0,
|
|
3499
|
+
throw (0, import_agent_tool24.createTaggedError)(
|
|
3657
3500
|
"EXEC_INVALID",
|
|
3658
3501
|
"command must be a single executable name (no path, no shell chars)",
|
|
3659
3502
|
{ command: rawCommand }
|
|
3660
3503
|
);
|
|
3661
3504
|
}
|
|
3662
3505
|
if (!allowedCommands.includes(baseName)) {
|
|
3663
|
-
throw (0,
|
|
3506
|
+
throw (0, import_agent_tool24.createTaggedError)(
|
|
3664
3507
|
"EXEC_NOT_ALLOWED",
|
|
3665
3508
|
`Command "${baseName}" is not in allowedCommands`,
|
|
3666
3509
|
{ command: baseName, allowed: allowedCommands }
|
|
@@ -3668,9 +3511,9 @@ var runCommandHandler = (async (args) => {
|
|
|
3668
3511
|
}
|
|
3669
3512
|
const cmdArgs = Array.isArray(args.args) ? args.args : Array.isArray(args.arguments) ? args.arguments : [];
|
|
3670
3513
|
const timeoutMs = args.timeoutMs ?? commandTimeoutMs;
|
|
3671
|
-
let cwd = (0,
|
|
3514
|
+
let cwd = (0, import_node_path5.resolve)(ctx.config.sandboxRoot);
|
|
3672
3515
|
if (args.cwd != null && args.cwd !== "") {
|
|
3673
|
-
cwd = await resolveSandboxedPath(args.cwd, ctx.config.sandboxRoot);
|
|
3516
|
+
cwd = await (0, import_agent_tool23.resolveSandboxedPath)(args.cwd, ctx.config.sandboxRoot);
|
|
3674
3517
|
}
|
|
3675
3518
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
3676
3519
|
const proc = (0, import_node_child_process.spawn)(baseName, cmdArgs, {
|
|
@@ -3687,7 +3530,7 @@ var runCommandHandler = (async (args) => {
|
|
|
3687
3530
|
if (totalBytes + len > maxCommandOutputBytes) {
|
|
3688
3531
|
proc.kill("SIGKILL");
|
|
3689
3532
|
rejectPromise(
|
|
3690
|
-
(0,
|
|
3533
|
+
(0, import_agent_tool24.createTaggedError)(
|
|
3691
3534
|
"EXEC_OUTPUT_TOO_LARGE",
|
|
3692
3535
|
`Command output exceeded ${maxCommandOutputBytes} bytes`,
|
|
3693
3536
|
{ maxBytes: maxCommandOutputBytes }
|
|
@@ -3725,7 +3568,7 @@ var runCommandHandler = (async (args) => {
|
|
|
3725
3568
|
proc.on("error", (err) => {
|
|
3726
3569
|
clearTimeout(timeout);
|
|
3727
3570
|
rejectPromise(
|
|
3728
|
-
(0,
|
|
3571
|
+
(0, import_agent_tool24.createTaggedError)("EXEC_SPAWN_ERROR", err.message, { command: baseName })
|
|
3729
3572
|
);
|
|
3730
3573
|
});
|
|
3731
3574
|
proc.on("close", (code, signal) => {
|
|
@@ -3959,7 +3802,8 @@ var CORE_GROUP_PREFIX = {
|
|
|
3959
3802
|
function registerCoreTools(registry, userConfig, options) {
|
|
3960
3803
|
const config = {
|
|
3961
3804
|
...DEFAULT_CORE_TOOLS_CONFIG,
|
|
3962
|
-
...userConfig
|
|
3805
|
+
...userConfig,
|
|
3806
|
+
blockedHosts: userConfig.blockedHosts ?? []
|
|
3963
3807
|
};
|
|
3964
3808
|
const adapter = new CoreAdapter(config);
|
|
3965
3809
|
const onlySet = options?.only?.length ? new Set(options.only) : null;
|
|
@@ -3976,6 +3820,9 @@ function registerCoreTools(registry, userConfig, options) {
|
|
|
3976
3820
|
}
|
|
3977
3821
|
return adapter;
|
|
3978
3822
|
}
|
|
3823
|
+
|
|
3824
|
+
// index.ts
|
|
3825
|
+
var import_agent_tool25 = require("@easynet/agent-tool");
|
|
3979
3826
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3980
3827
|
0 && (module.exports = {
|
|
3981
3828
|
CoreAdapter,
|