# DesktopPet 本地工作区 Agent 施工计划 > 归档说明:该路线已于 2026-07-16 从 QtDesktopPet 当前产品方向中移除,本文仅保留历史设计,不再作为施工依据。 ## 1. 定位 本地工作区 Agent 是下一阶段核心功能。它不是继续维护旧版“文件操作 v1”,而是新增一个独立的工作区系统: > 用户选择一个本地工作区目录后,桌宠可以读取、搜索、分析该目录内的文件,并在用户确认后创建、修改、复制、移动、重命名或删除到回收站。 第一阶段优先实现文件级工具,不做 Shell 命令执行,不做脚本执行,不做自动安装依赖。 ## 2. 总原则 - 不允许 AI 直接获得全盘文件权限。 - 不允许 AI 自由执行系统命令。 - 不允许永久删除文件。 - 不允许绕过用户确认修改本地文件。 - 不允许默认读取敏感文件。 - 所有写操作必须先生成计划,展示路径、动作和风险,用户确认后才能执行。 - 所有文件路径必须限制在用户选择的工作区内。 - `PetWindow` 只负责 UI 入口、展示和确认,不承载复杂业务逻辑。 - 新模块先新增、后替换旧 `src/fileops/`。 ## 3. 分期目标 当前执行状态: - v1a.1/v1b/v1b.5 已落地到 `src/workspace/` 和 `src/ui/WorkspaceAgentWindow.*`。 - 当前不持久化工作区路径,不执行写操作,不替换旧 `src/fileops/`。 - v1b 已支持打开工作区内普通文件、打开文件夹、显示文件所在位置。 - v1b.5 已提供独立 Agent 工作区窗口、右键/托盘入口和默认 `Alt+A` 呼出快捷键;窗口包含左侧结果导航、中间任务对话、右侧详情/上下文和 v1c 预留变更区。 ### v1a:只读工作区 目标: - 选择工作区。 - 显示当前工作区。 - 扫描工作区文件树。 - 搜索文件名。 - 搜索文本内容。 - 读取文本文件。 - 分析项目结构。 - 总结文件内容。 验收: - 工作区外路径被拒绝。 - 系统目录被拒绝。 - `.git/build/node_modules/dist/release_packages` 等目录被跳过。 - 敏感文件默认拒绝读取。 - 二进制文件拒绝读取。 ### v1b:打开和定位 状态:已落地。 目标: - 打开工作区内普通文件。 - 打开工作区内文件夹。 - 显示文件所在位置。 验收: - 危险后缀拒绝打开。 - `.lnk` 不直接打开。 - 工作区外路径拒绝。 - 打开文件必须二次确认,打开文件夹作为低风险操作直接执行。 ### v1c:低风险写入 进入 v1c 前已完成: - `创建 test.txt / 新建文件 / 写入 README / 修改 main.cpp` 明确拒绝,不再误进入旧 fileops 读取文件流程。 - 独立 Agent 窗口可以分区展示上一轮结果、文本命中、上下文、选中项详情和最近读取文件。 - 窗口支持对选中结果执行读取、打开和显示位置。 - 窗口可通过桌宠右键菜单、托盘菜单和可配置全局快捷键呼出。 目标: - 创建文本文件。 - 创建文件夹。 - 复制单个文件。 - 同目录重命名文件。 验收: - 所有写操作必须确认。 - 目标文件或目录已存在时拒绝覆盖。 - 文件名非法时拒绝。 - 危险后缀拒绝创建或写入。 ### v1d:高风险写入 目标: - 修改已有文本文件。 - 移动单个文件。 - 删除文件到回收站。 - 删除文件夹到回收站。 验收: - 修改前必须备份。 - 移动和删除必须强确认。 - 删除只进入回收站。 - 批量删除第一阶段拒绝。 - 失败时不能破坏原文件。 ### v1e:替换旧文件操作 目标: - `FileOperation` 意图迁移为 `Workspace`。 - `PetWindow::handleFileOperationChatMessage()` 过渡为调用 `WorkspaceController`。 - 新模块覆盖旧能力后删除旧 `src/fileops/`。 验收: - 无 `FileOperationManager` 有效引用。 - CMake 不再登记旧 fileops 文件。 - README 和测试文档改为“本地工作区 Agent”。 ## 4. 新目录结构 建议新增: ```text src/workspace/ ├── WorkspaceTypes.h ├── WorkspaceSession.h ├── WorkspaceSession.cpp ├── WorkspaceIndex.h ├── WorkspaceIndex.cpp ├── WorkspaceScanner.h ├── WorkspaceScanner.cpp ├── WorkspaceAccessPolicy.h ├── WorkspaceAccessPolicy.cpp ├── WorkspaceTool.h ├── WorkspaceToolRegistry.h ├── WorkspaceToolRegistry.cpp ├── WorkspaceAgent.h ├── WorkspaceAgent.cpp ├── WorkspaceController.h ├── WorkspaceController.cpp ├── WorkspaceHistory.h ├── WorkspaceHistory.cpp └── tools/ ├── ListFilesTool.h ├── ListFilesTool.cpp ├── ReadFileTool.h ├── ReadFileTool.cpp ├── SearchFilesTool.h ├── SearchFilesTool.cpp ├── SearchTextTool.h ├── SearchTextTool.cpp ├── OpenFileTool.h ├── OpenFileTool.cpp ├── CreateFileTool.h ├── CreateFileTool.cpp ├── CreateDirectoryTool.h ├── CreateDirectoryTool.cpp ├── WriteFileTool.h ├── WriteFileTool.cpp ├── CopyFileTool.h ├── CopyFileTool.cpp ├── MoveFileTool.h ├── MoveFileTool.cpp ├── RenameFileTool.h ├── RenameFileTool.cpp ├── DeleteToTrashTool.h └── DeleteToTrashTool.cpp ``` 第一阶段继续保持 `CMAKE_AUTOMOC OFF`,新增业务类不使用 `Q_OBJECT`。 ## 5. 核心类型 ```cpp enum class WorkspacePermissionMode { ReadOnly, ConfirmBeforeWrite, Advanced }; ``` 第一阶段默认 `ConfirmBeforeWrite`,但所有写操作仍必须确认。`Advanced` 只预留,不启用自动写入。 ```cpp enum class WorkspaceToolRisk { ReadOnly, Low, Medium, High, Dangerous }; ``` 风险定义: - `ReadOnly`:列目录、搜索、读取普通文本文件。 - `Low`:打开文件夹、显示文件所在位置。 - `Medium`:打开普通文件、创建文件、创建文件夹、复制文件。 - `High`:修改文件、移动文件、重命名文件、删除到回收站。 - `Dangerous`:永久删除、执行命令、运行脚本、修改系统目录。 第一阶段遇到 `Dangerous` 直接拒绝。 ```cpp struct WorkspaceFileInfo { QString relativePath; QString absolutePath; QString fileName; QString suffix; qint64 sizeBytes = 0; QDateTime lastModified; bool isDirectory = false; bool isTextFile = false; bool isHidden = false; }; ``` ```cpp enum class WorkspaceActionType { Unknown, ListFiles, SearchFiles, SearchText, ReadFile, OpenFile, OpenDirectory, RevealInExplorer, CreateFile, CreateDirectory, WriteFile, CopyFile, MoveFile, RenameFile, DeleteToTrash }; ``` ```cpp struct WorkspaceActionPlan { QString id; WorkspaceActionType type = WorkspaceActionType::Unknown; WorkspaceToolRisk risk = WorkspaceToolRisk::ReadOnly; QString title; QString description; QString sourcePath; QString targetPath; QString relativeSourcePath; QString relativeTargetPath; QString content; QString searchKeyword; QStringList warnings; bool requiresConfirmation = false; bool allowOverwrite = false; bool confirmed = false; }; ``` ```cpp struct WorkspaceToolResult { bool success = false; QString message; QString errorMessage; QString outputText; QString targetPath; QVector files; }; ``` ## 6. 安全策略 `WorkspaceAccessPolicy` 是最重要的模块,所有工具必须经过它校验。 职责: - 路径标准化。 - 判断路径是否在工作区内。 - 阻止 `../` 跳出工作区。 - 阻止符号链接跳出工作区。 - 阻止系统目录。 - 阻止危险文件类型。 - 阻止敏感文件默认读取。 - 限制写入行为。 - 限制删除行为。 建议接口: ```cpp class WorkspaceAccessPolicy { public: explicit WorkspaceAccessPolicy(const QString &workspaceRoot); QString workspaceRoot() const; QString normalizePath(const QString &path) const; QString toAbsolutePath(const QString &relativeOrAbsolutePath) const; QString toRelativePath(const QString &absolutePath) const; bool isInsideWorkspace(const QString &path, QString *errorMessage = nullptr) const; bool hasSymlinkSegment(const QString &path, QString *errorMessage = nullptr) const; bool isSystemPath(const QString &path) const; bool isDangerousSuffix(const QString &path) const; bool isSensitiveFile(const QString &path) const; bool isSupportedTextFile(const QString &path) const; bool canReadFile(const QString &path, QString *errorMessage = nullptr) const; bool canReadDirectory(const QString &path, QString *errorMessage = nullptr) const; bool canCreateFile(const QString &path, QString *errorMessage = nullptr) const; bool canCreateDirectory(const QString &path, QString *errorMessage = nullptr) const; bool canWriteFile(const QString &path, QString *errorMessage = nullptr) const; bool canMoveFile(const QString &sourcePath, const QString &targetPath, QString *errorMessage = nullptr) const; bool canDeleteToTrash(const QString &path, QString *errorMessage = nullptr) const; }; ``` 禁止危险后缀: ```text .exe .bat .cmd .ps1 .vbs .msi .scr .reg .com .pif .lnk ``` 敏感文件默认拒绝: ```text .env *.pem *.key id_rsa id_ed25519 *.pfx *.p12 credentials.json secrets.json token.json ``` 文件名包含以下关键词也视为敏感: ```text secret token password credential private apikey api_key ``` ## 7. 扫描和索引 `WorkspaceScanner` 第一版使用 `QDir` + 手动目录栈扫描工作区,后续如需取消、进度回调或更细粒度过滤,再考虑替换为 `QDirIterator` 或异步扫描。 默认限制: - 最大递归深度:8。 - 最大文件数量:5000。 - 跳过隐藏目录。 - 跳过常见产物目录。 跳过目录: ```text .git .vs .idea build cmake-build-debug cmake-build-release node_modules dist release release_packages logs ``` `WorkspaceIndex` 第一版只做内存索引: ```cpp class WorkspaceIndex { public: void clear(); void setFiles(const QVector &files); QVector allFiles() const; QVector findByName(const QString &keyword, int maxResults) const; QVector findBySuffix(const QStringList &suffixes, int maxResults) const; QVector recentFiles(int maxResults) const; }; ``` ## 8. 工具清单 ### 8.1 只读工具 `ListFilesTool` - 列出工作区内目录。 - 最多显示 200 项。 - 不递归或浅递归。 `ReadFileTool` - 只读文本文件。 - 最大读取 128KB。 - 超出截断。 - 敏感文件默认拒绝。 - 不读二进制文件。 支持后缀: ```text .cpp .h .hpp .c .cc .py .js .ts .json .md .txt .ini .xml .yaml .yml .cmake .pro .css .html ``` `SearchFilesTool` - 只搜索当前工作区索引。 - 最多返回 30 个结果。 - 按相关性和最近修改时间排序。 `SearchTextTool` - 最多扫描 1000 个文本文件。 - 单文件最大读取 128KB。 - 最多返回 50 条匹配。 - 每条显示文件路径、行号、片段。 ### 8.2 打开工具 `OpenFileTool` - 用系统默认程序打开文件。 - 只能打开工作区内普通文件。 - 危险后缀拒绝。 - 敏感文件需要确认或第一版拒绝。 `OpenDirectoryTool` - 打开工作区内目录。 - 工作区外路径拒绝。 `RevealInExplorerTool` - 第一版可以先打开所在文件夹。 - 如果后续使用 `explorer.exe /select`,必须固定程序路径和参数,不接受聊天文本命令。 ### 8.3 写入工具 `CreateFileTool` - 只能在工作区内创建。 - 目标不能已存在。 - 文件名必须合法。 - 危险后缀拒绝。 - 必须确认。 `CreateDirectoryTool` - 只能在工作区内创建。 - 目标不能已存在。 - 必须确认。 `WriteFileTool` - 修改已有文本文件前自动备份。 - 禁止覆盖二进制文件。 - 禁止写敏感文件。 - 禁止写危险后缀。 - 必须确认。 备份目录: ```text /.desktoppet/backups/ ``` 备份命名: ```text relative_path.replace("/", "__") + "." + yyyyMMdd-HHmmss + ".bak" ``` `CopyFileTool` - 只复制单文件。 - 源和目标都必须在工作区内。 - 不覆盖。 - 必须确认。 `MoveFileTool` - 只移动单文件。 - 源和目标都必须在工作区内。 - 不覆盖。 - 必须确认。 `RenameFileTool` - 只允许同目录重命名。 - 文件名不能包含路径分隔符。 - 不覆盖。 - 必须确认。 `DeleteToTrashTool` - 只移动到系统回收站。 - 不永久删除。 - 单文件删除第一阶段可支持。 - 文件夹删除需要强确认。 - 批量删除第一阶段拒绝。 ## 9. WorkspaceAgent 第一版采用半自动 Agent,不做复杂工具循环。 推荐流程: ```text 用户输入 ↓ WorkspaceController 判断工作区任务 ↓ 程序根据关键词和索引检索相关文件 ↓ 读取少量相关文件 ↓ 把文件树摘要、相关文件内容、用户问题交给模型 ↓ 模型返回分析结果或修改建议 ↓ 涉及写操作时生成 WorkspaceActionPlan ↓ 用户确认 ↓ 执行工具 ``` 工作区专用系统提示词: ```text 你是 QtDesktopPet 的本地工作区助手。 你只能基于用户授权的工作区文件进行分析。 你不能假设自己看过未读取的文件。 你不能要求访问工作区外路径。 你不能执行系统命令。 你不能生成危险操作指令。 涉及创建、修改、移动、重命名、删除文件时,必须先生成清晰的操作计划,等待用户确认。 涉及敏感文件、密钥、凭证时,必须提醒风险。 回答代码问题时要引用具体文件路径。 当信息不足时,说明还需要读取哪些文件。 ``` 后续可升级为工具循环,但第一版不做。 ## 10. WorkspaceController 建议接口: ```cpp class WorkspaceController { public: explicit WorkspaceController(); bool hasWorkspace() const; QString workspaceRoot() const; bool openWorkspace(const QString &rootPath, QString *errorMessage = nullptr); void closeWorkspace(); WorkspaceToolResult scanWorkspace(); WorkspaceToolResult handleMessage(const QString &message); bool hasPendingPlan() const; WorkspaceActionPlan pendingPlan() const; WorkspaceToolResult confirmPendingPlan(); void cancelPendingPlan(); private: WorkspaceSession m_session; WorkspaceAgent m_agent; std::optional m_pendingPlan; }; ``` 原则: - `handleMessage()` 不直接执行高风险写操作。 - 需要确认时保存到 `m_pendingPlan`。 - UI 调用 `confirmPendingPlan()` 后才执行。 - 所有错误通过 `WorkspaceToolResult` 返回,不在工具层弹窗。 ## 11. UI 接入 聊天入口支持: ```text 打开工作区 选择工作区 当前工作区 扫描工作区 分析这个项目 搜索当前工作区 读取 main.cpp 打开第一个 ``` 如果没有选择工作区,提示用户选择目录。 气泡只显示短状态: ```text 已打开工作区。 正在扫描文件。 找到了 12 个相关文件。 需要你确认修改计划。 操作已完成。 ``` 复杂结果不全部塞进气泡,当前通过独立 Agent 窗口展示。 当前独立 Agent 窗口可显示: - 当前工作区路径。 - 文件树。 - 搜索结果。 - 已读取文件。 - AI 分析结果。 - 待确认操作计划。 - 执行结果。 - 最近操作历史。 ## 12. 意图分发 后续建议新增: ```cpp enum class UserIntentType { Chat, Reminder, Weather, Workspace, FileOperation, LaunchApp }; ``` 意图原则: - `Reminder` 保持最高优先级。 - 明确天气问答走 `Weather`。 - 明确工作区、代码、项目分析走 `Workspace`。 - 当前阶段,未明确“工作区/项目/代码”且没有工作区文件名特征的普通文件读写请求仍可走旧 `FileOperation`。 - 明确应用名启动走 `LaunchApp`。 - 其余走 `Chat` 或输入框联网模式。 不能用宽关键词简单吞掉所有请求: - “打开微信”应走 `LaunchApp`。 - “打开文件夹”这种泛请求不走 `Workspace`;“打开 docs / 打开这个项目里的 docs”走 `Workspace`。 - “搜索 Qt 最新版本”不应走工作区搜索。 - “搜索这个项目里的 main”应走工作区搜索。 ## 13. 迁移步骤 1. 新增 `src/workspace/`,不改旧 `src/fileops/`。 2. CMake 登记 workspace 新文件。 3. `PetWindow` 增加 `WorkspaceController` 成员。 4. 新增工作区打开、扫描、搜索、读取入口。 5. v1b 支持打开和定位;写操作计划和确认框从后续阶段开始。 6. 新模块覆盖旧文件操作能力后,`handleFileOperationChatMessage()` 转发到 `WorkspaceController`。 7. 确认无旧引用后删除 `src/fileops/`。 8. 更新 CMake、README、测试文档。 删除旧文件前必须执行: ```text rg "FileOperationManager|FileSandbox|FileBackupManager|src/fileops|FileOperation" ``` 确认没有有效代码引用后再删。 ## 14. 日志要求 允许记录: - 打开工作区路径。 - 扫描文件数量。 - 执行的工具名称。 - 操作是否成功。 - 错误摘要。 禁止记录: - API Key。 - Authorization Header。 - 完整敏感文件内容。 - `.env` 内容。 - 密钥文件内容。 - 用户完整隐私文本。 使用项目已有 `Logger`,不要新增零散调试输出。 ## 15. 测试清单 ### 工作区选择 - 选择普通项目目录。 - 选择空目录。 - 选择不存在目录。 - 选择 `C:/Windows`,应拒绝。 - 选择 `Program Files`,应拒绝。 - 选择中文路径。 - 选择包含空格的路径。 ### 扫描 - 扫描普通 Qt 项目。 - 扫描包含 build 目录的项目。 - 扫描包含 `.git` 的项目。 - 扫描大量文件目录。 - 扫描中文文件名。 - 扫描深层目录。 要求: - 不崩溃。 - 不扫系统目录。 - 不进入跳过目录。 - 结果数量受限制。 ### 搜索文件 - 搜索 `main`。 - 搜索 `.cpp`。 - 搜索 `README`。 - 搜索不存在文件。 - 搜索中文文件名。 要求: - 最多返回 30 条。 - 显示相对路径。 - 结果可用于后续“打开第几个”。 ### 搜索文本 - 搜索 `class`。 - 搜索 `include`。 - 搜索中文关键词。 - 搜索不存在关键词。 - 搜索超大文件。 要求: - 显示路径、行号、片段。 - 跳过二进制文件。 - 跳过超大文件。 - 不读取敏感文件。 ### 读取文件 - 读取 `.cpp`。 - 读取 `.md`。 - 读取 `.json`。 - 读取图片应拒绝。 - 读取 `.exe` 应拒绝。 - 读取 `.env` 应拒绝或强确认。 - 读取工作区外文件应拒绝。 ### 创建文件 - 在工作区创建 `test.txt`。 - 创建已存在文件应拒绝。 - 创建非法文件名应拒绝。 - 创建 `.bat` 应拒绝。 - 创建到工作区外应拒绝。 ### 修改文件 - 修改普通 `.txt`。 - 修改 `.cpp`。 - 修改前生成备份。 - 修改二进制文件应拒绝。 - 修改敏感文件应拒绝。 要求: - 必须确认。 - 必须备份。 - 失败不能破坏原文件。 ### 移动和重命名 - 移动普通文件。 - 移动到已存在目标应拒绝。 - 重命名普通文件。 - 重命名为非法文件名应拒绝。 - 移动到工作区外应拒绝。 ### 删除到回收站 - 删除普通文件到回收站。 - 删除文件夹到回收站。 - 删除工作区外文件应拒绝。 - 永久删除请求应拒绝。 - 批量删除请求第一阶段应拒绝。 ### 对话上下文 ```text 用户:搜索 README 用户:打开第一个 用户:搜索 fileops 用户:读取第二个 用户:找一下包含 FileOperationManager 的文件 用户:总结这些文件的作用 ``` 要求: - 系统能记住上一轮搜索结果。 - “第一个”“第二个”能正确解析。 - 上下文过期后要求用户重新选择。 ## 16. 静态推演要求 每完成一个阶段,需要记录: - 入口路径。 - 业务模块调用链。 - 路径校验点。 - 用户确认点。 - 失败回滚策略。 - 不支持能力的拒绝话术。 - 对提醒、天气、联网模式、应用启动的回归影响。 ## 17. 最终验收标准 本轮重构完成后至少达到: 1. 用户可以选择一个本地项目目录作为工作区。 2. 程序可以扫描工作区并建立文件索引。 3. 用户可以通过对话搜索文件。 4. 用户可以通过对话读取和分析文本文件。 5. 用户可以要求分析项目结构。 6. 用户可以创建文本文件和文件夹。 7. 用户可以移动、重命名、删除到回收站。 8. 所有写操作必须展示计划并等待确认。 9. 所有路径必须限制在工作区内。 10. 不允许永久删除。 11. 不允许执行脚本或命令。 12. 不允许默认读取敏感文件。 13. 旧文件操作功能被新 Workspace 系统替代。 14. 项目可以由用户手动构建通过。