diff --git a/README.md b/README.md index 7026ca3..a8b7637 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > 本文件用于团队开发期间快速配置环境和启动项目,不是正式的项目 README。 -> 当前基线:2026-08-30。第一阶段 Web 联调版的前端页面、Knowledge/Retrieval Core、AI/Agent Core、Extension Core、Provider 预设与本地加密凭据链路均已实现;Tauri Host、Stronghold、真实桌面文件系统和 Sync Server 尚未接入。 +> 当前基线:2026-09-02。第一阶段 Web 联调前后端已经完成;第二阶段已完成 Workspace 去 Mock、Agent Trace 持久化与 SSE 恢复、stdio MCP Bridge、隔离 Plugin Host,以及 Plugin Command/Settings 后端 Contract 和前端 Service。真实音频、Provider 协议增强、Benchmark、导出、主题包、Trace 可视化、Mermaid 与函数图像仍在后续开发;Tauri Host、Stronghold、原生多 Vault 文件系统和 Sync Server 尚未接入。 ## 当前目录 @@ -118,7 +118,7 @@ cd frontend pnpm test ``` -当前回归基线为后端 126 项测试、前端 29 项测试,且 TypeScript 类型检查和生产构建通过。测试数量会随功能增长,以本地实际输出和 CI 为准。 +当前回归基线为后端 136 项测试、前端 29 项测试,且 TypeScript 类型检查和生产构建通过。测试数量会随功能增长,以本地实际输出和 CI 为准。 构建产物位于 `frontend/dist`,该目录不提交到 Git。 @@ -134,6 +134,7 @@ pnpm test | [AI Core 与 Agent Core](docs/development/AI-Core与Agent-Core开发说明.md) | Provider、Agent、Tool、Permission 与 Extension Core | | [MCP Bridge 与 Plugin Host](docs/development/MCP-Bridge与Plugin-Host开发说明.md) | stdio MCP、隔离进程、Tool 映射、状态与错误边界 | | [Plugin Command 与 Settings](docs/development/Plugin-Command与Settings开发说明.md) | Command Registry、Settings Schema、Secret 引用与联调边界 | +| [Plugin Command 与 Settings 复盘](docs/retrospectives/Plugin-Command与Settings问题与修复复盘.md) | 阶段 D 连续审阅发现的安全、事务、Schema 与运行时契约问题 | | [Git 使用细则](docs/guides/Git使用细则-团队开发版.md) | 分支、提交、PR、Review 与合并流程 | | [CI/CD 细则](docs/guides/CI-CD细则-团队开发版.md) | Gitea 流水线、质量门禁、产物、发布与回滚规则 | | [Agent Trace 复盘](docs/retrospectives/Agent-Core第二阶段问题与修复复盘.md) | Agent 持久化、SSE 恢复、事件契约与脱敏问题复盘 | @@ -147,6 +148,6 @@ pnpm test - 后端附件目录默认是 `backend/data/attachments`,可通过 `APP_ATTACHMENTS_PATH` 覆盖;该目录由桌面 Host 管理。 - 跨模块接口发生变化时,需要同步更新前后端类型和 `docs` 中的接口说明。 - 当前已实现接口见 `docs/contracts/后端接口契约-开发版.md`,第二阶段规划接口见 `docs/contracts/第二阶段接口契约-开发版.md`;已实现能力以 `/openapi.json` 为准。 -- 前端页面、交互、状态管理和第一阶段验收要求见 `docs/contracts/前端页面需求说明-开发版.md`。 +- 前端页面、交互、状态管理及当前阶段后续页面需求见 `docs/contracts/前端页面需求说明-开发版.md`。 - 分支、提交、Pull Request、Review 和冲突处理规范见 `docs/guides/Git使用细则-团队开发版.md`。 - CI 检查、产物、发布和回滚规范见 `docs/guides/CI-CD细则-团队开发版.md`。 diff --git a/backend/README.md b/backend/README.md index a087fa7..a857f76 100644 --- a/backend/README.md +++ b/backend/README.md @@ -23,7 +23,7 @@ uv run uvicorn app.main:app --reload --host 127.0.0.1 --port 8000 uv run pytest ``` -当前基线为 126 项测试通过。Provider API Key 可通过前端设置页写入,也可用 `OPENAI_API_KEY`、`DEEPSEEK_API_KEY` 或 `AINOTE_CREDENTIAL_` 注入;不要把真实密钥写入仓库。`plugin.*` 是 Plugin Settings 的保留凭据命名空间,通用 Provider 凭据接口不能读写。 +当前基线为 136 项测试通过。Provider API Key 可通过前端设置页写入,也可用 `OPENAI_API_KEY`、`DEEPSEEK_API_KEY` 或 `AINOTE_CREDENTIAL_` 注入;不要把真实密钥写入仓库。`plugin.*` 是 Plugin Settings 的保留凭据命名空间,通用 Provider 凭据接口不能读写。 团队接口清单见 `../docs/contracts/后端接口契约-开发版.md`,机器可读契约以运行时的 `/openapi.json` 为准。 diff --git a/docs/README.md b/docs/README.md index 8625a06..de9938b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -49,6 +49,7 @@ - [后端全面审阅问题与修复复盘](retrospectives/后端全面审阅问题与修复复盘.md) - [Agent Core 第二阶段问题与修复复盘](retrospectives/Agent-Core第二阶段问题与修复复盘.md) - [Knowledge 与 Retrieval Core 问题与修复复盘](retrospectives/Knowledge与Retrieval-Core问题与修复复盘.md) +- [Plugin Command 与 Settings 问题与修复复盘](retrospectives/Plugin-Command与Settings问题与修复复盘.md) - [前端合并审阅问题与修复复盘](retrospectives/前端合并审阅问题与修复复盘.md) ## 推荐阅读顺序 diff --git a/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md b/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md index 80a321b..2458a4f 100644 --- a/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md +++ b/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md @@ -2329,7 +2329,7 @@ Markdown Workspace 第一阶段 Plugin Runtime 已完成安装、启用、停用、权限和声明式 Tool 注册,建立 Skill 调用 Plugin Tool 的基础链路。Command、Settings 和 MCP 执行不计入第一阶段完成项。 -截至 2026-09-02,上述第一阶段后端链路和 Web 联调前端均已完成;第二阶段前置的 Workspace 去 Mock 联调、Agent Trace 持久化/恢复接口、stdio MCP Bridge / Plugin Host 以及 Plugin Command/Settings 后端 Contract 也已完成。当前验证基线为后端 126 项测试、前端 29 项测试、TypeScript 类型检查及生产构建通过。向量链路当前使用 `HashEmbeddingProvider` 验证工程正确性,真实 Embedding 召回质量不属于该测试结论。 +截至 2026-09-02,上述第一阶段后端链路和 Web 联调前端均已完成;第二阶段的 Workspace 去 Mock 联调、Agent Trace 持久化/恢复接口、stdio MCP Bridge / Plugin Host 以及 Plugin Command/Settings 后端 Contract 与前端 Service 也已完成。当前验证基线为后端 136 项测试、前端 29 项测试、TypeScript 类型检查及生产构建通过。向量链路当前使用 `HashEmbeddingProvider` 验证工程正确性,真实 Embedding 召回质量不属于该测试结论。 第二阶段在既有 Contract 上接入: @@ -2361,7 +2361,7 @@ Frontend Extension └── Plugin Settings UI ``` -上述列表描述第二阶段技术范围,其中 stdio MCP Bridge 已实现,其余能力以各自开发说明的状态为准。每项功能必须继续经过现有 Service、Contract、Permission 和 Adapter 边界,不因 Demo 需要在 Vue 组件、Router 或 Agent Runtime 中直接绑定第三方协议。 +上述列表描述第二阶段技术范围,其中 stdio MCP Bridge、Plugin Command Contribution 和 Plugin Settings Contribution 后端 Contract 已实现,其余能力以各自开发说明的状态为准。每项功能必须继续经过现有 Service、Contract、Permission 和 Adapter 边界,不因 Demo 需要在 Vue 组件、Router 或 Agent Runtime 中直接绑定第三方协议。 第三阶段处理: @@ -2415,9 +2415,9 @@ Sync Server 按独立服务开发和部署,不进入桌面客户端核心启 目标桌面端采用 Tauri 2、Rust、Vue 3 和 TypeScript;当前可运行形态是 Vue/Vite Web 前端加 FastAPI。用户笔记以 Markdown 和 Assets 保存在本地 Vault,SQLite 已管理笔记元数据、全文索引、向量索引、任务及 Agent Trace;Provider/Extension Registry 当前仍为内存实现。 -Python AI Core 未来作为 Tauri Sidecar 运行,当前由开发命令独立启动,FastAPI 提供本地接口。Knowledge Core 管理笔记结构;Retrieval Core 当前通过 FTS5、`HashEmbeddingProvider`、sqlite-vec、RRF 和轻量 Reranker 跑通混合检索,真实 Embedding 与正式 Benchmark 在第二阶段接入;Agent Runtime 使用 Tool Registry 操作知识库和任务,并将扩展 Agent Trace Contract 供可视化和 Benchmark 共用;Skill Runtime 将提示词、工具、权限和检索参数组装为可复用 Agent 配置。 +Python AI Core 未来作为 Tauri Sidecar 运行,当前由开发命令独立启动,FastAPI 提供本地接口。Knowledge Core 管理笔记结构;Retrieval Core 当前通过 FTS5、`HashEmbeddingProvider`、sqlite-vec、RRF 和轻量 Reranker 跑通混合检索,真实 Embedding 与正式 Benchmark 仍待第二阶段后续接入;Agent Runtime 使用 Tool Registry 操作知识库和任务,并已持久化可供前端可视化与 Benchmark 共用的 Agent Trace Contract;Skill Runtime 将提示词、工具、权限和检索参数组装为可复用 Agent 配置。 -当前 Plugin Runtime 支持 Manifest、生命周期和声明式白名单 Tool Contribution,并已通过 stdio MCP Bridge 接入独立进程 Tool、Host 状态与重启接口;Command 与 Settings Contribution 尚待后续阶段实现。Provider Adapter 当前实现 Mock、OpenAI Chat/OpenAI-Compatible 与 Ollama,第二阶段按统一行为测试完善 OpenAI Responses、Anthropic Messages 等协议。多模态目标方案使用 faster-whisper、pyannote.audio 和可选 emotion2vec;当前只读取 Host 预生成 transcript。 +当前 Plugin Runtime 支持 Manifest、生命周期、声明式白名单 Tool Contribution、Plugin Command 与 Plugin Settings/Secret,并已通过 stdio MCP Bridge 接入独立进程 Tool、专用 MCP Command Target、Host 状态与重启接口。Provider Adapter 当前实现 Mock、OpenAI Chat/OpenAI-Compatible 与 Ollama,OpenAI Responses、Anthropic Messages 等协议仍待第二阶段后续完善。多模态目标方案使用 faster-whisper、pyannote.audio 和可选 emotion2vec;当前只读取 Host 预生成 transcript。 第二阶段内容输出以 Document AST、Exporter Adapter、Mermaid Renderer 和 Function Plot Renderer 为共同边界,支持 HTML、PDF、DOCX 与静态图导出。Theme Package 使用 Manifest、Design Token 和受限 CSS 实现本地导入;联网主题市场不属于本阶段核心依赖。API Key 在 Web 联调期由 Fernet 开发存储加密保存,桌面版迁移到 Tauri Stronghold。多设备同步的目标方案为独立、可自托管的 Sync Server,目前尚未实现;本地核心功能不依赖 Sync Server。 diff --git a/docs/architecture/第一阶段分工表.md b/docs/architecture/第一阶段分工表.md index 9a9a2a5..972cbf3 100644 --- a/docs/architecture/第一阶段分工表.md +++ b/docs/architecture/第一阶段分工表.md @@ -1,6 +1,6 @@ # 第一阶段分工表 -> 状态更新:2026-08-30。本文保留原始职责划分,同时记录当前交付状态。第一阶段后端目标已完成,前端 Web 联调页面已完成;尚未纳入本阶段完成项的是 Tauri Host、Stronghold、真实桌面文件系统、独立 MCP Plugin Host、真实音频模型和 Sync Server。 +> 状态更新:2026-09-02。本文保留第一阶段原始职责划分和交付口径。第一阶段后端目标与前端 Web 联调页面均已完成;第二阶段此后又完成 Agent Trace 持久化与 SSE 恢复、独立 stdio MCP Plugin Host 和 Plugin Command/Settings 后端 Contract。Tauri Host、Stronghold、原生多 Vault 文件系统、真实音频模型和 Sync Server 仍未实现。 ## 当前交付状态 diff --git a/docs/contracts/后端接口契约-开发版.md b/docs/contracts/后端接口契约-开发版.md index cc1abc9..6cfa1f0 100644 --- a/docs/contracts/后端接口契约-开发版.md +++ b/docs/contracts/后端接口契约-开发版.md @@ -1,6 +1,6 @@ # 后端接口契约(开发版) -> 更新日期:2026-09-01。本文档记录当前前后端联调使用的已实现接口;机器可读字段、校验规则和响应模型以 FastAPI 运行时生成的 OpenAPI 为准。第二阶段尚未实现的规划接口见 `第二阶段接口契约-开发版.md`,不要将规划路径视为当前服务能力。 +> 更新日期:2026-09-02。本文档记录当前前后端联调使用的已实现接口;机器可读字段、校验规则和响应模型以 FastAPI 运行时生成的 OpenAPI 为准。第二阶段尚未实现的规划接口见 `第二阶段接口契约-开发版.md`,不要将规划路径视为当前服务能力。 ## 契约入口 @@ -176,7 +176,7 @@ RunCancelled ## 当前实现状态 -更新至 2026-09-02:后端 126 项回归测试通过;第二阶段 Plugin Command 与 Plugin Settings/Secret 接口已实现,详细 DTO 和边界见《第二阶段接口契约-开发版》第 7 节。 +更新至 2026-09-02:后端 136 项回归测试通过;第二阶段 Plugin Command 与 Plugin Settings/Secret 接口已实现,详细 DTO 和边界见《第二阶段接口契约-开发版》第 7 节。 - Chat、Agent Run、Agent Events、Tool 列表、Provider 配置生命周期、模型列表和连接测试已经接入 AI Core。 - Agent Run/Event 已持久化到 SQLite;SSE 帧携带 sequence `id`,断线后可以回放缺失事件。Trace API 与 Benchmark 共用同一事件事实,并在入库前执行 Secret 脱敏和结果限长。 diff --git a/docs/contracts/第二阶段接口契约-开发版.md b/docs/contracts/第二阶段接口契约-开发版.md index 00d3adb..87aceb4 100644 --- a/docs/contracts/第二阶段接口契约-开发版.md +++ b/docs/contracts/第二阶段接口契约-开发版.md @@ -2,7 +2,7 @@ > 文档状态:接口冻结草案 > -> 更新日期:2026-09-01 +> 更新日期:2026-09-02 > > 依据:`../architecture/第二阶段团队分工表.md`、`../architecture/AI笔记软件技术栈说明-团队版-v2.3.md`、`后端接口契约-开发版.md` @@ -27,7 +27,7 @@ | 标记 | 含义 | | --- | --- | -| 已实现 | 第一阶段接口已经存在,第二阶段保持兼容 | +| 已实现 | 接口已经落地并由当前 OpenAPI 与自动化测试覆盖 | | 扩展 | 路径已存在,第二阶段增加字段、事件或行为 | | 计划新增 | 第二阶段需要新增实现 | | 内部 Contract | 不直接暴露 HTTP,由两个模块共同遵守 | diff --git a/docs/development/AI-Core与Agent-Core开发说明.md b/docs/development/AI-Core与Agent-Core开发说明.md index 4e4adfe..0aadeb4 100644 --- a/docs/development/AI-Core与Agent-Core开发说明.md +++ b/docs/development/AI-Core与Agent-Core开发说明.md @@ -2,7 +2,7 @@ > 本文档用于团队开发和模块联调,记录当前已经落地的核心边界与使用方式。 -> 更新日期:2026-09-02。第一阶段 AI Core、Agent Core、Extension Core 和 Model Core 主链路已经完成;第二阶段 Agent Trace 持久化、可恢复 SSE、stdio MCP Bridge、隔离 Plugin Host 以及 Plugin Command/Settings 已落地,后端当前回归基线为 126 项测试通过。 +> 更新日期:2026-09-02。第一阶段 AI Core、Agent Core、Extension Core 和 Model Core 主链路已经完成;第二阶段 Agent Trace 持久化、可恢复 SSE、stdio MCP Bridge、隔离 Plugin Host 以及 Plugin Command/Settings 已落地,后端当前回归基线为 136 项测试通过。 ## 当前实现 @@ -347,6 +347,6 @@ Skill Manifest - Run/Trace 已通过 Repository 接入 SQLite;后续增加按保留策略归档和 Benchmark 引用保护。 - Permission 已有核心等待/恢复机制,前端确认 UI 已完成联调和中文展示。 - Task 已持久化到 SQLite;Attachment Tool 读取 Host 管理目录中的 UTF-8 文件。 -- `audio.transcribe` 当前消费 Host 预生成的 transcript;faster-whisper 与说话人分离仍按技术基线在第二阶段接入。 +- `audio.transcribe` 当前消费 Host 预生成的 transcript;faster-whisper 与说话人分离仍待第二阶段后续接入。 - Extension 安装记录暂存内存;后续接入持久化 Registry 与版本升级流程。 - 当前 Plugin Host 支持内置声明式 handler、本地 stdio MCP Server 以及 Plugin Command/Settings;Streamable HTTP、OS 级沙箱与 UI Contribution 留在后续阶段。 diff --git a/docs/development/Knowledge与Retrieval-Core开发说明.md b/docs/development/Knowledge与Retrieval-Core开发说明.md index f8b7ed1..074eded 100644 --- a/docs/development/Knowledge与Retrieval-Core开发说明.md +++ b/docs/development/Knowledge与Retrieval-Core开发说明.md @@ -3,7 +3,7 @@ > 本文档用于团队开发和模块联调,记录 Knowledge Core / Retrieval Core 已经落地的 > 模块边界、数据模型、接口与使用方式,对应分工表中的杨星萱。 -> 更新日期:2026-09-02。第一阶段 Knowledge/Retrieval 主链路已经完成,并已接入 Agent Tool Registry;完整后端回归基线为 126 项测试通过。 +> 更新日期:2026-09-02。第一阶段 Knowledge/Retrieval 主链路已经完成,并已接入 Agent Tool Registry;完整后端回归基线为 136 项测试通过。 ## 当前实现 @@ -198,7 +198,7 @@ cd backend uv run pytest -q ``` -当前后端完整测试共 71 个用例通过(单元 + 端到端)。测试通过 `tests/conftest.py` 的 autouse fixture 把 +当前后端完整测试共 136 个用例通过(单元 + 端到端)。测试通过 `tests/conftest.py` 的 autouse fixture 把 数据目录/DB/Vault 重定向到临时目录,不读写真实 `backend/data`,任何本机状态下结果确定。 ## 配置 diff --git a/docs/development/Plugin-Command与Settings开发说明.md b/docs/development/Plugin-Command与Settings开发说明.md index 1285b16..cec644e 100644 --- a/docs/development/Plugin-Command与Settings开发说明.md +++ b/docs/development/Plugin-Command与Settings开发说明.md @@ -1,6 +1,6 @@ # Plugin Command 与 Settings 开发说明 -> 更新日期:2026-09-02。本文记录第二阶段阶段 D 已实现的 Plugin Command Contribution、Plugin Settings Contribution、Secret 边界和前端 Service Contract。当前回归基线为后端 126 项测试、前端 29 项测试,TypeScript 类型检查和生产构建通过。 +> 更新日期:2026-09-02。本文记录第二阶段阶段 D 已实现的 Plugin Command Contribution、Plugin Settings Contribution、Secret 边界和前端 Service Contract。当前回归基线为后端 136 项测试、前端 29 项测试,TypeScript 类型检查和生产构建通过。 ## 1. 阶段目标 diff --git a/docs/development/前端写作体验优化开发说明.md b/docs/development/前端写作体验优化开发说明.md index 99f4f44..aaf4841 100644 --- a/docs/development/前端写作体验优化开发说明.md +++ b/docs/development/前端写作体验优化开发说明.md @@ -1,6 +1,6 @@ # 前端写作体验优化开发说明 -> 更新日期:2026-08-30。本文所述优化均已进入当前分支;前端完整回归基线为 14 项测试通过,TypeScript 检查和 Vite 生产构建通过。 +> 更新日期:2026-09-02。本文所述优化均已进入 `main`;当前前端完整回归基线为 29 项测试通过,TypeScript 检查和 Vite 生产构建通过。 ## 1. 本次目标 @@ -103,7 +103,7 @@ pnpm build pnpm test ``` -验证结果:TypeScript 类型检查与 Vite 生产构建均通过。当前前端完整回归测试共 14 项;其中写作与文件切换相关回归覆盖: +验证结果:TypeScript 类型检查与 Vite 生产构建均通过。当前前端完整回归测试共 29 项;其中写作与文件切换相关回归覆盖: - 顶部工具栏对选区应用加粗; - 浮动工具栏对选区应用斜体; diff --git a/docs/development/前端壳子与接口层开发说明.md b/docs/development/前端壳子与接口层开发说明.md index 7368ab2..964912f 100644 --- a/docs/development/前端壳子与接口层开发说明.md +++ b/docs/development/前端壳子与接口层开发说明.md @@ -1,6 +1,6 @@ # 前端壳子与接口层开发说明 -> 更新日期:2026-08-30 +> 更新日期:2026-09-02 > 适用范围:Vue 3 + TypeScript 页面、Workspace、公共 Service、FastAPI 接口适配和 SSE。 > 文档用途:帮助团队理解当前前端可用能力、模块边界、启动方式和后续页面开发入口。 @@ -187,12 +187,12 @@ pnpm build ```text pnpm build passed pnpm test 29 passed -uv run pytest 126 passed +uv run pytest 136 passed preview smoke HTTP 200 git diff --check passed ``` -当前前端使用 Vitest 执行 Store、Workspace API Adapter、SSE 恢复游标、Plugin Command/Settings Service、文件树、编辑器组件、智能体标签、轻量动效约束、Markdown 对比度 Token、scoped CSS 选择器约束和 Shiki GitHub 双主题测试;`pnpm build` 同时执行 `vue-tsc -b` 与 Vite 生产构建。后端测试出现过 `.pytest_cache` 无法写入的 Windows 权限警告,不影响 126 项测试结果,也不涉及产品代码。 +当前前端使用 Vitest 执行 Store、Workspace API Adapter、SSE 恢复游标、Plugin Command/Settings Service、文件树、编辑器组件、智能体标签、轻量动效约束、Markdown 对比度 Token、scoped CSS 选择器约束和 Shiki GitHub 双主题测试;`pnpm build` 同时执行 `vue-tsc -b` 与 Vite 生产构建。后端测试出现过 `.pytest_cache` 无法写入的 Windows 权限警告,不影响 136 项测试结果,也不涉及产品代码。 Vite 当前会提示 Chat 与 Workspace 的部分异步 Chunk 超过 500 kB,这是 Milkdown、CodeMirror、KaTeX 和 Shiki 等编辑/渲染依赖带来的性能优化项,不影响构建成功或功能正确性;进入桌面打包前应通过手动分包或更细粒度动态加载继续优化。 diff --git a/docs/development/模型提供商与模型发现开发说明.md b/docs/development/模型提供商与模型发现开发说明.md index ea9547f..825e501 100644 --- a/docs/development/模型提供商与模型发现开发说明.md +++ b/docs/development/模型提供商与模型发现开发说明.md @@ -1,6 +1,6 @@ # 模型提供商与模型发现开发说明 -> 更新日期:2026-08-30。OpenAI、DeepSeek、Ollama 预设、模型自动发现、默认模型选择和开发阶段加密凭据存储均已实现并接入设置页。 +> 更新日期:2026-09-02。OpenAI、DeepSeek、Ollama 预设、模型自动发现、默认模型选择和开发阶段加密凭据存储均已实现并接入设置页。 ## 1. 本次目标 @@ -104,4 +104,4 @@ pnpm build 自动化验证覆盖 Provider 预设、OpenAI-Compatible `/models` 请求与鉴权头、模型映射、前端自动刷新、排序去重及按 Provider 隔离错误。生产构建同时执行 Vue 和 TypeScript 类型检查。 -当前完整回归基线:后端 126 项测试、前端 29 项测试通过,前端类型检查和生产构建通过。Provider 配置目前仍保存在内存 Registry,AI Core 重启后需要重新创建;凭据密文会保留。`plugin.*` 为 Plugin Secret 保留命名空间,Provider 配置、临时测试凭据和通用凭据 API 均拒绝该前缀。OpenAI Responses 与 Anthropic Messages Adapter 尚未实现,设置页正式预设不会使用这两种协议。 +当前完整回归基线:后端 136 项测试、前端 29 项测试通过,前端类型检查和生产构建通过。Provider 配置目前仍保存在内存 Registry,AI Core 重启后需要重新创建;凭据密文会保留。`plugin.*` 为 Plugin Secret 保留命名空间,Provider 配置、临时测试凭据和通用凭据 API 均拒绝该前缀。OpenAI Responses 与 Anthropic Messages Adapter 尚未实现,设置页正式预设不会使用这两种协议。 diff --git a/docs/guides/第一阶段测试验证操作手册.md b/docs/guides/第一阶段测试验证操作手册.md index 1194ae9..6925272 100644 --- a/docs/guides/第一阶段测试验证操作手册.md +++ b/docs/guides/第一阶段测试验证操作手册.md @@ -1,9 +1,11 @@ # 第一阶段测试验证操作手册 -> 适用基线:2026-08-30 `main` -> 适用对象:开发、自测、代码审阅、合并验收和 Demo 前检查 +> 适用基线:2026-09-02 `main` +> 适用对象:开发、自测、代码审阅、合并验收和 Demo 前检查 > 验证范围:Vue Web 前端、FastAPI、Knowledge/Retrieval Core、AI/Agent Core、Extension Core、Provider 与开发阶段凭据链路 +> 状态说明:本文保留第一阶段功能验收口径;当前全量自动化回归同时覆盖第二阶段已经合并的 Agent Trace 持久化与 SSE 恢复、stdio MCP Host、Plugin Command/Settings Contract 和前端 Service,但不反向修改第一阶段的交付定义。 + ## 1. 验证目标 本手册用于确认第一阶段已经形成可运行的本地知识工作流: @@ -18,7 +20,7 @@ → Skill / Plugin 完成生命周期与 Tool 注册 ``` -当前不作为第一阶段通过条件的内容:Tauri/Rust Host、Stronghold、真实桌面文件系统、独立 MCP Plugin Host、真实音频模型和 Sync Server。 +当前不作为第一阶段通过条件的内容:Tauri/Rust Host、Stronghold、原生多 Vault 文件系统、真实音频模型和 Sync Server。独立 stdio MCP Plugin Host 已在第二阶段完成,并进入当前全量回归测试。 ## 2. 环境准备 @@ -68,7 +70,7 @@ uv run pytest -q -p no:cacheprovider 当前基线: ```text -81 passed +136 passed ``` 通过标准:退出码为 0、失败数为 0。用例数可以随功能增加,但不得低于当前基线。 @@ -83,11 +85,11 @@ pnpm test 当前基线: ```text -11 test files passed -27 tests passed +12 test files passed +29 tests passed ``` -通过标准:退出码为 0、失败数为 0。测试覆盖 Provider Store、主题偏好、Workspace、文件树、文件切换、可视化编辑器、智能体中文标签、轻量动效性能约束、Markdown 对比度 Token、scoped CSS 选择器约束和 Shiki GitHub 双主题输出。 +通过标准:退出码为 0、失败数为 0。测试覆盖 Provider Store、主题偏好、Workspace、文件树、文件切换、可视化编辑器、智能体中文标签、SSE 恢复游标、Plugin Command/Settings Service、轻量动效性能约束、Markdown 对比度 Token、scoped CSS 选择器约束和 Shiki GitHub 双主题输出。 ### 3.3 类型检查与生产构建 @@ -330,7 +332,7 @@ Invoke-RestMethod -Method Delete -Uri "$apiBase/notes/$noteId" - 没有真实密钥、生成目录或运行数据进入 Git; - 已记录测试环境、提交、结果、警告和遗留问题。 -外部 OpenAI/DeepSeek、Tauri、Stronghold、真实文件系统、真实音频模型与 Sync Server 失败或未测,不阻止当前第一阶段 Web 联调基线通过,但必须在验收记录中注明“未纳入本阶段”或“选测未执行”。 +外部 OpenAI/DeepSeek、Tauri、Stronghold、原生多 Vault 文件系统、真实音频模型与 Sync Server 失败或未测,不阻止当前第一阶段 Web 联调基线通过,但必须在验收记录中注明“未纳入本阶段”或“选测未执行”。 ## 9. 验收记录模板 diff --git a/docs/retrospectives/Knowledge与Retrieval-Core问题与修复复盘.md b/docs/retrospectives/Knowledge与Retrieval-Core问题与修复复盘.md index cf1b432..d639789 100644 --- a/docs/retrospectives/Knowledge与Retrieval-Core问题与修复复盘.md +++ b/docs/retrospectives/Knowledge与Retrieval-Core问题与修复复盘.md @@ -3,7 +3,7 @@ > 本文记录 `feat/knowledge-retrieval-core` 合并前后的两轮代码审阅、问题复现、修复过程与工程经验。 > 它既是团队内部的问题档案,也可作为后续技术文档、课程报告和博客文章的素材底稿。 -> 2026-08-30 状态补充:本文中的 43 项测试是当时该模块的历史基线,不应替换为当前全仓测试数。相关修复仍有效,当前完整后端回归为 71 项通过,Knowledge/Retrieval 已通过 `notes.*` 与 `rag.search` Tool 接入 Agent Runtime。 +> 2026-09-02 状态补充:本文中的 43 项测试是当时该模块的历史基线,不应替换为当前全仓测试数。相关修复仍有效,当前完整后端回归为 136 项通过,Knowledge/Retrieval 已通过 `notes.*` 与 `rag.search` Tool 接入 Agent Runtime。 ## 1. 背景 diff --git a/docs/retrospectives/Plugin-Command与Settings问题与修复复盘.md b/docs/retrospectives/Plugin-Command与Settings问题与修复复盘.md new file mode 100644 index 0000000..8ea1985 --- /dev/null +++ b/docs/retrospectives/Plugin-Command与Settings问题与修复复盘.md @@ -0,0 +1,464 @@ +# Plugin Command 与 Settings 问题与修复复盘 + +> 审阅与修复日期:2026-09-02 +> 涉及分支:`feat/plugin-command-settings` +> 初始功能提交:`6a08ad8 feat(extension): 实现插件命令与设置贡献` +> 最终修复提交:`d39ae72 fix(extension): 收紧插件命令运行时契约` +> 合并提交:`ff3da5d Merge pull request 'feat(extension): 实现 Plugin Command 与 Settings Contribution' (#10)` +> 文档用途:记录阶段 D 从首次提交、连续审阅到合并期间发现的问题,说明形成原因、实际后果、解决思路和最终方案,供后续开发、问题定位、比赛材料和技术博客写作使用。 + +## 1. 背景与结论 + +阶段 D 在既有 Extension Core、MCP Bridge 和 Plugin Host 上增加 Plugin Command 与 Settings Contribution。初始实现已经具备命令注册、参数校验、设置持久化、Secret 加密存储和前端 Service,但首次提交仍把若干“接口能够调用”误当成了“安全边界已经闭合”。 + +本次分支没有在初始功能提交后直接合并,而是围绕清单输入、凭据隔离、JSON Schema、MCP 协议、事务一致性和前后端 Contract 连续审阅。最终共形成 1 个功能提交和 6 个修复提交,处理 12 类问题: + +| 编号 | 问题 | 级别 | 处理结果 | +| --- | --- | --- | --- | +| D-01 | Plugin Secret 可被通用凭据接口或 Provider 引用 | P0 | 建立 `plugin.*` 保留命名空间和双层访问门禁 | +| D-02 | Command 与 Settings 清单边界不完整 | P1 | 收紧空值、重复项、权限、类型和数值边界校验 | +| D-03 | MCP Command Target 只有声明,没有真实执行链路 | P0 | 增加专用 MCP 命令目标并与 Agent Tool 隔离 | +| D-04 | JSON Schema 外部引用可能触发越权 I/O | P0 | 只允许当前文档内 Fragment 引用 | +| D-05 | Secret 引用可被篡改并跨凭据命名空间 | P0 | 改用定长哈希引用并在读取、删除前重新核对 | +| D-06 | Secret 删除和插件卸载缺少事务一致性 | P0 | 原子替换凭据表,失败时恢复 Settings 引用 | +| D-07 | Schema 引用校验忽略嵌套 `$id` 资源作用域 | P1 | 使用 Draft 2020-12 Resource Resolver 按资源解析 | +| D-08 | MCP Command 未收到普通 Settings | P1 | 在固定信封中同时传递 Settings 与声明过的 Secret | +| D-09 | Command Effect 是任意字典,前后端边界过宽 | P0 | 改为五类判别联合并限制各自 Payload | +| D-10 | 必填普通设置没有阻止启用和执行 | P1 | 在 Enable 与 Execute 两个入口增加运行时门禁 | +| D-11 | MCP 工具 Schema 被发现后丢弃,真实信封未校验 | P0 | 保存目标 Schema,并在调用前校验完整信封 | +| D-12 | 启用探测和回归测试存在假阳性或假阴性 | P1 | 使用最小协议标记,移除自制求解器并补强测试 | + +最终验证基线为后端 136 项测试、前端 29 项测试、TypeScript 类型检查、前端生产构建、`uv lock --check` 和 `git diff --check` 通过。PR #10 已合并到 `main`。 + +## 2. 提交与审阅过程 + +| 顺序 | 提交 | 主要内容 | +| --- | --- | --- | +| 1 | `6a08ad8` | 首次实现 Plugin Command、Settings、Secret API 和前端 Service | +| 2 | `c3ef9df` | 收紧 Plugin Secret、Provider 凭据和 Command 清单边界 | +| 3 | `9e680a0` | 补齐真实 MCP Command Target,限制 JSON Schema 外部引用 | +| 4 | `022c322` | 改造 Secret 引用,修复删除和卸载事务 | +| 5 | `c06b962` | 按 Draft 2020-12 资源作用域修复 Schema 引用解析 | +| 6 | `eb3464b` | 补回 MCP Command 信封中的普通 Settings | +| 7 | `d39ae72` | 收紧 Effect、必填设置和 MCP 运行时 Contract,修复测试盲点 | +| 合并 | `ff3da5d` | PR #10 合并进入 `main` | + +这段过程说明,Extension Core 的风险主要不在正常路径能否运行,而在不同入口是否共享同一套边界。HTTP、Provider Factory、Plugin Runtime、MCP Host、Settings Store 和测试 Fixture 只要有一个入口绕过限制,就可能形成跨命名空间访问、错误执行或假测试通过。 + +## 3. D-01:Plugin Secret 可被通用凭据接口或 Provider 引用 + +### 原因 + +初始实现把 Plugin Secret 存入已有 `EncryptedCredentialStore`,但只在 Plugin Settings API 中隐藏明文,没有为凭据 ID 建立用途隔离。通用凭据 API 可以读写或删除同名 ID,Provider 配置也可以把 Plugin Secret 的凭据引用当作自己的 API Key 使用。 + +此外,Command 能否读取 Secret 只依赖 Plugin 拥有 `secrets.use` 权限,没有继续限制到当前 Command 在 `commands.yaml` 中明确声明的字段。 + +### 后果 + +- 前端或其他模块可以覆盖、删除 Plugin 私有 Secret; +- Provider 可能把插件密钥发送给外部模型服务; +- 同一 Plugin 内权限较低的 Command 可以读取与自己无关的 Secret; +- API 没有回显明文并不代表 Secret 没有发生横向流动。 + +### 解决思路 + +Secret 隔离必须同时覆盖存储命名空间、公共 HTTP 入口、Provider 解析入口和 Command 字段级授权,不能只在返回 DTO 上隐藏值。 + +### 解决方案 + +- 将 `plugin.*` 设为 Plugin Settings 专用保留命名空间; +- 通用凭据查询、写入和删除接口拒绝访问该前缀; +- 在 `ProviderFactory` 外包一层 `ProviderCredentialResolver`,即使绕过 HTTP 配置校验也不能读取 Plugin Secret; +- Command 通过 `secrets` 字段声明允许读取的 Setting Key; +- Resolver 同时检查插件权限、字段是否存在、字段类型和 Command 声明; +- 未声明字段返回 `PLUGIN_SECRET_ACCESS_DENIED`,必填 Secret 未配置返回 `PLUGIN_SECRET_REQUIRED`; +- 审计事件不记录 arguments、effect 或 Secret。 + +## 4. D-02:Command 与 Settings 清单边界不完整 + +### 原因 + +YAML 解析成功只说明语法可读,并不代表清单结构满足宿主协议。初始校验对 `commands:` 空值、重复 Secret、未声明权限、无效执行目标、Settings 默认值及非有限数值边界等情况覆盖不足。 + +例如 YAML 中只有 `commands:` 时,解析结果是 `null` 而不是空数组;`NaN` 和正负无穷虽然属于 Python 浮点值,却不能成为可移植的表单边界。 + +### 后果 + +- 安装阶段可能放过无法执行的 Command; +- 空清单在后续遍历时变成内部异常,而不是稳定业务错误; +- 前后端对数值范围和默认值产生不一致理解; +- 重复声明或越过 Plugin 命名空间的 ID 会污染全局注册表; +- 错误只能到运行期暴露,定位成本更高。 + +### 解决思路 + +把 Plugin 包视为不可信输入,在安装阶段完成结构、语义和权限的完整验证,并将解析异常统一转换成稳定的 `ExtensionError`。 + +### 解决方案 + +- 要求 `contributes` 声明与 `commands.yaml`、`settings.yaml` 内容完全一致; +- 拒绝 `null` Command 列表、重复 ID、重复 Secret 和越过 Plugin 命名空间的标识; +- 执行目标只能在受控 `handler` 与当前 Plugin 的 `mcp_tool` 中二选一; +- 校验 `when`、Context、Location 和权限白名单; +- Settings 类型限定为 `string`、`number`、`boolean`、`select`、`secret`; +- 校验默认值、Select 选项、必填规则和最小/最大边界; +- 拒绝 `NaN`、正无穷和负无穷; +- 清单错误统一返回可定位的稳定错误码。 + +## 5. D-03:MCP Command Target 只有声明,没有真实执行链路 + +### 原因 + +初始 Command 执行器只支持宿主内置 Handler。接口和规划中虽然存在 MCP Command 的概念,但 Runtime 没有把 Command 绑定到 MCP 工具,也没有定义 Command Context、Settings 和 Secret 如何进入 MCP 请求。 + +直接复用 Agent `ToolRegistry` 看似省事,却会把“用户主动执行的插件命令”和“模型可自主调用的 Agent Tool”混成同一种能力。 + +### 后果 + +- MCP 插件声明的 Command 实际无法执行; +- 如果简单注册为 Agent Tool,模型可能绕过命令位置、Context 裁剪和 Secret 声明直接调用; +- Command 超时、Effect 和错误边界无法统一; +- 前端看到命令已注册,点击后却只能得到运行时错误。 + +### 解决思路 + +为 MCP Command 建立独立执行通道。它可以复用 MCP 连接,但不能自动进入 Agent Tool Registry;宿主负责构造固定协议信封并验证返回的白名单 Effect。 + +### 解决方案 + +- `commands.yaml` 支持当前 Plugin 命名空间内的 `mcp_tool` 目标; +- Runtime 在 Plugin 启用后绑定目标,在禁用、异常退出和重启时同步注销; +- MCP Command 不注册到 Agent `ToolRegistry`; +- 宿主只传递已校验 arguments、已裁剪 Context、有效 Settings 和当前 Command 声明的 Secret; +- MCP 返回结果必须转换成受控 Effect; +- 远程原始异常、过大结果和超时统一映射为稳定宿主错误。 + +## 6. D-04:JSON Schema 外部引用可能触发越权 I/O + +### 原因 + +Command 和 MCP Tool 都接受插件提供的 JSON Schema。初始实现直接交给校验器处理 `$ref` 或 `$dynamicRef`,没有限制引用 URI。恶意或错误 Schema 可以引用本地文件、HTTP 地址或其他外部资源。 + +### 后果 + +- Schema 校验可能读取宿主文件或发起未授权网络请求; +- 安装一个插件就可能产生隐式 I/O; +- 离线环境中校验结果不稳定; +- 外部资源变化会让相同插件包得到不同验证结果; +- Command 和 Agent Tool 如果采用不同规则,会出现新的绕过路径。 + +### 解决思路 + +当前阶段不需要跨文件 Schema。宿主应只允许当前文档内部的 Fragment 引用,并在注册阶段递归检查所有 Schema 节点。 + +### 解决方案 + +- Command 与 Tool 共用 `schema_security` 校验边界; +- 递归扫描 `$ref` 和 `$dynamicRef`; +- 只允许以 `#` 开头的当前文档 Fragment; +- 拒绝文件、HTTP 和其他外部资源 URI; +- 无法解析的本地引用在安装或注册阶段直接失败; +- 运行期继续使用官方 Draft 2020-12 Validator 校验数据。 + +## 7. D-05:Secret 引用可被篡改并跨凭据命名空间 + +### 原因 + +初始 Settings 文件保存的 Secret 引用由可读的 Plugin ID 和 Setting Key 拼接而成。长度随名称增长,而且 Runtime 读取引用时默认信任磁盘内容,没有重新确认该引用确实属于当前字段。 + +本地文件损坏或被篡改后,一个 Plugin Setting 可以被改为指向 Provider 凭据或另一个 Plugin 的 Secret。 + +### 后果 + +- 长 Plugin ID 和 Setting Key 可能超过凭据 ID 长度限制; +- Settings 文件泄露内部字段名称; +- 篡改引用可能造成跨命名空间读取或删除; +- 卸载一个插件时可能误删其他模块的凭据。 + +### 解决思路 + +Secret 引用应由宿主确定性生成,长度固定,并在每次敏感操作前由当前 `plugin_id + setting_key` 重新计算,而不是信任持久化文件。 + +### 解决方案 + +使用以下语义生成引用: + +```text +plugin. +``` + +- 引用长度固定且符合凭据 ID 规则; +- Settings Store 只保存引用和 `configured` 状态,不保存明文; +- 读取、覆盖、删除和卸载前重新计算期望引用; +- 引用不匹配时按损坏存储拒绝处理; +- 增加跨命名空间篡改回归测试。 + +## 8. D-06:Secret 删除和插件卸载缺少事务一致性 + +### 原因 + +Secret 同时涉及 Settings 引用文件和加密凭据文件。初始删除流程按顺序修改两个存储,但任一步失败都没有完整回滚。插件卸载多个 Secret 时逐条删除,执行到一半失败会留下部分清理状态。 + +### 后果 + +- Settings 显示未配置,但密文仍残留; +- 凭据已删除,Settings 却仍显示已配置; +- 多 Secret 卸载可能只删除前几项; +- 重试操作无法判断上一次执行到哪里; +- 用户以为插件卸载已清除密钥,实际磁盘仍可能保留数据。 + +### 解决思路 + +把引用更新和凭据删除看作一个逻辑事务。底层单文件凭据表应一次构造新状态并原子替换;跨 Settings 与 Credential Store 的操作需要显式补偿回滚。 + +### 解决方案 + +- `EncryptedCredentialStore` 增加多凭据原子删除; +- 先验证全部目标引用,再生成新的凭据表; +- 通过临时文件和原子替换一次提交; +- 删除单个 Secret 时,凭据删除失败则恢复原 Settings 引用; +- 卸载 Plugin 时,批量删除失败则恢复完整 Settings 命名空间; +- 错误统一转换为稳定存储错误,避免部分成功被当作完整成功。 + +## 9. D-07:Schema 引用校验忽略嵌套 `$id` 资源作用域 + +### 原因 + +第一版本地引用检查把整个 Schema 当成单一 Fragment 树,用根文档指针或 Anchor 查找所有引用。Draft 2020-12 允许嵌套 `$id` 创建新的 Schema Resource;资源内部的 `#anchor` 应相对于新的 Base URI 解析,根资源也不能反向使用嵌套资源的 Anchor。 + +### 后果 + +- 合法的嵌套资源引用被误拒绝; +- 根 Schema 可能错误引用只属于子资源的 Anchor; +- 宿主预检结果与官方运行时 Validator 不一致; +- 同一 Schema 在安装阶段通过,却可能在执行阶段失败,反之亦然。 + +### 解决思路 + +安全限制仍然是“禁止外部资源”,但本地资源内部的解析语义必须遵守 JSON Schema 标准,不能自己用字符串和全局 Anchor 集合近似实现。 + +### 解决方案 + +- 引入与 Draft 2020-12 Validator 配套的 Resource Registry; +- 为根资源和嵌套 `$id` 建立正确作用域; +- 每个引用按其所在资源的 Base URI 解析; +- 保留外部资源拒绝策略; +- 增加“根资源不能使用子资源 Anchor”和“子资源可使用自身 Anchor”的成对测试。 + +## 10. D-08:MCP Command 未收到普通 Settings + +### 原因 + +真实 MCP Command 链路补齐后,固定信封传递了 Command ID、Arguments、Context 和 Secret,但遗漏了已经通过 Schema 校验的普通 Settings。声明式内置 Handler 能读取 Settings,MCP Handler 却不能,两个执行目标语义不一致。 + +### 后果 + +- 用户在插件设置页修改普通配置,对 MCP Command 不生效; +- 插件只能把非敏感设置错误地编码进 arguments 或 Secret; +- 内置 Handler 测试通过会掩盖 MCP 路径的缺口; +- 插件从内置实现迁移到 MCP 后行为发生变化。 + +### 解决思路 + +内置 Handler 与 MCP Command 应消费同一份运行时配置。差别只在执行介质,不在 Command Contract。 + +### 解决方案 + +- MCP 固定信封增加 `settings`; +- Settings 由 `PluginSettingsStore.runtime_values()` 产生; +- 只传递当前 Plugin Schema 中有效的非敏感字段; +- Secret 继续放在独立 `secrets` 命名空间; +- Fixture 回显非敏感配置用于断言,但不回显 Secret; +- 增加 Settings 实际到达 MCP Server 的集成测试。 + +## 11. D-09:Command Effect 是任意字典,前后端边界过宽 + +### 原因 + +初始 `PluginCommandEffect` 只有 `type` 和任意 `payload`。宿主虽然限制 Effect 名称和总体大小,却没有限制 Payload 字段、路由名称、刷新范围或通知级别。前端 TypeScript 也只能把 Payload 当成普通对象处理。 + +### 后果 + +- 插件可以返回前端从未支持的字段和路由; +- 前端需要在运行时猜测 Payload 结构; +- `navigate` 或 `refresh` 可能越过宿主允许的目标; +- OpenAPI 无法表达不同 Effect 的必填字段; +- 无效 Effect 往往要到页面执行时才暴露。 + +### 解决思路 + +Effect 是宿主能力协议,不是插件任意消息。每种 Effect 都应是独立、封闭、可判别的 Contract,并在进入 HTTP 响应前完成验证。 + +### 解决方案 + +- 后端建立 `notification`、`navigate`、`refresh`、`job`、`none` 五类模型; +- 使用 `type` 作为 Pydantic 判别字段; +- 限制通知级别、消息长度、路由白名单、刷新 Scope 和 Job ID; +- TypeScript 同步为精确的判别联合; +- OpenAPI `PluginCommandResult.effect` 生成 `oneOf` 和 discriminator; +- 保留可序列化性和 64 KiB 总大小限制作为第二层保护。 + +## 12. D-10:必填普通设置没有阻止启用和执行 + +### 原因 + +初始 Runtime 会合并已保存值和默认值,却没有检查 `required` 且没有默认值的普通字段是否仍为空。Secret 已有独立缺失检查,因此测试容易只覆盖 Secret,忽略普通 Settings。 + +### 后果 + +- 配置不完整的 Plugin 仍可启动 MCP Host; +- Command 到插件内部才因缺少字段失败; +- 用户只能看到模糊执行错误,不知道应先补配置; +- 插件启用后删除必填值,后续执行没有再次校验。 + +### 解决思路 + +必填设置既是启用前置条件,也是每次执行的运行时不变量。不能只在保存表单时校验,因为磁盘内容可能变化,启用后的配置也可能被更新。 + +### 解决方案 + +- `runtime_values()` 返回完整有效普通 Settings; +- 缺少必填且无默认值的字段时抛出 `PLUGIN_SETTINGS_REQUIRED`; +- Plugin Enable 前执行一次检查,不启动无效 Host; +- 每次 Command Execute 前重新检查; +- 返回 409 和缺失字段上下文,便于前端引导用户进入设置页; +- 增加“补齐设置后可启用”的完整回归测试。 + +## 13. D-11:MCP 工具 Schema 被发现后丢弃,真实信封未校验 + +### 原因 + +MCP 初始化阶段能够取得工具名称和 `inputSchema`,但 Runtime 记录只保留了工具名。Command 执行时直接发送宿主信封,没有用目标工具的完整 Schema 校验实际数据。 + +这意味着插件只要暴露同名工具就可能通过启用检查,即使它根本不接受 NotesAgent Command 协议。 + +### 后果 + +- 不兼容目标在启用阶段被注册为可执行 Command; +- 错误推迟到远程 MCP Server,返回信息不稳定; +- Context、Settings 或 Secret 结构变化时无法在宿主边界发现漂移; +- 前端看到可用命令,执行后才得到 502; +- 禁用或重启后若 Schema 缓存不清理,还可能使用过期契约。 + +### 解决思路 + +发现阶段保留完整目标 Schema;启用阶段只检查最低协议标记;执行阶段再用真实数据验证全部约束。Schema 生命周期必须和 MCP 工具生命周期一致。 + +### 解决方案 + +- Plugin 运行记录增加 MCP Command Schema 映射; +- 禁用、回滚、重启和 Host 不可用时同步清理 Schema; +- 启用时要求目标 Schema 顶层直接声明 `properties._notesagent`,且类型为 `object`; +- 执行前构造完整固定信封; +- 使用官方 Draft 2020-12 Validator 校验真实信封; +- 不匹配时返回 `PLUGIN_COMMAND_TARGET_SCHEMA_MISMATCH`,不调用 MCP Server。 + +## 14. D-12:启用探测和回归测试存在假阳性或假阴性 + +### 原因 + +审阅期间先后暴露了三类测试方法问题: + +1. 启用阶段曾用空 arguments、Context、Settings 和 Secret 伪造信封,以判断目标 Schema 是否兼容。合法 Schema 如果要求真实业务字段,会被错误拒绝; +2. 为避免空数据误判,曾尝试加入自定义 JSON Schema 可满足性求解,但该近似实现无法正确覆盖 `not`、`oneOf` 等完整 Draft 2020-12 语义; +3. MCP Secret Fixture 即使没有收到 `api_key` 也会返回成功,测试只验证了命令成功,没有证明 Secret 真正到达服务端。 + +最后还发现空 Echo 消息会构造 `notification`,但新的通知 Contract 要求消息非空,导致合法空输入被包装为 502。 + +### 后果 + +- 合法插件可能在启用阶段被拒绝,形成假阴性; +- 不兼容 Schema 可能被自定义求解器放过,形成假阳性; +- Secret 传递链路回归后测试仍显示通过; +- Contract 收紧后,旧 Fixture 的边界值会产生新的运行时错误; +- 测试数量增加,却没有真正覆盖需要证明的安全事实。 + +### 解决思路 + +启用阶段只做稳定且明确的协议结构检查,完整 Schema 语义交给官方 Validator 和真实执行数据。测试必须让目标事实缺失时明确失败,而不是通过返回值间接猜测。 + +### 解决方案 + +- 取消空业务数据 Probe; +- 将启用门槛缩小为直接 `_notesagent: { type: object }` 协议标记; +- 允许 `$ref`、`$dynamicRef`、`allOf`、`anyOf`、`oneOf` 和 `not` 等约束出现在 `_notesagent` 内部; +- 完全移除自定义 Schema 可满足性求解器; +- 实际执行统一交给官方 Draft 2020-12 Validator; +- MCP Fixture 未收到声明的 Secret 时主动返回 MCP 错误,但永不返回明文; +- 空 Echo 返回 `none` Effect,非空 Echo 返回 `notification`; +- 为协议标记、真实信封、Secret 到达、空 Echo 和恶意 Effect 分别增加回归测试。 + +## 15. 验证方法与结果 + +本分支最终执行以下验证: + +```powershell +cd backend +uv lock --check +uv run pytest + +cd ../frontend +pnpm test -- --run +pnpm type-check +pnpm build + +cd .. +git diff --check +``` + +结果: + +```text +backend: 136 passed +frontend: 29 passed +TypeScript type-check passed +frontend production build passed +uv lock --check passed +git diff --check passed +``` + +后端测试在 Windows 下仍有既有 `.pytest_cache` 权限警告,不影响测试结果。前端生产构建仍有既有大 Chunk 提示,不影响本次功能正确性和合并结论。 + +新增或强化的关键测试包括: + +- Plugin Secret 公共 API、Provider Resolver 和 Command Resolver 三层隔离; +- 清单空值、重复项、无效权限、非有限边界和非法 Schema; +- MCP Command 与 Agent Tool 隔离; +- 固定信封中的 Context、Settings 和声明式 Secret; +- 外部 Schema 引用拒绝和嵌套 `$id` 资源作用域; +- Secret 定长引用、篡改阻断、删除回滚和卸载原子性; +- 五类 Effect 的合法 Payload 和恶意 Payload 拒绝; +- 必填普通设置对 Enable 和 Execute 的双重门禁; +- MCP 实际信封校验、Secret 到达证明和空 Echo 行为。 + +## 16. 预防措施 + +- Plugin 包、MCP Schema 和 MCP 返回值一律按不可信输入处理; +- Secret 安全检查必须覆盖写入、读取、删除、解析、传输和审计全链路; +- 保留命名空间需要在公共 API 和内部 Resolver 两侧同时阻断; +- 多存储更新必须设计原子提交或补偿回滚,并测试中途失败; +- 不自行实现通用 JSON Schema 求解器,标准语义交给官方 Validator; +- 启用阶段只检查静态协议能力,不使用伪业务数据推导可执行性; +- Agent Tool 和用户触发的 Plugin Command 必须保持独立注册和权限边界; +- Pydantic Contract、OpenAPI、TypeScript DTO 和测试 Fixture 在同一提交中同步; +- 回归测试应直接证明目标事实,例如“Secret 确实到达且未落盘”,不能只证明接口返回成功; +- 每次收紧 Contract 后,重新检查空值、默认值、最大值和旧 Fixture 等边界输入。 + +## 17. 当前边界与后续事项 + +本次合并完成的是阶段 D 的宿主协议和开发期运行边界,不等于第三方插件已经具备生产级操作系统隔离。 + +当前仍保留以下后续事项: + +- 阶段 C.5 按规划放在第二阶段功能与测试完成后、第三阶段桌面集成正式构建 Tauri/Rust 沙箱之前; +- 生产环境继续通过配置门禁拒绝未沙箱化的 MCP Host; +- 桌面端将 Plugin Secret 从开发期 Fernet 文件迁移到 Stronghold 或系统 Keychain,保持现有引用和 HTTP Contract; +- 前端后续实现命令面板、上下文菜单和动态 Settings 表单,继续复用现有 Service; +- Command 审计当前是 500 条有界内存队列,长期审计持久化需在后续阶段单独设计; +- 前端大 Chunk 应通过路由和 Markdown 依赖拆包处理,不与本次 Extension Contract 修改混合。 + +## 18. 复盘结论 + +本次最重要的经验是:插件系统的正确性不能只按“命令是否执行成功”判断。真正需要审阅的是数据从清单进入注册表、从 Settings 进入运行时、从 Secret Store 进入执行器、从宿主信封进入 MCP,以及从 MCP Effect 返回前端的每一道边界。 + +连续审阅避免了跨命名空间 Secret 访问、非事务删除、外部 Schema I/O、MCP 伪兼容和任意 Effect 等问题进入 `main`。最终实现把每个边界落到明确 Contract、稳定错误码和可失败的回归测试上,为下一阶段前端集成和桌面安全沙箱提供了可复用基础。 diff --git a/docs/retrospectives/前端合并审阅问题与修复复盘.md b/docs/retrospectives/前端合并审阅问题与修复复盘.md index 2643ef3..27ed505 100644 --- a/docs/retrospectives/前端合并审阅问题与修复复盘.md +++ b/docs/retrospectives/前端合并审阅问题与修复复盘.md @@ -4,7 +4,7 @@ > 涉及提交:`f9efc4f`,合并提交 `c6c28e4`。 > 文档用途:记录前端分支合并后暴露的问题域、形成原因、实际后果、修复思路和落地方案,供后续技术文档、比赛材料与博客写作使用。 -> 2026-08-30 状态补充:在本文两轮修复之后,项目又完成 Milkdown 写作工具栏、文件切换二次竞态修复、Shiki 只读高亮、Provider 预设/模型发现/加密 API Key 输入,以及智能体页面汉化。当前前端回归基线为 14 项测试和生产构建通过。 +> 2026-09-02 状态补充:在本文多轮修复之后,项目又完成 Milkdown 写作工具栏、文件切换二次竞态修复、Shiki 只读高亮、Provider 预设/模型发现/加密 API Key 输入、智能体页面汉化,以及 Plugin Command/Settings Service。当前前端回归基线为 29 项测试,TypeScript 类型检查和生产构建通过。 ## 1. 结论 @@ -281,4 +281,4 @@ git diff --check passed 第三轮交互完善继续处理了文件切换、Markdown 选区格式、代码块默认状态、亮暗主题对比度和浮动工具栏失效问题。Provider 设置页增加 OpenAI、DeepSeek、Ollama 预设与模型自动发现,API Key 改为提交给后端加密保存,不进入 Pinia 或 Local Storage。智能体页面的运行状态、事件、工具、权限及导航文案已完成中文化,同时保留技术 ID 便于排障。 -该轮新增 Store、Workspace、文件树、编辑器和中文标签回归测试;当前结果为前端 14 项、后端 71 项测试通过,生产构建通过。 +该轮新增 Store、Workspace、文件树、编辑器和中文标签回归测试;该轮当时结果为前端 14 项、后端 71 项测试通过,生产构建通过。最新全仓基线见本文开头的状态补充。 diff --git a/docs/retrospectives/后端全面审阅问题与修复复盘.md b/docs/retrospectives/后端全面审阅问题与修复复盘.md index 370bc7c..eef08de 100644 --- a/docs/retrospectives/后端全面审阅问题与修复复盘.md +++ b/docs/retrospectives/后端全面审阅问题与修复复盘.md @@ -4,7 +4,7 @@ > 审阅范围:FastAPI、Knowledge / Retrieval Core、Agent Core、Extension Core、Provider Adapter、公共接口和后端开发文档。 > 文档用途:记录问题形成原因、实际影响、修复判断和落地方案,供后续开发文档、比赛材料与技术博客使用。 -> 2026-09-02 状态补充:本文记录的缺陷均保持修复。此后又加入 Provider 预设、模型发现、DeepSeek/OpenAI 凭据解析、Fernet 加密存储、Agent Trace 持久化、stdio MCP Plugin Host 和 Plugin Command/Settings,当前完整后端回归基线为 126 项测试通过。 +> 2026-09-02 状态补充:本文记录的缺陷均保持修复。此后又加入 Provider 预设、模型发现、DeepSeek/OpenAI 凭据解析、Fernet 加密存储、Agent Trace 持久化、stdio MCP Plugin Host 和 Plugin Command/Settings,当前完整后端回归基线为 136 项测试通过。 ## 1. 审阅结论