Repository navigation
目录排除规则统一到全应用
Flymd 有一套目录排除规则,用来把模板 / 附件目录挡在 AI 的视野之外。
但它此前只管住了 MCP 一条通道——其余三条 AI 通道各走各的:
| AI 通道 | 此前 |
|---|---|
| MCP 客户端 | ✅ 完整生效 |
定时任务(YAML recipes 的 {{files}}) |
❌ 全树遍历,无过滤 |
| AI 助手的知识库(flymd-RAG) | ❌ 插件自己的 excludeDirs,默认空 |
| 插件的库文件枚举 | ❌ 无全局规则 |
于是同一个模板目录,在 MCP 里 AI 看不见,在定时任务与知识库里却能出现。
边界只是「看起来有」,实际并不成立。
现在一套规则,全应用生效。
规则仍然只有一份实现
实现在 Rust 的 flymd_mcp::config::McpConfig 里。桌面应用本来就以路径依赖引入了
mcp-server 的 lib 目标(当初为共享 AI 写入护栏核心),所以把已有能力暴露给应用即可:
- 不复刻第二份匹配逻辑——不存在「两边规则慢慢漂移」的问题
- 不给应用新增任何依赖
- 判定放在 Rust 侧,一次 IPC 判一批,插件与宿主零规则副本
具体落点:
flymd_list_markdown_files改为按规则剪枝遍历——被排除的目录整棵不进结果- 新增两个命令:
flymd_ai_scope(取生效规则)、flymd_ai_scope_filter(批量判定) - 插件侧新增
context.getAiScope()/context.filterAiExcludedPaths()
配置文件改名
<库根>/.flymd/mcp.json → <库根>/.flymd/ai-scope.json(它现在管的不只是 MCP)。
旧名继续生效——两个文件都读、都合并,用户已有的配置不会因为改名而失效。
AI 助手的知识库自动继承
flymd-RAG 的批量路径走宿主的 listLibraryFiles,宿主已经过滤过,零改动继承。
它的增量监听路径绕过 listLibraryFiles(走文件 watcher),单独补了判定。
如果某个模板目录此前已被索引进知识库,需要重建一次索引才会清掉。
插件 API
新增库内受限读写
context.readLibraryFile() / context.writeLibraryFile():
库根约束 + 排除规则约束的库内文件读写,写入自动留 AI 写入护栏快照,可回滚。
修复:AI 助手的「TODO 便签」
此前它调用的 read_text_file_any / write_text_file_any 在插件 denylist 里
(denylist 落地在那次调用之后 1206 个提交,加 denylist 时没扫到这处调用),
所以这个功能一直是坏的,用户看到的是「读取 TODO 文件失败」。
现在改走库内受限读写。
没有给 denylist 开特例——那两个命令接受任意绝对路径,放进 denylist 是对的。
新 API 是「受限入口」,不是「放开原有入口」。
补记文档
context.aiGuardList() / context.aiGuardRollbackLast() 此前没有写进插件文档,现已补上。
安全边界
- 库根由宿主决定,不接受插件传入(与
ai_guard_*同一条规矩) - 路径必须是库内相对路径:绝对路径、前导斜杠、
..越界一律拒绝
(前导斜杠也拒绝——约定与 MCP 的resolve_write_path一致) - 落在被排除目录里的路径拒绝读写:AI 不该看见的地方,插件也不该碰
- 判定失败时拒绝放行——宁可一次合法写入被拒,也不能在规则失效时放行
版本号约定调整
此前一天之内连发 v2.0.0 → v2.0.1 → v2.1.0 → v2.2.0,minor 位在六小时内从 0 走到 2。
这样 minor 号承载不了「这次带来了什么」的信息。
从 v2.2.1 起改为:
- 第三位(patch) 承载日常增量:功能补齐、一致性修复、bug 修复、文档
- 第二位(minor) 留给成规模的版本
- 第一位(major) 留给破坏性变更
MCP 服务器同理:0.3.0 → 0.3.1。
验证
- 新增 5 个 Rust 单测(
src-tauri)+ 3 个 MCP 单测 + 12 个 TS 单测 - MCP 服务器 60 个单测、桌面应用侧 27+15 个单测、前端 1141 个测试全过
- typecheck 与构建门禁通过,mcp-server clippy 零警告
- 真实库实测:AI 视角的待办里,模板目录下的 30 条假待办全部不可见
- 新旧配置文件名均实测生效