# 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](https://github.com/anthropics/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 | `react`、`react-dom` |
| UI 组件 | shadcn/ui（base-ui + Tailwind CSS 4） | `@base-ui/react`、`tailwindcss 4`、`class-variance-authority`、`tailwind-merge`、`lucide-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** | `serde`、`chrono`、`uuid` |
| 数据库 | **SQLite via sqlx 0.8** | `sqlx { sqlite, runtime-tokio }` + WAL 模式 |
| HTTP | reqwest 0.12 | `json`、`rustls-tls`、`stream`，用于 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` 或卡片图标单击 `togglePlatformLink` → `invoke("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_skills`（`ON 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 共享组件

**UnifiedSkillCard**（`src/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`。**约定：不要为特定场景新建卡片组件**。

**InstallDialog**（`src/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-accent`；`init()` 在渲染前调用防闪烁

---

## 六、必需依赖

### 6.1 开发期

| 类别 | 依赖 | 说明 |
|---|---|---|
| 运行时 | Node.js LTS + pnpm | `package.json` 中 `pnpm.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-47`、`linker.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/                         # 项目内文档
```
