From 806a294508dc4b1c38bed9c85e11722830503743 Mon Sep 17 00:00:00 2001 From: fullex <0xfullex@gmail.com> Date: Sat, 29 Nov 2025 11:55:45 +0800 Subject: [PATCH] feat: add v2-refactor-temp directory for V2 refactoring tools - Add data-classify tools for data inventory extraction and code generation - Include consolidated Chinese documentation (README.md) - Update generated file path references This temporary directory will be removed after V2 refactor is complete. --- .../data/preference/preferenceSchemas.ts | 4 +- .../migrators/mappings/PreferencesMappings.ts | 194 +- v2-refactor-temp/README.md | 40 + .../tools/data-classify/.gitignore | 1 + .../tools/data-classify/README.md | 510 +++ .../data-classify/data/classification.json | 3409 +++++++++++++++++ .../tools/data-classify/data/inventory.json | 1566 ++++++++ .../tools/data-classify/package-lock.json | 490 +++ .../tools/data-classify/package.json | 30 + .../data-classify/scripts/check-duplicates.js | 78 + .../scripts/extract-inventory.js | 545 +++ .../data-classify/scripts/generate-all.js | 43 + .../scripts/generate-migration.js | 239 ++ .../scripts/generate-preferences.js | 401 ++ .../scripts/lib/classificationUtils.js | 323 ++ .../scripts/validate-consistency.js | 293 ++ .../scripts/validate-generation.js | 239 ++ 17 files changed, 8312 insertions(+), 93 deletions(-) create mode 100644 v2-refactor-temp/README.md create mode 100644 v2-refactor-temp/tools/data-classify/.gitignore create mode 100644 v2-refactor-temp/tools/data-classify/README.md create mode 100644 v2-refactor-temp/tools/data-classify/data/classification.json create mode 100644 v2-refactor-temp/tools/data-classify/data/inventory.json create mode 100644 v2-refactor-temp/tools/data-classify/package-lock.json create mode 100644 v2-refactor-temp/tools/data-classify/package.json create mode 100644 v2-refactor-temp/tools/data-classify/scripts/check-duplicates.js create mode 100644 v2-refactor-temp/tools/data-classify/scripts/extract-inventory.js create mode 100644 v2-refactor-temp/tools/data-classify/scripts/generate-all.js create mode 100644 v2-refactor-temp/tools/data-classify/scripts/generate-migration.js create mode 100644 v2-refactor-temp/tools/data-classify/scripts/generate-preferences.js create mode 100644 v2-refactor-temp/tools/data-classify/scripts/lib/classificationUtils.js create mode 100644 v2-refactor-temp/tools/data-classify/scripts/validate-consistency.js create mode 100644 v2-refactor-temp/tools/data-classify/scripts/validate-generation.js diff --git a/packages/shared/data/preference/preferenceSchemas.ts b/packages/shared/data/preference/preferenceSchemas.ts index 368a38bb70..0e09764733 100644 --- a/packages/shared/data/preference/preferenceSchemas.ts +++ b/packages/shared/data/preference/preferenceSchemas.ts @@ -1,10 +1,10 @@ /** * Auto-generated preferences configuration - * Generated at: 2025-11-28T16:19:17.585Z + * Generated at: 2025-11-29T03:45:07.207Z * * This file is automatically generated from classification.json * To update this file, modify classification.json and run: - * node local/tools/data-classify/scripts/generate-preferences.js + * node v2-refactor-temp/tools/data-classify/scripts/generate-preferences.js * * ## Key Naming Convention * diff --git a/src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts b/src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts index a1a3406bfa..4718d44b25 100644 --- a/src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts +++ b/src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts @@ -1,6 +1,6 @@ /** * Auto-generated preference mappings from classification.json - * Generated at: 2025-11-28T13:37:20.033Z + * Generated at: 2025-11-29T03:45:07.227Z * * This file contains pure mapping relationships without default values. * Default values are managed in packages/shared/data/preferences.ts @@ -30,50 +30,18 @@ export const ELECTRON_STORE_MAPPINGS = [ */ export const REDUX_STORE_MAPPINGS = { settings: [ - { - originalKey: 'autoCheckUpdate', - targetKey: 'app.dist.auto_update.enabled' - }, - { - originalKey: 'clickTrayToShowQuickAssistant', - targetKey: 'feature.quick_assistant.click_tray_to_show' - }, - { - originalKey: 'disableHardwareAcceleration', - targetKey: 'app.disable_hardware_acceleration' - }, - { - originalKey: 'enableDataCollection', - targetKey: 'app.privacy.data_collection.enabled' - }, - { - originalKey: 'enableDeveloperMode', - targetKey: 'app.developer_mode.enabled' - }, - { - originalKey: 'enableQuickAssistant', - targetKey: 'feature.quick_assistant.enabled' - }, { originalKey: 'language', targetKey: 'app.language' }, - { - originalKey: 'launchToTray', - targetKey: 'app.tray.on_launch' - }, - { - originalKey: 'testChannel', - targetKey: 'app.dist.test_plan.channel' - }, - { - originalKey: 'testPlan', - targetKey: 'app.dist.test_plan.enabled' - }, { originalKey: 'theme', targetKey: 'ui.theme_mode' }, + { + originalKey: 'launchToTray', + targetKey: 'app.tray.on_launch' + }, { originalKey: 'tray', targetKey: 'app.tray.enabled' @@ -82,6 +50,38 @@ export const REDUX_STORE_MAPPINGS = { originalKey: 'trayOnClose', targetKey: 'app.tray.on_close' }, + { + originalKey: 'clickTrayToShowQuickAssistant', + targetKey: 'feature.quick_assistant.click_tray_to_show' + }, + { + originalKey: 'enableQuickAssistant', + targetKey: 'feature.quick_assistant.enabled' + }, + { + originalKey: 'autoCheckUpdate', + targetKey: 'app.dist.auto_update.enabled' + }, + { + originalKey: 'testPlan', + targetKey: 'app.dist.test_plan.enabled' + }, + { + originalKey: 'testChannel', + targetKey: 'app.dist.test_plan.channel' + }, + { + originalKey: 'enableDataCollection', + targetKey: 'app.privacy.data_collection.enabled' + }, + { + originalKey: 'disableHardwareAcceleration', + targetKey: 'app.disable_hardware_acceleration' + }, + { + originalKey: 'enableDeveloperMode', + targetKey: 'app.developer_mode.enabled' + }, { originalKey: 'showAssistants', targetKey: 'assistant.tab.show' @@ -649,12 +649,8 @@ export const REDUX_STORE_MAPPINGS = { targetKey: 'feature.selection.enabled' }, { - originalKey: 'filterList', - targetKey: 'feature.selection.filter_list' - }, - { - originalKey: 'filterMode', - targetKey: 'feature.selection.filter_mode' + originalKey: 'triggerMode', + targetKey: 'feature.selection.trigger_mode' }, { originalKey: 'isFollowToolbar', @@ -665,8 +661,12 @@ export const REDUX_STORE_MAPPINGS = { targetKey: 'feature.selection.remember_win_size' }, { - originalKey: 'triggerMode', - targetKey: 'feature.selection.trigger_mode' + originalKey: 'filterMode', + targetKey: 'feature.selection.filter_mode' + }, + { + originalKey: 'filterList', + targetKey: 'feature.selection.filter_list' }, { originalKey: 'isCompact', @@ -696,55 +696,25 @@ export const REDUX_STORE_MAPPINGS = { }, { originalKey: 'memoryConfig.isAutoDimensions', - targetKey: 'feature.memory.is_auto_dimensions' + targetKey: 'feature.memory.auto_dimensions' + }, + { + originalKey: 'memoryConfig.customFactExtractionPrompt', + targetKey: 'feature.memory.fact_extraction_prompt' + }, + { + originalKey: 'memoryConfig.customUpdateMemoryPrompt', + targetKey: 'feature.memory.update_memory_prompt' + }, + { + originalKey: 'currentUserId', + targetKey: 'feature.memory.current_user_id' }, { originalKey: 'globalMemoryEnabled', targetKey: 'feature.memory.enabled' } ], - note: [ - { - originalKey: 'settings.isFullWidth', - targetKey: 'feature.notes.full_width' - }, - { - originalKey: 'settings.fontFamily', - targetKey: 'feature.notes.font_family' - }, - { - originalKey: 'settings.fontSize', - targetKey: 'feature.notes.font_size' - }, - { - originalKey: 'settings.showTableOfContents', - targetKey: 'feature.notes.show_table_of_contents' - }, - { - originalKey: 'settings.defaultViewMode', - targetKey: 'feature.notes.default_view_mode' - }, - { - originalKey: 'settings.defaultEditMode', - targetKey: 'feature.notes.default_edit_mode' - }, - { - originalKey: 'settings.showTabStatus', - targetKey: 'feature.notes.show_tab_status' - }, - { - originalKey: 'settings.showWorkspace', - targetKey: 'feature.notes.show_workspace' - }, - { - originalKey: 'notesPath', - targetKey: 'feature.notes.path' - }, - { - originalKey: 'sortType', - targetKey: 'feature.notes.sort_type' - } - ], nutstore: [ { originalKey: 'nutstoreToken', @@ -836,6 +806,48 @@ export const REDUX_STORE_MAPPINGS = { originalKey: 'shortcuts.exit_fullscreen', targetKey: 'shortcut.app.exit_fullscreen' } + ], + note: [ + { + originalKey: 'settings.isFullWidth', + targetKey: 'feature.notes.full_width' + }, + { + originalKey: 'settings.fontFamily', + targetKey: 'feature.notes.font_family' + }, + { + originalKey: 'settings.fontSize', + targetKey: 'feature.notes.font_size' + }, + { + originalKey: 'settings.showTableOfContents', + targetKey: 'feature.notes.show_table_of_contents' + }, + { + originalKey: 'settings.defaultViewMode', + targetKey: 'feature.notes.default_view_mode' + }, + { + originalKey: 'settings.defaultEditMode', + targetKey: 'feature.notes.default_edit_mode' + }, + { + originalKey: 'settings.showTabStatus', + targetKey: 'feature.notes.show_tab_status' + }, + { + originalKey: 'settings.showWorkspace', + targetKey: 'feature.notes.show_workspace' + }, + { + originalKey: 'notesPath', + targetKey: 'feature.notes.path' + }, + { + originalKey: 'sortType', + targetKey: 'feature.notes.sort_type' + } ] } as const @@ -844,9 +856,9 @@ export const REDUX_STORE_MAPPINGS = { /** * 映射统计: * - ElectronStore项: 1 - * - Redux Store项: 199 - * - Redux分类: settings, selectionStore, memory, note, nutstore, shortcuts - * - 总配置项: 200 + * - Redux Store项: 202 + * - Redux分类: settings, selectionStore, memory, nutstore, shortcuts, note + * - 总配置项: 203 * * 使用说明: * 1. ElectronStore读取: configManager.get(mapping.originalKey) diff --git a/v2-refactor-temp/README.md b/v2-refactor-temp/README.md new file mode 100644 index 0000000000..859b662510 --- /dev/null +++ b/v2-refactor-temp/README.md @@ -0,0 +1,40 @@ +# V2 重构临时目录 + +本目录是 Cherry Studio V2 数据和 UI 重构项目的临时工作目录,用于存放重构过程中使用的共享工具、文档和临时文件。 + +**重要**: 本目录将在 V2 重构完成后删除。 + +## 目录结构 + +``` +v2-refactor-temp/ +├── tools/ # 重构工具 +│ └── data-classify/ # 数据分类与代码生成工具 +├── docs/ # 临时文档(如有需要) +└── README.md # 本文件 +``` + +## 包含内容 + +### 工具 (tools/) + +- **data-classify/** - 数据分类与代码生成工具 + - 从源码提取数据清单 + - 管理数据分类映射 + - 生成 TypeScript 类型定义和迁移映射 + - 详见 [tools/data-classify/README.md](./tools/data-classify/README.md) + +## 使用说明 + +1. 本目录不包含任何生产代码,仅用于重构辅助 +2. 生成的代码会输出到正式的项目目录中 +3. 不要在本目录中存放需要长期保留的内容 + +## 清理计划 + +V2 重构完成后,本目录将被完全删除。届时需要: + +1. 确认所有工具不再需要 +2. 将有价值的文档迁移到正式位置(如有) +3. 删除整个 `v2-refactor-temp/` 目录 +4. 更新 `.gitignore` 和相关引用 diff --git a/v2-refactor-temp/tools/data-classify/.gitignore b/v2-refactor-temp/tools/data-classify/.gitignore new file mode 100644 index 0000000000..9e5a635a43 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/.gitignore @@ -0,0 +1 @@ +*.backup.* \ No newline at end of file diff --git a/v2-refactor-temp/tools/data-classify/README.md b/v2-refactor-temp/tools/data-classify/README.md new file mode 100644 index 0000000000..14a82d7d26 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/README.md @@ -0,0 +1,510 @@ +# 数据分类与代码生成工具 + +Cherry Studio 数据重构项目的自动化工具集,用于管理数据分类和生成 TypeScript 代码。 + +**版本**: 2.0.0 +**更新日期**: 2025-11-28 + +## 概述 + +本工具集提供以下功能: +- **数据提取**: 扫描源代码,构建数据清单 +- **分类管理**: 维护分类映射,支持增量更新 +- **代码生成**: 生成 TypeScript 接口和迁移映射 +- **验证检查**: 确保清单与分类之间的一致性 + +## 目录结构 + +``` +v2-refactor-temp/tools/data-classify/ +├── scripts/ +│ ├── lib/ +│ │ └── classificationUtils.js # 共享工具函数 +│ ├── extract-inventory.js # 从源码提取数据清单 +│ ├── generate-all.js # 运行所有生成器 +│ ├── generate-preferences.js # 生成 preferenceSchemas.ts +│ ├── generate-migration.js # 生成 PreferencesMappings.ts +│ ├── validate-consistency.js # 验证数据一致性 +│ ├── validate-generation.js # 验证生成代码质量 +│ └── check-duplicates.js # 检查重复的目标键 +├── data/ +│ ├── classification.json # 分类映射(人工维护) +│ └── inventory.json # 数据清单(脚本生成) +├── package.json +└── README.md # 本文档 +``` + +## 快速开始 + +```bash +# 进入工具目录 +cd v2-refactor-temp/tools/data-classify + +# 安装依赖 +npm install + +# 运行完整工作流 +npm run all + +# 或者分步执行 +npm run extract # 提取数据清单 +npm run generate # 生成所有代码 +npm run validate # 验证一致性 +npm run validate:gen # 验证生成代码 +``` + +## 可用脚本 + +| 脚本 | 说明 | +|------|------| +| `npm run extract` | 从源文件提取数据清单 | +| `npm run generate` | 运行所有代码生成器 | +| `npm run generate:preferences` | 仅生成 preferenceSchemas.ts | +| `npm run generate:migration` | 仅生成 PreferencesMappings.ts | +| `npm run validate` | 验证数据一致性 | +| `npm run validate:gen` | 验证生成代码质量 | +| `npm run check:duplicates` | 检查重复的目标键 | +| `npm run all` | 运行完整工作流 | + +## 脚本架构 + +### 依赖关系图 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 共享模块 │ +│ scripts/lib/classificationUtils.js │ +│ - loadClassification() - traverseClassifications() │ +│ - saveClassification() - calculateStats() │ +│ - loadInventory() - normalizeType() │ +│ - extractPreferencesData() - inferTypeFromValue() │ +└─────────────────────────────────────────────────────────────┘ + ▲ ▲ + │ │ + ┌───────────┘ └───────────┐ + │ │ +┌───────┴───────┐ ┌────────┴────────┐ +│ extract- │ │ validate- │ +│ inventory.js │ │ consistency.js │ +│ │ │ │ +│ 扫描源码 │ │ 检查数据 │ +│ 构建清单 │ │ 一致性 │ +└───────────────┘ └─────────────────┘ + +┌─────────────────────┐ +│ generate-all.js │──────────────────────────────────┐ +│ │ │ +│ 编排所有生成器 │ │ +└─────────────────────┘ │ + │ │ + │ require() │ require() + ▼ ▼ +┌─────────────────────┐ ┌─────────────────────┐ +│ generate- │ │ generate- │ +│ preferences.js │ │ migration.js │ +│ │ │ │ +│ 生成 │ │ 生成 │ +│ preferenceSchemas.ts│ │ PreferencesMappings │ +└─────────────────────┘ └─────────────────────┘ + +┌─────────────────────┐ ┌─────────────────────┐ +│ validate- │ │ check- │ +│ generation.js │ │ duplicates.js │ +│ │ │ │ +│ 验证生成代码质量 │ │ 检查重复目标键 │ +│ (独立运行) │ │ (独立运行) │ +└─────────────────────┘ └─────────────────────┘ +``` + +### 脚本详情 + +| 脚本 | 输入 | 输出 | 依赖 | +|------|------|------|------| +| `extract-inventory.js` | 源代码文件 | `data/inventory.json` | `classificationUtils.js` | +| `generate-preferences.js` | `classification.json` | `preferenceSchemas.ts` | 无 | +| `generate-migration.js` | `classification.json` | `PreferencesMappings.ts` | 无 | +| `generate-all.js` | - | 运行两个生成器 | `generate-preferences.js`, `generate-migration.js` | +| `validate-consistency.js` | `inventory.json`, `classification.json` | `validation-report.md` | `classificationUtils.js` | +| `validate-generation.js` | 生成的 `.ts` 文件 | 控制台输出 | 无 | +| `check-duplicates.js` | `classification.json` | 控制台输出 | 无 | + +## 数据分类工作流 + +### 1. 提取数据清单 + +```bash +npm run extract +``` + +扫描源文件并提取以下数据源的信息: +- **Redux Store**: `src/renderer/src/store/*.ts` +- **Electron Store**: `src/main/services/ConfigManager.ts` +- **LocalStorage**: 所有使用 localStorage 的文件 +- **Dexie 数据库**: `src/renderer/src/databases/index.ts` + +### 2. 分类数据 + +编辑 `data/classification.json` 对每个数据项进行分类: + +```json +{ + "originalKey": "theme", + "type": "string", + "status": "classified", + "category": "preferences", + "targetKey": "ui.theme_mode" +} +``` + +### 3. 生成代码 + +```bash +npm run generate +``` + +生成以下 TypeScript 文件: +- `packages/shared/data/preference/preferenceSchemas.ts` - 类型定义 +- `src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts` - 迁移映射 + +### 4. 验证 + +```bash +npm run validate +npm run validate:gen +``` + +验证内容: +- 所有清单项都已分类 +- 没有孤立的分类条目 +- 命名规范一致 +- 没有重复的目标键 +- 生成代码结构正确 + +--- + +## 数据分类标准 + +根据 Cherry Studio 数据重构架构,所有数据需要分类到以下 5 个类别之一: + +### 1. 偏好配置 (preferences) + +**判断标准**: +- ✅ 影响应用全局行为的配置 +- ✅ 用户可以修改的设置项 +- ✅ 简单的数据类型(boolean/string/number/简单 array/object) +- ✅ 结构相对稳定,不经常变化 +- ✅ 数据量小,可以重建 +- ✅ 需要在窗口间同步 + +**典型例子**: +- `showAssistants`: 是否显示助手面板 +- `theme`: 主题设置(light/dark/system) +- `fontSize`: 字体大小 +- `language`: 界面语言 + +**命名规范**: +- 使用点分隔的层级结构:`ui.fontSize`、`system.language` +- 分组前缀:`ui.*`(界面)、`system.*`(系统)、`app.*`(应用行为)等 + +### 2. 用户数据 (user_data) + +**判断标准**: +- ✅ 用户创建或输入的内容 +- ✅ 不可丢失的重要数据 +- ✅ 数据量可能很大 +- ✅ 需要完整备份和迁移机制 +- ✅ 可能包含敏感信息 + +**典型例子**: +- `topics`: 对话历史 +- `messages`: 消息内容 +- `files`: 用户上传的文件 +- `knowledge_notes`: 知识库笔记 + +**特殊处理**: +- 敏感数据需要加密存储 +- 大数据表需要考虑分页和流式处理 + +### 3. 缓存数据 (cache) + +**判断标准**: +- ✅ 可以重新生成的数据 +- ✅ 主要用于性能优化 +- ✅ 丢失后不影响核心功能 +- ✅ 有过期时间或清理机制 + +**典型例子**: +- `failed_favicon_*`: 失败的 favicon 缓存 +- 搜索结果缓存 +- 图片预览缓存 +- 模型响应缓存 + +### 4. 运行时数据 (runtime) + +**判断标准**: +- ✅ 内存型数据,不需要持久化 +- ✅ 生命周期 ≤ 应用进程 +- ✅ 应用重启后可以丢失 +- ✅ 临时状态信息 + +**典型例子**: +- 当前选中的对话 +- 临时的输入状态 +- UI 组件的展开/折叠状态 +- 网络请求状态 + +### 5. 应用资源 (resources) + +**判断标准**: +- ✅ 静态资源文件 +- ✅ 随应用分发的内容 +- ✅ 不需要用户修改 +- ✅ 暂不考虑重构 + +**典型例子**: +- 图标文件 +- 本地化翻译文件 +- 默认配置文件 +- 帮助文档 + +--- + +## 分类决策流程图 + +``` +数据项 + ↓ +是否用户创建/输入的内容? + ↓ 是 ↓ 否 +用户数据 是否需要持久化? + ↓ 否 ↓ 是 + 运行时数据 是否可重新生成? + ↓ 是 ↓ 否 + 缓存数据 是否用户可修改? + ↓ 是 ↓ 否 + 偏好配置 应用资源 +``` + +--- + +## 分类示例 + +### 示例 1: Redux settings.showAssistants + +```json +{ + "classifications": { + "redux": { + "settings": [ + { + "originalKey": "showAssistants", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "ui.show_assistants" + } + ] + } + } +} +``` + +**分析过程**: +1. 数据用途:控制是否显示助手面板 +2. 用户可修改:✅ +3. 影响全局:✅ +4. 数据简单:✅ boolean 类型 +5. 结论:偏好配置 + +### 示例 2: 嵌套结构 (Redux settings with children) + +```json +{ + "originalKey": "codeEditor", + "type": "object", + "children": [ + { + "originalKey": "enabled", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "code_editor.enabled" + }, + { + "originalKey": "fontSize", + "type": "number", + "defaultValue": 14, + "status": "classified", + "category": "preferences", + "targetKey": "code_editor.font_size" + } + ] +} +``` + +**注意**: 父级项不需要 `status`/`category`/`targetKey`,这些只在叶子节点设置。 + +### 示例 3: Dexie topics 表 + +```json +{ + "originalKey": "topics", + "type": "table", + "status": "classified", + "category": "user_data", + "targetTable": "topic", + "notes": "用户对话历史,核心业务数据" +} +``` + +--- + +## 命名规范 + +偏好配置键必须遵循:`namespace.sub.key_name` + +**规则**: +- 至少 2 个由点分隔的段 +- 仅使用小写字母、数字、下划线 +- 模式:`/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/` + +**示例**: +- `app.theme` (有效) +- `chat.input.send_shortcut` (有效) +- `Theme` (无效 - 没有点分隔符) +- `App.User` (无效 - 大写字母) + +--- + +## 增量更新策略 + +### 核心特性 +- **保留已分类数据**: 重新运行提取不会丢失已有分类 +- **标记删除项**: 删除的数据项被标记但不移除 +- **自动发现新项**: 新数据项自动添加到待处理列表 +- **自动备份**: 每次运行前自动备份原分类文件 + +### 更新流程 +1. 代码变更后运行 `npm run extract` +2. 脚本自动备份 `classification.json` 到 `classification.backup.json` +3. 脚本识别新增和删除的数据项 +4. 新项添加到 `pending` 数组 +5. 删除项标记为 `status: 'classified-deleted'` +6. 手动处理新的待处理项 + +--- + +## 文件格式说明 + +### inventory.json 结构 + +```json +{ + "metadata": { + "generatedAt": "ISO 日期", + "version": "版本号" + }, + "redux": { + "moduleName": { + "fieldName": { + "type": "数据类型", + "defaultValue": "默认值" + } + } + }, + "electronStore": { ... }, + "localStorage": { ... }, + "dexie": { ... } +} +``` + +### classification.json 结构 + +```json +{ + "metadata": { + "version": "版本号", + "lastUpdated": "ISO 日期" + }, + "classifications": { + "redux": { + "moduleName": [ + { + "originalKey": "字段名", + "type": "数据类型", + "status": "classified|pending|classified-deleted", + "category": "preferences|user_data|cache|runtime|resources", + "targetKey": "target.key.name" + } + ] + }, + "electronStore": { ... }, + "localStorage": { ... }, + "dexie": { ... } + } +} +``` + +### 状态值说明 + +| Status | 说明 | 操作建议 | +|--------|------|----------| +| `pending` | 待分类 | 需要人工分析并设置 category 和 targetKey | +| `classified` | 已分类 | 分类完成,可用于代码生成 | +| `classified-deleted` | 已分类但源已删除 | 源代码中已不存在,保留历史记录 | + +--- + +## 故障排除 + +### "Module not found" 错误 + +```bash +cd v2-refactor-temp/tools/data-classify +npm install +``` + +### 验证错误 + +1. 检查 `validation-report.md` 了解详情 +2. 修复 `classification.json` 条目 +3. 重新运行验证 + +### 生成代码问题 + +1. 运行 `npm run validate:gen` 识别问题 +2. 检查源分类数据 +3. 使用 `npm run generate` 重新生成 + +### 数据项被错误标记为删除 + +检查提取脚本的模式是否正确匹配代码结构。 + +### 如何恢复意外删除的分类 + +从以下位置恢复 `classification.json`: +- 自动备份文件:`classification.backup.json` +- Git 历史记录 + +--- + +## 当前进度 (2025-11-28) + +### 已完成 +1. **自动生成映射关系** - `generate-migration.js` 生成纯映射代码 +2. **158 个真实配置项迁移** - 替换了原来的 3 个硬编码测试项 +3. **嵌套路径支持** - 处理 Redux Store children 结构(39 个嵌套路径) +4. **类型安全迁移** - 基于 `preferenceSchemas.ts` 类型定义 +5. **脚本重构** - 共享工具、一致路径、移除废弃脚本 + +### 生成的核心文件 +- **preferenceSchemas.ts** - 类型安全配置定义(200 个偏好项) +- **PreferencesMappings.ts** - 纯映射常量(ElectronStore + Redux 项) + +### 技术特性 +- **数据源分离**: ElectronStore(简单数组)、Redux Store(按类别分组) +- **嵌套路径解析**: 支持 `codeEditor.enabled`、`exportMenuOptions.docx` 等 +- **统一默认值管理**: 单一数据源,无重复定义 +- **自动去重**: 重复 targetKey 自动处理(redux 优先级最高) diff --git a/v2-refactor-temp/tools/data-classify/data/classification.json b/v2-refactor-temp/tools/data-classify/data/classification.json new file mode 100644 index 0000000000..d32170ccd9 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/data/classification.json @@ -0,0 +1,3409 @@ +{ + "metadata": { + "version": "2.0.0", + "lastUpdated": "2025-11-29T03:44:52.215Z", + "totalItems": 385, + "classified": 256, + "pending": 123, + "deleted": 0 + }, + "classifications": { + "redux": { + "assistants": [ + { + "originalKey": "defaultAssistant", + "type": "unknown", + "defaultValue": "getDefaultAssistant()", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "assistants", + "type": "array", + "defaultValue": "[getDefaultAssistant()]", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "tagsOrder", + "type": "string", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "collapsedTags", + "type": "object", + "defaultValue": {}, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "presets", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "unifiedListOrder", + "type": "unknown", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "backup": [ + { + "originalKey": "webdavSync", + "type": "object", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }", + "status": "classified", + "category": "cache", + "targetKey": null + }, + { + "originalKey": "localBackupSync", + "type": "object", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }", + "status": "classified", + "category": "cache", + "targetKey": null + }, + { + "originalKey": "s3Sync", + "type": "object", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }", + "status": "classified", + "category": "cache", + "targetKey": null + } + ], + "copilot": [ + { + "originalKey": "username", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": null + }, + { + "originalKey": "avatar", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": null + }, + { + "originalKey": "defaultHeaders", + "type": "object", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": null + } + ], + "inputTools": [ + { + "originalKey": "toolOrder", + "type": "string", + "defaultValue": "DEFAULT_TOOL_ORDER", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "sessionToolOrder", + "type": "string", + "defaultValue": "DEFAULT_TOOL_ORDER_BY_SCOPE[TopicType.Session]", + "status": "pending", + "category": null, + "targetKey": null + } + ], + "knowledge": [ + { + "originalKey": "bases", + "type": "array", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "llm": [ + { + "originalKey": "providers", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "defaultModel", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[0]", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": null, + "defaultValue": "gpt-3.5-turbo", + "originalKey": "id", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "GPT-3.5 Turbo", + "originalKey": "name", + "status": "pending", + "targetKey": null, + "type": "string" + } + ] + }, + { + "originalKey": "topicNamingModel", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[1]", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": null, + "defaultValue": "gpt-4", + "originalKey": "id", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "GPT-4", + "originalKey": "name", + "status": "pending", + "targetKey": null, + "type": "string" + } + ] + }, + { + "originalKey": "quickModel", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[1]", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": null, + "defaultValue": "gpt-4", + "originalKey": "id", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "GPT-4", + "originalKey": "name", + "status": "pending", + "targetKey": null, + "type": "string" + } + ] + }, + { + "originalKey": "translateModel", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[2]", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": null, + "defaultValue": "claude-3", + "originalKey": "id", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "Claude 3", + "originalKey": "name", + "status": "pending", + "targetKey": null, + "type": "string" + } + ] + }, + { + "originalKey": "quickAssistantId", + "type": "string", + "defaultValue": "", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "settings", + "type": "unknown", + "defaultValue": "{ ollama: { keepAliveTime: 0 }, lmstudio: { keepAliveTime: 0 }, gpustack: { keepAliveTime: 0 }, vertexai: { serviceAccount: { privateKey: '', clientEmail: '' }, projectId: '', location: '' }, awsBedrock: { authType: 'iam', accessKeyId: '', secretAccessKey: '', apiKey: '', region: '' } }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "children": [ + { + "category": null, + "defaultValue": 0, + "originalKey": "keepAliveTime", + "status": "pending", + "targetKey": null, + "type": "number" + } + ], + "originalKey": "ollama" + }, + { + "children": [ + { + "category": null, + "defaultValue": 0, + "originalKey": "keepAliveTime", + "status": "pending", + "targetKey": null, + "type": "number" + } + ], + "originalKey": "lmstudio" + }, + { + "children": [ + { + "category": null, + "defaultValue": 0, + "originalKey": "keepAliveTime", + "status": "pending", + "targetKey": null, + "type": "number" + } + ], + "originalKey": "gpustack" + }, + { + "children": [ + { + "children": [ + { + "category": null, + "defaultValue": "", + "originalKey": "privateKey", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "", + "originalKey": "clientEmail", + "status": "pending", + "targetKey": null, + "type": "string" + } + ], + "originalKey": "serviceAccount" + }, + { + "category": null, + "defaultValue": "", + "originalKey": "projectId", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "", + "originalKey": "location", + "status": "pending", + "targetKey": null, + "type": "string" + } + ], + "originalKey": "vertexai" + }, + { + "children": [ + { + "category": null, + "defaultValue": "", + "originalKey": "accessKeyId", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "", + "originalKey": "secretAccessKey", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "", + "originalKey": "region", + "status": "pending", + "targetKey": null, + "type": "string" + } + ], + "originalKey": "awsBedrock" + } + ] + } + ], + "mcp": [ + { + "originalKey": "servers", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "isUvInstalled", + "type": "boolean", + "defaultValue": true, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "memory": [ + { + "originalKey": "memoryConfig", + "type": "unknown", + "defaultValue": "defaultMemoryConfig", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": 1536, + "originalKey": "embedderDimensions", + "status": "classified", + "targetKey": "feature.memory.embedder_dimensions", + "type": "number" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "isAutoDimensions", + "status": "classified", + "targetKey": "feature.memory.auto_dimensions", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": "VALUE: MEMORY_FACT_EXTRACTION_PROMPT", + "originalKey": "customFactExtractionPrompt", + "status": "classified", + "targetKey": "feature.memory.fact_extraction_prompt", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "VALUE: MEMORY_UPDATE_SYSTEM_PROMPT", + "originalKey": "customUpdateMemoryPrompt", + "status": "classified", + "targetKey": "feature.memory.update_memory_prompt", + "type": "string" + } + ] + }, + { + "originalKey": "currentUserId", + "type": "string", + "defaultValue": "default-user", + "status": "classified", + "category": "preferences", + "targetKey": "feature.memory.current_user_id" + }, + { + "originalKey": "globalMemoryEnabled", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.memory.enabled" + } + ], + "messageBlock": [], + "migrate": [], + "minapps": [ + { + "originalKey": "enabled", + "type": "string", + "defaultValue": "DEFAULT_MIN_APPS", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "disabled", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + } + ], + "newMessage": [], + "nutstore": [ + { + "originalKey": "nutstoreToken", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.nutstore.token" + }, + { + "originalKey": "nutstorePath", + "type": "string", + "defaultValue": "/cherry-studio", + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.nutstore.path" + }, + { + "originalKey": "nutstoreAutoSync", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.nutstore.auto_sync" + }, + { + "originalKey": "nutstoreSyncInterval", + "type": "number", + "defaultValue": 0, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.nutstore.sync_interval" + }, + { + "originalKey": "nutstoreSyncState", + "type": "object", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }", + "status": "pending", + "category": "preferences", + "targetKey": null + }, + { + "originalKey": "nutstoreSkipBackupFile", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.nutstore.skip_backup_file" + }, + { + "originalKey": "nutstoreMaxBackups", + "type": "number", + "defaultValue": 0, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.nutstore.max_backups" + } + ], + "paintings": [ + { + "originalKey": "siliconflow_paintings", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "dmxapi_paintings", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "tokenflux_paintings", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "zhipu_paintings", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "aihubmix_image_generate", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "aihubmix_image_remix", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "aihubmix_image_edit", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "aihubmix_image_upscale", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "openai_image_generate", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "openai_image_edit", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + } + ], + "preprocess": [ + { + "originalKey": "providers", + "type": "array", + "defaultValue": "[ { id: 'mineru', name: 'MinerU', apiKey: '', apiHost: 'https://mineru.net' }", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "defaultProvider", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "runtime": [ + { + "originalKey": "chat", + "type": "object", + "defaultValue": "{ isMultiSelectMode: false, selectedMessageIds: [], activeTopic: null, activeAgentId: null, activeTopicOrSession: 'topic', activeSessionIdMap: {}, renamingTopics: [], newlyRenamedTopics: [], sessionWaiting: {} }", + "status": "classified", + "category": "cache", + "targetKey": null + } + ], + "selectionStore": [ + { + "originalKey": "selectionEnabled", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.enabled" + }, + { + "originalKey": "triggerMode", + "type": "PreferenceTypes.SelectionTriggerMode", + "defaultValue": "VALUE: PreferenceTypes.SelectionTriggerMode.Selected", + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.trigger_mode" + }, + { + "originalKey": "isCompact", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.compact" + }, + { + "originalKey": "isAutoClose", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.auto_close" + }, + { + "originalKey": "isAutoPin", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.auto_pin" + }, + { + "originalKey": "isFollowToolbar", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.follow_toolbar" + }, + { + "originalKey": "isRemeberWinSize", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.remember_win_size" + }, + { + "originalKey": "filterMode", + "type": "PreferenceTypes.SelectionFilterMode", + "defaultValue": "VALUE: PreferenceTypes.SelectionFilterMode.Default", + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.filter_mode" + }, + { + "originalKey": "filterList", + "type": "string[]", + "defaultValue": [], + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.filter_list" + }, + { + "originalKey": "actionWindowOpacity", + "type": "number", + "defaultValue": 100, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.action_window_opacity" + }, + { + "originalKey": "actionItems", + "type": "PreferenceTypes.SelectionActionItem[]", + "defaultValue": [ + { + "enabled": true, + "icon": "languages", + "id": "translate", + "isBuiltIn": true, + "name": "selection.action.builtin.translate" + }, + { + "enabled": true, + "icon": "file-question", + "id": "explain", + "isBuiltIn": true, + "name": "selection.action.builtin.explain" + }, + { + "enabled": true, + "icon": "scan-text", + "id": "summary", + "isBuiltIn": true, + "name": "selection.action.builtin.summary" + }, + { + "enabled": true, + "icon": "search", + "id": "search", + "isBuiltIn": true, + "name": "selection.action.builtin.search", + "searchEngine": "Google|https://www.google.com/search?q={{queryString}}" + }, + { + "enabled": true, + "icon": "clipboard-copy", + "id": "copy", + "isBuiltIn": true, + "name": "selection.action.builtin.copy" + }, + { + "enabled": false, + "icon": "wand-sparkles", + "id": "refine", + "isBuiltIn": true, + "name": "selection.action.builtin.refine" + }, + { + "enabled": false, + "icon": "quote", + "id": "quote", + "isBuiltIn": true, + "name": "selection.action.builtin.quote" + } + ], + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.action_items" + } + ], + "settings": [ + { + "originalKey": "showAssistants", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "assistant.tab.show" + }, + { + "originalKey": "showTopics", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "topic.tab.show" + }, + { + "originalKey": "assistantsTabSortType", + "type": "PreferenceTypes.AssistantTabSortType", + "defaultValue": "list", + "status": "classified", + "category": "preferences", + "targetKey": "assistant.tab.sort_type" + }, + { + "originalKey": "sendMessageShortcut", + "type": "PreferenceTypes.SendMessageShortcut", + "defaultValue": "Enter", + "status": "classified", + "category": "preferences", + "targetKey": "chat.input.send_message_shortcut" + }, + { + "originalKey": "language", + "type": "PreferenceTypes.LanguageVarious", + "defaultValue": "VALUE: null", + "status": "classified", + "category": "preferences", + "targetKey": "app.language" + }, + { + "originalKey": "targetLanguage", + "type": "string", + "defaultValue": "en-us", + "status": "classified", + "category": "preferences", + "targetKey": "feature.translate.target_language" + }, + { + "originalKey": "proxyMode", + "type": "PreferenceTypes.ProxyMode", + "defaultValue": "system", + "status": "classified", + "category": "preferences", + "targetKey": "app.proxy.mode" + }, + { + "originalKey": "proxyUrl", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "app.proxy.url" + }, + { + "originalKey": "proxyBypassRules", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "app.proxy.bypass_rules" + }, + { + "originalKey": "userName", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "app.user.name" + }, + { + "originalKey": "userId", + "type": "string", + "defaultValue": "uuid()", + "status": "classified", + "category": "preferences", + "targetKey": "app.user.id" + }, + { + "originalKey": "showPrompt", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.show_prompt" + }, + { + "originalKey": "showMessageDivider", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.show_divider" + }, + { + "originalKey": "messageFont", + "type": "string", + "defaultValue": "system", + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.font" + }, + { + "originalKey": "showInputEstimatedTokens", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.input.show_estimated_tokens" + }, + { + "originalKey": "launchOnBoot", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.launch_on_boot" + }, + { + "originalKey": "launchToTray", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.tray.on_launch" + }, + { + "originalKey": "trayOnClose", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "app.tray.on_close" + }, + { + "originalKey": "tray", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "app.tray.enabled" + }, + { + "originalKey": "theme", + "type": "PreferenceTypes.ThemeMode", + "defaultValue": "VALUE: PreferenceTypes.ThemeMode.system", + "status": "classified", + "category": "preferences", + "targetKey": "ui.theme_mode" + }, + { + "originalKey": "userTheme", + "type": "unknown", + "defaultValue": "{ colorPrimary: '#00b96b', userFontFamily: '', userCodeFontFamily: '' }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": "#00b96b", + "originalKey": "colorPrimary", + "status": "classified", + "targetKey": "ui.theme_user.color_primary", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "", + "originalKey": "userFontFamily", + "status": "classified", + "targetKey": "ui.theme_user.font_family", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "", + "originalKey": "userCodeFontFamily", + "status": "classified", + "targetKey": "ui.theme_user.code_font_family", + "type": "string" + } + ] + }, + { + "originalKey": "windowStyle", + "type": "PreferenceTypes.WindowStyle", + "defaultValue": "opaque", + "status": "classified", + "category": "preferences", + "targetKey": "ui.window_style" + }, + { + "originalKey": "fontSize", + "type": "number", + "defaultValue": 14, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.font_size" + }, + { + "originalKey": "topicPosition", + "type": "string", + "defaultValue": "left", + "status": "classified", + "category": "preferences", + "targetKey": "topic.position" + }, + { + "originalKey": "showTopicTime", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "topic.tab.show_time" + }, + { + "originalKey": "pinTopicsToTop", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "topic.tab.pin_to_top" + }, + { + "originalKey": "assistantIconType", + "type": "PreferenceTypes.AssistantIconType", + "defaultValue": "emoji", + "status": "classified", + "category": "preferences", + "targetKey": "assistant.icon_type" + }, + { + "originalKey": "pasteLongTextAsFile", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.input.paste_long_text_as_file" + }, + { + "originalKey": "pasteLongTextThreshold", + "type": "number", + "defaultValue": 1500, + "status": "classified", + "category": "preferences", + "targetKey": "chat.input.paste_long_text_threshold" + }, + { + "originalKey": "clickAssistantToShowTopic", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "assistant.click_to_show_topic" + }, + { + "originalKey": "autoCheckUpdate", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "app.dist.auto_update.enabled" + }, + { + "originalKey": "testPlan", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.dist.test_plan.enabled" + }, + { + "originalKey": "testChannel", + "type": "PreferenceTypes.UpgradeChannel", + "defaultValue": "VALUE: PreferenceTypes.UpgradeChannel.LATEST", + "status": "classified", + "category": "preferences", + "targetKey": "app.dist.test_plan.channel" + }, + { + "originalKey": "renderInputMessageAsMarkdown", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.render_as_markdown" + }, + { + "originalKey": "codeExecution", + "type": "unknown", + "defaultValue": "{ enabled: false, timeoutMinutes: 1 }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": false, + "originalKey": "enabled", + "status": "classified", + "targetKey": "chat.code.execution.enabled", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": 1, + "originalKey": "timeoutMinutes", + "status": "classified", + "targetKey": "chat.code.execution.timeout_minutes", + "type": "number" + } + ] + }, + { + "originalKey": "enabled", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.execution.enabled" + }, + { + "originalKey": "timeoutMinutes", + "type": "number", + "defaultValue": 1, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.execution.timeout_minutes" + }, + { + "originalKey": "codeEditor", + "type": "unknown", + "defaultValue": "{ enabled: false, themeLight: 'auto', themeDark: 'auto', highlightActiveLine: false, foldGutter: false, autocompletion: true, keymap: false }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": false, + "originalKey": "enabled", + "status": "classified", + "targetKey": "chat.code.editor.enabled", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": "auto", + "originalKey": "themeLight", + "status": "classified", + "targetKey": "chat.code.editor.theme_light", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "auto", + "originalKey": "themeDark", + "status": "classified", + "targetKey": "chat.code.editor.theme_dark", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": false, + "originalKey": "highlightActiveLine", + "status": "classified", + "targetKey": "chat.code.editor.highlight_active_line", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": false, + "originalKey": "foldGutter", + "status": "classified", + "targetKey": "chat.code.editor.fold_gutter", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "autocompletion", + "status": "classified", + "targetKey": "chat.code.editor.autocompletion", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": false, + "originalKey": "keymap", + "status": "classified", + "targetKey": "chat.code.editor.keymap", + "type": "boolean" + } + ] + }, + { + "originalKey": "themeLight", + "type": "string", + "defaultValue": "auto", + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.editor.theme_light" + }, + { + "originalKey": "themeDark", + "type": "string", + "defaultValue": "auto", + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.editor.theme_dark" + }, + { + "originalKey": "highlightActiveLine", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.editor.highlight_active_line" + }, + { + "originalKey": "foldGutter", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.editor.fold_gutter" + }, + { + "originalKey": "autocompletion", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.editor.autocompletion" + }, + { + "originalKey": "keymap", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.editor.keymap" + }, + { + "originalKey": "codePreview", + "type": "unknown", + "defaultValue": "{ themeLight: 'auto', themeDark: 'auto' }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": "auto", + "originalKey": "themeLight", + "status": "classified", + "targetKey": "chat.code.preview.theme_light", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "auto", + "originalKey": "themeDark", + "status": "classified", + "targetKey": "chat.code.preview.theme_dark", + "type": "string" + } + ] + }, + { + "originalKey": "codeViewer", + "type": "unknown", + "defaultValue": "{ themeLight: 'auto', themeDark: 'auto' }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": "auto", + "originalKey": "themeLight", + "status": "classified", + "targetKey": "chat.code.viewer.theme_light", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "auto", + "originalKey": "themeDark", + "status": "classified", + "targetKey": "chat.code.viewer.theme_dark", + "type": "string" + } + ] + }, + { + "originalKey": "codeShowLineNumbers", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.show_line_numbers" + }, + { + "originalKey": "codeCollapsible", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.collapsible" + }, + { + "originalKey": "codeWrappable", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.wrappable" + }, + { + "originalKey": "codeImageTools", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.image_tools" + }, + { + "originalKey": "codeFancyBlock", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.code.fancy_block" + }, + { + "originalKey": "mathEngine", + "type": "PreferenceTypes.MathEngine", + "defaultValue": "KaTeX", + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.math.engine" + }, + { + "originalKey": "mathEnableSingleDollar", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.math.single_dollar" + }, + { + "originalKey": "messageStyle", + "type": "PreferenceTypes.ChatMessageStyle", + "defaultValue": "plain", + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.style" + }, + { + "originalKey": "foldDisplayMode", + "type": "PreferenceTypes.MultiModelFoldDisplayMode", + "defaultValue": "expanded", + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.multi_model.fold_display_mode" + }, + { + "originalKey": "gridColumns", + "type": "number", + "defaultValue": 2, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.multi_model.grid_columns" + }, + { + "originalKey": "gridPopoverTrigger", + "type": "PreferenceTypes.MultiModelGridPopoverTrigger", + "defaultValue": "click", + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.multi_model.grid_popover_trigger" + }, + { + "originalKey": "messageNavigation", + "type": "PreferenceTypes.ChatMessageNavigationMode", + "defaultValue": "none", + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.navigation_mode" + }, + { + "originalKey": "skipBackupFile", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.general.skip_backup_file" + }, + { + "originalKey": "webdavHost", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.host" + }, + { + "originalKey": "webdavUser", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.user" + }, + { + "originalKey": "webdavPass", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.pass" + }, + { + "originalKey": "webdavPath", + "type": "string", + "defaultValue": "/cherry-studio", + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.path" + }, + { + "originalKey": "webdavAutoSync", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.auto_sync" + }, + { + "originalKey": "webdavSyncInterval", + "type": "number", + "defaultValue": 0, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.sync_interval" + }, + { + "originalKey": "webdavMaxBackups", + "type": "number", + "defaultValue": 0, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.max_backups" + }, + { + "originalKey": "webdavSkipBackupFile", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.skip_backup_file" + }, + { + "originalKey": "webdavDisableStream", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.webdav.disable_stream" + }, + { + "originalKey": "translateModelPrompt", + "type": "string", + "defaultValue": "VALUE: TRANSLATE_PROMPT", + "status": "classified", + "category": "preferences", + "targetKey": "feature.translate.model_prompt" + }, + { + "originalKey": "autoTranslateWithSpace", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.input.translate.auto_translate_with_space" + }, + { + "originalKey": "showTranslateConfirm", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.input.translate.show_confirm" + }, + { + "originalKey": "enableTopicNaming", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "topic.naming.enabled" + }, + { + "originalKey": "customCss", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "ui.custom_css" + }, + { + "originalKey": "topicNamingPrompt", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "topic.naming_prompt" + }, + { + "originalKey": "confirmDeleteMessage", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.confirm_delete" + }, + { + "originalKey": "confirmRegenerateMessage", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.confirm_regenerate" + }, + { + "originalKey": "sidebarIcons", + "type": "unknown", + "defaultValue": "{ visible: DefaultPreferences.default['ui.sidebar.icons.visible'], disabled: [] }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": [ + "assistants", + "store", + "paintings", + "translate", + "minapp", + "knowledge", + "files", + "code_tools", + "notes" + ], + "originalKey": "visible", + "status": "classified", + "targetKey": "ui.sidebar.icons.visible", + "type": "PreferenceTypes.SidebarIcon[]" + }, + { + "category": "preferences", + "defaultValue": [], + "originalKey": "disabled", + "status": "classified", + "targetKey": "ui.sidebar.icons.invisible", + "type": "PreferenceTypes.SidebarIcon[]" + } + ] + }, + { + "originalKey": "visible", + "type": "PreferenceTypes.SidebarIcon[]", + "defaultValue": [ + "assistants", + "store", + "paintings", + "translate", + "minapp", + "knowledge", + "files", + "code_tools", + "notes" + ], + "status": "classified", + "category": "preferences", + "targetKey": "ui.sidebar.icons.visible" + }, + { + "originalKey": "disabled", + "type": "PreferenceTypes.SidebarIcon[]", + "defaultValue": [], + "status": "classified", + "category": "preferences", + "targetKey": "ui.sidebar.icons.invisible" + }, + { + "originalKey": "narrowMode", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.narrow_mode" + }, + { + "originalKey": "enableQuickAssistant", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.quick_assistant.enabled" + }, + { + "originalKey": "clickTrayToShowQuickAssistant", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.quick_assistant.click_tray_to_show" + }, + { + "originalKey": "multiModelMessageStyle", + "type": "PreferenceTypes.MultiModelMessageStyle", + "defaultValue": "horizontal", + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.multi_model.style" + }, + { + "originalKey": "readClipboardAtStartup", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "feature.quick_assistant.read_clipboard_at_startup" + }, + { + "originalKey": "notionDatabaseID", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.notion.database_id" + }, + { + "originalKey": "notionApiKey", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.notion.api_key" + }, + { + "originalKey": "notionPageNameKey", + "type": "string", + "defaultValue": "Name", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.notion.page_name_key" + }, + { + "originalKey": "markdownExportPath", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.markdown.path" + }, + { + "originalKey": "forceDollarMathInMarkdown", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.markdown.force_dollar_math" + }, + { + "originalKey": "useTopicNamingForMessageTitle", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.markdown.use_topic_naming_for_message_title" + }, + { + "originalKey": "showModelNameInMarkdown", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.markdown.show_model_name" + }, + { + "originalKey": "showModelProviderInMarkdown", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.markdown.show_model_provider" + }, + { + "originalKey": "thoughtAutoCollapse", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.thought.auto_collapse" + }, + { + "originalKey": "notionExportReasoning", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.notion.export_reasoning" + }, + { + "originalKey": "excludeCitationsInExport", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.markdown.exclude_citations" + }, + { + "originalKey": "standardizeCitationsInExport", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.markdown.standardize_citations" + }, + { + "originalKey": "yuqueToken", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.yuque.token" + }, + { + "originalKey": "yuqueUrl", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.yuque.url" + }, + { + "originalKey": "yuqueRepoId", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.yuque.repo_id" + }, + { + "originalKey": "joplinToken", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.joplin.token" + }, + { + "originalKey": "joplinUrl", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.joplin.url" + }, + { + "originalKey": "joplinExportReasoning", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.joplin.export_reasoning" + }, + { + "originalKey": "defaultObsidianVault", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.obsidian.default_vault" + }, + { + "originalKey": "defaultAgent", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": null + }, + { + "originalKey": "siyuanApiUrl", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.siyuan.api_url" + }, + { + "originalKey": "siyuanToken", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.siyuan.token" + }, + { + "originalKey": "siyuanBoxId", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.siyuan.box_id" + }, + { + "originalKey": "siyuanRootPath", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "data.integration.siyuan.root_path" + }, + { + "originalKey": "agentssubscribeUrl", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": null + }, + { + "originalKey": "maxKeepAliveMinapps", + "type": "number", + "defaultValue": 3, + "status": "classified", + "category": "preferences", + "targetKey": "feature.minapp.max_keep_alive" + }, + { + "originalKey": "showOpenedMinappsInSidebar", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "feature.minapp.show_opened_in_sidebar" + }, + { + "originalKey": "minappsOpenLinkExternal", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "feature.minapp.open_link_external" + }, + { + "originalKey": "enableDataCollection", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.privacy.data_collection.enabled" + }, + { + "originalKey": "enableSpellCheck", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.spell_check.enabled" + }, + { + "originalKey": "spellCheckLanguages", + "type": "string[]", + "defaultValue": [], + "status": "classified", + "category": "preferences", + "targetKey": "app.spell_check.languages" + }, + { + "originalKey": "enableQuickPanelTriggers", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.input.quick_panel.triggers_enabled" + }, + { + "originalKey": "disableHardwareAcceleration", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.disable_hardware_acceleration" + }, + { + "originalKey": "exportMenuOptions", + "type": "unknown", + "defaultValue": "{ image: true, markdown: true, markdown_reason: true, notion: true, yuque: true, joplin: true, obsidian: true, siyuan: true, docx: true, plain_text: true, notes: true }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": true, + "originalKey": "image", + "status": "classified", + "targetKey": "data.export.menus.image", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "markdown", + "status": "classified", + "targetKey": "data.export.menus.markdown", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "markdown_reason", + "status": "classified", + "targetKey": "data.export.menus.markdown_reason", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "notion", + "status": "classified", + "targetKey": "data.export.menus.notion", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "yuque", + "status": "classified", + "targetKey": "data.export.menus.yuque", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "joplin", + "status": "classified", + "targetKey": "data.export.menus.joplin", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "obsidian", + "status": "classified", + "targetKey": "data.export.menus.obsidian", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "siyuan", + "status": "classified", + "targetKey": "data.export.menus.siyuan", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "docx", + "status": "classified", + "targetKey": "data.export.menus.docx", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "plain_text", + "status": "classified", + "targetKey": "data.export.menus.plain_text", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "notes", + "status": "classified", + "targetKey": "data.export.menus.notes", + "type": "boolean" + } + ] + }, + { + "originalKey": "image", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.image" + }, + { + "originalKey": "markdown", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.markdown" + }, + { + "originalKey": "markdown_reason", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.markdown_reason" + }, + { + "originalKey": "notion", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.notion" + }, + { + "originalKey": "yuque", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.yuque" + }, + { + "originalKey": "joplin", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.joplin" + }, + { + "originalKey": "obsidian", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.obsidian" + }, + { + "originalKey": "siyuan", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.siyuan" + }, + { + "originalKey": "docx", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.docx" + }, + { + "originalKey": "plain_text", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.plain_text" + }, + { + "originalKey": "notes", + "type": "boolean", + "defaultValue": true, + "status": "classified", + "category": "preferences", + "targetKey": "data.export.menus.notes" + }, + { + "originalKey": "openAI", + "type": "unknown", + "defaultValue": "{ summaryText: 'auto', serviceTier: 'auto', verbosity: undefined }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": "off", + "originalKey": "summaryText", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "auto", + "originalKey": "serviceTier", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "medium", + "originalKey": "verbosity", + "status": "pending", + "targetKey": null, + "type": "string" + } + ] + }, + { + "originalKey": "summaryText", + "type": "string", + "defaultValue": "off", + "status": "pending", + "category": "preferences", + "targetKey": null + }, + { + "originalKey": "serviceTier", + "type": "string", + "defaultValue": "auto", + "status": "pending", + "category": "preferences", + "targetKey": null + }, + { + "originalKey": "verbosity", + "type": "string", + "defaultValue": "medium", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "notification", + "type": "unknown", + "defaultValue": "{ assistant: false, backup: false, knowledge: false }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": false, + "originalKey": "assistant", + "status": "classified", + "targetKey": "app.notification.assistant.enabled", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": false, + "originalKey": "backup", + "status": "classified", + "targetKey": "app.notification.backup.enabled", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": false, + "originalKey": "knowledge", + "status": "classified", + "targetKey": "app.notification.knowledge.enabled", + "type": "boolean" + } + ] + }, + { + "originalKey": "assistant", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.notification.assistant.enabled" + }, + { + "originalKey": "backup", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.notification.backup.enabled" + }, + { + "originalKey": "knowledge", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.notification.knowledge.enabled" + }, + { + "originalKey": "localBackupDir", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.local.dir" + }, + { + "originalKey": "localBackupAutoSync", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.local.auto_sync" + }, + { + "originalKey": "localBackupSyncInterval", + "type": "number", + "defaultValue": 0, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.local.sync_interval" + }, + { + "originalKey": "localBackupMaxBackups", + "type": "number", + "defaultValue": 0, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.local.max_backups" + }, + { + "originalKey": "localBackupSkipBackupFile", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "data.backup.local.skip_backup_file" + }, + { + "originalKey": "defaultPaintingProvider", + "type": "string", + "defaultValue": "zhipu", + "status": "pending", + "category": "cache", + "targetKey": null + }, + { + "originalKey": "s3", + "type": "unknown", + "defaultValue": "{ endpoint: '', region: '', bucket: '', accessKeyId: '', secretAccessKey: '', root: '', autoSync: false, syncInterval: 0, maxBackups: 0, skipBackupFile: false }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": "", + "originalKey": "endpoint", + "status": "classified", + "targetKey": "data.backup.s3.endpoint", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "", + "originalKey": "region", + "status": "classified", + "targetKey": "data.backup.s3.region", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "", + "originalKey": "bucket", + "status": "classified", + "targetKey": "data.backup.s3.bucket", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "", + "originalKey": "accessKeyId", + "status": "classified", + "targetKey": "data.backup.s3.access_key_id", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "", + "originalKey": "secretAccessKey", + "status": "classified", + "targetKey": "data.backup.s3.secret_access_key", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "", + "originalKey": "root", + "status": "classified", + "targetKey": "data.backup.s3.root", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": false, + "originalKey": "autoSync", + "status": "classified", + "targetKey": "data.backup.s3.auto_sync", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": 0, + "originalKey": "syncInterval", + "status": "classified", + "targetKey": "data.backup.s3.sync_interval", + "type": "number" + }, + { + "category": "preferences", + "defaultValue": 0, + "originalKey": "maxBackups", + "status": "classified", + "targetKey": "data.backup.s3.max_backups", + "type": "number" + }, + { + "category": "preferences", + "defaultValue": false, + "originalKey": "skipBackupFile", + "status": "classified", + "targetKey": "data.backup.s3.skip_backup_file", + "type": "boolean" + } + ] + }, + { + "originalKey": "enableDeveloperMode", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "app.developer_mode.enabled" + }, + { + "originalKey": "navbarPosition", + "type": "'left' | 'top'", + "defaultValue": "top", + "status": "classified", + "category": "preferences", + "targetKey": "ui.navbar.position" + }, + { + "originalKey": "apiServer", + "type": "unknown", + "defaultValue": "{ enabled: false, host: 'localhost', port: 23333, apiKey: `cs-sk-${uuid()}` }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": false, + "originalKey": "enabled", + "status": "classified", + "targetKey": "feature.csaas.enabled", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": "localhost", + "originalKey": "host", + "status": "classified", + "targetKey": "feature.csaas.host", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": 23333, + "originalKey": "port", + "status": "classified", + "targetKey": "feature.csaas.port", + "type": "number" + }, + { + "category": "preferences", + "defaultValue": "`cs-sk-${uuid()}`", + "originalKey": "apiKey", + "status": "classified", + "targetKey": "feature.csaas.api_key", + "type": "string" + } + ] + }, + { + "originalKey": "showMessageOutline", + "type": "boolean", + "defaultValue": false, + "status": "classified", + "category": "preferences", + "targetKey": "chat.message.show_outline" + } + ], + "shortcuts": [ + { + "originalKey": "shortcuts", + "type": "array", + "defaultValue": "[ ...ZOOM_SHORTCUTS", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": { + "editable": false, + "enabled": true, + "key": ["CommandOrControl", "="], + "system": true + }, + "originalKey": "zoom_in", + "status": "classified", + "targetKey": "shortcut.app.zoom_in", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": false, + "enabled": true, + "key": ["CommandOrControl", "-"], + "system": true + }, + "originalKey": "zoom_out", + "status": "classified", + "targetKey": "shortcut.app.zoom_out", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": false, + "enabled": true, + "key": ["CommandOrControl", "0"], + "system": true + }, + "originalKey": "zoom_reset", + "status": "classified", + "targetKey": "shortcut.app.zoom_reset", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": false, + "enabled": true, + "key": ["CommandOrControl", ","], + "system": true + }, + "originalKey": "show_settings", + "status": "classified", + "targetKey": "shortcut.app.show_settings", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": true, + "key": [], + "system": true + }, + "originalKey": "show_app", + "status": "classified", + "targetKey": "shortcut.app.show_main_window", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": false, + "key": ["CommandOrControl", "E"], + "system": true + }, + "originalKey": "mini_window", + "status": "classified", + "targetKey": "shortcut.app.show_mini_window", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": false, + "key": [], + "system": true + }, + "originalKey": "selection_assistant_toggle", + "status": "classified", + "targetKey": "shortcut.selection.toggle_enabled", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": false, + "key": [], + "system": true + }, + "originalKey": "selection_assistant_select_text", + "status": "classified", + "targetKey": "shortcut.selection.get_text", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": true, + "key": ["CommandOrControl", "N"], + "system": false + }, + "originalKey": "new_topic", + "status": "classified", + "targetKey": "shortcut.topic.new", + "type": "object" + }, + { + "category": null, + "defaultValue": { + "editable": true, + "enabled": false, + "key": ["CommandOrControl", "T"], + "system": false + }, + "originalKey": "rename_topic", + "status": "pending", + "targetKey": null, + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": true, + "key": ["CommandOrControl", "["], + "system": false + }, + "originalKey": "toggle_show_assistants", + "status": "classified", + "targetKey": "shortcut.app.toggle_show_assistants", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": false, + "key": ["CommandOrControl", "Shift", "C"], + "system": false + }, + "originalKey": "copy_last_message", + "status": "classified", + "targetKey": "shortcut.chat.copy_last_message", + "type": "object" + }, + { + "category": null, + "defaultValue": { + "editable": true, + "enabled": false, + "key": ["CommandOrControl", "Shift", "E"], + "system": false + }, + "originalKey": "edit_last_user_message", + "status": "pending", + "targetKey": null, + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": true, + "key": ["CommandOrControl", "F"], + "system": false + }, + "originalKey": "search_message_in_chat", + "status": "classified", + "targetKey": "shortcut.chat.search_message", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": true, + "key": ["CommandOrControl", "Shift", "F"], + "system": false + }, + "originalKey": "search_message", + "status": "classified", + "targetKey": "shortcut.app.search_message", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": true, + "key": ["CommandOrControl", "L"], + "system": false + }, + "originalKey": "clear_topic", + "status": "classified", + "targetKey": "shortcut.chat.clear", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": true, + "enabled": true, + "key": ["CommandOrControl", "K"], + "system": false + }, + "originalKey": "toggle_new_context", + "status": "classified", + "targetKey": "shortcut.chat.toggle_new_context", + "type": "object" + }, + { + "category": "preferences", + "defaultValue": { + "editable": false, + "enabled": true, + "key": ["Escape"], + "system": true + }, + "originalKey": "exit_fullscreen", + "status": "classified", + "targetKey": "shortcut.app.exit_fullscreen", + "type": "object" + } + ] + } + ], + "tabs": [ + { + "originalKey": "tabs", + "type": "array", + "defaultValue": "[ { id: 'home', path: '/' }", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "activeTabId", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "toolPermissions": [ + { + "originalKey": "requests", + "type": "string", + "defaultValue": {}, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "translate": [ + { + "originalKey": "translateInput", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "translatedContent", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "settings", + "type": "unknown", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "autoCopy", + "type": "boolean", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "websearch": [ + { + "originalKey": "defaultProvider", + "type": "string", + "defaultValue": "local-bing", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "providers", + "type": "string", + "defaultValue": "WEB_SEARCH_PROVIDERS", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "searchWithTime", + "type": "boolean", + "defaultValue": true, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "maxResults", + "type": "number", + "defaultValue": 5, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "excludeDomains", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "subscribeSources", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "overwrite", + "type": "boolean", + "defaultValue": false, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "compressionConfig", + "type": "unknown", + "defaultValue": "{ method: 'none', cutoffUnit: 'char' }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": null, + "defaultValue": "none", + "originalKey": "method", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "char", + "originalKey": "cutoffUnit", + "status": "pending", + "targetKey": null, + "type": "string" + } + ] + }, + { + "originalKey": "providerConfig", + "type": "object", + "defaultValue": {}, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "codeTools": [ + { + "originalKey": "selectedCliTool", + "type": "string", + "defaultValue": "codeTools.qwenCode", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "selectedModels", + "type": "string", + "defaultValue": "{ [codeTools.qwenCode]: null, [codeTools.claudeCode]: null, [codeTools.geminiCli]: null, [codeTools.openaiCodex]: null, [codeTools.iFlowCli]: null, [codeTools.githubCopilotCli]: null }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": null, + "defaultValue": null, + "originalKey": "[codeTools.qwenCode]", + "status": "pending", + "targetKey": null, + "type": "null" + }, + { + "category": null, + "defaultValue": null, + "originalKey": "[codeTools.claudeCode]", + "status": "pending", + "targetKey": null, + "type": "null" + }, + { + "category": null, + "defaultValue": null, + "originalKey": "[codeTools.geminiCli]", + "status": "pending", + "targetKey": null, + "type": "null" + }, + { + "category": null, + "defaultValue": null, + "originalKey": "[codeTools.openaiCodex]", + "status": "pending", + "targetKey": null, + "type": "null" + } + ] + }, + { + "originalKey": "environmentVariables", + "type": "string", + "defaultValue": { + "qwen-code": "", + "claude-code": "", + "gemini-cli": "", + "openai-codex": "", + "iflow-cli": "", + "github-copilot-cli": "" + }, + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": null, + "defaultValue": "", + "originalKey": "qwen-code", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "", + "originalKey": "claude-code", + "status": "pending", + "targetKey": null, + "type": "string" + }, + { + "category": null, + "defaultValue": "", + "originalKey": "gemini-cli", + "status": "pending", + "targetKey": null, + "type": "string" + } + ] + }, + { + "originalKey": "directories", + "type": "array", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "currentDirectory", + "type": "string", + "defaultValue": "", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "selectedTerminal", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "ocr": [ + { + "originalKey": "providers", + "type": "array", + "defaultValue": "BUILTIN_OCR_PROVIDERS", + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "imageProviderId", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "note": [ + { + "originalKey": "activeNodeId", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "activeFilePath", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "settings", + "type": "unknown", + "defaultValue": "{ isFullWidth: true, fontFamily: 'default', fontSize: 16, showTableOfContents: true, defaultViewMode: 'edit', defaultEditMode: 'preview', showTabStatus: true, showWorkspace: true }", + "status": "pending", + "category": null, + "targetKey": null, + "children": [ + { + "category": "preferences", + "defaultValue": true, + "originalKey": "isFullWidth", + "status": "classified", + "targetKey": "feature.notes.full_width", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": "default", + "originalKey": "fontFamily", + "status": "classified", + "targetKey": "feature.notes.font_family", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": 16, + "originalKey": "fontSize", + "status": "classified", + "targetKey": "feature.notes.font_size", + "type": "number" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "showTableOfContents", + "status": "classified", + "targetKey": "feature.notes.show_table_of_contents", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": "edit", + "originalKey": "defaultViewMode", + "status": "classified", + "targetKey": "feature.notes.default_view_mode", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": "preview", + "originalKey": "defaultEditMode", + "status": "classified", + "targetKey": "feature.notes.default_edit_mode", + "type": "string" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "showTabStatus", + "status": "classified", + "targetKey": "feature.notes.show_tab_status", + "type": "boolean" + }, + { + "category": "preferences", + "defaultValue": true, + "originalKey": "showWorkspace", + "status": "classified", + "targetKey": "feature.notes.show_workspace", + "type": "boolean" + } + ] + }, + { + "originalKey": "notesPath", + "type": "string", + "defaultValue": "", + "status": "classified", + "category": "preferences", + "targetKey": "feature.notes.path" + }, + { + "originalKey": "sortType", + "type": "string", + "defaultValue": "sort_a2z", + "status": "classified", + "category": "preferences", + "targetKey": "feature.notes.sort_type" + }, + { + "originalKey": "starredPaths", + "type": "string", + "defaultValue": [], + "status": "pending", + "category": null, + "targetKey": null + }, + { + "originalKey": "expandedPaths", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ] + }, + "electronStore": { + "Language": [ + { + "originalKey": "Language", + "type": "string", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.language" + } + ], + "Theme": [ + { + "originalKey": "Theme", + "type": "PreferenceTypes.ThemeMode", + "defaultValue": "VALUE: PreferenceTypes.ThemeMode.system", + "status": "classified", + "category": "preferences", + "targetKey": "ui.theme_mode" + } + ], + "LaunchToTray": [ + { + "originalKey": "LaunchToTray", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.tray.on_launch" + } + ], + "Tray": [ + { + "originalKey": "Tray", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.tray.enabled" + } + ], + "TrayOnClose": [ + { + "originalKey": "TrayOnClose", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.tray.on_close" + } + ], + "ZoomFactor": [ + { + "originalKey": "ZoomFactor", + "type": "number", + "defaultValue": 1, + "status": "classified", + "category": "preferences", + "targetKey": "app.zoom_factor" + } + ], + "Shortcuts": [ + { + "originalKey": "Shortcuts", + "type": "unknown", + "defaultValue": null, + "status": "pending", + "category": "preferences", + "targetKey": null + } + ], + "ClickTrayToShowQuickAssistant": [ + { + "originalKey": "ClickTrayToShowQuickAssistant", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "feature.quick_assistant.click_tray_to_show" + } + ], + "EnableQuickAssistant": [ + { + "originalKey": "EnableQuickAssistant", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "feature.quick_assistant.enabled" + } + ], + "AutoUpdate": [ + { + "originalKey": "AutoUpdate", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.dist.auto_update.enabled" + } + ], + "TestPlan": [ + { + "originalKey": "TestPlan", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.dist.test_plan.enabled" + } + ], + "TestChannel": [ + { + "originalKey": "TestChannel", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.dist.test_plan.channel" + } + ], + "EnableDataCollection": [ + { + "originalKey": "EnableDataCollection", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.privacy.data_collection.enabled" + } + ], + "SelectionAssistantEnabled": [ + { + "originalKey": "SelectionAssistantEnabled", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.enabled" + } + ], + "SelectionAssistantTriggerMode": [ + { + "originalKey": "SelectionAssistantTriggerMode", + "type": "PreferenceTypes.SelectionTriggerMode", + "defaultValue": "VALUE: PreferenceTypes.SelectionTriggerMode.Selected", + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.trigger_mode" + } + ], + "SelectionAssistantFollowToolbar": [ + { + "originalKey": "SelectionAssistantFollowToolbar", + "type": "boolean", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.follow_toolbar" + } + ], + "SelectionAssistantRemeberWinSize": [ + { + "originalKey": "SelectionAssistantRemeberWinSize", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.remember_win_size" + } + ], + "SelectionAssistantFilterMode": [ + { + "originalKey": "SelectionAssistantFilterMode", + "type": "PreferenceTypes.SelectionFilterMode", + "defaultValue": "default", + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.filter_mode" + } + ], + "SelectionAssistantFilterList": [ + { + "originalKey": "SelectionAssistantFilterList", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "feature.selection.filter_list" + } + ], + "DisableHardwareAcceleration": [ + { + "originalKey": "DisableHardwareAcceleration", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.disable_hardware_acceleration" + } + ], + "Proxy": [ + { + "originalKey": "Proxy", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": null + } + ], + "EnableDeveloperMode": [ + { + "originalKey": "EnableDeveloperMode", + "type": "unknown", + "defaultValue": null, + "status": "classified", + "category": "preferences", + "targetKey": "app.developer_mode.enabled" + } + ], + "ClientId": [ + { + "originalKey": "ClientId", + "type": "unknown", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ] + }, + "localStorage": { + "persist:cherry-studio": [ + { + "originalKey": "persist:cherry-studio", + "type": "string", + "defaultValue": "data.localStorage['persist:cherry-studio']", + "status": "pending", + "category": null, + "targetKey": null + } + ], + "memory_currentUserId": [ + { + "originalKey": "memory_currentUserId", + "type": "string", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ] + }, + "dexie": { + "files": [ + { + "originalKey": "files", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "topics": [ + { + "originalKey": "topics", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "settings": [ + { + "originalKey": "settings", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "knowledge_notes": [ + { + "originalKey": "knowledge_notes", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "translate_history": [ + { + "originalKey": "translate_history", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "quick_phrases": [ + { + "originalKey": "quick_phrases", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "message_blocks": [ + { + "originalKey": "message_blocks", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ], + "translate_languages": [ + { + "originalKey": "translate_languages", + "type": "table", + "defaultValue": null, + "status": "pending", + "category": null, + "targetKey": null + } + ] + } + } +} diff --git a/v2-refactor-temp/tools/data-classify/data/inventory.json b/v2-refactor-temp/tools/data-classify/data/inventory.json new file mode 100644 index 0000000000..d728e55890 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/data/inventory.json @@ -0,0 +1,1566 @@ +{ + "metadata": { + "generatedAt": "2025-11-29T03:44:51.977Z", + "version": "2.0.0", + "description": "Cherry Studio data inventory" + }, + "redux": { + "assistants": { + "_meta": { + "file": "src/renderer/src/store/assistants.ts", + "interface": "AssistantsState" + }, + "defaultAssistant": { + "file": "src/renderer/src/store/assistants.ts", + "type": "unknown", + "defaultValue": "getDefaultAssistant()" + }, + "assistants": { + "file": "src/renderer/src/store/assistants.ts", + "type": "array", + "defaultValue": "[getDefaultAssistant()]" + }, + "tagsOrder": { + "file": "src/renderer/src/store/assistants.ts", + "type": "string", + "defaultValue": [] + }, + "collapsedTags": { + "file": "src/renderer/src/store/assistants.ts", + "type": "string", + "defaultValue": {} + }, + "presets": { + "file": "src/renderer/src/store/assistants.ts", + "type": "array", + "defaultValue": [] + }, + "unifiedListOrder": { + "file": "src/renderer/src/store/assistants.ts", + "type": "unknown", + "defaultValue": null + } + }, + "backup": { + "_meta": { + "file": "src/renderer/src/store/backup.ts", + "interface": "BackupState" + }, + "webdavSync": { + "file": "src/renderer/src/store/backup.ts", + "type": "unknown", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }" + }, + "localBackupSync": { + "file": "src/renderer/src/store/backup.ts", + "type": "unknown", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }" + }, + "s3Sync": { + "file": "src/renderer/src/store/backup.ts", + "type": "unknown", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }" + } + }, + "copilot": { + "_meta": { + "file": "src/renderer/src/store/copilot.ts", + "interface": "CopilotState" + }, + "username": { + "file": "src/renderer/src/store/copilot.ts", + "type": "string", + "defaultValue": "" + }, + "avatar": { + "file": "src/renderer/src/store/copilot.ts", + "type": "string", + "defaultValue": null + }, + "defaultHeaders": { + "file": "src/renderer/src/store/copilot.ts", + "type": "string", + "defaultValue": null + } + }, + "inputTools": { + "_meta": { + "file": "src/renderer/src/store/inputTools.ts", + "interface": "InputToolsState" + }, + "toolOrder": { + "file": "src/renderer/src/store/inputTools.ts", + "type": "string", + "defaultValue": "DEFAULT_TOOL_ORDER" + }, + "sessionToolOrder": { + "file": "src/renderer/src/store/inputTools.ts", + "type": "string", + "defaultValue": "DEFAULT_TOOL_ORDER_BY_SCOPE[TopicType.Session]" + } + }, + "knowledge": { + "_meta": { + "file": "src/renderer/src/store/knowledge.ts", + "interface": "KnowledgeState" + }, + "bases": { + "file": "src/renderer/src/store/knowledge.ts", + "type": "array", + "defaultValue": null + } + }, + "llm": { + "_meta": { + "file": "src/renderer/src/store/llm.ts", + "interface": "LlmState" + }, + "providers": { + "file": "src/renderer/src/store/llm.ts", + "type": "array", + "defaultValue": "SYSTEM_PROVIDERS" + }, + "defaultModel": { + "file": "src/renderer/src/store/llm.ts", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[0]" + }, + "topicNamingModel": { + "file": "src/renderer/src/store/llm.ts", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[1]" + }, + "quickModel": { + "file": "src/renderer/src/store/llm.ts", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[1]" + }, + "translateModel": { + "file": "src/renderer/src/store/llm.ts", + "type": "unknown", + "defaultValue": "SYSTEM_MODELS.defaultModel[2]" + }, + "quickAssistantId": { + "file": "src/renderer/src/store/llm.ts", + "type": "string", + "defaultValue": "" + }, + "settings": { + "file": "src/renderer/src/store/llm.ts", + "type": "unknown", + "defaultValue": "{ ollama: { keepAliveTime: 0 }, lmstudio: { keepAliveTime: 0 }, gpustack: { keepAliveTime: 0 }, vertexai: { serviceAccount: { privateKey: '', clientEmail: '' }, projectId: '', location: '' }, awsBedrock: { authType: 'iam', accessKeyId: '', secretAccessKey: '', apiKey: '', region: '' } }" + } + }, + "mcp": { + "_meta": { + "file": "src/renderer/src/store/mcp.ts", + "interface": "McpState" + }, + "servers": { + "file": "src/renderer/src/store/mcp.ts", + "type": "array", + "defaultValue": [] + }, + "isUvInstalled": { + "file": "src/renderer/src/store/mcp.ts", + "type": "boolean", + "defaultValue": true + } + }, + "memory": { + "_meta": { + "file": "src/renderer/src/store/memory.ts", + "interface": "MemoryState" + }, + "memoryConfig": { + "file": "src/renderer/src/store/memory.ts", + "type": "unknown", + "defaultValue": "defaultMemoryConfig" + }, + "currentUserId": { + "file": "src/renderer/src/store/memory.ts", + "type": "string", + "defaultValue": "localStorage.getItem('memory_currentUserId') || 'default-user'" + }, + "globalMemoryEnabled": { + "file": "src/renderer/src/store/memory.ts", + "type": "boolean", + "defaultValue": null + } + }, + "messageBlock": { + "_meta": { + "file": "src/renderer/src/store/messageBlock.ts", + "interface": "MessageBlockState" + } + }, + "migrate": { + "_meta": { + "file": "src/renderer/src/store/migrate.ts", + "interface": "MigrateState" + } + }, + "minapps": { + "_meta": { + "file": "src/renderer/src/store/minapps.ts", + "interface": "MinappsState" + }, + "enabled": { + "file": "src/renderer/src/store/minapps.ts", + "type": "string", + "defaultValue": "DEFAULT_MIN_APPS" + }, + "disabled": { + "file": "src/renderer/src/store/minapps.ts", + "type": "array", + "defaultValue": [] + } + }, + "newMessage": { + "_meta": { + "file": "src/renderer/src/store/newMessage.ts", + "interface": "NewMessageState" + } + }, + "nutstore": { + "_meta": { + "file": "src/renderer/src/store/nutstore.ts", + "interface": "NutstoreState" + }, + "nutstoreToken": { + "file": "src/renderer/src/store/nutstore.ts", + "type": "string", + "defaultValue": "" + }, + "nutstorePath": { + "file": "src/renderer/src/store/nutstore.ts", + "type": "string", + "defaultValue": "/cherry-studio" + }, + "nutstoreAutoSync": { + "file": "src/renderer/src/store/nutstore.ts", + "type": "boolean", + "defaultValue": false + }, + "nutstoreSyncInterval": { + "file": "src/renderer/src/store/nutstore.ts", + "type": "number", + "defaultValue": 0 + }, + "nutstoreSyncState": { + "file": "src/renderer/src/store/nutstore.ts", + "type": "unknown", + "defaultValue": "{ lastSyncTime: null, syncing: false, lastSyncError: null }" + }, + "nutstoreSkipBackupFile": { + "file": "src/renderer/src/store/nutstore.ts", + "type": "boolean", + "defaultValue": false + }, + "nutstoreMaxBackups": { + "file": "src/renderer/src/store/nutstore.ts", + "type": "number", + "defaultValue": null + } + }, + "paintings": { + "_meta": { + "file": "src/renderer/src/store/paintings.ts", + "interface": "PaintingsState" + }, + "siliconflow_paintings": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "dmxapi_paintings": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "tokenflux_paintings": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "zhipu_paintings": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "aihubmix_image_generate": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "aihubmix_image_remix": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "aihubmix_image_edit": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "aihubmix_image_upscale": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "openai_image_generate": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + }, + "openai_image_edit": { + "file": "src/renderer/src/store/paintings.ts", + "type": "array", + "defaultValue": [] + } + }, + "preprocess": { + "_meta": { + "file": "src/renderer/src/store/preprocess.ts", + "interface": "PreprocessState" + }, + "providers": { + "file": "src/renderer/src/store/preprocess.ts", + "type": "array", + "defaultValue": "[ { id: 'mineru', name: 'MinerU', apiKey: '', apiHost: 'https://mineru.net' }" + }, + "defaultProvider": { + "file": "src/renderer/src/store/preprocess.ts", + "type": "string", + "defaultValue": null + } + }, + "runtime": { + "_meta": { + "file": "src/renderer/src/store/runtime.ts", + "interface": "RuntimeState" + }, + "chat": { + "file": "src/renderer/src/store/runtime.ts", + "type": "unknown", + "defaultValue": "{ isMultiSelectMode: false, selectedMessageIds: [], activeTopic: null, activeAgentId: null, activeTopicOrSession: 'topic', activeSessionIdMap: {}, renamingTopics: [], newlyRenamedTopics: [], sessionWaiting: {} }" + } + }, + "selectionStore": { + "_meta": { + "file": "src/renderer/src/store/selectionStore.ts", + "interface": "SelectionState" + }, + "selectionEnabled": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "boolean", + "defaultValue": false + }, + "triggerMode": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "unknown", + "defaultValue": "SelectionTriggerMode.Selected" + }, + "isCompact": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "boolean", + "defaultValue": false + }, + "isAutoClose": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "boolean", + "defaultValue": false + }, + "isAutoPin": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "boolean", + "defaultValue": false + }, + "isFollowToolbar": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "boolean", + "defaultValue": true + }, + "isRemeberWinSize": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "boolean", + "defaultValue": false + }, + "filterMode": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "unknown", + "defaultValue": "SelectionFilterMode.Default" + }, + "filterList": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "string", + "defaultValue": [] + }, + "actionWindowOpacity": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "number", + "defaultValue": 100 + }, + "actionItems": { + "file": "src/renderer/src/store/selectionStore.ts", + "type": "array", + "defaultValue": null + } + }, + "settings": { + "_meta": { + "file": "src/renderer/src/store/settings.ts", + "interface": "SettingsState" + }, + "showAssistants": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "showTopics": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "assistantsTabSortType": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "list" + }, + "sendMessageShortcut": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "Enter" + }, + "language": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "navigator.language as LanguageVarious" + }, + "targetLanguage": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "en-us" + }, + "proxyMode": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "system" + }, + "proxyUrl": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "proxyBypassRules": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "userName": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "userId": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "uuid()" + }, + "showPrompt": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "showMessageDivider": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "messageFont": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "system" + }, + "showInputEstimatedTokens": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "launchOnBoot": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "launchToTray": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "trayOnClose": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "tray": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "theme": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "ThemeMode.system" + }, + "userTheme": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ colorPrimary: '#00b96b', userFontFamily: '', userCodeFontFamily: '' }" + }, + "windowStyle": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "isMac ? 'transparent' : 'opaque'" + }, + "fontSize": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 14 + }, + "topicPosition": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "left" + }, + "showTopicTime": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "pinTopicsToTop": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "assistantIconType": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "emoji" + }, + "pasteLongTextAsFile": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "pasteLongTextThreshold": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 1500 + }, + "clickAssistantToShowTopic": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "autoCheckUpdate": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "testPlan": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "testChannel": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "UpgradeChannel.LATEST" + }, + "renderInputMessageAsMarkdown": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "codeExecution": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ enabled: false, timeoutMinutes: 1 }" + }, + "enabled": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "timeoutMinutes": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": null + }, + "codeEditor": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ enabled: false, themeLight: 'auto', themeDark: 'auto', highlightActiveLine: false, foldGutter: false, autocompletion: true, keymap: false }" + }, + "themeLight": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": null + }, + "themeDark": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": null + }, + "highlightActiveLine": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "foldGutter": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "autocompletion": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "keymap": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "codePreview": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ themeLight: 'auto', themeDark: 'auto' }" + }, + "codeViewer": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ themeLight: 'auto', themeDark: 'auto' }" + }, + "codeShowLineNumbers": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "codeCollapsible": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "codeWrappable": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "codeImageTools": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "codeFancyBlock": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "mathEngine": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "KaTeX" + }, + "mathEnableSingleDollar": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "messageStyle": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "plain" + }, + "foldDisplayMode": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "expanded" + }, + "gridColumns": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 2 + }, + "gridPopoverTrigger": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "click" + }, + "messageNavigation": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "none" + }, + "skipBackupFile": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "webdavHost": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "webdavUser": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "webdavPass": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "webdavPath": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "/cherry-studio" + }, + "webdavAutoSync": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "webdavSyncInterval": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 0 + }, + "webdavMaxBackups": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 0 + }, + "webdavSkipBackupFile": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "webdavDisableStream": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "translateModelPrompt": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "TRANSLATE_PROMPT" + }, + "autoTranslateWithSpace": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "showTranslateConfirm": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "enableTopicNaming": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "customCss": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "topicNamingPrompt": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "confirmDeleteMessage": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "confirmRegenerateMessage": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "sidebarIcons": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ visible: DefaultPreferences.default['ui.sidebar.icons.visible'], disabled: [] }" + }, + "visible": { + "file": "src/renderer/src/store/settings.ts", + "type": "array", + "defaultValue": null + }, + "disabled": { + "file": "src/renderer/src/store/settings.ts", + "type": "array", + "defaultValue": null + }, + "narrowMode": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "enableQuickAssistant": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "clickTrayToShowQuickAssistant": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "multiModelMessageStyle": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "horizontal" + }, + "readClipboardAtStartup": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "notionDatabaseID": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "notionApiKey": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "notionPageNameKey": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "Name" + }, + "markdownExportPath": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "forceDollarMathInMarkdown": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "useTopicNamingForMessageTitle": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "showModelNameInMarkdown": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "showModelProviderInMarkdown": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "thoughtAutoCollapse": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "notionExportReasoning": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "excludeCitationsInExport": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "standardizeCitationsInExport": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "yuqueToken": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "yuqueUrl": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "yuqueRepoId": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "joplinToken": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "joplinUrl": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "joplinExportReasoning": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "defaultObsidianVault": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "defaultAgent": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "siyuanApiUrl": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "siyuanToken": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "siyuanBoxId": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "siyuanRootPath": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": null + }, + "agentssubscribeUrl": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "maxKeepAliveMinapps": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 3 + }, + "showOpenedMinappsInSidebar": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": true + }, + "minappsOpenLinkExternal": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "enableDataCollection": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "enableSpellCheck": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "spellCheckLanguages": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": [] + }, + "enableQuickPanelTriggers": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "disableHardwareAcceleration": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "exportMenuOptions": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ image: true, markdown: true, markdown_reason: true, notion: true, yuque: true, joplin: true, obsidian: true, siyuan: true, docx: true, plain_text: true, notes: true }" + }, + "image": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "markdown": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "markdown_reason": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "notion": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "yuque": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "joplin": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "obsidian": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "siyuan": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "docx": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "plain_text": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "notes": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "openAI": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ summaryText: 'auto', serviceTier: 'auto', verbosity: undefined }" + }, + "summaryText": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": null + }, + "serviceTier": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": null + }, + "verbosity": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": null + }, + "notification": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ assistant: false, backup: false, knowledge: false }" + }, + "assistant": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "backup": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "knowledge": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + }, + "localBackupDir": { + "file": "src/renderer/src/store/settings.ts", + "type": "string", + "defaultValue": "" + }, + "localBackupAutoSync": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "localBackupSyncInterval": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 0 + }, + "localBackupMaxBackups": { + "file": "src/renderer/src/store/settings.ts", + "type": "number", + "defaultValue": 0 + }, + "localBackupSkipBackupFile": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "defaultPaintingProvider": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "cherryin" + }, + "s3": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ endpoint: '', region: '', bucket: '', accessKeyId: '', secretAccessKey: '', root: '', autoSync: false, syncInterval: 0, maxBackups: 0, skipBackupFile: false }" + }, + "enableDeveloperMode": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": false + }, + "navbarPosition": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "top" + }, + "apiServer": { + "file": "src/renderer/src/store/settings.ts", + "type": "unknown", + "defaultValue": "{ enabled: false, host: 'localhost', port: 23333, apiKey: `cs-sk-${uuid()}` }" + }, + "showMessageOutline": { + "file": "src/renderer/src/store/settings.ts", + "type": "boolean", + "defaultValue": null + } + }, + "shortcuts": { + "_meta": { + "file": "src/renderer/src/store/shortcuts.ts", + "interface": "ShortcutsState" + }, + "shortcuts": { + "file": "src/renderer/src/store/shortcuts.ts", + "type": "array", + "defaultValue": "[ ...ZOOM_SHORTCUTS" + } + }, + "tabs": { + "_meta": { + "file": "src/renderer/src/store/tabs.ts", + "interface": "TabsState" + }, + "tabs": { + "file": "src/renderer/src/store/tabs.ts", + "type": "array", + "defaultValue": "[ { id: 'home', path: '/' }" + }, + "activeTabId": { + "file": "src/renderer/src/store/tabs.ts", + "type": "string", + "defaultValue": null + } + }, + "toolPermissions": { + "_meta": { + "file": "src/renderer/src/store/toolPermissions.ts", + "interface": "ToolPermissionsState" + }, + "requests": { + "file": "src/renderer/src/store/toolPermissions.ts", + "type": "string", + "defaultValue": {} + } + }, + "translate": { + "_meta": { + "file": "src/renderer/src/store/translate.ts", + "interface": "TranslateState" + }, + "translateInput": { + "file": "src/renderer/src/store/translate.ts", + "type": "string", + "defaultValue": null + }, + "translatedContent": { + "file": "src/renderer/src/store/translate.ts", + "type": "string", + "defaultValue": null + }, + "settings": { + "file": "src/renderer/src/store/translate.ts", + "type": "unknown", + "defaultValue": null + }, + "autoCopy": { + "file": "src/renderer/src/store/translate.ts", + "type": "boolean", + "defaultValue": null + } + }, + "websearch": { + "_meta": { + "file": "src/renderer/src/store/websearch.ts", + "interface": "WebSearchState" + }, + "defaultProvider": { + "file": "src/renderer/src/store/websearch.ts", + "type": "string", + "defaultValue": "local-bing" + }, + "providers": { + "file": "src/renderer/src/store/websearch.ts", + "type": "array", + "defaultValue": "WEB_SEARCH_PROVIDERS" + }, + "searchWithTime": { + "file": "src/renderer/src/store/websearch.ts", + "type": "boolean", + "defaultValue": true + }, + "maxResults": { + "file": "src/renderer/src/store/websearch.ts", + "type": "number", + "defaultValue": 5 + }, + "excludeDomains": { + "file": "src/renderer/src/store/websearch.ts", + "type": "string", + "defaultValue": [] + }, + "subscribeSources": { + "file": "src/renderer/src/store/websearch.ts", + "type": "array", + "defaultValue": [] + }, + "overwrite": { + "file": "src/renderer/src/store/websearch.ts", + "type": "boolean", + "defaultValue": false + }, + "compressionConfig": { + "file": "src/renderer/src/store/websearch.ts", + "type": "unknown", + "defaultValue": "{ method: 'none', cutoffUnit: 'char' }" + }, + "providerConfig": { + "file": "src/renderer/src/store/websearch.ts", + "type": "string", + "defaultValue": {} + } + }, + "codeTools": { + "_meta": { + "file": "src/renderer/src/store/codeTools.ts", + "interface": "CodeToolsState" + }, + "selectedCliTool": { + "file": "src/renderer/src/store/codeTools.ts", + "type": "unknown", + "defaultValue": "codeTools.qwenCode" + }, + "selectedModels": { + "file": "src/renderer/src/store/codeTools.ts", + "type": "string", + "defaultValue": "{ [codeTools.qwenCode]: null, [codeTools.claudeCode]: null, [codeTools.geminiCli]: null, [codeTools.openaiCodex]: null, [codeTools.iFlowCli]: null, [codeTools.githubCopilotCli]: null }" + }, + "environmentVariables": { + "file": "src/renderer/src/store/codeTools.ts", + "type": "string", + "defaultValue": { + "qwen-code": "", + "claude-code": "", + "gemini-cli": "", + "openai-codex": "", + "iflow-cli": "", + "github-copilot-cli": "" + } + }, + "directories": { + "file": "src/renderer/src/store/codeTools.ts", + "type": "string", + "defaultValue": [] + }, + "currentDirectory": { + "file": "src/renderer/src/store/codeTools.ts", + "type": "string", + "defaultValue": "" + }, + "selectedTerminal": { + "file": "src/renderer/src/store/codeTools.ts", + "type": "string", + "defaultValue": null + } + }, + "ocr": { + "_meta": { + "file": "src/renderer/src/store/ocr.ts", + "interface": "OcrState" + }, + "providers": { + "file": "src/renderer/src/store/ocr.ts", + "type": "array", + "defaultValue": "BUILTIN_OCR_PROVIDERS" + }, + "imageProviderId": { + "file": "src/renderer/src/store/ocr.ts", + "type": "string", + "defaultValue": null + } + }, + "note": { + "_meta": { + "file": "src/renderer/src/store/note.ts", + "interface": "NoteState" + }, + "activeNodeId": { + "file": "src/renderer/src/store/note.ts", + "type": "string", + "defaultValue": null + }, + "activeFilePath": { + "file": "src/renderer/src/store/note.ts", + "type": "string", + "defaultValue": null + }, + "settings": { + "file": "src/renderer/src/store/note.ts", + "type": "unknown", + "defaultValue": "{ isFullWidth: true, fontFamily: 'default', fontSize: 16, showTableOfContents: true, defaultViewMode: 'edit', defaultEditMode: 'preview', showTabStatus: true, showWorkspace: true }" + }, + "notesPath": { + "file": "src/renderer/src/store/note.ts", + "type": "string", + "defaultValue": "" + }, + "sortType": { + "file": "src/renderer/src/store/note.ts", + "type": "unknown", + "defaultValue": "sort_a2z" + }, + "starredPaths": { + "file": "src/renderer/src/store/note.ts", + "type": "string", + "defaultValue": [] + }, + "expandedPaths": { + "file": "src/renderer/src/store/note.ts", + "type": "string", + "defaultValue": null + } + } + }, + "electronStore": { + "Language": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.Language", + "type": "unknown", + "defaultValue": null + }, + "Theme": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.Theme", + "type": "unknown", + "defaultValue": null + }, + "LaunchToTray": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.LaunchToTray", + "type": "unknown", + "defaultValue": null + }, + "Tray": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.Tray", + "type": "unknown", + "defaultValue": null + }, + "TrayOnClose": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.TrayOnClose", + "type": "unknown", + "defaultValue": null + }, + "ZoomFactor": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.ZoomFactor", + "type": "unknown", + "defaultValue": null + }, + "Shortcuts": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.Shortcuts", + "type": "unknown", + "defaultValue": null + }, + "ClickTrayToShowQuickAssistant": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.ClickTrayToShowQuickAssistant", + "type": "unknown", + "defaultValue": null + }, + "EnableQuickAssistant": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.EnableQuickAssistant", + "type": "unknown", + "defaultValue": null + }, + "AutoUpdate": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.AutoUpdate", + "type": "unknown", + "defaultValue": null + }, + "TestPlan": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.TestPlan", + "type": "unknown", + "defaultValue": null + }, + "TestChannel": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.TestChannel", + "type": "unknown", + "defaultValue": null + }, + "EnableDataCollection": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.EnableDataCollection", + "type": "unknown", + "defaultValue": null + }, + "SelectionAssistantEnabled": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.SelectionAssistantEnabled", + "type": "unknown", + "defaultValue": null + }, + "SelectionAssistantTriggerMode": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.SelectionAssistantTriggerMode", + "type": "unknown", + "defaultValue": null + }, + "SelectionAssistantFollowToolbar": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.SelectionAssistantFollowToolbar", + "type": "unknown", + "defaultValue": null + }, + "SelectionAssistantRemeberWinSize": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.SelectionAssistantRemeberWinSize", + "type": "unknown", + "defaultValue": null + }, + "SelectionAssistantFilterMode": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.SelectionAssistantFilterMode", + "type": "unknown", + "defaultValue": null + }, + "SelectionAssistantFilterList": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.SelectionAssistantFilterList", + "type": "unknown", + "defaultValue": null + }, + "DisableHardwareAcceleration": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.DisableHardwareAcceleration", + "type": "unknown", + "defaultValue": null + }, + "Proxy": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.Proxy", + "type": "unknown", + "defaultValue": null + }, + "EnableDeveloperMode": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.EnableDeveloperMode", + "type": "unknown", + "defaultValue": null + }, + "ClientId": { + "file": "src/main/services/ConfigManager.ts", + "enum": "ConfigKeys.ClientId", + "type": "unknown", + "defaultValue": null + } + }, + "localStorage": { + "persist:cherry-studio": { + "file": "src\\main\\utils\\index.ts", + "type": "string", + "defaultValue": null + }, + "memory_currentUserId": { + "file": "src\\renderer\\src\\store\\memory.ts", + "type": "string", + "defaultValue": null + } + }, + "dexie": { + "files": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable", + "schema": null + }, + "topics": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable<{ id: string; messages: NewMessage[] }, 'id'>", + "schema": null + }, + "settings": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable<{ id: string; value: any }, 'id'>", + "schema": null + }, + "knowledge_notes": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable", + "schema": null + }, + "translate_history": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable", + "schema": null + }, + "quick_phrases": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable", + "schema": null + }, + "message_blocks": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable", + "schema": null + }, + "translate_languages": { + "file": "src/renderer/src/databases/index.ts", + "type": "EntityTable", + "schema": null + } + } +} diff --git a/v2-refactor-temp/tools/data-classify/package-lock.json b/v2-refactor-temp/tools/data-classify/package-lock.json new file mode 100644 index 0000000000..79d94dbde4 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/package-lock.json @@ -0,0 +1,490 @@ +{ + "name": "data-classify", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "data-classify", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "glob": "^11.0.3" + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/v2-refactor-temp/tools/data-classify/package.json b/v2-refactor-temp/tools/data-classify/package.json new file mode 100644 index 0000000000..c91a06d4ab --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/package.json @@ -0,0 +1,30 @@ +{ + "name": "data-classify", + "version": "2.0.0", + "description": "Data classification and code generation tools for Cherry Studio data refactoring", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "extract": "node scripts/extract-inventory.js", + "generate": "node scripts/generate-all.js", + "generate:preferences": "node scripts/generate-preferences.js", + "generate:migration": "node scripts/generate-migration.js", + "validate": "node scripts/validate-consistency.js", + "validate:gen": "node scripts/validate-generation.js", + "check:duplicates": "node scripts/check-duplicates.js", + "all": "npm run extract && npm run generate && npm run validate && npm run validate:gen" + }, + "keywords": [ + "data-classification", + "code-generation", + "migration" + ], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "glob": "^11.0.3" + } +} diff --git a/v2-refactor-temp/tools/data-classify/scripts/check-duplicates.js b/v2-refactor-temp/tools/data-classify/scripts/check-duplicates.js new file mode 100644 index 0000000000..2cb4be52d8 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/check-duplicates.js @@ -0,0 +1,78 @@ +#!/usr/bin/env node + +const fs = require('fs') +const path = require('path') + +function checkDuplicatesAndChildren() { + const classificationFile = path.join(__dirname, '../data/classification.json') + const classification = JSON.parse(fs.readFileSync(classificationFile, 'utf8')) + + // 提取所有preferences项(包括children) + const allPrefs = [] + + function extractItems(items, source, category, parentKey = '') { + if (!Array.isArray(items)) return + + items.forEach((item) => { + // 处理有children的项目 + if (item.children) { + console.log(`发现children项: ${source}/${category}/${item.originalKey}`) + extractItems(item.children, source, category, `${parentKey}${item.originalKey}.`) + return + } + + // 处理普通项目 + if (item.category === 'preferences' && item.status === 'classified' && item.targetKey) { + allPrefs.push({ + source, + category, + originalKey: parentKey + item.originalKey, + targetKey: item.targetKey, + fullPath: `${source}/${category}/${parentKey}${item.originalKey}` + }) + } + }) + } + // 遍历所有数据源 + ;['electronStore', 'redux', 'localStorage'].forEach((source) => { + if (classification.classifications[source]) { + Object.keys(classification.classifications[source]).forEach((category) => { + const items = classification.classifications[source][category] + extractItems(items, source, category) + }) + } + }) + + console.log(`\n=== 总共找到 ${allPrefs.length} 个preferences项 ===\n`) + + // 检查重复的targetKey + const targetKeyGroups = {} + allPrefs.forEach((pref) => { + if (!targetKeyGroups[pref.targetKey]) { + targetKeyGroups[pref.targetKey] = [] + } + targetKeyGroups[pref.targetKey].push(pref) + }) + + // 显示重复项 + const duplicates = Object.keys(targetKeyGroups).filter((key) => targetKeyGroups[key].length > 1) + if (duplicates.length > 0) { + console.log('=== 重复的targetKey ===') + duplicates.forEach((targetKey) => { + console.log(`\n${targetKey}:`) + targetKeyGroups[targetKey].forEach((pref) => { + console.log(` - ${pref.fullPath}`) + }) + }) + } else { + console.log('✅ 没有发现重复的targetKey') + } + + return { allPrefs, duplicates: duplicates.map((key) => targetKeyGroups[key]) } +} + +if (require.main === module) { + checkDuplicatesAndChildren() +} + +module.exports = checkDuplicatesAndChildren diff --git a/v2-refactor-temp/tools/data-classify/scripts/extract-inventory.js b/v2-refactor-temp/tools/data-classify/scripts/extract-inventory.js new file mode 100644 index 0000000000..3b3503c99c --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/extract-inventory.js @@ -0,0 +1,545 @@ +#!/usr/bin/env node + +/** + * Data Inventory Extractor + * + * Extracts data inventory from Cherry Studio source code and manages + * incremental updates to classification.json with backup protection. + * + * Features: + * - Extracts Redux, ElectronStore, LocalStorage, and Dexie data + * - Preserves existing classifications during updates + * - Creates automatic backups before modifications + * - Supports nested data structures with children + * + * Usage: + * node v2-refactor-temp/tools/data-classify/scripts/extract-inventory.js + */ + +const fs = require('fs') +const path = require('path') + +const { + loadClassification, + saveClassification, + normalizeType, + inferTypeFromValue, + calculateStats, + DATA_DIR +} = require('./lib/classificationUtils') + +// Redux store modules configuration +const REDUX_STORE_MODULES = { + assistants: { file: 'assistants.ts', interface: 'AssistantsState' }, + backup: { file: 'backup.ts', interface: 'BackupState' }, + copilot: { file: 'copilot.ts', interface: 'CopilotState' }, + inputTools: { file: 'inputTools.ts', interface: 'InputToolsState' }, + knowledge: { file: 'knowledge.ts', interface: 'KnowledgeState' }, + llm: { file: 'llm.ts', interface: 'LlmState' }, + mcp: { file: 'mcp.ts', interface: 'McpState' }, + memory: { file: 'memory.ts', interface: 'MemoryState' }, + messageBlock: { file: 'messageBlock.ts', interface: 'MessageBlockState' }, + migrate: { file: 'migrate.ts', interface: 'MigrateState' }, + minapps: { file: 'minapps.ts', interface: 'MinappsState' }, + newMessage: { file: 'newMessage.ts', interface: 'NewMessageState' }, + nutstore: { file: 'nutstore.ts', interface: 'NutstoreState' }, + paintings: { file: 'paintings.ts', interface: 'PaintingsState' }, + preprocess: { file: 'preprocess.ts', interface: 'PreprocessState' }, + runtime: { file: 'runtime.ts', interface: 'RuntimeState' }, + selectionStore: { file: 'selectionStore.ts', interface: 'SelectionState' }, + settings: { file: 'settings.ts', interface: 'SettingsState' }, + shortcuts: { file: 'shortcuts.ts', interface: 'ShortcutsState' }, + tabs: { file: 'tabs.ts', interface: 'TabsState' }, + toolPermissions: { file: 'toolPermissions.ts', interface: 'ToolPermissionsState' }, + translate: { file: 'translate.ts', interface: 'TranslateState' }, + websearch: { file: 'websearch.ts', interface: 'WebSearchState' }, + codeTools: { file: 'codeTools.ts', interface: 'CodeToolsState' }, + ocr: { file: 'ocr.ts', interface: 'OcrState' }, + note: { file: 'note.ts', interface: 'NoteState' } +} + +class DataExtractor { + constructor(rootDir = '../../../../') { + this.rootDir = path.resolve(__dirname, rootDir) + this.dataDir = DATA_DIR + console.log('Root directory:', this.rootDir) + console.log('Data directory:', this.dataDir) + } + + /** + * Main extraction entry point + */ + async extract() { + console.log('Starting data inventory extraction...\n') + + const inventory = { + metadata: { + generatedAt: new Date().toISOString(), + version: '2.0.0', + description: 'Cherry Studio data inventory' + }, + redux: await this.extractReduxData(), + electronStore: await this.extractElectronStoreData(), + localStorage: await this.extractLocalStorageData(), + dexie: await this.extractDexieData() + } + + // Load existing classification and merge + let existingClassification + try { + existingClassification = loadClassification(this.dataDir) + } catch { + existingClassification = { classifications: {} } + } + + const updatedData = this.mergeWithExisting(inventory, existingClassification) + + // Save results + this.saveInventory(updatedData.inventory) + saveClassification(updatedData.classification, this.dataDir) + + console.log('\nData extraction complete!') + this.printSummary(updatedData) + } + + /** + * Extract Redux store data from source files + */ + async extractReduxData() { + console.log('Extracting Redux Store data...') + const reduxData = {} + + for (const [moduleName, moduleInfo] of Object.entries(REDUX_STORE_MODULES)) { + const filePath = path.join(this.rootDir, `src/renderer/src/store/${moduleInfo.file}`) + + if (!fs.existsSync(filePath)) { + console.warn(` Warning: ${moduleInfo.file} not found`) + continue + } + + const content = fs.readFileSync(filePath, 'utf8') + const stateInterface = this.extractStateInterface(content, moduleInfo.interface) + const initialState = this.extractInitialState(content) + + reduxData[moduleName] = { + _meta: { + file: `src/renderer/src/store/${moduleInfo.file}`, + interface: moduleInfo.interface + } + } + + // Add fields from interface and initial state + const fields = Object.keys(stateInterface).length > 0 ? stateInterface : initialState + + for (const [fieldName, fieldInfo] of Object.entries(fields)) { + if (fieldName === '_meta') continue + + reduxData[moduleName][fieldName] = { + file: `src/renderer/src/store/${moduleInfo.file}`, + type: fieldInfo.type || inferTypeFromValue(initialState[fieldName]), + defaultValue: initialState[fieldName] ?? fieldInfo.defaultValue ?? null + } + } + } + + console.log(` Found ${Object.keys(reduxData).length} Redux modules`) + return reduxData + } + + /** + * Extract Electron Store configuration keys + */ + async extractElectronStoreData() { + console.log('Extracting Electron Store data...') + const electronStoreData = {} + + const configManagerPath = path.join(this.rootDir, 'src/main/services/ConfigManager.ts') + if (!fs.existsSync(configManagerPath)) { + console.warn(' Warning: ConfigManager.ts not found') + return electronStoreData + } + + const content = fs.readFileSync(configManagerPath, 'utf8') + const configKeys = this.extractConfigKeys(content) + + for (const key of configKeys) { + electronStoreData[key] = { + file: 'src/main/services/ConfigManager.ts', + enum: `ConfigKeys.${key}`, + type: 'unknown', + defaultValue: null + } + } + + console.log(` Found ${configKeys.length} ConfigKeys`) + return electronStoreData + } + + /** + * Extract localStorage usage from source files + */ + async extractLocalStorageData() { + console.log('Extracting LocalStorage data...') + const localStorageData = {} + + const { glob } = require('glob') + const files = await glob('src/**/*.ts', { cwd: this.rootDir }) + + for (const file of files) { + const filePath = path.join(this.rootDir, file) + const content = fs.readFileSync(filePath, 'utf8') + + // Find localStorage.getItem and localStorage.setItem calls + const getItemRegex = /localStorage\.getItem\(['"]([^'"]+)['"]\)/g + const setItemRegex = /localStorage\.setItem\(['"]([^'"]+)['"],/g + + let match + while ((match = getItemRegex.exec(content)) !== null) { + if (!localStorageData[match[1]]) { + localStorageData[match[1]] = { + file: file, + type: 'string', + defaultValue: null + } + } + } + + while ((match = setItemRegex.exec(content)) !== null) { + if (!localStorageData[match[1]]) { + localStorageData[match[1]] = { + file: file, + type: 'string', + defaultValue: null + } + } + } + } + + console.log(` Found ${Object.keys(localStorageData).length} localStorage keys`) + return localStorageData + } + + /** + * Extract Dexie database tables + */ + async extractDexieData() { + console.log('Extracting Dexie data...') + const dexieData = {} + + const databasePath = path.join(this.rootDir, 'src/renderer/src/databases/index.ts') + if (!fs.existsSync(databasePath)) { + console.warn(' Warning: databases/index.ts not found') + return dexieData + } + + const content = fs.readFileSync(databasePath, 'utf8') + + // Match table definitions like: tableName: EntityTable + const tableRegex = /(\w+):\s*EntityTable<([^>]+)>/g + let match + + while ((match = tableRegex.exec(content)) !== null) { + dexieData[match[1]] = { + file: 'src/renderer/src/databases/index.ts', + type: `EntityTable<${match[2]}>`, + schema: null + } + } + + console.log(` Found ${Object.keys(dexieData).length} Dexie tables`) + return dexieData + } + + /** + * Extract TypeScript interface fields + */ + extractStateInterface(content, interfaceName) { + const fields = {} + + // Match interface definition + const interfaceMatch = content.match(new RegExp(`export interface ${interfaceName}\\s*\\{([\\s\\S]*?)\\n\\}`, 'm')) + + if (!interfaceMatch) return fields + + const interfaceBody = interfaceMatch[1] + const lines = interfaceBody.split('\n') + + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*')) continue + + // Match field: type pattern + const fieldMatch = trimmed.match(/^(\w+)(\?)?:\s*([^;]+)/) + if (fieldMatch) { + const fieldName = fieldMatch[1] + let fieldType = fieldMatch[3].trim().replace(/[,;]$/, '') + + fields[fieldName] = { + type: normalizeType(fieldType), + defaultValue: null + } + } + } + + return fields + } + + /** + * Extract initial state values from TypeScript file + */ + extractInitialState(content) { + const state = {} + + // Match initialState definition + const stateMatch = content.match(/(?:export )?const initialState[^=]*=\s*\{([\s\S]*?)\n\}(?=\s*\n|$)/m) + + if (!stateMatch) return state + + // Simple field extraction + const stateBody = stateMatch[1] + const lines = stateBody.split('\n') + let currentField = null + let currentValue = '' + let braceCount = 0 + + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed || trimmed.startsWith('//')) continue + + if (currentField) { + currentValue += ' ' + trimmed + braceCount += (trimmed.match(/\{/g) || []).length + braceCount -= (trimmed.match(/\}/g) || []).length + + if (braceCount === 0 && (trimmed.endsWith(',') || trimmed === '}')) { + state[currentField] = this.parseValue(currentValue.replace(/,$/, '').trim()) + currentField = null + currentValue = '' + } + continue + } + + const fieldMatch = trimmed.match(/^(\w+):\s*(.+)/) + if (fieldMatch) { + const fieldName = fieldMatch[1] + const fieldValue = fieldMatch[2] + + braceCount = (fieldValue.match(/\{/g) || []).length - (fieldValue.match(/\}/g) || []).length + + if (braceCount === 0 && (fieldValue.endsWith(',') || fieldValue.endsWith('}'))) { + state[fieldName] = this.parseValue(fieldValue.replace(/,$/, '').trim()) + } else { + currentField = fieldName + currentValue = fieldValue + } + } + } + + return state + } + + /** + * Extract ConfigKeys enum values + */ + extractConfigKeys(content) { + const keys = [] + const enumMatch = content.match(/export enum ConfigKeys \{([^}]+)\}/g) + + if (enumMatch) { + const enumContent = enumMatch[0] + const keyRegex = /(\w+)\s*=/g + let match + + while ((match = keyRegex.exec(enumContent)) !== null) { + keys.push(match[1]) + } + } + + return keys + } + + /** + * Parse a value string to appropriate type + */ + parseValue(valueStr) { + const trimmed = valueStr.trim() + + if (trimmed === 'true') return true + if (trimmed === 'false') return false + if (trimmed === 'null') return null + if (trimmed === 'undefined') return undefined + if (/^-?\d+$/.test(trimmed)) return parseInt(trimmed, 10) + if (/^-?\d*\.\d+$/.test(trimmed)) return parseFloat(trimmed) + + // Handle strings + if ((trimmed.startsWith('"') && trimmed.endsWith('"')) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) { + return trimmed.slice(1, -1) + } + + // Handle arrays and objects - return as string for complex values + if (trimmed.startsWith('[') || trimmed.startsWith('{')) { + try { + return JSON.parse(trimmed.replace(/'/g, '"')) + } catch { + return trimmed + } + } + + return trimmed + } + + /** + * Merge new inventory with existing classification + */ + mergeWithExisting(newInventory, existingClassification) { + const updatedClassifications = this.convertToNestedStructure(newInventory, existingClassification) + + // Calculate statistics + const stats = calculateStats(updatedClassifications) + + const updatedClassification = { + metadata: { + version: '2.0.0', + lastUpdated: new Date().toISOString(), + totalItems: stats.total, + classified: stats.byStatus.classified || 0, + pending: stats.byStatus.pending || 0, + deleted: stats.byStatus['classified-deleted'] || 0 + }, + classifications: updatedClassifications + } + + return { + inventory: newInventory, + classification: updatedClassification + } + } + + /** + * Convert flat inventory to nested classification structure + */ + convertToNestedStructure(newInventory, existingClassification) { + const nestedClassifications = {} + const existing = existingClassification?.classifications || {} + + for (const [source, data] of Object.entries(newInventory)) { + if (source === 'metadata') continue + + if (!nestedClassifications[source]) { + nestedClassifications[source] = {} + } + + if (source === 'redux') { + // Redux: group by module + for (const [moduleName, moduleData] of Object.entries(data)) { + if (!nestedClassifications[source][moduleName]) { + nestedClassifications[source][moduleName] = [] + } + + for (const fieldName of Object.keys(moduleData)) { + if (fieldName === '_meta') continue + + const fieldData = moduleData[fieldName] + const existingItem = this.findExisting(existing, source, moduleName, fieldName) + + nestedClassifications[source][moduleName].push({ + originalKey: fieldName, + type: existingItem?.type || normalizeType(fieldData?.type), + defaultValue: existingItem?.defaultValue ?? fieldData?.defaultValue ?? null, + status: existingItem?.status || 'pending', + category: existingItem?.category || null, + targetKey: existingItem?.targetKey || null, + ...(existingItem?.children ? { children: existingItem.children } : {}) + }) + } + } + } else { + // Other sources: direct mapping + for (const [tableName, tableData] of Object.entries(data)) { + if (!nestedClassifications[source][tableName]) { + nestedClassifications[source][tableName] = [] + } + + const existingItem = this.findExisting(existing, source, tableName, null) + + nestedClassifications[source][tableName].push({ + originalKey: tableName, + type: existingItem?.type || (source === 'dexie' ? 'table' : normalizeType(tableData?.type)), + defaultValue: existingItem?.defaultValue ?? tableData?.defaultValue ?? null, + status: existingItem?.status || 'pending', + category: existingItem?.category || null, + targetKey: existingItem?.targetKey || null + }) + } + } + } + + return nestedClassifications + } + + /** + * Find existing classification item + */ + findExisting(existing, source, moduleOrTable, field) { + if (!existing[source]) return null + + const sourceData = existing[source] + const items = sourceData[moduleOrTable] + + if (!Array.isArray(items)) return null + + // For redux: find by field name in module items + if (field) { + for (const item of items) { + if (item.originalKey === field) return item + if (item.children) { + const child = item.children.find((c) => c.originalKey === field) + if (child) return child + } + } + } else { + // For other sources: find by table name + return items.find((item) => item.originalKey === moduleOrTable) + } + + return null + } + + /** + * Save inventory to file + */ + saveInventory(inventory) { + const inventoryPath = path.join(this.dataDir, 'inventory.json') + fs.writeFileSync(inventoryPath, JSON.stringify(inventory, null, 2), 'utf8') + console.log(`\nInventory saved: ${inventoryPath}`) + } + + /** + * Print extraction summary + */ + printSummary(updatedData) { + const { inventory, classification } = updatedData + + console.log('\n========== Extraction Summary ==========') + console.log(`Redux modules: ${Object.keys(inventory.redux || {}).length}`) + console.log(`Electron Store keys: ${Object.keys(inventory.electronStore || {}).length}`) + console.log(`LocalStorage keys: ${Object.keys(inventory.localStorage || {}).length}`) + console.log(`Dexie tables: ${Object.keys(inventory.dexie || {}).length}`) + console.log('----------------------------------------') + console.log(`Total items: ${classification.metadata.totalItems}`) + console.log(`Classified: ${classification.metadata.classified}`) + console.log(`Pending: ${classification.metadata.pending}`) + if (classification.metadata.deleted > 0) { + console.log(`Deleted: ${classification.metadata.deleted}`) + } + console.log('========================================\n') + } +} + +// Run script +if (require.main === module) { + const extractor = new DataExtractor() + extractor.extract().catch(console.error) +} + +module.exports = DataExtractor diff --git a/v2-refactor-temp/tools/data-classify/scripts/generate-all.js b/v2-refactor-temp/tools/data-classify/scripts/generate-all.js new file mode 100644 index 0000000000..7a08dbc019 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/generate-all.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node + +const PreferencesGenerator = require('./generate-preferences') +const MigrationGenerator = require('./generate-migration') + +async function generateAll() { + console.log('🚀 开始生成preferences.ts和迁移代码...\n') + + try { + // 步骤1: 生成preferences.ts + console.log('📋 步骤 1/2: 生成preferences.ts') + const preferencesGenerator = new PreferencesGenerator() + preferencesGenerator.generate() + console.log('✅ preferences.ts 生成完成\n') + + // 步骤2: 生成迁移代码 + console.log('🔄 步骤 2/2: 生成迁移代码') + const migrationGenerator = new MigrationGenerator() + migrationGenerator.generate() + console.log('✅ 迁移代码生成完成\n') + + // 成功总结 + console.log('🎉 所有代码生成成功!') + console.log('\n📝 生成的文件:') + console.log(' - packages/shared/data/preference/preferenceSchemas.ts') + console.log(' - src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts') + + console.log('\n🔧 下一步操作:') + console.log(' 1. 运行 yarn typecheck 检查类型') + console.log(' 2. 运行 yarn lint --fix 格式化代码') + console.log(' 3. 测试迁移代码的功能') + } catch (error) { + console.error('❌ 生成过程中发生错误:', error.message) + process.exit(1) + } +} + +// 如果直接运行此脚本 +if (require.main === module) { + generateAll() +} + +module.exports = generateAll diff --git a/v2-refactor-temp/tools/data-classify/scripts/generate-migration.js b/v2-refactor-temp/tools/data-classify/scripts/generate-migration.js new file mode 100644 index 0000000000..9b26a7e39e --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/generate-migration.js @@ -0,0 +1,239 @@ +#!/usr/bin/env node + +const fs = require('fs') +const path = require('path') + +class SimpleMappingGenerator { + constructor() { + this.dataDir = path.resolve(__dirname, '../data') + this.targetDir = path.resolve(__dirname, '../../../../src/main/data/migration/v2/migrators/mappings') + this.classificationFile = path.join(this.dataDir, 'classification.json') + } + + generate() { + console.log('开始生成简化的映射关系代码...') + + // 读取分类数据 + const classification = this.loadClassification() + + // 提取preferences相关数据 + const preferencesData = this.extractPreferencesData(classification) + + // 创建目标目录 + this.ensureTargetDirectory() + + // 生成映射关系文件 + this.generateMappings(preferencesData) + + console.log('映射关系生成完成!') + this.printSummary(preferencesData) + } + + loadClassification() { + if (!fs.existsSync(this.classificationFile)) { + throw new Error(`分类文件不存在: ${this.classificationFile}`) + } + + const content = fs.readFileSync(this.classificationFile, 'utf8') + return JSON.parse(content) + } + + extractPreferencesData(classification) { + const allPreferencesData = [] + const sources = ['electronStore', 'redux', 'localStorage'] + + // 递归提取项目,包括children (保持现有逻辑) + const extractItems = (items, source, category, parentKey = '') => { + if (!Array.isArray(items)) return + + items.forEach((item) => { + // 处理有children的项目 + if (item.children && Array.isArray(item.children)) { + console.log(`处理children项: ${source}/${category}/${item.originalKey}`) + extractItems(item.children, source, category, `${parentKey}${item.originalKey}.`) + return + } + + // 处理普通项目 + if (item.category === 'preferences' && item.status === 'classified' && item.targetKey) { + allPreferencesData.push({ + ...item, + source, + sourceCategory: category, + originalKey: parentKey + item.originalKey, // 包含父级路径 + fullPath: `${source}/${category}/${parentKey}${item.originalKey}` + }) + } + }) + } + + sources.forEach((source) => { + if (classification.classifications[source]) { + Object.keys(classification.classifications[source]).forEach((category) => { + const items = classification.classifications[source][category] + extractItems(items, source, category) + }) + } + }) + + console.log(`提取到 ${allPreferencesData.length} 个preferences项(包含children)`) + + // 处理重复的targetKey,优先使用redux数据 + const targetKeyGroups = {} + allPreferencesData.forEach((item) => { + if (!targetKeyGroups[item.targetKey]) { + targetKeyGroups[item.targetKey] = [] + } + targetKeyGroups[item.targetKey].push(item) + }) + + // 去重:按redux > localStorage > electronStore优先级选择 + const sourcePriority = { redux: 3, localStorage: 2, electronStore: 1 } + const deduplicatedData = [] + + Object.keys(targetKeyGroups).forEach((targetKey) => { + const items = targetKeyGroups[targetKey] + if (items.length > 1) { + console.log(`发现重复targetKey: ${targetKey},共${items.length}项`) + items.forEach((item) => console.log(` - ${item.fullPath}`)) + + // 按优先级排序,选择最高优先级的项 + items.sort((a, b) => sourcePriority[b.source] - sourcePriority[a.source]) + const selected = items[0] + console.log(` 选择: ${selected.fullPath}`) + deduplicatedData.push(selected) + } else { + deduplicatedData.push(items[0]) + } + }) + + console.log(`去重后剩余 ${deduplicatedData.length} 个preferences项`) + + // 按数据源分组 + const preferencesData = { + electronStore: [], + redux: [], + localStorage: [], + all: deduplicatedData + } + + deduplicatedData.forEach((item) => { + if (preferencesData[item.source]) { + preferencesData[item.source].push(item) + } + }) + + return preferencesData + } + + ensureTargetDirectory() { + if (!fs.existsSync(this.targetDir)) { + fs.mkdirSync(this.targetDir, { recursive: true }) + } + } + + generateMappings(preferencesData) { + // 生成ElectronStore映射 - 简单结构,不需要sourceCategory + const electronStoreMappings = preferencesData.electronStore.map((item) => ({ + originalKey: item.originalKey, + targetKey: item.targetKey + })) + + // 生成Redux映射 - 按category分组 + const reduxMappings = {} + preferencesData.redux.forEach((item) => { + if (!reduxMappings[item.sourceCategory]) { + reduxMappings[item.sourceCategory] = [] + } + reduxMappings[item.sourceCategory].push({ + originalKey: item.originalKey, // 可能包含嵌套路径,如"codeEditor.enabled" + targetKey: item.targetKey + }) + }) + + // 生成映射关系文件内容 + const content = `/** + * Auto-generated preference mappings from classification.json + * Generated at: ${new Date().toISOString()} + * + * This file contains pure mapping relationships without default values. + * Default values are managed in packages/shared/data/preferences.ts + * + * === AUTO-GENERATED CONTENT START === + */ + +/** + * ElectronStore映射关系 - 简单一层结构 + * + * ElectronStore没有嵌套,originalKey直接对应configManager.get(key) + */ +export const ELECTRON_STORE_MAPPINGS = ${JSON.stringify(electronStoreMappings, null, 2)} as const + +/** + * Redux Store映射关系 - 按category分组,支持嵌套路径 + * + * Redux Store可能有children结构,originalKey可能包含嵌套路径: + * - 直接字段: "theme" -> reduxData.settings.theme + * - 嵌套字段: "codeEditor.enabled" -> reduxData.settings.codeEditor.enabled + * - 多层嵌套: "exportMenuOptions.docx" -> reduxData.settings.exportMenuOptions.docx + */ +export const REDUX_STORE_MAPPINGS = ${JSON.stringify(reduxMappings, null, 2)} as const + +// === AUTO-GENERATED CONTENT END === + +/** + * 映射统计: + * - ElectronStore项: ${electronStoreMappings.length} + * - Redux Store项: ${preferencesData.redux.length} + * - Redux分类: ${Object.keys(reduxMappings).join(', ')} + * - 总配置项: ${preferencesData.all.length} + * + * 使用说明: + * 1. ElectronStore读取: configManager.get(mapping.originalKey) + * 2. Redux读取: 需要解析嵌套路径 reduxData[category][originalKey路径] + * 3. 默认值: 从defaultPreferences.default[mapping.targetKey]获取 + */` + + // 写入文件 + const targetFile = path.join(this.targetDir, 'PreferencesMappings.ts') + fs.writeFileSync(targetFile, content, 'utf8') + + console.log(`映射关系文件已生成: ${targetFile}`) + } + + printSummary(preferencesData) { + console.log(`\n生成摘要:`) + console.log(`- 输出文件: PreferencesMappings.ts`) + console.log(`- ElectronStore映射: ${preferencesData.electronStore.length}`) + console.log(`- Redux Store映射: ${preferencesData.redux.length}`) + console.log(`- 总配置项: ${preferencesData.all.length}`) + + // 显示Redux分类 + const reduxCategories = [...new Set(preferencesData.redux.map((item) => item.sourceCategory))] + console.log(`- Redux分类: ${reduxCategories.join(', ')}`) + + // 显示一些嵌套路径的例子 + const nestedKeys = preferencesData.redux + .filter((item) => item.originalKey.includes('.')) + .slice(0, 5) + .map((item) => item.originalKey) + + if (nestedKeys.length > 0) { + console.log(`\n嵌套路径示例:`) + nestedKeys.forEach((key) => console.log(` - ${key}`)) + } + } +} + +// 主执行逻辑 +if (require.main === module) { + try { + const generator = new SimpleMappingGenerator() + generator.generate() + } catch (error) { + console.error('生成失败:', error.message) + process.exit(1) + } +} + +module.exports = SimpleMappingGenerator diff --git a/v2-refactor-temp/tools/data-classify/scripts/generate-preferences.js b/v2-refactor-temp/tools/data-classify/scripts/generate-preferences.js new file mode 100644 index 0000000000..de7e672d02 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/generate-preferences.js @@ -0,0 +1,401 @@ +#!/usr/bin/env node + +const fs = require('fs') +const path = require('path') + +class PreferencesGenerator { + constructor() { + this.dataDir = path.resolve(__dirname, '../data') + this.targetFile = path.resolve(__dirname, '../../../../packages/shared/data/preference/preferenceSchemas.ts') + this.classificationFile = path.join(this.dataDir, 'classification.json') + } + + generate() { + console.log('开始生成 preferences.ts...') + + // 读取分类数据 + const classification = this.loadClassification() + + // 提取preferences相关数据 + const preferencesData = this.extractPreferencesData(classification) + + // 构建类型结构 + const typeStructure = this.buildTypeStructure(preferencesData) + + // 生成TypeScript代码 + const content = this.generateTypeScriptCode(typeStructure, preferencesData) + + // 写入文件 + this.writePreferencesFile(content) + + console.log('preferences.ts 生成完成!') + this.printSummary(preferencesData) + } + + loadClassification() { + if (!fs.existsSync(this.classificationFile)) { + throw new Error(`分类文件不存在: ${this.classificationFile}`) + } + + const content = fs.readFileSync(this.classificationFile, 'utf8') + return JSON.parse(content) + } + + extractPreferencesData(classification) { + const allPreferencesData = [] + const sources = ['electronStore', 'redux', 'localStorage'] + + // 递归提取项目,包括children + const extractItems = (items, source, category, parentKey = '') => { + if (!Array.isArray(items)) return + + items.forEach((item) => { + // 处理有children的项目 + if (item.children && Array.isArray(item.children)) { + console.log(`处理children项: ${source}/${category}/${item.originalKey}`) + extractItems(item.children, source, category, `${parentKey}${item.originalKey}.`) + return + } + + // 处理普通项目 + if (item.category === 'preferences' && item.status === 'classified' && item.targetKey) { + allPreferencesData.push({ + ...item, + source, + sourceCategory: category, + originalKey: parentKey + item.originalKey, // 包含父级路径 + fullPath: `${source}/${category}/${parentKey}${item.originalKey}` + }) + } + }) + } + + sources.forEach((source) => { + if (classification.classifications[source]) { + Object.keys(classification.classifications[source]).forEach((category) => { + const items = classification.classifications[source][category] + extractItems(items, source, category) + }) + } + }) + + console.log(`提取到 ${allPreferencesData.length} 个preferences项(包含children)`) + + // 处理重复的targetKey,优先使用redux数据 + const targetKeyGroups = {} + allPreferencesData.forEach((item) => { + if (!targetKeyGroups[item.targetKey]) { + targetKeyGroups[item.targetKey] = [] + } + targetKeyGroups[item.targetKey].push(item) + }) + + // 去重:按redux > localStorage > electronStore优先级选择 + const sourcePriority = { redux: 3, localStorage: 2, electronStore: 1 } + const deduplicatedData = [] + + Object.keys(targetKeyGroups).forEach((targetKey) => { + const items = targetKeyGroups[targetKey] + if (items.length > 1) { + console.log(`发现重复targetKey: ${targetKey},共${items.length}项`) + items.forEach((item) => console.log(` - ${item.fullPath}`)) + + // 按优先级排序,选择最高优先级的项 + items.sort((a, b) => sourcePriority[b.source] - sourcePriority[a.source]) + const selected = items[0] + console.log(` 选择: ${selected.fullPath}`) + deduplicatedData.push(selected) + } else { + deduplicatedData.push(items[0]) + } + }) + + console.log(`去重后剩余 ${deduplicatedData.length} 个preferences项`) + return deduplicatedData + } + + buildTypeStructure(preferencesData) { + const structure = { default: {} } + + preferencesData.forEach((item) => { + if (!item.targetKey) return + + // 直接使用targetKey作为键,不进行拆分 + structure.default[item.targetKey] = { + type: this.mapType(item.type, item.defaultValue), + defaultValue: item.defaultValue, + description: `${item.source}/${item.sourceCategory}/${item.originalKey}`, + originalItem: item + } + }) + + return structure + } + + mapType(itemType, defaultValue) { + // 优先使用明确定义的类型,只有当type为unknown时才进行类型推断 + // 'VALUE: null' is a special marker to indicate the value should be null and not overwritten + const isNullable = defaultValue === null || defaultValue === undefined || defaultValue === 'VALUE: null' + + // 如果type不是unknown,直接使用定义好的类型 + if (itemType && itemType !== 'unknown') { + // 处理简单的基础类型 + if (itemType === 'boolean') { + return isNullable ? 'boolean | null' : 'boolean' + } + if (itemType === 'string') { + return isNullable ? 'string | null' : 'string' + } + if (itemType === 'number') { + return isNullable ? 'number | null' : 'number' + } + + // 处理数组类型(支持string[]、number[]等格式) + if (itemType.endsWith('[]')) { + return isNullable ? `${itemType} | null` : itemType + } + + // 处理array泛型类型 + if (itemType === 'array') { + // 尝试从默认值推断数组元素类型 + if (Array.isArray(defaultValue) && defaultValue.length > 0) { + const elementType = typeof defaultValue[0] + return `${elementType}[]` + } + return isNullable ? 'unknown[] | null' : 'unknown[]' + } + + // 处理object类型 + if (itemType === 'object') { + return isNullable ? 'Record | null' : 'Record' + } + + // 对于其他明确定义的类型,直接使用 + return isNullable ? `${itemType} | null` : itemType + } + + // 只有当type为unknown或未定义时,才基于默认值进行类型推断 + if (defaultValue !== null && defaultValue !== undefined) { + const valueType = typeof defaultValue + if (valueType === 'boolean' || valueType === 'string' || valueType === 'number') { + return valueType + } + if (Array.isArray(defaultValue)) { + return 'unknown[]' + } + if (valueType === 'object') { + return 'Record' + } + } + + return 'unknown | null' + } + + generateTypeScriptCode(structure, preferencesData) { + const header = `/** + * Auto-generated preferences configuration + * Generated at: ${new Date().toISOString()} + * + * This file is automatically generated from classification.json + * To update this file, modify classification.json and run: + * node v2-refactor-temp/tools/data-classify/scripts/generate-preferences.js + * + * ## Key Naming Convention + * + * All preference keys MUST follow the format: \`namespace.sub.key_name\` + * + * Rules: + * - At least 2 segments separated by dots (.) + * - Each segment uses lowercase letters, numbers, and underscores only + * - Pattern: /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$/ + * + * Examples: + * - 'app.user.avatar' (valid) + * - 'chat.multi_select_mode' (valid) + * - 'userAvatar' (invalid - missing dot separator) + * - 'App.user' (invalid - uppercase not allowed) + * + * This convention is enforced by ESLint rule: data-schema-key/valid-key + * + * === AUTO-GENERATED CONTENT START === + */ + +import { MEMORY_FACT_EXTRACTION_PROMPT, MEMORY_UPDATE_SYSTEM_PROMPT,TRANSLATE_PROMPT } from '@shared/config/prompts' +import * as PreferenceTypes from '@shared/data/preference/preferenceTypes' + +/* eslint @typescript-eslint/member-ordering: ["error", { + "interfaces": { "order": "alphabetically" }, + "typeLiterals": { "order": "alphabetically" } +}] */` + // 生成接口定义 + const interfaceCode = this.generateInterface(structure) + + // 生成默认值对象 + const defaultsCode = this.generateDefaults(structure) + + const footer = ` +// === AUTO-GENERATED CONTENT END === + +/** + * 生成统计: + * - 总配置项: ${preferencesData.length} + * - electronStore项: ${preferencesData.filter((p) => p.source === 'electronStore').length} + * - redux项: ${preferencesData.filter((p) => p.source === 'redux').length} + * - localStorage项: ${preferencesData.filter((p) => p.source === 'localStorage').length} + */` + + return [header, interfaceCode, defaultsCode, footer].join('\n\n') + } + + generateInterface(structure, depth = 0) { + const indent = ' '.repeat(depth) + + if (depth === 0) { + // 顶层接口 + let code = `export interface PreferenceSchemas {\n` + Object.keys(structure) + .sort() + .forEach((scope) => { + code += `${indent} ${scope}: {\n` + code += this.generateInterfaceProperties(structure[scope], depth + 2) + code += `${indent} }\n` + }) + code += `}` + return code + } + } + + generateInterfaceProperties(obj, depth) { + const indent = ' '.repeat(depth) + let code = '' + + // 获取所有键并排序 + const keys = Object.keys(obj).sort() + + keys.forEach((key) => { + const value = obj[key] + + if (value.type) { + // 叶子节点 - 实际的配置项,直接使用targetKey + const comment = value.description ? `${indent}// ${value.description}\n` : '' + code += `${comment}${indent}'${key}': ${value.type}\n` + } else { + // 中间节点 - 嵌套对象 + code += `${indent}'${key}': {\n` + code += this.generateInterfaceProperties(value, depth + 1) + code += `${indent}}\n` + } + }) + + return code + } + + generateDefaults(structure) { + const header = `/* eslint sort-keys: ["error", "asc", {"caseSensitive": true, "natural": false}] */ +export const DefaultPreferences: PreferenceSchemas = {` + + let code = header + '\n' + + Object.keys(structure) + .sort() + .forEach((scope) => { + code += ` ${scope}: {\n` + code += this.generateDefaultsProperties(structure[scope], 2) + code += ' }\n' + }) + + code += '}' + return code + } + + generateDefaultsProperties(obj, depth) { + const indent = ' '.repeat(depth) + let code = '' + + // 获取所有键并排序 + const keys = Object.keys(obj).sort() + + keys.forEach((key, index) => { + const value = obj[key] + const isLast = index === keys.length - 1 + + if (value.type) { + // 叶子节点 - 实际的配置项,直接使用targetKey + const defaultVal = this.formatDefaultValue(value.defaultValue) + code += `${indent}'${key}': ${defaultVal}${isLast ? '' : ','}\n` + } else { + // 中间节点 - 嵌套对象 + code += `${indent}'${key}': {\n` + code += this.generateDefaultsProperties(value, depth + 1) + code += `${indent}}${isLast ? '' : ','}\n` + } + }) + + return code + } + + formatDefaultValue(value) { + if (value === null || value === undefined) { + return 'null' + } + if (typeof value === 'string') { + // Handle special "VALUE: xxxx" format - use xxxx directly without quotes + if (value.startsWith('VALUE: ')) { + return value.substring(7) // Remove "VALUE: " prefix and don't add quotes + } + return `'${value.replace(/'/g, "\\'")}'` + } + if (typeof value === 'boolean' || typeof value === 'number') { + return String(value) + } + if (Array.isArray(value)) { + return `[${value.map((item) => this.formatDefaultValue(item)).join(', ')}]` + } + if (typeof value === 'object') { + const entries = Object.entries(value).map(([k, v]) => `${k}: ${this.formatDefaultValue(v)}`) + return `{ ${entries.join(', ')} }` + } + return JSON.stringify(value) + } + + writePreferencesFile(content) { + const targetDir = path.dirname(this.targetFile) + if (!fs.existsSync(targetDir)) { + fs.mkdirSync(targetDir, { recursive: true }) + } + + fs.writeFileSync(this.targetFile, content, 'utf8') + } + + printSummary(preferencesData) { + console.log(`\n生成摘要:`) + console.log(`- 总配置项: ${preferencesData.length}`) + console.log(`- electronStore项: ${preferencesData.filter((p) => p.source === 'electronStore').length}`) + console.log(`- redux项: ${preferencesData.filter((p) => p.source === 'redux').length}`) + console.log(`- localStorage项: ${preferencesData.filter((p) => p.source === 'localStorage').length}`) + console.log(`- 输出文件: ${this.targetFile}`) + + // 显示一些示例targetKey + const sampleKeys = preferencesData + .slice(0, 5) + .map((p) => p.targetKey) + .filter(Boolean) + if (sampleKeys.length > 0) { + console.log(`\n示例配置键:`) + sampleKeys.forEach((key) => console.log(` - ${key}`)) + } + } +} + +// 主执行逻辑 +if (require.main === module) { + try { + const generator = new PreferencesGenerator() + generator.generate() + } catch (error) { + console.error('生成失败:', error.message) + process.exit(1) + } +} + +module.exports = PreferencesGenerator diff --git a/v2-refactor-temp/tools/data-classify/scripts/lib/classificationUtils.js b/v2-refactor-temp/tools/data-classify/scripts/lib/classificationUtils.js new file mode 100644 index 0000000000..33ac25adf5 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/lib/classificationUtils.js @@ -0,0 +1,323 @@ +/** + * Shared utilities for data classification tools + * + * This module provides common functions used across multiple scripts: + * - Loading and saving classification data + * - Extracting preferences data with deduplication + * - Traversing nested classification structures + */ + +const fs = require('fs') +const path = require('path') + +/** + * Default data directory path + */ +const DATA_DIR = path.resolve(__dirname, '../../data') + +/** + * Load classification.json file + * @param {string} [dataDir] - Optional custom data directory + * @returns {Object} Parsed classification data + */ +function loadClassification(dataDir = DATA_DIR) { + const classificationFile = path.join(dataDir, 'classification.json') + + if (!fs.existsSync(classificationFile)) { + throw new Error(`Classification file not found: ${classificationFile}`) + } + + const content = fs.readFileSync(classificationFile, 'utf8') + return JSON.parse(content) +} + +/** + * Save classification data to file with backup + * @param {Object} classification - Classification data to save + * @param {string} [dataDir] - Optional custom data directory + */ +function saveClassification(classification, dataDir = DATA_DIR) { + const classificationFile = path.join(dataDir, 'classification.json') + + // Create backup if file exists + if (fs.existsSync(classificationFile)) { + const timestamp = new Date().toISOString().replace(/[:.]/g, '-') + const backupPath = path.join(dataDir, `classification.backup.${timestamp}.json`) + fs.copyFileSync(classificationFile, backupPath) + console.log(`Backup created: ${backupPath}`) + } + + fs.writeFileSync(classificationFile, JSON.stringify(classification, null, 2), 'utf8') + console.log(`Classification saved: ${classificationFile}`) +} + +/** + * Load inventory.json file + * @param {string} [dataDir] - Optional custom data directory + * @returns {Object} Parsed inventory data + */ +function loadInventory(dataDir = DATA_DIR) { + const inventoryFile = path.join(dataDir, 'inventory.json') + + if (!fs.existsSync(inventoryFile)) { + throw new Error(`Inventory file not found: ${inventoryFile}`) + } + + const content = fs.readFileSync(inventoryFile, 'utf8') + return JSON.parse(content) +} + +/** + * Source priority for deduplication + * Higher number = higher priority + */ +const SOURCE_PRIORITY = { + redux: 3, + localStorage: 2, + electronStore: 1 +} + +/** + * Extract preferences data from classification with deduplication + * Supports nested structures with children + * + * @param {Object} classification - Classification data object + * @returns {Object} Object with categorized preferences data: + * - all: all deduplicated items + * - electronStore: items from electronStore + * - redux: items from redux + * - localStorage: items from localStorage + */ +function extractPreferencesData(classification) { + const allPreferencesData = [] + const sources = ['electronStore', 'redux', 'localStorage'] + + // Recursive function to extract items including children + const extractItems = (items, source, category, parentKey = '') => { + if (!Array.isArray(items)) return + + items.forEach((item) => { + // Handle items with children + if (item.children && Array.isArray(item.children)) { + extractItems(item.children, source, category, `${parentKey}${item.originalKey}.`) + return + } + + // Handle regular items + if (item.category === 'preferences' && item.status === 'classified' && item.targetKey) { + allPreferencesData.push({ + ...item, + source, + sourceCategory: category, + originalKey: parentKey + item.originalKey, + fullPath: `${source}/${category}/${parentKey}${item.originalKey}` + }) + } + }) + } + + // Extract from all sources + sources.forEach((source) => { + if (classification.classifications[source]) { + Object.keys(classification.classifications[source]).forEach((category) => { + const items = classification.classifications[source][category] + extractItems(items, source, category) + }) + } + }) + + // Handle duplicate targetKeys with priority-based selection + const targetKeyGroups = {} + allPreferencesData.forEach((item) => { + if (!targetKeyGroups[item.targetKey]) { + targetKeyGroups[item.targetKey] = [] + } + targetKeyGroups[item.targetKey].push(item) + }) + + // Deduplicate using source priority + const deduplicatedData = [] + Object.keys(targetKeyGroups).forEach((targetKey) => { + const items = targetKeyGroups[targetKey] + if (items.length > 1) { + // Sort by priority and select highest + items.sort((a, b) => SOURCE_PRIORITY[b.source] - SOURCE_PRIORITY[a.source]) + } + deduplicatedData.push(items[0]) + }) + + // Group by source + const result = { + electronStore: [], + redux: [], + localStorage: [], + all: deduplicatedData + } + + deduplicatedData.forEach((item) => { + if (result[item.source]) { + result[item.source].push(item) + } + }) + + return result +} + +/** + * Traverse nested classification structure + * Calls callback for each item (including nested children) + * + * @param {Object} classifications - The classifications object + * @param {Function} callback - Function to call for each item: (item, source, category, fullKey) => void + */ +function traverseClassifications(classifications, callback) { + const traverse = (items, source, category, parentKey = '') => { + if (!Array.isArray(items)) return + + for (const item of items) { + const fullKey = parentKey ? `${parentKey}.${item.originalKey}` : item.originalKey + + // Call callback for this item + callback(item, source, category, fullKey) + + // Recurse into children + if (item.children && Array.isArray(item.children)) { + traverse(item.children, source, category, fullKey) + } + } + } + + // Iterate through all sources and categories + for (const [source, sourceData] of Object.entries(classifications)) { + if (typeof sourceData === 'object' && sourceData !== null) { + for (const [category, items] of Object.entries(sourceData)) { + if (Array.isArray(items)) { + traverse(items, source, category, '') + } + } + } + } +} + +/** + * Get all flat keys from nested classification structure + * Used for comparison and validation + * + * @param {Object} classifications - The classifications object + * @returns {string[]} Array of full keys in format "source.category.field" or "source.category.parent.child" + */ +function getAllClassificationKeys(classifications) { + const keys = [] + + traverseClassifications(classifications, (item, source, category, fullKey) => { + // Build the complete key path + if (source === 'redux') { + keys.push(`${source}.${category}.${fullKey}`) + } else { + keys.push(`${source}.${fullKey}`) + } + }) + + return keys +} + +/** + * Calculate statistics from nested classification structure + * + * @param {Object} classifications - The classifications object + * @returns {Object} Statistics object with counts by status and category + */ +function calculateStats(classifications) { + const stats = { + byStatus: { + pending: 0, + classified: 0, + 'classified-deleted': 0 + }, + byCategory: {}, + total: 0 + } + + traverseClassifications(classifications, (item) => { + stats.total++ + + // Count by status + if (item.status) { + stats.byStatus[item.status] = (stats.byStatus[item.status] || 0) + 1 + } + + // Count by category (only for classified items) + if (item.status === 'classified' && item.category) { + stats.byCategory[item.category] = (stats.byCategory[item.category] || 0) + 1 + } + }) + + return stats +} + +/** + * Normalize type string to standard format + * + * @param {string} type - Type string to normalize + * @returns {string} Normalized type string + */ +function normalizeType(type) { + if (!type || type === 'unknown') { + return 'unknown' + } + + const cleanType = String(type).toLowerCase().trim() + + // Handle union types - extract primary type + if (cleanType.includes('|')) { + const types = cleanType.split('|').map((t) => t.trim()) + const nonNullTypes = types.filter((t) => t !== 'null' && t !== 'undefined') + if (nonNullTypes.length > 0) { + return normalizeType(nonNullTypes[0]) + } + return normalizeType(types[0]) + } + + // Map to standard types + if (cleanType === 'string' || cleanType.includes('string')) return 'string' + if (cleanType === 'number' || cleanType.includes('number')) return 'number' + if (cleanType === 'boolean' || cleanType.includes('boolean')) return 'boolean' + if (cleanType === 'array' || cleanType.includes('[]')) return 'array' + if (cleanType === 'object' || cleanType.includes('object') || cleanType.includes('record')) return 'object' + if (cleanType === 'null') return 'null' + if (cleanType === 'undefined') return 'undefined' + if (cleanType.includes('entitytable') || cleanType === 'table') return 'table' + + return 'unknown' +} + +/** + * Infer type from a value + * + * @param {*} value - Value to infer type from + * @returns {string} Inferred type string + */ +function inferTypeFromValue(value) { + if (value === null) return 'null' + if (value === undefined) return 'undefined' + if (typeof value === 'boolean') return 'boolean' + if (typeof value === 'number') return 'number' + if (typeof value === 'string') return 'string' + if (Array.isArray(value)) return 'array' + if (typeof value === 'object') return 'object' + return 'unknown' +} + +module.exports = { + DATA_DIR, + loadClassification, + saveClassification, + loadInventory, + extractPreferencesData, + traverseClassifications, + getAllClassificationKeys, + calculateStats, + normalizeType, + inferTypeFromValue, + SOURCE_PRIORITY +} diff --git a/v2-refactor-temp/tools/data-classify/scripts/validate-consistency.js b/v2-refactor-temp/tools/data-classify/scripts/validate-consistency.js new file mode 100644 index 0000000000..01e0bcff82 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/validate-consistency.js @@ -0,0 +1,293 @@ +#!/usr/bin/env node + +/** + * Data Consistency Validator + * + * Validates consistency between inventory.json and classification.json files. + * Supports nested classification structures with children arrays. + * + * Checks: + * - Missing classifications (data in inventory but not classified) + * - Orphaned classifications (classified items not in inventory) + * - Naming consistency (preferences should use dot-separated keys) + * - Duplicate target keys + * + * Usage: + * node v2-refactor-temp/tools/data-classify/scripts/validate-consistency.js + */ + +const fs = require('fs') +const path = require('path') + +const { + loadClassification, + loadInventory, + traverseClassifications, + calculateStats, + DATA_DIR +} = require('./lib/classificationUtils') + +class DataValidator { + constructor() { + this.dataDir = DATA_DIR + } + + /** + * Main validation entry point + */ + validate() { + console.log('Starting data consistency validation...\n') + + let inventory, classification + try { + inventory = loadInventory(this.dataDir) + classification = loadClassification(this.dataDir) + } catch (error) { + console.error(`Failed to load data files: ${error.message}`) + process.exit(1) + } + + const issues = [] + + // Run all consistency checks + issues.push(...this.checkMissingClassifications(inventory, classification)) + issues.push(...this.checkOrphanedClassifications(inventory, classification)) + issues.push(...this.checkNamingConsistency(classification)) + issues.push(...this.checkDuplicateTargets(classification)) + + // Generate validation report + this.generateReport(issues, classification) + + if (issues.length === 0) { + console.log('Validation passed, no issues found') + } else { + const errors = issues.filter((i) => i.severity === 'error') + const warnings = issues.filter((i) => i.severity === 'warning') + console.log(`Found ${errors.length} errors, ${warnings.length} warnings`) + if (errors.length > 0) { + process.exit(1) + } + } + } + + /** + * Get all data keys from inventory + */ + getAllInventoryKeys(inventory) { + const keys = [] + + for (const [source, data] of Object.entries(inventory)) { + if (source === 'metadata') continue + + for (const [moduleOrTable, moduleData] of Object.entries(data)) { + if (source === 'redux') { + // Redux: keys are source.module.field + for (const fieldName of Object.keys(moduleData)) { + if (fieldName === '_meta') continue + keys.push(`${source}.${moduleOrTable}.${fieldName}`) + } + } else { + // Other sources: keys are source.tableName + keys.push(`${source}.${moduleOrTable}`) + } + } + } + + return keys + } + + /** + * Get all data keys from classification (supports nested structure) + */ + getAllClassificationKeys(classification) { + const keys = [] + + traverseClassifications(classification.classifications, (item, source, category, fullKey) => { + // Skip deleted items + if (item.status === 'classified-deleted') return + + // Build full key path + if (source === 'redux') { + keys.push(`${source}.${category}.${fullKey}`) + } else { + keys.push(`${source}.${fullKey}`) + } + }) + + return keys + } + + /** + * Check for data items not yet classified + */ + checkMissingClassifications(inventory, classification) { + const issues = [] + const inventoryKeys = this.getAllInventoryKeys(inventory) + const classificationKeys = new Set(this.getAllClassificationKeys(classification)) + + for (const key of inventoryKeys) { + if (!classificationKeys.has(key)) { + issues.push({ + type: 'missing_classification', + severity: 'warning', + key: key, + message: `Data item "${key}" is not classified` + }) + } + } + + return issues + } + + /** + * Check for classified items not in current inventory + */ + checkOrphanedClassifications(inventory, classification) { + const issues = [] + const inventoryKeys = new Set(this.getAllInventoryKeys(inventory)) + + traverseClassifications(classification.classifications, (item, source, category, fullKey) => { + // Skip deleted items + if (item.status === 'classified-deleted') return + + // Build full key path + let fullKeyPath + if (source === 'redux') { + fullKeyPath = `${source}.${category}.${fullKey}` + } else { + fullKeyPath = `${source}.${fullKey}` + } + + if (!inventoryKeys.has(fullKeyPath)) { + issues.push({ + type: 'orphaned_classification', + severity: 'warning', + key: fullKeyPath, + message: `Classified item "${fullKeyPath}" not found in current inventory` + }) + } + }) + + return issues + } + + /** + * Check naming consistency for preferences + */ + checkNamingConsistency(classification) { + const issues = [] + + traverseClassifications(classification.classifications, (item) => { + if (item.status !== 'classified') return + if (item.category !== 'preferences') return + + // Preferences should have dot-separated targetKey + if (item.targetKey && !item.targetKey.includes('.')) { + issues.push({ + type: 'naming_inconsistency', + severity: 'warning', + key: item.originalKey, + message: `Preference targetKey "${item.targetKey}" should use dot-separated hierarchy (e.g., "ui.theme")` + }) + } + }) + + return issues + } + + /** + * Check for duplicate target keys + */ + checkDuplicateTargets(classification) { + const issues = [] + const targetKeyMap = {} + + traverseClassifications(classification.classifications, (item, source, category, fullKey) => { + if (item.status === 'classified-deleted') return + + const targetKey = item.targetKey || item.targetTable + if (!targetKey) return + + const sourceKey = source === 'redux' ? `${source}.${category}.${fullKey}` : `${source}.${fullKey}` + + if (targetKeyMap[targetKey]) { + issues.push({ + type: 'duplicate_target', + severity: 'error', + key: sourceKey, + message: `Target key "${targetKey}" is used by both "${sourceKey}" and "${targetKeyMap[targetKey]}"` + }) + } else { + targetKeyMap[targetKey] = sourceKey + } + }) + + return issues + } + + /** + * Generate validation report markdown file + */ + generateReport(issues, classification) { + const reportPath = path.join(this.dataDir, '../validation-report.md') + const stats = calculateStats(classification.classifications) + + let report = `# Data Validation Report\n\n` + report += `Generated: ${new Date().toISOString()}\n` + report += `Issues found: ${issues.length}\n\n` + + if (issues.length === 0) { + report += `## Validation Passed\n\nNo consistency issues found.\n\n` + } else { + const errors = issues.filter((i) => i.severity === 'error') + const warnings = issues.filter((i) => i.severity === 'warning') + + if (errors.length > 0) { + report += `## Errors (${errors.length})\n\n` + for (const issue of errors) { + report += `### ${issue.type}\n` + report += `- **Item**: \`${issue.key}\`\n` + report += `- **Issue**: ${issue.message}\n\n` + } + } + + if (warnings.length > 0) { + report += `## Warnings (${warnings.length})\n\n` + for (const issue of warnings) { + report += `### ${issue.type}\n` + report += `- **Item**: \`${issue.key}\`\n` + report += `- **Issue**: ${issue.message}\n\n` + } + } + } + + // Statistics section + report += `## Classification Statistics\n\n` + + report += `### By Status\n\n` + report += `- **Pending**: ${stats.byStatus.pending || 0}\n` + report += `- **Classified**: ${stats.byStatus.classified || 0}\n` + report += `- **Deleted**: ${stats.byStatus['classified-deleted'] || 0}\n\n` + + if (Object.keys(stats.byCategory).length > 0) { + report += `### By Category\n\n` + for (const [category, count] of Object.entries(stats.byCategory)) { + report += `- **${category}**: ${count}\n` + } + report += `\n` + } + + report += `### Total Items: ${stats.total}\n` + + fs.writeFileSync(reportPath, report, 'utf8') + console.log(`Validation report saved: ${reportPath}`) + } +} + +// Run script +if (require.main === module) { + const validator = new DataValidator() + validator.validate() +} + +module.exports = DataValidator diff --git a/v2-refactor-temp/tools/data-classify/scripts/validate-generation.js b/v2-refactor-temp/tools/data-classify/scripts/validate-generation.js new file mode 100644 index 0000000000..f6f6d05f46 --- /dev/null +++ b/v2-refactor-temp/tools/data-classify/scripts/validate-generation.js @@ -0,0 +1,239 @@ +#!/usr/bin/env node + +/** + * Generated Code Quality Validator + * + * Validates the quality and correctness of auto-generated code files. + * Checks generated preferences schema and migration mapping files. + * + * Validates: + * - preferenceSchemas.ts - Interface definitions and default values + * - PreferencesMappings.ts - Source to target key mappings + * + * Usage: + * node v2-refactor-temp/tools/data-classify/scripts/validate-generation.js + */ + +const fs = require('fs') +const path = require('path') + +class GenerationValidator { + constructor() { + this.projectRoot = path.resolve(__dirname, '../../../../') + + // Updated paths to match actual project structure + this.preferencesFile = path.join(this.projectRoot, 'packages/shared/data/preference/preferenceSchemas.ts') + this.mappingsFile = path.join( + this.projectRoot, + 'src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts' + ) + + this.results = { + preferences: { valid: false, errors: [], warnings: [] }, + mappings: { valid: false, errors: [], warnings: [] } + } + } + + /** + * Main validation entry point + */ + validate() { + console.log('Validating generated code quality...\n') + + this.validatePreferencesFile() + this.validateMappingsFile() + this.printSummary() + + return this.results + } + + /** + * Validate preferenceSchemas.ts file + */ + validatePreferencesFile() { + console.log('Validating preferenceSchemas.ts...') + + if (!fs.existsSync(this.preferencesFile)) { + this.results.preferences.errors.push(`File not found: ${this.preferencesFile}`) + return + } + + try { + const content = fs.readFileSync(this.preferencesFile, 'utf8') + + // Check for auto-generation marker + if (!content.includes('AUTO-GENERATED CONTENT START')) { + this.results.preferences.errors.push('Missing auto-generated content marker') + } + + // Check for interface definition (updated name) + if (!content.includes('export interface PreferenceSchemas')) { + this.results.preferences.errors.push('Missing PreferenceSchemas interface definition') + } + + // Check for ESLint configuration + if (!content.includes('/* eslint')) { + this.results.preferences.warnings.push('Missing ESLint configuration comment') + } + + // Check for imports + if (!content.includes("from '@shared/data/preference/preferenceTypes'")) { + this.results.preferences.warnings.push('Missing preferenceTypes import') + } + + // Count preference keys + const keyMatches = content.match(/'[\w.]+'/g) + if (keyMatches) { + const keyCount = keyMatches.length + console.log(` Found ${keyCount} preference keys`) + + if (keyCount < 50) { + this.results.preferences.warnings.push(`Low preference key count: ${keyCount} (expected 100+)`) + } + } else { + this.results.preferences.warnings.push('Could not parse preference key count') + } + + // Check key naming convention + const invalidKeys = [] + const keyPattern = /^\s*'([^']+)':/gm + let match + while ((match = keyPattern.exec(content)) !== null) { + const key = match[1] + // Keys should be dot-separated lowercase + if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(key)) { + invalidKeys.push(key) + } + } + + if (invalidKeys.length > 0 && invalidKeys.length <= 5) { + this.results.preferences.warnings.push( + `Found ${invalidKeys.length} keys not matching naming convention: ${invalidKeys.slice(0, 3).join(', ')}...` + ) + } else if (invalidKeys.length > 5) { + this.results.preferences.warnings.push(`Found ${invalidKeys.length} keys not matching naming convention`) + } + + if (this.results.preferences.errors.length === 0) { + this.results.preferences.valid = true + console.log(' preferenceSchemas.ts validation passed') + } + } catch (error) { + this.results.preferences.errors.push(`Failed to read file: ${error.message}`) + } + } + + /** + * Validate PreferencesMappings.ts file + */ + validateMappingsFile() { + console.log('\nValidating PreferencesMappings.ts...') + + if (!fs.existsSync(this.mappingsFile)) { + this.results.mappings.errors.push(`File not found: ${this.mappingsFile}`) + return + } + + try { + const content = fs.readFileSync(this.mappingsFile, 'utf8') + + // Check for auto-generation marker + if (!content.includes('AUTO-GENERATED CONTENT')) { + this.results.mappings.warnings.push('Missing auto-generated content marker') + } + + // Check for ELECTRON_STORE_MAPPINGS export + if (!content.includes('export const ELECTRON_STORE_MAPPINGS')) { + this.results.mappings.errors.push('Missing ELECTRON_STORE_MAPPINGS export') + } + + // Check for REDUX_STORE_MAPPINGS export + if (!content.includes('export const REDUX_STORE_MAPPINGS')) { + this.results.mappings.errors.push('Missing REDUX_STORE_MAPPINGS export') + } + + // Check for as const assertion for type safety + if (!content.includes('as const')) { + this.results.mappings.warnings.push('Missing "as const" assertion for type safety') + } + + // Count mapping entries + const originalKeyMatches = content.match(/originalKey:/g) + if (originalKeyMatches) { + const mappingCount = originalKeyMatches.length + console.log(` Found ${mappingCount} mapping entries`) + + if (mappingCount < 10) { + this.results.mappings.warnings.push(`Low mapping count: ${mappingCount} (expected 50+)`) + } + } + + // Check for valid mapping structure + const mappingPattern = /\{\s*originalKey:\s*'[^']+',\s*targetKey:\s*'[^']+'\s*\}/g + const validMappings = content.match(mappingPattern) + if (!validMappings || validMappings.length === 0) { + this.results.mappings.warnings.push('Could not find valid mapping structures') + } + + if (this.results.mappings.errors.length === 0) { + this.results.mappings.valid = true + console.log(' PreferencesMappings.ts validation passed') + } + } catch (error) { + this.results.mappings.errors.push(`Failed to read file: ${error.message}`) + } + } + + /** + * Print validation summary + */ + printSummary() { + console.log('\n' + '='.repeat(50)) + console.log('Validation Summary') + console.log('='.repeat(50)) + + // Preferences results + console.log(`\npreferenceSchemas.ts: ${this.results.preferences.valid ? 'PASSED' : 'FAILED'}`) + for (const error of this.results.preferences.errors) { + console.log(` ERROR: ${error}`) + } + for (const warning of this.results.preferences.warnings) { + console.log(` WARNING: ${warning}`) + } + + // Mappings results + console.log(`\nPreferencesMappings.ts: ${this.results.mappings.valid ? 'PASSED' : 'FAILED'}`) + for (const error of this.results.mappings.errors) { + console.log(` ERROR: ${error}`) + } + for (const warning of this.results.mappings.warnings) { + console.log(` WARNING: ${warning}`) + } + + // Overall result + const overallValid = this.results.preferences.valid && this.results.mappings.valid + const totalErrors = this.results.preferences.errors.length + this.results.mappings.errors.length + const totalWarnings = this.results.preferences.warnings.length + this.results.mappings.warnings.length + + console.log('\n' + '='.repeat(50)) + console.log(`Overall: ${overallValid ? 'PASSED' : 'FAILED'}`) + console.log(`Errors: ${totalErrors}, Warnings: ${totalWarnings}`) + + if (overallValid) { + console.log('\nGenerated code quality is acceptable!') + } else { + console.log('\nPlease fix the errors and regenerate the code.') + } + } +} + +// Run script +if (require.main === module) { + const validator = new GenerationValidator() + const results = validator.validate() + + const hasErrors = results.preferences.errors.length > 0 || results.mappings.errors.length > 0 + process.exit(hasErrors ? 1 : 0) +} + +module.exports = GenerationValidator