improve tools
This commit is contained in:
@@ -2,6 +2,14 @@ import * as plugins from './plugins.js';
|
||||
import * as interfaces from './smartagent.interfaces.js';
|
||||
import { BaseToolWrapper } from './smartagent.tools.base.js';
|
||||
|
||||
/**
|
||||
* Options for FilesystemTool
|
||||
*/
|
||||
export interface IFilesystemToolOptions {
|
||||
/** Base path to scope all operations to. If set, all paths must be within this directory. */
|
||||
basePath?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filesystem tool for file and directory operations
|
||||
* Wraps @push.rocks/smartfs
|
||||
@@ -10,6 +18,31 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
public name = 'filesystem';
|
||||
public description = 'Read, write, list, and delete files and directories';
|
||||
|
||||
/** Base path to scope all operations to */
|
||||
private basePath?: string;
|
||||
|
||||
constructor(options?: IFilesystemToolOptions) {
|
||||
super();
|
||||
if (options?.basePath) {
|
||||
this.basePath = plugins.path.resolve(options.basePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a path is within the allowed base path
|
||||
* @throws Error if path is outside allowed directory
|
||||
*/
|
||||
private validatePath(pathArg: string): string {
|
||||
const resolved = plugins.path.resolve(pathArg);
|
||||
if (this.basePath) {
|
||||
// Ensure the resolved path starts with the base path
|
||||
if (!resolved.startsWith(this.basePath + plugins.path.sep) && resolved !== this.basePath) {
|
||||
throw new Error(`Access denied: path "${pathArg}" is outside allowed directory "${this.basePath}"`);
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
public actions: interfaces.IToolAction[] = [
|
||||
{
|
||||
name: 'read',
|
||||
@@ -172,9 +205,10 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
try {
|
||||
switch (action) {
|
||||
case 'read': {
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
const encoding = (params.encoding as string) || 'utf8';
|
||||
const content = await this.smartfs
|
||||
.file(params.path as string)
|
||||
.file(validatedPath)
|
||||
.encoding(encoding as 'utf8' | 'binary' | 'base64')
|
||||
.read();
|
||||
return {
|
||||
@@ -188,9 +222,10 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'write': {
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
const encoding = (params.encoding as string) || 'utf8';
|
||||
await this.smartfs
|
||||
.file(params.path as string)
|
||||
.file(validatedPath)
|
||||
.encoding(encoding as 'utf8' | 'binary' | 'base64')
|
||||
.write(params.content as string);
|
||||
return {
|
||||
@@ -204,7 +239,8 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'append': {
|
||||
await this.smartfs.file(params.path as string).append(params.content as string);
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
await this.smartfs.file(validatedPath).append(params.content as string);
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
@@ -215,7 +251,8 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'list': {
|
||||
let dir = this.smartfs.directory(params.path as string);
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
let dir = this.smartfs.directory(validatedPath);
|
||||
if (params.recursive) {
|
||||
dir = dir.recursive();
|
||||
}
|
||||
@@ -234,33 +271,34 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'delete': {
|
||||
const path = params.path as string;
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
// Check if it's a directory or file
|
||||
const exists = await this.smartfs.file(path).exists();
|
||||
const exists = await this.smartfs.file(validatedPath).exists();
|
||||
if (exists) {
|
||||
// Try to get stats to check if it's a directory
|
||||
try {
|
||||
const stats = await this.smartfs.file(path).stat();
|
||||
const stats = await this.smartfs.file(validatedPath).stat();
|
||||
if (stats.isDirectory && params.recursive) {
|
||||
await this.smartfs.directory(path).recursive().delete();
|
||||
await this.smartfs.directory(validatedPath).recursive().delete();
|
||||
} else {
|
||||
await this.smartfs.file(path).delete();
|
||||
await this.smartfs.file(validatedPath).delete();
|
||||
}
|
||||
} catch {
|
||||
await this.smartfs.file(path).delete();
|
||||
await this.smartfs.file(validatedPath).delete();
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
path,
|
||||
path: params.path,
|
||||
deleted: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
case 'exists': {
|
||||
const exists = await this.smartfs.file(params.path as string).exists();
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
const exists = await this.smartfs.file(validatedPath).exists();
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
@@ -271,7 +309,8 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'stat': {
|
||||
const stats = await this.smartfs.file(params.path as string).stat();
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
const stats = await this.smartfs.file(validatedPath).stat();
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
@@ -282,7 +321,9 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'copy': {
|
||||
await this.smartfs.file(params.source as string).copy(params.destination as string);
|
||||
const validatedSource = this.validatePath(params.source as string);
|
||||
const validatedDest = this.validatePath(params.destination as string);
|
||||
await this.smartfs.file(validatedSource).copy(validatedDest);
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
@@ -294,7 +335,9 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'move': {
|
||||
await this.smartfs.file(params.source as string).move(params.destination as string);
|
||||
const validatedSource = this.validatePath(params.source as string);
|
||||
const validatedDest = this.validatePath(params.destination as string);
|
||||
await this.smartfs.file(validatedSource).move(validatedDest);
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
@@ -306,7 +349,8 @@ export class FilesystemTool extends BaseToolWrapper {
|
||||
}
|
||||
|
||||
case 'mkdir': {
|
||||
let dir = this.smartfs.directory(params.path as string);
|
||||
const validatedPath = this.validatePath(params.path as string);
|
||||
let dir = this.smartfs.directory(validatedPath);
|
||||
if (params.recursive !== false) {
|
||||
dir = dir.recursive();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user