@agentforge/tools 0.16.76 → 0.16.78
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/README.md +21 -0
- package/dist/index.cjs +479 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +148 -63
- package/dist/index.d.ts +148 -63
- package/dist/index.js +468 -118
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var core = require('@agentforge/core');
|
|
4
|
-
var
|
|
4
|
+
var promises = require('dns/promises');
|
|
5
|
+
var net = require('net');
|
|
6
|
+
var axios13 = require('axios');
|
|
5
7
|
var zod = require('zod');
|
|
6
8
|
var cheerio = require('cheerio');
|
|
7
9
|
var webApi = require('@slack/web-api');
|
|
@@ -14,7 +16,7 @@ var events = require('events');
|
|
|
14
16
|
var stream = require('stream');
|
|
15
17
|
var crypto = require('crypto');
|
|
16
18
|
var fs = require('fs');
|
|
17
|
-
var
|
|
19
|
+
var path = require('path');
|
|
18
20
|
var dateFns = require('date-fns');
|
|
19
21
|
|
|
20
22
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -37,10 +39,11 @@ function _interopNamespace(e) {
|
|
|
37
39
|
return Object.freeze(n);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
var
|
|
42
|
+
var net__default = /*#__PURE__*/_interopDefault(net);
|
|
43
|
+
var axios13__default = /*#__PURE__*/_interopDefault(axios13);
|
|
41
44
|
var cheerio__namespace = /*#__PURE__*/_interopNamespace(cheerio);
|
|
42
45
|
var neo4j__default = /*#__PURE__*/_interopDefault(neo4j);
|
|
43
|
-
var
|
|
46
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
44
47
|
|
|
45
48
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
46
49
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
@@ -48,6 +51,204 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
48
51
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
49
52
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
50
53
|
});
|
|
54
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
55
|
+
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
56
|
+
var IPV4_MAPPED_NETWORK = "::ffff:0:0";
|
|
57
|
+
var SENSITIVE_REDIRECT_HEADERS = /* @__PURE__ */ new Set(["authorization", "cookie", "proxy-authorization"]);
|
|
58
|
+
var DEFAULT_DESTINATION_POLICY = Object.freeze({
|
|
59
|
+
allowLocalhost: false,
|
|
60
|
+
allowPrivateNetwork: false,
|
|
61
|
+
allowLinkLocal: false,
|
|
62
|
+
allowMetadata: false,
|
|
63
|
+
allowRedirects: true,
|
|
64
|
+
maxRedirects: DEFAULT_MAX_REDIRECTS
|
|
65
|
+
});
|
|
66
|
+
var DestinationPolicyError = class extends Error {
|
|
67
|
+
constructor(url, reason, message) {
|
|
68
|
+
super(message);
|
|
69
|
+
this.url = url;
|
|
70
|
+
this.reason = reason;
|
|
71
|
+
this.name = "DestinationPolicyError";
|
|
72
|
+
}
|
|
73
|
+
code = "WEB_DESTINATION_BLOCKED";
|
|
74
|
+
};
|
|
75
|
+
function ipv4ToNumber(address) {
|
|
76
|
+
const octets = address.split(".").map(Number);
|
|
77
|
+
if (octets.length !== 4 || octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) return void 0;
|
|
78
|
+
return ((octets[0] * 256 + octets[1]) * 256 + octets[2]) * 256 + octets[3] >>> 0;
|
|
79
|
+
}
|
|
80
|
+
function ipv4InCidr(address, network, prefix) {
|
|
81
|
+
const value = ipv4ToNumber(address);
|
|
82
|
+
const networkValue = ipv4ToNumber(network);
|
|
83
|
+
if (value === void 0 || networkValue === void 0) return false;
|
|
84
|
+
const mask = prefix === 0 ? 0 : 4294967295 << 32 - prefix >>> 0;
|
|
85
|
+
return (value & mask) === (networkValue & mask);
|
|
86
|
+
}
|
|
87
|
+
function expandIpv6(address) {
|
|
88
|
+
const normalized = address.toLowerCase().split("%")[0];
|
|
89
|
+
let input = normalized;
|
|
90
|
+
const ipv4Start = normalized.lastIndexOf(":") + 1;
|
|
91
|
+
const ipv4 = normalized.slice(ipv4Start);
|
|
92
|
+
if (net__default.default.isIP(ipv4) === 4) {
|
|
93
|
+
const value = ipv4ToNumber(ipv4);
|
|
94
|
+
if (value === void 0) return void 0;
|
|
95
|
+
input = `${normalized.slice(0, ipv4Start)}${(value >>> 16).toString(16)}:${(value & 65535).toString(16)}`;
|
|
96
|
+
}
|
|
97
|
+
const halves = input.split("::");
|
|
98
|
+
if (halves.length > 2) return void 0;
|
|
99
|
+
const left = halves[0] ? halves[0].split(":").filter(Boolean) : [];
|
|
100
|
+
const right = halves.length === 2 && halves[1] ? halves[1].split(":").filter(Boolean) : [];
|
|
101
|
+
const missing = 8 - left.length - right.length;
|
|
102
|
+
if (missing < 0 || halves.length === 1 && missing !== 0) return void 0;
|
|
103
|
+
const groups = [...left, ...Array.from({ length: missing }, () => "0"), ...right];
|
|
104
|
+
if (groups.length !== 8 || groups.some((group) => !/^[0-9a-f]{1,4}$/.test(group))) return void 0;
|
|
105
|
+
return groups.reduce((value, group) => value << 16n | BigInt(parseInt(group, 16)), 0n);
|
|
106
|
+
}
|
|
107
|
+
function ipv6InCidr(address, network, prefix) {
|
|
108
|
+
return prefix === 0 || address >> BigInt(128 - prefix) === network >> BigInt(128 - prefix);
|
|
109
|
+
}
|
|
110
|
+
function ipv6ToIpv4(address) {
|
|
111
|
+
const mappedNetwork = expandIpv6(IPV4_MAPPED_NETWORK);
|
|
112
|
+
if (mappedNetwork === void 0 || !ipv6InCidr(address, mappedNetwork, 96)) return void 0;
|
|
113
|
+
const value = Number(address & 0xffffffffn) >>> 0;
|
|
114
|
+
return [value >>> 24, value >>> 16 & 255, value >>> 8 & 255, value & 255].join(".");
|
|
115
|
+
}
|
|
116
|
+
function classifyIp(address) {
|
|
117
|
+
const normalized = address.replace(/^\[|\]$/g, "").toLowerCase();
|
|
118
|
+
const version = net__default.default.isIP(normalized);
|
|
119
|
+
if (version === 4) {
|
|
120
|
+
if (normalized === "169.254.169.254") return "metadata";
|
|
121
|
+
if (ipv4InCidr(normalized, "127.0.0.0", 8)) return "localhost";
|
|
122
|
+
if (ipv4InCidr(normalized, "169.254.0.0", 16)) return "link-local";
|
|
123
|
+
if (ipv4InCidr(normalized, "10.0.0.0", 8) || ipv4InCidr(normalized, "172.16.0.0", 12) || ipv4InCidr(normalized, "192.168.0.0", 16) || ipv4InCidr(normalized, "100.64.0.0", 10)) return "private-network";
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
if (version !== 6) return void 0;
|
|
127
|
+
const value = expandIpv6(normalized);
|
|
128
|
+
if (value === void 0) return void 0;
|
|
129
|
+
const mappedIpv4 = ipv6ToIpv4(value);
|
|
130
|
+
if (mappedIpv4) return classifyIp(mappedIpv4);
|
|
131
|
+
if (value === expandIpv6("fd00:ec2::254")) return "metadata";
|
|
132
|
+
if (value === expandIpv6("::1")) return "localhost";
|
|
133
|
+
if (ipv6InCidr(value, expandIpv6("fe80::"), 10)) return "link-local";
|
|
134
|
+
if (ipv6InCidr(value, expandIpv6("fc00::"), 7)) return "private-network";
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
function classifyHostname(hostname) {
|
|
138
|
+
const normalized = hostname.toLowerCase().replace(/\.$/, "");
|
|
139
|
+
if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "localhost.localdomain") return "localhost";
|
|
140
|
+
if (normalized === "metadata" || normalized === "metadata.google.internal" || normalized === "instance-data") return "metadata";
|
|
141
|
+
return classifyIp(normalized);
|
|
142
|
+
}
|
|
143
|
+
function policyAllows(reason, policy) {
|
|
144
|
+
if (reason === "localhost") return policy.allowLocalhost === true;
|
|
145
|
+
if (reason === "metadata") return policy.allowMetadata === true;
|
|
146
|
+
if (reason === "private-network") return policy.allowPrivateNetwork === true;
|
|
147
|
+
if (reason === "link-local") return policy.allowLinkLocal === true;
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
async function resolveDestinationAddresses(hostname) {
|
|
151
|
+
try {
|
|
152
|
+
const addresses = await promises.lookup(hostname, { all: true, verbatim: true });
|
|
153
|
+
return addresses.map(({ address, family }) => ({ address, family }));
|
|
154
|
+
} catch (error) {
|
|
155
|
+
throw new DestinationPolicyError(hostname, "dns-resolution-failed", `Destination policy could not resolve hostname "${hostname}" before making a request: ${error instanceof Error ? error.message : String(error)}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function blockDestination(url, reason) {
|
|
159
|
+
throw new DestinationPolicyError(url, reason, `Destination blocked by web egress policy (${reason}): ${url}`);
|
|
160
|
+
}
|
|
161
|
+
async function validateDestinationAllowed(url, policy) {
|
|
162
|
+
const effectivePolicy = { ...DEFAULT_DESTINATION_POLICY, ...policy };
|
|
163
|
+
let parsed;
|
|
164
|
+
try {
|
|
165
|
+
parsed = new URL(url);
|
|
166
|
+
} catch {
|
|
167
|
+
blockDestination(url, "unsupported-protocol");
|
|
168
|
+
}
|
|
169
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") blockDestination(url, "unsupported-protocol");
|
|
170
|
+
const hostname = parsed.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
171
|
+
const directReason = classifyHostname(hostname);
|
|
172
|
+
if (directReason && !policyAllows(directReason, effectivePolicy)) blockDestination(url, directReason);
|
|
173
|
+
const version = net__default.default.isIP(hostname);
|
|
174
|
+
if (version !== 0) return [{ address: hostname, family: version }];
|
|
175
|
+
const addresses = await resolveDestinationAddresses(hostname);
|
|
176
|
+
for (const { address } of addresses) {
|
|
177
|
+
const reason = classifyIp(address);
|
|
178
|
+
if (reason && !policyAllows(reason, effectivePolicy)) blockDestination(url, reason);
|
|
179
|
+
}
|
|
180
|
+
return addresses;
|
|
181
|
+
}
|
|
182
|
+
async function assertDestinationAllowed(url, policy = {}) {
|
|
183
|
+
await validateDestinationAllowed(url, policy);
|
|
184
|
+
}
|
|
185
|
+
function isRedirectStatus(status) {
|
|
186
|
+
return REDIRECT_STATUSES.has(status);
|
|
187
|
+
}
|
|
188
|
+
function responseLocation(response) {
|
|
189
|
+
const headers = response.headers;
|
|
190
|
+
return headers.location ?? headers.Location;
|
|
191
|
+
}
|
|
192
|
+
function stripSensitiveRedirectHeaders(headers) {
|
|
193
|
+
if (!headers) return headers;
|
|
194
|
+
const sanitizedHeaders = { ...headers };
|
|
195
|
+
for (const headerName of Object.keys(sanitizedHeaders)) {
|
|
196
|
+
if (SENSITIVE_REDIRECT_HEADERS.has(headerName.toLowerCase())) delete sanitizedHeaders[headerName];
|
|
197
|
+
}
|
|
198
|
+
return sanitizedHeaders;
|
|
199
|
+
}
|
|
200
|
+
function createPinnedLookup(addresses) {
|
|
201
|
+
return (_hostname, options, callback) => {
|
|
202
|
+
const requestedFamily = "family" in options && (options.family === 4 || options.family === 6) ? options.family : void 0;
|
|
203
|
+
const candidates = requestedFamily ? addresses.filter(({ family: family2 }) => family2 === requestedFamily) : addresses;
|
|
204
|
+
if (candidates.length === 0) {
|
|
205
|
+
callback(new Error(`No validated destination address matches the requested address family: ${requestedFamily}`), "", void 0);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if ("all" in options && options.all === true) {
|
|
209
|
+
callback(null, candidates, void 0);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const [{ address, family }] = candidates;
|
|
213
|
+
callback(null, address, family);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async function requestWithDestinationPolicy(config, policy = {}) {
|
|
217
|
+
if (!config.url) throw new Error("A request URL is required for destination policy enforcement");
|
|
218
|
+
const effectivePolicy = { ...DEFAULT_DESTINATION_POLICY, ...policy };
|
|
219
|
+
const maxRedirects = effectivePolicy.maxRedirects;
|
|
220
|
+
if (!Number.isInteger(maxRedirects) || maxRedirects < 0) throw new Error("maxRedirects must be a non-negative integer");
|
|
221
|
+
let currentUrl = config.url;
|
|
222
|
+
let currentConfig = {
|
|
223
|
+
...config,
|
|
224
|
+
url: currentUrl,
|
|
225
|
+
maxRedirects: 0,
|
|
226
|
+
validateStatus: (status) => isRedirectStatus(status) || (config.validateStatus ? config.validateStatus(status) : status >= 200 && status < 300)
|
|
227
|
+
};
|
|
228
|
+
for (let redirectCount = 0; ; redirectCount += 1) {
|
|
229
|
+
const validatedAddresses = await validateDestinationAllowed(currentUrl, effectivePolicy);
|
|
230
|
+
currentConfig.lookup = createPinnedLookup(validatedAddresses);
|
|
231
|
+
const response = await axios13__default.default(currentConfig);
|
|
232
|
+
if (!isRedirectStatus(response.status)) return response;
|
|
233
|
+
if (effectivePolicy.allowRedirects === false) blockDestination(currentUrl, "redirect");
|
|
234
|
+
if (redirectCount >= maxRedirects) throw new DestinationPolicyError(currentUrl, "redirect", `Maximum redirect count (${maxRedirects}) exceeded for ${currentUrl}`);
|
|
235
|
+
const location = responseLocation(response);
|
|
236
|
+
if (!location) throw new DestinationPolicyError(currentUrl, "redirect", `Redirect response did not include a Location header: ${currentUrl}`);
|
|
237
|
+
const previousUrl = currentUrl;
|
|
238
|
+
try {
|
|
239
|
+
currentUrl = new URL(location, currentUrl).toString();
|
|
240
|
+
} catch {
|
|
241
|
+
throw new DestinationPolicyError(currentUrl, "redirect", `Redirect response included an invalid Location header: ${location}`);
|
|
242
|
+
}
|
|
243
|
+
const method = String(currentConfig.method ?? "GET").toUpperCase();
|
|
244
|
+
const nextMethod = response.status === 303 || (response.status === 301 || response.status === 302) && method === "POST" ? "GET" : method;
|
|
245
|
+
currentConfig = { ...currentConfig, url: currentUrl, method: nextMethod };
|
|
246
|
+
if (new URL(previousUrl).origin !== new URL(currentUrl).origin) {
|
|
247
|
+
currentConfig.headers = stripSensitiveRedirectHeaders(currentConfig.headers);
|
|
248
|
+
}
|
|
249
|
+
if (nextMethod === "GET" || nextMethod === "HEAD") delete currentConfig.data;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
51
252
|
var HttpMethod = zod.z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
|
|
52
253
|
var httpRequestSchema = zod.z.object({
|
|
53
254
|
url: zod.z.string().url().describe("The URL to make the request to"),
|
|
@@ -69,8 +270,8 @@ var httpPostSchema = zod.z.object({
|
|
|
69
270
|
});
|
|
70
271
|
|
|
71
272
|
// src/web/http/tools/http-client.ts
|
|
72
|
-
function createHttpClientTool(defaultTimeout = 3e4, defaultHeaders = {}) {
|
|
73
|
-
return core.toolBuilder().name("http-client").description("Make HTTP requests to web APIs and services. Supports GET, POST, PUT, DELETE, PATCH methods with custom headers and body.").category(core.ToolCategory.WEB).tags(["http", "api", "request", "web"]).schema(httpRequestSchema).implement(async (input) => {
|
|
273
|
+
function createHttpClientTool(defaultTimeout = 3e4, defaultHeaders = {}, destinationPolicy = {}) {
|
|
274
|
+
return core.toolBuilder().name("http-client").description("Make policy-checked HTTP requests to web APIs and services. Supports GET, POST, PUT, DELETE, PATCH methods with custom headers and body. Local, metadata, link-local, and private-network destinations are blocked by default.").category(core.ToolCategory.WEB).tags(["http", "api", "request", "web"]).schema(httpRequestSchema).implement(async (input) => {
|
|
74
275
|
const config = {
|
|
75
276
|
method: input.method,
|
|
76
277
|
url: input.url,
|
|
@@ -81,37 +282,42 @@ function createHttpClientTool(defaultTimeout = 3e4, defaultHeaders = {}) {
|
|
|
81
282
|
validateStatus: () => true
|
|
82
283
|
// Don't throw on any status code
|
|
83
284
|
};
|
|
84
|
-
const response = await
|
|
285
|
+
const response = await requestWithDestinationPolicy(config, destinationPolicy);
|
|
85
286
|
return {
|
|
86
287
|
status: response.status,
|
|
87
288
|
statusText: response.statusText,
|
|
88
289
|
headers: response.headers,
|
|
89
290
|
data: response.data,
|
|
90
|
-
url: input.url,
|
|
291
|
+
url: response.config.url ?? input.url,
|
|
91
292
|
method: input.method ?? "GET"
|
|
92
293
|
};
|
|
93
294
|
}).build();
|
|
94
295
|
}
|
|
95
|
-
function createHttpGetTool(defaultTimeout = 3e4, defaultHeaders = {}) {
|
|
96
|
-
return core.toolBuilder().name("http-get").description("Make a
|
|
97
|
-
const response = await
|
|
296
|
+
function createHttpGetTool(defaultTimeout = 3e4, defaultHeaders = {}, destinationPolicy = {}) {
|
|
297
|
+
return core.toolBuilder().name("http-get").description("Make a policy-checked HTTP GET request to a URL and return the response data. Local, metadata, link-local, and private-network destinations are blocked by default.").category(core.ToolCategory.WEB).tags(["http", "get", "fetch", "web"]).schema(httpGetSchema).implement(async (input) => {
|
|
298
|
+
const response = await requestWithDestinationPolicy({
|
|
299
|
+
method: "GET",
|
|
300
|
+
url: input.url,
|
|
98
301
|
headers: { ...defaultHeaders, ...input.headers },
|
|
99
302
|
params: input.params,
|
|
100
303
|
timeout: defaultTimeout
|
|
101
|
-
});
|
|
304
|
+
}, destinationPolicy);
|
|
102
305
|
return response.data;
|
|
103
306
|
}).build();
|
|
104
307
|
}
|
|
105
|
-
function createHttpPostTool(defaultTimeout = 3e4, defaultHeaders = {}) {
|
|
106
|
-
return core.toolBuilder().name("http-post").description("Make a
|
|
107
|
-
const response = await
|
|
308
|
+
function createHttpPostTool(defaultTimeout = 3e4, defaultHeaders = {}, destinationPolicy = {}) {
|
|
309
|
+
return core.toolBuilder().name("http-post").description("Make a policy-checked HTTP POST request with JSON body and return the response data. Local, metadata, link-local, and private-network destinations are blocked by default.").category(core.ToolCategory.WEB).tags(["http", "post", "api", "web"]).schema(httpPostSchema).implement(async (input) => {
|
|
310
|
+
const response = await requestWithDestinationPolicy({
|
|
311
|
+
method: "POST",
|
|
312
|
+
url: input.url,
|
|
313
|
+
data: input.body,
|
|
108
314
|
headers: {
|
|
109
315
|
"Content-Type": "application/json",
|
|
110
316
|
...defaultHeaders,
|
|
111
317
|
...input.headers
|
|
112
318
|
},
|
|
113
319
|
timeout: defaultTimeout
|
|
114
|
-
});
|
|
320
|
+
}, destinationPolicy);
|
|
115
321
|
return response.data;
|
|
116
322
|
}).build();
|
|
117
323
|
}
|
|
@@ -122,11 +328,11 @@ var httpGet = createHttpGetTool();
|
|
|
122
328
|
var httpPost = createHttpPostTool();
|
|
123
329
|
var httpTools = [httpClient, httpGet, httpPost];
|
|
124
330
|
function createHttpTools(config = {}) {
|
|
125
|
-
const { defaultTimeout = 3e4, defaultHeaders = {} } = config;
|
|
331
|
+
const { defaultTimeout = 3e4, defaultHeaders = {}, destinationPolicy = {} } = config;
|
|
126
332
|
return [
|
|
127
|
-
createHttpClientTool(defaultTimeout, defaultHeaders),
|
|
128
|
-
createHttpGetTool(defaultTimeout, defaultHeaders),
|
|
129
|
-
createHttpPostTool(defaultTimeout, defaultHeaders)
|
|
333
|
+
createHttpClientTool(defaultTimeout, defaultHeaders, destinationPolicy),
|
|
334
|
+
createHttpGetTool(defaultTimeout, defaultHeaders, destinationPolicy),
|
|
335
|
+
createHttpPostTool(defaultTimeout, defaultHeaders, destinationPolicy)
|
|
130
336
|
];
|
|
131
337
|
}
|
|
132
338
|
var webScraperSchema = zod.z.object({
|
|
@@ -139,18 +345,20 @@ var webScraperSchema = zod.z.object({
|
|
|
139
345
|
extractMetadata: zod.z.boolean().default(false).describe("Extract meta tags (title, description, etc.)"),
|
|
140
346
|
timeout: zod.z.number().default(3e4).describe("Request timeout in milliseconds")
|
|
141
347
|
});
|
|
142
|
-
function createWebScraperTool(defaultTimeout = 3e4, userAgent = "Mozilla/5.0 (compatible; AgentForge/1.0; +https://agentforge.dev)") {
|
|
143
|
-
return core.toolBuilder().name("web-scraper").description("Scrape and extract data from web pages.
|
|
144
|
-
const response = await
|
|
348
|
+
function createWebScraperTool(defaultTimeout = 3e4, userAgent = "Mozilla/5.0 (compatible; AgentForge/1.0; +https://agentforge.dev)", destinationPolicy = {}) {
|
|
349
|
+
return core.toolBuilder().name("web-scraper").description("Scrape and extract data from policy-checked web pages. Local, metadata, link-local, and private-network destinations are blocked by default. Supports text, HTML, links, images, and CSS selectors.").category(core.ToolCategory.WEB).tags(["scraper", "web", "html", "extract", "parse"]).schema(webScraperSchema).implement(async (input) => {
|
|
350
|
+
const response = await requestWithDestinationPolicy({
|
|
351
|
+
method: "GET",
|
|
352
|
+
url: input.url,
|
|
145
353
|
timeout: input.timeout || defaultTimeout,
|
|
146
354
|
headers: {
|
|
147
355
|
"User-Agent": userAgent
|
|
148
356
|
}
|
|
149
|
-
});
|
|
357
|
+
}, destinationPolicy);
|
|
150
358
|
const html = response.data;
|
|
151
359
|
const $ = cheerio__namespace.load(html);
|
|
152
360
|
const result = {
|
|
153
|
-
url: input.url
|
|
361
|
+
url: response.config.url ?? input.url
|
|
154
362
|
};
|
|
155
363
|
const $selected = input.selector ? $(input.selector) : $("body");
|
|
156
364
|
if (input.extractText) {
|
|
@@ -215,8 +423,8 @@ function createWebScraperTool(defaultTimeout = 3e4, userAgent = "Mozilla/5.0 (co
|
|
|
215
423
|
var webScraper = createWebScraperTool();
|
|
216
424
|
var scraperTools = [webScraper];
|
|
217
425
|
function createScraperTools(config = {}) {
|
|
218
|
-
const { defaultTimeout = 3e4, userAgent = "Mozilla/5.0 (compatible; AgentForge/1.0; +https://agentforge.dev)" } = config;
|
|
219
|
-
return [createWebScraperTool(defaultTimeout, userAgent)];
|
|
426
|
+
const { defaultTimeout = 3e4, userAgent = "Mozilla/5.0 (compatible; AgentForge/1.0; +https://agentforge.dev)", destinationPolicy = {} } = config;
|
|
427
|
+
return [createWebScraperTool(defaultTimeout, userAgent, destinationPolicy)];
|
|
220
428
|
}
|
|
221
429
|
var htmlParserSchema = zod.z.object({
|
|
222
430
|
html: zod.z.string().describe("The HTML content to parse"),
|
|
@@ -490,7 +698,7 @@ function isRetryableError(error) {
|
|
|
490
698
|
return false;
|
|
491
699
|
}
|
|
492
700
|
function sleep(ms) {
|
|
493
|
-
return new Promise((
|
|
701
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
494
702
|
}
|
|
495
703
|
async function retryWithBackoff(fn, config = DEFAULT_RETRY_CONFIG) {
|
|
496
704
|
let lastError;
|
|
@@ -531,7 +739,7 @@ var DuckDuckGoProvider = class {
|
|
|
531
739
|
async search(query, maxResults, timeout = DEFAULT_TIMEOUT) {
|
|
532
740
|
return retryWithBackoff(async () => {
|
|
533
741
|
try {
|
|
534
|
-
const response = await
|
|
742
|
+
const response = await axios13__default.default.get(
|
|
535
743
|
"https://api.duckduckgo.com/",
|
|
536
744
|
{
|
|
537
745
|
params: {
|
|
@@ -635,7 +843,7 @@ var SerperProvider = class {
|
|
|
635
843
|
}
|
|
636
844
|
return retryWithBackoff(async () => {
|
|
637
845
|
try {
|
|
638
|
-
const response = await
|
|
846
|
+
const response = await axios13__default.default.post(
|
|
639
847
|
"https://google.serper.dev/search",
|
|
640
848
|
{
|
|
641
849
|
q: query,
|
|
@@ -1069,7 +1277,7 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1069
1277
|
logger19.info("search-confluence called", { query, limit });
|
|
1070
1278
|
try {
|
|
1071
1279
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1072
|
-
const response = await
|
|
1280
|
+
const response = await axios13__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
|
|
1073
1281
|
headers: {
|
|
1074
1282
|
Authorization: getAuthHeader2(),
|
|
1075
1283
|
Accept: "application/json"
|
|
@@ -1131,7 +1339,7 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1131
1339
|
logger19.info("get-confluence-page called", { page_id });
|
|
1132
1340
|
try {
|
|
1133
1341
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1134
|
-
const response = await
|
|
1342
|
+
const response = await axios13__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
|
|
1135
1343
|
headers: {
|
|
1136
1344
|
Authorization: getAuthHeader2(),
|
|
1137
1345
|
Accept: "application/json"
|
|
@@ -1182,7 +1390,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1182
1390
|
logger19.info("list-confluence-spaces called", { limit });
|
|
1183
1391
|
try {
|
|
1184
1392
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1185
|
-
const response = await
|
|
1393
|
+
const response = await axios13__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
|
|
1186
1394
|
headers: {
|
|
1187
1395
|
Authorization: getAuthHeader2(),
|
|
1188
1396
|
Accept: "application/json"
|
|
@@ -1228,7 +1436,7 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1228
1436
|
logger19.info("get-space-pages called", { space_key, limit });
|
|
1229
1437
|
try {
|
|
1230
1438
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1231
|
-
const response = await
|
|
1439
|
+
const response = await axios13__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
|
|
1232
1440
|
headers: {
|
|
1233
1441
|
Authorization: getAuthHeader2(),
|
|
1234
1442
|
Accept: "application/json"
|
|
@@ -1302,7 +1510,7 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1302
1510
|
if (parent_page_id) {
|
|
1303
1511
|
pageData.ancestors = [{ id: parent_page_id }];
|
|
1304
1512
|
}
|
|
1305
|
-
const response = await
|
|
1513
|
+
const response = await axios13__default.default.post(
|
|
1306
1514
|
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`,
|
|
1307
1515
|
pageData,
|
|
1308
1516
|
{
|
|
@@ -1350,7 +1558,7 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1350
1558
|
logger19.info("update-confluence-page called", { page_id, title });
|
|
1351
1559
|
try {
|
|
1352
1560
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1353
|
-
const getResponse = await
|
|
1561
|
+
const getResponse = await axios13__default.default.get(
|
|
1354
1562
|
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1355
1563
|
{
|
|
1356
1564
|
headers: {
|
|
@@ -1360,7 +1568,7 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1360
1568
|
}
|
|
1361
1569
|
);
|
|
1362
1570
|
const currentVersion = getResponse.data.version.number;
|
|
1363
|
-
const updateResponse = await
|
|
1571
|
+
const updateResponse = await axios13__default.default.put(
|
|
1364
1572
|
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1365
1573
|
{
|
|
1366
1574
|
type: "page",
|
|
@@ -1421,7 +1629,7 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1421
1629
|
});
|
|
1422
1630
|
try {
|
|
1423
1631
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1424
|
-
const getResponse = await
|
|
1632
|
+
const getResponse = await axios13__default.default.get(
|
|
1425
1633
|
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1426
1634
|
{
|
|
1427
1635
|
headers: {
|
|
@@ -1432,7 +1640,7 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger19) {
|
|
|
1432
1640
|
);
|
|
1433
1641
|
const currentVersion = getResponse.data.version.number;
|
|
1434
1642
|
const pageData = getResponse.data;
|
|
1435
|
-
await
|
|
1643
|
+
await axios13__default.default.put(
|
|
1436
1644
|
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1437
1645
|
{
|
|
1438
1646
|
version: { number: currentVersion + 1 },
|
|
@@ -1999,8 +2207,8 @@ var objectOmitSchema = zod.z.object({
|
|
|
1999
2207
|
});
|
|
2000
2208
|
|
|
2001
2209
|
// src/data/transformer/tools/shared.ts
|
|
2002
|
-
function getNestedValue(value,
|
|
2003
|
-
return
|
|
2210
|
+
function getNestedValue(value, path13) {
|
|
2211
|
+
return path13.split(".").reduce((current, key) => {
|
|
2004
2212
|
if (current == null) {
|
|
2005
2213
|
return void 0;
|
|
2006
2214
|
}
|
|
@@ -2390,7 +2598,7 @@ function isRetryableError2(error) {
|
|
|
2390
2598
|
return false;
|
|
2391
2599
|
}
|
|
2392
2600
|
function sleep2(ms) {
|
|
2393
|
-
return new Promise((
|
|
2601
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
2394
2602
|
}
|
|
2395
2603
|
async function retryWithBackoff2(fn, config = DEFAULT_RETRY_CONFIG2) {
|
|
2396
2604
|
let lastError;
|
|
@@ -2497,7 +2705,7 @@ var OpenAIEmbeddingProvider = class {
|
|
|
2497
2705
|
const modelToUse = model || this.defaultModel;
|
|
2498
2706
|
return retryWithBackoff2(async () => {
|
|
2499
2707
|
try {
|
|
2500
|
-
const response = await
|
|
2708
|
+
const response = await axios13__default.default.post(
|
|
2501
2709
|
`${this.baseURL}/embeddings`,
|
|
2502
2710
|
{
|
|
2503
2711
|
input: text,
|
|
@@ -2561,7 +2769,7 @@ var OpenAIEmbeddingProvider = class {
|
|
|
2561
2769
|
const modelToUse = model || this.defaultModel;
|
|
2562
2770
|
return retryWithBackoff2(async () => {
|
|
2563
2771
|
try {
|
|
2564
|
-
const response = await
|
|
2772
|
+
const response = await axios13__default.default.post(
|
|
2565
2773
|
`${this.baseURL}/embeddings`,
|
|
2566
2774
|
{
|
|
2567
2775
|
input: texts,
|
|
@@ -2641,7 +2849,7 @@ var CohereEmbeddingProvider = class {
|
|
|
2641
2849
|
const modelToUse = model || this.defaultModel;
|
|
2642
2850
|
return retryWithBackoff2(async () => {
|
|
2643
2851
|
try {
|
|
2644
|
-
const response = await
|
|
2852
|
+
const response = await axios13__default.default.post(
|
|
2645
2853
|
`${this.baseUrl}/embed`,
|
|
2646
2854
|
{
|
|
2647
2855
|
texts,
|
|
@@ -2669,7 +2877,7 @@ var CohereEmbeddingProvider = class {
|
|
|
2669
2877
|
} : void 0
|
|
2670
2878
|
};
|
|
2671
2879
|
} catch (error) {
|
|
2672
|
-
if (
|
|
2880
|
+
if (axios13__default.default.isAxiosError(error)) {
|
|
2673
2881
|
const status = error.response?.status;
|
|
2674
2882
|
const message = error.response?.data?.message || error.message;
|
|
2675
2883
|
let wrappedError;
|
|
@@ -2709,7 +2917,7 @@ var HuggingFaceEmbeddingProvider = class {
|
|
|
2709
2917
|
const modelToUse = model || this.defaultModel;
|
|
2710
2918
|
return retryWithBackoff2(async () => {
|
|
2711
2919
|
try {
|
|
2712
|
-
const response = await
|
|
2920
|
+
const response = await axios13__default.default.post(
|
|
2713
2921
|
`${this.baseUrl}/${modelToUse}`,
|
|
2714
2922
|
{
|
|
2715
2923
|
inputs: text,
|
|
@@ -2731,7 +2939,7 @@ var HuggingFaceEmbeddingProvider = class {
|
|
|
2731
2939
|
dimensions: embedding.length
|
|
2732
2940
|
};
|
|
2733
2941
|
} catch (error) {
|
|
2734
|
-
if (
|
|
2942
|
+
if (axios13__default.default.isAxiosError(error)) {
|
|
2735
2943
|
const status = error.response?.status;
|
|
2736
2944
|
const message = error.response?.data?.error || error.message;
|
|
2737
2945
|
let wrappedError;
|
|
@@ -2758,7 +2966,7 @@ var HuggingFaceEmbeddingProvider = class {
|
|
|
2758
2966
|
const modelToUse = model || this.defaultModel;
|
|
2759
2967
|
return retryWithBackoff2(async () => {
|
|
2760
2968
|
try {
|
|
2761
|
-
const response = await
|
|
2969
|
+
const response = await axios13__default.default.post(
|
|
2762
2970
|
`${this.baseUrl}/${modelToUse}`,
|
|
2763
2971
|
{
|
|
2764
2972
|
inputs: texts,
|
|
@@ -2781,7 +2989,7 @@ var HuggingFaceEmbeddingProvider = class {
|
|
|
2781
2989
|
dimensions
|
|
2782
2990
|
};
|
|
2783
2991
|
} catch (error) {
|
|
2784
|
-
if (
|
|
2992
|
+
if (axios13__default.default.isAxiosError(error)) {
|
|
2785
2993
|
const status = error.response?.status;
|
|
2786
2994
|
const message = error.response?.data?.error || error.message;
|
|
2787
2995
|
let wrappedError;
|
|
@@ -2832,7 +3040,7 @@ var VoyageEmbeddingProvider = class {
|
|
|
2832
3040
|
const modelToUse = model || this.defaultModel;
|
|
2833
3041
|
return retryWithBackoff2(async () => {
|
|
2834
3042
|
try {
|
|
2835
|
-
const response = await
|
|
3043
|
+
const response = await axios13__default.default.post(
|
|
2836
3044
|
`${this.baseUrl}/embeddings`,
|
|
2837
3045
|
{
|
|
2838
3046
|
input: texts,
|
|
@@ -2859,7 +3067,7 @@ var VoyageEmbeddingProvider = class {
|
|
|
2859
3067
|
} : void 0
|
|
2860
3068
|
};
|
|
2861
3069
|
} catch (error) {
|
|
2862
|
-
if (
|
|
3070
|
+
if (axios13__default.default.isAxiosError(error)) {
|
|
2863
3071
|
const status = error.response?.status;
|
|
2864
3072
|
const message = error.response?.data?.message || error.message;
|
|
2865
3073
|
let wrappedError;
|
|
@@ -2898,7 +3106,7 @@ var OllamaEmbeddingProvider = class {
|
|
|
2898
3106
|
const modelToUse = model || this.defaultModel;
|
|
2899
3107
|
return retryWithBackoff2(async () => {
|
|
2900
3108
|
try {
|
|
2901
|
-
const response = await
|
|
3109
|
+
const response = await axios13__default.default.post(
|
|
2902
3110
|
`${this.baseUrl}/api/embeddings`,
|
|
2903
3111
|
{
|
|
2904
3112
|
model: modelToUse,
|
|
@@ -2917,7 +3125,7 @@ var OllamaEmbeddingProvider = class {
|
|
|
2917
3125
|
dimensions: embedding.length
|
|
2918
3126
|
};
|
|
2919
3127
|
} catch (error) {
|
|
2920
|
-
if (
|
|
3128
|
+
if (axios13__default.default.isAxiosError(error)) {
|
|
2921
3129
|
const status = error.response?.status;
|
|
2922
3130
|
const message = error.response?.data?.error || error.message;
|
|
2923
3131
|
let wrappedError;
|
|
@@ -3289,16 +3497,16 @@ function formatRelationship(rel) {
|
|
|
3289
3497
|
properties: formatValue(rel.properties)
|
|
3290
3498
|
};
|
|
3291
3499
|
}
|
|
3292
|
-
function formatPath(
|
|
3500
|
+
function formatPath(path13) {
|
|
3293
3501
|
return {
|
|
3294
|
-
start: formatNode(
|
|
3295
|
-
end: formatNode(
|
|
3296
|
-
segments:
|
|
3502
|
+
start: formatNode(path13.start),
|
|
3503
|
+
end: formatNode(path13.end),
|
|
3504
|
+
segments: path13.segments.map((segment) => ({
|
|
3297
3505
|
start: formatNode(segment.start),
|
|
3298
3506
|
relationship: formatRelationship(segment.relationship),
|
|
3299
3507
|
end: formatNode(segment.end)
|
|
3300
3508
|
})),
|
|
3301
|
-
length:
|
|
3509
|
+
length: path13.length
|
|
3302
3510
|
};
|
|
3303
3511
|
}
|
|
3304
3512
|
function formatResults(records) {
|
|
@@ -5475,8 +5683,8 @@ function toBatchErrorMessage(error) {
|
|
|
5475
5683
|
return error instanceof Error ? error.message : String(error);
|
|
5476
5684
|
}
|
|
5477
5685
|
function delayBatchRetry(ms) {
|
|
5478
|
-
return new Promise((
|
|
5479
|
-
setTimeout(
|
|
5686
|
+
return new Promise((resolve3) => {
|
|
5687
|
+
setTimeout(resolve3, ms);
|
|
5480
5688
|
});
|
|
5481
5689
|
}
|
|
5482
5690
|
|
|
@@ -5902,7 +6110,7 @@ function withTransactionTimeout(operation, timeoutMs, onTimeout) {
|
|
|
5902
6110
|
if (!timeoutMs) {
|
|
5903
6111
|
return operation;
|
|
5904
6112
|
}
|
|
5905
|
-
return new Promise((
|
|
6113
|
+
return new Promise((resolve3, reject) => {
|
|
5906
6114
|
let timedOut = false;
|
|
5907
6115
|
const timer = setTimeout(() => {
|
|
5908
6116
|
timedOut = true;
|
|
@@ -5914,7 +6122,7 @@ function withTransactionTimeout(operation, timeoutMs, onTimeout) {
|
|
|
5914
6122
|
return;
|
|
5915
6123
|
}
|
|
5916
6124
|
clearTimeout(timer);
|
|
5917
|
-
|
|
6125
|
+
resolve3(result);
|
|
5918
6126
|
}).catch((error) => {
|
|
5919
6127
|
if (timedOut) {
|
|
5920
6128
|
return;
|
|
@@ -9147,11 +9355,135 @@ var fileDeleteSchema = zod.z.object({
|
|
|
9147
9355
|
var fileExistsSchema = zod.z.object({
|
|
9148
9356
|
path: zod.z.string().describe("Path to check")
|
|
9149
9357
|
});
|
|
9150
|
-
|
|
9358
|
+
var FileSystemPolicyError = class extends Error {
|
|
9359
|
+
constructor(message, operation, inputPath) {
|
|
9360
|
+
super(message);
|
|
9361
|
+
this.operation = operation;
|
|
9362
|
+
this.inputPath = inputPath;
|
|
9363
|
+
this.name = "FileSystemPolicyError";
|
|
9364
|
+
}
|
|
9365
|
+
code = "FILE_SYSTEM_POLICY_VIOLATION";
|
|
9366
|
+
};
|
|
9367
|
+
function containsTraversal(inputPath) {
|
|
9368
|
+
return inputPath.split(/[\\/]+/).includes("..");
|
|
9369
|
+
}
|
|
9370
|
+
function isWithinRoot(root, target) {
|
|
9371
|
+
const relative4 = path__namespace.relative(root, target);
|
|
9372
|
+
return relative4 === "" || !relative4.startsWith(`..${path__namespace.sep}`) && relative4 !== ".." && !path__namespace.isAbsolute(relative4);
|
|
9373
|
+
}
|
|
9374
|
+
async function resolveWithMissingTail(inputPath) {
|
|
9375
|
+
let currentPath = inputPath;
|
|
9376
|
+
const missingSegments = [];
|
|
9377
|
+
while (true) {
|
|
9378
|
+
try {
|
|
9379
|
+
const resolvedPath = await fs.promises.realpath(currentPath);
|
|
9380
|
+
return path__namespace.join(resolvedPath, ...missingSegments);
|
|
9381
|
+
} catch (error) {
|
|
9382
|
+
const code = error.code;
|
|
9383
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
9384
|
+
throw error;
|
|
9385
|
+
}
|
|
9386
|
+
const parentPath = path__namespace.dirname(currentPath);
|
|
9387
|
+
if (parentPath === currentPath) {
|
|
9388
|
+
throw error;
|
|
9389
|
+
}
|
|
9390
|
+
missingSegments.unshift(path__namespace.basename(currentPath));
|
|
9391
|
+
currentPath = parentPath;
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
}
|
|
9395
|
+
var FileSystemPolicy = class {
|
|
9396
|
+
allowedRoots;
|
|
9397
|
+
allowOutsideRoots;
|
|
9398
|
+
allowRootDeletion;
|
|
9399
|
+
baseDirectory;
|
|
9400
|
+
constructor(options = {}) {
|
|
9401
|
+
const configuredRoots = [
|
|
9402
|
+
...options.allowedRoots ?? [],
|
|
9403
|
+
...options.workspaceRoot ? [options.workspaceRoot] : []
|
|
9404
|
+
];
|
|
9405
|
+
this.allowedRoots = [...new Set(configuredRoots.map((root) => path__namespace.resolve(root)))];
|
|
9406
|
+
this.baseDirectory = path__namespace.resolve(options.workspaceRoot ?? process.cwd());
|
|
9407
|
+
this.allowOutsideRoots = options.allowOutsideRoots ?? this.allowedRoots.length === 0;
|
|
9408
|
+
this.allowRootDeletion = options.allowRootDeletion ?? this.allowOutsideRoots;
|
|
9409
|
+
}
|
|
9410
|
+
async resolvePath(inputPath, operation) {
|
|
9411
|
+
const { resolvedPath } = await this.resolvePathWithRoots(inputPath, operation);
|
|
9412
|
+
return resolvedPath;
|
|
9413
|
+
}
|
|
9414
|
+
async resolveDeletePath(inputPath, recursive) {
|
|
9415
|
+
const { resolvedPath, resolvedRoots } = await this.resolvePathWithRoots(inputPath, "directory deletion");
|
|
9416
|
+
if (recursive && !this.allowRootDeletion && resolvedRoots.some((root) => root === resolvedPath)) {
|
|
9417
|
+
throw new FileSystemPolicyError(
|
|
9418
|
+
"Filesystem policy blocked directory deletion: recursive deletion of an allowed root is not permitted",
|
|
9419
|
+
"directory deletion",
|
|
9420
|
+
inputPath
|
|
9421
|
+
);
|
|
9422
|
+
}
|
|
9423
|
+
return resolvedPath;
|
|
9424
|
+
}
|
|
9425
|
+
async resolvePathWithRoots(inputPath, operation) {
|
|
9426
|
+
const absolutePath = path__namespace.resolve(this.baseDirectory, inputPath);
|
|
9427
|
+
if (this.allowOutsideRoots) {
|
|
9428
|
+
return { resolvedPath: absolutePath, resolvedRoots: [] };
|
|
9429
|
+
}
|
|
9430
|
+
if (containsTraversal(inputPath)) {
|
|
9431
|
+
throw new FileSystemPolicyError(
|
|
9432
|
+
`Filesystem policy blocked ${operation}: path traversal is not allowed`,
|
|
9433
|
+
operation,
|
|
9434
|
+
inputPath
|
|
9435
|
+
);
|
|
9436
|
+
}
|
|
9437
|
+
let resolvedPath;
|
|
9438
|
+
try {
|
|
9439
|
+
resolvedPath = await resolveWithMissingTail(absolutePath);
|
|
9440
|
+
} catch {
|
|
9441
|
+
throw new FileSystemPolicyError(
|
|
9442
|
+
`Filesystem policy could not resolve ${operation} path`,
|
|
9443
|
+
operation,
|
|
9444
|
+
inputPath
|
|
9445
|
+
);
|
|
9446
|
+
}
|
|
9447
|
+
const resolvedRoots = await this.resolveRoots(operation, inputPath);
|
|
9448
|
+
if (!resolvedRoots.some((root) => isWithinRoot(root, resolvedPath))) {
|
|
9449
|
+
throw new FileSystemPolicyError(
|
|
9450
|
+
`Filesystem policy blocked ${operation}: path is outside the allowed roots`,
|
|
9451
|
+
operation,
|
|
9452
|
+
inputPath
|
|
9453
|
+
);
|
|
9454
|
+
}
|
|
9455
|
+
return { resolvedPath, resolvedRoots };
|
|
9456
|
+
}
|
|
9457
|
+
async resolveRoots(operation, inputPath) {
|
|
9458
|
+
try {
|
|
9459
|
+
return await Promise.all(this.allowedRoots.map((root) => fs.promises.realpath(root)));
|
|
9460
|
+
} catch {
|
|
9461
|
+
throw new FileSystemPolicyError(
|
|
9462
|
+
`Filesystem policy could not resolve an allowed root for ${operation}`,
|
|
9463
|
+
operation,
|
|
9464
|
+
inputPath
|
|
9465
|
+
);
|
|
9466
|
+
}
|
|
9467
|
+
}
|
|
9468
|
+
};
|
|
9469
|
+
var DEFAULT_FILE_SYSTEM_POLICY = new FileSystemPolicy();
|
|
9470
|
+
function createFileSystemPolicy(options = {}) {
|
|
9471
|
+
return new FileSystemPolicy(options);
|
|
9472
|
+
}
|
|
9473
|
+
function resolveFileSystemPolicy(policy) {
|
|
9474
|
+
if (!policy) {
|
|
9475
|
+
return DEFAULT_FILE_SYSTEM_POLICY;
|
|
9476
|
+
}
|
|
9477
|
+
return policy instanceof FileSystemPolicy ? policy : createFileSystemPolicy(policy);
|
|
9478
|
+
}
|
|
9479
|
+
|
|
9480
|
+
// src/file/operations/tools/file-reader.ts
|
|
9481
|
+
function createFileReaderTool(defaultEncoding = "utf8", policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9151
9482
|
return core.toolBuilder().name("file-reader").description("Read the contents of a file from the file system. Supports text and binary files with various encodings.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "read", "io", "filesystem"]).schema(fileReaderSchema).implementSafe(async (input) => {
|
|
9152
9483
|
const encoding = input.encoding || defaultEncoding;
|
|
9153
|
-
const
|
|
9154
|
-
const
|
|
9484
|
+
const safePath = await policy.resolvePath(input.path, "file read");
|
|
9485
|
+
const content = await fs.promises.readFile(safePath, encoding);
|
|
9486
|
+
const stats = await fs.promises.stat(safePath);
|
|
9155
9487
|
return {
|
|
9156
9488
|
content,
|
|
9157
9489
|
size: stats.size,
|
|
@@ -9160,16 +9492,17 @@ function createFileReaderTool(defaultEncoding = "utf8") {
|
|
|
9160
9492
|
};
|
|
9161
9493
|
}).build();
|
|
9162
9494
|
}
|
|
9163
|
-
function createFileWriterTool(defaultEncoding = "utf8", createDirsDefault = false) {
|
|
9495
|
+
function createFileWriterTool(defaultEncoding = "utf8", createDirsDefault = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9164
9496
|
return core.toolBuilder().name("file-writer").description("Write content to a file. Creates the file if it doesn't exist, or overwrites it if it does.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "write", "io", "filesystem"]).schema(fileWriterSchema).implementSafe(async (input) => {
|
|
9165
9497
|
const encoding = input.encoding || defaultEncoding;
|
|
9166
9498
|
const createDirs = input.createDirs ?? createDirsDefault;
|
|
9499
|
+
const safePath = await policy.resolvePath(input.path, "file write");
|
|
9167
9500
|
if (createDirs) {
|
|
9168
|
-
const dir =
|
|
9501
|
+
const dir = path__namespace.dirname(safePath);
|
|
9169
9502
|
await fs.promises.mkdir(dir, { recursive: true });
|
|
9170
9503
|
}
|
|
9171
|
-
await fs.promises.writeFile(
|
|
9172
|
-
const stats = await fs.promises.stat(
|
|
9504
|
+
await fs.promises.writeFile(safePath, input.content, encoding);
|
|
9505
|
+
const stats = await fs.promises.stat(safePath);
|
|
9173
9506
|
return {
|
|
9174
9507
|
path: input.path,
|
|
9175
9508
|
size: stats.size,
|
|
@@ -9177,31 +9510,34 @@ function createFileWriterTool(defaultEncoding = "utf8", createDirsDefault = fals
|
|
|
9177
9510
|
};
|
|
9178
9511
|
}).build();
|
|
9179
9512
|
}
|
|
9180
|
-
function createFileAppendTool(defaultEncoding = "utf8") {
|
|
9513
|
+
function createFileAppendTool(defaultEncoding = "utf8", policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9181
9514
|
return core.toolBuilder().name("file-append").description("Append content to the end of a file. Creates the file if it doesn't exist.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "append", "io", "filesystem"]).schema(fileAppendSchema).implementSafe(async (input) => {
|
|
9182
9515
|
const encoding = input.encoding || defaultEncoding;
|
|
9183
|
-
await
|
|
9184
|
-
|
|
9516
|
+
const safePath = await policy.resolvePath(input.path, "file append");
|
|
9517
|
+
await fs.promises.appendFile(safePath, input.content, encoding);
|
|
9518
|
+
const stats = await fs.promises.stat(safePath);
|
|
9185
9519
|
return {
|
|
9186
9520
|
path: input.path,
|
|
9187
9521
|
size: stats.size
|
|
9188
9522
|
};
|
|
9189
9523
|
}).build();
|
|
9190
9524
|
}
|
|
9191
|
-
function createFileDeleteTool() {
|
|
9525
|
+
function createFileDeleteTool(policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9192
9526
|
return core.toolBuilder().name("file-delete").description("Delete a file from the file system. Returns an error if the file doesn't exist.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "delete", "remove", "filesystem"]).schema(fileDeleteSchema).implementSafe(async (input) => {
|
|
9193
|
-
await
|
|
9527
|
+
const safePath = await policy.resolvePath(input.path, "file deletion");
|
|
9528
|
+
await fs.promises.unlink(safePath);
|
|
9194
9529
|
return {
|
|
9195
9530
|
path: input.path,
|
|
9196
9531
|
message: "File deleted successfully"
|
|
9197
9532
|
};
|
|
9198
9533
|
}).build();
|
|
9199
9534
|
}
|
|
9200
|
-
function createFileExistsTool() {
|
|
9535
|
+
function createFileExistsTool(policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9201
9536
|
return core.toolBuilder().name("file-exists").description("Check if a file or directory exists at the specified path.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "exists", "check", "filesystem"]).schema(fileExistsSchema).implement(async (input) => {
|
|
9202
9537
|
try {
|
|
9203
|
-
await
|
|
9204
|
-
|
|
9538
|
+
const safePath = await policy.resolvePath(input.path, "file existence check");
|
|
9539
|
+
await fs.promises.access(safePath);
|
|
9540
|
+
const stats = await fs.promises.stat(safePath);
|
|
9205
9541
|
return {
|
|
9206
9542
|
exists: true,
|
|
9207
9543
|
path: input.path,
|
|
@@ -9210,7 +9546,13 @@ function createFileExistsTool() {
|
|
|
9210
9546
|
size: stats.size,
|
|
9211
9547
|
modified: stats.mtime.toISOString()
|
|
9212
9548
|
};
|
|
9213
|
-
} catch {
|
|
9549
|
+
} catch (error) {
|
|
9550
|
+
if (error instanceof FileSystemPolicyError) {
|
|
9551
|
+
return {
|
|
9552
|
+
success: false,
|
|
9553
|
+
error: error.message
|
|
9554
|
+
};
|
|
9555
|
+
}
|
|
9214
9556
|
return {
|
|
9215
9557
|
exists: false,
|
|
9216
9558
|
path: input.path
|
|
@@ -9235,14 +9577,16 @@ var fileOperationTools = [
|
|
|
9235
9577
|
function createFileOperationTools(config = {}) {
|
|
9236
9578
|
const {
|
|
9237
9579
|
defaultEncoding = "utf8",
|
|
9238
|
-
createDirsDefault = false
|
|
9580
|
+
createDirsDefault = false,
|
|
9581
|
+
policy: policyInput
|
|
9239
9582
|
} = config;
|
|
9583
|
+
const policy = resolveFileSystemPolicy(policyInput);
|
|
9240
9584
|
return [
|
|
9241
|
-
createFileReaderTool(defaultEncoding),
|
|
9242
|
-
createFileWriterTool(defaultEncoding, createDirsDefault),
|
|
9243
|
-
createFileAppendTool(defaultEncoding),
|
|
9244
|
-
createFileDeleteTool(),
|
|
9245
|
-
createFileExistsTool()
|
|
9585
|
+
createFileReaderTool(defaultEncoding, policy),
|
|
9586
|
+
createFileWriterTool(defaultEncoding, createDirsDefault, policy),
|
|
9587
|
+
createFileAppendTool(defaultEncoding, policy),
|
|
9588
|
+
createFileDeleteTool(policy),
|
|
9589
|
+
createFileExistsTool(policy)
|
|
9246
9590
|
];
|
|
9247
9591
|
}
|
|
9248
9592
|
var directoryListSchema = zod.z.object({
|
|
@@ -9265,21 +9609,23 @@ var fileSearchSchema = zod.z.object({
|
|
|
9265
9609
|
recursive: zod.z.boolean().default(true).describe("Search in subdirectories"),
|
|
9266
9610
|
caseSensitive: zod.z.boolean().default(false).describe("Case-sensitive pattern matching")
|
|
9267
9611
|
});
|
|
9268
|
-
function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false) {
|
|
9612
|
+
function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9269
9613
|
return core.toolBuilder().name("directory-list").description("List all files and directories in a directory. Can optionally include file details and filter by extension.").category(core.ToolCategory.FILE_SYSTEM).tags(["directory", "list", "files", "filesystem"]).schema(directoryListSchema).implementSafe(async (input) => {
|
|
9614
|
+
const safePath = await policy.resolvePath(input.path, "directory listing");
|
|
9615
|
+
const includeDetails = input.includeDetails ?? defaultIncludeDetails;
|
|
9270
9616
|
const listFiles = async (dir, recursive2) => {
|
|
9271
9617
|
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
9272
9618
|
const files2 = [];
|
|
9273
9619
|
for (const entry of entries) {
|
|
9274
|
-
const fullPath =
|
|
9275
|
-
const relativePath =
|
|
9620
|
+
const fullPath = path__namespace.join(dir, entry.name);
|
|
9621
|
+
const relativePath = path__namespace.relative(safePath, fullPath);
|
|
9276
9622
|
if (input.extension && !entry.name.endsWith(input.extension)) {
|
|
9277
9623
|
if (!entry.isDirectory() || !recursive2) {
|
|
9278
9624
|
continue;
|
|
9279
9625
|
}
|
|
9280
9626
|
}
|
|
9281
|
-
if (
|
|
9282
|
-
const stats = await fs.promises.
|
|
9627
|
+
if (includeDetails) {
|
|
9628
|
+
const stats = await fs.promises.lstat(fullPath);
|
|
9283
9629
|
files2.push({
|
|
9284
9630
|
name: entry.name,
|
|
9285
9631
|
path: relativePath,
|
|
@@ -9305,7 +9651,7 @@ function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails
|
|
|
9305
9651
|
return files2;
|
|
9306
9652
|
};
|
|
9307
9653
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9308
|
-
const files = await listFiles(
|
|
9654
|
+
const files = await listFiles(safePath, recursive);
|
|
9309
9655
|
return {
|
|
9310
9656
|
path: input.path,
|
|
9311
9657
|
files,
|
|
@@ -9313,37 +9659,40 @@ function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails
|
|
|
9313
9659
|
};
|
|
9314
9660
|
}).build();
|
|
9315
9661
|
}
|
|
9316
|
-
function createDirectoryCreateTool(defaultRecursive = true) {
|
|
9662
|
+
function createDirectoryCreateTool(defaultRecursive = true, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9317
9663
|
return core.toolBuilder().name("directory-create").description("Create a new directory. Can optionally create parent directories if they don't exist.").category(core.ToolCategory.FILE_SYSTEM).tags(["directory", "create", "mkdir", "filesystem"]).schema(directoryCreateSchema).implementSafe(async (input) => {
|
|
9318
9664
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9319
|
-
await
|
|
9665
|
+
const safePath = await policy.resolvePath(input.path, "directory creation");
|
|
9666
|
+
await fs.promises.mkdir(safePath, { recursive });
|
|
9320
9667
|
return {
|
|
9321
9668
|
path: input.path,
|
|
9322
9669
|
message: "Directory created successfully"
|
|
9323
9670
|
};
|
|
9324
9671
|
}).build();
|
|
9325
9672
|
}
|
|
9326
|
-
function createDirectoryDeleteTool(defaultRecursive = false) {
|
|
9673
|
+
function createDirectoryDeleteTool(defaultRecursive = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9327
9674
|
return core.toolBuilder().name("directory-delete").description("Delete a directory. Can optionally delete non-empty directories recursively.").category(core.ToolCategory.FILE_SYSTEM).tags(["directory", "delete", "remove", "filesystem"]).schema(directoryDeleteSchema).implementSafe(async (input) => {
|
|
9328
9675
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9329
|
-
await
|
|
9676
|
+
const safePath = await policy.resolveDeletePath(input.path, recursive);
|
|
9677
|
+
await fs.promises.rm(safePath, { recursive, force: false });
|
|
9330
9678
|
return {
|
|
9331
9679
|
path: input.path,
|
|
9332
9680
|
message: "Directory deleted successfully"
|
|
9333
9681
|
};
|
|
9334
9682
|
}).build();
|
|
9335
9683
|
}
|
|
9336
|
-
function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = false) {
|
|
9684
|
+
function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9337
9685
|
return core.toolBuilder().name("file-search").description("Search for files by name pattern in a directory. Supports wildcards and recursive search.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "search", "find", "filesystem"]).schema(fileSearchSchema).implementSafe(async (input) => {
|
|
9338
9686
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9339
9687
|
const caseSensitive = input.caseSensitive ?? defaultCaseSensitive;
|
|
9688
|
+
const safeDirectory = await policy.resolvePath(input.directory, "file search");
|
|
9340
9689
|
const searchFiles = async (dir) => {
|
|
9341
9690
|
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
9342
9691
|
const matches2 = [];
|
|
9343
9692
|
const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
|
|
9344
9693
|
const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
|
|
9345
9694
|
for (const entry of entries) {
|
|
9346
|
-
const fullPath =
|
|
9695
|
+
const fullPath = path__namespace.join(dir, entry.name);
|
|
9347
9696
|
if (entry.isFile() && regex.test(entry.name)) {
|
|
9348
9697
|
matches2.push(fullPath);
|
|
9349
9698
|
}
|
|
@@ -9354,7 +9703,7 @@ function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = fa
|
|
|
9354
9703
|
}
|
|
9355
9704
|
return matches2;
|
|
9356
9705
|
};
|
|
9357
|
-
const matches = await searchFiles(
|
|
9706
|
+
const matches = await searchFiles(safeDirectory);
|
|
9358
9707
|
return {
|
|
9359
9708
|
directory: input.directory,
|
|
9360
9709
|
pattern: input.pattern,
|
|
@@ -9379,15 +9728,17 @@ function createDirectoryOperationTools(config = {}) {
|
|
|
9379
9728
|
const {
|
|
9380
9729
|
defaultRecursive = false,
|
|
9381
9730
|
defaultIncludeDetails = false,
|
|
9382
|
-
defaultCaseSensitive = false
|
|
9731
|
+
defaultCaseSensitive = false,
|
|
9732
|
+
policy: policyInput
|
|
9383
9733
|
} = config;
|
|
9734
|
+
const policy = resolveFileSystemPolicy(policyInput);
|
|
9384
9735
|
return [
|
|
9385
|
-
createDirectoryListTool(defaultRecursive, defaultIncludeDetails),
|
|
9386
|
-
createDirectoryCreateTool(true),
|
|
9736
|
+
createDirectoryListTool(defaultRecursive, defaultIncludeDetails, policy),
|
|
9737
|
+
createDirectoryCreateTool(true, policy),
|
|
9387
9738
|
// Always default to true for create
|
|
9388
|
-
createDirectoryDeleteTool(false),
|
|
9739
|
+
createDirectoryDeleteTool(false, policy),
|
|
9389
9740
|
// Always default to false for delete (safety)
|
|
9390
|
-
createFileSearchTool(defaultRecursive, defaultCaseSensitive)
|
|
9741
|
+
createFileSearchTool(defaultRecursive, defaultCaseSensitive, policy)
|
|
9391
9742
|
];
|
|
9392
9743
|
}
|
|
9393
9744
|
var pathJoinSchema = zod.z.object({
|
|
@@ -9418,7 +9769,7 @@ var pathNormalizeSchema = zod.z.object({
|
|
|
9418
9769
|
});
|
|
9419
9770
|
function createPathJoinTool() {
|
|
9420
9771
|
return core.toolBuilder().name("path-join").description("Join multiple path segments into a single path. Handles platform-specific separators.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "join", "filesystem"]).schema(pathJoinSchema).implement(async (input) => {
|
|
9421
|
-
const joined =
|
|
9772
|
+
const joined = path__namespace.join(...input.segments);
|
|
9422
9773
|
return {
|
|
9423
9774
|
path: joined,
|
|
9424
9775
|
segments: input.segments
|
|
@@ -9427,59 +9778,59 @@ function createPathJoinTool() {
|
|
|
9427
9778
|
}
|
|
9428
9779
|
function createPathResolveTool() {
|
|
9429
9780
|
return core.toolBuilder().name("path-resolve").description("Resolve a sequence of paths into an absolute path. Resolves relative paths from the current working directory.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "resolve", "absolute", "filesystem"]).schema(pathResolveSchema).implement(async (input) => {
|
|
9430
|
-
const resolved =
|
|
9781
|
+
const resolved = path__namespace.resolve(...input.paths);
|
|
9431
9782
|
return {
|
|
9432
9783
|
path: resolved,
|
|
9433
|
-
isAbsolute:
|
|
9784
|
+
isAbsolute: path__namespace.isAbsolute(resolved)
|
|
9434
9785
|
};
|
|
9435
9786
|
}).build();
|
|
9436
9787
|
}
|
|
9437
9788
|
function createPathParseTool() {
|
|
9438
9789
|
return core.toolBuilder().name("path-parse").description("Parse a file path into its components (directory, filename, extension, etc.).").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "parse", "filesystem"]).schema(pathParseSchema).implement(async (input) => {
|
|
9439
|
-
const parsed =
|
|
9790
|
+
const parsed = path__namespace.parse(input.path);
|
|
9440
9791
|
return {
|
|
9441
9792
|
root: parsed.root,
|
|
9442
9793
|
dir: parsed.dir,
|
|
9443
9794
|
base: parsed.base,
|
|
9444
9795
|
name: parsed.name,
|
|
9445
9796
|
ext: parsed.ext,
|
|
9446
|
-
isAbsolute:
|
|
9797
|
+
isAbsolute: path__namespace.isAbsolute(input.path)
|
|
9447
9798
|
};
|
|
9448
9799
|
}).build();
|
|
9449
9800
|
}
|
|
9450
9801
|
function createPathBasenameTool() {
|
|
9451
9802
|
return core.toolBuilder().name("path-basename").description("Get the last portion of a path (filename with extension). Optionally remove the extension.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "basename", "filename", "filesystem"]).schema(pathBasenameSchema).implement(async (input) => {
|
|
9452
|
-
const
|
|
9803
|
+
const basename5 = input.removeExtension ? path__namespace.basename(input.path, path__namespace.extname(input.path)) : path__namespace.basename(input.path);
|
|
9453
9804
|
return {
|
|
9454
|
-
basename:
|
|
9455
|
-
extension:
|
|
9805
|
+
basename: basename5,
|
|
9806
|
+
extension: path__namespace.extname(input.path)
|
|
9456
9807
|
};
|
|
9457
9808
|
}).build();
|
|
9458
9809
|
}
|
|
9459
9810
|
function createPathDirnameTool() {
|
|
9460
9811
|
return core.toolBuilder().name("path-dirname").description("Get the directory name of a path (everything except the last portion).").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "dirname", "directory", "filesystem"]).schema(pathDirnameSchema).implement(async (input) => {
|
|
9461
|
-
const
|
|
9812
|
+
const dirname4 = path__namespace.dirname(input.path);
|
|
9462
9813
|
return {
|
|
9463
|
-
dirname:
|
|
9464
|
-
basename:
|
|
9814
|
+
dirname: dirname4,
|
|
9815
|
+
basename: path__namespace.basename(input.path)
|
|
9465
9816
|
};
|
|
9466
9817
|
}).build();
|
|
9467
9818
|
}
|
|
9468
9819
|
function createPathExtensionTool() {
|
|
9469
9820
|
return core.toolBuilder().name("path-extension").description('Get the file extension from a path (including the dot, e.g., ".txt").').category(core.ToolCategory.FILE_SYSTEM).tags(["path", "extension", "ext", "filesystem"]).schema(pathExtensionSchema).implement(async (input) => {
|
|
9470
|
-
const ext =
|
|
9821
|
+
const ext = path__namespace.extname(input.path);
|
|
9471
9822
|
return {
|
|
9472
9823
|
extension: ext,
|
|
9473
9824
|
hasExtension: ext.length > 0,
|
|
9474
|
-
filename:
|
|
9825
|
+
filename: path__namespace.basename(input.path, ext)
|
|
9475
9826
|
};
|
|
9476
9827
|
}).build();
|
|
9477
9828
|
}
|
|
9478
9829
|
function createPathRelativeTool() {
|
|
9479
9830
|
return core.toolBuilder().name("path-relative").description("Get the relative path from one path to another.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "relative", "filesystem"]).schema(pathRelativeSchema).implement(async (input) => {
|
|
9480
|
-
const
|
|
9831
|
+
const relative4 = path__namespace.relative(input.from, input.to);
|
|
9481
9832
|
return {
|
|
9482
|
-
relativePath:
|
|
9833
|
+
relativePath: relative4,
|
|
9483
9834
|
from: input.from,
|
|
9484
9835
|
to: input.to
|
|
9485
9836
|
};
|
|
@@ -9487,7 +9838,7 @@ function createPathRelativeTool() {
|
|
|
9487
9838
|
}
|
|
9488
9839
|
function createPathNormalizeTool() {
|
|
9489
9840
|
return core.toolBuilder().name("path-normalize").description('Normalize a path by resolving ".." and "." segments and removing duplicate separators.').category(core.ToolCategory.FILE_SYSTEM).tags(["path", "normalize", "filesystem"]).schema(pathNormalizeSchema).implement(async (input) => {
|
|
9490
|
-
const normalized =
|
|
9841
|
+
const normalized = path__namespace.normalize(input.path);
|
|
9491
9842
|
return {
|
|
9492
9843
|
normalized,
|
|
9493
9844
|
original: input.path
|
|
@@ -10395,14 +10746,19 @@ exports.CreditCardValidatorSchema = CreditCardValidatorSchema;
|
|
|
10395
10746
|
exports.CurrentDateTimeSchema = CurrentDateTimeSchema;
|
|
10396
10747
|
exports.DEFAULT_BATCH_SIZE = DEFAULT_BATCH_SIZE;
|
|
10397
10748
|
exports.DEFAULT_CHUNK_SIZE = DEFAULT_CHUNK_SIZE;
|
|
10749
|
+
exports.DEFAULT_DESTINATION_POLICY = DEFAULT_DESTINATION_POLICY;
|
|
10750
|
+
exports.DEFAULT_FILE_SYSTEM_POLICY = DEFAULT_FILE_SYSTEM_POLICY;
|
|
10398
10751
|
exports.DEFAULT_RETRY_CONFIG = DEFAULT_RETRY_CONFIG2;
|
|
10399
10752
|
exports.DateArithmeticSchema = DateArithmeticSchema;
|
|
10400
10753
|
exports.DateComparisonSchema = DateComparisonSchema;
|
|
10401
10754
|
exports.DateDifferenceSchema = DateDifferenceSchema;
|
|
10402
10755
|
exports.DateFormatterSchema = DateFormatterSchema;
|
|
10756
|
+
exports.DestinationPolicyError = DestinationPolicyError;
|
|
10403
10757
|
exports.DuckDuckGoProvider = DuckDuckGoProvider;
|
|
10404
10758
|
exports.EmailValidatorSchema = EmailValidatorSchema;
|
|
10405
10759
|
exports.EmbeddingManager = EmbeddingManager;
|
|
10760
|
+
exports.FileSystemPolicy = FileSystemPolicy;
|
|
10761
|
+
exports.FileSystemPolicyError = FileSystemPolicyError;
|
|
10406
10762
|
exports.HttpMethod = HttpMethod;
|
|
10407
10763
|
exports.IpValidatorSchema = IpValidatorSchema;
|
|
10408
10764
|
exports.MAX_BATCH_SIZE = MAX_BATCH_SIZE;
|
|
@@ -10433,6 +10789,7 @@ exports.arrayMapSchema = arrayMapSchema;
|
|
|
10433
10789
|
exports.arraySort = arraySort;
|
|
10434
10790
|
exports.arraySortSchema = arraySortSchema;
|
|
10435
10791
|
exports.askHumanTool = askHumanTool;
|
|
10792
|
+
exports.assertDestinationAllowed = assertDestinationAllowed;
|
|
10436
10793
|
exports.benchmarkBatchExecution = benchmarkBatchExecution;
|
|
10437
10794
|
exports.benchmarkStreamingSelectMemory = benchmarkStreamingSelectMemory;
|
|
10438
10795
|
exports.buildDeleteQuery = buildDeleteQuery;
|
|
@@ -10475,6 +10832,7 @@ exports.createFileExistsTool = createFileExistsTool;
|
|
|
10475
10832
|
exports.createFileOperationTools = createFileOperationTools;
|
|
10476
10833
|
exports.createFileReaderTool = createFileReaderTool;
|
|
10477
10834
|
exports.createFileSearchTool = createFileSearchTool;
|
|
10835
|
+
exports.createFileSystemPolicy = createFileSystemPolicy;
|
|
10478
10836
|
exports.createFileWriterTool = createFileWriterTool;
|
|
10479
10837
|
exports.createHtmlParserTool = createHtmlParserTool;
|
|
10480
10838
|
exports.createHtmlParserTools = createHtmlParserTools;
|
|
@@ -10682,6 +11040,8 @@ exports.relationalInsert = relationalInsert;
|
|
|
10682
11040
|
exports.relationalQuery = relationalQuery;
|
|
10683
11041
|
exports.relationalSelect = relationalSelect;
|
|
10684
11042
|
exports.relationalUpdate = relationalUpdate;
|
|
11043
|
+
exports.requestWithDestinationPolicy = requestWithDestinationPolicy;
|
|
11044
|
+
exports.resolveFileSystemPolicy = resolveFileSystemPolicy;
|
|
10685
11045
|
exports.retryWithBackoff = retryWithBackoff2;
|
|
10686
11046
|
exports.scraperTools = scraperTools;
|
|
10687
11047
|
exports.searchConfluence = searchConfluence;
|