@lupaflow/tools 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,763 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ BaseTool: () => BaseTool,
24
+ CalculatorTool: () => CalculatorTool,
25
+ DeleteFileTool: () => DeleteFileTool,
26
+ EditFileTool: () => EditFileTool,
27
+ GlobTool: () => GlobTool,
28
+ GrepTool: () => GrepTool,
29
+ HTTPTool: () => HTTPTool,
30
+ ListDirectoryTool: () => ListDirectoryTool,
31
+ ReadFileTool: () => ReadFileTool,
32
+ SearchTool: () => SearchTool,
33
+ ShellTool: () => ShellTool,
34
+ WriteFileTool: () => WriteFileTool,
35
+ toolRegistry: () => toolRegistry
36
+ });
37
+ module.exports = __toCommonJS(src_exports);
38
+
39
+ // src/registry.ts
40
+ var import_core = require("@lupaflow/core");
41
+ var ToolRegistry = class {
42
+ tools = /* @__PURE__ */ new Map();
43
+ register(tool) {
44
+ this.tools.set(tool.definition.name, tool);
45
+ }
46
+ get(name) {
47
+ const tool = this.tools.get(name);
48
+ if (!tool) {
49
+ throw new import_core.ToolError(name, `Tool not found: "${name}"`);
50
+ }
51
+ return tool;
52
+ }
53
+ has(name) {
54
+ return this.tools.has(name);
55
+ }
56
+ list() {
57
+ return Array.from(this.tools.values());
58
+ }
59
+ remove(name) {
60
+ this.tools.delete(name);
61
+ }
62
+ clear() {
63
+ this.tools.clear();
64
+ }
65
+ };
66
+ var toolRegistry = new ToolRegistry();
67
+
68
+ // src/interface.ts
69
+ var BaseTool = class {
70
+ toJSON() {
71
+ return this.definition;
72
+ }
73
+ };
74
+
75
+ // src/builtins/calculator.ts
76
+ var CalculatorTool = class extends BaseTool {
77
+ definition = {
78
+ name: "calculator",
79
+ description: "Evaluate mathematical expressions safely",
80
+ parameters: {
81
+ expression: {
82
+ type: "string",
83
+ description: "Mathematical expression to evaluate (e.g., '2 + 2 * 3')"
84
+ }
85
+ },
86
+ required: ["expression"]
87
+ };
88
+ async execute(args) {
89
+ const { expression } = args;
90
+ const sanitized = expression.replace(/[^0-9+\-*/.()^% ]/g, "");
91
+ try {
92
+ const result = Function(`"use strict"; return (${sanitized})`)();
93
+ return { result, expression };
94
+ } catch (err) {
95
+ return { error: err.message, expression };
96
+ }
97
+ }
98
+ };
99
+
100
+ // src/builtins/http.ts
101
+ var HTTPTool = class extends BaseTool {
102
+ definition = {
103
+ name: "http",
104
+ description: "Make HTTP requests (GET, POST, PUT, DELETE)",
105
+ parameters: {
106
+ method: {
107
+ type: "string",
108
+ description: "HTTP method: GET, POST, PUT, DELETE"
109
+ },
110
+ url: {
111
+ type: "string",
112
+ description: "Request URL"
113
+ },
114
+ headers: {
115
+ type: "object",
116
+ description: "Request headers as key-value object"
117
+ },
118
+ body: {
119
+ type: "string",
120
+ description: "Request body (stringified JSON for POST/PUT)"
121
+ }
122
+ },
123
+ required: ["method", "url"]
124
+ };
125
+ async execute(args) {
126
+ const { method, url, headers, body } = args;
127
+ const response = await fetch(url, {
128
+ method: method.toUpperCase(),
129
+ headers: { "Content-Type": "application/json", ...headers },
130
+ body: body || void 0
131
+ });
132
+ const text = await response.text();
133
+ let data = text;
134
+ try {
135
+ data = JSON.parse(text);
136
+ } catch {
137
+ }
138
+ return {
139
+ status: response.status,
140
+ statusText: response.statusText,
141
+ headers: Object.fromEntries(response.headers.entries()),
142
+ data
143
+ };
144
+ }
145
+ };
146
+
147
+ // src/builtins/search.ts
148
+ var SearchTool = class extends BaseTool {
149
+ definition = {
150
+ name: "search",
151
+ description: "Search the web for information",
152
+ parameters: {
153
+ query: {
154
+ type: "string",
155
+ description: "Search query"
156
+ },
157
+ maxResults: {
158
+ type: "number",
159
+ description: "Maximum number of results (default: 5)"
160
+ }
161
+ },
162
+ required: ["query"]
163
+ };
164
+ async execute(args) {
165
+ const { query, maxResults } = args;
166
+ const tavilyKey = process.env.TAVILY_API_KEY;
167
+ if (tavilyKey) {
168
+ return this.searchTavily(query, maxResults || 5, tavilyKey);
169
+ }
170
+ return this.searchDuckDuckGo(query, maxResults || 5);
171
+ }
172
+ async searchTavily(query, maxResults, apiKey) {
173
+ try {
174
+ const res = await fetch("https://api.tavily.com/search", {
175
+ method: "POST",
176
+ headers: { "Content-Type": "application/json" },
177
+ body: JSON.stringify({
178
+ api_key: apiKey,
179
+ query,
180
+ search_depth: "advanced",
181
+ include_answer: true,
182
+ max_results: maxResults
183
+ })
184
+ });
185
+ if (!res.ok) {
186
+ throw new Error(`Tavily API error: ${res.status} ${res.statusText}`);
187
+ }
188
+ const data = await res.json();
189
+ return {
190
+ query,
191
+ results: data.results.map((r) => ({
192
+ title: r.title,
193
+ url: r.url,
194
+ snippet: r.content
195
+ })),
196
+ answer: data.answer,
197
+ source: "tavily"
198
+ };
199
+ } catch (err) {
200
+ return { error: err.message, query, source: "tavily" };
201
+ }
202
+ }
203
+ async searchDuckDuckGo(query, maxResults) {
204
+ try {
205
+ const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
206
+ const response = await fetch(url);
207
+ const html = await response.text();
208
+ const results = [];
209
+ const linkRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g;
210
+ const snippetRegex = /<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
211
+ let count = 0;
212
+ let linkMatch;
213
+ while ((linkMatch = linkRegex.exec(html)) !== null && count < maxResults) {
214
+ const snippetMatch = snippetRegex.exec(html);
215
+ results.push({
216
+ link: linkMatch[1],
217
+ title: linkMatch[2].replace(/<[^>]*>/g, ""),
218
+ snippet: snippetMatch ? snippetMatch[1].replace(/<[^>]*>/g, "") : ""
219
+ });
220
+ count++;
221
+ }
222
+ return { query, results, source: "duckduckgo" };
223
+ } catch (err) {
224
+ return { error: err.message, query, source: "duckduckgo" };
225
+ }
226
+ }
227
+ };
228
+
229
+ // src/builtins/readFile.ts
230
+ var import_promises = require("fs/promises");
231
+ var import_path = require("path");
232
+ var MAX_FILE_SIZE = 1e4;
233
+ var ReadFileTool = class extends BaseTool {
234
+ definition = {
235
+ name: "readFile",
236
+ description: "Read the contents of a file",
237
+ parameters: {
238
+ path: {
239
+ type: "string",
240
+ description: "Relative path to the file to read"
241
+ }
242
+ },
243
+ required: ["path"]
244
+ };
245
+ async execute(args) {
246
+ const { path } = args;
247
+ const cwd = process.cwd();
248
+ const resolved = (0, import_path.resolve)(cwd, path);
249
+ const rel = (0, import_path.relative)(cwd, resolved);
250
+ if (rel.startsWith("..") || (0, import_path.isAbsolute)(rel)) {
251
+ return { error: "Path is outside the project directory" };
252
+ }
253
+ try {
254
+ const content = await (0, import_promises.readFile)(resolved, "utf-8");
255
+ if (content.length > MAX_FILE_SIZE) {
256
+ return {
257
+ content: content.slice(0, MAX_FILE_SIZE),
258
+ truncated: true,
259
+ totalLength: content.length
260
+ };
261
+ }
262
+ return { content };
263
+ } catch (err) {
264
+ const msg = err.message?.replace(/^ENOENT:\s*/, "") || String(err);
265
+ return { error: msg };
266
+ }
267
+ }
268
+ };
269
+
270
+ // src/builtins/writeFile.ts
271
+ var import_promises2 = require("fs/promises");
272
+ var import_path2 = require("path");
273
+ var WriteFileTool = class extends BaseTool {
274
+ definition = {
275
+ name: "writeFile",
276
+ description: "Create a new file or overwrite an existing one",
277
+ parameters: {
278
+ path: {
279
+ type: "string",
280
+ description: "Relative path to write"
281
+ },
282
+ content: {
283
+ type: "string",
284
+ description: "File contents"
285
+ }
286
+ },
287
+ required: ["path", "content"]
288
+ };
289
+ async execute(args) {
290
+ const { path, content } = args;
291
+ const cwd = process.cwd();
292
+ const resolved = (0, import_path2.resolve)(cwd, path);
293
+ const rel = (0, import_path2.relative)(cwd, resolved);
294
+ if (rel.startsWith("..") || (0, import_path2.isAbsolute)(rel)) {
295
+ return { error: "Path is outside the project directory" };
296
+ }
297
+ try {
298
+ let oldContent = null;
299
+ try {
300
+ oldContent = await (0, import_promises2.readFile)(resolved, "utf-8");
301
+ } catch {
302
+ }
303
+ const backupDir = (0, import_path2.resolve)(cwd, ".lupaflow/backups");
304
+ if (oldContent !== null) {
305
+ const backupPath = (0, import_path2.resolve)(backupDir, rel);
306
+ await (0, import_promises2.mkdir)((0, import_path2.dirname)(backupPath), { recursive: true });
307
+ await (0, import_promises2.writeFile)(backupPath, oldContent, "utf-8");
308
+ }
309
+ await (0, import_promises2.mkdir)((0, import_path2.dirname)(resolved), { recursive: true });
310
+ await (0, import_promises2.writeFile)(resolved, content, "utf-8");
311
+ const result = {
312
+ success: true,
313
+ path: rel
314
+ };
315
+ if (oldContent !== null) {
316
+ result.diff = computeDiff(oldContent, content);
317
+ }
318
+ return result;
319
+ } catch (err) {
320
+ return { error: err.message };
321
+ }
322
+ }
323
+ };
324
+ function computeDiff(oldStr, newStr) {
325
+ const oldLines = oldStr.split("\n");
326
+ const newLines = newStr.split("\n");
327
+ const lines = [];
328
+ let i = 0, j = 0;
329
+ while (i < oldLines.length || j < newLines.length) {
330
+ if (i < oldLines.length && j < newLines.length && oldLines[i] === newLines[j]) {
331
+ lines.push(` ${oldLines[i]}`);
332
+ i++;
333
+ j++;
334
+ } else {
335
+ let found = false;
336
+ for (let k = 1; k <= 3; k++) {
337
+ if (i + k < oldLines.length && oldLines[i + k] === newLines[j]) {
338
+ for (let l = 0; l < k; l++) lines.push(`-${oldLines[i + l]}`);
339
+ i += k;
340
+ found = true;
341
+ break;
342
+ }
343
+ if (j + k < newLines.length && oldLines[i] === newLines[j + k]) {
344
+ for (let l = 0; l < k; l++) lines.push(`+${newLines[j + l]}`);
345
+ j += k;
346
+ found = true;
347
+ break;
348
+ }
349
+ }
350
+ if (!found) {
351
+ if (i < oldLines.length) lines.push(`-${oldLines[i]}`);
352
+ if (j < newLines.length) lines.push(`+${newLines[j]}`);
353
+ i++;
354
+ j++;
355
+ }
356
+ }
357
+ }
358
+ return lines.join("\n");
359
+ }
360
+
361
+ // src/builtins/editFile.ts
362
+ var import_promises3 = require("fs/promises");
363
+ var import_path3 = require("path");
364
+ var EditFileTool = class extends BaseTool {
365
+ definition = {
366
+ name: "editFile",
367
+ description: "Replace an exact string match in a file with new content",
368
+ parameters: {
369
+ path: {
370
+ type: "string",
371
+ description: "Relative path to edit"
372
+ },
373
+ oldString: {
374
+ type: "string",
375
+ description: "Exact text to replace; must be unique in the file"
376
+ },
377
+ newString: {
378
+ type: "string",
379
+ description: "Replacement text"
380
+ }
381
+ },
382
+ required: ["path", "oldString", "newString"]
383
+ };
384
+ async execute(args) {
385
+ const { path, oldString, newString } = args;
386
+ const cwd = process.cwd();
387
+ const resolved = (0, import_path3.resolve)(cwd, path);
388
+ const rel = (0, import_path3.relative)(cwd, resolved);
389
+ if (rel.startsWith("..") || (0, import_path3.isAbsolute)(rel)) {
390
+ return { error: "Path is outside the project directory" };
391
+ }
392
+ try {
393
+ const content = await (0, import_promises3.readFile)(resolved, "utf-8");
394
+ const occurrences = content.split(oldString).length - 1;
395
+ if (occurrences === 0) {
396
+ return { error: "oldString not found in file" };
397
+ }
398
+ if (occurrences > 1) {
399
+ return { error: `oldString is ambiguous; found ${occurrences} matches` };
400
+ }
401
+ const backupDir = (0, import_path3.resolve)(cwd, ".lupaflow/backups");
402
+ const backupPath = (0, import_path3.resolve)(backupDir, rel);
403
+ await (0, import_promises3.mkdir)((0, import_path3.dirname)(backupPath), { recursive: true });
404
+ await (0, import_promises3.writeFile)(backupPath, content, "utf-8");
405
+ const newContent = content.replace(oldString, newString);
406
+ await (0, import_promises3.writeFile)(resolved, newContent, "utf-8");
407
+ return {
408
+ success: true,
409
+ path: rel,
410
+ diff: computeDiff2(content, newContent)
411
+ };
412
+ } catch (err) {
413
+ return { error: err.message };
414
+ }
415
+ }
416
+ };
417
+ function computeDiff2(oldStr, newStr) {
418
+ const oldLines = oldStr.split("\n");
419
+ const newLines = newStr.split("\n");
420
+ const lines = [];
421
+ let i = 0, j = 0;
422
+ while (i < oldLines.length || j < newLines.length) {
423
+ if (i < oldLines.length && j < newLines.length && oldLines[i] === newLines[j]) {
424
+ lines.push(` ${oldLines[i]}`);
425
+ i++;
426
+ j++;
427
+ } else {
428
+ let found = false;
429
+ for (let k = 1; k <= 3; k++) {
430
+ if (i + k < oldLines.length && oldLines[i + k] === newLines[j]) {
431
+ for (let l = 0; l < k; l++) lines.push(`-${oldLines[i + l]}`);
432
+ i += k;
433
+ found = true;
434
+ break;
435
+ }
436
+ if (j + k < newLines.length && oldLines[i] === newLines[j + k]) {
437
+ for (let l = 0; l < k; l++) lines.push(`+${newLines[j + l]}`);
438
+ j += k;
439
+ found = true;
440
+ break;
441
+ }
442
+ }
443
+ if (!found) {
444
+ if (i < oldLines.length) lines.push(`-${oldLines[i]}`);
445
+ if (j < newLines.length) lines.push(`+${newLines[j]}`);
446
+ i++;
447
+ j++;
448
+ }
449
+ }
450
+ }
451
+ return lines.join("\n");
452
+ }
453
+
454
+ // src/builtins/deleteFile.ts
455
+ var import_promises4 = require("fs/promises");
456
+ var import_path4 = require("path");
457
+ var DeleteFileTool = class extends BaseTool {
458
+ definition = {
459
+ name: "deleteFile",
460
+ description: "Delete a file",
461
+ parameters: {
462
+ path: {
463
+ type: "string",
464
+ description: "Relative path to the file to delete"
465
+ }
466
+ },
467
+ required: ["path"]
468
+ };
469
+ async execute(args) {
470
+ const { path } = args;
471
+ const cwd = process.cwd();
472
+ const resolved = (0, import_path4.resolve)(cwd, path);
473
+ const rel = (0, import_path4.relative)(cwd, resolved);
474
+ if (rel.startsWith("..") || (0, import_path4.isAbsolute)(rel)) {
475
+ return { error: "Path is outside the project directory" };
476
+ }
477
+ try {
478
+ await (0, import_promises4.unlink)(resolved);
479
+ return { success: true, path: rel };
480
+ } catch (err) {
481
+ return { error: err.message };
482
+ }
483
+ }
484
+ };
485
+
486
+ // src/builtins/listDirectory.ts
487
+ var import_promises5 = require("fs/promises");
488
+ var import_path5 = require("path");
489
+ var ListDirectoryTool = class extends BaseTool {
490
+ definition = {
491
+ name: "listDirectory",
492
+ description: "List entries in a directory",
493
+ parameters: {
494
+ path: {
495
+ type: "string",
496
+ description: "Relative directory path to list"
497
+ }
498
+ },
499
+ required: ["path"]
500
+ };
501
+ async execute(args) {
502
+ const { path } = args;
503
+ const cwd = process.cwd();
504
+ const resolved = (0, import_path5.resolve)(cwd, path);
505
+ const rel = (0, import_path5.relative)(cwd, resolved);
506
+ if (rel.startsWith("..") || (0, import_path5.isAbsolute)(rel)) {
507
+ return { error: "Path is outside the project directory" };
508
+ }
509
+ try {
510
+ const entries = await (0, import_promises5.readdir)(resolved);
511
+ const results = [];
512
+ for (const entry of entries) {
513
+ if (entry.startsWith(".") || entry === "node_modules") continue;
514
+ try {
515
+ const info = await (0, import_promises5.stat)((0, import_path5.join)(resolved, entry));
516
+ results.push({
517
+ name: entry,
518
+ type: info.isDirectory() ? "directory" : "file"
519
+ });
520
+ } catch {
521
+ }
522
+ }
523
+ results.sort(
524
+ (a, b) => a.type !== b.type ? a.type === "directory" ? -1 : 1 : a.name.localeCompare(b.name)
525
+ );
526
+ return { path: rel || ".", entries: results };
527
+ } catch (err) {
528
+ return { error: err.message };
529
+ }
530
+ }
531
+ };
532
+
533
+ // src/builtins/glob.ts
534
+ var import_path6 = require("path");
535
+ var MAX_RESULTS = 200;
536
+ var GlobTool = class extends BaseTool {
537
+ definition = {
538
+ name: "glob",
539
+ description: "Find files matching a glob pattern",
540
+ parameters: {
541
+ pattern: {
542
+ type: "string",
543
+ description: "Glob pattern to match files"
544
+ },
545
+ path: {
546
+ type: "string",
547
+ description: "Directory to search from (default: .)"
548
+ }
549
+ },
550
+ required: ["pattern"]
551
+ };
552
+ async execute(args) {
553
+ const { pattern, path: dir = "." } = args;
554
+ const cwd = process.cwd();
555
+ const resolved = (0, import_path6.resolve)(cwd, dir);
556
+ const rel = (0, import_path6.relative)(cwd, resolved);
557
+ if (rel.startsWith("..") || (0, import_path6.isAbsolute)(rel)) {
558
+ return { error: "Path is outside the project directory" };
559
+ }
560
+ try {
561
+ const glob = new Bun.Glob(pattern);
562
+ const files = [];
563
+ let truncated = false;
564
+ for await (const match of glob.scan({ cwd: resolved, dot: false, onlyFiles: true })) {
565
+ if (match.includes("node_modules")) continue;
566
+ if (files.length >= MAX_RESULTS) {
567
+ truncated = true;
568
+ break;
569
+ }
570
+ files.push((0, import_path6.relative)(cwd, (0, import_path6.resolve)(resolved, match)));
571
+ }
572
+ files.sort();
573
+ const result = { files };
574
+ if (truncated) result.truncated = true;
575
+ return result;
576
+ } catch (err) {
577
+ return { error: err.message };
578
+ }
579
+ }
580
+ };
581
+
582
+ // src/builtins/grep.ts
583
+ var import_path7 = require("path");
584
+ var MAX_MATCHES = 50;
585
+ var GrepTool = class extends BaseTool {
586
+ definition = {
587
+ name: "grep",
588
+ description: "Search file contents using a regex pattern",
589
+ parameters: {
590
+ pattern: {
591
+ type: "string",
592
+ description: "Regex pattern to search for"
593
+ },
594
+ path: {
595
+ type: "string",
596
+ description: "Directory to search from (default: .)"
597
+ },
598
+ include: {
599
+ type: "string",
600
+ description: "Optional glob for files to include (e.g. *.ts)"
601
+ }
602
+ },
603
+ required: ["pattern"]
604
+ };
605
+ async execute(args) {
606
+ const { pattern, path: dir = ".", include } = args;
607
+ const cwd = process.cwd();
608
+ const resolved = (0, import_path7.resolve)(cwd, dir);
609
+ const rel = (0, import_path7.relative)(cwd, resolved);
610
+ if (rel.startsWith("..") || (0, import_path7.isAbsolute)(rel)) {
611
+ return { error: "Path is outside the project directory" };
612
+ }
613
+ try {
614
+ const grepArgs = [
615
+ "-rn",
616
+ "--color=never",
617
+ "--exclude-dir=node_modules",
618
+ "--exclude-dir=.git",
619
+ "-E"
620
+ ];
621
+ if (include) grepArgs.push(`--include=${include}`);
622
+ grepArgs.push(pattern, resolved);
623
+ const proc = Bun.spawn(["grep", ...grepArgs], {
624
+ cwd,
625
+ stdout: "pipe",
626
+ stderr: "pipe"
627
+ });
628
+ const [stdout, stderr] = await Promise.all([
629
+ new Response(proc.stdout).text(),
630
+ new Response(proc.stderr).text()
631
+ ]);
632
+ const exitCode = await proc.exited;
633
+ if (exitCode !== 0 && exitCode !== 1) {
634
+ const msg = stderr.trim() || `grep exited with code ${exitCode}`;
635
+ return { error: msg };
636
+ }
637
+ const trimmed = stderr.trim();
638
+ if (trimmed) {
639
+ return { error: trimmed };
640
+ }
641
+ const lines = stdout.trim().split("\n");
642
+ if (!lines[0]) {
643
+ return { matches: [], message: "No matches found" };
644
+ }
645
+ const matches = [];
646
+ let truncated = false;
647
+ for (const line of lines) {
648
+ if (matches.length >= MAX_MATCHES) {
649
+ truncated = true;
650
+ break;
651
+ }
652
+ const match = line.match(/^(.+?):(\d+):(.*)$/);
653
+ if (match) {
654
+ matches.push({
655
+ file: (0, import_path7.relative)(cwd, match[1]),
656
+ line: Number(match[2]),
657
+ content: match[3]
658
+ });
659
+ }
660
+ }
661
+ const result = { matches };
662
+ if (truncated) {
663
+ result.truncated = true;
664
+ result.totalMatches = lines.length;
665
+ }
666
+ return result;
667
+ } catch (err) {
668
+ return { error: err.message || String(err) };
669
+ }
670
+ }
671
+ };
672
+
673
+ // src/builtins/shell.ts
674
+ var MAX_OUTPUT = 2e4;
675
+ var DEFAULT_TIMEOUT = 3e4;
676
+ var ShellTool = class extends BaseTool {
677
+ definition = {
678
+ name: "shell",
679
+ description: "Execute a shell command",
680
+ parameters: {
681
+ command: {
682
+ type: "string",
683
+ description: "Shell command to run"
684
+ },
685
+ description: {
686
+ type: "string",
687
+ description: "Short description of what the command does"
688
+ },
689
+ timeout: {
690
+ type: "number",
691
+ description: "Timeout in milliseconds (default: 30000)"
692
+ }
693
+ },
694
+ required: ["command"]
695
+ };
696
+ async execute(args) {
697
+ const { command, timeout = DEFAULT_TIMEOUT } = args;
698
+ try {
699
+ const isWindows = process.platform === "win32";
700
+ const shell = isWindows ? "cmd.exe" : "bash";
701
+ const shellFlag = isWindows ? "/c" : "-c";
702
+ const env = isWindows ? { ...process.env } : { ...process.env, TERM: "dumb" };
703
+ const proc = Bun.spawn([shell, shellFlag, command], {
704
+ cwd: process.cwd(),
705
+ stdout: "pipe",
706
+ stderr: "pipe",
707
+ env
708
+ });
709
+ const timer = setTimeout(() => proc.kill(), timeout);
710
+ const [stdout, stderr] = await Promise.all([
711
+ new Response(proc.stdout).text(),
712
+ new Response(proc.stderr).text()
713
+ ]);
714
+ const exitCode = await proc.exited;
715
+ clearTimeout(timer);
716
+ return {
717
+ stdout: truncate(stdout, MAX_OUTPUT),
718
+ stderr: truncate(stderr, MAX_OUTPUT),
719
+ exitCode
720
+ };
721
+ } catch (err) {
722
+ return {
723
+ stdout: "",
724
+ stderr: err.message || String(err),
725
+ exitCode: 1
726
+ };
727
+ }
728
+ }
729
+ };
730
+ function truncate(value, limit) {
731
+ return value.length > limit ? `${value.slice(0, limit)}
732
+ ... (truncated, ${value.length} total chars)` : value;
733
+ }
734
+
735
+ // src/index.ts
736
+ toolRegistry.register(new CalculatorTool());
737
+ toolRegistry.register(new HTTPTool());
738
+ toolRegistry.register(new SearchTool());
739
+ toolRegistry.register(new ReadFileTool());
740
+ toolRegistry.register(new WriteFileTool());
741
+ toolRegistry.register(new EditFileTool());
742
+ toolRegistry.register(new DeleteFileTool());
743
+ toolRegistry.register(new ListDirectoryTool());
744
+ toolRegistry.register(new GlobTool());
745
+ toolRegistry.register(new GrepTool());
746
+ toolRegistry.register(new ShellTool());
747
+ // Annotate the CommonJS export names for ESM import in node:
748
+ 0 && (module.exports = {
749
+ BaseTool,
750
+ CalculatorTool,
751
+ DeleteFileTool,
752
+ EditFileTool,
753
+ GlobTool,
754
+ GrepTool,
755
+ HTTPTool,
756
+ ListDirectoryTool,
757
+ ReadFileTool,
758
+ SearchTool,
759
+ ShellTool,
760
+ WriteFileTool,
761
+ toolRegistry
762
+ });
763
+ //# sourceMappingURL=index.cjs.map