mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-01 17:59:09 +08:00
feat(preferences): auto-generate preferences configuration from classification.json
This commit introduces an auto-generated preferences configuration file, replacing the previous manual definitions. The new structure is based on the latest classification.json and includes comprehensive settings for various application features. The auto-generation process ensures that the preferences are up-to-date and consistent with the defined classifications.
This commit is contained in:
parent
21e40db086
commit
4e3f8a8f76
@ -1,35 +1,510 @@
|
||||
/**
|
||||
* we should use sorted object keys
|
||||
* use `eslint --fix` to auto sort keys
|
||||
* Auto-generated preferences configuration
|
||||
* Generated at: 2025-08-09T07:25:38.982Z
|
||||
*
|
||||
* This file is automatically generated from classification.json
|
||||
* To update this file, modify classification.json and run:
|
||||
* node .claude/data-classify/scripts/generate-preferences.js
|
||||
*
|
||||
* === AUTO-GENERATED CONTENT START ===
|
||||
*/
|
||||
|
||||
/* eslint @typescript-eslint/member-ordering: ["error", {
|
||||
"interfaces": { "order": "alphabetically" },
|
||||
"typeLiterals": { "order": "alphabetically" }
|
||||
}] */
|
||||
|
||||
export interface PreferencesType {
|
||||
default: {
|
||||
'app.test5': {
|
||||
content1: string
|
||||
content2: number
|
||||
}
|
||||
'sys.a.test3': boolean
|
||||
'sys.a.test4': string[]
|
||||
'ui.a.test1': string
|
||||
'ui.b.test2': number
|
||||
// redux/settings/enableDeveloperMode
|
||||
'app.developer_mode.enabled': boolean
|
||||
// redux/settings/disableHardwareAcceleration
|
||||
'app.disable_hardware_acceleration': boolean
|
||||
// redux/settings/autoCheckUpdate
|
||||
'app.dist.auto_update.enabled': boolean
|
||||
// redux/settings/testChannel
|
||||
'app.dist.test_plan.channel': string
|
||||
// redux/settings/testPlan
|
||||
'app.dist.test_plan.enabled': boolean
|
||||
// electronStore/Language/Language
|
||||
'app.language': unknown | null
|
||||
// redux/settings/launchOnBoot
|
||||
'app.launch_on_boot': boolean
|
||||
// redux/settings/notification.assistant
|
||||
'app.notification.assistant.enabled': boolean
|
||||
// redux/settings/notification.backup
|
||||
'app.notification.backup.enabled': boolean
|
||||
// redux/settings/notification.knowledge
|
||||
'app.notification.knowledge.enabled': boolean
|
||||
// redux/settings/enableDataCollection
|
||||
'app.privacy.data_collection.enabled': boolean
|
||||
// redux/settings/proxyBypassRules
|
||||
'app.proxy.bypass_rules': string | null
|
||||
// redux/settings/proxyMode
|
||||
'app.proxy.mode': string
|
||||
// redux/settings/proxyUrl
|
||||
'app.proxy.url': string | null
|
||||
// redux/settings/enableSpellCheck
|
||||
'app.spell_check.enabled': boolean
|
||||
// redux/settings/spellCheckLanguages
|
||||
'app.spell_check.languages': unknown[]
|
||||
// redux/settings/theme
|
||||
'app.theme.mode': string
|
||||
// redux/settings/userTheme
|
||||
'app.theme.user_defined': Record<string, unknown>
|
||||
// redux/settings/windowStyle
|
||||
'app.theme.window_style': string
|
||||
// redux/settings/tray
|
||||
'app.tray.enabled': boolean
|
||||
// redux/settings/trayOnClose
|
||||
'app.tray.on_close': boolean
|
||||
// redux/settings/launchToTray
|
||||
'app.tray.on_launch': boolean
|
||||
// redux/settings/userId
|
||||
'app.user.id': string
|
||||
// redux/settings/userName
|
||||
'app.user.name': string
|
||||
// electronStore/ZoomFactor/ZoomFactor
|
||||
'app.zoom_factor': unknown | null
|
||||
// redux/settings/codeCollapsible
|
||||
'chat.code.collapsible': boolean
|
||||
// redux/settings/codeEditor.autocompletion
|
||||
'chat.code.editor.autocompletion': boolean
|
||||
// redux/settings/codeEditor.foldGutter
|
||||
'chat.code.editor.fold_gutter': boolean
|
||||
// redux/settings/codeEditor.enabled
|
||||
'chat.code.editor.highlight_active_line': boolean
|
||||
// redux/settings/codeEditor.keymap
|
||||
'chat.code.editor.keymap': boolean
|
||||
// redux/settings/codeEditor.themeDark
|
||||
'chat.code.editor.theme_dark': string
|
||||
// redux/settings/codeEditor.themeLight
|
||||
'chat.code.editor.theme_light': string
|
||||
// redux/settings/codeExecution.enabled
|
||||
'chat.code.execution.enabled': boolean
|
||||
// redux/settings/codeExecution.timeoutMinutes
|
||||
'chat.code.execution.timeout_minutes': number
|
||||
// redux/settings/codeImageTools
|
||||
'chat.code.image_tools': boolean
|
||||
// redux/settings/codePreview.themeDark
|
||||
'chat.code.preview.theme_dark': string
|
||||
// redux/settings/codePreview.themeLight
|
||||
'chat.code.preview.theme_light': string
|
||||
// redux/settings/codeShowLineNumbers
|
||||
'chat.code.show_line_numbers': boolean
|
||||
// redux/settings/codeViewer.themeDark
|
||||
'chat.code.viewer.theme_dark': string
|
||||
// redux/settings/codeViewer.themeLight
|
||||
'chat.code.viewer.theme_light': string
|
||||
// redux/settings/codeWrappable
|
||||
'chat.code.wrappable': boolean
|
||||
// redux/settings/enableBackspaceDeleteModel
|
||||
'chat.input.backspace_delete_model': boolean
|
||||
// redux/settings/pasteLongTextAsFile
|
||||
'chat.input.paste_long_text_as_file': boolean
|
||||
// redux/settings/pasteLongTextThreshold
|
||||
'chat.input.paste_long_text_threshold': number
|
||||
// redux/settings/enableQuickPanelTriggers
|
||||
'chat.input.quick_panel.triggers_enabled': boolean
|
||||
// redux/settings/sendMessageShortcut
|
||||
'chat.input.send_message_shortcut': string
|
||||
// redux/settings/showInputEstimatedTokens
|
||||
'chat.input.show_estimated_tokens': boolean
|
||||
// redux/settings/autoTranslateWithSpace
|
||||
'chat.input.translate.auto_translate_with_space': boolean
|
||||
// redux/settings/showTranslateConfirm
|
||||
'chat.input.translate.show_confirm': boolean
|
||||
// redux/settings/messageFont
|
||||
'chat.message.font': string
|
||||
// redux/settings/fontSize
|
||||
'chat.message.font_size': number
|
||||
// redux/settings/mathEngine
|
||||
'chat.message.math_engine': string
|
||||
// redux/settings/foldDisplayMode
|
||||
'chat.message.multi_model.fold_display_mode': string
|
||||
// redux/settings/gridColumns
|
||||
'chat.message.multi_model.grid_columns': number
|
||||
// redux/settings/gridPopoverTrigger
|
||||
'chat.message.multi_model.grid_popover_trigger': string
|
||||
// redux/settings/multiModelMessageStyle
|
||||
'chat.message.multi_model.style': string
|
||||
// redux/settings/messageNavigation
|
||||
'chat.message.navigation_mode': string
|
||||
// redux/settings/showMessageDivider
|
||||
'chat.message.show_divider': boolean
|
||||
// redux/settings/showPrompt
|
||||
'chat.message.show_prompt': boolean
|
||||
// redux/settings/showTokens
|
||||
'chat.message.show_tokens': boolean
|
||||
// redux/settings/messageStyle
|
||||
'chat.message.style': string
|
||||
// redux/settings/thoughtAutoCollapse
|
||||
'chat.message.thought.auto_collapse': boolean
|
||||
// redux/settings/narrowMode
|
||||
'chat.narrow_mode': boolean
|
||||
// redux/settings/skipBackupFile
|
||||
'data.backup.general.skip_backup_file': boolean
|
||||
// redux/settings/localBackupAutoSync
|
||||
'data.backup.local.auto_sync': boolean
|
||||
// redux/settings/localBackupDir
|
||||
'data.backup.local.dir': string
|
||||
// redux/settings/localBackupMaxBackups
|
||||
'data.backup.local.max_backups': number
|
||||
// redux/settings/localBackupSkipBackupFile
|
||||
'data.backup.local.skip_backup_file': boolean
|
||||
// redux/settings/localBackupSyncInterval
|
||||
'data.backup.local.sync_interval': number
|
||||
// redux/nutstore/nutstoreAutoSync
|
||||
'data.backup.nutstore.auto_sync': boolean | null
|
||||
// redux/nutstore/nutstorePath
|
||||
'data.backup.nutstore.path': string | null
|
||||
// redux/nutstore/nutstoreSkipBackupFile
|
||||
'data.backup.nutstore.skip_backup_file': boolean | null
|
||||
// redux/nutstore/nutstoreSyncInterval
|
||||
'data.backup.nutstore.sync_interval': number | null
|
||||
// redux/nutstore/nutstoreSyncState
|
||||
'data.backup.nutstore.sync_state': Record<string, unknown> | null
|
||||
// redux/nutstore/nutstoreToken
|
||||
'data.backup.nutstore.token': string | null
|
||||
// redux/settings/s3.accessKeyId
|
||||
'data.backup.s3.access_key_id': string
|
||||
// redux/settings/s3.autoSync
|
||||
'data.backup.s3.auto_sync': boolean
|
||||
// redux/settings/s3.bucket
|
||||
'data.backup.s3.bucket': string
|
||||
// redux/settings/s3.endpoint
|
||||
'data.backup.s3.endpoint': string
|
||||
// redux/settings/s3.maxBackups
|
||||
'data.backup.s3.max_backups': number
|
||||
// redux/settings/s3.region
|
||||
'data.backup.s3.region': string
|
||||
// redux/settings/s3.root
|
||||
'data.backup.s3.root': string
|
||||
// redux/settings/s3.secretAccessKey
|
||||
'data.backup.s3.secret_access_key': string
|
||||
// redux/settings/s3.skipBackupFile
|
||||
'data.backup.s3.skip_backup_file': boolean
|
||||
// redux/settings/s3.syncInterval
|
||||
'data.backup.s3.sync_interval': number
|
||||
// redux/settings/webdavAutoSync
|
||||
'data.backup.webdav.auto_sync': boolean
|
||||
// redux/settings/webdavDisableStream
|
||||
'data.backup.webdav.disable_stream': boolean
|
||||
// redux/settings/webdavHost
|
||||
'data.backup.webdav.host': string
|
||||
// redux/settings/webdavMaxBackups
|
||||
'data.backup.webdav.max_backups': number
|
||||
// redux/settings/webdavPass
|
||||
'data.backup.webdav.pass': string
|
||||
// redux/settings/webdavPath
|
||||
'data.backup.webdav.path': string
|
||||
// redux/settings/webdavSkipBackupFile
|
||||
'data.backup.webdav.skip_backup_file': boolean
|
||||
// redux/settings/webdavSyncInterval
|
||||
'data.backup.webdav.sync_interval': number
|
||||
// redux/settings/webdavUser
|
||||
'data.backup.webdav.user': string
|
||||
// redux/settings/excludeCitationsInExport
|
||||
'data.export.markdown.exclude_citations': boolean
|
||||
// redux/settings/forceDollarMathInMarkdown
|
||||
'data.export.markdown.force_dollar_math': boolean
|
||||
// redux/settings/markdownExportPath
|
||||
'data.export.markdown.path': string | null
|
||||
// redux/settings/showModelNameInMarkdown
|
||||
'data.export.markdown.show_model_name': boolean
|
||||
// redux/settings/showModelProviderInMarkdown
|
||||
'data.export.markdown.show_model_provider': boolean
|
||||
// redux/settings/standardizeCitationsInExport
|
||||
'data.export.markdown.standardize_citations': boolean
|
||||
// redux/settings/useTopicNamingForMessageTitle
|
||||
'data.export.markdown.use_topic_naming_for_message_title': boolean
|
||||
// redux/settings/exportMenuOptions.docx
|
||||
'data.export.menus.docx': boolean
|
||||
// redux/settings/exportMenuOptions.image
|
||||
'data.export.menus.image': boolean
|
||||
// redux/settings/exportMenuOptions.joplin
|
||||
'data.export.menus.joplin': boolean
|
||||
// redux/settings/exportMenuOptions.markdown
|
||||
'data.export.menus.markdown': boolean
|
||||
// redux/settings/exportMenuOptions.markdown_reason
|
||||
'data.export.menus.markdown_reason': boolean
|
||||
// redux/settings/exportMenuOptions.notion
|
||||
'data.export.menus.notion': boolean
|
||||
// redux/settings/exportMenuOptions.obsidian
|
||||
'data.export.menus.obsidian': boolean
|
||||
// redux/settings/exportMenuOptions.plain_text
|
||||
'data.export.menus.plain_text': boolean
|
||||
// redux/settings/exportMenuOptions.siyuan
|
||||
'data.export.menus.siyuan': boolean
|
||||
// redux/settings/exportMenuOptions.yuque
|
||||
'data.export.menus.yuque': boolean
|
||||
// redux/settings/joplinExportReasoning
|
||||
'data.integration.joplin.export_reasoning': boolean
|
||||
// redux/settings/joplinToken
|
||||
'data.integration.joplin.token': string
|
||||
// redux/settings/joplinUrl
|
||||
'data.integration.joplin.url': string
|
||||
// redux/settings/notionApiKey
|
||||
'data.integration.notion.api_key': string
|
||||
// redux/settings/notionDatabaseID
|
||||
'data.integration.notion.database_id': string
|
||||
// redux/settings/notionExportReasoning
|
||||
'data.integration.notion.export_reasoning': boolean
|
||||
// redux/settings/notionPageNameKey
|
||||
'data.integration.notion.page_name_key': string
|
||||
// redux/settings/defaultObsidianVault
|
||||
'data.integration.obsidian.default_vault': string | null
|
||||
// redux/settings/siyuanApiUrl
|
||||
'data.integration.siyuan.api_url': string | null
|
||||
// redux/settings/siyuanBoxId
|
||||
'data.integration.siyuan.box_id': string | null
|
||||
// redux/settings/siyuanRootPath
|
||||
'data.integration.siyuan.root_path': string | null
|
||||
// redux/settings/siyuanToken
|
||||
'data.integration.siyuan.token': string | null
|
||||
// redux/settings/yuqueRepoId
|
||||
'data.integration.yuque.repo_id': string
|
||||
// redux/settings/yuqueToken
|
||||
'data.integration.yuque.token': string
|
||||
// redux/settings/yuqueUrl
|
||||
'data.integration.yuque.url': string
|
||||
// redux/settings/apiServer.apiKey
|
||||
'feature.csaas.api_key': string
|
||||
// redux/settings/apiServer.enabled
|
||||
'feature.csaas.enabled': boolean
|
||||
// redux/settings/apiServer.host
|
||||
'feature.csaas.host': string
|
||||
// redux/settings/apiServer.port
|
||||
'feature.csaas.port': number
|
||||
// redux/settings/maxKeepAliveMinapps
|
||||
'feature.minapp.max_keep_alive': number
|
||||
// redux/settings/minappsOpenLinkExternal
|
||||
'feature.minapp.open_link_external': boolean
|
||||
// redux/settings/showOpenedMinappsInSidebar
|
||||
'feature.minapp.show_opened_in_sidebar': boolean
|
||||
// redux/settings/clickTrayToShowQuickAssistant
|
||||
'feature.quick_assistant.click_tray_to_show': boolean
|
||||
// redux/settings/enableQuickAssistant
|
||||
'feature.quick_assistant.enabled': boolean
|
||||
// redux/settings/readClipboardAtStartup
|
||||
'feature.quick_assistant.read_clipboard_at_startup': boolean
|
||||
// redux/selectionStore/actionItems
|
||||
'feature.selection.action_items': unknown[]
|
||||
// redux/selectionStore/actionWindowOpacity
|
||||
'feature.selection.action_window_opacity': number
|
||||
// redux/selectionStore/selectionEnabled
|
||||
'feature.selection.enabled': boolean
|
||||
// redux/selectionStore/filterList
|
||||
'feature.selection.filter_list': unknown[]
|
||||
// redux/selectionStore/filterMode
|
||||
'feature.selection.filter_mode': string
|
||||
// electronStore/SelectionAssistantFollowToolbar/SelectionAssistantFollowToolbar
|
||||
'feature.selection.follow_toolbar': unknown | null
|
||||
// redux/selectionStore/isAutoClose
|
||||
'feature.selection.is_auto_close': boolean
|
||||
// redux/selectionStore/isAutoPin
|
||||
'feature.selection.is_auto_pin': boolean
|
||||
// redux/selectionStore/isCompact
|
||||
'feature.selection.is_compact': boolean
|
||||
// redux/selectionStore/isFollowToolbar
|
||||
'feature.selection.is_follow_toolbar': boolean
|
||||
// redux/selectionStore/isRemeberWinSize
|
||||
'feature.selection.is_remeber_win_size': boolean
|
||||
// electronStore/SelectionAssistantRemeberWinSize/SelectionAssistantRemeberWinSize
|
||||
'feature.selection.remember_win_size': unknown | null
|
||||
// redux/selectionStore/triggerMode
|
||||
'feature.selection.trigger_mode': string
|
||||
// redux/settings/enableTopicNaming
|
||||
'topic.naming.enabled': boolean
|
||||
// redux/settings/topicNamingPrompt
|
||||
'topic.naming.prompt': string
|
||||
// redux/settings/pinTopicsToTop
|
||||
'topic.pin_to_top': boolean
|
||||
// redux/settings/topicPosition
|
||||
'topic.position': string
|
||||
// redux/settings/showTopicTime
|
||||
'topic.show_time': boolean
|
||||
// redux/settings/assistantIconType
|
||||
'ui.assistant_icon_type': string
|
||||
// redux/settings/clickAssistantToShowTopic
|
||||
'ui.click_assistant_to_show_topic': boolean
|
||||
// redux/settings/customCss
|
||||
'ui.custom_css': string
|
||||
// redux/settings/navbarPosition
|
||||
'ui.navbar.position': string
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint sort-keys: ["error", "asc", {"caseSensitive": true, "natural": false}] */
|
||||
export const defaultPreferences: PreferencesType = {
|
||||
default: {
|
||||
'app.test5': {
|
||||
content1: 'test5-1',
|
||||
content2: 2
|
||||
},
|
||||
'sys.a.test3': true,
|
||||
'sys.a.test4': ['test4-1', 'test4-2'],
|
||||
'ui.a.test1': 'test1',
|
||||
'ui.b.test2': 1
|
||||
'app.developer_mode.enabled': false,
|
||||
'app.disable_hardware_acceleration': false,
|
||||
'app.dist.auto_update.enabled': true,
|
||||
'app.dist.test_plan.channel': 'UpgradeChannel.LATEST',
|
||||
'app.dist.test_plan.enabled': false,
|
||||
'app.language': null,
|
||||
'app.launch_on_boot': false,
|
||||
'app.notification.assistant.enabled': false,
|
||||
'app.notification.backup.enabled': false,
|
||||
'app.notification.knowledge.enabled': false,
|
||||
'app.privacy.data_collection.enabled': false,
|
||||
'app.proxy.bypass_rules': null,
|
||||
'app.proxy.mode': 'system',
|
||||
'app.proxy.url': null,
|
||||
'app.spell_check.enabled': false,
|
||||
'app.spell_check.languages': [],
|
||||
'app.theme.mode': 'ThemeMode.system',
|
||||
'app.theme.user_defined': { colorPrimary: '#00b96b' },
|
||||
'app.theme.window_style': 'opaque',
|
||||
'app.tray.enabled': true,
|
||||
'app.tray.on_close': true,
|
||||
'app.tray.on_launch': false,
|
||||
'app.user.id': 'uuid()',
|
||||
'app.user.name': '',
|
||||
'app.zoom_factor': null,
|
||||
'chat.code.collapsible': false,
|
||||
'chat.code.editor.autocompletion': true,
|
||||
'chat.code.editor.fold_gutter': false,
|
||||
'chat.code.editor.highlight_active_line': false,
|
||||
'chat.code.editor.keymap': false,
|
||||
'chat.code.editor.theme_dark': 'auto',
|
||||
'chat.code.editor.theme_light': 'auto',
|
||||
'chat.code.execution.enabled': false,
|
||||
'chat.code.execution.timeout_minutes': 1,
|
||||
'chat.code.image_tools': false,
|
||||
'chat.code.preview.theme_dark': 'auto',
|
||||
'chat.code.preview.theme_light': 'auto',
|
||||
'chat.code.show_line_numbers': false,
|
||||
'chat.code.viewer.theme_dark': 'auto',
|
||||
'chat.code.viewer.theme_light': 'auto',
|
||||
'chat.code.wrappable': false,
|
||||
'chat.input.backspace_delete_model': true,
|
||||
'chat.input.paste_long_text_as_file': false,
|
||||
'chat.input.paste_long_text_threshold': 1500,
|
||||
'chat.input.quick_panel.triggers_enabled': false,
|
||||
'chat.input.send_message_shortcut': 'Enter',
|
||||
'chat.input.show_estimated_tokens': false,
|
||||
'chat.input.translate.auto_translate_with_space': false,
|
||||
'chat.input.translate.show_confirm': true,
|
||||
'chat.message.font': 'system',
|
||||
'chat.message.font_size': 14,
|
||||
'chat.message.math_engine': 'KaTeX',
|
||||
'chat.message.multi_model.fold_display_mode': 'expanded',
|
||||
'chat.message.multi_model.grid_columns': 2,
|
||||
'chat.message.multi_model.grid_popover_trigger': 'click',
|
||||
'chat.message.multi_model.style': 'horizontal',
|
||||
'chat.message.navigation_mode': 'none',
|
||||
'chat.message.show_divider': true,
|
||||
'chat.message.show_prompt': true,
|
||||
'chat.message.show_tokens': true,
|
||||
'chat.message.style': 'plain',
|
||||
'chat.message.thought.auto_collapse': true,
|
||||
'chat.narrow_mode': false,
|
||||
'data.backup.general.skip_backup_file': false,
|
||||
'data.backup.local.auto_sync': false,
|
||||
'data.backup.local.dir': '',
|
||||
'data.backup.local.max_backups': 0,
|
||||
'data.backup.local.skip_backup_file': false,
|
||||
'data.backup.local.sync_interval': 0,
|
||||
'data.backup.nutstore.auto_sync': null,
|
||||
'data.backup.nutstore.path': null,
|
||||
'data.backup.nutstore.skip_backup_file': null,
|
||||
'data.backup.nutstore.sync_interval': null,
|
||||
'data.backup.nutstore.sync_state': null,
|
||||
'data.backup.nutstore.token': null,
|
||||
'data.backup.s3.access_key_id': '',
|
||||
'data.backup.s3.auto_sync': false,
|
||||
'data.backup.s3.bucket': '',
|
||||
'data.backup.s3.endpoint': '',
|
||||
'data.backup.s3.max_backups': 0,
|
||||
'data.backup.s3.region': '',
|
||||
'data.backup.s3.root': '',
|
||||
'data.backup.s3.secret_access_key': '',
|
||||
'data.backup.s3.skip_backup_file': false,
|
||||
'data.backup.s3.sync_interval': 0,
|
||||
'data.backup.webdav.auto_sync': false,
|
||||
'data.backup.webdav.disable_stream': false,
|
||||
'data.backup.webdav.host': '',
|
||||
'data.backup.webdav.max_backups': 0,
|
||||
'data.backup.webdav.pass': '',
|
||||
'data.backup.webdav.path': '/cherry-studio',
|
||||
'data.backup.webdav.skip_backup_file': false,
|
||||
'data.backup.webdav.sync_interval': 0,
|
||||
'data.backup.webdav.user': '',
|
||||
'data.export.markdown.exclude_citations': false,
|
||||
'data.export.markdown.force_dollar_math': false,
|
||||
'data.export.markdown.path': null,
|
||||
'data.export.markdown.show_model_name': false,
|
||||
'data.export.markdown.show_model_provider': false,
|
||||
'data.export.markdown.standardize_citations': false,
|
||||
'data.export.markdown.use_topic_naming_for_message_title': false,
|
||||
'data.export.menus.docx': true,
|
||||
'data.export.menus.image': true,
|
||||
'data.export.menus.joplin': true,
|
||||
'data.export.menus.markdown': true,
|
||||
'data.export.menus.markdown_reason': true,
|
||||
'data.export.menus.notion': true,
|
||||
'data.export.menus.obsidian': true,
|
||||
'data.export.menus.plain_text': true,
|
||||
'data.export.menus.siyuan': true,
|
||||
'data.export.menus.yuque': true,
|
||||
'data.integration.joplin.export_reasoning': false,
|
||||
'data.integration.joplin.token': '',
|
||||
'data.integration.joplin.url': '',
|
||||
'data.integration.notion.api_key': '',
|
||||
'data.integration.notion.database_id': '',
|
||||
'data.integration.notion.export_reasoning': false,
|
||||
'data.integration.notion.page_name_key': 'Name',
|
||||
'data.integration.obsidian.default_vault': null,
|
||||
'data.integration.siyuan.api_url': null,
|
||||
'data.integration.siyuan.box_id': null,
|
||||
'data.integration.siyuan.root_path': null,
|
||||
'data.integration.siyuan.token': null,
|
||||
'data.integration.yuque.repo_id': '',
|
||||
'data.integration.yuque.token': '',
|
||||
'data.integration.yuque.url': '',
|
||||
'feature.csaas.api_key': '`cs-sk-${uuid()}`',
|
||||
'feature.csaas.enabled': false,
|
||||
'feature.csaas.host': 'localhost',
|
||||
'feature.csaas.port': 23333,
|
||||
'feature.minapp.max_keep_alive': 3,
|
||||
'feature.minapp.open_link_external': false,
|
||||
'feature.minapp.show_opened_in_sidebar': true,
|
||||
'feature.quick_assistant.click_tray_to_show': false,
|
||||
'feature.quick_assistant.enabled': false,
|
||||
'feature.quick_assistant.read_clipboard_at_startup': true,
|
||||
'feature.selection.action_items': [],
|
||||
'feature.selection.action_window_opacity': 100,
|
||||
'feature.selection.enabled': false,
|
||||
'feature.selection.filter_list': [],
|
||||
'feature.selection.filter_mode': 'default',
|
||||
'feature.selection.follow_toolbar': null,
|
||||
'feature.selection.is_auto_close': false,
|
||||
'feature.selection.is_auto_pin': false,
|
||||
'feature.selection.is_compact': false,
|
||||
'feature.selection.is_follow_toolbar': true,
|
||||
'feature.selection.is_remeber_win_size': false,
|
||||
'feature.selection.remember_win_size': null,
|
||||
'feature.selection.trigger_mode': 'selected',
|
||||
'topic.naming.enabled': true,
|
||||
'topic.naming.prompt': '',
|
||||
'topic.pin_to_top': false,
|
||||
'topic.position': 'left',
|
||||
'topic.show_time': false,
|
||||
'ui.assistant_icon_type': 'emoji',
|
||||
'ui.click_assistant_to_show_topic': true,
|
||||
'ui.custom_css': '',
|
||||
'ui.navbar.position': 'top'
|
||||
}
|
||||
}
|
||||
|
||||
// === AUTO-GENERATED CONTENT END ===
|
||||
|
||||
/**
|
||||
* 生成统计:
|
||||
* - 总配置项: 158
|
||||
* - electronStore项: 4
|
||||
* - redux项: 154
|
||||
* - localStorage项: 0
|
||||
*/
|
||||
|
||||
152
src/main/data/migrate/electronStoreToPreferences.ts
Normal file
152
src/main/data/migrate/electronStoreToPreferences.ts
Normal file
@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Auto-generated ElectronStore to Preferences migration
|
||||
* Generated at: 2025-08-09T07:20:05.910Z
|
||||
*
|
||||
* === AUTO-GENERATED CONTENT START ===
|
||||
*/
|
||||
|
||||
import dbService from '@data/db/DbService'
|
||||
import { loggerService } from '@logger'
|
||||
import { configManager } from '@main/services/ConfigManager'
|
||||
|
||||
import type { MigrationResult } from './index'
|
||||
import { TypeConverter } from './utils/typeConverters'
|
||||
|
||||
const logger = loggerService.withContext('ElectronStoreMigrator')
|
||||
|
||||
// 键映射表
|
||||
const KEY_MAPPINGS = [
|
||||
{
|
||||
originalKey: 'Language',
|
||||
targetKey: 'app.language',
|
||||
sourceCategory: 'Language',
|
||||
type: 'unknown',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
originalKey: 'SelectionAssistantFollowToolbar',
|
||||
targetKey: 'feature.selection.follow_toolbar',
|
||||
sourceCategory: 'SelectionAssistantFollowToolbar',
|
||||
type: 'unknown',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
originalKey: 'SelectionAssistantRemeberWinSize',
|
||||
targetKey: 'feature.selection.remember_win_size',
|
||||
sourceCategory: 'SelectionAssistantRemeberWinSize',
|
||||
type: 'unknown',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
originalKey: 'ZoomFactor',
|
||||
targetKey: 'app.zoom_factor',
|
||||
sourceCategory: 'ZoomFactor',
|
||||
type: 'unknown',
|
||||
defaultValue: null
|
||||
}
|
||||
] as const
|
||||
|
||||
export class ElectronStoreMigrator {
|
||||
private typeConverter: TypeConverter
|
||||
|
||||
constructor() {
|
||||
this.typeConverter = new TypeConverter()
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行ElectronStore到preferences的迁移
|
||||
*/
|
||||
async migrate(): Promise<MigrationResult> {
|
||||
logger.info('开始ElectronStore迁移', { totalItems: KEY_MAPPINGS.length })
|
||||
|
||||
const result: MigrationResult = {
|
||||
success: true,
|
||||
migratedCount: 0,
|
||||
errors: [],
|
||||
source: 'electronStore'
|
||||
}
|
||||
|
||||
for (const mapping of KEY_MAPPINGS) {
|
||||
try {
|
||||
await this.migrateItem(mapping)
|
||||
result.migratedCount++
|
||||
} catch (error) {
|
||||
logger.error('迁移单项失败', { mapping, error })
|
||||
result.errors.push({
|
||||
key: mapping.originalKey,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
})
|
||||
result.success = false
|
||||
}
|
||||
}
|
||||
|
||||
logger.info('ElectronStore迁移完成', result)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 迁移单个配置项
|
||||
*/
|
||||
private async migrateItem(mapping: (typeof KEY_MAPPINGS)[0]): Promise<void> {
|
||||
const { originalKey, targetKey, type, defaultValue } = mapping
|
||||
|
||||
// 从ElectronStore读取原始值
|
||||
const originalValue = configManager.get(originalKey)
|
||||
|
||||
if (originalValue === undefined || originalValue === null) {
|
||||
// 如果原始值不存在,使用默认值
|
||||
if (defaultValue !== null && defaultValue !== undefined) {
|
||||
const convertedValue = this.typeConverter.convert(defaultValue, type)
|
||||
await dbService.setPreference('default', targetKey, convertedValue)
|
||||
logger.debug('使用默认值迁移', { originalKey, targetKey, defaultValue: convertedValue })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 类型转换
|
||||
const convertedValue = this.typeConverter.convert(originalValue, type)
|
||||
|
||||
// 写入preferences表
|
||||
await dbService.setPreference('default', targetKey, convertedValue)
|
||||
|
||||
logger.debug('成功迁移配置项', {
|
||||
originalKey,
|
||||
targetKey,
|
||||
originalValue,
|
||||
convertedValue
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证迁移结果
|
||||
*/
|
||||
async validateMigration(): Promise<boolean> {
|
||||
logger.info('开始验证ElectronStore迁移结果')
|
||||
|
||||
for (const mapping of KEY_MAPPINGS) {
|
||||
const { targetKey } = mapping
|
||||
|
||||
try {
|
||||
const value = await dbService.getPreference('default', targetKey)
|
||||
if (value === null) {
|
||||
logger.error('验证失败:配置项不存在', { targetKey })
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('验证失败:读取配置项错误', { targetKey, error })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
logger.info('ElectronStore迁移验证成功')
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// === AUTO-GENERATED CONTENT END ===
|
||||
|
||||
/**
|
||||
* 迁移统计:
|
||||
* - ElectronStore配置项: 4
|
||||
* - 包含的原始键: Language, SelectionAssistantFollowToolbar, SelectionAssistantRemeberWinSize, ZoomFactor
|
||||
*/
|
||||
132
src/main/data/migrate/index.ts
Normal file
132
src/main/data/migrate/index.ts
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Auto-generated migration index
|
||||
* Generated at: 2025-08-09T07:20:05.909Z
|
||||
*
|
||||
* This file is automatically generated from classification.json
|
||||
* To update this file, modify classification.json and run:
|
||||
* node .claude/data-classify/scripts/generate-migration.js
|
||||
*
|
||||
* === AUTO-GENERATED CONTENT START ===
|
||||
*/
|
||||
|
||||
import { ElectronStoreMigrator } from './electronStoreToPreferences'
|
||||
import { ReduxMigrator } from './reduxToPreferences'
|
||||
import { loggerService } from '@logger'
|
||||
|
||||
const logger = loggerService.withContext('MigrationManager')
|
||||
|
||||
export interface MigrationResult {
|
||||
success: boolean
|
||||
migratedCount: number
|
||||
errors: Array<{
|
||||
key: string
|
||||
error: string
|
||||
}>
|
||||
source: 'electronStore' | 'redux'
|
||||
}
|
||||
|
||||
export interface MigrationSummary {
|
||||
totalItems: number
|
||||
successCount: number
|
||||
errorCount: number
|
||||
electronStore: MigrationResult
|
||||
redux: MigrationResult
|
||||
}
|
||||
|
||||
export class MigrationManager {
|
||||
private electronStoreMigrator: ElectronStoreMigrator
|
||||
private reduxMigrator: ReduxMigrator
|
||||
|
||||
constructor() {
|
||||
this.electronStoreMigrator = new ElectronStoreMigrator()
|
||||
this.reduxMigrator = new ReduxMigrator()
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行完整的preferences迁移
|
||||
* @returns 迁移摘要
|
||||
*/
|
||||
async migrateAllPreferences(): Promise<MigrationSummary> {
|
||||
logger.info('开始完整preferences迁移')
|
||||
|
||||
try {
|
||||
// 并行执行两个迁移器
|
||||
const [electronStoreResult, reduxResult] = await Promise.all([
|
||||
this.electronStoreMigrator.migrate(),
|
||||
this.reduxMigrator.migrate()
|
||||
])
|
||||
|
||||
const summary: MigrationSummary = {
|
||||
totalItems: 158,
|
||||
successCount: electronStoreResult.migratedCount + reduxResult.migratedCount,
|
||||
errorCount: electronStoreResult.errors.length + reduxResult.errors.length,
|
||||
electronStore: electronStoreResult,
|
||||
redux: reduxResult
|
||||
}
|
||||
|
||||
if (summary.errorCount > 0) {
|
||||
logger.warn('迁移完成但有错误', { summary })
|
||||
} else {
|
||||
logger.info('迁移完全成功', { summary })
|
||||
}
|
||||
|
||||
return summary
|
||||
} catch (error) {
|
||||
logger.error('迁移过程中发生致命错误', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证迁移结果
|
||||
* @param summary 迁移摘要
|
||||
* @returns 是否验证成功
|
||||
*/
|
||||
async validateMigration(summary: MigrationSummary): Promise<boolean> {
|
||||
logger.info('开始验证迁移结果')
|
||||
|
||||
// 基本验证:检查成功率
|
||||
const successRate = summary.successCount / summary.totalItems
|
||||
if (successRate < 0.95) { // 要求95%以上成功率
|
||||
logger.error('迁移成功率过低', { successRate, summary })
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证关键配置项是否存在
|
||||
const criticalKeys = [
|
||||
'app.theme.mode',
|
||||
'app.language',
|
||||
'app.user.id',
|
||||
'feature.quick_assistant.enabled',
|
||||
'chat.message.font_size'
|
||||
]
|
||||
|
||||
try {
|
||||
const dbServiceModule = await import('@main/db/DbService')
|
||||
const dbService = dbServiceModule.default
|
||||
|
||||
for (const key of criticalKeys) {
|
||||
const result = await dbService.getPreference('default', key)
|
||||
if (result === null) {
|
||||
logger.error('关键配置项迁移失败', { key })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
logger.info('迁移验证成功')
|
||||
return true
|
||||
} catch (error) {
|
||||
logger.error('验证过程中发生错误', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === AUTO-GENERATED CONTENT END ===
|
||||
|
||||
/**
|
||||
* 生成统计:
|
||||
* - 总迁移项: 158
|
||||
* - ElectronStore项: 4
|
||||
* - Redux项: 154
|
||||
*/
|
||||
1081
src/main/data/migrate/reduxToPreferences.ts
Normal file
1081
src/main/data/migrate/reduxToPreferences.ts
Normal file
File diff suppressed because it is too large
Load Diff
72
src/main/data/migrate/utils/migrationHelpers.ts
Normal file
72
src/main/data/migrate/utils/migrationHelpers.ts
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Migration helper utilities
|
||||
* Generated at: 2025-08-09T07:20:05.912Z
|
||||
*/
|
||||
|
||||
import { loggerService } from '@logger'
|
||||
|
||||
const logger = loggerService.withContext('MigrationHelpers')
|
||||
|
||||
export interface BackupInfo {
|
||||
timestamp: string
|
||||
version: string
|
||||
dataSize: number
|
||||
backupPath: string
|
||||
}
|
||||
|
||||
export class MigrationHelpers {
|
||||
/**
|
||||
* 创建数据备份
|
||||
*/
|
||||
static async createBackup(): Promise<BackupInfo> {
|
||||
logger.info('开始创建数据备份')
|
||||
|
||||
// 实现备份逻辑
|
||||
const timestamp = new Date().toISOString()
|
||||
const backupInfo: BackupInfo = {
|
||||
timestamp,
|
||||
version: process.env.npm_package_version || 'unknown',
|
||||
dataSize: 0,
|
||||
backupPath: ''
|
||||
}
|
||||
|
||||
// TODO: 实现具体的备份逻辑
|
||||
|
||||
logger.info('数据备份完成', backupInfo)
|
||||
return backupInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证备份完整性
|
||||
*/
|
||||
static async validateBackup(backupInfo: BackupInfo): Promise<boolean> {
|
||||
logger.info('验证备份完整性', backupInfo)
|
||||
|
||||
// TODO: 实现备份验证逻辑
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复备份
|
||||
*/
|
||||
static async restoreBackup(backupInfo: BackupInfo): Promise<boolean> {
|
||||
logger.info('开始恢复备份', backupInfo)
|
||||
|
||||
// TODO: 实现备份恢复逻辑
|
||||
|
||||
logger.info('备份恢复完成')
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理临时文件
|
||||
*/
|
||||
static async cleanup(): Promise<void> {
|
||||
logger.info('清理迁移临时文件')
|
||||
|
||||
// TODO: 实现清理逻辑
|
||||
|
||||
logger.info('清理完成')
|
||||
}
|
||||
}
|
||||
125
src/main/data/migrate/utils/typeConverters.ts
Normal file
125
src/main/data/migrate/utils/typeConverters.ts
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Type conversion utilities for migration
|
||||
* Generated at: 2025-08-09T07:20:05.912Z
|
||||
*/
|
||||
|
||||
import { loggerService } from '@logger'
|
||||
|
||||
const logger = loggerService.withContext('TypeConverter')
|
||||
|
||||
export class TypeConverter {
|
||||
/**
|
||||
* 转换值到指定类型
|
||||
*/
|
||||
convert(value: any, targetType: string): any {
|
||||
if (value === null || value === undefined) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
switch (targetType) {
|
||||
case 'boolean':
|
||||
return this.toBoolean(value)
|
||||
|
||||
case 'string':
|
||||
return this.toString(value)
|
||||
|
||||
case 'number':
|
||||
return this.toNumber(value)
|
||||
|
||||
case 'array':
|
||||
case 'unknown[]':
|
||||
return this.toArray(value)
|
||||
|
||||
case 'object':
|
||||
case 'Record<string, unknown>':
|
||||
return this.toObject(value)
|
||||
|
||||
default:
|
||||
// 未知类型,保持原样
|
||||
logger.debug('未知类型,保持原值', { targetType, value })
|
||||
return value
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('类型转换失败', { value, targetType, error })
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
private toBoolean(value: any): boolean {
|
||||
if (typeof value === 'boolean') {
|
||||
return value
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
const lower = value.toLowerCase()
|
||||
return lower === 'true' || lower === '1' || lower === 'yes'
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
return value !== 0
|
||||
}
|
||||
return Boolean(value)
|
||||
}
|
||||
|
||||
private toString(value: any): string {
|
||||
if (typeof value === 'string') {
|
||||
return value
|
||||
}
|
||||
if (typeof value === 'number' || typeof value === 'boolean') {
|
||||
return String(value)
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
return String(value)
|
||||
}
|
||||
|
||||
private toNumber(value: any): number {
|
||||
if (typeof value === 'number') {
|
||||
return value
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
const parsed = parseFloat(value)
|
||||
if (isNaN(parsed)) {
|
||||
logger.warn('字符串无法转换为数字', { value })
|
||||
return 0
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? 1 : 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private toArray(value: any): any[] {
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
return Array.isArray(parsed) ? parsed : [value]
|
||||
} catch {
|
||||
return [value]
|
||||
}
|
||||
}
|
||||
return [value]
|
||||
}
|
||||
|
||||
private toObject(value: any): Record<string, any> {
|
||||
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
||||
return value
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
|
||||
? parsed
|
||||
: { value }
|
||||
} catch {
|
||||
return { value }
|
||||
}
|
||||
}
|
||||
return { value }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user