diff --git a/docs/delete-file-confirmation.md b/docs/delete-file-confirmation.md new file mode 100644 index 0000000..fee6df0 --- /dev/null +++ b/docs/delete-file-confirmation.md @@ -0,0 +1,294 @@ +# 删除文件确认功能实现文档 + +## 1. 功能概述 + +在 AI 返回删除文件命令时,前端拦截并弹出确认对话框,用户确认后才执行删除操作。 + +## 2. 架构设计 + +### 2.1 消息流程 + +``` +AI 后端 → 删除文件工具调用 → 前端拦截 → 用户确认对话框 + ↓ + 确定/取消 + ↓ + 执行删除/返回取消结果 + ↓ + 返回 TOOL_EXECUTION_RESULT + ↓ + AI 后端 +``` + +### 2.2 关键原则 + +**前端必须返回结果**:无论用户选择什么,前端都必须向后端返回 `TOOL_EXECUTION_RESULT`,否则后端会等待超时。 + +## 3. 实现方案 + +### 3.1 修改位置 + +文件:`src/utils/messageHandler.ts` + +在处理工具调用的函数中,找到删除文件的工具处理逻辑。 + +### 3.2 核心代码实现 + +```typescript +/** + * 处理删除文件工具调用(带用户确认) + */ +async function handleDeleteFileTool( + toolCall: any, + panel: vscode.WebviewPanel +): Promise { + const filePath = toolCall.arguments.filePath; // 根据实际参数名调整 + + // 弹出确认对话框 + const confirmed = await vscode.window.showWarningMessage( + `确定要删除文件吗?\n\n${filePath}`, + { + modal: true, // 模态对话框,阻止其他操作 + detail: '此操作不可撤销' + }, + '确定删除', + '取消' + ); + + // 用户确认删除 + if (confirmed === '确定删除') { + try { + // 执行删除操作 + const uri = vscode.Uri.file(filePath); + await vscode.workspace.fs.delete(uri, { + recursive: false, // 如果是目录需要设置为 true + useTrash: true // 移到回收站而非永久删除(推荐) + }); + + // 返回成功结果 + return { + type: 'TOOL_EXECUTION_RESULT', + toolCallId: toolCall.id, + result: JSON.stringify({ + success: true, + message: `文件已删除: ${filePath}` + }) + }; + } catch (error) { + // 删除失败 + return { + type: 'TOOL_EXECUTION_RESULT', + toolCallId: toolCall.id, + result: JSON.stringify({ + success: false, + error: `删除失败: ${error.message}` + }) + }; + } + } + + // 用户取消或关闭对话框 + return { + type: 'TOOL_EXECUTION_RESULT', + toolCallId: toolCall.id, + result: JSON.stringify({ + success: false, + message: '用户取消了删除操作' + }) + }; +} +``` + +### 3.3 集成到消息处理流程 + +在 `messageHandler.ts` 的工具调用处理逻辑中: + +```typescript +// 示例:在处理工具调用的地方 +async function handleToolCall(toolCall: any, panel: vscode.WebviewPanel) { + switch (toolCall.name) { + case 'deleteFile': // 根据实际工具名称调整 + return await handleDeleteFileTool(toolCall, panel); + + case 'deleteDirectory': // 如果有删除目录的工具 + return await handleDeleteDirectoryTool(toolCall, panel); + + // ... 其他工具 + } +} +``` + +## 4. 用户体验优化 + +### 4.1 对话框样式 + +```typescript +const confirmed = await vscode.window.showWarningMessage( + `确定要删除文件吗?\n\n📄 ${path.basename(filePath)}\n📁 ${path.dirname(filePath)}`, + { + modal: true, + detail: '⚠️ 文件将被移到回收站,可以恢复' + }, + '确定删除', + '取消' +); +``` + +### 4.2 批量删除优化 + +如果 AI 一次返回多个删除操作: + +```typescript +// 方案 1:逐个确认 +for (const file of filesToDelete) { + await handleDeleteFileTool(file, panel); +} + +// 方案 2:批量确认(推荐) +const confirmed = await vscode.window.showWarningMessage( + `确定要删除以下 ${filesToDelete.length} 个文件吗?\n\n${filesToDelete.join('\n')}`, + { modal: true }, + '全部删除', + '取消' +); +``` + +## 5. 安全考虑 + +### 5.1 使用回收站 + +```typescript +await vscode.workspace.fs.delete(uri, { + useTrash: true // 移到回收站,可恢复 +}); +``` + +### 5.2 路径验证 + +```typescript +// 防止删除工作区外的文件 +const workspaceFolders = vscode.workspace.workspaceFolders; +if (!workspaceFolders) { + return { success: false, error: '未打开工作区' }; +} + +const isInWorkspace = workspaceFolders.some(folder => + filePath.startsWith(folder.uri.fsPath) +); + +if (!isInWorkspace) { + return { success: false, error: '只能删除工作区内的文件' }; +} +``` + +### 5.3 敏感文件保护 + +```typescript +const protectedFiles = [ + 'package.json', + 'tsconfig.json', + '.git', + 'node_modules' +]; + +const fileName = path.basename(filePath); +if (protectedFiles.includes(fileName)) { + vscode.window.showErrorMessage(`不允许删除系统文件: ${fileName}`); + return { success: false, error: '受保护的文件' }; +} +``` + +## 6. 错误处理 + +### 6.1 常见错误 + +```typescript +try { + await vscode.workspace.fs.delete(uri, { useTrash: true }); +} catch (error) { + if (error.code === 'FileNotFound') { + return { success: false, error: '文件不存在' }; + } + if (error.code === 'NoPermissions') { + return { success: false, error: '没有删除权限' }; + } + return { success: false, error: error.message }; +} +``` + +## 7. 测试场景 + +### 7.1 基本测试 + +- [ ] 用户点击"确定删除" → 文件被删除 +- [ ] 用户点击"取消" → 文件保留,返回取消消息 +- [ ] 用户关闭对话框 → 文件保留,返回取消消息 +- [ ] 文件不存在 → 返回错误消息 +- [ ] 没有删除权限 → 返回错误消息 + +### 7.2 边界测试 + +- [ ] 删除工作区外的文件 → 拒绝 +- [ ] 删除受保护文件 → 拒绝 +- [ ] 批量删除 → 正确处理 +- [ ] 后端收到取消消息后继续对话 → 流程正常 + +## 8. 配置选项(可选) + +可以添加用户设置来控制行为: + +```json +// package.json +"configuration": { + "properties": { + "ic-coder.confirmDelete": { + "type": "boolean", + "default": true, + "description": "删除文件前是否需要确认" + }, + "ic-coder.useTrash": { + "type": "boolean", + "default": true, + "description": "删除文件时移到回收站而非永久删除" + } + } +} +``` + +读取配置: + +```typescript +const config = vscode.workspace.getConfiguration('ic-coder'); +const needConfirm = config.get('confirmDelete', true); +const useTrash = config.get('useTrash', true); + +if (needConfirm) { + // 弹出确认对话框 +} +``` + +## 9. 总结 + +### 9.1 后端是否需要修改? + +**不需要**。后端继续返回删除工具调用,前端负责: +1. 拦截工具调用 +2. 弹出确认对话框 +3. 执行或取消删除 +4. **必须返回结果给后端** + +### 9.2 关键要点 + +- ✅ 前端必须返回 `TOOL_EXECUTION_RESULT` +- ✅ 使用 `useTrash: true` 提高安全性 +- ✅ 验证文件路径在工作区内 +- ✅ 保护敏感文件 +- ✅ 提供清晰的错误消息 + +### 9.3 下一步 + +1. 在 `messageHandler.ts` 中找到工具调用处理逻辑 +2. 实现 `handleDeleteFileTool` 函数 +3. 集成到现有流程 +4. 测试各种场景 +5. 考虑添加用户配置选项