skills-manage-readme.md 23 KB

skills-manage 项目调研报告

调研对象:skills-manage/ 目录,版本 0.10.0,Apache-2.0 项目定位:跨平台 AI 编码 Agent 技能管理桌面应用(Tauri v2 + React + Rust + SQLite) 参考用途:为本项目的"技能(Skill)"管理能力提供桌面端借鉴(多平台分发、符号链接、市场导入、AI 解释)


一、项目概览

skills-manage 是一个桌面端的 AI 技能中央管理器。核心思想:

  • ~/.agents/skills/ 作为唯一中央目录(canonical source of truth),所有 SKILL.md 物理上只在这里存一份
  • 各 AI 编码工具(Claude Code / Cursor / Gemini CLI / Codex / Hermes 等 27+ 个平台)通过符号链接(symlink)接入,达到"一份技能、多平台共享"
  • 提供"中央库 / 平台视图 / 项目发现 / 市场 / 集合"五种视角,把散落的技能统一收编、批量分发

它遵循 Anthropic Agent Skills 开放模式,SKILL.md 用 YAML frontmatter 声明 name / description


二、技术栈

总体架构

React 前端 (src/)
    ↓ Tauri IPC(invoke() 调 #[tauri::command] 函数,50+ 个命令)
Rust 后端 (src-tauri/src/)
    ↓ SQLx 异步驱动
SQLite 数据库(~/.skillsmanage/db.sqlite,WAL 模式)

各层技术选型

技术 关键依赖
桌面框架 Tauri v2 tauri 2 + 4 个官方插件(sql/fs/dialog/shell)
前端框架 React 18 + TypeScript 5.8 reactreact-dom
UI 组件 shadcn/ui(base-ui + Tailwind CSS 4) @base-ui/reacttailwindcss 4class-variance-authoritytailwind-mergelucide-react
路由 React Router v7 react-router-dom ^7.5.0
状态管理 Zustand 5 zustand ^5.0.3(每业务域一个 store)
国际化 i18next + react-i18next 中英双语,fallbackLng: "zh"
Markdown react-markdown + remark-gfm 前端展示;后端解析用 serde_yaml
主题 Catppuccin 4 flavor × 14 accent 自定义 data-theme / data-accent HTML 属性
构建 Vite 6 + tsc dev 端口 24200
后端语言 Rust 2021 serdechronouuid
数据库 SQLite via sqlx 0.8 sqlx { sqlite, runtime-tokio } + WAL 模式
HTTP reqwest 0.12 jsonrustls-tlsstream,用于 GitHub API + AI 解释
压缩 flate2 + tar 解 GitHub tarball 到内存快照
YAML serde_yaml 0.9 解析 SKILL.md frontmatter
测试 Vitest 3 + jsdom + RTL(前端);cargo test + tempfile(后端) 前端 370+ 用例,后端 214+ 用例

为什么选 Tauri 而非 Electron

从代码可推断(README 未明说):

  1. Rust 原生提供跨平台文件系统与 symlink 能力(std::os::unix::fs::symlink vs std::os::windows::fs::symlink_dir
  2. SQLx 直连 SQLite,无需 Electron 常见的 better-sqlite3 等原生 Node 模块
  3. 产物体积小、启动快;官方插件机制成熟(sql/fs/dialog/shell)

为什么用 SQLite WAL 模式

db.rs:113 显式 PRAGMA journal_mode=WAL——允许读(UI 查询)与写(扫描 upsert)并发,避免扫描大量项目期间 UI 卡顿;同时嵌入式零配置,跨平台单文件。

为什么不用 sqlx::query_as!

宏要求编译期 DATABASE_URL 连接真实库做类型校验,对 CI 和开发者机构成负担。全项目统一 sqlx::query() + Row::get() 手动映射。


三、技能管理的具体逻辑

3.1 核心概念与数据模型

概念 说明 存储
Skill 一个含 SKILL.md(YAML frontmatter)的目录 skills
Agent(平台) AI 编码工具(Claude Code / Cursor / Codex / Hermes / Copilot 等 27+ 内置) agents
中央目录 ~/.agents/skills/,技能的唯一权威位置 由特殊 agent id=central 标记
安装(Installation) 中央 → 平台的符号链接/复制关系 skill_installations 表(复合主键 skill_id+agent_id)
观测(Observation) 每次扫描平台目录时的技能快照,用于区分"平台原生/只读/本应用安装" agent_skill_observations
集合(Collection) 用户自定义的技能分组,可批量安装 collections + collection_skills(多对多)
市场源(Registry) GitHub 仓库,作为远程技能目录 skill_registries 表(带 etag/last-modified 缓存)
市场技能 远程同步下来的技能元数据 marketplace_skills
发现(Discover) 全盘扫描到的项目级技能 discovered_skills
AI 解释缓存 (skill_id, lang) 缓存的 AI 说明 skill_explanations
设置 KV 存储(github_pat / ai_api_key / ai_model 等) settings

支持的 27+ 平台(节选):Claude Code、Codex CLI、Cursor、Gemini CLI、Trae、Factory Droid、Junie、Qwen、Windsurf、Qoder、Augment、OpenCode、KiloCode、OB1、Amp、Kiro、CodeBuddy、Hermes、Copilot、Aider;以及国内"龙虾系"(OpenClaw / QClaw / EasyClaw / AutoClaw / WorkBuddy)。特殊:central 即中央目录本身。

3.2 技能识别:SKILL.md frontmatter 解析

scanner.rs::parse_skill_md(scanner.rs:120):

  1. 平台/中央目录的直接子目录中是否含 SKILL.md
  2. 文件首行必须是 ---,截取至下一个 \n--- 作为 frontmatter
  3. serde_yaml 0.9 解析(不引入完整 markdown 解析器)
  4. name 必填(缺失静默跳过),description 可选

扫描时同步 upsert skills 表,并刷新 agent_skill_observations 记录观测。

3.3 技能安装链路(重点)

入口:前端 centralSkillsStore.batchInstall 或卡片图标单击 togglePlatformLinkinvoke("batch_install_to_agents" | "install_skill_to_agent", { skillId, agentIds, method })

核心流程linker.rs::install_skill_to_agent_impl,:254):

1. 禁止安装到 central 自身
2. 查 agent 与 central agent,确定 canonical_dir
3. 【关键】ensure_centralized:
     if canonical_dir/SKILL.md 不存在:
        从 DB 取该技能当前实际 file_path
        将其所在目录 copy_dir_all 到中央目录
        回写 DB 的 canonical_path / is_central=true / file_path
     → "仅存在于某平台的技能被自动收养进中央目录",调用方对此透明
4. 支持"通用 ~/.agents/skills" 的平台(universal_available)直接返回成功
5. 目标已存在 symlink → 删除重建
   目标已存在真实目录/文件 → 拒绝覆盖,报错(防误删用户手动放置的技能)
6. 计算相对路径 symlink_target_path(Windows 跨盘符时回退绝对路径)
7. 创建 symlink → upsert skill_installations (link_type="symlink")

回退策略install_skill_to_agent_auto_impl,:338):

  • Windows 上当错误信息含 "Failed to create symlink"(典型为无开发者模式/权限不足)时,自动回退到 install_skill_to_agent_copy_impl 整目录复制
  • Unix 上不回退,直接报错——保持行为可预期

为什么用相对路径 symlink:用户移动整个 home 目录或同步到另一台机器时链接不失效。

3.4 卸载链路

linker.rs::uninstall_skill_from_agent:删除 symlink/copy 目录 → 删除 skill_installations 行。中央目录的物理目录不动,仅断开分发关系。

3.5 Discover:全磁盘项目级技能发现

discover.rs::start_project_scan(:1387):

  • 扫描根:默认 10 个候选(~/projects~/Documents~/Developer/Applications 等),存在的自动启用;叠加用户在 settings 里加的自定义目录
  • 递归策略
    • 最大深度 MAX_SCAN_DEPTH = 8
    • 黑名单 SKIP_DIRS:node_modules / target / .git / build / dist / .next / venv 等 16 个
    • 深度 0 跳过 . 开头的隐藏目录,深层放行以命中 .claude/skills.agents/skills 等模式
    • 匹配模式来自各内置 agent 的 project_skills_dir
  • 进度流式推送:通过 app.emit("discover:progress" | "found" | "complete"),前端 store 订阅
  • 取消:全局 SCAN_CANCEL: AtomicBool + thread-local 覆盖(测试隔离)
  • is_already_central 实时重算:每次从 DB 加载时检查 ~/.agents/skills/<dir_name> 是否存在,不是静态快照
  • 导入import_discovered_skill_to_central / import_discovered_skill_to_platform特意不删 discovered 记录,以支持连续导入到多个平台

3.6 Marketplace:GitHub 远程技能市场

抓取方式github_import.rs::download_repository_archive,:824):

  • 不用 Git Trees API,而是 GET /repos/{owner}/{repo}/tarball/{branch} 整包下载
  • flate2::GzDecoder + tar 解压到内存快照
  • classify_skill_manifest_path 识别三种布局:
    • 根 SKILL.md(单技能仓库)
    • 根级 <dir>/SKILL.md(多技能仓库,排除 .github
    • skills/**/SKILL.md(含 .curated/.system 命名空间子目录)

认证与限流

  • github_pat 从 settings 表读取(github_import.rs:649
  • 仅对直连 github.com 请求附带 token,镜像请求不带(避免泄漏)
  • GITHUB_MIRROR_ENDPOINTS:github 直连 + ghfast.top / ghproxy.net / mirror.ghproxy.com 三个国内镜像,403/429 时依次回退
  • x-ratelimit-remaining/reset 头构造结构化错误(含可操作建议的中文提示)

缓存策略

  • 同步结果 upsert marketplace_skillsON CONFLICT(id) DO UPDATE
  • 非 force 刷新 + 有缓存 → 直接返回缓存
  • force 刷新失败 → 保留 last-good 缓存,只更新 last_sync_status="error"
  • 内置源(is_builtin=true)禁止删除;删除自定义源会先清掉其缓存技能

安装install_marketplace_skill 直接 GET download_url(raw.githubusercontent.com 直链)→ 写 ~/.agents/skills/<name>/SKILL.md注意:仅下载单文件 SKILL.md,不带附属文件;完整仓库需走 import_github_repo_skills

3.7 AI 解释(Skill Explanation)

marketplace.rs::explain_skill_stream(:1307):

  • 协议探测:按 ai_api_url 路径后缀区分 Anthropic(/v1/messages + x-api-key + anthropic-version)与 OpenAI 兼容(/v1/chat/completions + Authorization: Bearer
  • Prompt 构造:SKILL.md 内容截断 8000 字符;中英双语模板要求"一句话总结 + 适用场景 + 关键功能点,200 字以内"
  • 流式响应:SSE 按行解析;Anthropic 取 content_block_delta.delta.text(跳过 thinking_delta),OpenAI 取 choices[0].delta.content;每块 app.emit("skill:explanation:chunk") 推前端
  • 错误分类classify_reqwest_error 把 reqwest 错误分为 Proxy/Connect/Timeout/Dns/Tls/Auth/Response/Unknown,附中文可操作提示
  • 区域端点回退:MiniMax(minimaxi.com ↔ minimax.io)与 GLM(bigmodel.cn ↔ api.z.ai)在连接层失败时自动切换一次
  • 缓存skill_explanations 表按 (skill_id, lang) 存;INSERT OR REPLACE 保留原 created_at;空文本视为缓存腐败会删除并重新生成
  • 支持厂商:Anthropic / GLM / MiniMax / Kimi / DeepSeek / OpenRouter(src/data/aiProviders.ts 7 个预设)

3.8 集合(Collection)

collections.rs:分组管理 + batch_install_collection(对集合内每个技能 × 每个 agent 调 linker)+ JSON 导入/导出(CollectionExport { version, name, description, skills[], created_at, exported_from })。


四、IPC 命令清单(50+ 个)

按模块分组(lib.rs:41-112 注册):

模块 主要命令 职责
scanner scan_all_skills 全量扫描中央目录 + 所有启用平台
agents get_agents / detect_agents / add_custom_agent / update_custom_agent / remove_custom_agent 平台 CRUD;检测写回 is_detected
linker install_skill_to_agent / uninstall_skill_from_agent / batch_install_to_agents symlink/copy 安装与卸载
skills get_skills_by_agent / get_central_skills / get_central_skill_bundles / get_skill_detail / read_skill_content / list_skill_directory / open_in_file_manager / preview_delete_central_skill_bundle / delete_central_skill* 技能查询/内容/删除
collections create/get/update/delete_collection / add/remove_skill_to_collection / batch_install_collection / export/import_collection 集合管理
settings get/set_scan_directories / set_scan_directory_active / get_setting / set_setting 扫描目录 + KV 设置
discover discover_scan_roots / get_scan_roots / set_scan_root_enabled / start/stop_project_scan / get_discovered_skills / import_discovered_skill_to_central/platform / clear_discovered_skills / get_obsidian_vaults/skills 项目级技能发现
github_import preview_github_repo_import / import_github_repo_skills / fetch_github_skill_markdown GitHub 仓库导入(带进度事件 + 冲突解决)
marketplace list_registries / add/remove_registry / sync_registry(_with_options) / search_marketplace_skills / install_marketplace_skill / explain_skill(_stream) / get_skill_explanation / refresh_skill_explanation 市场源 + AI 解释

五、前端组织

5.1 路由

路由 页面文件 布局模式
/ → 重定向 /central
/central CentralSkillsView.tsx 技能卡片两列
/platform/:agentId PlatformView.tsx 技能卡片两列
/skill/:skillId SkillDetailPage.tsx 双栏:左 SKILL.md 预览全高,右 metadata + 紧凑图标式安装状态 + collections
/collections CollectionsListView.tsx / CollectionView.tsx 卡片横排选中 + 下方技能列表
/marketplace MarketplaceView.tsx 三 Tab:推荐 / 官方源目录 / 我的源
/discover, /discover/:projectPath DiscoverView.tsx 左面板项目列表 + 右面板技能详情
/obsidian/:vaultId ObsidianVaultView.tsx 独立视图
/settings SettingsView.tsx 卡片分区

5.2 Zustand Store(10 个)

约定:组件不直接 invoke(),一律走 store

Store 职责
centralSkillsStore 中央库 + bundle + 平台链接切换
platformStore 平台视图 + 全量扫描
skillStore 单平台技能列表
skillDetailStore 技能详情 + AI 解释流式订阅
collectionStore 集合 CRUD/批量安装/导入导出
discoverStore Discover 扫描与导入(监听 discover:* 事件)
marketplaceStore 市场三 Tab + GitHub 导入 + 解释
obsidianStore Obsidian vault
settingsStore 扫描目录 + GitHub PAT + 自定义平台
themeStore Catppuccin 主题(纯前端 localStorage,无 IPC)

5.3 共享组件

UnifiedSkillCardsrc/components/skill/UnifiedSkillCard.tsx):所有页面的技能卡片唯一实现,通过可选 props 自适应 5 种场景:

场景 特征 props
central platformIcons{agents, linkedAgents, readOnlyAgents, onToggle} 渲染 LOBSTER/CODING 两行图标即时切换
platform sourceType: "symlink"\|"copy"\|"native" + originKind + isReadOnly
discover checkbox{checked, onChange} + platformBadge + projectBadge + isCentral
marketplace isInstalled + tags[] + publisher
collection 复用基础 + onRemove

统一样式:rounded-xl ring-1 ring-border bg-card shadow-sm约定:不要为特定场景新建卡片组件

InstallDialogsrc/components/central/InstallDialog.tsx):

  • 打开时默认勾选"当前已链接(含只读)"的平台,反映现状
  • 确认时把勾选集合(剔除 read_only)+ 安装方式(symlink/copy 单选)传给 onInstall
  • 注意:该对话框只负责"安装到所选",取消勾选已链接平台不会触发卸载(卸载靠卡片图标 toggle 或平台视图)

5.4 i18n 与主题

  • 语言:仅 zh / en 两种语言包;fallbackLng: "zh";检测顺序 localStorage(i18nextLng) → navigator
  • 主题:Catppuccin 4 flavor(mocha / macchiato / frappe / latte)× 14 accent(rosewater … lavender)
  • 实现:themeStore.applyFlavor/applyAccent<html> 上写 data-theme / data-accent,持久化到 localStorage catppuccin-flavor / catppuccin-accentinit() 在渲染前调用防闪烁

六、必需依赖

6.1 开发期

类别 依赖 说明
运行时 Node.js LTS + pnpm package.jsonpnpm.onlyBuiltDependencies 声明 pnpm 专用
Rust stable toolchain(rustup) 2021 edition
系统库 Tauri v2 系统依赖 Windows:WebView2 + MSVC;macOS:Xcode CLT;Linux:webkit2gtk 等(详见 https://v2.tauri.app/start/prerequisites/
Rust crate tauri 2 + 4 插件 / sqlx 0.8 / serde_yaml 0.9 / reqwest 0.12 / flate2 / tar / chrono / uuid / futures-util src-tauri/Cargo.toml:16-31
前端依赖 react 18 / react-router-dom 7 / zustand 5 / i18next / tailwindcss 4 / @base-ui/react / lucide-react / cmdk / sonner / react-markdown / gray-matter package.json:17-44
测试 vitest 3 + jsdom + @testing-library/* / tokio(full) / tempfile 前端 370+ 用例,后端 214+ 用例

6.2 最终用户运行时

不需要 Node 也不需要 Rust——pnpm tauri build 产出平台原生安装包。

  • Windows:依赖系统 WebView2(Win10 1803+ 通常已内置;tauri.conf.json 配置 webviewInstallMode: embedBootstrapper 自动引导)
  • macOS:当前预编译包仅 Apple Silicon(.dmg / .app.zip),未 notarize,首次运行需 xattr -dr com.apple.quarantine
  • Linux:AppImage / deb / rpm 三形态

6.3 数据存储位置

数据 位置
应用数据库 ~/.skillsmanage/db.sqlite(含 collections / settings / 市场缓存 / AI 解释缓存)
中央技能目录 ~/.agents/skills/
各平台技能目录 ~/.claude/skills/ / ~/.cursor/skills/ / ~/.gemini/skills/ 等(由 agents 表 global_skills_dir 定义)
前端主题/语言偏好 localStorage

6.4 外网访问触发点(隐私说明)

应用本地优先,仅以下功能联网

功能 目标端点 是否带 token
Marketplace 源同步 / GitHub 仓库预览/导入 api.github.com + raw.githubusercontent.com;镜像回退 ghfast.top / ghproxy.net / mirror.ghproxy.com 直连 github.com 带 PAT;镜像不带
Marketplace 技能安装 raw.githubusercontent.com(download_url 直链) 不带
AI 技能解释 用户配置的 ai_api_url(Anthropic / GLM / MiniMax / Kimi / DeepSeek / OpenRouter) 带用户配置的 api_key

遥测:无;崩溃上报:无;凭证:仅存本地 SQLite settings 表(明文)。


七、关键技术决策(供本项目借鉴)

决策 价值 对应代码
~/.agents/skills/ 作为唯一中央目录 + symlink 分发 一份技能多平台共享,避免散落与不一致 path_utils.rs:45-47linker.rs:154
ensure_centralized 自动收养 仅存在于某平台的技能被自动拷贝进中央,调用方透明 linker.rs:154-195
相对路径 symlink 用户移动 home 目录链接不失效 linker.rs:89-100
拒绝覆盖真实目录 防误删用户手动放置的技能 linker.rs:301-312
Windows symlink 失败自动回退 copy 兼容无开发者模式的 Windows 环境 linker.rs:338-360
SQLite WAL + sqlx 手动映射 读写并发不卡 UI;避开 query_as! 宏对 DATABASE_URL 的依赖 db.rs:113、全项目
GitHub tarball 整包解压到内存 规避 Trees API 限流;flate2 + tar 流式 github_import.rs:824-870
镜像回退 + 限流头解析 国内可用性;结构化错误提示可操作 github_import.rs:219-240:1327-1341
AI 解释 (skill_id, lang) 缓存 + 空文本腐败检测 降本;防缓存损坏被永久复用 marketplace.rs:889-905
SSE 流式 + app.emit 前端无感知渲染;错误分类可操作 marketplace.rs:1220-1251
is_already_central 实时重算 避免静态快照过期导致的状态错乱 discover.rs:1445
前端组件不直接 invoke,统一走 store 便于测试 mock + 集中错误处理 src/test/setup.ts:88-95
Vitest 通过 window.__TAURI_INTERNALS__ mock IPC 前端单测无需启动真实 Tauri src/test/setup.ts:88-95

八、对本项目的借鉴意义

  1. 技能中央化 + 符号链接分发:本项目的 Skill 管理目前是单平台(agent-management 自己的库),可借鉴"中央目录 + 多平台 symlink"模式,把技能共享到 Claude Code / Cursor 等其他工具。
  2. SKILL.md frontmatter 用 serde_yaml 解析:与项目内已有的 Skill 解析逻辑可对照,避免重复造轮子。
  3. Discover 的扫描黑名单与深度限制MAX_SCAN_DEPTH=8 + 16 个 SKIP_DIRS):项目内做本地知识库或代码库扫描时可参考。
  4. GitHub tarball 整包 + 镜像回退 + 限流头解析:本项目已有从 GitHub 拉取 Skill 的需求时可复用此设计。
  5. AI 解释的协议探测 + 区域端点回退 + 缓存腐败检测:与本项目的 LLM 调用层设计可互鉴。
  6. is_already_central 实时重算:状态派生自文件系统而非数据库快照,避免缓存漂移——项目内做"技能是否已安装"判定可直接采用。

附录:文件结构速查

skills-manage/
├── src/                          # React 前端
│   ├── components/               # UI 组件(含 UnifiedSkillCard / InstallDialog)
│   ├── data/                     # officialSources.ts / aiProviders.ts 静态数据
│   ├── hooks/                    # 通用 hooks
│   ├── i18n/                     # zh.json / en.json / index.ts
│   ├── lib/                      # 前端工具
│   ├── pages/                    # 9 个路由页面
│   ├── stores/                   # 10 个 Zustand store
│   ├── test/                     # Vitest + RTL(370+ 用例)
│   ├── types/                    # 共享 TS 类型
│   ├── App.tsx                   # 路由声明
│   ├── main.tsx                  # 入口(含 theme init)
│   └── index.css                 # Catppuccin 4 flavor × 14 accent CSS 变量
├── src-tauri/
│   ├── src/
│   │   ├── commands/             # 10 个 IPC 模块(scanner/agents/linker/skills/collections/settings/discover/github_import/marketplace)
│   │   ├── db.rs                 # SQLite schema + 迁移 + 内置 seed(11 张表)
│   │   ├── path_utils.rs         # home 解析 + ~/.skillsmanage + ~/.agents/skills
│   │   ├── lib.rs                # Tauri Builder + invoke_handler 注册
│   │   └── main.rs               # 桌面入口
│   └── Cargo.toml                # Rust 依赖
├── package.json                  # 前端依赖
├── tauri.conf.json               # Tauri 配置(bundle / window / plugins)
└── docs/                         # 项目内文档