feat: 新增 6 个工具并重组目录结构

新增工具:
- grep_content: 在文件内容中搜索文本/正则表达式
- get_file_info: 获取文件元信息(大小、权限、时间等)
- move_file: 移动或重命名文件/目录
- copy_file: 复制文件或目录(支持递归)
- delete_file: 删除文件或目录
- create_directory: 创建目录

目录重组:
- src/tools/shell/ - Shell 相关工具(bash)
- src/tools/filesystem/ - 文件系统工具(12个)
- 每个子目录有独立的 index.ts 导出

权限系统扩展:
- 新增操作类型: grep, info, move, copy, mkdir
- 读取类操作默认允许,写入类操作需要确认
This commit is contained in:
2025-12-10 18:25:02 +08:00
parent 60a046357b
commit e435b2f8f8
23 changed files with 819 additions and 29 deletions
+5
View File
@@ -22,7 +22,12 @@ const DEFAULT_CONFIG: FilePermissionConfig = {
edit: 'ask', // 编辑需要确认
list: 'allow', // 列目录默认允许
search: 'allow', // 搜索默认允许
grep: 'allow', // 内容搜索默认允许
info: 'allow', // 获取文件信息默认允许
move: 'ask', // 移动需要确认
copy: 'ask', // 复制需要确认
delete: 'ask', // 删除需要确认
mkdir: 'ask', // 创建目录需要确认
},
sensitivePaths: [
// 系统关键路径 - 拒绝
+17 -1
View File
@@ -26,7 +26,18 @@ export interface PermissionContext {
}
// 文件操作类型
export type FileOperation = 'read' | 'write' | 'edit' | 'list' | 'search' | 'delete';
export type FileOperation =
| 'read' // 读取文件
| 'write' // 写入文件
| 'edit' // 编辑文件
| 'list' // 列出目录
| 'search' // 搜索文件
| 'grep' // 搜索内容
| 'info' // 获取文件信息
| 'move' // 移动/重命名
| 'copy' // 复制
| 'delete' // 删除
| 'mkdir'; // 创建目录
// 文件权限请求上下文
export interface FilePermissionContext {
@@ -46,7 +57,12 @@ export interface FilePermissionConfig {
edit: PermissionAction;
list: PermissionAction;
search: PermissionAction;
grep: PermissionAction;
info: PermissionAction;
move: PermissionAction;
copy: PermissionAction;
delete: PermissionAction;
mkdir: PermissionAction;
};
// 敏感路径规则(优先于操作默认策略)
sensitivePaths: {
+1
View File
@@ -0,0 +1 @@
复制文件或目录。支持递归复制整个目录结构。
@@ -0,0 +1 @@
创建新目录。支持递归创建父目录。如果目录已存在则不会报错。
+1
View File
@@ -0,0 +1 @@
删除文件或目录。删除目录时可以选择是否递归删除。需要谨慎使用。
+1
View File
@@ -0,0 +1 @@
获取文件或目录的详细信息,包括大小、权限、创建时间、修改时间等元数据。
+1
View File
@@ -0,0 +1 @@
在指定目录中搜索文件内容。支持正则表达式,可以指定文件类型过滤。用于查找代码中的特定文本、函数调用、变量引用等。
+1
View File
@@ -0,0 +1 @@
移动或重命名文件/目录。可以将文件移动到新位置或更改文件名。
+132
View File
@@ -0,0 +1,132 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
async function copyRecursive(source: string, dest: string): Promise<void> {
const stats = await fs.stat(source);
if (stats.isDirectory()) {
await fs.mkdir(dest, { recursive: true });
const entries = await fs.readdir(source);
for (const entry of entries) {
await copyRecursive(path.join(source, entry), path.join(dest, entry));
}
} else {
await fs.copyFile(source, dest);
}
}
export const copyFileTool: Tool = {
name: 'copy_file',
description: loadDescription('copy_file'),
parameters: {
source: {
type: 'string',
description: '源文件或目录的路径',
required: true,
},
destination: {
type: 'string',
description: '目标路径',
required: true,
},
},
execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
const source = params.source as string;
const destination = params.destination as string;
const cwd = process.cwd();
const absoluteSource = path.isAbsolute(source)
? source
: path.join(cwd, source);
const absoluteDest = path.isAbsolute(destination)
? destination
: path.join(cwd, destination);
// 权限检查 - 源文件需要 read 权限
const permissionManager = getPermissionManager();
const sourcePermResult = await permissionManager.checkFilePermission({
operation: 'read',
path: absoluteSource,
workdir: cwd,
});
if (!sourcePermResult.allowed) {
if (sourcePermResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 读取 ${absoluteSource}\n原因: ${sourcePermResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${sourcePermResult.reason || '不允许读取此文件'}`,
};
}
// 权限检查 - 目标位置需要 copy 权限
const destPermResult = await permissionManager.checkFilePermission({
operation: 'copy',
path: absoluteDest,
workdir: cwd,
});
if (!destPermResult.allowed) {
if (destPermResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 复制到 ${absoluteDest}\n原因: ${destPermResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${destPermResult.reason || '不允许复制到此位置'}`,
};
}
try {
// 检查源文件是否存在
const sourceStats = await fs.stat(absoluteSource);
// 检查目标是否是目录
let finalDest = absoluteDest;
try {
const destStats = await fs.stat(absoluteDest);
if (destStats.isDirectory()) {
// 如果目标是目录,将源文件复制到该目录下
finalDest = path.join(absoluteDest, path.basename(absoluteSource));
}
} catch {
// 目标不存在,直接使用目标路径
}
// 确保目标目录存在
await fs.mkdir(path.dirname(finalDest), { recursive: true });
// 执行复制
if (sourceStats.isDirectory()) {
await copyRecursive(absoluteSource, finalDest);
} else {
await fs.copyFile(absoluteSource, finalDest);
}
return {
success: true,
output: `已复制: ${absoluteSource} -> ${finalDest}`,
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
+83
View File
@@ -0,0 +1,83 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const createDirectoryTool: Tool = {
name: 'create_directory',
description: loadDescription('create_directory'),
parameters: {
path: {
type: 'string',
description: '要创建的目录路径',
required: true,
},
},
execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
const dirPath = params.path as string;
const cwd = process.cwd();
const absolutePath = path.isAbsolute(dirPath)
? dirPath
: path.join(cwd, dirPath);
// 权限检查
const permissionManager = getPermissionManager();
const permResult = await permissionManager.checkFilePermission({
operation: 'mkdir',
path: absolutePath,
workdir: cwd,
});
if (!permResult.allowed) {
if (permResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 创建目录 ${absolutePath}\n原因: ${permResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${permResult.reason || '不允许创建此目录'}`,
};
}
try {
// 检查目录是否已存在
try {
const stats = await fs.stat(absolutePath);
if (stats.isDirectory()) {
return {
success: true,
output: `目录已存在: ${absolutePath}`,
};
} else {
return {
success: false,
output: '',
error: `路径已存在且不是目录: ${absolutePath}`,
};
}
} catch {
// 目录不存在,继续创建
}
// 创建目录(递归创建父目录)
await fs.mkdir(absolutePath, { recursive: true });
return {
success: true,
output: `已创建目录: ${absolutePath}`,
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
+91
View File
@@ -0,0 +1,91 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const deleteFileTool: Tool = {
name: 'delete_file',
description: loadDescription('delete_file'),
parameters: {
path: {
type: 'string',
description: '要删除的文件或目录的路径',
required: true,
},
recursive: {
type: 'boolean',
description: '是否递归删除目录(默认 false',
required: false,
},
},
execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
const filePath = params.path as string;
const recursive = (params.recursive as boolean) || false;
const cwd = process.cwd();
const absolutePath = path.isAbsolute(filePath)
? filePath
: path.join(cwd, filePath);
// 权限检查
const permissionManager = getPermissionManager();
const permResult = await permissionManager.checkFilePermission({
operation: 'delete',
path: absolutePath,
workdir: cwd,
});
if (!permResult.allowed) {
if (permResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 删除 ${absolutePath}\n原因: ${permResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${permResult.reason || '不允许删除此文件'}`,
};
}
try {
const stats = await fs.stat(absolutePath);
if (stats.isDirectory()) {
if (!recursive) {
// 检查目录是否为空
const entries = await fs.readdir(absolutePath);
if (entries.length > 0) {
return {
success: false,
output: '',
error: `目录不为空。如需删除非空目录,请设置 recursive: true`,
};
}
await fs.rmdir(absolutePath);
} else {
await fs.rm(absolutePath, { recursive: true });
}
return {
success: true,
output: `已删除目录: ${absolutePath}`,
};
} else {
await fs.unlink(absolutePath);
return {
success: true,
output: `已删除文件: ${absolutePath}`,
};
}
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
@@ -1,8 +1,8 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../types/index.js';
import { loadDescription } from './load_description.js';
import { getPermissionManager } from '../permission/index.js';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const editFileTool: Tool = {
name: 'edit_file',
+134
View File
@@ -0,0 +1,134 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
function formatSize(bytes: number): string {
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let unitIndex = 0;
let size = bytes;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}
function formatPermissions(mode: number): string {
const types: Record<number, string> = {
0o140000: 'socket',
0o120000: 'symbolic link',
0o100000: 'regular file',
0o060000: 'block device',
0o040000: 'directory',
0o020000: 'character device',
0o010000: 'FIFO',
};
const fileType = Object.entries(types).find(([mask]) => (mode & 0o170000) === Number(mask));
const perms = [
(mode & 0o400) ? 'r' : '-',
(mode & 0o200) ? 'w' : '-',
(mode & 0o100) ? 'x' : '-',
(mode & 0o040) ? 'r' : '-',
(mode & 0o020) ? 'w' : '-',
(mode & 0o010) ? 'x' : '-',
(mode & 0o004) ? 'r' : '-',
(mode & 0o002) ? 'w' : '-',
(mode & 0o001) ? 'x' : '-',
].join('');
return `${fileType?.[1] || 'unknown'} (${perms})`;
}
export const getFileInfoTool: Tool = {
name: 'get_file_info',
description: loadDescription('get_file_info'),
parameters: {
path: {
type: 'string',
description: '文件或目录的路径',
required: true,
},
},
execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
const filePath = params.path as string;
const cwd = process.cwd();
const absolutePath = path.isAbsolute(filePath)
? filePath
: path.join(cwd, filePath);
// 权限检查
const permissionManager = getPermissionManager();
const permResult = await permissionManager.checkFilePermission({
operation: 'info',
path: absolutePath,
workdir: cwd,
});
if (!permResult.allowed) {
if (permResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 获取文件信息 ${absolutePath}\n原因: ${permResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${permResult.reason || '不允许获取此文件信息'}`,
};
}
try {
const stats = await fs.stat(absolutePath);
const info = [
`路径: ${absolutePath}`,
`类型: ${stats.isDirectory() ? '目录' : stats.isFile() ? '文件' : stats.isSymbolicLink() ? '符号链接' : '其他'}`,
`大小: ${formatSize(stats.size)}`,
`权限: ${formatPermissions(stats.mode)}`,
`创建时间: ${stats.birthtime.toLocaleString()}`,
`修改时间: ${stats.mtime.toLocaleString()}`,
`访问时间: ${stats.atime.toLocaleString()}`,
`inode: ${stats.ino}`,
`硬链接数: ${stats.nlink}`,
];
// 如果是符号链接,显示目标
if (stats.isSymbolicLink()) {
try {
const target = await fs.readlink(absolutePath);
info.push(`链接目标: ${target}`);
} catch {
// 忽略
}
}
// 如果是目录,统计子项数量
if (stats.isDirectory()) {
try {
const entries = await fs.readdir(absolutePath);
info.push(`子项数量: ${entries.length}`);
} catch {
// 忽略
}
}
return {
success: true,
output: info.join('\n'),
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
+159
View File
@@ -0,0 +1,159 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
interface GrepMatch {
file: string;
line: number;
content: string;
}
export const grepContentTool: Tool = {
name: 'grep_content',
description: loadDescription('grep_content'),
parameters: {
directory: {
type: 'string',
description: '搜索的起始目录',
required: true,
},
pattern: {
type: 'string',
description: '搜索的文本或正则表达式模式',
required: true,
},
file_pattern: {
type: 'string',
description: '文件名匹配模式(可选,如 *.ts)',
required: false,
},
max_results: {
type: 'number',
description: '最大结果数量(可选,默认 100)',
required: false,
},
},
execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
const directory = params.directory as string;
const pattern = params.pattern as string;
const filePattern = params.file_pattern as string | undefined;
const maxResults = (params.max_results as number) || 100;
const cwd = process.cwd();
const absolutePath = path.isAbsolute(directory)
? directory
: path.join(cwd, directory);
// 权限检查
const permissionManager = getPermissionManager();
const permResult = await permissionManager.checkFilePermission({
operation: 'grep',
path: absolutePath,
workdir: cwd,
});
if (!permResult.allowed) {
if (permResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 搜索目录 ${absolutePath}\n原因: ${permResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${permResult.reason || '不允许搜索此目录'}`,
};
}
const matches: GrepMatch[] = [];
const searchRegex = new RegExp(pattern, 'gi');
const fileRegex = filePattern
? new RegExp(filePattern.replace(/\*/g, '.*').replace(/\?/g, '.'), 'i')
: null;
async function searchFile(filePath: string): Promise<void> {
if (matches.length >= maxResults) return;
try {
const content = await fs.readFile(filePath, 'utf-8');
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
if (matches.length >= maxResults) break;
if (searchRegex.test(lines[i])) {
matches.push({
file: filePath,
line: i + 1,
content: lines[i].trim().substring(0, 200), // 截断过长的行
});
}
// 重置正则表达式的 lastIndex
searchRegex.lastIndex = 0;
}
} catch {
// 忽略无法读取的文件(如二进制文件)
}
}
async function searchDirectory(dir: string, depth = 0): Promise<void> {
if (depth > 10 || matches.length >= maxResults) return;
try {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (matches.length >= maxResults) break;
const fullPath = path.join(dir, entry.name);
// 跳过隐藏文件和 node_modules
if (entry.name.startsWith('.') || entry.name === 'node_modules') {
continue;
}
if (entry.isDirectory()) {
await searchDirectory(fullPath, depth + 1);
} else if (entry.isFile()) {
// 检查文件名是否匹配
if (fileRegex && !fileRegex.test(entry.name)) {
continue;
}
await searchFile(fullPath);
}
}
} catch {
// 忽略权限错误
}
}
try {
await searchDirectory(absolutePath);
if (matches.length === 0) {
return {
success: true,
output: '没有找到匹配的内容',
};
}
const output = matches
.map((m) => `${m.file}:${m.line}: ${m.content}`)
.join('\n');
return {
success: true,
output: `找到 ${matches.length} 处匹配${matches.length >= maxResults ? '(已达上限)' : ''}:\n\n${output}`,
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
+20
View File
@@ -0,0 +1,20 @@
// 文件读写
export { readFileTool } from './read_file.js';
export { writeFileTool } from './write_file.js';
export { editFileTool } from './edit_file.js';
// 目录操作
export { listDirTool } from './list_directory.js';
export { createDirectoryTool } from './create_directory.js';
// 搜索
export { searchFilesTool } from './search_files.js';
export { grepContentTool } from './grep_content.js';
// 文件信息
export { getFileInfoTool } from './get_file_info.js';
// 文件管理
export { moveFileTool } from './move_file.js';
export { copyFileTool } from './copy_file.js';
export { deleteFileTool } from './delete_file.js';
@@ -1,8 +1,8 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../types/index.js';
import { loadDescription } from './load_description.js';
import { getPermissionManager } from '../permission/index.js';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const listDirTool: Tool = {
name: 'list_directory',
+114
View File
@@ -0,0 +1,114 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const moveFileTool: Tool = {
name: 'move_file',
description: loadDescription('move_file'),
parameters: {
source: {
type: 'string',
description: '源文件或目录的路径',
required: true,
},
destination: {
type: 'string',
description: '目标路径',
required: true,
},
},
execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
const source = params.source as string;
const destination = params.destination as string;
const cwd = process.cwd();
const absoluteSource = path.isAbsolute(source)
? source
: path.join(cwd, source);
const absoluteDest = path.isAbsolute(destination)
? destination
: path.join(cwd, destination);
// 权限检查 - 源文件需要 move 权限
const permissionManager = getPermissionManager();
const sourcePermResult = await permissionManager.checkFilePermission({
operation: 'move',
path: absoluteSource,
workdir: cwd,
});
if (!sourcePermResult.allowed) {
if (sourcePermResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 移动 ${absoluteSource}\n原因: ${sourcePermResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${sourcePermResult.reason || '不允许移动此文件'}`,
};
}
// 权限检查 - 目标位置需要 write 权限
const destPermResult = await permissionManager.checkFilePermission({
operation: 'write',
path: absoluteDest,
workdir: cwd,
});
if (!destPermResult.allowed) {
if (destPermResult.needsConfirmation) {
return {
success: false,
output: '',
error: `需要用户确认: 写入到 ${absoluteDest}\n原因: ${destPermResult.reason || '需要权限确认'}`,
};
}
return {
success: false,
output: '',
error: `权限被拒绝: ${destPermResult.reason || '不允许写入到此位置'}`,
};
}
try {
// 检查源文件是否存在
await fs.access(absoluteSource);
// 检查目标是否是目录
let finalDest = absoluteDest;
try {
const destStats = await fs.stat(absoluteDest);
if (destStats.isDirectory()) {
// 如果目标是目录,将源文件移动到该目录下
finalDest = path.join(absoluteDest, path.basename(absoluteSource));
}
} catch {
// 目标不存在,直接使用目标路径
}
// 确保目标目录存在
await fs.mkdir(path.dirname(finalDest), { recursive: true });
// 执行移动
await fs.rename(absoluteSource, finalDest);
return {
success: true,
output: `已移动: ${absoluteSource} -> ${finalDest}`,
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
@@ -1,8 +1,8 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../types/index.js';
import { loadDescription } from './load_description.js';
import { getPermissionManager } from '../permission/index.js';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const readFileTool: Tool = {
name: 'read_file',
@@ -1,8 +1,8 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../types/index.js';
import { loadDescription } from './load_description.js';
import { getPermissionManager } from '../permission/index.js';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const searchFilesTool: Tool = {
name: 'search_files',
@@ -1,8 +1,8 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import type { Tool, ToolResult } from '../types/index.js';
import { loadDescription } from './load_description.js';
import { getPermissionManager } from '../permission/index.js';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
export const writeFileTool: Tool = {
name: 'write_file',
+39 -10
View File
@@ -1,18 +1,47 @@
import type { Tool } from '../types/index.js';
import { bashTool } from './bash.js';
import { readFileTool } from './read_file.js';
import { writeFileTool } from './write_file.js';
import { editFileTool } from './edit_file.js';
import { listDirTool } from './list_directory.js';
import { searchFilesTool } from './search_files.js';
// 所有可用工具的注册中心
// 添加新工具只需在此数组中添加一行
export const allTools: Tool[] = [
bashTool,
// Shell 工具
import { bashTool } from './shell/index.js';
// 文件系统工具
import {
readFileTool,
writeFileTool,
editFileTool,
listDirTool,
createDirectoryTool,
searchFilesTool,
grepContentTool,
getFileInfoTool,
moveFileTool,
copyFileTool,
deleteFileTool,
} from './filesystem/index.js';
// 所有可用工具的注册中心
// 添加新工具只需在此数组中添加一行
export const allTools: Tool[] = [
// Shell
bashTool,
// 文件读写
readFileTool,
writeFileTool,
editFileTool,
// 目录操作
listDirTool,
createDirectoryTool,
// 搜索
searchFilesTool,
grepContentTool,
// 文件信息
getFileInfoTool,
// 文件管理
moveFileTool,
copyFileTool,
deleteFileTool,
];
@@ -1,8 +1,8 @@
import { exec } from 'child_process';
import { promisify } from 'util';
import type { Tool, ToolResult } from '../types/index.js';
import { loadDescription } from './load_description.js';
import { getPermissionManager } from '../permission/index.js';
import type { Tool, ToolResult } from '../../types/index.js';
import { loadDescription } from '../load_description.js';
import { getPermissionManager } from '../../permission/index.js';
const execAsync = promisify(exec);
+1
View File
@@ -0,0 +1 @@
export { bashTool } from './bash.js';