@agentforge/tools 0.9.1 → 0.10.1
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 +192 -9
- package/dist/index.cjs +2588 -1498
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4572 -991
- package/dist/index.d.ts +4572 -991
- package/dist/index.js +2413 -1496
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { toolBuilder, ToolCategory, LogLevel, createLogger } from '@agentforge/core';
|
|
2
|
+
import axios12 from 'axios';
|
|
2
3
|
import { z } from 'zod';
|
|
3
|
-
import
|
|
4
|
-
import * as cheerio2 from 'cheerio';
|
|
4
|
+
import * as cheerio from 'cheerio';
|
|
5
5
|
import { WebClient } from '@slack/web-api';
|
|
6
6
|
import { parse } from 'csv-parse/sync';
|
|
7
7
|
import { stringify } from 'csv-stringify/sync';
|
|
8
8
|
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
|
|
9
9
|
import { promises } from 'fs';
|
|
10
|
-
import * as
|
|
10
|
+
import * as path7 from 'path';
|
|
11
11
|
import { format, parse as parse$1, isValid, add, sub, differenceInDays, differenceInHours, differenceInMinutes, isAfter, isBefore } from 'date-fns';
|
|
12
12
|
import { randomUUID } from 'crypto';
|
|
13
13
|
|
|
14
|
-
// src/web/http-client.ts
|
|
14
|
+
// src/web/http/tools/http-client.ts
|
|
15
15
|
var HttpMethod = z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
|
|
16
16
|
var httpRequestSchema = z.object({
|
|
17
17
|
url: z.string().url().describe("The URL to make the request to"),
|
|
@@ -21,54 +21,79 @@ var httpRequestSchema = z.object({
|
|
|
21
21
|
timeout: z.number().default(3e4).describe("Request timeout in milliseconds"),
|
|
22
22
|
params: z.record(z.string()).optional().describe("Optional URL query parameters")
|
|
23
23
|
});
|
|
24
|
-
var
|
|
25
|
-
const config = {
|
|
26
|
-
method: input.method,
|
|
27
|
-
url: input.url,
|
|
28
|
-
headers: input.headers,
|
|
29
|
-
data: input.body,
|
|
30
|
-
timeout: input.timeout,
|
|
31
|
-
params: input.params,
|
|
32
|
-
validateStatus: () => true
|
|
33
|
-
// Don't throw on any status code
|
|
34
|
-
};
|
|
35
|
-
const response = await axios(config);
|
|
36
|
-
return {
|
|
37
|
-
status: response.status,
|
|
38
|
-
statusText: response.statusText,
|
|
39
|
-
headers: response.headers,
|
|
40
|
-
data: response.data,
|
|
41
|
-
url: input.url,
|
|
42
|
-
method: input.method ?? "GET"
|
|
43
|
-
};
|
|
44
|
-
}).build();
|
|
45
|
-
var httpGet = toolBuilder().name("http-get").description("Make a simple HTTP GET request to a URL and return the response data.").category(ToolCategory.WEB).tags(["http", "get", "fetch", "web"]).schema(z.object({
|
|
24
|
+
var httpGetSchema = z.object({
|
|
46
25
|
url: z.string().url().describe("The URL to fetch"),
|
|
47
26
|
headers: z.record(z.string()).optional().describe("Optional HTTP headers"),
|
|
48
27
|
params: z.record(z.string()).optional().describe("Optional URL query parameters")
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
headers: input.headers,
|
|
52
|
-
params: input.params,
|
|
53
|
-
timeout: 3e4
|
|
54
|
-
});
|
|
55
|
-
return response.data;
|
|
56
|
-
}).build();
|
|
57
|
-
var httpPost = toolBuilder().name("http-post").description("Make a simple HTTP POST request with JSON body and return the response data.").category(ToolCategory.WEB).tags(["http", "post", "api", "web"]).schema(z.object({
|
|
28
|
+
});
|
|
29
|
+
var httpPostSchema = z.object({
|
|
58
30
|
url: z.string().url().describe("The URL to post to"),
|
|
59
31
|
body: z.any().describe("The request body (will be sent as JSON)"),
|
|
60
32
|
headers: z.record(z.string()).optional().describe("Optional HTTP headers")
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// src/web/http/tools/http-client.ts
|
|
36
|
+
function createHttpClientTool(defaultTimeout = 3e4, defaultHeaders = {}) {
|
|
37
|
+
return 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(ToolCategory.WEB).tags(["http", "api", "request", "web"]).schema(httpRequestSchema).implement(async (input) => {
|
|
38
|
+
const config = {
|
|
39
|
+
method: input.method,
|
|
40
|
+
url: input.url,
|
|
41
|
+
headers: { ...defaultHeaders, ...input.headers },
|
|
42
|
+
data: input.body,
|
|
43
|
+
timeout: input.timeout ?? defaultTimeout,
|
|
44
|
+
params: input.params,
|
|
45
|
+
validateStatus: () => true
|
|
46
|
+
// Don't throw on any status code
|
|
47
|
+
};
|
|
48
|
+
const response = await axios12(config);
|
|
49
|
+
return {
|
|
50
|
+
status: response.status,
|
|
51
|
+
statusText: response.statusText,
|
|
52
|
+
headers: response.headers,
|
|
53
|
+
data: response.data,
|
|
54
|
+
url: input.url,
|
|
55
|
+
method: input.method ?? "GET"
|
|
56
|
+
};
|
|
57
|
+
}).build();
|
|
58
|
+
}
|
|
59
|
+
function createHttpGetTool(defaultTimeout = 3e4, defaultHeaders = {}) {
|
|
60
|
+
return toolBuilder().name("http-get").description("Make a simple HTTP GET request to a URL and return the response data.").category(ToolCategory.WEB).tags(["http", "get", "fetch", "web"]).schema(httpGetSchema).implement(async (input) => {
|
|
61
|
+
const response = await axios12.get(input.url, {
|
|
62
|
+
headers: { ...defaultHeaders, ...input.headers },
|
|
63
|
+
params: input.params,
|
|
64
|
+
timeout: defaultTimeout
|
|
65
|
+
});
|
|
66
|
+
return response.data;
|
|
67
|
+
}).build();
|
|
68
|
+
}
|
|
69
|
+
function createHttpPostTool(defaultTimeout = 3e4, defaultHeaders = {}) {
|
|
70
|
+
return toolBuilder().name("http-post").description("Make a simple HTTP POST request with JSON body and return the response data.").category(ToolCategory.WEB).tags(["http", "post", "api", "web"]).schema(httpPostSchema).implement(async (input) => {
|
|
71
|
+
const response = await axios12.post(input.url, input.body, {
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
...defaultHeaders,
|
|
75
|
+
...input.headers
|
|
76
|
+
},
|
|
77
|
+
timeout: defaultTimeout
|
|
78
|
+
});
|
|
79
|
+
return response.data;
|
|
80
|
+
}).build();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/web/http/index.ts
|
|
84
|
+
var httpClient = createHttpClientTool();
|
|
85
|
+
var httpGet = createHttpGetTool();
|
|
86
|
+
var httpPost = createHttpPostTool();
|
|
87
|
+
var httpTools = [httpClient, httpGet, httpPost];
|
|
88
|
+
function createHttpTools(config = {}) {
|
|
89
|
+
const { defaultTimeout = 3e4, defaultHeaders = {} } = config;
|
|
90
|
+
return [
|
|
91
|
+
createHttpClientTool(defaultTimeout, defaultHeaders),
|
|
92
|
+
createHttpGetTool(defaultTimeout, defaultHeaders),
|
|
93
|
+
createHttpPostTool(defaultTimeout, defaultHeaders)
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
var webScraperSchema = z.object({
|
|
72
97
|
url: z.string().url().describe("The URL of the web page to scrape"),
|
|
73
98
|
selector: z.string().optional().describe("Optional CSS selector to extract specific elements"),
|
|
74
99
|
extractText: z.boolean().default(true).describe("Extract text content from the page"),
|
|
@@ -77,240 +102,295 @@ var webScraper = toolBuilder().name("web-scraper").description("Scrape and extra
|
|
|
77
102
|
extractImages: z.boolean().default(false).describe("Extract all image URLs from the page"),
|
|
78
103
|
extractMetadata: z.boolean().default(false).describe("Extract meta tags (title, description, etc.)"),
|
|
79
104
|
timeout: z.number().default(3e4).describe("Request timeout in milliseconds")
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const html = response.data;
|
|
88
|
-
const $ = cheerio2.load(html);
|
|
89
|
-
const result = {
|
|
90
|
-
url: input.url
|
|
91
|
-
};
|
|
92
|
-
const $selected = input.selector ? $(input.selector) : $("body");
|
|
93
|
-
if (input.extractText) {
|
|
94
|
-
result.text = $selected.text().trim();
|
|
95
|
-
}
|
|
96
|
-
if (input.extractHtml) {
|
|
97
|
-
result.html = $selected.html() || "";
|
|
98
|
-
}
|
|
99
|
-
if (input.extractLinks) {
|
|
100
|
-
result.links = [];
|
|
101
|
-
$("a[href]").each((_, el) => {
|
|
102
|
-
const href = $(el).attr("href");
|
|
103
|
-
if (href) {
|
|
104
|
-
try {
|
|
105
|
-
const absoluteUrl = new URL(href, input.url).href;
|
|
106
|
-
result.links.push(absoluteUrl);
|
|
107
|
-
} catch {
|
|
108
|
-
result.links.push(href);
|
|
109
|
-
}
|
|
105
|
+
});
|
|
106
|
+
function createWebScraperTool(defaultTimeout = 3e4, userAgent = "Mozilla/5.0 (compatible; AgentForge/1.0; +https://agentforge.dev)") {
|
|
107
|
+
return toolBuilder().name("web-scraper").description("Scrape and extract data from web pages. Can extract text, HTML, links, images, and use CSS selectors to target specific elements.").category(ToolCategory.WEB).tags(["scraper", "web", "html", "extract", "parse"]).schema(webScraperSchema).implement(async (input) => {
|
|
108
|
+
const response = await axios12.get(input.url, {
|
|
109
|
+
timeout: input.timeout || defaultTimeout,
|
|
110
|
+
headers: {
|
|
111
|
+
"User-Agent": userAgent
|
|
110
112
|
}
|
|
111
113
|
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
result
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
114
|
+
const html = response.data;
|
|
115
|
+
const $ = cheerio.load(html);
|
|
116
|
+
const result = {
|
|
117
|
+
url: input.url
|
|
118
|
+
};
|
|
119
|
+
const $selected = input.selector ? $(input.selector) : $("body");
|
|
120
|
+
if (input.extractText) {
|
|
121
|
+
result.text = $selected.text().trim();
|
|
122
|
+
}
|
|
123
|
+
if (input.extractHtml) {
|
|
124
|
+
result.html = $selected.html() || "";
|
|
125
|
+
}
|
|
126
|
+
if (input.extractLinks) {
|
|
127
|
+
result.links = [];
|
|
128
|
+
$("a[href]").each((_, el) => {
|
|
129
|
+
const href = $(el).attr("href");
|
|
130
|
+
if (href) {
|
|
131
|
+
try {
|
|
132
|
+
const absoluteUrl = new URL(href, input.url).href;
|
|
133
|
+
result.links.push(absoluteUrl);
|
|
134
|
+
} catch {
|
|
135
|
+
result.links.push(href);
|
|
136
|
+
}
|
|
123
137
|
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (input.extractImages) {
|
|
141
|
+
result.images = [];
|
|
142
|
+
$("img[src]").each((_, el) => {
|
|
143
|
+
const src = $(el).attr("src");
|
|
144
|
+
if (src) {
|
|
145
|
+
try {
|
|
146
|
+
const absoluteUrl = new URL(src, input.url).href;
|
|
147
|
+
result.images.push(absoluteUrl);
|
|
148
|
+
} catch {
|
|
149
|
+
result.images.push(src);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (input.extractMetadata) {
|
|
155
|
+
result.metadata = {};
|
|
156
|
+
const title = $("title").text() || $('meta[property="og:title"]').attr("content");
|
|
157
|
+
if (title) result.metadata.title = title;
|
|
158
|
+
const description = $('meta[name="description"]').attr("content") || $('meta[property="og:description"]').attr("content");
|
|
159
|
+
if (description) result.metadata.description = description;
|
|
160
|
+
$("meta[name], meta[property]").each((_, el) => {
|
|
161
|
+
const name = $(el).attr("name") || $(el).attr("property");
|
|
162
|
+
const content = $(el).attr("content");
|
|
163
|
+
if (name && content) {
|
|
164
|
+
result.metadata[name] = content;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (input.selector) {
|
|
169
|
+
result.selected = $selected.map((_, el) => ({
|
|
170
|
+
text: $(el).text().trim(),
|
|
171
|
+
html: $(el).html()
|
|
172
|
+
})).get();
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}).build();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/web/scraper/index.ts
|
|
179
|
+
var webScraper = createWebScraperTool();
|
|
180
|
+
var scraperTools = [webScraper];
|
|
181
|
+
function createScraperTools(config = {}) {
|
|
182
|
+
const { defaultTimeout = 3e4, userAgent = "Mozilla/5.0 (compatible; AgentForge/1.0; +https://agentforge.dev)" } = config;
|
|
183
|
+
return [createWebScraperTool(defaultTimeout, userAgent)];
|
|
184
|
+
}
|
|
185
|
+
var htmlParserSchema = z.object({
|
|
150
186
|
html: z.string().describe("The HTML content to parse"),
|
|
151
187
|
selector: z.string().describe("CSS selector to find elements"),
|
|
152
188
|
extractText: z.boolean().default(true).describe("Extract text content from selected elements"),
|
|
153
189
|
extractHtml: z.boolean().default(false).describe("Extract inner HTML of selected elements"),
|
|
154
190
|
extractAttributes: z.array(z.string().describe("String value")).optional().describe('List of attributes to extract (e.g., ["href", "src", "class"])')
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
const $selected = $(input.selector);
|
|
158
|
-
const results = $selected.map((_, el) => {
|
|
159
|
-
const $el = $(el);
|
|
160
|
-
const item = {};
|
|
161
|
-
if (input.extractText) {
|
|
162
|
-
item.text = $el.text().trim();
|
|
163
|
-
}
|
|
164
|
-
if (input.extractHtml) {
|
|
165
|
-
item.html = $el.html();
|
|
166
|
-
}
|
|
167
|
-
if (input.extractAttributes && input.extractAttributes.length > 0) {
|
|
168
|
-
item.attributes = {};
|
|
169
|
-
for (const attr of input.extractAttributes) {
|
|
170
|
-
const value = $el.attr(attr);
|
|
171
|
-
if (value !== void 0) {
|
|
172
|
-
item.attributes[attr] = value;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return item;
|
|
177
|
-
}).get();
|
|
178
|
-
return {
|
|
179
|
-
count: results.length,
|
|
180
|
-
results
|
|
181
|
-
};
|
|
182
|
-
}).build();
|
|
183
|
-
var extractLinks = toolBuilder().name("extract-links").description("Extract all links (anchor tags) from HTML content with their text and href attributes.").category(ToolCategory.WEB).tags(["html", "links", "extract", "anchor"]).schema(z.object({
|
|
191
|
+
});
|
|
192
|
+
var extractLinksSchema = z.object({
|
|
184
193
|
html: z.string().describe("The HTML content to extract links from"),
|
|
185
194
|
baseUrl: z.string().url().optional().describe("Optional base URL to resolve relative links")
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
const links = [];
|
|
189
|
-
$("a[href]").each((_, el) => {
|
|
190
|
-
const $el = $(el);
|
|
191
|
-
let href = $el.attr("href") || "";
|
|
192
|
-
if (input.baseUrl && href) {
|
|
193
|
-
try {
|
|
194
|
-
href = new URL(href, input.baseUrl).href;
|
|
195
|
-
} catch {
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
links.push({
|
|
199
|
-
text: $el.text().trim(),
|
|
200
|
-
href,
|
|
201
|
-
title: $el.attr("title")
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
return {
|
|
205
|
-
count: links.length,
|
|
206
|
-
links
|
|
207
|
-
};
|
|
208
|
-
}).build();
|
|
209
|
-
var extractImages = toolBuilder().name("extract-images").description("Extract all images from HTML content with their src, alt, and other attributes.").category(ToolCategory.WEB).tags(["html", "images", "extract", "img"]).schema(z.object({
|
|
195
|
+
});
|
|
196
|
+
var extractImagesSchema = z.object({
|
|
210
197
|
html: z.string().describe("The HTML content to extract images from"),
|
|
211
198
|
baseUrl: z.string().url().optional().describe("Optional base URL to resolve relative image URLs")
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const $
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
199
|
+
});
|
|
200
|
+
function createHtmlParserTool() {
|
|
201
|
+
return toolBuilder().name("html-parser").description("Parse HTML content and extract data using CSS selectors. Returns text, attributes, and structure of selected elements.").category(ToolCategory.WEB).tags(["html", "parser", "css", "selector", "extract"]).schema(htmlParserSchema).implement(async (input) => {
|
|
202
|
+
const $ = cheerio.load(input.html);
|
|
203
|
+
const $selected = $(input.selector);
|
|
204
|
+
const results = $selected.map((_, el) => {
|
|
205
|
+
const $el = $(el);
|
|
206
|
+
const item = {};
|
|
207
|
+
if (input.extractText) {
|
|
208
|
+
item.text = $el.text().trim();
|
|
222
209
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
210
|
+
if (input.extractHtml) {
|
|
211
|
+
item.html = $el.html();
|
|
212
|
+
}
|
|
213
|
+
if (input.extractAttributes && input.extractAttributes.length > 0) {
|
|
214
|
+
item.attributes = {};
|
|
215
|
+
for (const attr of input.extractAttributes) {
|
|
216
|
+
const value = $el.attr(attr);
|
|
217
|
+
if (value !== void 0) {
|
|
218
|
+
item.attributes[attr] = value;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return item;
|
|
223
|
+
}).get();
|
|
224
|
+
return {
|
|
225
|
+
count: results.length,
|
|
226
|
+
results
|
|
227
|
+
};
|
|
228
|
+
}).build();
|
|
229
|
+
}
|
|
230
|
+
function createExtractLinksTool() {
|
|
231
|
+
return toolBuilder().name("extract-links").description("Extract all links (anchor tags) from HTML content with their text and href attributes.").category(ToolCategory.WEB).tags(["html", "links", "extract", "anchor"]).schema(extractLinksSchema).implement(async (input) => {
|
|
232
|
+
const $ = cheerio.load(input.html);
|
|
233
|
+
const links = [];
|
|
234
|
+
$("a[href]").each((_, el) => {
|
|
235
|
+
const $el = $(el);
|
|
236
|
+
let href = $el.attr("href") || "";
|
|
237
|
+
if (input.baseUrl && href) {
|
|
238
|
+
try {
|
|
239
|
+
href = new URL(href, input.baseUrl).href;
|
|
240
|
+
} catch {
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
links.push({
|
|
244
|
+
text: $el.text().trim(),
|
|
245
|
+
href,
|
|
246
|
+
title: $el.attr("title")
|
|
247
|
+
});
|
|
230
248
|
});
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
249
|
+
return {
|
|
250
|
+
count: links.length,
|
|
251
|
+
links
|
|
252
|
+
};
|
|
253
|
+
}).build();
|
|
254
|
+
}
|
|
255
|
+
function createExtractImagesTool() {
|
|
256
|
+
return toolBuilder().name("extract-images").description("Extract all images from HTML content with their src, alt, and other attributes.").category(ToolCategory.WEB).tags(["html", "images", "extract", "img"]).schema(extractImagesSchema).implement(async (input) => {
|
|
257
|
+
const $ = cheerio.load(input.html);
|
|
258
|
+
const images = [];
|
|
259
|
+
$("img[src]").each((_, el) => {
|
|
260
|
+
const $el = $(el);
|
|
261
|
+
let src = $el.attr("src") || "";
|
|
262
|
+
if (input.baseUrl && src) {
|
|
263
|
+
try {
|
|
264
|
+
src = new URL(src, input.baseUrl).href;
|
|
265
|
+
} catch {
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
images.push({
|
|
269
|
+
src,
|
|
270
|
+
alt: $el.attr("alt"),
|
|
271
|
+
title: $el.attr("title"),
|
|
272
|
+
width: $el.attr("width"),
|
|
273
|
+
height: $el.attr("height")
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
return {
|
|
277
|
+
count: images.length,
|
|
278
|
+
images
|
|
279
|
+
};
|
|
280
|
+
}).build();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/web/html-parser/index.ts
|
|
284
|
+
var htmlParser = createHtmlParserTool();
|
|
285
|
+
var extractLinks = createExtractLinksTool();
|
|
286
|
+
var extractImages = createExtractImagesTool();
|
|
287
|
+
var htmlParserTools = [htmlParser, extractLinks, extractImages];
|
|
288
|
+
function createHtmlParserTools(config = {}) {
|
|
289
|
+
return [
|
|
290
|
+
createHtmlParserTool(),
|
|
291
|
+
createExtractLinksTool(),
|
|
292
|
+
createExtractImagesTool()
|
|
293
|
+
];
|
|
294
|
+
}
|
|
295
|
+
var urlValidatorSchema = z.object({
|
|
238
296
|
url: z.string().describe("The URL to validate and parse")
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
url: parsed.href,
|
|
243
|
-
protocol: parsed.protocol,
|
|
244
|
-
hostname: parsed.hostname,
|
|
245
|
-
port: parsed.port,
|
|
246
|
-
pathname: parsed.pathname,
|
|
247
|
-
search: parsed.search,
|
|
248
|
-
hash: parsed.hash,
|
|
249
|
-
origin: parsed.origin
|
|
250
|
-
};
|
|
251
|
-
}).build();
|
|
252
|
-
var urlBuilder = toolBuilder().name("url-builder").description("Build a URL from components (protocol, hostname, path, query parameters, hash).").category(ToolCategory.WEB).tags(["url", "builder", "construct"]).schema(z.object({
|
|
297
|
+
});
|
|
298
|
+
var urlBuilderSchema = z.object({
|
|
253
299
|
protocol: z.string().default("https").describe("Protocol (http, https, etc.)"),
|
|
254
300
|
hostname: z.string().describe("Hostname or domain name"),
|
|
255
301
|
port: z.string().optional().describe("Optional port number"),
|
|
256
302
|
pathname: z.string().default("/").describe("URL path"),
|
|
257
303
|
query: z.record(z.string()).optional().describe("Query parameters as key-value pairs"),
|
|
258
304
|
hash: z.string().optional().describe("URL hash/fragment")
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
if (input.port) {
|
|
262
|
-
url.port = input.port;
|
|
263
|
-
}
|
|
264
|
-
url.pathname = input.pathname ?? "/";
|
|
265
|
-
if (input.query) {
|
|
266
|
-
Object.entries(input.query).forEach(([key, value]) => {
|
|
267
|
-
url.searchParams.append(key, value);
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
if (input.hash) {
|
|
271
|
-
url.hash = input.hash;
|
|
272
|
-
}
|
|
273
|
-
return {
|
|
274
|
-
url: url.href,
|
|
275
|
-
components: {
|
|
276
|
-
protocol: url.protocol,
|
|
277
|
-
hostname: url.hostname,
|
|
278
|
-
port: url.port,
|
|
279
|
-
pathname: url.pathname,
|
|
280
|
-
search: url.search,
|
|
281
|
-
hash: url.hash,
|
|
282
|
-
origin: url.origin
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
}).build();
|
|
286
|
-
var urlQueryParser = toolBuilder().name("url-query-parser").description("Parse query parameters from a URL or query string into a key-value object.").category(ToolCategory.WEB).tags(["url", "query", "parse", "params"]).schema(z.object({
|
|
305
|
+
});
|
|
306
|
+
var urlQueryParserSchema = z.object({
|
|
287
307
|
input: z.string().describe('URL or query string to parse (e.g., "?foo=bar&baz=qux" or full URL)')
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
308
|
+
});
|
|
309
|
+
function createUrlValidatorTool() {
|
|
310
|
+
return toolBuilder().name("url-validator").description("Validate and parse URLs. Returns detailed information about the URL structure including protocol, hostname, path, query parameters, and hash.").category(ToolCategory.WEB).tags(["url", "validator", "parse", "validate"]).schema(urlValidatorSchema).implementSafe(async (input) => {
|
|
311
|
+
const parsed = new URL(input.url);
|
|
312
|
+
return {
|
|
313
|
+
url: parsed.href,
|
|
314
|
+
protocol: parsed.protocol,
|
|
315
|
+
hostname: parsed.hostname,
|
|
316
|
+
port: parsed.port,
|
|
317
|
+
pathname: parsed.pathname,
|
|
318
|
+
search: parsed.search,
|
|
319
|
+
hash: parsed.hash,
|
|
320
|
+
origin: parsed.origin
|
|
321
|
+
};
|
|
322
|
+
}).build();
|
|
323
|
+
}
|
|
324
|
+
function createUrlBuilderTool() {
|
|
325
|
+
return toolBuilder().name("url-builder").description("Build a URL from components (protocol, hostname, path, query parameters, hash).").category(ToolCategory.WEB).tags(["url", "builder", "construct"]).schema(urlBuilderSchema).implement(async (input) => {
|
|
326
|
+
const url = new URL(`${input.protocol}://${input.hostname}`);
|
|
327
|
+
if (input.port) {
|
|
328
|
+
url.port = input.port;
|
|
329
|
+
}
|
|
330
|
+
url.pathname = input.pathname ?? "/";
|
|
331
|
+
if (input.query) {
|
|
332
|
+
Object.entries(input.query).forEach(([key, value]) => {
|
|
333
|
+
url.searchParams.append(key, value);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (input.hash) {
|
|
337
|
+
url.hash = input.hash;
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
url: url.href,
|
|
341
|
+
components: {
|
|
342
|
+
protocol: url.protocol,
|
|
343
|
+
hostname: url.hostname,
|
|
344
|
+
port: url.port,
|
|
345
|
+
pathname: url.pathname,
|
|
346
|
+
search: url.search,
|
|
347
|
+
hash: url.hash,
|
|
348
|
+
origin: url.origin
|
|
304
349
|
}
|
|
305
|
-
}
|
|
306
|
-
|
|
350
|
+
};
|
|
351
|
+
}).build();
|
|
352
|
+
}
|
|
353
|
+
function createUrlQueryParserTool() {
|
|
354
|
+
return toolBuilder().name("url-query-parser").description("Parse query parameters from a URL or query string into a key-value object.").category(ToolCategory.WEB).tags(["url", "query", "parse", "params"]).schema(urlQueryParserSchema).implement(async (input) => {
|
|
355
|
+
let searchParams;
|
|
356
|
+
try {
|
|
357
|
+
const url = new URL(input.input);
|
|
358
|
+
searchParams = url.searchParams;
|
|
359
|
+
} catch {
|
|
360
|
+
const queryString = input.input.startsWith("?") ? input.input.slice(1) : input.input;
|
|
361
|
+
searchParams = new URLSearchParams(queryString);
|
|
307
362
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
363
|
+
const params = {};
|
|
364
|
+
searchParams.forEach((value, key) => {
|
|
365
|
+
if (params[key]) {
|
|
366
|
+
if (Array.isArray(params[key])) {
|
|
367
|
+
params[key].push(value);
|
|
368
|
+
} else {
|
|
369
|
+
params[key] = [params[key], value];
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
params[key] = value;
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
return {
|
|
376
|
+
params,
|
|
377
|
+
count: Object.keys(params).length
|
|
378
|
+
};
|
|
379
|
+
}).build();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// src/web/url-validator/index.ts
|
|
383
|
+
var urlValidator = createUrlValidatorTool();
|
|
384
|
+
var urlBuilder = createUrlBuilderTool();
|
|
385
|
+
var urlQueryParser = createUrlQueryParserTool();
|
|
386
|
+
var urlValidatorTools = [urlValidator, urlBuilder, urlQueryParser];
|
|
387
|
+
function createUrlValidatorTools(config = {}) {
|
|
388
|
+
return [
|
|
389
|
+
createUrlValidatorTool(),
|
|
390
|
+
createUrlBuilderTool(),
|
|
391
|
+
createUrlQueryParserTool()
|
|
392
|
+
];
|
|
393
|
+
}
|
|
314
394
|
var webSearchSchema = z.object({
|
|
315
395
|
query: z.string().min(1).describe("The search query"),
|
|
316
396
|
maxResults: z.number().min(1).max(50).default(10).describe("Maximum number of results to return (1-50)"),
|
|
@@ -415,7 +495,7 @@ var DuckDuckGoProvider = class {
|
|
|
415
495
|
async search(query, maxResults, timeout = DEFAULT_TIMEOUT) {
|
|
416
496
|
return retryWithBackoff(async () => {
|
|
417
497
|
try {
|
|
418
|
-
const response = await
|
|
498
|
+
const response = await axios12.get(
|
|
419
499
|
"https://api.duckduckgo.com/",
|
|
420
500
|
{
|
|
421
501
|
params: {
|
|
@@ -519,7 +599,7 @@ var SerperProvider = class {
|
|
|
519
599
|
}
|
|
520
600
|
return retryWithBackoff(async () => {
|
|
521
601
|
try {
|
|
522
|
-
const response = await
|
|
602
|
+
const response = await axios12.post(
|
|
523
603
|
"https://google.serper.dev/search",
|
|
524
604
|
{
|
|
525
605
|
q: query,
|
|
@@ -657,8 +737,28 @@ var webSearch = toolBuilder().name("web-search").description(
|
|
|
657
737
|
};
|
|
658
738
|
}
|
|
659
739
|
}).build();
|
|
660
|
-
|
|
661
|
-
|
|
740
|
+
function createGetConfiguredSlackClient(token, botName = "AgentForge Bot", botIcon = ":robot_face:") {
|
|
741
|
+
let configuredClient = null;
|
|
742
|
+
return function getConfiguredSlackClient() {
|
|
743
|
+
if (!configuredClient) {
|
|
744
|
+
const slackToken = token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN;
|
|
745
|
+
if (!slackToken) {
|
|
746
|
+
throw new Error(
|
|
747
|
+
"Slack token not configured. Please provide a token in config or set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
configuredClient = new WebClient(slackToken);
|
|
751
|
+
}
|
|
752
|
+
return {
|
|
753
|
+
client: configuredClient,
|
|
754
|
+
config: {
|
|
755
|
+
token: token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN || "",
|
|
756
|
+
botName,
|
|
757
|
+
botIcon
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
};
|
|
761
|
+
}
|
|
662
762
|
var defaultSlackClient = null;
|
|
663
763
|
function getDefaultSlackClient() {
|
|
664
764
|
if (!defaultSlackClient) {
|
|
@@ -670,196 +770,17 @@ function getDefaultSlackClient() {
|
|
|
670
770
|
}
|
|
671
771
|
defaultSlackClient = new WebClient(token);
|
|
672
772
|
}
|
|
673
|
-
return defaultSlackClient;
|
|
674
|
-
}
|
|
675
|
-
var sendSlackMessage = toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
|
|
676
|
-
"Use this for general team communication. For notifications with @mentions, consider using notify-slack instead. Use get-slack-channels first if you need to find the right channel."
|
|
677
|
-
).suggests(["get-slack-channels"]).schema(
|
|
678
|
-
z.object({
|
|
679
|
-
channel: z.string().describe("Channel name (e.g., 'general') or ID (e.g., 'C123456')"),
|
|
680
|
-
message: z.string().describe("Message content to send")
|
|
681
|
-
})
|
|
682
|
-
).implementSafe(async ({ channel, message }) => {
|
|
683
|
-
logger.info("send-slack-message called", { channel, messageLength: message.length });
|
|
684
|
-
try {
|
|
685
|
-
const slack = getDefaultSlackClient();
|
|
686
|
-
const result = await slack.chat.postMessage({
|
|
687
|
-
channel,
|
|
688
|
-
text: message,
|
|
689
|
-
username: "AgentForge Bot",
|
|
690
|
-
icon_emoji: ":robot_face:"
|
|
691
|
-
});
|
|
692
|
-
logger.info("send-slack-message result", {
|
|
693
|
-
channel: result.channel,
|
|
694
|
-
timestamp: result.ts,
|
|
695
|
-
messageLength: message.length,
|
|
696
|
-
success: true
|
|
697
|
-
});
|
|
698
|
-
return {
|
|
699
|
-
channel: result.channel,
|
|
700
|
-
message,
|
|
701
|
-
timestamp: result.ts,
|
|
702
|
-
message_id: result.ts
|
|
703
|
-
};
|
|
704
|
-
} catch (error) {
|
|
705
|
-
logger.error("send-slack-message failed", {
|
|
706
|
-
channel,
|
|
707
|
-
error: error.message,
|
|
708
|
-
data: error.data
|
|
709
|
-
});
|
|
710
|
-
throw error;
|
|
711
|
-
}
|
|
712
|
-
}).build();
|
|
713
|
-
var notifySlack = toolBuilder().name("notify-slack").description("Send a notification to a Slack channel with optional @mentions for urgent alerts").category(ToolCategory.WEB).tags(["slack", "notification", "alert"]).usageNotes(
|
|
714
|
-
"Use this for urgent notifications that require @mentions. For general messages without mentions, use send-slack-message instead."
|
|
715
|
-
).suggests(["get-slack-channels"]).schema(
|
|
716
|
-
z.object({
|
|
717
|
-
channel: z.string().describe("Channel name or ID"),
|
|
718
|
-
message: z.string().describe("Notification message"),
|
|
719
|
-
mentions: z.array(z.string()).optional().describe("List of usernames to mention (without @)")
|
|
720
|
-
})
|
|
721
|
-
).implementSafe(async ({ channel, message, mentions = [] }) => {
|
|
722
|
-
logger.info("notify-slack called", {
|
|
723
|
-
channel,
|
|
724
|
-
messageLength: message.length,
|
|
725
|
-
mentionCount: mentions.length
|
|
726
|
-
});
|
|
727
|
-
const slack = getDefaultSlackClient();
|
|
728
|
-
const mentionText = mentions.length > 0 ? mentions.map((m) => `<@${m}>`).join(" ") + " " : "";
|
|
729
|
-
const fullMessage = `${mentionText}${message}`;
|
|
730
|
-
const result = await slack.chat.postMessage({
|
|
731
|
-
channel,
|
|
732
|
-
text: fullMessage,
|
|
733
|
-
username: "AgentForge Bot",
|
|
734
|
-
icon_emoji: ":robot_face:"
|
|
735
|
-
});
|
|
736
|
-
logger.info("notify-slack result", {
|
|
737
|
-
channel: result.channel,
|
|
738
|
-
timestamp: result.ts,
|
|
739
|
-
mentions: mentions.length
|
|
740
|
-
});
|
|
741
|
-
return {
|
|
742
|
-
channel: result.channel,
|
|
743
|
-
message: fullMessage,
|
|
744
|
-
mentions,
|
|
745
|
-
timestamp: result.ts,
|
|
746
|
-
notification_id: result.ts
|
|
747
|
-
};
|
|
748
|
-
}).build();
|
|
749
|
-
var getSlackChannels = toolBuilder().name("get-slack-channels").description("Get a list of available Slack channels to find the right channel for messaging").category(ToolCategory.WEB).tags(["slack", "channels", "list"]).usageNotes(
|
|
750
|
-
"Use this first to discover available channels before sending messages. Helps ensure you are sending to the correct channel."
|
|
751
|
-
).follows(["send-slack-message", "notify-slack"]).schema(
|
|
752
|
-
z.object({
|
|
753
|
-
include_private: z.boolean().optional().describe("Include private channels (default: false)")
|
|
754
|
-
})
|
|
755
|
-
).implementSafe(async ({ include_private = false }) => {
|
|
756
|
-
logger.info("get-slack-channels called", { include_private });
|
|
757
|
-
const slack = getDefaultSlackClient();
|
|
758
|
-
const publicChannels = await slack.conversations.list({
|
|
759
|
-
types: "public_channel",
|
|
760
|
-
exclude_archived: true
|
|
761
|
-
});
|
|
762
|
-
let allChannels = publicChannels.channels || [];
|
|
763
|
-
if (include_private) {
|
|
764
|
-
const privateChannels = await slack.conversations.list({
|
|
765
|
-
types: "private_channel",
|
|
766
|
-
exclude_archived: true
|
|
767
|
-
});
|
|
768
|
-
allChannels = [...allChannels, ...privateChannels.channels || []];
|
|
769
|
-
}
|
|
770
|
-
logger.info("get-slack-channels result", {
|
|
771
|
-
channelCount: allChannels.length,
|
|
772
|
-
includePrivate: include_private
|
|
773
|
-
});
|
|
774
773
|
return {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
num_members: c.num_members || 0
|
|
781
|
-
}))
|
|
782
|
-
};
|
|
783
|
-
}).build();
|
|
784
|
-
var getSlackMessages = toolBuilder().name("get-slack-messages").description("Retrieve message history from a Slack channel to read recent conversations").category(ToolCategory.WEB).tags(["slack", "messages", "history", "read"]).usageNotes(
|
|
785
|
-
"Use this to read recent messages from a channel. Use get-slack-channels first if you need to find the channel ID. Returns messages in reverse chronological order (newest first)."
|
|
786
|
-
).suggests(["get-slack-channels"]).schema(
|
|
787
|
-
z.object({
|
|
788
|
-
channel: z.string().describe("Channel name (e.g., 'general') or ID (e.g., 'C123456')"),
|
|
789
|
-
limit: z.number().int().min(1).max(100).optional().describe("Number of messages to retrieve (default: 20, max: 100)")
|
|
790
|
-
})
|
|
791
|
-
).implementSafe(async ({ channel, limit = 20 }) => {
|
|
792
|
-
logger.info("get-slack-messages called", { channel, limit });
|
|
793
|
-
try {
|
|
794
|
-
const slack = getDefaultSlackClient();
|
|
795
|
-
let channelId = channel;
|
|
796
|
-
if (!channel.startsWith("C") && !channel.startsWith("D")) {
|
|
797
|
-
const channels = await slack.conversations.list({
|
|
798
|
-
types: "public_channel,private_channel",
|
|
799
|
-
exclude_archived: true
|
|
800
|
-
});
|
|
801
|
-
const found = channels.channels?.find((c) => c.name === channel);
|
|
802
|
-
if (!found) {
|
|
803
|
-
logger.error("get-slack-messages: channel not found", { channel });
|
|
804
|
-
throw new Error(
|
|
805
|
-
`Channel '${channel}' not found. Use get-slack-channels to see available channels.`
|
|
806
|
-
);
|
|
807
|
-
}
|
|
808
|
-
channelId = found.id;
|
|
809
|
-
}
|
|
810
|
-
const result = await slack.conversations.history({
|
|
811
|
-
channel: channelId,
|
|
812
|
-
limit: Math.min(limit, 100)
|
|
813
|
-
// Cap at 100 for performance
|
|
814
|
-
});
|
|
815
|
-
logger.info("get-slack-messages result", {
|
|
816
|
-
channel: channelId,
|
|
817
|
-
messageCount: result.messages?.length || 0,
|
|
818
|
-
limit
|
|
819
|
-
});
|
|
820
|
-
return {
|
|
821
|
-
channel: channelId,
|
|
822
|
-
count: result.messages?.length || 0,
|
|
823
|
-
messages: result.messages?.map((m) => ({
|
|
824
|
-
user: m.user || "unknown",
|
|
825
|
-
text: m.text || "",
|
|
826
|
-
timestamp: m.ts,
|
|
827
|
-
thread_ts: m.thread_ts,
|
|
828
|
-
type: m.type,
|
|
829
|
-
subtype: m.subtype
|
|
830
|
-
})) || []
|
|
831
|
-
};
|
|
832
|
-
} catch (error) {
|
|
833
|
-
logger.error("get-slack-messages failed", {
|
|
834
|
-
channel,
|
|
835
|
-
error: error.message,
|
|
836
|
-
data: error.data
|
|
837
|
-
});
|
|
838
|
-
throw error;
|
|
839
|
-
}
|
|
840
|
-
}).build();
|
|
841
|
-
function createSlackTools(config = {}) {
|
|
842
|
-
const {
|
|
843
|
-
token,
|
|
844
|
-
botName = "AgentForge Bot",
|
|
845
|
-
botIcon = ":robot_face:",
|
|
846
|
-
logLevel: customLogLevel
|
|
847
|
-
} = config;
|
|
848
|
-
let configuredClient = null;
|
|
849
|
-
function getConfiguredSlackClient() {
|
|
850
|
-
if (!configuredClient) {
|
|
851
|
-
const slackToken = token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN;
|
|
852
|
-
if (!slackToken) {
|
|
853
|
-
throw new Error(
|
|
854
|
-
"Slack token not configured. Please provide a token in config or set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
|
-
configuredClient = new WebClient(slackToken);
|
|
774
|
+
client: defaultSlackClient,
|
|
775
|
+
config: {
|
|
776
|
+
token: process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN || "",
|
|
777
|
+
botName: "AgentForge Bot",
|
|
778
|
+
botIcon: ":robot_face:"
|
|
858
779
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
function createSendSlackMessageTool(getSlackClient, logger4) {
|
|
783
|
+
return toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
|
|
863
784
|
"Use this for general team communication. For notifications with @mentions, consider using notify-slack instead. Use get-slack-channels first if you need to find the right channel."
|
|
864
785
|
).suggests(["get-slack-channels"]).schema(
|
|
865
786
|
z.object({
|
|
@@ -867,16 +788,16 @@ function createSlackTools(config = {}) {
|
|
|
867
788
|
message: z.string().describe("Message content to send")
|
|
868
789
|
})
|
|
869
790
|
).implementSafe(async ({ channel, message }) => {
|
|
870
|
-
|
|
791
|
+
logger4.info("send-slack-message called", { channel, messageLength: message.length });
|
|
871
792
|
try {
|
|
872
|
-
const slack =
|
|
793
|
+
const { client: slack, config } = getSlackClient();
|
|
873
794
|
const result = await slack.chat.postMessage({
|
|
874
795
|
channel,
|
|
875
796
|
text: message,
|
|
876
|
-
username: botName,
|
|
877
|
-
icon_emoji: botIcon
|
|
797
|
+
username: config.botName,
|
|
798
|
+
icon_emoji: config.botIcon
|
|
878
799
|
});
|
|
879
|
-
|
|
800
|
+
logger4.info("send-slack-message result", {
|
|
880
801
|
channel: result.channel,
|
|
881
802
|
timestamp: result.ts,
|
|
882
803
|
messageLength: message.length,
|
|
@@ -889,7 +810,7 @@ function createSlackTools(config = {}) {
|
|
|
889
810
|
message_id: result.ts
|
|
890
811
|
};
|
|
891
812
|
} catch (error) {
|
|
892
|
-
|
|
813
|
+
logger4.error("send-slack-message failed", {
|
|
893
814
|
channel,
|
|
894
815
|
error: error.message,
|
|
895
816
|
data: error.data
|
|
@@ -897,7 +818,9 @@ function createSlackTools(config = {}) {
|
|
|
897
818
|
throw error;
|
|
898
819
|
}
|
|
899
820
|
}).build();
|
|
900
|
-
|
|
821
|
+
}
|
|
822
|
+
function createNotifySlackTool(getSlackClient, logger4) {
|
|
823
|
+
return toolBuilder().name("notify-slack").description("Send a notification to a Slack channel with optional @mentions for urgent alerts").category(ToolCategory.WEB).tags(["slack", "notification", "alert"]).usageNotes(
|
|
901
824
|
"Use this for urgent notifications that require @mentions. For general messages without mentions, use send-slack-message instead."
|
|
902
825
|
).suggests(["get-slack-channels"]).schema(
|
|
903
826
|
z.object({
|
|
@@ -906,21 +829,21 @@ function createSlackTools(config = {}) {
|
|
|
906
829
|
mentions: z.array(z.string()).optional().describe("List of usernames to mention (without @)")
|
|
907
830
|
})
|
|
908
831
|
).implementSafe(async ({ channel, message, mentions = [] }) => {
|
|
909
|
-
|
|
832
|
+
logger4.info("notify-slack called", {
|
|
910
833
|
channel,
|
|
911
834
|
messageLength: message.length,
|
|
912
835
|
mentionCount: mentions.length
|
|
913
836
|
});
|
|
914
|
-
const slack =
|
|
837
|
+
const { client: slack, config } = getSlackClient();
|
|
915
838
|
const mentionText = mentions.length > 0 ? mentions.map((m) => `<@${m}>`).join(" ") + " " : "";
|
|
916
839
|
const fullMessage = `${mentionText}${message}`;
|
|
917
840
|
const result = await slack.chat.postMessage({
|
|
918
841
|
channel,
|
|
919
842
|
text: fullMessage,
|
|
920
|
-
username: botName,
|
|
921
|
-
icon_emoji: botIcon
|
|
843
|
+
username: config.botName,
|
|
844
|
+
icon_emoji: config.botIcon
|
|
922
845
|
});
|
|
923
|
-
|
|
846
|
+
logger4.info("notify-slack result", {
|
|
924
847
|
channel: result.channel,
|
|
925
848
|
timestamp: result.ts,
|
|
926
849
|
mentions: mentions.length
|
|
@@ -933,15 +856,17 @@ function createSlackTools(config = {}) {
|
|
|
933
856
|
notification_id: result.ts
|
|
934
857
|
};
|
|
935
858
|
}).build();
|
|
936
|
-
|
|
859
|
+
}
|
|
860
|
+
function createGetSlackChannelsTool(getSlackClient, logger4) {
|
|
861
|
+
return toolBuilder().name("get-slack-channels").description("Get a list of available Slack channels to find the right channel for messaging").category(ToolCategory.WEB).tags(["slack", "channels", "list"]).usageNotes(
|
|
937
862
|
"Use this first to discover available channels before sending messages. Helps ensure you are sending to the correct channel."
|
|
938
863
|
).follows(["send-slack-message", "notify-slack"]).schema(
|
|
939
864
|
z.object({
|
|
940
865
|
include_private: z.boolean().optional().describe("Include private channels (default: false)")
|
|
941
866
|
})
|
|
942
867
|
).implementSafe(async ({ include_private = false }) => {
|
|
943
|
-
|
|
944
|
-
const slack =
|
|
868
|
+
logger4.info("get-slack-channels called", { include_private });
|
|
869
|
+
const { client: slack } = getSlackClient();
|
|
945
870
|
const publicChannels = await slack.conversations.list({
|
|
946
871
|
types: "public_channel",
|
|
947
872
|
exclude_archived: true
|
|
@@ -954,7 +879,7 @@ function createSlackTools(config = {}) {
|
|
|
954
879
|
});
|
|
955
880
|
allChannels = [...allChannels, ...privateChannels.channels || []];
|
|
956
881
|
}
|
|
957
|
-
|
|
882
|
+
logger4.info("get-slack-channels result", {
|
|
958
883
|
channelCount: allChannels.length,
|
|
959
884
|
includePrivate: include_private
|
|
960
885
|
});
|
|
@@ -968,7 +893,9 @@ function createSlackTools(config = {}) {
|
|
|
968
893
|
}))
|
|
969
894
|
};
|
|
970
895
|
}).build();
|
|
971
|
-
|
|
896
|
+
}
|
|
897
|
+
function createGetSlackMessagesTool(getSlackClient, logger4) {
|
|
898
|
+
return toolBuilder().name("get-slack-messages").description("Retrieve message history from a Slack channel to read recent conversations").category(ToolCategory.WEB).tags(["slack", "messages", "history", "read"]).usageNotes(
|
|
972
899
|
"Use this to read recent messages from a channel. Use get-slack-channels first if you need to find the channel ID. Returns messages in reverse chronological order (newest first)."
|
|
973
900
|
).suggests(["get-slack-channels"]).schema(
|
|
974
901
|
z.object({
|
|
@@ -976,9 +903,9 @@ function createSlackTools(config = {}) {
|
|
|
976
903
|
limit: z.number().int().min(1).max(100).optional().describe("Number of messages to retrieve (default: 20, max: 100)")
|
|
977
904
|
})
|
|
978
905
|
).implementSafe(async ({ channel, limit = 20 }) => {
|
|
979
|
-
|
|
906
|
+
logger4.info("get-slack-messages called", { channel, limit });
|
|
980
907
|
try {
|
|
981
|
-
const slack =
|
|
908
|
+
const { client: slack } = getSlackClient();
|
|
982
909
|
let channelId = channel;
|
|
983
910
|
if (!channel.startsWith("C") && !channel.startsWith("D")) {
|
|
984
911
|
const channels = await slack.conversations.list({
|
|
@@ -987,7 +914,7 @@ function createSlackTools(config = {}) {
|
|
|
987
914
|
});
|
|
988
915
|
const found = channels.channels?.find((c) => c.name === channel);
|
|
989
916
|
if (!found) {
|
|
990
|
-
|
|
917
|
+
logger4.error("get-slack-messages: channel not found", { channel });
|
|
991
918
|
throw new Error(
|
|
992
919
|
`Channel '${channel}' not found. Use get-slack-channels to see available channels.`
|
|
993
920
|
);
|
|
@@ -997,8 +924,9 @@ function createSlackTools(config = {}) {
|
|
|
997
924
|
const result = await slack.conversations.history({
|
|
998
925
|
channel: channelId,
|
|
999
926
|
limit: Math.min(limit, 100)
|
|
927
|
+
// Cap at 100 for performance
|
|
1000
928
|
});
|
|
1001
|
-
|
|
929
|
+
logger4.info("get-slack-messages result", {
|
|
1002
930
|
channel: channelId,
|
|
1003
931
|
messageCount: result.messages?.length || 0,
|
|
1004
932
|
limit
|
|
@@ -1016,7 +944,7 @@ function createSlackTools(config = {}) {
|
|
|
1016
944
|
})) || []
|
|
1017
945
|
};
|
|
1018
946
|
} catch (error) {
|
|
1019
|
-
|
|
947
|
+
logger4.error("get-slack-messages failed", {
|
|
1020
948
|
channel,
|
|
1021
949
|
error: error.message,
|
|
1022
950
|
data: error.data
|
|
@@ -1024,6 +952,36 @@ function createSlackTools(config = {}) {
|
|
|
1024
952
|
throw error;
|
|
1025
953
|
}
|
|
1026
954
|
}).build();
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// src/web/slack/index.ts
|
|
958
|
+
var logLevel = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
|
|
959
|
+
var logger = createLogger("[tools:slack]", { level: logLevel });
|
|
960
|
+
var sendSlackMessage = createSendSlackMessageTool(getDefaultSlackClient, logger);
|
|
961
|
+
var notifySlack = createNotifySlackTool(getDefaultSlackClient, logger);
|
|
962
|
+
var getSlackChannels = createGetSlackChannelsTool(getDefaultSlackClient, logger);
|
|
963
|
+
var getSlackMessages = createGetSlackMessagesTool(getDefaultSlackClient, logger);
|
|
964
|
+
var slackTools = [
|
|
965
|
+
// Write tools
|
|
966
|
+
sendSlackMessage,
|
|
967
|
+
notifySlack,
|
|
968
|
+
// Read tools
|
|
969
|
+
getSlackChannels,
|
|
970
|
+
getSlackMessages
|
|
971
|
+
];
|
|
972
|
+
function createSlackTools(config = {}) {
|
|
973
|
+
const {
|
|
974
|
+
token,
|
|
975
|
+
botName = "AgentForge Bot",
|
|
976
|
+
botIcon = ":robot_face:",
|
|
977
|
+
logLevel: customLogLevel
|
|
978
|
+
} = config;
|
|
979
|
+
const getConfiguredSlackClient = createGetConfiguredSlackClient(token, botName, botIcon);
|
|
980
|
+
const toolLogger = customLogLevel ? createLogger("[tools:slack]", { level: customLogLevel }) : logger;
|
|
981
|
+
const sendMessage = createSendSlackMessageTool(getConfiguredSlackClient, toolLogger);
|
|
982
|
+
const notify = createNotifySlackTool(getConfiguredSlackClient, toolLogger);
|
|
983
|
+
const getChannels = createGetSlackChannelsTool(getConfiguredSlackClient, toolLogger);
|
|
984
|
+
const getMessages = createGetSlackMessagesTool(getConfiguredSlackClient, toolLogger);
|
|
1027
985
|
return {
|
|
1028
986
|
sendMessage,
|
|
1029
987
|
notify,
|
|
@@ -1031,1205 +989,2164 @@ function createSlackTools(config = {}) {
|
|
|
1031
989
|
getMessages
|
|
1032
990
|
};
|
|
1033
991
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
992
|
+
|
|
993
|
+
// src/web/confluence/auth.ts
|
|
994
|
+
function createGetConfiguredAuth(apiKey, email, siteUrl) {
|
|
995
|
+
return function getConfiguredAuth() {
|
|
996
|
+
const ATLASSIAN_API_KEY = apiKey || process.env.ATLASSIAN_API_KEY || "";
|
|
997
|
+
const ATLASSIAN_EMAIL = email || process.env.ATLASSIAN_EMAIL || "";
|
|
998
|
+
const ATLASSIAN_SITE_URL = (siteUrl || process.env.ATLASSIAN_SITE_URL || "").replace(/\/$/, "");
|
|
999
|
+
if (!ATLASSIAN_API_KEY || !ATLASSIAN_EMAIL || !ATLASSIAN_SITE_URL) {
|
|
1000
|
+
throw new Error(
|
|
1001
|
+
"Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in config or environment variables."
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
|
|
1043
1005
|
};
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
const json = input.pretty ? JSON.stringify(input.data, null, input.indent) : JSON.stringify(input.data);
|
|
1051
|
-
return {
|
|
1052
|
-
json,
|
|
1053
|
-
length: json.length
|
|
1006
|
+
}
|
|
1007
|
+
function createGetConfiguredAuthHeader(getConfiguredAuth) {
|
|
1008
|
+
return function getConfiguredAuthHeader() {
|
|
1009
|
+
const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfiguredAuth();
|
|
1010
|
+
const auth = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
|
|
1011
|
+
return `Basic ${auth}`;
|
|
1054
1012
|
};
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1013
|
+
}
|
|
1014
|
+
function getConfig() {
|
|
1015
|
+
const ATLASSIAN_API_KEY = process.env.ATLASSIAN_API_KEY || "";
|
|
1016
|
+
const ATLASSIAN_EMAIL = process.env.ATLASSIAN_EMAIL || "";
|
|
1017
|
+
const ATLASSIAN_SITE_URL = (process.env.ATLASSIAN_SITE_URL || "").replace(/\/$/, "");
|
|
1018
|
+
if (!ATLASSIAN_API_KEY || !ATLASSIAN_EMAIL || !ATLASSIAN_SITE_URL) {
|
|
1019
|
+
throw new Error("Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env");
|
|
1020
|
+
}
|
|
1021
|
+
return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
|
|
1022
|
+
}
|
|
1023
|
+
function getAuthHeader() {
|
|
1024
|
+
const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfig();
|
|
1025
|
+
const auth = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
|
|
1026
|
+
return `Basic ${auth}`;
|
|
1027
|
+
}
|
|
1028
|
+
function createSearchConfluenceTool(getAuth, getAuthHeader2, logger4) {
|
|
1029
|
+
return toolBuilder().name("search-confluence").description("Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts.").category(ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes("Use this to find relevant documentation, policies, or information in Confluence. You can search by keywords or use CQL for advanced queries (e.g., 'space=AI AND type=page'). Use get-confluence-page to retrieve full content of specific pages.").suggests(["get-confluence-page"]).schema(z.object({
|
|
1030
|
+
query: z.string().describe("Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"),
|
|
1031
|
+
limit: z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
|
|
1032
|
+
})).implement(async ({ query, limit = 10 }) => {
|
|
1033
|
+
logger4.info("search-confluence called", { query, limit });
|
|
1034
|
+
try {
|
|
1035
|
+
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1036
|
+
const response = await axios12.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
|
|
1037
|
+
headers: {
|
|
1038
|
+
Authorization: getAuthHeader2(),
|
|
1039
|
+
Accept: "application/json"
|
|
1040
|
+
},
|
|
1041
|
+
params: {
|
|
1042
|
+
cql: query,
|
|
1043
|
+
limit: Math.min(limit, 25),
|
|
1044
|
+
expand: "space,version"
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
const { ATLASSIAN_SITE_URL: siteUrl } = getAuth();
|
|
1048
|
+
const results = response.data.results.map((page) => ({
|
|
1049
|
+
id: page.id,
|
|
1050
|
+
title: page.title,
|
|
1051
|
+
type: page.type,
|
|
1052
|
+
space: page.space?.name || "Unknown",
|
|
1053
|
+
spaceKey: page.space?.key || "",
|
|
1054
|
+
url: `${siteUrl}/wiki${page._links.webui}`,
|
|
1055
|
+
lastModified: page.version?.when || ""
|
|
1056
|
+
}));
|
|
1057
|
+
if (results.length === 0) {
|
|
1058
|
+
logger4.warn("search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry", {
|
|
1059
|
+
query,
|
|
1060
|
+
limit,
|
|
1061
|
+
totalSize: response.data.totalSize
|
|
1062
|
+
});
|
|
1063
|
+
} else {
|
|
1064
|
+
logger4.info("search-confluence result", {
|
|
1065
|
+
query,
|
|
1066
|
+
resultCount: results.length,
|
|
1067
|
+
totalSize: response.data.totalSize,
|
|
1068
|
+
titles: results.map((r) => r.title).slice(0, 3)
|
|
1069
|
+
// Log first 3 titles
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
return JSON.stringify({
|
|
1073
|
+
success: true,
|
|
1074
|
+
count: results.length,
|
|
1075
|
+
total: response.data.totalSize,
|
|
1076
|
+
results
|
|
1077
|
+
});
|
|
1078
|
+
} catch (error) {
|
|
1079
|
+
logger4.error("search-confluence error", {
|
|
1080
|
+
query,
|
|
1081
|
+
error: error.response?.data?.message || error.message,
|
|
1082
|
+
status: error.response?.status
|
|
1083
|
+
});
|
|
1084
|
+
return JSON.stringify({
|
|
1085
|
+
success: false,
|
|
1086
|
+
error: error.response?.data?.message || error.message
|
|
1087
|
+
});
|
|
1069
1088
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1089
|
+
}).build();
|
|
1090
|
+
}
|
|
1091
|
+
function createGetConfluencePageTool(getAuth, getAuthHeader2, logger4) {
|
|
1092
|
+
return toolBuilder().name("get-confluence-page").description("Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata.").category(ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes("Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results.").requires(["search-confluence"]).schema(z.object({
|
|
1093
|
+
page_id: z.string().describe("The Confluence page ID (from search results)")
|
|
1094
|
+
})).implement(async ({ page_id }) => {
|
|
1095
|
+
logger4.info("get-confluence-page called", { page_id });
|
|
1096
|
+
try {
|
|
1097
|
+
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1098
|
+
const response = await axios12.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
|
|
1099
|
+
headers: {
|
|
1100
|
+
Authorization: getAuthHeader2(),
|
|
1101
|
+
Accept: "application/json"
|
|
1102
|
+
},
|
|
1103
|
+
params: {
|
|
1104
|
+
expand: "body.storage,space,version,history"
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
const page = response.data;
|
|
1108
|
+
logger4.info("get-confluence-page result", {
|
|
1109
|
+
page_id,
|
|
1110
|
+
title: page.title,
|
|
1111
|
+
space: page.space?.name,
|
|
1112
|
+
contentLength: page.body?.storage?.value?.length || 0
|
|
1113
|
+
});
|
|
1114
|
+
return JSON.stringify({
|
|
1115
|
+
success: true,
|
|
1116
|
+
page: {
|
|
1117
|
+
id: page.id,
|
|
1118
|
+
title: page.title,
|
|
1119
|
+
type: page.type,
|
|
1120
|
+
space: page.space?.name || "Unknown",
|
|
1121
|
+
spaceKey: page.space?.key || "",
|
|
1122
|
+
content: page.body?.storage?.value || "",
|
|
1123
|
+
url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
|
|
1124
|
+
created: page.history?.createdDate || "",
|
|
1125
|
+
lastModified: page.version?.when || "",
|
|
1126
|
+
version: page.version?.number || 1
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
logger4.error("get-confluence-page error", {
|
|
1131
|
+
page_id,
|
|
1132
|
+
error: error.response?.data?.message || error.message,
|
|
1133
|
+
status: error.response?.status
|
|
1134
|
+
});
|
|
1135
|
+
return JSON.stringify({
|
|
1136
|
+
success: false,
|
|
1137
|
+
error: error.response?.data?.message || error.message
|
|
1138
|
+
});
|
|
1072
1139
|
}
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}).
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1140
|
+
}).build();
|
|
1141
|
+
}
|
|
1142
|
+
function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger4) {
|
|
1143
|
+
return toolBuilder().name("list-confluence-spaces").description("List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information.").category(ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes("Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance').").follows(["search-confluence"]).schema(z.object({
|
|
1144
|
+
limit: z.number().optional().describe("Maximum number of spaces to return (default: 25)")
|
|
1145
|
+
})).implement(async ({ limit = 25 }) => {
|
|
1146
|
+
logger4.info("list-confluence-spaces called", { limit });
|
|
1147
|
+
try {
|
|
1148
|
+
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1149
|
+
const response = await axios12.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
|
|
1150
|
+
headers: {
|
|
1151
|
+
Authorization: getAuthHeader2(),
|
|
1152
|
+
Accept: "application/json"
|
|
1153
|
+
},
|
|
1154
|
+
params: {
|
|
1155
|
+
limit
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
1158
|
+
const spaces = response.data.results.map((space) => ({
|
|
1159
|
+
key: space.key,
|
|
1160
|
+
name: space.name,
|
|
1161
|
+
type: space.type,
|
|
1162
|
+
description: space.description?.plain?.value || "",
|
|
1163
|
+
url: `${ATLASSIAN_SITE_URL}/wiki${space._links.webui}`
|
|
1164
|
+
}));
|
|
1165
|
+
logger4.info("list-confluence-spaces result", {
|
|
1166
|
+
spaceCount: spaces.length,
|
|
1167
|
+
spaceKeys: spaces.map((s) => s.key).slice(0, 5)
|
|
1168
|
+
// Log first 5 space keys
|
|
1169
|
+
});
|
|
1170
|
+
return JSON.stringify({
|
|
1171
|
+
success: true,
|
|
1172
|
+
count: spaces.length,
|
|
1173
|
+
spaces
|
|
1174
|
+
});
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
logger4.error("list-confluence-spaces error", {
|
|
1177
|
+
error: error.response?.data?.message || error.message,
|
|
1178
|
+
status: error.response?.status
|
|
1179
|
+
});
|
|
1180
|
+
return JSON.stringify({
|
|
1181
|
+
success: false,
|
|
1182
|
+
error: error.response?.data?.message || error.message
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
}).build();
|
|
1186
|
+
}
|
|
1187
|
+
function createGetSpacePagesTool(getAuth, getAuthHeader2, logger4) {
|
|
1188
|
+
return toolBuilder().name("get-space-pages").description("Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area.").category(ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes("Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first.").requires(["list-confluence-spaces"]).schema(z.object({
|
|
1189
|
+
space_key: z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
|
|
1190
|
+
limit: z.number().optional().describe("Maximum number of pages to return (default: 25)")
|
|
1191
|
+
})).implement(async ({ space_key, limit = 25 }) => {
|
|
1192
|
+
logger4.info("get-space-pages called", { space_key, limit });
|
|
1193
|
+
try {
|
|
1194
|
+
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1195
|
+
const response = await axios12.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
|
|
1196
|
+
headers: {
|
|
1197
|
+
Authorization: getAuthHeader2(),
|
|
1198
|
+
Accept: "application/json"
|
|
1199
|
+
},
|
|
1200
|
+
params: {
|
|
1201
|
+
spaceKey: space_key,
|
|
1202
|
+
type: "page",
|
|
1203
|
+
limit,
|
|
1204
|
+
expand: "version"
|
|
1100
1205
|
}
|
|
1206
|
+
});
|
|
1207
|
+
const pages = response.data.results.map((page) => ({
|
|
1208
|
+
id: page.id,
|
|
1209
|
+
title: page.title,
|
|
1210
|
+
url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
|
|
1211
|
+
lastModified: page.version?.when || ""
|
|
1212
|
+
}));
|
|
1213
|
+
if (pages.length === 0) {
|
|
1214
|
+
logger4.warn("get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry", {
|
|
1215
|
+
space_key,
|
|
1216
|
+
limit
|
|
1217
|
+
});
|
|
1218
|
+
} else {
|
|
1219
|
+
logger4.info("get-space-pages result", {
|
|
1220
|
+
space_key,
|
|
1221
|
+
pageCount: pages.length,
|
|
1222
|
+
titles: pages.map((p) => p.title).slice(0, 3)
|
|
1223
|
+
// Log first 3 titles
|
|
1224
|
+
});
|
|
1101
1225
|
}
|
|
1102
|
-
return
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1226
|
+
return JSON.stringify({
|
|
1227
|
+
success: true,
|
|
1228
|
+
space: space_key,
|
|
1229
|
+
count: pages.length,
|
|
1230
|
+
pages
|
|
1231
|
+
});
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
logger4.error("get-space-pages error", {
|
|
1234
|
+
space_key,
|
|
1235
|
+
error: error.response?.data?.message || error.message,
|
|
1236
|
+
status: error.response?.status
|
|
1237
|
+
});
|
|
1238
|
+
return JSON.stringify({
|
|
1239
|
+
success: false,
|
|
1240
|
+
error: error.response?.data?.message || error.message
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
}).build();
|
|
1244
|
+
}
|
|
1245
|
+
function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger4) {
|
|
1246
|
+
return toolBuilder().name("create-confluence-page").description("Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format).").category(ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes("Use this to create new documentation pages. Content should be in Confluence storage format (HTML). Get the space key from list-confluence-spaces first. Be mindful of creating duplicate pages.").requires(["list-confluence-spaces"]).schema(z.object({
|
|
1247
|
+
space_key: z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
|
|
1248
|
+
title: z.string().describe("The title of the new page"),
|
|
1249
|
+
content: z.string().describe("The page content in HTML format (Confluence storage format)"),
|
|
1250
|
+
parent_page_id: z.string().optional().describe("Optional parent page ID to create this as a child page")
|
|
1251
|
+
})).implement(async ({ space_key, title, content, parent_page_id }) => {
|
|
1252
|
+
logger4.info("create-confluence-page called", { space_key, title, hasParent: !!parent_page_id });
|
|
1253
|
+
try {
|
|
1254
|
+
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1255
|
+
const pageData = {
|
|
1256
|
+
type: "page",
|
|
1257
|
+
title,
|
|
1258
|
+
space: { key: space_key },
|
|
1259
|
+
body: {
|
|
1260
|
+
storage: {
|
|
1261
|
+
value: content,
|
|
1262
|
+
representation: "storage"
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
if (parent_page_id) {
|
|
1267
|
+
pageData.ancestors = [{ id: parent_page_id }];
|
|
1268
|
+
}
|
|
1269
|
+
const response = await axios12.post(
|
|
1270
|
+
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`,
|
|
1271
|
+
pageData,
|
|
1272
|
+
{
|
|
1273
|
+
headers: {
|
|
1274
|
+
Authorization: getAuthHeader2(),
|
|
1275
|
+
"Content-Type": "application/json"
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
);
|
|
1279
|
+
logger4.info("create-confluence-page result", {
|
|
1280
|
+
page_id: response.data.id,
|
|
1281
|
+
title: response.data.title,
|
|
1282
|
+
space: space_key
|
|
1283
|
+
});
|
|
1284
|
+
return JSON.stringify({
|
|
1285
|
+
success: true,
|
|
1286
|
+
page: {
|
|
1287
|
+
id: response.data.id,
|
|
1288
|
+
title: response.data.title,
|
|
1289
|
+
space: space_key,
|
|
1290
|
+
url: `${ATLASSIAN_SITE_URL}/wiki${response.data._links.webui}`,
|
|
1291
|
+
version: response.data.version?.number || 1
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
logger4.error("create-confluence-page error", {
|
|
1296
|
+
space_key,
|
|
1297
|
+
title,
|
|
1298
|
+
error: error.response?.data?.message || error.message,
|
|
1299
|
+
status: error.response?.status
|
|
1300
|
+
});
|
|
1301
|
+
return JSON.stringify({
|
|
1302
|
+
success: false,
|
|
1303
|
+
error: error.response?.data?.message || error.message
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
}).build();
|
|
1307
|
+
}
|
|
1308
|
+
function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger4) {
|
|
1309
|
+
return toolBuilder().name("update-confluence-page").description("Update an existing Confluence page's content. Requires page ID, new title, and new content.").category(ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes("Use this to update existing documentation. You must provide the page ID (from search results). The tool will automatically handle version incrementing. Always get the current page content first to avoid overwriting important information.").requires(["get-confluence-page"]).schema(z.object({
|
|
1310
|
+
page_id: z.string().describe("The ID of the page to update"),
|
|
1311
|
+
title: z.string().describe("The new title for the page"),
|
|
1312
|
+
content: z.string().describe("The new content in HTML format (Confluence storage format)")
|
|
1313
|
+
})).implement(async ({ page_id, title, content }) => {
|
|
1314
|
+
logger4.info("update-confluence-page called", { page_id, title });
|
|
1315
|
+
try {
|
|
1316
|
+
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1317
|
+
const getResponse = await axios12.get(
|
|
1318
|
+
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1319
|
+
{
|
|
1320
|
+
headers: {
|
|
1321
|
+
Authorization: getAuthHeader2()
|
|
1322
|
+
},
|
|
1323
|
+
params: { expand: "version" }
|
|
1324
|
+
}
|
|
1325
|
+
);
|
|
1326
|
+
const currentVersion = getResponse.data.version.number;
|
|
1327
|
+
const updateResponse = await axios12.put(
|
|
1328
|
+
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1329
|
+
{
|
|
1330
|
+
type: "page",
|
|
1331
|
+
title,
|
|
1332
|
+
version: { number: currentVersion + 1 },
|
|
1333
|
+
body: {
|
|
1334
|
+
storage: {
|
|
1335
|
+
value: content,
|
|
1336
|
+
representation: "storage"
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
headers: {
|
|
1342
|
+
Authorization: getAuthHeader2(),
|
|
1343
|
+
"Content-Type": "application/json"
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
);
|
|
1347
|
+
logger4.info("update-confluence-page result", {
|
|
1348
|
+
page_id,
|
|
1349
|
+
title: updateResponse.data.title,
|
|
1350
|
+
previousVersion: currentVersion,
|
|
1351
|
+
newVersion: updateResponse.data.version.number
|
|
1352
|
+
});
|
|
1353
|
+
return JSON.stringify({
|
|
1354
|
+
success: true,
|
|
1355
|
+
page: {
|
|
1356
|
+
id: updateResponse.data.id,
|
|
1357
|
+
title: updateResponse.data.title,
|
|
1358
|
+
url: `${ATLASSIAN_SITE_URL}/wiki${updateResponse.data._links.webui}`,
|
|
1359
|
+
version: updateResponse.data.version.number,
|
|
1360
|
+
previousVersion: currentVersion
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
logger4.error("update-confluence-page error", {
|
|
1365
|
+
page_id,
|
|
1366
|
+
title,
|
|
1367
|
+
error: error.response?.data?.message || error.message,
|
|
1368
|
+
status: error.response?.status
|
|
1369
|
+
});
|
|
1370
|
+
return JSON.stringify({
|
|
1371
|
+
success: false,
|
|
1372
|
+
error: error.response?.data?.message || error.message
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
}).build();
|
|
1376
|
+
}
|
|
1377
|
+
function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger4) {
|
|
1378
|
+
return toolBuilder().name("archive-confluence-page").description("Archive a Confluence page by moving it to trash. The page can be restored by space admins. Note: UI may require a note explaining why the page was archived.").category(ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes("Use this to archive outdated or obsolete documentation. The page is moved to trash, not permanently deleted. Space admins can restore it if needed. Be very careful - only archive pages that are truly obsolete.").conflicts(["create-confluence-page"]).schema(z.object({
|
|
1379
|
+
page_id: z.string().describe("The ID of the page to archive"),
|
|
1380
|
+
reason: z.string().optional().describe("Optional reason for archiving (for audit trail)")
|
|
1381
|
+
})).implement(async ({ page_id, reason }) => {
|
|
1382
|
+
logger4.info("archive-confluence-page called", { page_id, reason });
|
|
1383
|
+
try {
|
|
1384
|
+
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1385
|
+
const getResponse = await axios12.get(
|
|
1386
|
+
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1387
|
+
{
|
|
1388
|
+
headers: {
|
|
1389
|
+
Authorization: getAuthHeader2()
|
|
1390
|
+
},
|
|
1391
|
+
params: { expand: "version,body.storage,space" }
|
|
1392
|
+
}
|
|
1393
|
+
);
|
|
1394
|
+
const currentVersion = getResponse.data.version.number;
|
|
1395
|
+
const pageData = getResponse.data;
|
|
1396
|
+
await axios12.put(
|
|
1397
|
+
`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
|
|
1398
|
+
{
|
|
1399
|
+
version: { number: currentVersion + 1 },
|
|
1400
|
+
title: pageData.title,
|
|
1401
|
+
type: "page",
|
|
1402
|
+
status: "trashed",
|
|
1403
|
+
body: pageData.body,
|
|
1404
|
+
space: { key: pageData.space.key }
|
|
1405
|
+
},
|
|
1406
|
+
{
|
|
1407
|
+
headers: {
|
|
1408
|
+
Authorization: getAuthHeader2(),
|
|
1409
|
+
"Content-Type": "application/json"
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
);
|
|
1413
|
+
logger4.info("archive-confluence-page result", {
|
|
1414
|
+
page_id,
|
|
1415
|
+
title: pageData.title,
|
|
1416
|
+
previousVersion: currentVersion,
|
|
1417
|
+
newVersion: currentVersion + 1
|
|
1418
|
+
});
|
|
1419
|
+
return JSON.stringify({
|
|
1420
|
+
success: true,
|
|
1421
|
+
archived: {
|
|
1422
|
+
id: page_id,
|
|
1423
|
+
title: pageData.title,
|
|
1424
|
+
previousVersion: currentVersion,
|
|
1425
|
+
newVersion: currentVersion + 1,
|
|
1426
|
+
reason: reason || "Archived via API",
|
|
1427
|
+
note: "Page moved to trash. Space admins can restore it from the Confluence UI."
|
|
1428
|
+
}
|
|
1429
|
+
});
|
|
1430
|
+
} catch (error) {
|
|
1431
|
+
logger4.error("archive-confluence-page error", {
|
|
1432
|
+
page_id,
|
|
1433
|
+
error: error.response?.data?.message || error.message,
|
|
1434
|
+
status: error.response?.status
|
|
1435
|
+
});
|
|
1436
|
+
return JSON.stringify({
|
|
1437
|
+
success: false,
|
|
1438
|
+
error: error.response?.data?.message || error.message
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
}).build();
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
// src/web/confluence/index.ts
|
|
1445
|
+
var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
|
|
1446
|
+
var logger2 = createLogger("[tools:confluence]", { level: logLevel2 });
|
|
1447
|
+
var searchConfluence = createSearchConfluenceTool(getConfig, getAuthHeader, logger2);
|
|
1448
|
+
var getConfluencePage = createGetConfluencePageTool(getConfig, getAuthHeader, logger2);
|
|
1449
|
+
var listConfluenceSpaces = createListConfluenceSpacesTool(getConfig, getAuthHeader, logger2);
|
|
1450
|
+
var getSpacePages = createGetSpacePagesTool(getConfig, getAuthHeader, logger2);
|
|
1451
|
+
var createConfluencePage = createCreateConfluencePageTool(getConfig, getAuthHeader, logger2);
|
|
1452
|
+
var updateConfluencePage = createUpdateConfluencePageTool(getConfig, getAuthHeader, logger2);
|
|
1453
|
+
var archiveConfluencePage = createArchiveConfluencePageTool(getConfig, getAuthHeader, logger2);
|
|
1454
|
+
var confluenceTools = [
|
|
1455
|
+
// Read tools
|
|
1456
|
+
searchConfluence,
|
|
1457
|
+
getConfluencePage,
|
|
1458
|
+
listConfluenceSpaces,
|
|
1459
|
+
getSpacePages,
|
|
1460
|
+
// Write tools
|
|
1461
|
+
createConfluencePage,
|
|
1462
|
+
updateConfluencePage,
|
|
1463
|
+
archiveConfluencePage
|
|
1464
|
+
];
|
|
1465
|
+
function createConfluenceTools(config = {}) {
|
|
1466
|
+
const {
|
|
1467
|
+
apiKey,
|
|
1468
|
+
email,
|
|
1469
|
+
siteUrl,
|
|
1470
|
+
logLevel: customLogLevel
|
|
1471
|
+
} = config;
|
|
1472
|
+
const getConfiguredAuth = createGetConfiguredAuth(apiKey, email, siteUrl);
|
|
1473
|
+
const getConfiguredAuthHeader = createGetConfiguredAuthHeader(getConfiguredAuth);
|
|
1474
|
+
const toolLogger = customLogLevel ? createLogger("tools:confluence", { level: customLogLevel }) : logger2;
|
|
1475
|
+
const searchConfluence2 = createSearchConfluenceTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
|
|
1476
|
+
const getConfluencePage2 = createGetConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
|
|
1477
|
+
const listConfluenceSpaces2 = createListConfluenceSpacesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
|
|
1478
|
+
const getSpacePages2 = createGetSpacePagesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
|
|
1479
|
+
const createConfluencePage2 = createCreateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
|
|
1480
|
+
const updateConfluencePage2 = createUpdateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
|
|
1481
|
+
const archiveConfluencePage2 = createArchiveConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
|
|
1482
|
+
return {
|
|
1483
|
+
searchConfluence: searchConfluence2,
|
|
1484
|
+
getConfluencePage: getConfluencePage2,
|
|
1485
|
+
listConfluenceSpaces: listConfluenceSpaces2,
|
|
1486
|
+
getSpacePages: getSpacePages2,
|
|
1487
|
+
createConfluencePage: createConfluencePage2,
|
|
1488
|
+
updateConfluencePage: updateConfluencePage2,
|
|
1489
|
+
archiveConfluencePage: archiveConfluencePage2
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1492
|
+
var csvParserSchema = z.object({
|
|
1110
1493
|
csv: z.string().describe("CSV string to parse"),
|
|
1111
1494
|
delimiter: z.string().default(",").describe("Column delimiter character"),
|
|
1112
1495
|
hasHeaders: z.boolean().default(true).describe("First row contains column headers"),
|
|
1113
1496
|
skipEmptyLines: z.boolean().default(true).describe("Skip empty lines in the CSV"),
|
|
1114
1497
|
trim: z.boolean().default(true).describe("Trim whitespace from values")
|
|
1115
|
-
})
|
|
1116
|
-
|
|
1117
|
-
const records = parse(input.csv, {
|
|
1118
|
-
delimiter: input.delimiter,
|
|
1119
|
-
columns: input.hasHeaders,
|
|
1120
|
-
skip_empty_lines: input.skipEmptyLines,
|
|
1121
|
-
trim: input.trim,
|
|
1122
|
-
relax_column_count: true
|
|
1123
|
-
});
|
|
1124
|
-
return {
|
|
1125
|
-
success: true,
|
|
1126
|
-
data: records,
|
|
1127
|
-
rowCount: records.length,
|
|
1128
|
-
columnCount: records.length > 0 ? Object.keys(records[0]).length : 0
|
|
1129
|
-
};
|
|
1130
|
-
} catch (error) {
|
|
1131
|
-
return {
|
|
1132
|
-
success: false,
|
|
1133
|
-
error: error instanceof Error ? error.message : "Failed to parse CSV"
|
|
1134
|
-
};
|
|
1135
|
-
}
|
|
1136
|
-
}).build();
|
|
1137
|
-
var csvGenerator = toolBuilder().name("csv-generator").description("Convert an array of objects to CSV string. Automatically extracts headers from object keys.").category(ToolCategory.UTILITY).tags(["csv", "generate", "stringify", "data"]).schema(z.object({
|
|
1498
|
+
});
|
|
1499
|
+
var csvGeneratorSchema = z.object({
|
|
1138
1500
|
data: z.array(z.record(z.any().describe("Column value"))).describe("Array of objects to convert to CSV"),
|
|
1139
1501
|
delimiter: z.string().default(",").describe("Column delimiter character"),
|
|
1140
1502
|
includeHeaders: z.boolean().default(true).describe("Include header row with column names"),
|
|
1141
1503
|
columns: z.array(z.string().describe("String value")).optional().describe("Optional list of columns to include (in order)")
|
|
1142
|
-
})
|
|
1143
|
-
|
|
1144
|
-
const csv = stringify(input.data, {
|
|
1145
|
-
delimiter: input.delimiter,
|
|
1146
|
-
header: input.includeHeaders,
|
|
1147
|
-
columns: input.columns
|
|
1148
|
-
});
|
|
1149
|
-
return {
|
|
1150
|
-
success: true,
|
|
1151
|
-
csv,
|
|
1152
|
-
rowCount: input.data.length
|
|
1153
|
-
};
|
|
1154
|
-
} catch (error) {
|
|
1155
|
-
return {
|
|
1156
|
-
success: false,
|
|
1157
|
-
error: error instanceof Error ? error.message : "Failed to generate CSV"
|
|
1158
|
-
};
|
|
1159
|
-
}
|
|
1160
|
-
}).build();
|
|
1161
|
-
var csvToJson = toolBuilder().name("csv-to-json").description("Convert CSV string to JSON array. Each row becomes an object with column headers as keys.").category(ToolCategory.UTILITY).tags(["csv", "json", "convert", "data"]).schema(z.object({
|
|
1504
|
+
});
|
|
1505
|
+
var csvToJsonSchema = z.object({
|
|
1162
1506
|
csv: z.string().describe("CSV string to convert"),
|
|
1163
1507
|
delimiter: z.string().default(",").describe("Column delimiter character"),
|
|
1164
1508
|
pretty: z.boolean().default(false).describe("Format JSON with indentation")
|
|
1165
|
-
})
|
|
1166
|
-
|
|
1167
|
-
const records = parse(input.csv, {
|
|
1168
|
-
delimiter: input.delimiter,
|
|
1169
|
-
columns: true,
|
|
1170
|
-
skip_empty_lines: true,
|
|
1171
|
-
trim: true
|
|
1172
|
-
});
|
|
1173
|
-
const json = input.pretty ? JSON.stringify(records, null, 2) : JSON.stringify(records);
|
|
1174
|
-
return {
|
|
1175
|
-
success: true,
|
|
1176
|
-
json,
|
|
1177
|
-
recordCount: records.length
|
|
1178
|
-
};
|
|
1179
|
-
} catch (error) {
|
|
1180
|
-
return {
|
|
1181
|
-
success: false,
|
|
1182
|
-
error: error instanceof Error ? error.message : "Failed to convert CSV to JSON"
|
|
1183
|
-
};
|
|
1184
|
-
}
|
|
1185
|
-
}).build();
|
|
1186
|
-
var jsonToCsv = toolBuilder().name("json-to-csv").description("Convert JSON array to CSV string. Each object becomes a row with keys as column headers.").category(ToolCategory.UTILITY).tags(["json", "csv", "convert", "data"]).schema(z.object({
|
|
1509
|
+
});
|
|
1510
|
+
var jsonToCsvSchema = z.object({
|
|
1187
1511
|
json: z.string().describe("JSON array string to convert"),
|
|
1188
1512
|
delimiter: z.string().default(",").describe("Column delimiter character")
|
|
1189
|
-
})
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1513
|
+
});
|
|
1514
|
+
function createCsvParserTool(defaultDelimiter = ",", defaultHasHeaders = true, defaultSkipEmptyLines = true, defaultTrim = true) {
|
|
1515
|
+
return toolBuilder().name("csv-parser").description("Parse CSV string into an array of objects. Supports custom delimiters, headers, and options.").category(ToolCategory.UTILITY).tags(["csv", "parse", "data", "table"]).schema(csvParserSchema).implement(async (input) => {
|
|
1516
|
+
try {
|
|
1517
|
+
const records = parse(input.csv, {
|
|
1518
|
+
delimiter: input.delimiter ?? defaultDelimiter,
|
|
1519
|
+
columns: input.hasHeaders ?? defaultHasHeaders,
|
|
1520
|
+
skip_empty_lines: input.skipEmptyLines ?? defaultSkipEmptyLines,
|
|
1521
|
+
trim: input.trim ?? defaultTrim,
|
|
1522
|
+
relax_column_count: true
|
|
1523
|
+
});
|
|
1524
|
+
return {
|
|
1525
|
+
success: true,
|
|
1526
|
+
data: records,
|
|
1527
|
+
rowCount: records.length,
|
|
1528
|
+
columnCount: records.length > 0 ? Object.keys(records[0]).length : 0
|
|
1529
|
+
};
|
|
1530
|
+
} catch (error) {
|
|
1193
1531
|
return {
|
|
1194
1532
|
success: false,
|
|
1195
|
-
error:
|
|
1533
|
+
error: error instanceof Error ? error.message : "Failed to parse CSV"
|
|
1196
1534
|
};
|
|
1197
1535
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1536
|
+
}).build();
|
|
1537
|
+
}
|
|
1538
|
+
function createCsvGeneratorTool(defaultDelimiter = ",") {
|
|
1539
|
+
return toolBuilder().name("csv-generator").description("Convert an array of objects to CSV string. Automatically extracts headers from object keys.").category(ToolCategory.UTILITY).tags(["csv", "generate", "stringify", "data"]).schema(csvGeneratorSchema).implement(async (input) => {
|
|
1540
|
+
try {
|
|
1541
|
+
const csv = stringify(input.data, {
|
|
1542
|
+
delimiter: input.delimiter ?? defaultDelimiter,
|
|
1543
|
+
header: input.includeHeaders,
|
|
1544
|
+
columns: input.columns
|
|
1545
|
+
});
|
|
1546
|
+
return {
|
|
1547
|
+
success: true,
|
|
1548
|
+
csv,
|
|
1549
|
+
rowCount: input.data.length
|
|
1550
|
+
};
|
|
1551
|
+
} catch (error) {
|
|
1552
|
+
return {
|
|
1553
|
+
success: false,
|
|
1554
|
+
error: error instanceof Error ? error.message : "Failed to generate CSV"
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
}).build();
|
|
1558
|
+
}
|
|
1559
|
+
function createCsvToJsonTool(defaultDelimiter = ",") {
|
|
1560
|
+
return toolBuilder().name("csv-to-json").description("Convert CSV string to JSON array. Each row becomes an object with column headers as keys.").category(ToolCategory.UTILITY).tags(["csv", "json", "convert", "data"]).schema(csvToJsonSchema).implement(async (input) => {
|
|
1561
|
+
try {
|
|
1562
|
+
const records = parse(input.csv, {
|
|
1563
|
+
delimiter: input.delimiter ?? defaultDelimiter,
|
|
1564
|
+
columns: true,
|
|
1565
|
+
skip_empty_lines: true,
|
|
1566
|
+
trim: true
|
|
1567
|
+
});
|
|
1568
|
+
const json = input.pretty ? JSON.stringify(records, null, 2) : JSON.stringify(records);
|
|
1569
|
+
return {
|
|
1570
|
+
success: true,
|
|
1571
|
+
json,
|
|
1572
|
+
recordCount: records.length
|
|
1573
|
+
};
|
|
1574
|
+
} catch (error) {
|
|
1575
|
+
return {
|
|
1576
|
+
success: false,
|
|
1577
|
+
error: error instanceof Error ? error.message : "Failed to convert CSV to JSON"
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
}).build();
|
|
1581
|
+
}
|
|
1582
|
+
function createJsonToCsvTool(defaultDelimiter = ",") {
|
|
1583
|
+
return toolBuilder().name("json-to-csv").description("Convert JSON array to CSV string. Each object becomes a row with keys as column headers.").category(ToolCategory.UTILITY).tags(["json", "csv", "convert", "data"]).schema(jsonToCsvSchema).implement(async (input) => {
|
|
1584
|
+
try {
|
|
1585
|
+
const data = JSON.parse(input.json);
|
|
1586
|
+
if (!Array.isArray(data)) {
|
|
1587
|
+
return {
|
|
1588
|
+
success: false,
|
|
1589
|
+
error: "Input must be a JSON array"
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
const csv = stringify(data, {
|
|
1593
|
+
delimiter: input.delimiter ?? defaultDelimiter,
|
|
1594
|
+
header: true
|
|
1595
|
+
});
|
|
1596
|
+
return {
|
|
1597
|
+
success: true,
|
|
1598
|
+
csv,
|
|
1599
|
+
rowCount: data.length
|
|
1600
|
+
};
|
|
1601
|
+
} catch (error) {
|
|
1602
|
+
return {
|
|
1603
|
+
success: false,
|
|
1604
|
+
error: error instanceof Error ? error.message : "Failed to convert JSON to CSV"
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
}).build();
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// src/data/csv/index.ts
|
|
1611
|
+
var csvParser = createCsvParserTool();
|
|
1612
|
+
var csvGenerator = createCsvGeneratorTool();
|
|
1613
|
+
var csvToJson = createCsvToJsonTool();
|
|
1614
|
+
var jsonToCsv = createJsonToCsvTool();
|
|
1615
|
+
var csvTools = [csvParser, csvGenerator, csvToJson, jsonToCsv];
|
|
1616
|
+
function createCsvTools(config = {}) {
|
|
1617
|
+
const {
|
|
1618
|
+
defaultDelimiter = ",",
|
|
1619
|
+
defaultHasHeaders = true,
|
|
1620
|
+
defaultSkipEmptyLines = true,
|
|
1621
|
+
defaultTrim = true
|
|
1622
|
+
} = config;
|
|
1623
|
+
return [
|
|
1624
|
+
createCsvParserTool(defaultDelimiter, defaultHasHeaders, defaultSkipEmptyLines, defaultTrim),
|
|
1625
|
+
createCsvGeneratorTool(defaultDelimiter),
|
|
1626
|
+
createCsvToJsonTool(defaultDelimiter),
|
|
1627
|
+
createJsonToCsvTool(defaultDelimiter)
|
|
1628
|
+
];
|
|
1629
|
+
}
|
|
1630
|
+
var jsonParserSchema = z.object({
|
|
1631
|
+
json: z.string().describe("JSON string to parse"),
|
|
1632
|
+
strict: z.boolean().default(true).describe("Use strict JSON parsing (no trailing commas, etc.)")
|
|
1633
|
+
});
|
|
1634
|
+
var jsonStringifySchema = z.object({
|
|
1635
|
+
data: z.any().describe("Data to convert to JSON string"),
|
|
1636
|
+
pretty: z.boolean().default(false).describe("Format with indentation for readability"),
|
|
1637
|
+
indent: z.number().default(2).describe("Number of spaces for indentation (when pretty is true)")
|
|
1638
|
+
});
|
|
1639
|
+
var jsonQuerySchema = z.object({
|
|
1640
|
+
data: z.any().describe("JSON data to query"),
|
|
1641
|
+
path: z.string().describe('Dot notation path to query (e.g., "user.name" or "items[0].id")')
|
|
1642
|
+
});
|
|
1643
|
+
var jsonValidatorSchema = z.object({
|
|
1644
|
+
json: z.string().describe("JSON string to validate")
|
|
1645
|
+
});
|
|
1646
|
+
var jsonMergeSchema = z.object({
|
|
1647
|
+
objects: z.array(z.any().describe("Object to merge")).describe("Array of objects to merge"),
|
|
1648
|
+
deep: z.boolean().default(false).describe("Perform deep merge (nested objects)")
|
|
1649
|
+
});
|
|
1650
|
+
function createJsonParserTool() {
|
|
1651
|
+
return toolBuilder().name("json-parser").description("Parse JSON string into an object. Validates JSON syntax and returns parsed data or error details.").category(ToolCategory.UTILITY).tags(["json", "parse", "data"]).schema(jsonParserSchema).implementSafe(async (input) => {
|
|
1652
|
+
const parsed = JSON.parse(input.json);
|
|
1202
1653
|
return {
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
rowCount: data.length
|
|
1654
|
+
data: parsed,
|
|
1655
|
+
type: Array.isArray(parsed) ? "array" : typeof parsed
|
|
1206
1656
|
};
|
|
1207
|
-
}
|
|
1657
|
+
}).build();
|
|
1658
|
+
}
|
|
1659
|
+
function createJsonStringifyTool(defaultIndent = 2, defaultPretty = false) {
|
|
1660
|
+
return toolBuilder().name("json-stringify").description("Convert an object to a JSON string with optional formatting (pretty print).").category(ToolCategory.UTILITY).tags(["json", "stringify", "format", "data"]).schema(jsonStringifySchema).implementSafe(async (input) => {
|
|
1661
|
+
const pretty = input.pretty ?? defaultPretty;
|
|
1662
|
+
const indent = input.indent ?? defaultIndent;
|
|
1663
|
+
const json = pretty ? JSON.stringify(input.data, null, indent) : JSON.stringify(input.data);
|
|
1208
1664
|
return {
|
|
1209
|
-
|
|
1210
|
-
|
|
1665
|
+
json,
|
|
1666
|
+
length: json.length
|
|
1211
1667
|
};
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1668
|
+
}).build();
|
|
1669
|
+
}
|
|
1670
|
+
function createJsonQueryTool() {
|
|
1671
|
+
return toolBuilder().name("json-query").description('Query JSON data using dot notation path (e.g., "user.address.city"). Supports array indexing.').category(ToolCategory.UTILITY).tags(["json", "query", "path", "data"]).schema(jsonQuerySchema).implementSafe(async (input) => {
|
|
1672
|
+
const parts = input.path.split(".");
|
|
1673
|
+
let current = input.data;
|
|
1674
|
+
for (const part of parts) {
|
|
1675
|
+
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
|
|
1676
|
+
if (arrayMatch) {
|
|
1677
|
+
const [, key, index] = arrayMatch;
|
|
1678
|
+
current = current[key][parseInt(index, 10)];
|
|
1679
|
+
} else {
|
|
1680
|
+
current = current[part];
|
|
1681
|
+
}
|
|
1682
|
+
if (current === void 0) {
|
|
1683
|
+
throw new Error(`Path not found: ${input.path}`);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1228
1686
|
return {
|
|
1229
|
-
|
|
1230
|
-
|
|
1687
|
+
value: current,
|
|
1688
|
+
type: Array.isArray(current) ? "array" : typeof current
|
|
1231
1689
|
};
|
|
1232
|
-
}
|
|
1690
|
+
}).build();
|
|
1691
|
+
}
|
|
1692
|
+
function createJsonValidatorTool() {
|
|
1693
|
+
return toolBuilder().name("json-validator").description("Validate JSON string syntax without parsing. Returns whether the JSON is valid and any error details.").category(ToolCategory.UTILITY).tags(["json", "validate", "check", "data"]).schema(jsonValidatorSchema).implementSafe(async (input) => {
|
|
1694
|
+
JSON.parse(input.json);
|
|
1233
1695
|
return {
|
|
1234
|
-
|
|
1235
|
-
|
|
1696
|
+
valid: true,
|
|
1697
|
+
message: "Valid JSON"
|
|
1236
1698
|
};
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1699
|
+
}).build();
|
|
1700
|
+
}
|
|
1701
|
+
function createJsonMergeTool() {
|
|
1702
|
+
return toolBuilder().name("json-merge").description("Merge two or more JSON objects. Later objects override earlier ones for conflicting keys.").category(ToolCategory.UTILITY).tags(["json", "merge", "combine", "data"]).schema(jsonMergeSchema).implement(async (input) => {
|
|
1703
|
+
if (input.deep) {
|
|
1704
|
+
const deepMerge = (target, source) => {
|
|
1705
|
+
const output = { ...target };
|
|
1706
|
+
for (const key in source) {
|
|
1707
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
1708
|
+
output[key] = deepMerge(output[key] || {}, source[key]);
|
|
1709
|
+
} else {
|
|
1710
|
+
output[key] = source[key];
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
return output;
|
|
1714
|
+
};
|
|
1715
|
+
return input.objects.reduce((acc, obj) => deepMerge(acc, obj), {});
|
|
1716
|
+
} else {
|
|
1717
|
+
return Object.assign({}, ...input.objects);
|
|
1718
|
+
}
|
|
1719
|
+
}).build();
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// src/data/json/index.ts
|
|
1723
|
+
var jsonParser = createJsonParserTool();
|
|
1724
|
+
var jsonStringify = createJsonStringifyTool();
|
|
1725
|
+
var jsonQuery = createJsonQueryTool();
|
|
1726
|
+
var jsonValidator = createJsonValidatorTool();
|
|
1727
|
+
var jsonMerge = createJsonMergeTool();
|
|
1728
|
+
var jsonTools = [jsonParser, jsonStringify, jsonQuery, jsonValidator, jsonMerge];
|
|
1729
|
+
function createJsonTools(config = {}) {
|
|
1730
|
+
const {
|
|
1731
|
+
defaultIndent = 2,
|
|
1732
|
+
defaultPretty = false
|
|
1733
|
+
} = config;
|
|
1734
|
+
return [
|
|
1735
|
+
createJsonParserTool(),
|
|
1736
|
+
createJsonStringifyTool(defaultIndent, defaultPretty),
|
|
1737
|
+
createJsonQueryTool(),
|
|
1738
|
+
createJsonValidatorTool(),
|
|
1739
|
+
createJsonMergeTool()
|
|
1740
|
+
];
|
|
1741
|
+
}
|
|
1742
|
+
var xmlParserSchema = z.object({
|
|
1743
|
+
xml: z.string().describe("XML string to parse"),
|
|
1744
|
+
ignoreAttributes: z.boolean().default(false).describe("Ignore XML attributes"),
|
|
1745
|
+
parseAttributeValue: z.boolean().default(true).describe("Parse attribute values (numbers, booleans)"),
|
|
1746
|
+
trimValues: z.boolean().default(true).describe("Trim whitespace from text values")
|
|
1747
|
+
});
|
|
1748
|
+
var xmlGeneratorSchema = z.object({
|
|
1240
1749
|
data: z.any().describe("Object to convert to XML"),
|
|
1241
1750
|
rootName: z.string().default("root").describe("Name of the root XML element"),
|
|
1242
1751
|
format: z.boolean().default(false).describe("Format XML with indentation"),
|
|
1243
1752
|
indentSize: z.number().default(2).describe("Number of spaces for indentation (when format is true)")
|
|
1244
|
-
})
|
|
1245
|
-
|
|
1246
|
-
const indentSize = input.indentSize ?? 2;
|
|
1247
|
-
const rootName = input.rootName ?? "root";
|
|
1248
|
-
const builder = new XMLBuilder({
|
|
1249
|
-
format: input.format ?? false,
|
|
1250
|
-
indentBy: " ".repeat(indentSize),
|
|
1251
|
-
ignoreAttributes: false
|
|
1252
|
-
});
|
|
1253
|
-
const dataToConvert = input.data[rootName] ? input.data : { [rootName]: input.data };
|
|
1254
|
-
const xml = builder.build(dataToConvert);
|
|
1255
|
-
return {
|
|
1256
|
-
success: true,
|
|
1257
|
-
xml
|
|
1258
|
-
};
|
|
1259
|
-
} catch (error) {
|
|
1260
|
-
return {
|
|
1261
|
-
success: false,
|
|
1262
|
-
error: error instanceof Error ? error.message : "Failed to generate XML"
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
}).build();
|
|
1266
|
-
var xmlToJson = toolBuilder().name("xml-to-json").description("Convert XML string to JSON. Preserves structure and can include or exclude attributes.").category(ToolCategory.UTILITY).tags(["xml", "json", "convert", "data"]).schema(z.object({
|
|
1753
|
+
});
|
|
1754
|
+
var xmlToJsonSchema = z.object({
|
|
1267
1755
|
xml: z.string().describe("XML string to convert"),
|
|
1268
1756
|
ignoreAttributes: z.boolean().default(false).describe("Ignore XML attributes in conversion"),
|
|
1269
1757
|
pretty: z.boolean().default(false).describe("Format JSON with indentation")
|
|
1270
|
-
})
|
|
1271
|
-
|
|
1272
|
-
const parser = new XMLParser({
|
|
1273
|
-
ignoreAttributes: input.ignoreAttributes,
|
|
1274
|
-
parseAttributeValue: true,
|
|
1275
|
-
trimValues: true
|
|
1276
|
-
});
|
|
1277
|
-
const result = parser.parse(input.xml);
|
|
1278
|
-
const json = input.pretty ? JSON.stringify(result, null, 2) : JSON.stringify(result);
|
|
1279
|
-
return {
|
|
1280
|
-
success: true,
|
|
1281
|
-
json
|
|
1282
|
-
};
|
|
1283
|
-
} catch (error) {
|
|
1284
|
-
return {
|
|
1285
|
-
success: false,
|
|
1286
|
-
error: error instanceof Error ? error.message : "Failed to convert XML to JSON"
|
|
1287
|
-
};
|
|
1288
|
-
}
|
|
1289
|
-
}).build();
|
|
1290
|
-
var jsonToXml = toolBuilder().name("json-to-xml").description("Convert JSON string to XML. Each object key becomes an XML element.").category(ToolCategory.UTILITY).tags(["json", "xml", "convert", "data"]).schema(z.object({
|
|
1758
|
+
});
|
|
1759
|
+
var jsonToXmlSchema = z.object({
|
|
1291
1760
|
json: z.string().describe("JSON string to convert"),
|
|
1292
1761
|
rootName: z.string().default("root").describe("Name of the root XML element"),
|
|
1293
1762
|
format: z.boolean().default(false).describe("Format XML with indentation")
|
|
1294
|
-
})
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
}).build();
|
|
1316
|
-
|
|
1763
|
+
});
|
|
1764
|
+
function createXmlParserTool() {
|
|
1765
|
+
return toolBuilder().name("xml-parser").description("Parse XML string into a JavaScript object. Supports attributes, CDATA, and nested elements.").category(ToolCategory.UTILITY).tags(["xml", "parse", "data"]).schema(xmlParserSchema).implement(async (input) => {
|
|
1766
|
+
try {
|
|
1767
|
+
const parser = new XMLParser({
|
|
1768
|
+
ignoreAttributes: input.ignoreAttributes,
|
|
1769
|
+
parseAttributeValue: input.parseAttributeValue,
|
|
1770
|
+
trimValues: input.trimValues,
|
|
1771
|
+
parseTagValue: true
|
|
1772
|
+
});
|
|
1773
|
+
const result = parser.parse(input.xml);
|
|
1774
|
+
return {
|
|
1775
|
+
success: true,
|
|
1776
|
+
data: result
|
|
1777
|
+
};
|
|
1778
|
+
} catch (error) {
|
|
1779
|
+
return {
|
|
1780
|
+
success: false,
|
|
1781
|
+
error: error instanceof Error ? error.message : "Failed to parse XML"
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
}).build();
|
|
1785
|
+
}
|
|
1786
|
+
function createXmlGeneratorTool(defaultRootName = "root", defaultFormat = false, defaultIndentSize = 2) {
|
|
1787
|
+
return toolBuilder().name("xml-generator").description("Convert a JavaScript object to XML string. Supports attributes, CDATA, and nested elements.").category(ToolCategory.UTILITY).tags(["xml", "generate", "stringify", "data"]).schema(xmlGeneratorSchema).implement(async (input) => {
|
|
1788
|
+
try {
|
|
1789
|
+
const indentSize = input.indentSize ?? defaultIndentSize;
|
|
1790
|
+
const rootName = input.rootName ?? defaultRootName;
|
|
1791
|
+
const format3 = input.format ?? defaultFormat;
|
|
1792
|
+
const builder = new XMLBuilder({
|
|
1793
|
+
format: format3,
|
|
1794
|
+
indentBy: " ".repeat(indentSize),
|
|
1795
|
+
ignoreAttributes: false
|
|
1796
|
+
});
|
|
1797
|
+
const dataToConvert = input.data[rootName] ? input.data : { [rootName]: input.data };
|
|
1798
|
+
const xml = builder.build(dataToConvert);
|
|
1799
|
+
return {
|
|
1800
|
+
success: true,
|
|
1801
|
+
xml
|
|
1802
|
+
};
|
|
1803
|
+
} catch (error) {
|
|
1804
|
+
return {
|
|
1805
|
+
success: false,
|
|
1806
|
+
error: error instanceof Error ? error.message : "Failed to generate XML"
|
|
1807
|
+
};
|
|
1808
|
+
}
|
|
1809
|
+
}).build();
|
|
1810
|
+
}
|
|
1811
|
+
function createXmlToJsonTool() {
|
|
1812
|
+
return toolBuilder().name("xml-to-json").description("Convert XML string to JSON. Preserves structure and can include or exclude attributes.").category(ToolCategory.UTILITY).tags(["xml", "json", "convert", "data"]).schema(xmlToJsonSchema).implement(async (input) => {
|
|
1813
|
+
try {
|
|
1814
|
+
const parser = new XMLParser({
|
|
1815
|
+
ignoreAttributes: input.ignoreAttributes,
|
|
1816
|
+
parseAttributeValue: true,
|
|
1817
|
+
trimValues: true
|
|
1818
|
+
});
|
|
1819
|
+
const result = parser.parse(input.xml);
|
|
1820
|
+
const json = input.pretty ? JSON.stringify(result, null, 2) : JSON.stringify(result);
|
|
1821
|
+
return {
|
|
1822
|
+
success: true,
|
|
1823
|
+
json
|
|
1824
|
+
};
|
|
1825
|
+
} catch (error) {
|
|
1826
|
+
return {
|
|
1827
|
+
success: false,
|
|
1828
|
+
error: error instanceof Error ? error.message : "Failed to convert XML to JSON"
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
}).build();
|
|
1832
|
+
}
|
|
1833
|
+
function createJsonToXmlTool(defaultRootName = "root", defaultFormat = false) {
|
|
1834
|
+
return toolBuilder().name("json-to-xml").description("Convert JSON string to XML. Each object key becomes an XML element.").category(ToolCategory.UTILITY).tags(["json", "xml", "convert", "data"]).schema(jsonToXmlSchema).implement(async (input) => {
|
|
1835
|
+
try {
|
|
1836
|
+
const data = JSON.parse(input.json);
|
|
1837
|
+
const rootName = input.rootName ?? defaultRootName;
|
|
1838
|
+
const format3 = input.format ?? defaultFormat;
|
|
1839
|
+
const builder = new XMLBuilder({
|
|
1840
|
+
format: format3,
|
|
1841
|
+
indentBy: " ",
|
|
1842
|
+
ignoreAttributes: false
|
|
1843
|
+
});
|
|
1844
|
+
const dataToConvert = data[rootName] ? data : { [rootName]: data };
|
|
1845
|
+
const xml = builder.build(dataToConvert);
|
|
1846
|
+
return {
|
|
1847
|
+
success: true,
|
|
1848
|
+
xml
|
|
1849
|
+
};
|
|
1850
|
+
} catch (error) {
|
|
1851
|
+
return {
|
|
1852
|
+
success: false,
|
|
1853
|
+
error: error instanceof Error ? error.message : "Failed to convert JSON to XML"
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
}).build();
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// src/data/xml/index.ts
|
|
1860
|
+
var xmlParser = createXmlParserTool();
|
|
1861
|
+
var xmlGenerator = createXmlGeneratorTool();
|
|
1862
|
+
var xmlToJson = createXmlToJsonTool();
|
|
1863
|
+
var jsonToXml = createJsonToXmlTool();
|
|
1864
|
+
var xmlTools = [xmlParser, xmlGenerator, xmlToJson, jsonToXml];
|
|
1865
|
+
function createXmlTools(config = {}) {
|
|
1866
|
+
const {
|
|
1867
|
+
defaultRootName = "root",
|
|
1868
|
+
defaultFormat = false,
|
|
1869
|
+
defaultIndentSize = 2
|
|
1870
|
+
} = config;
|
|
1871
|
+
return [
|
|
1872
|
+
createXmlParserTool(),
|
|
1873
|
+
createXmlGeneratorTool(defaultRootName, defaultFormat, defaultIndentSize),
|
|
1874
|
+
createXmlToJsonTool(),
|
|
1875
|
+
createJsonToXmlTool(defaultRootName, defaultFormat)
|
|
1876
|
+
];
|
|
1877
|
+
}
|
|
1878
|
+
var arrayFilterSchema = z.object({
|
|
1317
1879
|
array: z.array(z.any().describe("Array element")).describe("Array to filter"),
|
|
1318
1880
|
property: z.string().describe("Property name to filter by (use dot notation for nested properties)"),
|
|
1319
1881
|
operator: z.enum(["equals", "not-equals", "greater-than", "less-than", "contains", "starts-with", "ends-with"]).describe("Comparison operator"),
|
|
1320
1882
|
value: z.any().describe("Value to compare against")
|
|
1321
|
-
})
|
|
1322
|
-
|
|
1323
|
-
return path4.split(".").reduce((current, key) => current?.[key], obj);
|
|
1324
|
-
};
|
|
1325
|
-
const filtered = input.array.filter((item) => {
|
|
1326
|
-
const itemValue = getNestedValue(item, input.property);
|
|
1327
|
-
switch (input.operator) {
|
|
1328
|
-
case "equals":
|
|
1329
|
-
return itemValue === input.value;
|
|
1330
|
-
case "not-equals":
|
|
1331
|
-
return itemValue !== input.value;
|
|
1332
|
-
case "greater-than":
|
|
1333
|
-
return itemValue > input.value;
|
|
1334
|
-
case "less-than":
|
|
1335
|
-
return itemValue < input.value;
|
|
1336
|
-
case "contains":
|
|
1337
|
-
return String(itemValue).includes(String(input.value));
|
|
1338
|
-
case "starts-with":
|
|
1339
|
-
return String(itemValue).startsWith(String(input.value));
|
|
1340
|
-
case "ends-with":
|
|
1341
|
-
return String(itemValue).endsWith(String(input.value));
|
|
1342
|
-
default:
|
|
1343
|
-
return false;
|
|
1344
|
-
}
|
|
1345
|
-
});
|
|
1346
|
-
return {
|
|
1347
|
-
filtered,
|
|
1348
|
-
originalCount: input.array.length,
|
|
1349
|
-
filteredCount: filtered.length
|
|
1350
|
-
};
|
|
1351
|
-
}).build();
|
|
1352
|
-
var arrayMap = toolBuilder().name("array-map").description("Extract specific properties from each object in an array. Creates a new array with only the selected properties.").category(ToolCategory.UTILITY).tags(["array", "map", "data", "transform"]).schema(z.object({
|
|
1883
|
+
});
|
|
1884
|
+
var arrayMapSchema = z.object({
|
|
1353
1885
|
array: z.array(z.any().describe("Array element")).describe("Array to map"),
|
|
1354
1886
|
properties: z.array(z.string().describe("String value")).describe("List of property names to extract from each object")
|
|
1355
|
-
})
|
|
1356
|
-
|
|
1357
|
-
const result = {};
|
|
1358
|
-
for (const prop of input.properties) {
|
|
1359
|
-
const value = prop.split(".").reduce((current, key) => current?.[key], item);
|
|
1360
|
-
result[prop] = value;
|
|
1361
|
-
}
|
|
1362
|
-
return result;
|
|
1363
|
-
});
|
|
1364
|
-
return {
|
|
1365
|
-
mapped,
|
|
1366
|
-
count: mapped.length
|
|
1367
|
-
};
|
|
1368
|
-
}).build();
|
|
1369
|
-
var arraySort = toolBuilder().name("array-sort").description("Sort an array by a property value. Supports ascending and descending order.").category(ToolCategory.UTILITY).tags(["array", "sort", "data", "transform"]).schema(z.object({
|
|
1887
|
+
});
|
|
1888
|
+
var arraySortSchema = z.object({
|
|
1370
1889
|
array: z.array(z.any().describe("Array element")).describe("Array to sort"),
|
|
1371
1890
|
property: z.string().describe("Property name to sort by (use dot notation for nested properties)"),
|
|
1372
1891
|
order: z.enum(["asc", "desc"]).default("asc").describe("Sort order: ascending or descending")
|
|
1373
|
-
})
|
|
1374
|
-
|
|
1375
|
-
return path4.split(".").reduce((current, key) => current?.[key], obj);
|
|
1376
|
-
};
|
|
1377
|
-
const sorted = [...input.array].sort((a, b) => {
|
|
1378
|
-
const aValue = getNestedValue(a, input.property);
|
|
1379
|
-
const bValue = getNestedValue(b, input.property);
|
|
1380
|
-
if (aValue < bValue) return input.order === "asc" ? -1 : 1;
|
|
1381
|
-
if (aValue > bValue) return input.order === "asc" ? 1 : -1;
|
|
1382
|
-
return 0;
|
|
1383
|
-
});
|
|
1384
|
-
return {
|
|
1385
|
-
sorted,
|
|
1386
|
-
count: sorted.length
|
|
1387
|
-
};
|
|
1388
|
-
}).build();
|
|
1389
|
-
var arrayGroupBy = toolBuilder().name("array-group-by").description("Group an array of objects by a property value. Returns an object with groups as keys.").category(ToolCategory.UTILITY).tags(["array", "group", "data", "transform"]).schema(z.object({
|
|
1892
|
+
});
|
|
1893
|
+
var arrayGroupBySchema = z.object({
|
|
1390
1894
|
array: z.array(z.any().describe("Array element")).describe("Array to group"),
|
|
1391
1895
|
property: z.string().describe("Property name to group by")
|
|
1392
|
-
})
|
|
1393
|
-
|
|
1394
|
-
for (const item of input.array) {
|
|
1395
|
-
const key = String(item[input.property]);
|
|
1396
|
-
if (!groups[key]) {
|
|
1397
|
-
groups[key] = [];
|
|
1398
|
-
}
|
|
1399
|
-
groups[key].push(item);
|
|
1400
|
-
}
|
|
1401
|
-
return {
|
|
1402
|
-
groups,
|
|
1403
|
-
groupCount: Object.keys(groups).length,
|
|
1404
|
-
totalItems: input.array.length
|
|
1405
|
-
};
|
|
1406
|
-
}).build();
|
|
1407
|
-
var objectPick = toolBuilder().name("object-pick").description("Create a new object with only the specified properties from the source object.").category(ToolCategory.UTILITY).tags(["object", "pick", "data", "transform"]).schema(z.object({
|
|
1896
|
+
});
|
|
1897
|
+
var objectPickSchema = z.object({
|
|
1408
1898
|
object: z.record(z.any().describe("Property value")).describe("Source object"),
|
|
1409
1899
|
properties: z.array(z.string().describe("String value")).describe("List of property names to pick")
|
|
1410
|
-
})
|
|
1411
|
-
|
|
1412
|
-
for (const prop of input.properties) {
|
|
1413
|
-
if (prop in input.object) {
|
|
1414
|
-
picked[prop] = input.object[prop];
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
return picked;
|
|
1418
|
-
}).build();
|
|
1419
|
-
var objectOmit = toolBuilder().name("object-omit").description("Create a new object excluding the specified properties from the source object.").category(ToolCategory.UTILITY).tags(["object", "omit", "data", "transform"]).schema(z.object({
|
|
1900
|
+
});
|
|
1901
|
+
var objectOmitSchema = z.object({
|
|
1420
1902
|
object: z.record(z.any().describe("Property value")).describe("Source object"),
|
|
1421
1903
|
properties: z.array(z.string().describe("String value")).describe("List of property names to omit")
|
|
1422
|
-
})
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1904
|
+
});
|
|
1905
|
+
function createArrayFilterTool() {
|
|
1906
|
+
return toolBuilder().name("array-filter").description("Filter an array based on a property value. Supports equality, comparison, and contains operations.").category(ToolCategory.UTILITY).tags(["array", "filter", "data", "transform"]).schema(arrayFilterSchema).implement(async (input) => {
|
|
1907
|
+
const getNestedValue = (obj, path12) => {
|
|
1908
|
+
return path12.split(".").reduce((current, key) => current?.[key], obj);
|
|
1909
|
+
};
|
|
1910
|
+
const filtered = input.array.filter((item) => {
|
|
1911
|
+
const itemValue = getNestedValue(item, input.property);
|
|
1912
|
+
switch (input.operator) {
|
|
1913
|
+
case "equals":
|
|
1914
|
+
return itemValue === input.value;
|
|
1915
|
+
case "not-equals":
|
|
1916
|
+
return itemValue !== input.value;
|
|
1917
|
+
case "greater-than":
|
|
1918
|
+
return itemValue > input.value;
|
|
1919
|
+
case "less-than":
|
|
1920
|
+
return itemValue < input.value;
|
|
1921
|
+
case "contains":
|
|
1922
|
+
return String(itemValue).includes(String(input.value));
|
|
1923
|
+
case "starts-with":
|
|
1924
|
+
return String(itemValue).startsWith(String(input.value));
|
|
1925
|
+
case "ends-with":
|
|
1926
|
+
return String(itemValue).endsWith(String(input.value));
|
|
1927
|
+
default:
|
|
1928
|
+
return false;
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
return {
|
|
1932
|
+
filtered,
|
|
1933
|
+
originalCount: input.array.length,
|
|
1934
|
+
filteredCount: filtered.length
|
|
1935
|
+
};
|
|
1936
|
+
}).build();
|
|
1937
|
+
}
|
|
1938
|
+
function createArrayMapTool() {
|
|
1939
|
+
return toolBuilder().name("array-map").description("Extract specific properties from each object in an array. Creates a new array with only the selected properties.").category(ToolCategory.UTILITY).tags(["array", "map", "data", "transform"]).schema(arrayMapSchema).implement(async (input) => {
|
|
1940
|
+
const mapped = input.array.map((item) => {
|
|
1941
|
+
const result = {};
|
|
1942
|
+
for (const prop of input.properties) {
|
|
1943
|
+
const value = prop.split(".").reduce((current, key) => current?.[key], item);
|
|
1944
|
+
result[prop] = value;
|
|
1945
|
+
}
|
|
1946
|
+
return result;
|
|
1947
|
+
});
|
|
1948
|
+
return {
|
|
1949
|
+
mapped,
|
|
1950
|
+
count: mapped.length
|
|
1951
|
+
};
|
|
1952
|
+
}).build();
|
|
1953
|
+
}
|
|
1954
|
+
function createArraySortTool() {
|
|
1955
|
+
return toolBuilder().name("array-sort").description("Sort an array by a property value. Supports ascending and descending order.").category(ToolCategory.UTILITY).tags(["array", "sort", "data", "transform"]).schema(arraySortSchema).implement(async (input) => {
|
|
1956
|
+
const getNestedValue = (obj, path12) => {
|
|
1957
|
+
return path12.split(".").reduce((current, key) => current?.[key], obj);
|
|
1958
|
+
};
|
|
1959
|
+
const sorted = [...input.array].sort((a, b) => {
|
|
1960
|
+
const aValue = getNestedValue(a, input.property);
|
|
1961
|
+
const bValue = getNestedValue(b, input.property);
|
|
1962
|
+
if (aValue < bValue) return input.order === "asc" ? -1 : 1;
|
|
1963
|
+
if (aValue > bValue) return input.order === "asc" ? 1 : -1;
|
|
1964
|
+
return 0;
|
|
1965
|
+
});
|
|
1966
|
+
return {
|
|
1967
|
+
sorted,
|
|
1968
|
+
count: sorted.length
|
|
1969
|
+
};
|
|
1970
|
+
}).build();
|
|
1971
|
+
}
|
|
1972
|
+
function createArrayGroupByTool() {
|
|
1973
|
+
return toolBuilder().name("array-group-by").description("Group an array of objects by a property value. Returns an object with groups as keys.").category(ToolCategory.UTILITY).tags(["array", "group", "data", "transform"]).schema(arrayGroupBySchema).implement(async (input) => {
|
|
1974
|
+
const groups = {};
|
|
1975
|
+
for (const item of input.array) {
|
|
1976
|
+
const key = String(item[input.property]);
|
|
1977
|
+
if (!groups[key]) {
|
|
1978
|
+
groups[key] = [];
|
|
1979
|
+
}
|
|
1980
|
+
groups[key].push(item);
|
|
1981
|
+
}
|
|
1982
|
+
return {
|
|
1983
|
+
groups,
|
|
1984
|
+
groupCount: Object.keys(groups).length,
|
|
1985
|
+
totalItems: input.array.length
|
|
1986
|
+
};
|
|
1987
|
+
}).build();
|
|
1988
|
+
}
|
|
1989
|
+
function createObjectPickTool() {
|
|
1990
|
+
return toolBuilder().name("object-pick").description("Create a new object with only the specified properties from the source object.").category(ToolCategory.UTILITY).tags(["object", "pick", "data", "transform"]).schema(objectPickSchema).implement(async (input) => {
|
|
1991
|
+
const picked = {};
|
|
1992
|
+
for (const prop of input.properties) {
|
|
1993
|
+
if (prop in input.object) {
|
|
1994
|
+
picked[prop] = input.object[prop];
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
return picked;
|
|
1998
|
+
}).build();
|
|
1999
|
+
}
|
|
2000
|
+
function createObjectOmitTool() {
|
|
2001
|
+
return toolBuilder().name("object-omit").description("Create a new object excluding the specified properties from the source object.").category(ToolCategory.UTILITY).tags(["object", "omit", "data", "transform"]).schema(objectOmitSchema).implement(async (input) => {
|
|
2002
|
+
const omitted = { ...input.object };
|
|
2003
|
+
for (const prop of input.properties) {
|
|
2004
|
+
delete omitted[prop];
|
|
2005
|
+
}
|
|
2006
|
+
return omitted;
|
|
2007
|
+
}).build();
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
// src/data/transformer/index.ts
|
|
2011
|
+
var arrayFilter = createArrayFilterTool();
|
|
2012
|
+
var arrayMap = createArrayMapTool();
|
|
2013
|
+
var arraySort = createArraySortTool();
|
|
2014
|
+
var arrayGroupBy = createArrayGroupByTool();
|
|
2015
|
+
var objectPick = createObjectPickTool();
|
|
2016
|
+
var objectOmit = createObjectOmitTool();
|
|
2017
|
+
var transformerTools = [arrayFilter, arrayMap, arraySort, arrayGroupBy, objectPick, objectOmit];
|
|
2018
|
+
function createTransformerTools(config = {}) {
|
|
2019
|
+
return [
|
|
2020
|
+
createArrayFilterTool(),
|
|
2021
|
+
createArrayMapTool(),
|
|
2022
|
+
createArraySortTool(),
|
|
2023
|
+
createArrayGroupByTool(),
|
|
2024
|
+
createObjectPickTool(),
|
|
2025
|
+
createObjectOmitTool()
|
|
2026
|
+
];
|
|
2027
|
+
}
|
|
2028
|
+
var fileReaderSchema = z.object({
|
|
1430
2029
|
path: z.string().describe("Path to the file to read"),
|
|
1431
2030
|
encoding: z.enum(["utf8", "utf-8", "ascii", "base64", "hex", "binary"]).default("utf8").describe("File encoding")
|
|
1432
|
-
})
|
|
1433
|
-
|
|
1434
|
-
const stats = await promises.stat(input.path);
|
|
1435
|
-
return {
|
|
1436
|
-
content,
|
|
1437
|
-
size: stats.size,
|
|
1438
|
-
path: input.path,
|
|
1439
|
-
encoding: input.encoding
|
|
1440
|
-
};
|
|
1441
|
-
}).build();
|
|
1442
|
-
var fileWriter = 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(ToolCategory.FILE_SYSTEM).tags(["file", "write", "io", "filesystem"]).schema(z.object({
|
|
2031
|
+
});
|
|
2032
|
+
var fileWriterSchema = z.object({
|
|
1443
2033
|
path: z.string().describe("Path to the file to write"),
|
|
1444
2034
|
content: z.string().describe("Content to write to the file"),
|
|
1445
2035
|
encoding: z.enum(["utf8", "utf-8", "ascii", "base64", "hex"]).default("utf8").describe("File encoding"),
|
|
1446
2036
|
createDirs: z.boolean().default(false).describe("Create parent directories if they don't exist")
|
|
1447
|
-
})
|
|
1448
|
-
|
|
1449
|
-
const dir = path3.dirname(input.path);
|
|
1450
|
-
await promises.mkdir(dir, { recursive: true });
|
|
1451
|
-
}
|
|
1452
|
-
await promises.writeFile(input.path, input.content, input.encoding);
|
|
1453
|
-
const stats = await promises.stat(input.path);
|
|
1454
|
-
return {
|
|
1455
|
-
path: input.path,
|
|
1456
|
-
size: stats.size,
|
|
1457
|
-
encoding: input.encoding
|
|
1458
|
-
};
|
|
1459
|
-
}).build();
|
|
1460
|
-
var fileAppend = toolBuilder().name("file-append").description("Append content to the end of a file. Creates the file if it doesn't exist.").category(ToolCategory.FILE_SYSTEM).tags(["file", "append", "io", "filesystem"]).schema(z.object({
|
|
2037
|
+
});
|
|
2038
|
+
var fileAppendSchema = z.object({
|
|
1461
2039
|
path: z.string().describe("Path to the file to append to"),
|
|
1462
2040
|
content: z.string().describe("Content to append to the file"),
|
|
1463
2041
|
encoding: z.enum(["utf8", "utf-8", "ascii"]).default("utf8").describe("File encoding")
|
|
1464
|
-
})
|
|
1465
|
-
|
|
1466
|
-
const stats = await promises.stat(input.path);
|
|
1467
|
-
return {
|
|
1468
|
-
path: input.path,
|
|
1469
|
-
size: stats.size
|
|
1470
|
-
};
|
|
1471
|
-
}).build();
|
|
1472
|
-
var fileDelete = toolBuilder().name("file-delete").description("Delete a file from the file system. Returns an error if the file doesn't exist.").category(ToolCategory.FILE_SYSTEM).tags(["file", "delete", "remove", "filesystem"]).schema(z.object({
|
|
2042
|
+
});
|
|
2043
|
+
var fileDeleteSchema = z.object({
|
|
1473
2044
|
path: z.string().describe("Path to the file to delete")
|
|
1474
|
-
})
|
|
1475
|
-
|
|
1476
|
-
return {
|
|
1477
|
-
path: input.path,
|
|
1478
|
-
message: "File deleted successfully"
|
|
1479
|
-
};
|
|
1480
|
-
}).build();
|
|
1481
|
-
var fileExists = toolBuilder().name("file-exists").description("Check if a file or directory exists at the specified path.").category(ToolCategory.FILE_SYSTEM).tags(["file", "exists", "check", "filesystem"]).schema(z.object({
|
|
2045
|
+
});
|
|
2046
|
+
var fileExistsSchema = z.object({
|
|
1482
2047
|
path: z.string().describe("Path to check")
|
|
1483
|
-
})
|
|
1484
|
-
|
|
1485
|
-
|
|
2048
|
+
});
|
|
2049
|
+
function createFileReaderTool(defaultEncoding = "utf8") {
|
|
2050
|
+
return toolBuilder().name("file-reader").description("Read the contents of a file from the file system. Supports text and binary files with various encodings.").category(ToolCategory.FILE_SYSTEM).tags(["file", "read", "io", "filesystem"]).schema(fileReaderSchema).implementSafe(async (input) => {
|
|
2051
|
+
const encoding = input.encoding || defaultEncoding;
|
|
2052
|
+
const content = await promises.readFile(input.path, encoding);
|
|
2053
|
+
const stats = await promises.stat(input.path);
|
|
2054
|
+
return {
|
|
2055
|
+
content,
|
|
2056
|
+
size: stats.size,
|
|
2057
|
+
path: input.path,
|
|
2058
|
+
encoding
|
|
2059
|
+
};
|
|
2060
|
+
}).build();
|
|
2061
|
+
}
|
|
2062
|
+
function createFileWriterTool(defaultEncoding = "utf8", createDirsDefault = false) {
|
|
2063
|
+
return 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(ToolCategory.FILE_SYSTEM).tags(["file", "write", "io", "filesystem"]).schema(fileWriterSchema).implementSafe(async (input) => {
|
|
2064
|
+
const encoding = input.encoding || defaultEncoding;
|
|
2065
|
+
const createDirs = input.createDirs ?? createDirsDefault;
|
|
2066
|
+
if (createDirs) {
|
|
2067
|
+
const dir = path7.dirname(input.path);
|
|
2068
|
+
await promises.mkdir(dir, { recursive: true });
|
|
2069
|
+
}
|
|
2070
|
+
await promises.writeFile(input.path, input.content, encoding);
|
|
1486
2071
|
const stats = await promises.stat(input.path);
|
|
1487
2072
|
return {
|
|
1488
|
-
exists: true,
|
|
1489
2073
|
path: input.path,
|
|
1490
|
-
isFile: stats.isFile(),
|
|
1491
|
-
isDirectory: stats.isDirectory(),
|
|
1492
2074
|
size: stats.size,
|
|
1493
|
-
|
|
2075
|
+
encoding
|
|
1494
2076
|
};
|
|
1495
|
-
}
|
|
2077
|
+
}).build();
|
|
2078
|
+
}
|
|
2079
|
+
function createFileAppendTool(defaultEncoding = "utf8") {
|
|
2080
|
+
return toolBuilder().name("file-append").description("Append content to the end of a file. Creates the file if it doesn't exist.").category(ToolCategory.FILE_SYSTEM).tags(["file", "append", "io", "filesystem"]).schema(fileAppendSchema).implementSafe(async (input) => {
|
|
2081
|
+
const encoding = input.encoding || defaultEncoding;
|
|
2082
|
+
await promises.appendFile(input.path, input.content, encoding);
|
|
2083
|
+
const stats = await promises.stat(input.path);
|
|
1496
2084
|
return {
|
|
1497
|
-
|
|
1498
|
-
|
|
2085
|
+
path: input.path,
|
|
2086
|
+
size: stats.size
|
|
1499
2087
|
};
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
|
|
2088
|
+
}).build();
|
|
2089
|
+
}
|
|
2090
|
+
function createFileDeleteTool() {
|
|
2091
|
+
return toolBuilder().name("file-delete").description("Delete a file from the file system. Returns an error if the file doesn't exist.").category(ToolCategory.FILE_SYSTEM).tags(["file", "delete", "remove", "filesystem"]).schema(fileDeleteSchema).implementSafe(async (input) => {
|
|
2092
|
+
await promises.unlink(input.path);
|
|
2093
|
+
return {
|
|
2094
|
+
path: input.path,
|
|
2095
|
+
message: "File deleted successfully"
|
|
2096
|
+
};
|
|
2097
|
+
}).build();
|
|
2098
|
+
}
|
|
2099
|
+
function createFileExistsTool() {
|
|
2100
|
+
return toolBuilder().name("file-exists").description("Check if a file or directory exists at the specified path.").category(ToolCategory.FILE_SYSTEM).tags(["file", "exists", "check", "filesystem"]).schema(fileExistsSchema).implement(async (input) => {
|
|
2101
|
+
try {
|
|
2102
|
+
await promises.access(input.path);
|
|
2103
|
+
const stats = await promises.stat(input.path);
|
|
2104
|
+
return {
|
|
2105
|
+
exists: true,
|
|
2106
|
+
path: input.path,
|
|
2107
|
+
isFile: stats.isFile(),
|
|
2108
|
+
isDirectory: stats.isDirectory(),
|
|
2109
|
+
size: stats.size,
|
|
2110
|
+
modified: stats.mtime.toISOString()
|
|
2111
|
+
};
|
|
2112
|
+
} catch {
|
|
2113
|
+
return {
|
|
2114
|
+
exists: false,
|
|
2115
|
+
path: input.path
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
2118
|
+
}).build();
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// src/file/operations/index.ts
|
|
2122
|
+
var fileReader = createFileReaderTool();
|
|
2123
|
+
var fileWriter = createFileWriterTool();
|
|
2124
|
+
var fileAppend = createFileAppendTool();
|
|
2125
|
+
var fileDelete = createFileDeleteTool();
|
|
2126
|
+
var fileExists = createFileExistsTool();
|
|
2127
|
+
var fileOperationTools = [
|
|
2128
|
+
fileReader,
|
|
2129
|
+
fileWriter,
|
|
2130
|
+
fileAppend,
|
|
2131
|
+
fileDelete,
|
|
2132
|
+
fileExists
|
|
2133
|
+
];
|
|
2134
|
+
function createFileOperationTools(config = {}) {
|
|
2135
|
+
const {
|
|
2136
|
+
defaultEncoding = "utf8",
|
|
2137
|
+
createDirsDefault = false
|
|
2138
|
+
} = config;
|
|
2139
|
+
return [
|
|
2140
|
+
createFileReaderTool(defaultEncoding),
|
|
2141
|
+
createFileWriterTool(defaultEncoding, createDirsDefault),
|
|
2142
|
+
createFileAppendTool(defaultEncoding),
|
|
2143
|
+
createFileDeleteTool(),
|
|
2144
|
+
createFileExistsTool()
|
|
2145
|
+
];
|
|
2146
|
+
}
|
|
2147
|
+
var directoryListSchema = z.object({
|
|
1503
2148
|
path: z.string().describe("Path to the directory to list"),
|
|
1504
2149
|
recursive: z.boolean().default(false).describe("List files recursively in subdirectories"),
|
|
1505
2150
|
includeDetails: z.boolean().default(false).describe("Include file size, type, and modification date"),
|
|
1506
2151
|
extension: z.string().optional().describe('Optional file extension filter (e.g., ".txt", ".js")')
|
|
1507
|
-
})
|
|
1508
|
-
|
|
1509
|
-
const entries = await promises.readdir(dir, { withFileTypes: true });
|
|
1510
|
-
const files2 = [];
|
|
1511
|
-
for (const entry of entries) {
|
|
1512
|
-
const fullPath = path3.join(dir, entry.name);
|
|
1513
|
-
const relativePath = path3.relative(input.path, fullPath);
|
|
1514
|
-
if (input.extension && !entry.name.endsWith(input.extension)) {
|
|
1515
|
-
if (!entry.isDirectory() || !recursive) {
|
|
1516
|
-
continue;
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
if (input.includeDetails) {
|
|
1520
|
-
const stats = await promises.stat(fullPath);
|
|
1521
|
-
files2.push({
|
|
1522
|
-
name: entry.name,
|
|
1523
|
-
path: relativePath,
|
|
1524
|
-
fullPath,
|
|
1525
|
-
isFile: entry.isFile(),
|
|
1526
|
-
isDirectory: entry.isDirectory(),
|
|
1527
|
-
size: stats.size,
|
|
1528
|
-
modified: stats.mtime.toISOString()
|
|
1529
|
-
});
|
|
1530
|
-
} else {
|
|
1531
|
-
files2.push({
|
|
1532
|
-
name: entry.name,
|
|
1533
|
-
path: relativePath,
|
|
1534
|
-
isFile: entry.isFile(),
|
|
1535
|
-
isDirectory: entry.isDirectory()
|
|
1536
|
-
});
|
|
1537
|
-
}
|
|
1538
|
-
if (recursive && entry.isDirectory()) {
|
|
1539
|
-
const subFiles = await listFiles(fullPath, true);
|
|
1540
|
-
files2.push(...subFiles);
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
return files2;
|
|
1544
|
-
};
|
|
1545
|
-
const files = await listFiles(input.path, input.recursive ?? false);
|
|
1546
|
-
return {
|
|
1547
|
-
path: input.path,
|
|
1548
|
-
files,
|
|
1549
|
-
count: files.length
|
|
1550
|
-
};
|
|
1551
|
-
}).build();
|
|
1552
|
-
var directoryCreate = toolBuilder().name("directory-create").description("Create a new directory. Can optionally create parent directories if they don't exist.").category(ToolCategory.FILE_SYSTEM).tags(["directory", "create", "mkdir", "filesystem"]).schema(z.object({
|
|
2152
|
+
});
|
|
2153
|
+
var directoryCreateSchema = z.object({
|
|
1553
2154
|
path: z.string().describe("Path to the directory to create"),
|
|
1554
2155
|
recursive: z.boolean().default(true).describe("Create parent directories if they don't exist")
|
|
1555
|
-
})
|
|
1556
|
-
|
|
1557
|
-
return {
|
|
1558
|
-
path: input.path,
|
|
1559
|
-
message: "Directory created successfully"
|
|
1560
|
-
};
|
|
1561
|
-
}).build();
|
|
1562
|
-
var directoryDelete = toolBuilder().name("directory-delete").description("Delete a directory. Can optionally delete non-empty directories recursively.").category(ToolCategory.FILE_SYSTEM).tags(["directory", "delete", "remove", "filesystem"]).schema(z.object({
|
|
2156
|
+
});
|
|
2157
|
+
var directoryDeleteSchema = z.object({
|
|
1563
2158
|
path: z.string().describe("Path to the directory to delete"),
|
|
1564
2159
|
recursive: z.boolean().default(false).describe("Delete directory and all its contents")
|
|
1565
|
-
})
|
|
1566
|
-
|
|
1567
|
-
return {
|
|
1568
|
-
path: input.path,
|
|
1569
|
-
message: "Directory deleted successfully"
|
|
1570
|
-
};
|
|
1571
|
-
}).build();
|
|
1572
|
-
var fileSearch = toolBuilder().name("file-search").description("Search for files by name pattern in a directory. Supports wildcards and recursive search.").category(ToolCategory.FILE_SYSTEM).tags(["file", "search", "find", "filesystem"]).schema(z.object({
|
|
2160
|
+
});
|
|
2161
|
+
var fileSearchSchema = z.object({
|
|
1573
2162
|
directory: z.string().describe("Directory to search in"),
|
|
1574
2163
|
pattern: z.string().describe("File name pattern to search for (supports * wildcard)"),
|
|
1575
2164
|
recursive: z.boolean().default(true).describe("Search in subdirectories"),
|
|
1576
2165
|
caseSensitive: z.boolean().default(false).describe("Case-sensitive pattern matching")
|
|
1577
|
-
})
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
const
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
2166
|
+
});
|
|
2167
|
+
function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false) {
|
|
2168
|
+
return toolBuilder().name("directory-list").description("List all files and directories in a directory. Can optionally include file details and filter by extension.").category(ToolCategory.FILE_SYSTEM).tags(["directory", "list", "files", "filesystem"]).schema(directoryListSchema).implementSafe(async (input) => {
|
|
2169
|
+
const listFiles = async (dir, recursive2) => {
|
|
2170
|
+
const entries = await promises.readdir(dir, { withFileTypes: true });
|
|
2171
|
+
const files2 = [];
|
|
2172
|
+
for (const entry of entries) {
|
|
2173
|
+
const fullPath = path7.join(dir, entry.name);
|
|
2174
|
+
const relativePath = path7.relative(input.path, fullPath);
|
|
2175
|
+
if (input.extension && !entry.name.endsWith(input.extension)) {
|
|
2176
|
+
if (!entry.isDirectory() || !recursive2) {
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
if (input.includeDetails) {
|
|
2181
|
+
const stats = await promises.stat(fullPath);
|
|
2182
|
+
files2.push({
|
|
2183
|
+
name: entry.name,
|
|
2184
|
+
path: relativePath,
|
|
2185
|
+
fullPath,
|
|
2186
|
+
isFile: entry.isFile(),
|
|
2187
|
+
isDirectory: entry.isDirectory(),
|
|
2188
|
+
size: stats.size,
|
|
2189
|
+
modified: stats.mtime.toISOString()
|
|
2190
|
+
});
|
|
2191
|
+
} else {
|
|
2192
|
+
files2.push({
|
|
2193
|
+
name: entry.name,
|
|
2194
|
+
path: relativePath,
|
|
2195
|
+
isFile: entry.isFile(),
|
|
2196
|
+
isDirectory: entry.isDirectory()
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2199
|
+
if (recursive2 && entry.isDirectory()) {
|
|
2200
|
+
const subFiles = await listFiles(fullPath, true);
|
|
2201
|
+
files2.push(...subFiles);
|
|
2202
|
+
}
|
|
1587
2203
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
2204
|
+
return files2;
|
|
2205
|
+
};
|
|
2206
|
+
const recursive = input.recursive ?? defaultRecursive;
|
|
2207
|
+
const files = await listFiles(input.path, recursive);
|
|
2208
|
+
return {
|
|
2209
|
+
path: input.path,
|
|
2210
|
+
files,
|
|
2211
|
+
count: files.length
|
|
2212
|
+
};
|
|
2213
|
+
}).build();
|
|
2214
|
+
}
|
|
2215
|
+
function createDirectoryCreateTool(defaultRecursive = true) {
|
|
2216
|
+
return toolBuilder().name("directory-create").description("Create a new directory. Can optionally create parent directories if they don't exist.").category(ToolCategory.FILE_SYSTEM).tags(["directory", "create", "mkdir", "filesystem"]).schema(directoryCreateSchema).implementSafe(async (input) => {
|
|
2217
|
+
const recursive = input.recursive ?? defaultRecursive;
|
|
2218
|
+
await promises.mkdir(input.path, { recursive });
|
|
2219
|
+
return {
|
|
2220
|
+
path: input.path,
|
|
2221
|
+
message: "Directory created successfully"
|
|
2222
|
+
};
|
|
2223
|
+
}).build();
|
|
2224
|
+
}
|
|
2225
|
+
function createDirectoryDeleteTool(defaultRecursive = false) {
|
|
2226
|
+
return toolBuilder().name("directory-delete").description("Delete a directory. Can optionally delete non-empty directories recursively.").category(ToolCategory.FILE_SYSTEM).tags(["directory", "delete", "remove", "filesystem"]).schema(directoryDeleteSchema).implementSafe(async (input) => {
|
|
2227
|
+
const recursive = input.recursive ?? defaultRecursive;
|
|
2228
|
+
await promises.rm(input.path, { recursive, force: false });
|
|
2229
|
+
return {
|
|
2230
|
+
path: input.path,
|
|
2231
|
+
message: "Directory deleted successfully"
|
|
2232
|
+
};
|
|
2233
|
+
}).build();
|
|
2234
|
+
}
|
|
2235
|
+
function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = false) {
|
|
2236
|
+
return toolBuilder().name("file-search").description("Search for files by name pattern in a directory. Supports wildcards and recursive search.").category(ToolCategory.FILE_SYSTEM).tags(["file", "search", "find", "filesystem"]).schema(fileSearchSchema).implementSafe(async (input) => {
|
|
2237
|
+
const recursive = input.recursive ?? defaultRecursive;
|
|
2238
|
+
const caseSensitive = input.caseSensitive ?? defaultCaseSensitive;
|
|
2239
|
+
const searchFiles = async (dir) => {
|
|
2240
|
+
const entries = await promises.readdir(dir, { withFileTypes: true });
|
|
2241
|
+
const matches2 = [];
|
|
2242
|
+
const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
|
|
2243
|
+
const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
|
|
2244
|
+
for (const entry of entries) {
|
|
2245
|
+
const fullPath = path7.join(dir, entry.name);
|
|
2246
|
+
if (entry.isFile() && regex.test(entry.name)) {
|
|
2247
|
+
matches2.push(fullPath);
|
|
2248
|
+
}
|
|
2249
|
+
if (recursive && entry.isDirectory()) {
|
|
2250
|
+
const subMatches = await searchFiles(fullPath);
|
|
2251
|
+
matches2.push(...subMatches);
|
|
2252
|
+
}
|
|
1591
2253
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
};
|
|
1602
|
-
}
|
|
1603
|
-
|
|
2254
|
+
return matches2;
|
|
2255
|
+
};
|
|
2256
|
+
const matches = await searchFiles(input.directory);
|
|
2257
|
+
return {
|
|
2258
|
+
directory: input.directory,
|
|
2259
|
+
pattern: input.pattern,
|
|
2260
|
+
matches,
|
|
2261
|
+
count: matches.length
|
|
2262
|
+
};
|
|
2263
|
+
}).build();
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
// src/file/directory/index.ts
|
|
2267
|
+
var directoryList = createDirectoryListTool();
|
|
2268
|
+
var directoryCreate = createDirectoryCreateTool();
|
|
2269
|
+
var directoryDelete = createDirectoryDeleteTool();
|
|
2270
|
+
var fileSearch = createFileSearchTool();
|
|
2271
|
+
var directoryOperationTools = [
|
|
2272
|
+
directoryList,
|
|
2273
|
+
directoryCreate,
|
|
2274
|
+
directoryDelete,
|
|
2275
|
+
fileSearch
|
|
2276
|
+
];
|
|
2277
|
+
function createDirectoryOperationTools(config = {}) {
|
|
2278
|
+
const {
|
|
2279
|
+
defaultRecursive = false,
|
|
2280
|
+
defaultIncludeDetails = false,
|
|
2281
|
+
defaultCaseSensitive = false
|
|
2282
|
+
} = config;
|
|
2283
|
+
return [
|
|
2284
|
+
createDirectoryListTool(defaultRecursive, defaultIncludeDetails),
|
|
2285
|
+
createDirectoryCreateTool(true),
|
|
2286
|
+
// Always default to true for create
|
|
2287
|
+
createDirectoryDeleteTool(false),
|
|
2288
|
+
// Always default to false for delete (safety)
|
|
2289
|
+
createFileSearchTool(defaultRecursive, defaultCaseSensitive)
|
|
2290
|
+
];
|
|
2291
|
+
}
|
|
2292
|
+
var pathJoinSchema = z.object({
|
|
1604
2293
|
segments: z.array(z.string().describe("String value")).describe("Path segments to join")
|
|
1605
|
-
})
|
|
1606
|
-
|
|
1607
|
-
return {
|
|
1608
|
-
path: joined,
|
|
1609
|
-
segments: input.segments
|
|
1610
|
-
};
|
|
1611
|
-
}).build();
|
|
1612
|
-
var pathResolve = toolBuilder().name("path-resolve").description("Resolve a sequence of paths into an absolute path. Resolves relative paths from the current working directory.").category(ToolCategory.FILE_SYSTEM).tags(["path", "resolve", "absolute", "filesystem"]).schema(z.object({
|
|
2294
|
+
});
|
|
2295
|
+
var pathResolveSchema = z.object({
|
|
1613
2296
|
paths: z.array(z.string().describe("String value")).describe("Paths to resolve")
|
|
1614
|
-
})
|
|
1615
|
-
|
|
1616
|
-
return {
|
|
1617
|
-
path: resolved,
|
|
1618
|
-
isAbsolute: path3.isAbsolute(resolved)
|
|
1619
|
-
};
|
|
1620
|
-
}).build();
|
|
1621
|
-
var pathParse = toolBuilder().name("path-parse").description("Parse a file path into its components (directory, filename, extension, etc.).").category(ToolCategory.FILE_SYSTEM).tags(["path", "parse", "filesystem"]).schema(z.object({
|
|
2297
|
+
});
|
|
2298
|
+
var pathParseSchema = z.object({
|
|
1622
2299
|
path: z.string().describe("File path to parse")
|
|
1623
|
-
})
|
|
1624
|
-
|
|
1625
|
-
return {
|
|
1626
|
-
root: parsed.root,
|
|
1627
|
-
dir: parsed.dir,
|
|
1628
|
-
base: parsed.base,
|
|
1629
|
-
name: parsed.name,
|
|
1630
|
-
ext: parsed.ext,
|
|
1631
|
-
isAbsolute: path3.isAbsolute(input.path)
|
|
1632
|
-
};
|
|
1633
|
-
}).build();
|
|
1634
|
-
var pathBasename = toolBuilder().name("path-basename").description("Get the last portion of a path (filename with extension). Optionally remove the extension.").category(ToolCategory.FILE_SYSTEM).tags(["path", "basename", "filename", "filesystem"]).schema(z.object({
|
|
2300
|
+
});
|
|
2301
|
+
var pathBasenameSchema = z.object({
|
|
1635
2302
|
path: z.string().describe("File path"),
|
|
1636
2303
|
removeExtension: z.boolean().default(false).describe("Remove the file extension")
|
|
1637
|
-
})
|
|
1638
|
-
|
|
1639
|
-
return {
|
|
1640
|
-
basename: basename2,
|
|
1641
|
-
extension: path3.extname(input.path)
|
|
1642
|
-
};
|
|
1643
|
-
}).build();
|
|
1644
|
-
var pathDirname = toolBuilder().name("path-dirname").description("Get the directory name of a path (everything except the last portion).").category(ToolCategory.FILE_SYSTEM).tags(["path", "dirname", "directory", "filesystem"]).schema(z.object({
|
|
2304
|
+
});
|
|
2305
|
+
var pathDirnameSchema = z.object({
|
|
1645
2306
|
path: z.string().describe("File path")
|
|
1646
|
-
})
|
|
1647
|
-
|
|
1648
|
-
return {
|
|
1649
|
-
dirname: dirname3,
|
|
1650
|
-
basename: path3.basename(input.path)
|
|
1651
|
-
};
|
|
1652
|
-
}).build();
|
|
1653
|
-
var pathExtension = toolBuilder().name("path-extension").description('Get the file extension from a path (including the dot, e.g., ".txt").').category(ToolCategory.FILE_SYSTEM).tags(["path", "extension", "ext", "filesystem"]).schema(z.object({
|
|
2307
|
+
});
|
|
2308
|
+
var pathExtensionSchema = z.object({
|
|
1654
2309
|
path: z.string().describe("File path")
|
|
1655
|
-
})
|
|
1656
|
-
|
|
1657
|
-
return {
|
|
1658
|
-
extension: ext,
|
|
1659
|
-
hasExtension: ext.length > 0,
|
|
1660
|
-
filename: path3.basename(input.path, ext)
|
|
1661
|
-
};
|
|
1662
|
-
}).build();
|
|
1663
|
-
var pathRelative = toolBuilder().name("path-relative").description("Get the relative path from one path to another.").category(ToolCategory.FILE_SYSTEM).tags(["path", "relative", "filesystem"]).schema(z.object({
|
|
2310
|
+
});
|
|
2311
|
+
var pathRelativeSchema = z.object({
|
|
1664
2312
|
from: z.string().describe("Source path"),
|
|
1665
2313
|
to: z.string().describe("Destination path")
|
|
1666
|
-
})
|
|
1667
|
-
|
|
1668
|
-
return {
|
|
1669
|
-
relativePath: relative3,
|
|
1670
|
-
from: input.from,
|
|
1671
|
-
to: input.to
|
|
1672
|
-
};
|
|
1673
|
-
}).build();
|
|
1674
|
-
var pathNormalize = toolBuilder().name("path-normalize").description('Normalize a path by resolving ".." and "." segments and removing duplicate separators.').category(ToolCategory.FILE_SYSTEM).tags(["path", "normalize", "filesystem"]).schema(z.object({
|
|
2314
|
+
});
|
|
2315
|
+
var pathNormalizeSchema = z.object({
|
|
1675
2316
|
path: z.string().describe("Path to normalize")
|
|
1676
|
-
})
|
|
1677
|
-
|
|
1678
|
-
return {
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
2317
|
+
});
|
|
2318
|
+
function createPathJoinTool() {
|
|
2319
|
+
return toolBuilder().name("path-join").description("Join multiple path segments into a single path. Handles platform-specific separators.").category(ToolCategory.FILE_SYSTEM).tags(["path", "join", "filesystem"]).schema(pathJoinSchema).implement(async (input) => {
|
|
2320
|
+
const joined = path7.join(...input.segments);
|
|
2321
|
+
return {
|
|
2322
|
+
path: joined,
|
|
2323
|
+
segments: input.segments
|
|
2324
|
+
};
|
|
2325
|
+
}).build();
|
|
2326
|
+
}
|
|
2327
|
+
function createPathResolveTool() {
|
|
2328
|
+
return toolBuilder().name("path-resolve").description("Resolve a sequence of paths into an absolute path. Resolves relative paths from the current working directory.").category(ToolCategory.FILE_SYSTEM).tags(["path", "resolve", "absolute", "filesystem"]).schema(pathResolveSchema).implement(async (input) => {
|
|
2329
|
+
const resolved = path7.resolve(...input.paths);
|
|
2330
|
+
return {
|
|
2331
|
+
path: resolved,
|
|
2332
|
+
isAbsolute: path7.isAbsolute(resolved)
|
|
2333
|
+
};
|
|
2334
|
+
}).build();
|
|
2335
|
+
}
|
|
2336
|
+
function createPathParseTool() {
|
|
2337
|
+
return toolBuilder().name("path-parse").description("Parse a file path into its components (directory, filename, extension, etc.).").category(ToolCategory.FILE_SYSTEM).tags(["path", "parse", "filesystem"]).schema(pathParseSchema).implement(async (input) => {
|
|
2338
|
+
const parsed = path7.parse(input.path);
|
|
2339
|
+
return {
|
|
2340
|
+
root: parsed.root,
|
|
2341
|
+
dir: parsed.dir,
|
|
2342
|
+
base: parsed.base,
|
|
2343
|
+
name: parsed.name,
|
|
2344
|
+
ext: parsed.ext,
|
|
2345
|
+
isAbsolute: path7.isAbsolute(input.path)
|
|
2346
|
+
};
|
|
2347
|
+
}).build();
|
|
2348
|
+
}
|
|
2349
|
+
function createPathBasenameTool() {
|
|
2350
|
+
return toolBuilder().name("path-basename").description("Get the last portion of a path (filename with extension). Optionally remove the extension.").category(ToolCategory.FILE_SYSTEM).tags(["path", "basename", "filename", "filesystem"]).schema(pathBasenameSchema).implement(async (input) => {
|
|
2351
|
+
const basename4 = input.removeExtension ? path7.basename(input.path, path7.extname(input.path)) : path7.basename(input.path);
|
|
2352
|
+
return {
|
|
2353
|
+
basename: basename4,
|
|
2354
|
+
extension: path7.extname(input.path)
|
|
2355
|
+
};
|
|
2356
|
+
}).build();
|
|
2357
|
+
}
|
|
2358
|
+
function createPathDirnameTool() {
|
|
2359
|
+
return toolBuilder().name("path-dirname").description("Get the directory name of a path (everything except the last portion).").category(ToolCategory.FILE_SYSTEM).tags(["path", "dirname", "directory", "filesystem"]).schema(pathDirnameSchema).implement(async (input) => {
|
|
2360
|
+
const dirname3 = path7.dirname(input.path);
|
|
2361
|
+
return {
|
|
2362
|
+
dirname: dirname3,
|
|
2363
|
+
basename: path7.basename(input.path)
|
|
2364
|
+
};
|
|
2365
|
+
}).build();
|
|
2366
|
+
}
|
|
2367
|
+
function createPathExtensionTool() {
|
|
2368
|
+
return toolBuilder().name("path-extension").description('Get the file extension from a path (including the dot, e.g., ".txt").').category(ToolCategory.FILE_SYSTEM).tags(["path", "extension", "ext", "filesystem"]).schema(pathExtensionSchema).implement(async (input) => {
|
|
2369
|
+
const ext = path7.extname(input.path);
|
|
2370
|
+
return {
|
|
2371
|
+
extension: ext,
|
|
2372
|
+
hasExtension: ext.length > 0,
|
|
2373
|
+
filename: path7.basename(input.path, ext)
|
|
2374
|
+
};
|
|
2375
|
+
}).build();
|
|
2376
|
+
}
|
|
2377
|
+
function createPathRelativeTool() {
|
|
2378
|
+
return toolBuilder().name("path-relative").description("Get the relative path from one path to another.").category(ToolCategory.FILE_SYSTEM).tags(["path", "relative", "filesystem"]).schema(pathRelativeSchema).implement(async (input) => {
|
|
2379
|
+
const relative3 = path7.relative(input.from, input.to);
|
|
2380
|
+
return {
|
|
2381
|
+
relativePath: relative3,
|
|
2382
|
+
from: input.from,
|
|
2383
|
+
to: input.to
|
|
2384
|
+
};
|
|
2385
|
+
}).build();
|
|
2386
|
+
}
|
|
2387
|
+
function createPathNormalizeTool() {
|
|
2388
|
+
return toolBuilder().name("path-normalize").description('Normalize a path by resolving ".." and "." segments and removing duplicate separators.').category(ToolCategory.FILE_SYSTEM).tags(["path", "normalize", "filesystem"]).schema(pathNormalizeSchema).implement(async (input) => {
|
|
2389
|
+
const normalized = path7.normalize(input.path);
|
|
2390
|
+
return {
|
|
2391
|
+
normalized,
|
|
2392
|
+
original: input.path
|
|
2393
|
+
};
|
|
2394
|
+
}).build();
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
// src/file/path/index.ts
|
|
2398
|
+
var pathJoin = createPathJoinTool();
|
|
2399
|
+
var pathResolve = createPathResolveTool();
|
|
2400
|
+
var pathParse = createPathParseTool();
|
|
2401
|
+
var pathBasename = createPathBasenameTool();
|
|
2402
|
+
var pathDirname = createPathDirnameTool();
|
|
2403
|
+
var pathExtension = createPathExtensionTool();
|
|
2404
|
+
var pathRelative = createPathRelativeTool();
|
|
2405
|
+
var pathNormalize = createPathNormalizeTool();
|
|
2406
|
+
var pathUtilityTools = [
|
|
2407
|
+
pathJoin,
|
|
2408
|
+
pathResolve,
|
|
2409
|
+
pathParse,
|
|
2410
|
+
pathBasename,
|
|
2411
|
+
pathDirname,
|
|
2412
|
+
pathExtension,
|
|
2413
|
+
pathRelative,
|
|
2414
|
+
pathNormalize
|
|
2415
|
+
];
|
|
2416
|
+
function createPathUtilityTools(config = {}) {
|
|
2417
|
+
return [
|
|
2418
|
+
createPathJoinTool(),
|
|
2419
|
+
createPathResolveTool(),
|
|
2420
|
+
createPathParseTool(),
|
|
2421
|
+
createPathBasenameTool(),
|
|
2422
|
+
createPathDirnameTool(),
|
|
2423
|
+
createPathExtensionTool(),
|
|
2424
|
+
createPathRelativeTool(),
|
|
2425
|
+
createPathNormalizeTool()
|
|
2426
|
+
];
|
|
2427
|
+
}
|
|
2428
|
+
var CurrentDateTimeSchema = z.object({
|
|
1684
2429
|
format: z.enum(["iso", "unix", "custom"]).default("iso").describe("Output format"),
|
|
1685
2430
|
customFormat: z.string().optional().describe('Custom format string (e.g., "yyyy-MM-dd HH:mm:ss") when format is "custom"'),
|
|
1686
2431
|
timezone: z.string().optional().describe('Timezone (e.g., "America/New_York")')
|
|
1687
|
-
})
|
|
1688
|
-
|
|
1689
|
-
let formatted;
|
|
1690
|
-
if (input.format === "iso") {
|
|
1691
|
-
formatted = now.toISOString();
|
|
1692
|
-
} else if (input.format === "unix") {
|
|
1693
|
-
formatted = Math.floor(now.getTime() / 1e3);
|
|
1694
|
-
} else if (input.format === "custom" && input.customFormat) {
|
|
1695
|
-
formatted = format(now, input.customFormat);
|
|
1696
|
-
} else {
|
|
1697
|
-
formatted = now.toISOString();
|
|
1698
|
-
}
|
|
1699
|
-
return {
|
|
1700
|
-
formatted,
|
|
1701
|
-
iso: now.toISOString(),
|
|
1702
|
-
unix: Math.floor(now.getTime() / 1e3),
|
|
1703
|
-
year: now.getFullYear(),
|
|
1704
|
-
month: now.getMonth() + 1,
|
|
1705
|
-
day: now.getDate(),
|
|
1706
|
-
hour: now.getHours(),
|
|
1707
|
-
minute: now.getMinutes(),
|
|
1708
|
-
second: now.getSeconds()
|
|
1709
|
-
};
|
|
1710
|
-
}).build();
|
|
1711
|
-
var dateFormatter = toolBuilder().name("date-formatter").description("Format a date string or timestamp into a different format. Supports ISO, Unix timestamps, and custom formats.").category(ToolCategory.UTILITY).tags(["date", "format", "time"]).schema(z.object({
|
|
2432
|
+
});
|
|
2433
|
+
var DateFormatterSchema = z.object({
|
|
1712
2434
|
date: z.string().describe("Date string or Unix timestamp to format"),
|
|
1713
2435
|
outputFormat: z.string().describe('Output format string (e.g., "yyyy-MM-dd", "MMM dd, yyyy")'),
|
|
1714
2436
|
inputFormat: z.string().optional().describe("Input format string (optional, auto-detected if not provided)")
|
|
1715
|
-
})
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
2437
|
+
});
|
|
2438
|
+
var DateArithmeticSchema = z.object({
|
|
2439
|
+
date: z.string().describe("Starting date (ISO string or Unix timestamp)"),
|
|
2440
|
+
operation: z.enum(["add", "subtract"]).describe("Operation to perform"),
|
|
2441
|
+
amount: z.number().describe("Amount to add or subtract"),
|
|
2442
|
+
unit: z.enum(["years", "months", "weeks", "days", "hours", "minutes", "seconds"]).describe("Time unit")
|
|
2443
|
+
});
|
|
2444
|
+
var DateDifferenceSchema = z.object({
|
|
2445
|
+
startDate: z.string().describe("Start date (ISO string or Unix timestamp)"),
|
|
2446
|
+
endDate: z.string().describe("End date (ISO string or Unix timestamp)"),
|
|
2447
|
+
unit: z.enum(["days", "hours", "minutes"]).default("days").describe("Unit for the difference")
|
|
2448
|
+
});
|
|
2449
|
+
var DateComparisonSchema = z.object({
|
|
2450
|
+
date1: z.string().describe("First date to compare"),
|
|
2451
|
+
date2: z.string().describe("Second date to compare")
|
|
2452
|
+
});
|
|
2453
|
+
|
|
2454
|
+
// src/utility/date-time/tools/current-date-time.ts
|
|
2455
|
+
function createCurrentDateTimeTool() {
|
|
2456
|
+
return toolBuilder().name("current-date-time").description("Get the current date and time in various formats (ISO, Unix timestamp, formatted string).").category(ToolCategory.UTILITY).tags(["date", "time", "now", "current"]).schema(CurrentDateTimeSchema).implement(async (input) => {
|
|
2457
|
+
const now = /* @__PURE__ */ new Date();
|
|
2458
|
+
let formatted;
|
|
2459
|
+
if (input.format === "iso") {
|
|
2460
|
+
formatted = now.toISOString();
|
|
2461
|
+
} else if (input.format === "unix") {
|
|
2462
|
+
formatted = Math.floor(now.getTime() / 1e3);
|
|
2463
|
+
} else if (input.format === "custom" && input.customFormat) {
|
|
2464
|
+
formatted = format(now, input.customFormat);
|
|
1722
2465
|
} else {
|
|
1723
|
-
|
|
1724
|
-
}
|
|
1725
|
-
if (!isValid(date)) {
|
|
1726
|
-
return {
|
|
1727
|
-
success: false,
|
|
1728
|
-
error: "Invalid date"
|
|
1729
|
-
};
|
|
2466
|
+
formatted = now.toISOString();
|
|
1730
2467
|
}
|
|
1731
|
-
const formatted = format(date, input.outputFormat);
|
|
1732
2468
|
return {
|
|
1733
|
-
success: true,
|
|
1734
2469
|
formatted,
|
|
1735
|
-
iso:
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
2470
|
+
iso: now.toISOString(),
|
|
2471
|
+
unix: Math.floor(now.getTime() / 1e3),
|
|
2472
|
+
year: now.getFullYear(),
|
|
2473
|
+
month: now.getMonth() + 1,
|
|
2474
|
+
day: now.getDate(),
|
|
2475
|
+
hour: now.getHours(),
|
|
2476
|
+
minute: now.getMinutes(),
|
|
2477
|
+
second: now.getSeconds()
|
|
1741
2478
|
};
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
2479
|
+
}).build();
|
|
2480
|
+
}
|
|
2481
|
+
function createDateFormatterTool() {
|
|
2482
|
+
return toolBuilder().name("date-formatter").description("Format a date string or timestamp into a different format. Supports ISO, Unix timestamps, and custom formats.").category(ToolCategory.UTILITY).tags(["date", "format", "time"]).schema(DateFormatterSchema).implement(async (input) => {
|
|
2483
|
+
try {
|
|
2484
|
+
let date;
|
|
2485
|
+
if (input.inputFormat) {
|
|
2486
|
+
date = parse$1(input.date, input.inputFormat, /* @__PURE__ */ new Date());
|
|
2487
|
+
} else if (!isNaN(Number(input.date))) {
|
|
2488
|
+
date = new Date(Number(input.date) * 1e3);
|
|
2489
|
+
} else {
|
|
2490
|
+
date = new Date(input.date);
|
|
2491
|
+
}
|
|
2492
|
+
if (!isValid(date)) {
|
|
2493
|
+
return {
|
|
2494
|
+
success: false,
|
|
2495
|
+
error: "Invalid date"
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
const formatted = format(date, input.outputFormat);
|
|
2499
|
+
return {
|
|
2500
|
+
success: true,
|
|
2501
|
+
formatted,
|
|
2502
|
+
iso: date.toISOString()
|
|
2503
|
+
};
|
|
2504
|
+
} catch (error) {
|
|
1753
2505
|
return {
|
|
1754
2506
|
success: false,
|
|
1755
|
-
error: "
|
|
2507
|
+
error: error instanceof Error ? error.message : "Failed to format date"
|
|
1756
2508
|
};
|
|
1757
2509
|
}
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
const start = new Date(input.startDate);
|
|
1779
|
-
const end = new Date(input.endDate);
|
|
1780
|
-
if (!isValid(start) || !isValid(end)) {
|
|
2510
|
+
}).build();
|
|
2511
|
+
}
|
|
2512
|
+
function createDateArithmeticTool() {
|
|
2513
|
+
return toolBuilder().name("date-arithmetic").description("Add or subtract time from a date. Supports years, months, weeks, days, hours, minutes, and seconds.").category(ToolCategory.UTILITY).tags(["date", "time", "add", "subtract", "arithmetic"]).schema(DateArithmeticSchema).implement(async (input) => {
|
|
2514
|
+
try {
|
|
2515
|
+
const date = new Date(input.date);
|
|
2516
|
+
if (!isValid(date)) {
|
|
2517
|
+
return {
|
|
2518
|
+
success: false,
|
|
2519
|
+
error: "Invalid date"
|
|
2520
|
+
};
|
|
2521
|
+
}
|
|
2522
|
+
const duration = { [input.unit]: input.amount };
|
|
2523
|
+
const result = input.operation === "add" ? add(date, duration) : sub(date, duration);
|
|
2524
|
+
return {
|
|
2525
|
+
success: true,
|
|
2526
|
+
result: result.toISOString(),
|
|
2527
|
+
unix: Math.floor(result.getTime() / 1e3)
|
|
2528
|
+
};
|
|
2529
|
+
} catch (error) {
|
|
1781
2530
|
return {
|
|
1782
2531
|
success: false,
|
|
1783
|
-
error: "
|
|
2532
|
+
error: error instanceof Error ? error.message : "Failed to perform date arithmetic"
|
|
1784
2533
|
};
|
|
1785
2534
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
2535
|
+
}).build();
|
|
2536
|
+
}
|
|
2537
|
+
function createDateDifferenceTool() {
|
|
2538
|
+
return toolBuilder().name("date-difference").description("Calculate the difference between two dates in various units (days, hours, minutes).").category(ToolCategory.UTILITY).tags(["date", "time", "difference", "duration"]).schema(DateDifferenceSchema).implement(async (input) => {
|
|
2539
|
+
try {
|
|
2540
|
+
const start = new Date(input.startDate);
|
|
2541
|
+
const end = new Date(input.endDate);
|
|
2542
|
+
if (!isValid(start) || !isValid(end)) {
|
|
2543
|
+
return {
|
|
2544
|
+
success: false,
|
|
2545
|
+
error: "Invalid date(s)"
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
let difference;
|
|
2549
|
+
if (input.unit === "days") {
|
|
2550
|
+
difference = differenceInDays(end, start);
|
|
2551
|
+
} else if (input.unit === "hours") {
|
|
2552
|
+
difference = differenceInHours(end, start);
|
|
2553
|
+
} else {
|
|
2554
|
+
difference = differenceInMinutes(end, start);
|
|
2555
|
+
}
|
|
2556
|
+
return {
|
|
2557
|
+
success: true,
|
|
2558
|
+
difference,
|
|
2559
|
+
unit: input.unit,
|
|
2560
|
+
startDate: start.toISOString(),
|
|
2561
|
+
endDate: end.toISOString()
|
|
2562
|
+
};
|
|
2563
|
+
} catch (error) {
|
|
2564
|
+
return {
|
|
2565
|
+
success: false,
|
|
2566
|
+
error: error instanceof Error ? error.message : "Failed to calculate date difference"
|
|
2567
|
+
};
|
|
1793
2568
|
}
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
2569
|
+
}).build();
|
|
2570
|
+
}
|
|
2571
|
+
function createDateComparisonTool() {
|
|
2572
|
+
return toolBuilder().name("date-comparison").description("Compare two dates to determine if one is before, after, or equal to the other.").category(ToolCategory.UTILITY).tags(["date", "time", "compare", "comparison"]).schema(DateComparisonSchema).implement(async (input) => {
|
|
2573
|
+
try {
|
|
2574
|
+
const d1 = new Date(input.date1);
|
|
2575
|
+
const d2 = new Date(input.date2);
|
|
2576
|
+
if (!isValid(d1) || !isValid(d2)) {
|
|
2577
|
+
return {
|
|
2578
|
+
success: false,
|
|
2579
|
+
error: "Invalid date(s)"
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2582
|
+
return {
|
|
2583
|
+
success: true,
|
|
2584
|
+
date1IsBefore: isBefore(d1, d2),
|
|
2585
|
+
date1IsAfter: isAfter(d1, d2),
|
|
2586
|
+
datesAreEqual: d1.getTime() === d2.getTime(),
|
|
2587
|
+
date1: d1.toISOString(),
|
|
2588
|
+
date2: d2.toISOString()
|
|
2589
|
+
};
|
|
2590
|
+
} catch (error) {
|
|
1816
2591
|
return {
|
|
1817
2592
|
success: false,
|
|
1818
|
-
error: "
|
|
2593
|
+
error: error instanceof Error ? error.message : "Failed to compare dates"
|
|
1819
2594
|
};
|
|
1820
2595
|
}
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2596
|
+
}).build();
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
// src/utility/date-time/index.ts
|
|
2600
|
+
var currentDateTime = createCurrentDateTimeTool();
|
|
2601
|
+
var dateFormatter = createDateFormatterTool();
|
|
2602
|
+
var dateArithmetic = createDateArithmeticTool();
|
|
2603
|
+
var dateDifference = createDateDifferenceTool();
|
|
2604
|
+
var dateComparison = createDateComparisonTool();
|
|
2605
|
+
var dateTimeTools = [
|
|
2606
|
+
currentDateTime,
|
|
2607
|
+
dateFormatter,
|
|
2608
|
+
dateArithmetic,
|
|
2609
|
+
dateDifference,
|
|
2610
|
+
dateComparison
|
|
2611
|
+
];
|
|
2612
|
+
function createDateTimeTools(config = {}) {
|
|
2613
|
+
return [
|
|
2614
|
+
createCurrentDateTimeTool(),
|
|
2615
|
+
createDateFormatterTool(),
|
|
2616
|
+
createDateArithmeticTool(),
|
|
2617
|
+
createDateDifferenceTool(),
|
|
2618
|
+
createDateComparisonTool()
|
|
2619
|
+
];
|
|
2620
|
+
}
|
|
2621
|
+
var StringCaseConverterSchema = z.object({
|
|
1837
2622
|
text: z.string().describe("Text to convert"),
|
|
1838
2623
|
targetCase: z.enum(["lowercase", "uppercase", "title", "camel", "snake", "kebab", "pascal"]).describe("Target case format")
|
|
1839
|
-
})
|
|
1840
|
-
|
|
1841
|
-
switch (input.targetCase) {
|
|
1842
|
-
case "lowercase":
|
|
1843
|
-
result = input.text.toLowerCase();
|
|
1844
|
-
break;
|
|
1845
|
-
case "uppercase":
|
|
1846
|
-
result = input.text.toUpperCase();
|
|
1847
|
-
break;
|
|
1848
|
-
case "title":
|
|
1849
|
-
result = input.text.toLowerCase().replace(/\b\w/g, (char) => char.toUpperCase());
|
|
1850
|
-
break;
|
|
1851
|
-
case "camel":
|
|
1852
|
-
result = input.text.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (_, char) => char.toUpperCase());
|
|
1853
|
-
break;
|
|
1854
|
-
case "snake":
|
|
1855
|
-
result = input.text.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
1856
|
-
break;
|
|
1857
|
-
case "kebab":
|
|
1858
|
-
result = input.text.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1859
|
-
break;
|
|
1860
|
-
case "pascal":
|
|
1861
|
-
result = input.text.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (_, char) => char.toUpperCase()).replace(/^./, (char) => char.toUpperCase());
|
|
1862
|
-
break;
|
|
1863
|
-
default:
|
|
1864
|
-
result = input.text;
|
|
1865
|
-
}
|
|
1866
|
-
return {
|
|
1867
|
-
original: input.text,
|
|
1868
|
-
converted: result,
|
|
1869
|
-
targetCase: input.targetCase
|
|
1870
|
-
};
|
|
1871
|
-
}).build();
|
|
1872
|
-
var stringTrim = toolBuilder().name("string-trim").description("Remove whitespace from the beginning and/or end of a string. Supports trim, trim start, and trim end.").category(ToolCategory.UTILITY).tags(["string", "trim", "whitespace"]).schema(z.object({
|
|
2624
|
+
});
|
|
2625
|
+
var StringTrimSchema = z.object({
|
|
1873
2626
|
text: z.string().describe("Text to trim"),
|
|
1874
2627
|
mode: z.enum(["both", "start", "end"]).default("both").describe("Which side to trim"),
|
|
1875
2628
|
characters: z.string().optional().describe("Optional custom characters to trim (default: whitespace)")
|
|
1876
|
-
})
|
|
1877
|
-
|
|
1878
|
-
if (input.characters) {
|
|
1879
|
-
const chars = input.characters.split("").map((c) => c.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("");
|
|
1880
|
-
const regex = input.mode === "both" ? new RegExp(`^[${chars}]+|[${chars}]+$`, "g") : input.mode === "start" ? new RegExp(`^[${chars}]+`, "g") : new RegExp(`[${chars}]+$`, "g");
|
|
1881
|
-
result = input.text.replace(regex, "");
|
|
1882
|
-
} else {
|
|
1883
|
-
result = input.mode === "both" ? input.text.trim() : input.mode === "start" ? input.text.trimStart() : input.text.trimEnd();
|
|
1884
|
-
}
|
|
1885
|
-
return {
|
|
1886
|
-
original: input.text,
|
|
1887
|
-
trimmed: result,
|
|
1888
|
-
removed: input.text.length - result.length
|
|
1889
|
-
};
|
|
1890
|
-
}).build();
|
|
1891
|
-
var stringReplace = toolBuilder().name("string-replace").description("Replace occurrences of a substring or pattern in a string. Supports regex patterns and global replacement.").category(ToolCategory.UTILITY).tags(["string", "replace", "substitute"]).schema(z.object({
|
|
2629
|
+
});
|
|
2630
|
+
var StringReplaceSchema = z.object({
|
|
1892
2631
|
text: z.string().describe("Text to search in"),
|
|
1893
2632
|
search: z.string().describe("String or regex pattern to search for"),
|
|
1894
2633
|
replace: z.string().describe("Replacement string"),
|
|
1895
2634
|
global: z.boolean().default(true).describe("Replace all occurrences (true) or just the first (false)"),
|
|
1896
2635
|
caseInsensitive: z.boolean().default(false).describe("Case-insensitive search")
|
|
1897
|
-
})
|
|
1898
|
-
|
|
1899
|
-
const regex = new RegExp(input.search, flags);
|
|
1900
|
-
const result = input.text.replace(regex, input.replace);
|
|
1901
|
-
const matches = input.text.match(regex);
|
|
1902
|
-
const count = matches ? matches.length : 0;
|
|
1903
|
-
return {
|
|
1904
|
-
original: input.text,
|
|
1905
|
-
result,
|
|
1906
|
-
replacements: count
|
|
1907
|
-
};
|
|
1908
|
-
}).build();
|
|
1909
|
-
var stringSplit = toolBuilder().name("string-split").description("Split a string into an array of substrings using a delimiter. Supports regex delimiters and limit.").category(ToolCategory.UTILITY).tags(["string", "split", "array"]).schema(z.object({
|
|
2636
|
+
});
|
|
2637
|
+
var StringSplitSchema = z.object({
|
|
1910
2638
|
text: z.string().describe("Text to split"),
|
|
1911
2639
|
delimiter: z.string().describe("Delimiter to split on (can be a regex pattern)"),
|
|
1912
2640
|
limit: z.number().optional().describe("Maximum number of splits")
|
|
1913
|
-
})
|
|
1914
|
-
|
|
1915
|
-
return {
|
|
1916
|
-
parts,
|
|
1917
|
-
count: parts.length
|
|
1918
|
-
};
|
|
1919
|
-
}).build();
|
|
1920
|
-
var stringJoin = toolBuilder().name("string-join").description("Join an array of strings into a single string with a separator.").category(ToolCategory.UTILITY).tags(["string", "join", "array"]).schema(z.object({
|
|
2641
|
+
});
|
|
2642
|
+
var StringJoinSchema = z.object({
|
|
1921
2643
|
parts: z.array(z.string().describe("String value")).describe("Array of strings to join"),
|
|
1922
2644
|
separator: z.string().default("").describe("Separator to use between parts")
|
|
1923
|
-
})
|
|
1924
|
-
|
|
1925
|
-
return {
|
|
1926
|
-
result,
|
|
1927
|
-
partCount: input.parts.length,
|
|
1928
|
-
length: result.length
|
|
1929
|
-
};
|
|
1930
|
-
}).build();
|
|
1931
|
-
var stringSubstring = toolBuilder().name("string-substring").description("Extract a substring from a string using start and end positions.").category(ToolCategory.UTILITY).tags(["string", "substring", "slice"]).schema(z.object({
|
|
2645
|
+
});
|
|
2646
|
+
var StringSubstringSchema = z.object({
|
|
1932
2647
|
text: z.string().describe("Source text"),
|
|
1933
2648
|
start: z.number().describe("Start position (0-based)"),
|
|
1934
2649
|
end: z.number().optional().describe("End position (optional, defaults to end of string)")
|
|
1935
|
-
})
|
|
1936
|
-
|
|
1937
|
-
return {
|
|
1938
|
-
result,
|
|
1939
|
-
length: result.length,
|
|
1940
|
-
start: input.start,
|
|
1941
|
-
end: input.end ?? input.text.length
|
|
1942
|
-
};
|
|
1943
|
-
}).build();
|
|
1944
|
-
var stringLength = toolBuilder().name("string-length").description("Get the length of a string in characters, words, or lines.").category(ToolCategory.UTILITY).tags(["string", "length", "count"]).schema(z.object({
|
|
2650
|
+
});
|
|
2651
|
+
var StringLengthSchema = z.object({
|
|
1945
2652
|
text: z.string().describe("Text to measure")
|
|
1946
|
-
})
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
2653
|
+
});
|
|
2654
|
+
|
|
2655
|
+
// src/utility/string/tools/string-case-converter.ts
|
|
2656
|
+
function createStringCaseConverterTool() {
|
|
2657
|
+
return toolBuilder().name("string-case-converter").description("Convert string to different cases: lowercase, uppercase, title case, camel case, snake case, kebab case.").category(ToolCategory.UTILITY).tags(["string", "case", "convert", "transform"]).schema(StringCaseConverterSchema).implement(async (input) => {
|
|
2658
|
+
let result;
|
|
2659
|
+
switch (input.targetCase) {
|
|
2660
|
+
case "lowercase":
|
|
2661
|
+
result = input.text.toLowerCase();
|
|
2662
|
+
break;
|
|
2663
|
+
case "uppercase":
|
|
2664
|
+
result = input.text.toUpperCase();
|
|
2665
|
+
break;
|
|
2666
|
+
case "title":
|
|
2667
|
+
result = input.text.toLowerCase().replace(/\b\w/g, (char) => char.toUpperCase());
|
|
2668
|
+
break;
|
|
2669
|
+
case "camel":
|
|
2670
|
+
result = input.text.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (_, char) => char.toUpperCase());
|
|
2671
|
+
break;
|
|
2672
|
+
case "snake":
|
|
2673
|
+
result = input.text.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
2674
|
+
break;
|
|
2675
|
+
case "kebab":
|
|
2676
|
+
result = input.text.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
2677
|
+
break;
|
|
2678
|
+
case "pascal":
|
|
2679
|
+
result = input.text.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (_, char) => char.toUpperCase()).replace(/^./, (char) => char.toUpperCase());
|
|
2680
|
+
break;
|
|
2681
|
+
default:
|
|
2682
|
+
result = input.text;
|
|
2683
|
+
}
|
|
2684
|
+
return {
|
|
2685
|
+
original: input.text,
|
|
2686
|
+
converted: result,
|
|
2687
|
+
targetCase: input.targetCase
|
|
2688
|
+
};
|
|
2689
|
+
}).build();
|
|
2690
|
+
}
|
|
2691
|
+
function createStringTrimTool() {
|
|
2692
|
+
return toolBuilder().name("string-trim").description("Remove whitespace from the beginning and/or end of a string. Supports trim, trim start, and trim end.").category(ToolCategory.UTILITY).tags(["string", "trim", "whitespace"]).schema(StringTrimSchema).implement(async (input) => {
|
|
2693
|
+
let result;
|
|
2694
|
+
if (input.characters) {
|
|
2695
|
+
const chars = input.characters.split("").map((c) => c.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("");
|
|
2696
|
+
const regex = input.mode === "both" ? new RegExp(`^[${chars}]+|[${chars}]+$`, "g") : input.mode === "start" ? new RegExp(`^[${chars}]+`, "g") : new RegExp(`[${chars}]+$`, "g");
|
|
2697
|
+
result = input.text.replace(regex, "");
|
|
2698
|
+
} else {
|
|
2699
|
+
result = input.mode === "both" ? input.text.trim() : input.mode === "start" ? input.text.trimStart() : input.text.trimEnd();
|
|
2700
|
+
}
|
|
2701
|
+
return {
|
|
2702
|
+
original: input.text,
|
|
2703
|
+
trimmed: result,
|
|
2704
|
+
removed: input.text.length - result.length
|
|
2705
|
+
};
|
|
2706
|
+
}).build();
|
|
2707
|
+
}
|
|
2708
|
+
function createStringReplaceTool() {
|
|
2709
|
+
return toolBuilder().name("string-replace").description("Replace occurrences of a substring or pattern in a string. Supports regex patterns and global replacement.").category(ToolCategory.UTILITY).tags(["string", "replace", "substitute"]).schema(StringReplaceSchema).implement(async (input) => {
|
|
2710
|
+
const flags = (input.global ? "g" : "") + (input.caseInsensitive ? "i" : "");
|
|
2711
|
+
const regex = new RegExp(input.search, flags);
|
|
2712
|
+
const result = input.text.replace(regex, input.replace);
|
|
2713
|
+
const matches = input.text.match(regex);
|
|
2714
|
+
const count = matches ? matches.length : 0;
|
|
2715
|
+
return {
|
|
2716
|
+
original: input.text,
|
|
2717
|
+
result,
|
|
2718
|
+
replacements: count
|
|
2719
|
+
};
|
|
2720
|
+
}).build();
|
|
2721
|
+
}
|
|
2722
|
+
function createStringSplitTool() {
|
|
2723
|
+
return toolBuilder().name("string-split").description("Split a string into an array of substrings using a delimiter. Supports regex delimiters and limit.").category(ToolCategory.UTILITY).tags(["string", "split", "array"]).schema(StringSplitSchema).implement(async (input) => {
|
|
2724
|
+
const parts = input.text.split(input.delimiter, input.limit);
|
|
2725
|
+
return {
|
|
2726
|
+
parts,
|
|
2727
|
+
count: parts.length
|
|
2728
|
+
};
|
|
2729
|
+
}).build();
|
|
2730
|
+
}
|
|
2731
|
+
function createStringJoinTool() {
|
|
2732
|
+
return toolBuilder().name("string-join").description("Join an array of strings into a single string with a separator.").category(ToolCategory.UTILITY).tags(["string", "join", "array"]).schema(StringJoinSchema).implement(async (input) => {
|
|
2733
|
+
const result = input.parts.join(input.separator);
|
|
2734
|
+
return {
|
|
2735
|
+
result,
|
|
2736
|
+
partCount: input.parts.length,
|
|
2737
|
+
length: result.length
|
|
2738
|
+
};
|
|
2739
|
+
}).build();
|
|
2740
|
+
}
|
|
2741
|
+
function createStringSubstringTool() {
|
|
2742
|
+
return toolBuilder().name("string-substring").description("Extract a substring from a string using start and end positions.").category(ToolCategory.UTILITY).tags(["string", "substring", "slice"]).schema(StringSubstringSchema).implement(async (input) => {
|
|
2743
|
+
const result = input.text.substring(input.start, input.end);
|
|
2744
|
+
return {
|
|
2745
|
+
result,
|
|
2746
|
+
length: result.length,
|
|
2747
|
+
start: input.start,
|
|
2748
|
+
end: input.end ?? input.text.length
|
|
2749
|
+
};
|
|
2750
|
+
}).build();
|
|
2751
|
+
}
|
|
2752
|
+
function createStringLengthTool() {
|
|
2753
|
+
return toolBuilder().name("string-length").description("Get the length of a string in characters, words, or lines.").category(ToolCategory.UTILITY).tags(["string", "length", "count"]).schema(StringLengthSchema).implement(async (input) => {
|
|
2754
|
+
const words = input.text.trim().split(/\s+/).filter((w) => w.length > 0);
|
|
2755
|
+
const lines = input.text.split("\n");
|
|
2756
|
+
return {
|
|
2757
|
+
characters: input.text.length,
|
|
2758
|
+
words: words.length,
|
|
2759
|
+
lines: lines.length
|
|
2760
|
+
};
|
|
2761
|
+
}).build();
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
// src/utility/string/index.ts
|
|
2765
|
+
var stringCaseConverter = createStringCaseConverterTool();
|
|
2766
|
+
var stringTrim = createStringTrimTool();
|
|
2767
|
+
var stringReplace = createStringReplaceTool();
|
|
2768
|
+
var stringSplit = createStringSplitTool();
|
|
2769
|
+
var stringJoin = createStringJoinTool();
|
|
2770
|
+
var stringSubstring = createStringSubstringTool();
|
|
2771
|
+
var stringLength = createStringLengthTool();
|
|
2772
|
+
var stringUtilityTools = [
|
|
2773
|
+
stringCaseConverter,
|
|
2774
|
+
stringTrim,
|
|
2775
|
+
stringReplace,
|
|
2776
|
+
stringSplit,
|
|
2777
|
+
stringJoin,
|
|
2778
|
+
stringSubstring,
|
|
2779
|
+
stringLength
|
|
2780
|
+
];
|
|
2781
|
+
function createStringUtilityTools(config = {}) {
|
|
2782
|
+
return [
|
|
2783
|
+
createStringCaseConverterTool(),
|
|
2784
|
+
createStringTrimTool(),
|
|
2785
|
+
createStringReplaceTool(),
|
|
2786
|
+
createStringSplitTool(),
|
|
2787
|
+
createStringJoinTool(),
|
|
2788
|
+
createStringSubstringTool(),
|
|
2789
|
+
createStringLengthTool()
|
|
2790
|
+
];
|
|
2791
|
+
}
|
|
2792
|
+
var CalculatorSchema = z.object({
|
|
1956
2793
|
operation: z.enum(["add", "subtract", "multiply", "divide", "power", "modulo"]).describe("Mathematical operation to perform"),
|
|
1957
2794
|
a: z.number().describe("First number"),
|
|
1958
2795
|
b: z.number().describe("Second number")
|
|
1959
|
-
})
|
|
1960
|
-
|
|
1961
|
-
switch (input.operation) {
|
|
1962
|
-
case "add":
|
|
1963
|
-
result = input.a + input.b;
|
|
1964
|
-
break;
|
|
1965
|
-
case "subtract":
|
|
1966
|
-
result = input.a - input.b;
|
|
1967
|
-
break;
|
|
1968
|
-
case "multiply":
|
|
1969
|
-
result = input.a * input.b;
|
|
1970
|
-
break;
|
|
1971
|
-
case "divide":
|
|
1972
|
-
if (input.b === 0) {
|
|
1973
|
-
return {
|
|
1974
|
-
success: false,
|
|
1975
|
-
error: "Division by zero"
|
|
1976
|
-
};
|
|
1977
|
-
}
|
|
1978
|
-
result = input.a / input.b;
|
|
1979
|
-
break;
|
|
1980
|
-
case "power":
|
|
1981
|
-
result = Math.pow(input.a, input.b);
|
|
1982
|
-
break;
|
|
1983
|
-
case "modulo":
|
|
1984
|
-
result = input.a % input.b;
|
|
1985
|
-
break;
|
|
1986
|
-
default:
|
|
1987
|
-
return {
|
|
1988
|
-
success: false,
|
|
1989
|
-
error: "Unknown operation"
|
|
1990
|
-
};
|
|
1991
|
-
}
|
|
1992
|
-
return {
|
|
1993
|
-
success: true,
|
|
1994
|
-
result,
|
|
1995
|
-
operation: input.operation,
|
|
1996
|
-
a: input.a,
|
|
1997
|
-
b: input.b
|
|
1998
|
-
};
|
|
1999
|
-
}).build();
|
|
2000
|
-
var mathFunctions = toolBuilder().name("math-functions").description("Apply mathematical functions: sqrt, abs, round, floor, ceil, sin, cos, tan, log, exp.").category(ToolCategory.UTILITY).tags(["math", "functions", "trigonometry"]).schema(z.object({
|
|
2796
|
+
});
|
|
2797
|
+
var MathFunctionsSchema = z.object({
|
|
2001
2798
|
function: z.enum(["sqrt", "abs", "round", "floor", "ceil", "sin", "cos", "tan", "log", "exp"]).describe("Mathematical function to apply"),
|
|
2002
2799
|
value: z.number().describe("Input value")
|
|
2003
|
-
})
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
result = Math.ceil(input.value);
|
|
2800
|
+
});
|
|
2801
|
+
var RandomNumberSchema = z.object({
|
|
2802
|
+
min: z.number().default(0).describe("Minimum value (inclusive)"),
|
|
2803
|
+
max: z.number().default(1).describe("Maximum value (exclusive for decimals, inclusive for integers)"),
|
|
2804
|
+
integer: z.boolean().default(false).describe("Generate an integer (true) or decimal (false)")
|
|
2805
|
+
});
|
|
2806
|
+
var StatisticsSchema = z.object({
|
|
2807
|
+
numbers: z.array(z.number().describe("Number value")).describe("Array of numbers to analyze")
|
|
2808
|
+
});
|
|
2809
|
+
|
|
2810
|
+
// src/utility/math/tools/calculator.ts
|
|
2811
|
+
function createCalculatorTool() {
|
|
2812
|
+
return toolBuilder().name("calculator").description("Perform basic arithmetic operations: add, subtract, multiply, divide, power, modulo.").category(ToolCategory.UTILITY).tags(["math", "calculator", "arithmetic"]).schema(CalculatorSchema).implement(async (input) => {
|
|
2813
|
+
let result;
|
|
2814
|
+
switch (input.operation) {
|
|
2815
|
+
case "add":
|
|
2816
|
+
result = input.a + input.b;
|
|
2021
2817
|
break;
|
|
2022
|
-
case "
|
|
2023
|
-
result =
|
|
2818
|
+
case "subtract":
|
|
2819
|
+
result = input.a - input.b;
|
|
2024
2820
|
break;
|
|
2025
|
-
case "
|
|
2026
|
-
result =
|
|
2821
|
+
case "multiply":
|
|
2822
|
+
result = input.a * input.b;
|
|
2027
2823
|
break;
|
|
2028
|
-
case "
|
|
2029
|
-
|
|
2824
|
+
case "divide":
|
|
2825
|
+
if (input.b === 0) {
|
|
2826
|
+
return {
|
|
2827
|
+
success: false,
|
|
2828
|
+
error: "Division by zero"
|
|
2829
|
+
};
|
|
2830
|
+
}
|
|
2831
|
+
result = input.a / input.b;
|
|
2030
2832
|
break;
|
|
2031
|
-
case "
|
|
2032
|
-
result = Math.
|
|
2833
|
+
case "power":
|
|
2834
|
+
result = Math.pow(input.a, input.b);
|
|
2033
2835
|
break;
|
|
2034
|
-
case "
|
|
2035
|
-
result =
|
|
2836
|
+
case "modulo":
|
|
2837
|
+
result = input.a % input.b;
|
|
2036
2838
|
break;
|
|
2037
2839
|
default:
|
|
2038
2840
|
return {
|
|
2039
2841
|
success: false,
|
|
2040
|
-
error: "Unknown
|
|
2842
|
+
error: "Unknown operation"
|
|
2041
2843
|
};
|
|
2042
2844
|
}
|
|
2043
|
-
|
|
2845
|
+
return {
|
|
2846
|
+
success: true,
|
|
2847
|
+
result,
|
|
2848
|
+
operation: input.operation,
|
|
2849
|
+
a: input.a,
|
|
2850
|
+
b: input.b
|
|
2851
|
+
};
|
|
2852
|
+
}).build();
|
|
2853
|
+
}
|
|
2854
|
+
function createMathFunctionsTool() {
|
|
2855
|
+
return toolBuilder().name("math-functions").description("Apply mathematical functions: sqrt, abs, round, floor, ceil, sin, cos, tan, log, exp.").category(ToolCategory.UTILITY).tags(["math", "functions", "trigonometry"]).schema(MathFunctionsSchema).implement(async (input) => {
|
|
2856
|
+
let result;
|
|
2857
|
+
try {
|
|
2858
|
+
switch (input.function) {
|
|
2859
|
+
case "sqrt":
|
|
2860
|
+
result = Math.sqrt(input.value);
|
|
2861
|
+
break;
|
|
2862
|
+
case "abs":
|
|
2863
|
+
result = Math.abs(input.value);
|
|
2864
|
+
break;
|
|
2865
|
+
case "round":
|
|
2866
|
+
result = Math.round(input.value);
|
|
2867
|
+
break;
|
|
2868
|
+
case "floor":
|
|
2869
|
+
result = Math.floor(input.value);
|
|
2870
|
+
break;
|
|
2871
|
+
case "ceil":
|
|
2872
|
+
result = Math.ceil(input.value);
|
|
2873
|
+
break;
|
|
2874
|
+
case "sin":
|
|
2875
|
+
result = Math.sin(input.value);
|
|
2876
|
+
break;
|
|
2877
|
+
case "cos":
|
|
2878
|
+
result = Math.cos(input.value);
|
|
2879
|
+
break;
|
|
2880
|
+
case "tan":
|
|
2881
|
+
result = Math.tan(input.value);
|
|
2882
|
+
break;
|
|
2883
|
+
case "log":
|
|
2884
|
+
result = Math.log(input.value);
|
|
2885
|
+
break;
|
|
2886
|
+
case "exp":
|
|
2887
|
+
result = Math.exp(input.value);
|
|
2888
|
+
break;
|
|
2889
|
+
default:
|
|
2890
|
+
return {
|
|
2891
|
+
success: false,
|
|
2892
|
+
error: "Unknown function"
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
if (isNaN(result) || !isFinite(result)) {
|
|
2896
|
+
return {
|
|
2897
|
+
success: false,
|
|
2898
|
+
error: "Invalid result (NaN or Infinity)"
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
return {
|
|
2902
|
+
success: true,
|
|
2903
|
+
result,
|
|
2904
|
+
function: input.function,
|
|
2905
|
+
input: input.value
|
|
2906
|
+
};
|
|
2907
|
+
} catch (error) {
|
|
2044
2908
|
return {
|
|
2045
2909
|
success: false,
|
|
2046
|
-
error:
|
|
2910
|
+
error: error instanceof Error ? error.message : "Math operation failed"
|
|
2047
2911
|
};
|
|
2048
2912
|
}
|
|
2913
|
+
}).build();
|
|
2914
|
+
}
|
|
2915
|
+
function createRandomNumberTool() {
|
|
2916
|
+
return toolBuilder().name("random-number").description("Generate a random number within a specified range. Supports integers and decimals.").category(ToolCategory.UTILITY).tags(["random", "number", "generator"]).schema(RandomNumberSchema).implement(async (input) => {
|
|
2917
|
+
const min = input.min ?? 0;
|
|
2918
|
+
const max = input.max ?? 1;
|
|
2919
|
+
const integer = input.integer ?? false;
|
|
2920
|
+
let result;
|
|
2921
|
+
if (integer) {
|
|
2922
|
+
result = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
2923
|
+
} else {
|
|
2924
|
+
result = Math.random() * (max - min) + min;
|
|
2925
|
+
}
|
|
2049
2926
|
return {
|
|
2050
|
-
success: true,
|
|
2051
2927
|
result,
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
} catch (error) {
|
|
2056
|
-
return {
|
|
2057
|
-
success: false,
|
|
2058
|
-
error: error instanceof Error ? error.message : "Math operation failed"
|
|
2928
|
+
min,
|
|
2929
|
+
max,
|
|
2930
|
+
integer
|
|
2059
2931
|
};
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
max,
|
|
2080
|
-
integer
|
|
2081
|
-
};
|
|
2082
|
-
}).build();
|
|
2083
|
-
var statistics = toolBuilder().name("statistics").description("Calculate statistics for an array of numbers: sum, average, min, max, median, standard deviation.").category(ToolCategory.UTILITY).tags(["math", "statistics", "average", "sum"]).schema(z.object({
|
|
2084
|
-
numbers: z.array(z.number().describe("Number value")).describe("Array of numbers to analyze")
|
|
2085
|
-
})).implement(async (input) => {
|
|
2086
|
-
if (input.numbers.length === 0) {
|
|
2932
|
+
}).build();
|
|
2933
|
+
}
|
|
2934
|
+
function createStatisticsTool() {
|
|
2935
|
+
return toolBuilder().name("statistics").description("Calculate statistics for an array of numbers: sum, average, min, max, median, standard deviation.").category(ToolCategory.UTILITY).tags(["math", "statistics", "average", "sum"]).schema(StatisticsSchema).implement(async (input) => {
|
|
2936
|
+
if (input.numbers.length === 0) {
|
|
2937
|
+
return {
|
|
2938
|
+
success: false,
|
|
2939
|
+
error: "Empty array"
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
const sorted = [...input.numbers].sort((a, b) => a - b);
|
|
2943
|
+
const sum = input.numbers.reduce((acc, n) => acc + n, 0);
|
|
2944
|
+
const average = sum / input.numbers.length;
|
|
2945
|
+
const min = sorted[0];
|
|
2946
|
+
const max = sorted[sorted.length - 1];
|
|
2947
|
+
const mid = Math.floor(sorted.length / 2);
|
|
2948
|
+
const median = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
2949
|
+
const variance = input.numbers.reduce((acc, n) => acc + Math.pow(n - average, 2), 0) / input.numbers.length;
|
|
2950
|
+
const stdDev = Math.sqrt(variance);
|
|
2087
2951
|
return {
|
|
2088
|
-
success:
|
|
2089
|
-
|
|
2952
|
+
success: true,
|
|
2953
|
+
count: input.numbers.length,
|
|
2954
|
+
sum,
|
|
2955
|
+
average,
|
|
2956
|
+
min,
|
|
2957
|
+
max,
|
|
2958
|
+
median,
|
|
2959
|
+
standardDeviation: stdDev,
|
|
2960
|
+
variance
|
|
2090
2961
|
};
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
}
|
|
2113
|
-
var
|
|
2962
|
+
}).build();
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
// src/utility/math/index.ts
|
|
2966
|
+
var calculator = createCalculatorTool();
|
|
2967
|
+
var mathFunctions = createMathFunctionsTool();
|
|
2968
|
+
var randomNumber = createRandomNumberTool();
|
|
2969
|
+
var statistics = createStatisticsTool();
|
|
2970
|
+
var mathOperationTools = [
|
|
2971
|
+
calculator,
|
|
2972
|
+
mathFunctions,
|
|
2973
|
+
randomNumber,
|
|
2974
|
+
statistics
|
|
2975
|
+
];
|
|
2976
|
+
function createMathOperationTools(config = {}) {
|
|
2977
|
+
return [
|
|
2978
|
+
createCalculatorTool(),
|
|
2979
|
+
createMathFunctionsTool(),
|
|
2980
|
+
createRandomNumberTool(),
|
|
2981
|
+
createStatisticsTool()
|
|
2982
|
+
];
|
|
2983
|
+
}
|
|
2984
|
+
var EmailValidatorSchema = z.object({
|
|
2114
2985
|
email: z.string().describe("Email address to validate")
|
|
2115
|
-
})
|
|
2116
|
-
|
|
2117
|
-
const valid = emailRegex.test(input.email);
|
|
2118
|
-
return {
|
|
2119
|
-
valid,
|
|
2120
|
-
email: input.email,
|
|
2121
|
-
message: valid ? "Valid email address" : "Invalid email address format"
|
|
2122
|
-
};
|
|
2123
|
-
}).build();
|
|
2124
|
-
var urlValidatorSimple = toolBuilder().name("url-validator-simple").description("Validate if a string is a valid URL format.").category(ToolCategory.UTILITY).tags(["validation", "url", "validate"]).schema(z.object({
|
|
2986
|
+
});
|
|
2987
|
+
var UrlValidatorSimpleSchema = z.object({
|
|
2125
2988
|
url: z.string().describe("URL to validate")
|
|
2126
|
-
})
|
|
2127
|
-
|
|
2128
|
-
|
|
2989
|
+
});
|
|
2990
|
+
var PhoneValidatorSchema = z.object({
|
|
2991
|
+
phone: z.string().describe("Phone number to validate"),
|
|
2992
|
+
strict: z.boolean().default(false).describe("Use strict validation (requires country code)")
|
|
2993
|
+
});
|
|
2994
|
+
var CreditCardValidatorSchema = z.object({
|
|
2995
|
+
cardNumber: z.string().describe("Credit card number to validate")
|
|
2996
|
+
});
|
|
2997
|
+
var IpValidatorSchema = z.object({
|
|
2998
|
+
ip: z.string().describe("IP address to validate"),
|
|
2999
|
+
version: z.enum(["v4", "v6", "any"]).default("any").describe("IP version to validate against")
|
|
3000
|
+
});
|
|
3001
|
+
var UuidValidatorSchema = z.object({
|
|
3002
|
+
uuid: z.string().describe("UUID to validate")
|
|
3003
|
+
});
|
|
3004
|
+
|
|
3005
|
+
// src/utility/validation/tools/email-validator.ts
|
|
3006
|
+
function createEmailValidatorTool() {
|
|
3007
|
+
return toolBuilder().name("email-validator").description("Validate if a string is a valid email address format.").category(ToolCategory.UTILITY).tags(["validation", "email", "validate"]).schema(EmailValidatorSchema).implement(async (input) => {
|
|
3008
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3009
|
+
const valid = emailRegex.test(input.email);
|
|
2129
3010
|
return {
|
|
2130
|
-
valid
|
|
2131
|
-
|
|
2132
|
-
message: "Valid
|
|
3011
|
+
valid,
|
|
3012
|
+
email: input.email,
|
|
3013
|
+
message: valid ? "Valid email address" : "Invalid email address format"
|
|
2133
3014
|
};
|
|
2134
|
-
}
|
|
3015
|
+
}).build();
|
|
3016
|
+
}
|
|
3017
|
+
function createUrlValidatorSimpleTool() {
|
|
3018
|
+
return toolBuilder().name("url-validator-simple").description("Validate if a string is a valid URL format.").category(ToolCategory.UTILITY).tags(["validation", "url", "validate"]).schema(UrlValidatorSimpleSchema).implement(async (input) => {
|
|
3019
|
+
try {
|
|
3020
|
+
new URL(input.url);
|
|
3021
|
+
return {
|
|
3022
|
+
valid: true,
|
|
3023
|
+
url: input.url,
|
|
3024
|
+
message: "Valid URL"
|
|
3025
|
+
};
|
|
3026
|
+
} catch {
|
|
3027
|
+
return {
|
|
3028
|
+
valid: false,
|
|
3029
|
+
url: input.url,
|
|
3030
|
+
message: "Invalid URL format"
|
|
3031
|
+
};
|
|
3032
|
+
}
|
|
3033
|
+
}).build();
|
|
3034
|
+
}
|
|
3035
|
+
function createPhoneValidatorTool() {
|
|
3036
|
+
return toolBuilder().name("phone-validator").description("Validate if a string is a valid phone number format. Supports various international formats.").category(ToolCategory.UTILITY).tags(["validation", "phone", "validate"]).schema(PhoneValidatorSchema).implement(async (input) => {
|
|
3037
|
+
const basicRegex = /^[\d\s\-\+\(\)]+$/;
|
|
3038
|
+
const strictRegex = /^\+?[1-9]\d{1,14}$/;
|
|
3039
|
+
const regex = input.strict ? strictRegex : basicRegex;
|
|
3040
|
+
const valid = regex.test(input.phone.replace(/\s/g, ""));
|
|
2135
3041
|
return {
|
|
2136
|
-
valid
|
|
2137
|
-
|
|
2138
|
-
message: "Invalid
|
|
3042
|
+
valid,
|
|
3043
|
+
phone: input.phone,
|
|
3044
|
+
message: valid ? "Valid phone number format" : "Invalid phone number format"
|
|
2139
3045
|
};
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
3046
|
+
}).build();
|
|
3047
|
+
}
|
|
3048
|
+
function createCreditCardValidatorTool() {
|
|
3049
|
+
return toolBuilder().name("credit-card-validator").description("Validate if a string is a valid credit card number using the Luhn algorithm.").category(ToolCategory.UTILITY).tags(["validation", "credit-card", "validate", "luhn"]).schema(CreditCardValidatorSchema).implement(async (input) => {
|
|
3050
|
+
const cleaned = input.cardNumber.replace(/[\s\-]/g, "");
|
|
3051
|
+
if (!/^\d+$/.test(cleaned)) {
|
|
3052
|
+
return {
|
|
3053
|
+
valid: false,
|
|
3054
|
+
message: "Card number must contain only digits"
|
|
3055
|
+
};
|
|
3056
|
+
}
|
|
3057
|
+
let sum = 0;
|
|
3058
|
+
let isEven = false;
|
|
3059
|
+
for (let i = cleaned.length - 1; i >= 0; i--) {
|
|
3060
|
+
let digit = parseInt(cleaned[i], 10);
|
|
3061
|
+
if (isEven) {
|
|
3062
|
+
digit *= 2;
|
|
3063
|
+
if (digit > 9) {
|
|
3064
|
+
digit -= 9;
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
sum += digit;
|
|
3068
|
+
isEven = !isEven;
|
|
3069
|
+
}
|
|
3070
|
+
const valid = sum % 10 === 0;
|
|
2161
3071
|
return {
|
|
2162
|
-
valid
|
|
2163
|
-
|
|
3072
|
+
valid,
|
|
3073
|
+
cardNumber: input.cardNumber,
|
|
3074
|
+
message: valid ? "Valid credit card number" : "Invalid credit card number (failed Luhn check)"
|
|
2164
3075
|
};
|
|
2165
|
-
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
3076
|
+
}).build();
|
|
3077
|
+
}
|
|
3078
|
+
function createIpValidatorTool() {
|
|
3079
|
+
return toolBuilder().name("ip-validator").description("Validate if a string is a valid IPv4 or IPv6 address.").category(ToolCategory.UTILITY).tags(["validation", "ip", "validate", "network"]).schema(IpValidatorSchema).implement(async (input) => {
|
|
3080
|
+
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
3081
|
+
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
3082
|
+
let valid = false;
|
|
3083
|
+
let detectedVersion;
|
|
3084
|
+
if (input.version === "v4" || input.version === "any") {
|
|
3085
|
+
if (ipv4Regex.test(input.ip)) {
|
|
3086
|
+
const parts = input.ip.split(".");
|
|
3087
|
+
valid = parts.every((part) => {
|
|
3088
|
+
const num = parseInt(part, 10);
|
|
3089
|
+
return num >= 0 && num <= 255;
|
|
3090
|
+
});
|
|
3091
|
+
if (valid) detectedVersion = "IPv4";
|
|
2174
3092
|
}
|
|
2175
3093
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
valid,
|
|
2182
|
-
cardNumber: input.cardNumber,
|
|
2183
|
-
message: valid ? "Valid credit card number" : "Invalid credit card number (failed Luhn check)"
|
|
2184
|
-
};
|
|
2185
|
-
}).build();
|
|
2186
|
-
var ipValidator = toolBuilder().name("ip-validator").description("Validate if a string is a valid IPv4 or IPv6 address.").category(ToolCategory.UTILITY).tags(["validation", "ip", "validate", "network"]).schema(z.object({
|
|
2187
|
-
ip: z.string().describe("IP address to validate"),
|
|
2188
|
-
version: z.enum(["v4", "v6", "any"]).default("any").describe("IP version to validate against")
|
|
2189
|
-
})).implement(async (input) => {
|
|
2190
|
-
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
2191
|
-
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
2192
|
-
let valid = false;
|
|
2193
|
-
let detectedVersion;
|
|
2194
|
-
if (input.version === "v4" || input.version === "any") {
|
|
2195
|
-
if (ipv4Regex.test(input.ip)) {
|
|
2196
|
-
const parts = input.ip.split(".");
|
|
2197
|
-
valid = parts.every((part) => {
|
|
2198
|
-
const num = parseInt(part, 10);
|
|
2199
|
-
return num >= 0 && num <= 255;
|
|
2200
|
-
});
|
|
2201
|
-
if (valid) detectedVersion = "IPv4";
|
|
3094
|
+
if (!valid && (input.version === "v6" || input.version === "any")) {
|
|
3095
|
+
if (ipv6Regex.test(input.ip)) {
|
|
3096
|
+
valid = true;
|
|
3097
|
+
detectedVersion = "IPv6";
|
|
3098
|
+
}
|
|
2202
3099
|
}
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
detectedVersion
|
|
3100
|
+
return {
|
|
3101
|
+
valid,
|
|
3102
|
+
ip: input.ip,
|
|
3103
|
+
version: detectedVersion,
|
|
3104
|
+
message: valid ? `Valid ${detectedVersion} address` : "Invalid IP address format"
|
|
3105
|
+
};
|
|
3106
|
+
}).build();
|
|
3107
|
+
}
|
|
3108
|
+
function createUuidValidatorTool() {
|
|
3109
|
+
return toolBuilder().name("uuid-validator").description("Validate if a string is a valid UUID (v1, v3, v4, or v5).").category(ToolCategory.UTILITY).tags(["validation", "uuid", "validate", "guid"]).schema(UuidValidatorSchema).implement(async (input) => {
|
|
3110
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3111
|
+
const valid = uuidRegex.test(input.uuid);
|
|
3112
|
+
let version;
|
|
3113
|
+
if (valid) {
|
|
3114
|
+
version = parseInt(input.uuid[14], 10);
|
|
2208
3115
|
}
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
};
|
|
2216
|
-
}
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
3116
|
+
return {
|
|
3117
|
+
valid,
|
|
3118
|
+
uuid: input.uuid,
|
|
3119
|
+
version,
|
|
3120
|
+
message: valid ? `Valid UUID v${version}` : "Invalid UUID format"
|
|
3121
|
+
};
|
|
3122
|
+
}).build();
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
// src/utility/validation/index.ts
|
|
3126
|
+
var emailValidator = createEmailValidatorTool();
|
|
3127
|
+
var urlValidatorSimple = createUrlValidatorSimpleTool();
|
|
3128
|
+
var phoneValidator = createPhoneValidatorTool();
|
|
3129
|
+
var creditCardValidator = createCreditCardValidatorTool();
|
|
3130
|
+
var ipValidator = createIpValidatorTool();
|
|
3131
|
+
var uuidValidator = createUuidValidatorTool();
|
|
3132
|
+
var validationTools = [
|
|
3133
|
+
emailValidator,
|
|
3134
|
+
urlValidatorSimple,
|
|
3135
|
+
phoneValidator,
|
|
3136
|
+
creditCardValidator,
|
|
3137
|
+
ipValidator,
|
|
3138
|
+
uuidValidator
|
|
3139
|
+
];
|
|
3140
|
+
function createValidationTools(config = {}) {
|
|
3141
|
+
return [
|
|
3142
|
+
createEmailValidatorTool(),
|
|
3143
|
+
createUrlValidatorSimpleTool(),
|
|
3144
|
+
createPhoneValidatorTool(),
|
|
3145
|
+
createCreditCardValidatorTool(),
|
|
3146
|
+
createIpValidatorTool(),
|
|
3147
|
+
createUuidValidatorTool()
|
|
3148
|
+
];
|
|
3149
|
+
}
|
|
2233
3150
|
var AskHumanInputSchema = z.object({
|
|
2234
3151
|
/**
|
|
2235
3152
|
* The question to ask the human
|
|
@@ -2256,8 +3173,8 @@ var AskHumanInputSchema = z.object({
|
|
|
2256
3173
|
*/
|
|
2257
3174
|
suggestions: z.array(z.string()).optional().describe("Suggested responses for the human")
|
|
2258
3175
|
});
|
|
2259
|
-
var
|
|
2260
|
-
var
|
|
3176
|
+
var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
|
|
3177
|
+
var logger3 = createLogger("askHuman", { level: logLevel3 });
|
|
2261
3178
|
function createAskHumanTool() {
|
|
2262
3179
|
return toolBuilder().name("ask-human").description(
|
|
2263
3180
|
"Ask a human for input or approval. Use this when you need human guidance, approval for a critical action, or clarification on ambiguous requirements. The agent execution will pause until the human responds."
|
|
@@ -2290,13 +3207,13 @@ function createAskHumanTool() {
|
|
|
2290
3207
|
suggestions: validatedInput.suggestions,
|
|
2291
3208
|
status: "pending"
|
|
2292
3209
|
};
|
|
2293
|
-
|
|
3210
|
+
logger3.debug("About to call interrupt()", { humanRequest });
|
|
2294
3211
|
let response;
|
|
2295
3212
|
try {
|
|
2296
3213
|
response = interrupt(humanRequest);
|
|
2297
|
-
|
|
3214
|
+
logger3.debug("interrupt() returned successfully", { response, responseType: typeof response });
|
|
2298
3215
|
} catch (error) {
|
|
2299
|
-
|
|
3216
|
+
logger3.debug("interrupt() threw error (expected for GraphInterrupt)", {
|
|
2300
3217
|
errorType: error?.constructor?.name,
|
|
2301
3218
|
error: error instanceof Error ? error.message : String(error)
|
|
2302
3219
|
});
|
|
@@ -2321,6 +3238,6 @@ function createAskHumanTool() {
|
|
|
2321
3238
|
}
|
|
2322
3239
|
var askHumanTool = createAskHumanTool();
|
|
2323
3240
|
|
|
2324
|
-
export { AskHumanInputSchema, DuckDuckGoProvider, SerperProvider, arrayFilter, arrayGroupBy, arrayMap, arraySort, askHumanTool, calculator, createAskHumanTool, createDuckDuckGoProvider, createSerperProvider, createSlackTools, creditCardValidator, csvGenerator, csvParser, csvToJson, currentDateTime, dateArithmetic, dateComparison, dateDifference, dateFormatter, directoryCreate, directoryDelete, directoryList, emailValidator, extractImages, extractLinks, fileAppend, fileDelete, fileExists, fileReader, fileSearch, fileWriter, getSlackChannels, getSlackMessages, htmlParser, httpClient, httpGet, httpPost, ipValidator, jsonMerge, jsonParser, jsonQuery, jsonStringify, jsonToCsv, jsonToXml, jsonValidator, mathFunctions, notifySlack, objectOmit, objectPick, pathBasename, pathDirname, pathExtension, pathJoin, pathNormalize, pathParse, pathRelative, pathResolve, phoneValidator, randomNumber, searchResultSchema, sendSlackMessage, slackTools, statistics, stringCaseConverter, stringJoin, stringLength, stringReplace, stringSplit, stringSubstring, stringTrim, urlBuilder, urlQueryParser, urlValidator, urlValidatorSimple, uuidValidator, webScraper, webSearch, webSearchOutputSchema, webSearchSchema, xmlGenerator, xmlParser, xmlToJson };
|
|
3241
|
+
export { AskHumanInputSchema, CalculatorSchema, CreditCardValidatorSchema, CurrentDateTimeSchema, DateArithmeticSchema, DateComparisonSchema, DateDifferenceSchema, DateFormatterSchema, DuckDuckGoProvider, EmailValidatorSchema, HttpMethod, IpValidatorSchema, MathFunctionsSchema, PhoneValidatorSchema, RandomNumberSchema, SerperProvider, StatisticsSchema, StringCaseConverterSchema, StringJoinSchema, StringLengthSchema, StringReplaceSchema, StringSplitSchema, StringSubstringSchema, StringTrimSchema, UrlValidatorSimpleSchema, UuidValidatorSchema, archiveConfluencePage, arrayFilter, arrayFilterSchema, arrayGroupBy, arrayGroupBySchema, arrayMap, arrayMapSchema, arraySort, arraySortSchema, askHumanTool, calculator, confluenceTools, createArrayFilterTool, createArrayGroupByTool, createArrayMapTool, createArraySortTool, createAskHumanTool, createCalculatorTool, createConfluencePage, createConfluenceTools, createCreditCardValidatorTool, createCsvGeneratorTool, createCsvParserTool, createCsvToJsonTool, createCsvTools, createCurrentDateTimeTool, createDateArithmeticTool, createDateComparisonTool, createDateDifferenceTool, createDateFormatterTool, createDateTimeTools, createDirectoryCreateTool, createDirectoryDeleteTool, createDirectoryListTool, createDirectoryOperationTools, createDuckDuckGoProvider, createEmailValidatorTool, createExtractImagesTool, createExtractLinksTool, createFileAppendTool, createFileDeleteTool, createFileExistsTool, createFileOperationTools, createFileReaderTool, createFileSearchTool, createFileWriterTool, createHtmlParserTool, createHtmlParserTools, createHttpTools, createIpValidatorTool, createJsonMergeTool, createJsonParserTool, createJsonQueryTool, createJsonStringifyTool, createJsonToCsvTool, createJsonToXmlTool, createJsonTools, createJsonValidatorTool, createMathFunctionsTool, createMathOperationTools, createObjectOmitTool, createObjectPickTool, createPathBasenameTool, createPathDirnameTool, createPathExtensionTool, createPathJoinTool, createPathNormalizeTool, createPathParseTool, createPathRelativeTool, createPathResolveTool, createPathUtilityTools, createPhoneValidatorTool, createRandomNumberTool, createScraperTools, createSerperProvider, createSlackTools, createStatisticsTool, createStringCaseConverterTool, createStringJoinTool, createStringLengthTool, createStringReplaceTool, createStringSplitTool, createStringSubstringTool, createStringTrimTool, createStringUtilityTools, createTransformerTools, createUrlBuilderTool, createUrlQueryParserTool, createUrlValidatorSimpleTool, createUrlValidatorTool, createUrlValidatorTools, createUuidValidatorTool, createValidationTools, createWebScraperTool, createXmlGeneratorTool, createXmlParserTool, createXmlToJsonTool, createXmlTools, creditCardValidator, csvGenerator, csvGeneratorSchema, csvParser, csvParserSchema, csvToJson, csvToJsonSchema, csvTools, currentDateTime, dateArithmetic, dateComparison, dateDifference, dateFormatter, dateTimeTools, directoryCreate, directoryCreateSchema, directoryDelete, directoryDeleteSchema, directoryList, directoryListSchema, directoryOperationTools, emailValidator, extractImages, extractImagesSchema, extractLinks, extractLinksSchema, fileAppend, fileAppendSchema, fileDelete, fileDeleteSchema, fileExists, fileExistsSchema, fileOperationTools, fileReader, fileReaderSchema, fileSearch, fileSearchSchema, fileWriter, fileWriterSchema, getConfluencePage, getSlackChannels, getSlackMessages, getSpacePages, htmlParser, htmlParserSchema, htmlParserTools, httpClient, httpGet, httpGetSchema, httpPost, httpPostSchema, httpRequestSchema, httpTools, ipValidator, jsonMerge, jsonMergeSchema, jsonParser, jsonParserSchema, jsonQuery, jsonQuerySchema, jsonStringify, jsonStringifySchema, jsonToCsv, jsonToCsvSchema, jsonToXml, jsonToXmlSchema, jsonTools, jsonValidator, jsonValidatorSchema, listConfluenceSpaces, mathFunctions, mathOperationTools, notifySlack, objectOmit, objectOmitSchema, objectPick, objectPickSchema, pathBasename, pathBasenameSchema, pathDirname, pathDirnameSchema, pathExtension, pathExtensionSchema, pathJoin, pathJoinSchema, pathNormalize, pathNormalizeSchema, pathParse, pathParseSchema, pathRelative, pathRelativeSchema, pathResolve, pathResolveSchema, pathUtilityTools, phoneValidator, randomNumber, scraperTools, searchConfluence, searchResultSchema, sendSlackMessage, slackTools, statistics, stringCaseConverter, stringJoin, stringLength, stringReplace, stringSplit, stringSubstring, stringTrim, stringUtilityTools, transformerTools, updateConfluencePage, urlBuilder, urlBuilderSchema, urlQueryParser, urlQueryParserSchema, urlValidator, urlValidatorSchema, urlValidatorSimple, urlValidatorTools, uuidValidator, validationTools, webScraper, webScraperSchema, webSearch, webSearchOutputSchema, webSearchSchema, xmlGenerator, xmlGeneratorSchema, xmlParser, xmlParserSchema, xmlToJson, xmlToJsonSchema, xmlTools };
|
|
2325
3242
|
//# sourceMappingURL=index.js.map
|
|
2326
3243
|
//# sourceMappingURL=index.js.map
|