Files
IC-Coder-Plugin/docs/delete-file-confirmation.md
2026-03-02 17:36:20 +08:00

7.1 KiB
Raw Permalink Blame History

删除文件确认功能实现文档

1. 功能概述

在 AI 返回删除文件命令时,前端拦截并弹出确认对话框,用户确认后才执行删除操作。

2. 架构设计

2.1 消息流程

AI 后端 → 删除文件工具调用 → 前端拦截 → 用户确认对话框
                                              ↓
                                         确定/取消
                                              ↓
                                    执行删除/返回取消结果
                                              ↓
                                      返回 TOOL_EXECUTION_RESULT
                                              ↓
                                          AI 后端

2.2 关键原则

前端必须返回结果:无论用户选择什么,前端都必须向后端返回 TOOL_EXECUTION_RESULT,否则后端会等待超时。

3. 实现方案

3.1 修改位置

文件:src/utils/messageHandler.ts

在处理工具调用的函数中,找到删除文件的工具处理逻辑。

3.2 核心代码实现

/**
 * 处理删除文件工具调用(带用户确认)
 */
async function handleDeleteFileTool(
  toolCall: any,
  panel: vscode.WebviewPanel
): Promise<ToolExecutionResult> {
  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 的工具调用处理逻辑中:

// 示例:在处理工具调用的地方
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 对话框样式

const confirmed = await vscode.window.showWarningMessage(
  `确定要删除文件吗?\n\n📄 ${path.basename(filePath)}\n📁 ${path.dirname(filePath)}`,
  {
    modal: true,
    detail: '⚠️ 文件将被移到回收站,可以恢复'
  },
  '确定删除',
  '取消'
);

4.2 批量删除优化

如果 AI 一次返回多个删除操作:

// 方案 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 使用回收站

await vscode.workspace.fs.delete(uri, {
  useTrash: true  // 移到回收站,可恢复
});

5.2 路径验证

// 防止删除工作区外的文件
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 敏感文件保护

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 常见错误

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. 配置选项(可选)

可以添加用户设置来控制行为:

// package.json
"configuration": {
  "properties": {
    "ic-coder.confirmDelete": {
      "type": "boolean",
      "default": true,
      "description": "删除文件前是否需要确认"
    },
    "ic-coder.useTrash": {
      "type": "boolean",
      "default": true,
      "description": "删除文件时移到回收站而非永久删除"
    }
  }
}

读取配置:

const config = vscode.workspace.getConfiguration('ic-coder');
const needConfirm = config.get<boolean>('confirmDelete', true);
const useTrash = config.get<boolean>('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. 考虑添加用户配置选项