@push.rocks/smartagent 1.2.3 → 1.2.5
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_ts/plugins.d.ts +2 -0
- package/dist_ts/plugins.js +4 -1
- package/dist_ts/smartagent.classes.driveragent.d.ts +11 -1
- package/dist_ts/smartagent.classes.driveragent.js +26 -5
- package/dist_ts/smartagent.classes.dualagent.d.ts +10 -1
- package/dist_ts/smartagent.classes.dualagent.js +164 -8
- package/dist_ts/smartagent.interfaces.d.ts +43 -0
- package/dist_ts/smartagent.interfaces.js +1 -1
- package/dist_ts/smartagent.tools.filesystem.d.ts +8 -0
- package/dist_ts/smartagent.tools.filesystem.js +261 -8
- package/package.json +3 -2
- package/readme.md +154 -30
- package/ts/plugins.ts +5 -0
- package/ts/smartagent.classes.driveragent.ts +35 -4
- package/ts/smartagent.classes.dualagent.ts +177 -7
- package/ts/smartagent.interfaces.ts +62 -0
- package/ts/smartagent.tools.filesystem.ts +305 -7
|
@@ -26,6 +26,14 @@ export interface IDualAgentOptions extends plugins.smartai.ISmartAiOptions {
|
|
|
26
26
|
maxConsecutiveRejections?: number;
|
|
27
27
|
/** Enable verbose logging */
|
|
28
28
|
verbose?: boolean;
|
|
29
|
+
/** Maximum characters for tool result output before truncation (default: 15000). Set to 0 to disable. */
|
|
30
|
+
maxResultChars?: number;
|
|
31
|
+
/** Maximum history messages to pass to API (default: 20). Set to 0 for unlimited. */
|
|
32
|
+
maxHistoryMessages?: number;
|
|
33
|
+
/** Optional callback for live progress updates during execution */
|
|
34
|
+
onProgress?: (event: IProgressEvent) => void;
|
|
35
|
+
/** Prefix for log messages (e.g., "[README]", "[Commit]"). Default: empty */
|
|
36
|
+
logPrefix?: string;
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
// ================================
|
|
@@ -84,6 +92,8 @@ export interface IToolExecutionResult {
|
|
|
84
92
|
success: boolean;
|
|
85
93
|
result?: unknown;
|
|
86
94
|
error?: string;
|
|
95
|
+
/** Optional human-readable summary for history (if provided, used instead of full result) */
|
|
96
|
+
summary?: string;
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
/**
|
|
@@ -195,6 +205,58 @@ export interface IDualAgentRunResult {
|
|
|
195
205
|
error?: string;
|
|
196
206
|
}
|
|
197
207
|
|
|
208
|
+
// ================================
|
|
209
|
+
// Progress Event Interfaces
|
|
210
|
+
// ================================
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Progress event types for live feedback during agent execution
|
|
214
|
+
*/
|
|
215
|
+
export type TProgressEventType =
|
|
216
|
+
| 'task_started'
|
|
217
|
+
| 'iteration_started'
|
|
218
|
+
| 'tool_proposed'
|
|
219
|
+
| 'guardian_evaluating'
|
|
220
|
+
| 'tool_approved'
|
|
221
|
+
| 'tool_rejected'
|
|
222
|
+
| 'tool_executing'
|
|
223
|
+
| 'tool_completed'
|
|
224
|
+
| 'task_completed'
|
|
225
|
+
| 'clarification_needed'
|
|
226
|
+
| 'max_iterations'
|
|
227
|
+
| 'max_rejections';
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Log level for progress events
|
|
231
|
+
*/
|
|
232
|
+
export type TLogLevel = 'info' | 'warn' | 'error' | 'success';
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Progress event for live feedback during agent execution
|
|
236
|
+
*/
|
|
237
|
+
export interface IProgressEvent {
|
|
238
|
+
/** Type of progress event */
|
|
239
|
+
type: TProgressEventType;
|
|
240
|
+
/** Current iteration number */
|
|
241
|
+
iteration?: number;
|
|
242
|
+
/** Maximum iterations configured */
|
|
243
|
+
maxIterations?: number;
|
|
244
|
+
/** Name of the tool being used */
|
|
245
|
+
toolName?: string;
|
|
246
|
+
/** Action being performed */
|
|
247
|
+
action?: string;
|
|
248
|
+
/** Reason for rejection or other explanation */
|
|
249
|
+
reason?: string;
|
|
250
|
+
/** Human-readable message about the event */
|
|
251
|
+
message?: string;
|
|
252
|
+
/** Timestamp of the event */
|
|
253
|
+
timestamp: Date;
|
|
254
|
+
/** Log level for this event (info, warn, error, success) */
|
|
255
|
+
logLevel: TLogLevel;
|
|
256
|
+
/** Pre-formatted log message ready for output */
|
|
257
|
+
logMessage: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
198
260
|
// ================================
|
|
199
261
|
// Utility Types
|
|
200
262
|
// ================================
|
|
@@ -8,6 +8,8 @@ import { BaseToolWrapper } from './smartagent.tools.base.js';
|
|
|
8
8
|
export interface IFilesystemToolOptions {
|
|
9
9
|
/** Base path to scope all operations to. If set, all paths must be within this directory. */
|
|
10
10
|
basePath?: string;
|
|
11
|
+
/** Glob patterns to exclude from listings (e.g., ['.nogit/**', 'node_modules/**']) */
|
|
12
|
+
excludePatterns?: string[];
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -20,12 +22,25 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
20
22
|
|
|
21
23
|
/** Base path to scope all operations to */
|
|
22
24
|
private basePath?: string;
|
|
25
|
+
/** Glob patterns to exclude from listings */
|
|
26
|
+
private excludePatterns: string[];
|
|
23
27
|
|
|
24
28
|
constructor(options?: IFilesystemToolOptions) {
|
|
25
29
|
super();
|
|
26
30
|
if (options?.basePath) {
|
|
27
31
|
this.basePath = plugins.path.resolve(options.basePath);
|
|
28
32
|
}
|
|
33
|
+
this.excludePatterns = options?.excludePatterns || [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check if a relative path should be excluded based on exclude patterns
|
|
38
|
+
*/
|
|
39
|
+
private isExcluded(relativePath: string): boolean {
|
|
40
|
+
if (this.excludePatterns.length === 0) return false;
|
|
41
|
+
return this.excludePatterns.some(pattern =>
|
|
42
|
+
plugins.minimatch(relativePath, pattern, { dot: true })
|
|
43
|
+
);
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
/**
|
|
@@ -46,17 +61,25 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
46
61
|
public actions: interfaces.IToolAction[] = [
|
|
47
62
|
{
|
|
48
63
|
name: 'read',
|
|
49
|
-
description: 'Read
|
|
64
|
+
description: 'Read file contents (full or specific line range)',
|
|
50
65
|
parameters: {
|
|
51
66
|
type: 'object',
|
|
52
67
|
properties: {
|
|
53
|
-
path: { type: 'string', description: '
|
|
68
|
+
path: { type: 'string', description: 'Path to the file' },
|
|
54
69
|
encoding: {
|
|
55
70
|
type: 'string',
|
|
56
71
|
enum: ['utf8', 'binary', 'base64'],
|
|
57
72
|
default: 'utf8',
|
|
58
73
|
description: 'File encoding',
|
|
59
74
|
},
|
|
75
|
+
startLine: {
|
|
76
|
+
type: 'number',
|
|
77
|
+
description: 'First line to read (1-indexed, inclusive). If omitted, reads from beginning.',
|
|
78
|
+
},
|
|
79
|
+
endLine: {
|
|
80
|
+
type: 'number',
|
|
81
|
+
description: 'Last line to read (1-indexed, inclusive). If omitted, reads to end.',
|
|
82
|
+
},
|
|
60
83
|
},
|
|
61
84
|
required: ['path'],
|
|
62
85
|
},
|
|
@@ -182,6 +205,55 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
182
205
|
required: ['path'],
|
|
183
206
|
},
|
|
184
207
|
},
|
|
208
|
+
{
|
|
209
|
+
name: 'tree',
|
|
210
|
+
description: 'Show directory structure as a tree (no file contents)',
|
|
211
|
+
parameters: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
properties: {
|
|
214
|
+
path: { type: 'string', description: 'Root directory path' },
|
|
215
|
+
maxDepth: {
|
|
216
|
+
type: 'number',
|
|
217
|
+
default: 3,
|
|
218
|
+
description: 'Maximum depth to traverse (default: 3)',
|
|
219
|
+
},
|
|
220
|
+
filter: {
|
|
221
|
+
type: 'string',
|
|
222
|
+
description: 'Glob pattern to filter files (e.g., "*.ts")',
|
|
223
|
+
},
|
|
224
|
+
showSizes: {
|
|
225
|
+
type: 'boolean',
|
|
226
|
+
default: false,
|
|
227
|
+
description: 'Include file sizes in output',
|
|
228
|
+
},
|
|
229
|
+
format: {
|
|
230
|
+
type: 'string',
|
|
231
|
+
enum: ['string', 'json'],
|
|
232
|
+
default: 'string',
|
|
233
|
+
description: 'Output format: "string" for human-readable tree, "json" for structured array',
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
required: ['path'],
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: 'glob',
|
|
241
|
+
description: 'Find files matching a glob pattern',
|
|
242
|
+
parameters: {
|
|
243
|
+
type: 'object',
|
|
244
|
+
properties: {
|
|
245
|
+
pattern: {
|
|
246
|
+
type: 'string',
|
|
247
|
+
description: 'Glob pattern (e.g., "**/*.ts", "src/**/*.js")',
|
|
248
|
+
},
|
|
249
|
+
path: {
|
|
250
|
+
type: 'string',
|
|
251
|
+
description: 'Base path to search from (defaults to current directory)',
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
required: ['pattern'],
|
|
255
|
+
},
|
|
256
|
+
},
|
|
185
257
|
];
|
|
186
258
|
|
|
187
259
|
private smartfs!: plugins.smartfs.SmartFs;
|
|
@@ -207,16 +279,61 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
207
279
|
case 'read': {
|
|
208
280
|
const validatedPath = this.validatePath(params.path as string);
|
|
209
281
|
const encoding = (params.encoding as string) || 'utf8';
|
|
210
|
-
const
|
|
282
|
+
const startLine = params.startLine as number | undefined;
|
|
283
|
+
const endLine = params.endLine as number | undefined;
|
|
284
|
+
|
|
285
|
+
const fullContent = await this.smartfs
|
|
211
286
|
.file(validatedPath)
|
|
212
287
|
.encoding(encoding as 'utf8' | 'binary' | 'base64')
|
|
213
288
|
.read();
|
|
289
|
+
|
|
290
|
+
const contentStr = fullContent.toString();
|
|
291
|
+
const lines = contentStr.split('\n');
|
|
292
|
+
const totalLines = lines.length;
|
|
293
|
+
|
|
294
|
+
// Apply line range if specified
|
|
295
|
+
let resultContent: string;
|
|
296
|
+
let resultStartLine = 1;
|
|
297
|
+
let resultEndLine = totalLines;
|
|
298
|
+
|
|
299
|
+
if (startLine !== undefined || endLine !== undefined) {
|
|
300
|
+
const start = Math.max(1, startLine ?? 1);
|
|
301
|
+
const end = Math.min(totalLines, endLine ?? totalLines);
|
|
302
|
+
resultStartLine = start;
|
|
303
|
+
resultEndLine = end;
|
|
304
|
+
|
|
305
|
+
// Convert to 0-indexed for array slicing
|
|
306
|
+
const selectedLines = lines.slice(start - 1, end);
|
|
307
|
+
|
|
308
|
+
// Add line numbers to output for context
|
|
309
|
+
resultContent = selectedLines
|
|
310
|
+
.map((line, idx) => `${String(start + idx).padStart(5)}│ ${line}`)
|
|
311
|
+
.join('\n');
|
|
312
|
+
} else {
|
|
313
|
+
// No range specified - return full content but warn if large
|
|
314
|
+
const MAX_LINES_WITHOUT_RANGE = 500;
|
|
315
|
+
if (totalLines > MAX_LINES_WITHOUT_RANGE) {
|
|
316
|
+
// Return first portion with warning
|
|
317
|
+
const selectedLines = lines.slice(0, MAX_LINES_WITHOUT_RANGE);
|
|
318
|
+
resultContent = selectedLines
|
|
319
|
+
.map((line, idx) => `${String(idx + 1).padStart(5)}│ ${line}`)
|
|
320
|
+
.join('\n');
|
|
321
|
+
resultContent += `\n\n[... ${totalLines - MAX_LINES_WITHOUT_RANGE} more lines. Use startLine/endLine to read specific ranges.]`;
|
|
322
|
+
resultEndLine = MAX_LINES_WITHOUT_RANGE;
|
|
323
|
+
} else {
|
|
324
|
+
resultContent = contentStr;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
214
328
|
return {
|
|
215
329
|
success: true,
|
|
216
330
|
result: {
|
|
217
331
|
path: params.path,
|
|
218
|
-
content:
|
|
332
|
+
content: resultContent,
|
|
219
333
|
encoding,
|
|
334
|
+
totalLines,
|
|
335
|
+
startLine: resultStartLine,
|
|
336
|
+
endLine: resultEndLine,
|
|
220
337
|
},
|
|
221
338
|
};
|
|
222
339
|
}
|
|
@@ -259,7 +376,16 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
259
376
|
if (params.filter) {
|
|
260
377
|
dir = dir.filter(params.filter as string);
|
|
261
378
|
}
|
|
262
|
-
|
|
379
|
+
let entries = await dir.list();
|
|
380
|
+
|
|
381
|
+
// Filter out excluded paths
|
|
382
|
+
if (this.excludePatterns.length > 0) {
|
|
383
|
+
entries = entries.filter(entry => {
|
|
384
|
+
const relativePath = plugins.path.relative(validatedPath, entry.path);
|
|
385
|
+
return !this.isExcluded(relativePath) && !this.isExcluded(entry.name);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
263
389
|
return {
|
|
264
390
|
success: true,
|
|
265
391
|
result: {
|
|
@@ -364,6 +490,168 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
364
490
|
};
|
|
365
491
|
}
|
|
366
492
|
|
|
493
|
+
case 'tree': {
|
|
494
|
+
const validatedPath = this.validatePath(params.path as string);
|
|
495
|
+
const maxDepth = (params.maxDepth as number) ?? 3;
|
|
496
|
+
const filter = params.filter as string | undefined;
|
|
497
|
+
const showSizes = (params.showSizes as boolean) ?? false;
|
|
498
|
+
const format = (params.format as 'string' | 'json') ?? 'string';
|
|
499
|
+
|
|
500
|
+
// Collect all entries recursively up to maxDepth
|
|
501
|
+
interface ITreeEntry {
|
|
502
|
+
path: string;
|
|
503
|
+
relativePath: string;
|
|
504
|
+
isDir: boolean;
|
|
505
|
+
depth: number;
|
|
506
|
+
size?: number;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const entries: ITreeEntry[] = [];
|
|
510
|
+
|
|
511
|
+
const collectEntries = async (dirPath: string, depth: number, relativePath: string) => {
|
|
512
|
+
if (depth > maxDepth) return;
|
|
513
|
+
|
|
514
|
+
let dir = this.smartfs.directory(dirPath);
|
|
515
|
+
if (filter) {
|
|
516
|
+
dir = dir.filter(filter);
|
|
517
|
+
}
|
|
518
|
+
const items = await dir.list();
|
|
519
|
+
|
|
520
|
+
for (const item of items) {
|
|
521
|
+
// item is IDirectoryEntry with name, path, isFile, isDirectory properties
|
|
522
|
+
const itemPath = item.path;
|
|
523
|
+
const itemRelPath = relativePath ? `${relativePath}/${item.name}` : item.name;
|
|
524
|
+
const isDir = item.isDirectory;
|
|
525
|
+
|
|
526
|
+
// Skip excluded paths
|
|
527
|
+
if (this.isExcluded(itemRelPath) || this.isExcluded(item.name)) {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const entry: ITreeEntry = {
|
|
532
|
+
path: itemPath,
|
|
533
|
+
relativePath: itemRelPath,
|
|
534
|
+
isDir,
|
|
535
|
+
depth,
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
if (showSizes && !isDir && item.stats) {
|
|
539
|
+
entry.size = item.stats.size;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
entries.push(entry);
|
|
543
|
+
|
|
544
|
+
// Recurse into directories
|
|
545
|
+
if (isDir && depth < maxDepth) {
|
|
546
|
+
await collectEntries(itemPath, depth + 1, itemRelPath);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
await collectEntries(validatedPath, 0, '');
|
|
552
|
+
|
|
553
|
+
// Sort entries by path for consistent output
|
|
554
|
+
entries.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
555
|
+
|
|
556
|
+
if (format === 'json') {
|
|
557
|
+
return {
|
|
558
|
+
success: true,
|
|
559
|
+
result: {
|
|
560
|
+
path: params.path,
|
|
561
|
+
entries: entries.map((e) => ({
|
|
562
|
+
path: e.relativePath,
|
|
563
|
+
isDir: e.isDir,
|
|
564
|
+
depth: e.depth,
|
|
565
|
+
...(e.size !== undefined ? { size: e.size } : {}),
|
|
566
|
+
})),
|
|
567
|
+
count: entries.length,
|
|
568
|
+
},
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Format as string tree
|
|
573
|
+
const formatSize = (bytes: number): string => {
|
|
574
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
575
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
576
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
// Build tree string with proper indentation
|
|
580
|
+
let treeStr = `${params.path}/\n`;
|
|
581
|
+
const pathParts = new Map<string, number>(); // Track which paths are last in their parent
|
|
582
|
+
|
|
583
|
+
// Group by parent to determine last child
|
|
584
|
+
const parentChildCount = new Map<string, number>();
|
|
585
|
+
const parentCurrentChild = new Map<string, number>();
|
|
586
|
+
|
|
587
|
+
for (const entry of entries) {
|
|
588
|
+
const parentPath = entry.relativePath.includes('/')
|
|
589
|
+
? entry.relativePath.substring(0, entry.relativePath.lastIndexOf('/'))
|
|
590
|
+
: '';
|
|
591
|
+
parentChildCount.set(parentPath, (parentChildCount.get(parentPath) || 0) + 1);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
for (const entry of entries) {
|
|
595
|
+
const parentPath = entry.relativePath.includes('/')
|
|
596
|
+
? entry.relativePath.substring(0, entry.relativePath.lastIndexOf('/'))
|
|
597
|
+
: '';
|
|
598
|
+
parentCurrentChild.set(parentPath, (parentCurrentChild.get(parentPath) || 0) + 1);
|
|
599
|
+
const isLast = parentCurrentChild.get(parentPath) === parentChildCount.get(parentPath);
|
|
600
|
+
|
|
601
|
+
// Build prefix based on depth
|
|
602
|
+
let prefix = '';
|
|
603
|
+
const parts = entry.relativePath.split('/');
|
|
604
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
605
|
+
prefix += '│ ';
|
|
606
|
+
}
|
|
607
|
+
prefix += isLast ? '└── ' : '├── ';
|
|
608
|
+
|
|
609
|
+
const name = parts[parts.length - 1];
|
|
610
|
+
const suffix = entry.isDir ? '/' : '';
|
|
611
|
+
const sizeStr = showSizes && entry.size !== undefined ? ` (${formatSize(entry.size)})` : '';
|
|
612
|
+
|
|
613
|
+
treeStr += `${prefix}${name}${suffix}${sizeStr}\n`;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return {
|
|
617
|
+
success: true,
|
|
618
|
+
result: {
|
|
619
|
+
path: params.path,
|
|
620
|
+
tree: treeStr,
|
|
621
|
+
count: entries.length,
|
|
622
|
+
},
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
case 'glob': {
|
|
627
|
+
const pattern = params.pattern as string;
|
|
628
|
+
const basePath = params.path ? this.validatePath(params.path as string) : (this.basePath || process.cwd());
|
|
629
|
+
|
|
630
|
+
// Use smartfs to list with filter
|
|
631
|
+
const dir = this.smartfs.directory(basePath).recursive().filter(pattern);
|
|
632
|
+
const matches = await dir.list();
|
|
633
|
+
|
|
634
|
+
// Return file paths relative to base path for readability
|
|
635
|
+
// Filter out excluded paths
|
|
636
|
+
const files = matches
|
|
637
|
+
.map((entry) => ({
|
|
638
|
+
path: entry.path,
|
|
639
|
+
relativePath: plugins.path.relative(basePath, entry.path),
|
|
640
|
+
isDirectory: entry.isDirectory,
|
|
641
|
+
}))
|
|
642
|
+
.filter((file) => !this.isExcluded(file.relativePath));
|
|
643
|
+
|
|
644
|
+
return {
|
|
645
|
+
success: true,
|
|
646
|
+
result: {
|
|
647
|
+
pattern,
|
|
648
|
+
basePath,
|
|
649
|
+
files,
|
|
650
|
+
count: files.length,
|
|
651
|
+
},
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
367
655
|
default:
|
|
368
656
|
return {
|
|
369
657
|
success: false,
|
|
@@ -380,8 +668,12 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
380
668
|
|
|
381
669
|
public getCallSummary(action: string, params: Record<string, unknown>): string {
|
|
382
670
|
switch (action) {
|
|
383
|
-
case 'read':
|
|
384
|
-
|
|
671
|
+
case 'read': {
|
|
672
|
+
const lineRange = params.startLine || params.endLine
|
|
673
|
+
? ` lines ${params.startLine || 1}-${params.endLine || 'end'}`
|
|
674
|
+
: '';
|
|
675
|
+
return `Read file "${params.path}"${lineRange}`;
|
|
676
|
+
}
|
|
385
677
|
|
|
386
678
|
case 'write': {
|
|
387
679
|
const content = params.content as string;
|
|
@@ -416,6 +708,12 @@ export class FilesystemTool extends BaseToolWrapper {
|
|
|
416
708
|
case 'mkdir':
|
|
417
709
|
return `Create directory "${params.path}"${params.recursive !== false ? ' (with parents)' : ''}`;
|
|
418
710
|
|
|
711
|
+
case 'tree':
|
|
712
|
+
return `Show tree of "${params.path}" (depth: ${params.maxDepth ?? 3}, format: ${params.format ?? 'string'})`;
|
|
713
|
+
|
|
714
|
+
case 'glob':
|
|
715
|
+
return `Find files matching "${params.pattern}"${params.path ? ` in "${params.path}"` : ''}`;
|
|
716
|
+
|
|
419
717
|
default:
|
|
420
718
|
return `Unknown action: ${action}`;
|
|
421
719
|
}
|