- 人工智能
- 大模型
- AI 应用
- 交互助手
- 本地部署
【免费下载链接】cherry-studio
🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端
本文基于 Cherry Studio 开源仓库中的全局重构追踪文档 v2-todo.md 展开,系统梳理 v1→v2 重构中所有**跨切面(Cross-Cutting)**任务:Redux / Dexie / ElectronStore 三套 v1 数据栈的退役、antd / styled-components 向@cherrystudio/ui的收敛、14 个数据迁移器(Migrator)的收尾、Schema 迁移 SQL 的再生成、约 78 处@deprecated站点的清理,以及发布前的整目录清理流程。读完本文,你将掌握这次大型重构的整体推进顺序、各任务的状态判定方法,以及每项工作背后对应的源码实现位置,可作为二次开发与升级维护时的索引地图。
一、重构全景:一份"只跟踪全局任务"的作战文档
在 Cherry Studio 仓库中,v2 重构的文档组织遵循一个明确原则:全局性、跨模块的任务集中在 v2-todo.md 一处追踪,模块内部的细粒度 TODO 则保留在各模块自己的文档中,不在此重复。因此这份文档的定位是"顶层作战地图",而不是逐文件清单。
文档开篇给出了两个使用前提,理解它们对正确阅读本指南至关重要:
- 计数是近似值:文中所有文件数、slice 数、匹配数均来自代码扫描,会随开发推进漂移,执行前需要重新验证;
- 状态图例:✅ done(已完成)/🔲 todo(待办)/🟡 in progress(进行中)。
文档的 Overview 总表是整份重构的目录级快照:
| Category | Scale | Status |
|---|---|---|
| Remove Redux | ~100 files / 28 slices | ✅ done(store/deleted) |
| Remove Dexie | ~50 files | 🟡 mostly migrated, fallback paths pending |
| Remove ElectronStore | ~10 files | 🔲 awaiting migration-window close |
| Remove antd | ~145 files | 🟡 settings/knowledge pages already clean |
| Remove styled-components | ~112 files | 🟡 in progress |
| Migrator finalization | 4 explicit todos | 🟡 14 migrators mostly complete |
| Schema / migration SQL regen | release gate | 🔲 before release |
从这张表可以读出整次重构的骨架:数据层三栈拆除 + UI 层两库迁移 + 迁移器与 Schema 收尾 + 发布清理。下文按这四个维度逐一展开。
二、数据层拆除:Redux / Dexie / ElectronStore 三栈退役
v2 数据层的目标非常明确:移除全部三套 v1 数据栈(Redux / Dexie / ElectronStore),替换为 v2 的Cache / Preference / DataApi三层体系。围绕这三套栈的迁移进度与遗留策略,构成了数据层拆除的全部内容。
2.1 Redux(~100 文件 / 28 slices)— ✅ 已完成
Redux 是三个数据栈中第一个被完整移除的,文档记录了其拆除的完整路径:
- 全部 28 个 slice 迁移至 Cache / Preference / DataApi;
- 所有
useAppSelector/useDispatch调用点重新指向 v2 的读取与写入 API; - 各窗口入口的
<Provider>包裹被移除; src/renderer/store/目录整体删除;- 主进程侧被 stub 的
ReduxService桥接层一并删除。
从文档第 5 节还能看到配套动作:29 个store/*文件被列为移除待办的@deprecated站点,替代方向正是 "DataApi + Preference + SQLite"。也就是说 Redux 的拆除不是简单的删代码,而是先完成读写路径的重定向,再物理删除。
2.2 Dexie(~50 文件)— 🟡 大部分已迁移,回退路径待清理
Dexie 的迁移处于"大部分完成、收尾待办"的状态:
- 渲染进程侧的 Dexie schema 与升级入口(
src/renderer/databases/)已移除; - 但迁移专用访问仍保留:
DexieExporter、DexieFileReader、DexieSettingsReader三类读取器仅供 v1→v2 迁移流程使用,必须等到迁移窗口(migration window)关闭后才能删除(见文档 §6)。
这一策略在源码中有直接印证:迁移工具目录 中保留着DexieFileReader.ts、DexieSettingsReader.ts、ReduxStateReader.ts、LocalStorageReader.ts、LegacyAgentsDbReader.ts、LegacyHomeConfigReader.ts、JsonStreamReader.ts等一系列只读型遗留数据访问器——它们是迁移器读取 v1 数据的"井盖",迁移结束即废弃。
从源码结构看,v1 数据读取被统一收敛在src/main/data/migration/v2/utils/下,迁移器通过它们读旧数据、通过 MigrationDbService.ts 写新库,实现了"旧数据只读、新数据只写"的隔离,降低迁移过程中破坏源数据的风险。
2.3 ElectronStore(~10 文件)— 🔲 等待迁移窗口关闭
ElectronStore 是最后退役的数据栈,文档给出了明确的删除顺序:
- 入口最后删:文档将
src/main/services/ConfigManager.ts(标注@deprecated Scheduled for removal in v2.0.0,内部有new Store())列为最后一个待删除入口; - Boot config 已先行:启动配置已由
BootConfigMigrator迁移至 v2; - PreferencesMigrator 仍依赖:偏好迁移器需要通过遗留读取器读取 electron-store 的旧键,属于纯迁移期代码。
需要说明的是,这份文档是重构推进过程中的时间快照——截至本文撰写时,仓库中已无法直接检索到ConfigManager.ts文件,主进程的配置读取已全面切换至 v2 preference 体系;当前 MigrationEngine.ts 与 MigrationContext.ts 中仅保留对electron-store的迁移期只读访问(例如读取config.json以探测遗留数据目录),这正符合文档"迁移专用、迁移后删除"的设计。
三、UI 层拆除:antd / styled-components 向@cherrystudio/ui收敛
UI 层的目标是把两套被禁用的组件库 antd 与 styled-components 完全迁移到统一的 @cherrystudio/ui(基于 Tailwind + Shadcn 的自研组件体系)。
3.1 当前进展
- HeroUI 已完全移除(0 处 import);
@cherrystudio/ui已在约 400 个文件中被采用;- settings / knowledge / library / code / notes / mini-apps 页面已基本清理干净。
从源码可以直观验证这一规模:src/renderer/下大量组件、页面(如src/renderer/pages/settings/、src/renderer/pages/knowledge/、src/renderer/components/chat/、src/renderer/windows/migrationV2/等)都已通过from '@cherrystudio/ui'引入组件,与文档描述的"约 400 文件采用"相互印证。
3.2 迁移策略:重叠优先 + 分区批量
文档给出了两条关键战术:
- 重叠文件优先:antd 与 styled-components 有约 21 个文件同时 import 两者,优先处理这些文件可以"一次清两笔账";
- 按区域分批迁移,每个区域标注了 antd 文件数、styled 文件数与优先级:
| Area | antd | styled | Priority | Notes |
|---|---|---|---|---|
| home(主聊天 UI) | ~80 | ~58 | high | 核心 UX:Messages / Inputbar / Blocks |
| shared Popups | ~4 | ~4 | high | AddAssistantPopup / AgentModal / SelectModelPopup;高流量共享组件,迁移后级联解锁下游 |
| agents | ~22 | ~6 | medium | 可与 home 批量进行 |
| paintings(各 provider 配置页) | ~13 | ~11 | medium | 全部为 antd+styled 重叠,是很好的合并目标 |
| windows | ~10 | ~16 | medium | quickAssistant / selection / migrationV2 / trace |
| history / files / launchpad | ~5 | ~8 | low | 轻量 |
| 单文件钉子户 | 3 | — | low | SkillsSettings、ModelSelectorLegacy、ProviderLogoPicker |
这份优先级表的思路值得借鉴:先啃高流量共享组件(Popups),因为它们的迁移会级联解锁依赖它们的下游页面;而占文件数最多的 home 主聊天区虽然工作量大,但因为处于核心 UX 路径,被列为最高优先级。
3.3 特殊用例:MarkdownShadowDomRenderer
文档特别点名了src/renderer/components/MarkdownShadowDomRenderer.tsx:它曾使用 styled-components 向 Shadow DOM 注入 CSS,需要专门处理而不能走常规迁移路径。从当前源码看,该组件的实现已经演进为原生 Web API 方案——通过attachShadow({ mode: 'open' })创建影子根、从document.styleSheets中抓取包含.markdown规则的样式表、将 CSS 规则文本注入 shadow 内的<style>节点,再用createPortal把子节点渲染进影子树。这也再次印证了本文的基调:文档是重构快照,源码在持续前进,阅读时两者需对照。
四、Migrator 收尾:14 个迁移器的最后 1%
数据迁移是 v1→v2 的心脏。文档记录迁移器总数约为 14 个(同样为扫描近似值),大部分已完成,仅剩 4 项显式 TODO。
4.1 四个显式 TODO
| Item | Location | TODO |
|---|---|---|
| ChatMigrator i18n | ChatMigrator.ts:761 | // TODO: i18n;fallback 话题名为硬编码英文Unnamed Topic,需要 i18n key |
| KnowledgeVectorMigrator failure handling | KnowledgeVectorMigrator.ts | Base 级执行失败被当作整体迁移失败(README 标记 IMPORTANT);需确认设计或实现 skippable-base 模式 |
| TranslateMigrator missing test | migrators/__tests__/ | 唯一没有配套测试的迁移器;需补充TranslateMigrator.test.ts |
| V1_REQUIRED_VERSION lock-in | versionPolicy.ts:34 | TODO:待最终 v1 版本确定后更新(当时为1.9.0,预期 ~1.9.x) |
对照当前源码,这 4 项的进展状态如下(再次强调:仓库代码已领先于文档快照):
- ChatMigrator i18n:从 ChatMigrator.test.ts 的测试用例可以看到,迁移器已改为保留空的 topic name(
expect(result?.topic.name).toBe('')),让 UI 在渲染时调用t('chat.conversation.new')进行本地化,从而不再把英文Unnamed Topic写死进数据——这与 v2 原生创建的无名话题行为保持一致,中文用户不会再看到冻结的英文文案。也就是说,该 TODO 的"用 i18n 解决硬编码"方向已通过"空名 + 渲染时本地化"落地; - KnowledgeVectorMigrator failure handling:当前实现中已经存在每 base 非致命(per-base non-fatal)的处理路径——单个 base 失败时跳过该 base、将其计入
skippedCount以通过引擎的targetCount < sourceCount - skippedCount对账,并把失败降级为 warning,不再拖垮整个迁移(见 KnowledgeVectorMigrator.ts 附近注释)。"一个锁死或损坏的 base 不再拖垮整体迁移"的设计已落地; - TranslateMigrator missing test:截至撰写时,migrators 测试目录 中确实没有
TranslateMigrator.test.ts(仅mappings/__tests__/TranslateTransforms.test.ts覆盖了转换逻辑),该 TODO 仍待办; - V1_REQUIRED_VERSION:当前 versionPolicy.ts 中常量已更新为
'1.9.12',且顶部 TODO 注释("Update this value once the final v1 version is determined")仍然保留——说明该条目处于"已锁值、待终版确认"状态。
4.2 版本升级策略(源码级补充)
与 V1_REQUIRED_VERSION 相关的版本策略在 versionPolicy.ts 中有完整实现,它强制一条线性升级路径:
v1.old → v1.last(V1_REQUIRED_VERSION)→ v2.0.x(网关线)→ v2.1+核心逻辑checkUpgradePathCompatibility会拦截三类非法路径:
- 无
version.log且无历史版本 → 拦截(no_version_log); - 历史版本低于
V1_REQUIRED_VERSION→ 拦截(v1_too_old); - 从 v1.x 或 v2.0.0-beta 直接跳到
V2_DIRECT_MIGRATION_CEILING(2.1.0)以上 → 拦截(v2_gateway_skipped),因为每个 v2.0.x 补丁都保留完整的一次性迁移,可能包含某些 v1 profile 所需的修复。
值得注意的细节是pre-release 的差异性处理:currentVersion会通过semver.coerce()剥离 pre-release 标签(2.0.0-alpha视为2.0.0,防止误拦安装了预发布版的 v1 用户);而previousVersion不做 coerce(2.0.0-beta仍被视为"未通过网关")。这套语义保证了 alpha→beta→rc→2.0.0 的预发布链可以顺利升级,而 v1 用户则必须经由 2.0.x 网关完成一次性迁移。
4.3 有意跳过的内容(发布说明必须声明)
文档强调,以下有意为之的跳过必须在 release notes 中向用户明示:
- Knowledge:
video/memory类条目不迁移;目录子项不重建;遗留 sitemap 条目以 URL 条目形式迁移;分组元数据丢失(groupId = null); - KnowledgeVector:v1 遗留向量库原地保留不迁移;迁移成功后这些库以"孤儿"形式残留在磁盘上(当前无清理触发,未来可由用户确认后清理以回收磁盘);
- Note:
activeFilePath/activeNodeId不迁移,运行时重新建立; - MCP:provider 缓存不迁移,运行时重新拉取。
这些"主动放弃"的条目,配合上面的逐项 TODO,构成了迁移器收尾的完整画像:不是所有数据都值得迁移,明确放弃的数据需要作为产品级决策被记录和声明。
4.4 迁移引擎的底层编排(源码补充)
迁移的执行骨架在 MigrationEngine.ts 中:引擎负责协调所有 migrator、管理进度、处理失败。其中MIGRATION_TARGET_TABLES常量是迁移会写入的所有表的单一事实来源(约 40 张表,覆盖 chat、agent、knowledge、file、preference 等全域),并显式标注了clearMigrationData() 清库时的子→父顺序约束:
message必须先于topic清除(外键引用);topic必须先于assistant清除;user_model必须先于user_provider清除;- junction 表(
assistant_mcp_server、assistant_knowledge_base、prompt_binding)必须先于其父表清除; - agents 域按
agent_session_message_file_ref → agent_session_message → agent_channel_task → … → agent的依赖链逆序清理。
这套顺序约束保证了重试与跳过(retry / skip)时不会因外键约束而中断——引擎具备完整的"失败重试、部分跳过"能力,这也是 4.2 节 KnowledgeVector per-base 跳过机制能够成立的前提。
五、Schema 与迁移 SQL 收尾:重构出单条干净的初始迁移
文档第 4 节记录了 Schema 层面的发布门槛:
- migrations/sqlite-drizzle/ 目录当前保存的是增量开发链(文档撰写时为
0000–0012+meta/快照;截至本文撰写时该链已延伸至0020),"单条干净迁移"的再生成尚未发生; - 发布前必须从最终 schema 重新生成一条干净的初始迁移,以清掉中间开发状态(这一要求在 CLAUDE.md 中已被强制规定);
- 工具行为陷阱:
drizzle-kit generate在分叉链(forked chain)上仍然以退出码 0 正常退出,只有pnpm db:migrations:check才能标记出分叉;因此开发中期的 schema 漂移是可接受的,但严禁手写 patch migration。
这条规范的实际含义是:开发阶段允许 schema 频繁变动(毕竟迁移器还在收尾),但最终交付必须是一条自洽的、从零到一的干净迁移,避免把开发期的中间状态泄漏给用户升级路径。
六、@deprecated标记清理:约 78 处 / 58 文件
发布前还需清理代码中残留的@deprecated标记:约 78 处、分布在 58 个文件中,其中约 39 处明确写着Scheduled for removal in v2.0.0。文档按子系统分组给出了替代方向:
| Group | Scope | Replacement direction |
|---|---|---|
| Redux store slices | 29 files(store/*) | DataApi + Preference + SQLite |
| Dexie / message 数据源 | 4 files(databases/、DexieMessageDataSource、DbService) | DataApi(主聊天)/ AgentMessageDataSource(agent 会话) |
| Redux 耦合 hooks / 主进程桥 | 6 files(useStore/useSettings/useTagsLegacy、ReduxService等) | usePreference/useTags(v2);ReduxService已 stub |
| 共享数据类型 | agent / message / provider 类型(分页响应、citation 格式、遗留 provider 标志) | OffsetPaginationResponse、MainTextBlock.references等 |
| 协议 / 消息格式 | LanFile*JSON 格式、web-search 访问器 | 二进制帧、CitationMessageBlock |
| 组件 / 服务重构 | CodeEditor→@cherrystudio/ui、FileManager(不再扩展)、deleteMessageFiles→safeDeleteFiles等 | 见各标注 |
在源码中可以看到这些标记的实际分布,例如 legacyTypes.ts(整文件标注@deprecated v1 legacy — do not extend)、FileStorage.ts(@deprecated LEGACY v1 CODE — being migrated to FileManager)、LegacyBackupManager.ts(@deprecated LEGACY v1 CODE — removed when the v2 migration is dropped)等。
文档还给出了迁移相关 TODO/FIXME 的分布统计(约 53 条,从约 157 条中过滤而来,其余为普通代码注释),主工作流按规模排序:
- Preference / Provider 设置迁移(最大头,约 18 条,含
ProviderSettings/utils/v1ProviderShim.ts的 "delete after Phase 5"); - 服务架构 / 生命周期重构(约 10 条);
- Redux → SQLite/Drizzle(约 9 条,集中在
apiServer/routes/knowledge/handlers.ts); - Phase-2 文件服务 stub(约 8 条);
- 消息类型迁移(~5)、IPC handler 清理(~6)、DataApi 集成(~3)。
这组数字告诉读者:设置域是迁移后期最密集的战场,v1ProviderShim 这类过渡 shim 被明确标注了过期时间点(Phase 5 之后删除),是典型的"过渡代码要有明确生命周期"实践。
七、发布与清理:从迁移窗口关闭到整目录删除
文档第 6 节给出了发布期的三步收尾:
- 删除迁移专用代码:
DexieFileReader、DexieSettingsReader、electron-store 读取路径等仅被 v1→v2 迁移流程使用;一旦迁移窗口关闭(即最低支持的 v1 版本停止升级),立即删除; - 聚合 breaking changes:发布负责人聚合 breaking-changes 目录中的记录,将其翻译成中文用户可见的发布说明。该目录的 README 定义了严格的记录规范:用户可感知的变更(功能移除、默认行为改变、设置位置移动、数据迁移字段丢失、快捷键/URL scheme 变更、平台要求变化)必须记录;纯内部重构(IPC 通道改名、服务拆分、schema 微调、类型改名)不得记录;拿不准时宁多勿少,发布期可随时丢弃;
- 删除整个
v2-refactor-temp/目录:确认工具不再需要、把值得保留的文档移到正式位置、删除目录并清理.gitignore中的引用。这一步的依据是 v2-refactor-temp/README.md 中明示的 Cleanup plan——该目录不含任何生产代码,只承载重构期工具与工作笔记,重构落地即整体移除。
八、进一步阅读:重构相关的源码导航
如果希望深入本次重构的实现细节,以下仓库路径是最佳起点:
- 迁移核心骨架:MigrationEngine.ts(编排与重试)、MigrationContext.ts(迁移上下文,含 electron-store 只读访问)、MigrationPaths.ts(遗留数据目录探测)、versionPolicy.ts(版本网关);
- 迁移器与文档:migrators 目录 下的
*Migrator.ts与配套README-*Migrator.md,注册总表见 migratorRegistry.ts; - 迁移测试:migrators/tests与 core/tests,覆盖引擎跳过、版本策略、错误处理与各迁移器行为;
- 遗留数据读取器:migration/v2/utils(Dexie / Redux / LocalStorage / legacy DB 等只读访问器);
- 迁移窗口 UI 与 IPC:window/MigrationWindowManager.ts、window/MigrationIpcHandler.ts,渲染端入口在 migrationV2 窗口;
- 数据迁移相关文档总入口:migration/README.md 与 v2-refactor-temp/README.md。
最后提醒一点阅读姿势:v2-todo.md是重构进行中的状态快照,其统计数字(文件数、TODO 数、迁移链编号)会随开发演进,部分条目(如 ChatMigrator 的 i18n、KnowledgeVector 的 per-base 失败处理)在本文撰写时已被源码层面的新实现覆盖。将文档与当前仓库代码对照阅读,才能得到最准确的实时状态。
- 人工智能
- 大模型
- AI 应用
- 交互助手
- 本地部署
【免费下载链接】cherry-studio
🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端
相关推荐
Cherry Studio V2 数据与 UI 重构临时工作区:v2-refactor-temp 目录定位、工具链与收尾规范
Cherry Studio V2 数据与 UI 重构临时工作区:v2 refactor temp 目录定位、工具链与收尾规范 本篇技术指南以 Cherry St
人工智能大模型AI 应用交互助手本地部署Cherry Studio Knowledge V2 UI 重构约束指南:组件结构、数据边界与协作规范
Cherry Studio Knowledge V2 UI 重构约束指南:组件结构、数据边界与协作规范 本文是 Cherry Studio(cherry stu
人工智能大模型AI 应用交互助手本地部署Cherry Studio AgentsMigrator 深度解析:v1 Agent 数据到 v2 SQLite 的无损迁移与文件系统拆分
Cherry Studio AgentsMigrator 深度解析:v1 Agent 数据到 v2 SQLite 的无损迁移与文件系统拆分 导读 本文深入解析
AI 应用大模型桌面应用本地部署RAG
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考