Compare commits

...

99 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
4269a32cfb fix: Include notes directory in backup when configured outside Data folder
- Parse notes path from backup data during backup process
- If notes are outside {userData}/Data, backup them separately to Notes folder
- On restore, restore Notes folder to configured location
- Handles both default and custom notes paths correctly

This ensures users don't lose their notes when using custom paths.

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>
2025-11-12 10:54:27 +00:00
copilot-swe-agent[bot]
6493f1853d refactor: Store default notes path as relative for portability
- Changed getNotesDir() to return './Data/Notes' instead of absolute path
- Added getNotesDirAbsolute() for cases requiring absolute paths
- Updated FileStorage to use getNotesDirAbsolute()
- Added tests for both functions

This allows the default notes path to be portable across devices
while externally selected paths remain absolute.

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>
2025-11-12 09:20:09 +00:00
copilot-swe-agent[bot]
cbd4f418f6 test: Add tests for expandNotesPath function
- Added comprehensive test cases for tilde expansion
- Added tests for relative path expansion
- Added tests for absolute path handling
- Added tests for edge cases and custom base paths

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>
2025-11-12 09:03:09 +00:00
copilot-swe-agent[bot]
7d6ffe472c feat: Add support for relative paths in notes working directory
- Added expandNotesPath utility function to handle ~, ., and .. paths
- Updated validateNotesDirectory to expand relative paths
- Updated getDirectoryStructure to expand paths before scanning
- Updated startFileWatcher to expand paths before watching
- Made notes path input field editable in settings UI
- Updated locale files to explain relative path support

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>
2025-11-12 09:01:28 +00:00
copilot-swe-agent[bot]
f16b63bd69 Initial plan 2025-11-12 08:53:30 +00:00
Xiang, Haihao
2552d97ea7 fix: ensure the user can select any image in NewApiPage (#11238)
NewApiPage always show the first image in filteredPaintings. As a
result, the user is unable to select other images. This issue was
introduced in commit 0502ff4.
2025-11-12 13:30:23 +08:00
Phantom
803f4b5a64 fix(migrate): use provider apiHost for new-api (#11244)
fix(migrate): use provider apiHost for new-api case instead of hardcoded value
2025-11-12 10:05:21 +08:00
beyondkmp
31f8fff6e2 chore: update claude code plugins (#11237)
* chore: update claude code plugins

* update version

---------

Co-authored-by: Payne Fu <payne@Paynes-MacBook-Pro.local>
2025-11-11 19:19:30 +08:00
SuYao
2663cb19ce Chore/aisdk (#11232)
* chore(dependencies): update AI SDK dependencies to latest versions

* chore(patches): update AI SDK patches for Hugging Face, OpenAI, and Google
2025-11-11 00:09:26 +08:00
Pleasure1234
ce5d46bfc7 fix: remove explicit Content-Type header in file upload (#11231)
The Content-Type header was removed from the fetch request when uploading files. This change may allow the server to infer the correct content type or handle uploads more flexibly.
2025-11-10 23:28:38 +08:00
kangfenmao
c1fa24522d chore(release): update release notes for v1.7.0-beta.5
- Add MCPRouter provider and MCP marketplace features
- Improve UI optimization and MCP OAuth callback
- Fix various bugs including Agent allowed_tools inheritance
2025-11-10 20:19:40 +08:00
亢奋猫
2f66f5b511 refactor(AssistantPresetsPage): added assistants subscribe settings to AssistantPresetsPage (#11184)
refactor(DataSettings, MCPSettings, AssistantPresetsPage): clean up imports and enhance UI components

- Removed unused imports and components from DataSettings for better clarity.
- Updated MCPSettings layout by introducing a new Container styled with Scrollbar for improved scrolling.
- Added AssistantsSubscribeUrlSettings component to manage subscription URLs in AssistantPresetsPage, enhancing user interaction.
- Adjusted button styles and layout in AssistantPresetsPage for a more cohesive design.
2025-11-10 20:10:38 +08:00
亢奋猫
2d8555c326 fix(agents): inherit allowed_tools from Agent when creating Session (#11201)
When creating a Session under an Agent, the Session should inherit the Agent's allowed_tools configuration. Previously, the allowed_tools parameter was missing from the Session creation API call, causing inconsistency between Agent and Session configurations.

Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-10 18:44:33 +08:00
Konjac-XZ
e2c8edab61 fix: incorrect spelling caused Gemini endpoint’s thinking budget to fail (#11217) 2025-11-10 16:42:34 +08:00
kangfenmao
5e0a66fa1f docs(README): update AI Web Service Integration section and remove public beta notice
- Added a hyperlink to Poe in the AI Web Service Integration list for better accessibility.
- Removed the public beta notice for the Enterprise Edition to streamline the documentation.
- Updated the cost section to include a link to the AGPL-3.0 License for clarity.
2025-11-10 15:44:29 +08:00
亢奋猫
bc8b0a8d53 feat(agent): add permission mode display component for empty session state (#11204)
Replace empty state text with a visual permission mode display card that shows:
- Permission mode icon with unique colors for each mode (default, plan, acceptEdits, bypassPermissions)
- Permission mode title and description
- Clickable to navigate directly to tooling settings tab

Replace loading text with Ant Design Spin component for better UX.
2025-11-10 11:26:36 +08:00
fullex
e43562423e refactor: remove unused files and configurations (#11176)
* ♻️ refactor: remove unused resources/js directory and references

Remove legacy resources/js directory (bridge.js and utils.js) that was left over after minapp.html removal in commit 461458e5e. Also update .oxlintrc.json to remove the unused resources/js/** file pattern.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* ♻️ refactor: remove additional unused files

- Remove duplicate ipService.js (superseded by TypeScript version in src/main/utils/)
- Remove unused components.json (shadcn config with non-existent target directory)
- Remove unused context-menu.tsx component (no imports found)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-10 11:14:32 +08:00
亢奋猫
120ac122eb fix(ui): resolve sidebar tooltip overlap with window controls on macOS (#11216)
Fixes #11125

Add placement="right" to sidebar toggle tooltips in ChatNavbar, Navbar,
and Notes HeaderNavbar to prevent tooltips from overlapping with macOS
window control buttons (minimize, maximize, close) in the top-left corner.

This ensures tooltips appear to the right of the toggle buttons rather
than above them, avoiding overlap with native window controls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 23:24:35 +08:00
Phantom
9013fcba14 fix(useMessageOperations): skip timestamp update for UI-only changes (#10927)
Prevent unnecessary message updates when only UI-related states change by checking the update keys and skipping timestamp updates in those cases
2025-11-09 18:17:34 +08:00
Phantom
c32f4badbd fix(ErrorBlock): reorder field (#11057)
feat(ErrorBlock): add responseBody display above requestBodyValues

Move responseBody display to appear before requestBodyValues for better error flow readability
2025-11-09 17:53:05 +08:00
亢奋猫
66f66fe08e fix: prevent MCP card description text from overflowing dialog width (#11203)
* fix: prevent MCP card description text from overflowing dialog width

Add whitespace-pre-wrap and break-all classes to the MCP server description
text in Agent Settings to ensure long descriptions wrap properly within the
dialog bounds instead of causing layout overflow issues.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: display MCP server logo in Agent Settings tooling section

Add logo display support for MCP servers in the Agent Settings tooling
section. When a server has a logoUrl defined, it will now be shown next
to the server name as a 20x20px rounded image, matching the design
pattern used in MCPSettings.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 17:50:41 +08:00
亢奋猫
d5826c2dc7 fix(ui): truncate long Bash command in tag with popover (#11200)
* 🐛 fix(ui): truncate long Bash command in tag with popover

Add automatic truncation for Bash commands exceeding 200 characters in the tag display. When truncated, users can hover over the tag to view the full command in a popover.

- Add MAX_TAG_LENGTH constant (200 chars)
- Implement command truncation logic
- Add Popover component for full command display on hover
- Prevent UI overflow issues with long commands

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* ♻️ refactor(ui): reduce MAX_TAG_LENGTH to 100 for smaller screens

Reduce the command truncation threshold from 200 to 100 characters to better support smaller screen sizes and improve readability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: remove emoji requirement from conventional commits

Update commit message guidelines to use standard Conventional Commit format without emoji prefixes for better compatibility and consistency.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 12:27:15 +08:00
亢奋猫
85a628f8dd style(ui): center plugin browser tabs (#11205)
💄 style(ui): center plugin browser tabs

Center the tab items in the plugin browser component for better visual alignment and improved user experience.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 12:06:50 +08:00
cheng chao
ed453750fe fix(mcp): resolve OAuth callback page hanging and add i18n support (#11195)
- Fix OAuth callback server not sending HTTP response, causing browser to hang
- Add internationalization support for OAuth callback page (10 languages)
- Simplify callback page design with clean white background
- Improve user experience with localized success messages

Changes:
- src/main/services/mcp/oauth/callback.ts: Add HTTP response to OAuth callback
- src/renderer/src/i18n/: Add callback page translations for all supported languages

Signed-off-by: charles <kidccc@gmail.com>
2025-11-09 01:45:25 +08:00
亢奋猫
57d9a31c0f refactor(migrate): consolidate migrations into version 172 (#11194)
* refactor(migrate): consolidate migrations into version 172

Consolidates migrations 162-166 into a single migration 172 to fix data
inconsistencies between release/v1.6.x and v1.7.0-x versions. This
ensures a single, consistent migration path and corrects data deviations
that occurred during version upgrades.

Changes:
- Remove separate migrations 162-166
- Add consolidated migration 172 that includes:
  - Mini app additions (ling, huggingchat)
  - OCR provider updates (ovocr)
  - Agent to preset migration
  - Sidebar icon updates (agents -> store)
  - LLM provider Anthropic API host configurations
  - Assistant preset settings initialization

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(store): update persist version to 172

Update the redux-persist version number from 171 to 172 to match the
consolidated migration version.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(migrate): add missing break statement in switch case

Add missing break statement after 'grok' case to prevent fall-through
to 'cherryin' case. Also add break statement for 'longcat' case.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 00:31:35 +08:00
亢奋猫
58afbe8a79 refactor(config): optimize oxlint configuration by removing redundant default rules (#11192)
Remove ~60 redundant rule declarations that match oxlint's default behavior.
This reduces the config file by 28% (211 -> 152 lines) while maintaining
identical linting behavior.

Changes:
- Remove default error-level rules (constructor-super, no-debugger, etc.)
- Retain only custom configurations that differ from defaults
- Keep all environment overrides and plugin settings unchanged
- Preserve all modified severity levels (warn) and disabled rules (off)

Benefits:
- Improved readability: clearly shows project-specific lint strategy
- Reduced maintenance: no need to sync with oxlint default updates
- Smaller config: 46% fewer rule declarations (130 -> 70 rules)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 00:31:20 +08:00
亢奋猫
9a10516b52 chore: update bun and uv versions (#11193)
* chore: update bun and uv versions

- Update bun from 1.2.17 to 1.3.1
- Update uv from 0.7.13 to 0.9.5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: update UV installer to support tar.gz format

- Update UV package mappings from .zip to .tar.gz for macOS and Linux
- Add RISCV64 Linux platform support
- Implement dual extraction logic:
  - tar.gz extraction for macOS/Linux using tar command
  - zip extraction for Windows using StreamZip
- Flatten directory structure during extraction
- Maintain executable permissions on Unix-like systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* 🐛 fix: correct error handling in UV installer

Remove ineffective error code 102 return from nested function.
Chmod errors now properly propagate to outer try-catch block.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-09 00:31:00 +08:00
Phantom
e268e69597 refactor(config): centralize home directory constant to shared config (#11158)
Replace hardcoded '.cherrystudio' directory references with HOME_CHERRY_DIR constant
2025-11-07 22:24:05 +08:00
kangfenmao
10e78ac60e refactor(MCPSettings): update styled components and enhance server synchronization
- Changed RightContainer from Scrollbar to a standard div for layout adjustments.
- Updated DetailContainer to use Scrollbar for improved scrolling behavior.
- Modified server synchronization logic across multiple providers to include allServers in the results, enhancing server management capabilities.
- Refactored provider configurations to ensure consistency and support for new server data structure.
2025-11-07 19:22:58 +08:00
kangfenmao
44b2b859da feat(MCPRouter): add MCPRouter provider support and integration
- Introduced MCPRouter provider with token management and server synchronization functionalities.
- Added MCPRouter logo to settings page for visual representation.
- Updated provider configuration to include MCPRouter details and API interactions.
- Implemented functions for saving, retrieving, and clearing MCPRouter tokens, along with server synchronization logic.
2025-11-07 18:41:15 +08:00
kangfenmao
bfef0c5580 feat(MCPSettings): enhance MCP server management and localization support
- Updated auto-translation script to allow configurable max concurrent translations and delay via environment variables.
- Added new translations for "discover", "fetch", "marketplaces", "providers", and "servers" across multiple locales (en-us, zh-cn, zh-tw, de-de, el-gr, es-es, fr-fr, ja-jp, pt-pt, ru-ru).
- Improved MCPSettings UI by adjusting layout and adding a new provider settings component for better server management.
- Refactored MCP server list and market list components for improved usability and styling consistency.
2025-11-07 18:01:55 +08:00
fullex
1e8055031a Merge branch 'main' of github.com:CherryHQ/cherry-studio 2025-11-07 12:02:35 +08:00
fullex
8e33ff8d90 docs: update test plan documentation to clarify upgrade behavior for RC and Beta channels 2025-11-07 12:02:28 +08:00
kangfenmao
a619000340 chore: update v1.7.0-beta.4 release notes
Update electron-builder.yml with release notes covering:
- UI framework upgrade with improved performance and UX
- New features: AWS Bedrock API key support, SophNet provider, auto session rename, TopP parameter, and reasoning effort control
- Improvements to UI components, quick panel, painting models, system shutdown handling, and package size optimization
- Bug fixes for provider support, i18n translations, and API issues
2025-11-06 20:51:03 +08:00
kangfenmao
78278ce96d refactor: remove heroui
commit 7c8bf8b591
Author: defi-failure <159208748+defi-failure@users.noreply.github.com>
Date:   Thu Nov 6 17:59:38 2025 +0800

    fix: add token usage to agent session message

commit ff8e5ddd27
Author: defi-failure <159208748+defi-failure@users.noreply.github.com>
Date:   Thu Nov 6 17:25:54 2025 +0800

    fix: close prompt stream when finish or error chunk received

commit 530e6516fd
Author: defi-failure <159208748+defi-failure@users.noreply.github.com>
Date:   Thu Nov 6 17:19:53 2025 +0800

    chore: code cleanup

commit ab21c0d56c
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 16:13:36 2025 +0800

    feat(SessionItem): implement auto-rename feature for sessions and improve context menu handling

    - Added a new context menu option to automatically rename sessions based on topics.
    - Introduced useDeferredValue for managing target session state.
    - Updated imports to include necessary thunk actions and components.
    - Enhanced API service to handle optional assistant model in message summary fetching.
    - Exported renameAgentSessionIfNeeded function for better accessibility in the store.

commit 21ea8ccf37
Merge: ab7b207d2 816a92c60
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 15:29:09 2025 +0800

    Merge branch 'main' of github.com:CherryHQ/cherry-studio into refactor/heroui-antd

    # Conflicts:
    #	src/renderer/src/pages/home/Tabs/components/AddButton.tsx
    #	src/renderer/src/pages/home/Tabs/components/SessionItem.tsx
    #	src/renderer/src/pages/home/Tabs/components/Sessions.tsx
    #	src/renderer/src/pages/home/Tabs/components/Topics.tsx
    #	src/renderer/src/pages/paintings/NewApiPage.tsx

commit ab7b207d29
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 14:50:05 2025 +0800

    refactor: streamline event listener management in useAppInit and update ToolPermissionRequestCard styling

commit 3834c5d402
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 14:21:25 2025 +0800

    refactor: enhance API server state management and remove unused initialization in useAppInit

commit a64b94a41f
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 13:21:58 2025 +0800

    refactor: update OpenAPI documentation paths to include subdirectories for better route coverage

commit 2e0ff28505
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 12:26:09 2025 +0800

    refactor: center align columns in InstalledPluginsList and set AntTable size to small

commit 84bf94e2ff
Author: defi-failure <159208748+defi-failure@users.noreply.github.com>
Date:   Thu Nov 6 12:06:09 2025 +0800

    refactor: align create agent model selection with edit agent

commit 84f2281506
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 11:29:32 2025 +0800

    refactor: integrate API server functionality into various components and enhance user notifications

commit 4e01210df4
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 10:56:38 2025 +0800

    refactor: replace ContextMenu with Dropdown in AgentItem and SessionItem components for improved context menu handling

commit 9df38c7e83
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 10:27:30 2025 +0800

    refactor: update AddButton styling to use CSS variable for border radius and remove unused settings hook

commit 251c269ab3
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 10:11:21 2025 +0800

    refactor: remove unused error handling alerts from AssistantsTab component

commit 9b9640d8d1
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 10:07:26 2025 +0800

    refactor: adjust margin styling for UnifiedAddButton component

commit edd6b11aa7
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 10:04:01 2025 +0800

    refactor: update AddButton styling based on topic position and clean up CSS for root element

commit 1c0de625d8
Author: kangfenmao <kangfenmao@qq.com>
Date:   Thu Nov 6 09:56:42 2025 +0800

    fix: update assistant addition messages for multiple languages

commit 0ea4dd4e3a
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 21:01:24 2025 +0800

    fix: init message api err

commit f3bbd4ed44
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 20:42:49 2025 +0800

    refactor: remove heroui

commit d01609fc36
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 19:08:41 2025 +0800

    refactor: migrate heroui/toast to antd message

commit f4b14dfc10
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 18:51:29 2025 +0800

    refactor: enhance Sessions component layout with styled Scrollbar and adjust UnifiedAddButton margins

commit 6ae5f69163
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 18:44:13 2025 +0800

    refactor: update PluginSettings and ToolingSettings for improved layout and functionality

commit fcb0020787
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 18:29:52 2025 +0800

    wip

commit 02265f369e
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 17:26:39 2025 +0800

    fix: error block related

commit 5e22d9d36f
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 17:14:25 2025 +0800

    fix: note head nav related

commit 3f52b7766a
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 16:45:49 2025 +0800

    chore: remove dead code

commit 484622f12b
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 16:43:12 2025 +0800

    chore: remove dead code

commit 2bceb302e0
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 15:33:25 2025 +0800

    fix: tool setting related

commit 5c455f25eb
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 13:59:33 2025 +0800

    chore: remove dead code

commit d1d1dbc046
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 13:51:41 2025 +0800

    fix: tool permission card related

commit bf4ec23ef7
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 12:22:53 2025 +0800

    fix: remove button and modal renaming

commit 47db5baeb1
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 12:20:36 2025 +0800

    fix: plugin setting related

commit 81fecce552
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 12:16:42 2025 +0800

    refactor: enhance ChatNavbarContent structure by replacing Breadcrumbs with custom layout and adding separators

commit fc64b6c611
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 12:10:48 2025 +0800

    refactor: simplify MessageAgentTools component structure by removing unnecessary wrapper div

commit e0f383a050
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 12:08:32 2025 +0800

    fix: update button classes in AddAssistantOrAgentPopup for improved cursor behavior

commit 720284262f
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 12:06:58 2025 +0800

    refactor: update AgentModal to use TopView for improved modal management and enhance form structure

commit b334a2c5be
Author: kangfenmao <kangfenmao@qq.com>
Date:   Wed Nov 5 11:40:47 2025 +0800

    refactor: replace UpdateDialog with UpdateDialogPopup for better modal handling

commit 468aebd632
Author: dev <verc20.dev@proton.me>
Date:   Wed Nov 5 10:56:40 2025 +0800

    fix: plugins related wip

commit bd4a979f62
Author: dev <verc20.dev@proton.me>
Date:   Tue Nov 4 17:46:14 2025 +0800

    fix: add button related

commit b3316a4dc8
Author: dev <verc20.dev@proton.me>
Date:   Tue Nov 4 17:18:31 2025 +0800

    fix: agent tool result related components

commit 6ca7597a98
Author: dev <verc20.dev@proton.me>
Date:   Tue Nov 4 11:12:01 2025 +0800

    fix: lint

commit 7d0f0b38a6
Author: kangfenmao <kangfenmao@qq.com>
Date:   Tue Nov 4 09:56:32 2025 +0800

    wip

commit 96a607a410
Author: kangfenmao <kangfenmao@qq.com>
Date:   Mon Nov 3 20:23:25 2025 +0800

    wip

commit 235ad16252
Author: kangfenmao <kangfenmao@qq.com>
Date:   Mon Nov 3 20:08:45 2025 +0800

    wip

commit f23fe1b9e9
Author: kangfenmao <kangfenmao@qq.com>
Date:   Mon Nov 3 19:15:01 2025 +0800

    wip

commit 28fac543fc
Author: kangfenmao <kangfenmao@qq.com>
Date:   Mon Nov 3 18:39:39 2025 +0800

    wip

commit 3cc7ee01e2
Author: kangfenmao <kangfenmao@qq.com>
Date:   Mon Nov 3 17:33:13 2025 +0800

    wip

commit 37bdf9e508
Author: kangfenmao <kangfenmao@qq.com>
Date:   Sat Nov 1 19:16:58 2025 +0800

    wip

commit 1bf5104f97
Author: kangfenmao <kangfenmao@qq.com>
Date:   Sat Nov 1 12:12:01 2025 +0800

    wip
2025-11-06 18:27:43 +08:00
Phantom
76483d828e ci(i18n): change auto i18n workflow to run weekly (#11152)
* ci(i18n): change auto i18n workflow to run weekly

Update the workflow to run on a weekly schedule instead of on pull request events.
Also simplify the workflow by using yarn for dependency management and create a PR
for changes instead of committing directly to the branch.

* ci(github-actions): improve workflow step names with emojis

Use emojis in step names to enhance readability and visual scanning of workflow logs

* ci(workflow): prevent committing package.json and yarn.lock changes in i18n workflow
2025-11-06 18:25:04 +08:00
Jake Jia
816a92c609 feat(app-menu): add full i18n support and sync lanuage with app language settings (#11131)
Previously, the macOS menu bar was always displayed in English regardless of
system language or in-app language settings. This change enables the menu bar
to dynamically follow the application's language preference.

Key changes:
- Add language change listener to automatically update menu when user switches language
- Refactor AppMenuService with proper subscription management and cleanup
- Add appMenu translations for en-us, zh-cn, and zh-tw locales
- Implement destroy method to prevent memory leaks from config subscriptions
- Convert all menu items (File, Edit, View, Window, Help) to use localized labels

The menu bar now respects the in-app language setting and updates in real-time
when users change their preferences, providing a consistent multilingual experience.
2025-11-06 14:46:42 +08:00
beyondkmp
83e4d4363f fix: add Perplexity provider support and update API host formatting (#11162)
* feat: add Perplexity provider support and update API host formatting

- Introduced `isPerplexityProvider` function to identify Perplexity providers.
- Updated `formatProviderApiHost` to handle Perplexity provider API host formatting.
- Added unit tests for Perplexity provider configuration to ensure correct API host formatting behavior.

* fix: add 'perplexity' to unsupported API version providers list
2025-11-06 10:43:33 +08:00
Phantom
1103449a4f fix: wrong migration in #10727 (#11151) 2025-11-05 14:33:07 +08:00
beyondkmp
56c7a7f066 🐛 fix: resolve TypeScript type conflicts and React hooks warnings (#11148)
* 🐛 fix: resolve TypeScript type conflicts and React hooks warnings

- Add @smithy/types@4.7.1 to resolutions to unify AWS SDK dependencies
- Wrap updatePaintingState in useCallback to fix exhaustive-deps warning
- Fix AWS Bedrock client type incompatibility issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(i18n): Auto update translations for PR #11148

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
2025-11-05 14:19:14 +08:00
Phantom
caa59c4c50 refactor(Topics & Sessions): Style and code structure adjustments (#10868)
* refactor(Tabs): extract shared styled components into separate file

Move common styled components (ListItem, ListItemNameContainer, ListItemName, ListItemEditInput) from SessionItem.tsx and Topics.tsx into shared.tsx to improve code reuse and maintainability

* refactor(components): extract ListContainer component for shared tab layouts

Create reusable ListContainer component to standardize layout styling across tabs
Replace manual div containers in Sessions and Topics components with new ListContainer

* refactor(ListItem): convert styled component to Tailwind CSS function component

- Convert ListItem from styled-components to Tailwind CSS function component
- Maintain all original styling and hover/active states
- Use HTMLDivElement props interface for proper TypeScript typing
- Preserve CSS custom properties for theme variables

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(ListItemNameContainer): convert styled component to Tailwind CSS function component

- Convert ListItemNameContainer from styled-components to Tailwind CSS function component
- Simplify layout styles using Tailwind's utility classes
- Use HTMLDivElement props interface for proper TypeScript typing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(ListItemName): convert styled component to Tailwind CSS function component

- Convert ListItemName from styled-components to Tailwind CSS function component
- Use inline styles for webkit-specific line clamping properties
- Remove complex animations from component definition (can be added via CSS classes)
- Use HTMLDivElement props interface for proper TypeScript typing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(ListItemEditInput): convert styled component to Tailwind CSS function component

- Convert ListItemEditInput from styled-components to Tailwind CSS function component
- Use proper InputHTMLAttributes type for input elements
- Remove styled-components import as no longer needed
- Maintain all original styling using Tailwind utility classes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(components): improve type safety and class ordering in shared components

- Replace HTMLAttributes with more specific ComponentProps types
- Reorder class names for better readability and consistency

* refactor(components): update styling and class handling in list items

- Replace deprecated classNames utility with cn from @heroui/react
- Consolidate style properties into className using cn
- Improve CSS selector syntax for better specificity
- Standardize padding and border radius values

* Revert "refactor(ListItemName): convert styled component to Tailwind CSS function component"

This reverts commit 196136068d.

* style(shared): increase font size and remove redundant padding

The font size was increased from 13px to 14px for better readability. Redundant padding in ListItemEditInput was removed to maintain consistent styling.

* refactor(AddButton): simplify component by removing FC type and inline props

Remove unnecessary FC type declaration and inline the Props interface with ButtonProps. Also clean up prop spreading by moving it to the end of the component.

* style(Topics): remove redundant className and add overflow styles

* refactor(components): extract MenuButton to shared components

Move MenuButton implementation from individual components to shared module to reduce code duplication and improve maintainability

* refactor(PendingIndicator): convert styled component to Tailwind CSS function component

- Convert PendingIndicator from styled-components to Tailwind CSS function component
- Use ComponentPropsWithoutRef<'div'> for consistent TypeScript typing
- Replace styled-components attrs with Tailwind animate-pulse class
- Use CSS custom properties for pulse-size variable
- Remove styled-components import as no longer needed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(components): replace styled indicators with shared StatusIndicator

Consolidate PendingIndicator and FulfilledIndicator into a single StatusIndicator component with variant support

* style(shared.tsx): adjust border styles for singlealone active state

* refactor: use type-only imports for react props

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-05 14:14:40 +08:00
fullex
2546dfbe5d chore: update Node.js version to 22 and Yarn version to 4.9.1 across workflows and documentation 2025-11-05 12:54:30 +08:00
beyondkmp
5fea202a7d fix: add PowerMonitorService for system shutdown handling (#11115)
* feat: add PowerMonitorService for system shutdown handling

- Add PowerMonitorService to monitor system shutdown events
- Use @paymoapp/electron-shutdown-handler for Windows platform
- Use Electron's powerMonitor for macOS and Linux platforms
- Support registering multiple shutdown handlers via dependency injection
- Register shutdown handlers in ipc.ts to disable auto-update and save data

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* format code

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-04 18:56:09 +08:00
fullex
7dce1d776b feat: app's version history log (#11097)
* feat: integrate version tracking in app initialization

- Added versionService to record the current version during app startup.
- This change prepares for upcoming data refactoring in version 2.

* fix: lint from other PRs & format

* feat: enhance version tracking with meaningful change detection

- Updated VersionService to check for changes in version, OS, environment, packaged status, and install mode before recording a new entry.
- Improved logging to reflect whether version information has changed or remained the same.
2025-11-04 14:13:07 +08:00
beyondkmp
346af4d338 fix: add CherryAI provider support and update API host formatting (#11135)
* fix: add CherryAI provider support and update API host formatting

* format code

* add ut

* format code
2025-11-04 12:59:14 +08:00
Zephyr
abd5d3b96f feat: amazon bedrock request use bedrock api key (#10727)
* feat: amazon bedrock request use bedrock api key

* feat: ai-core/provider support bedrock api key

* refactor: extract AWS Bedrock auth type and remove redundant state

* feat: add bedrock reasoning support

Add AWS Bedrock-specific reasoning parameter handling to support Extended Thinking feature for Claude models via Bedrock API.

Changes:
- Add `buildBedrockProviderOptions` function in options.ts to handle Bedrock-specific provider options
- Add `getBedrockReasoningParams` function in reasoning.ts to generate reasoning config with budget tokens
- Register 'bedrock' case in provider options switch to route to Bedrock-specific builder
- Reuse `getAnthropicThinkingBudget` helper for consistent token budget calculation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: add migration for Bedrock auth type and API key fields

* refactor: replace any type with BedrockRuntimeClientConfig in AWS Bedrock client

* fix: bug fix

* fix: lint error

* fix: bedrock reasoning

* chore: bump persisted reducer version to 171

* Update src/renderer/src/store/migrate.ts

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: icarus <eurfelux@gmail.com>
2025-11-03 21:05:10 +08:00
Phantom
49bd298d37 feat(InputbarTools): add reasoning effort button to quick panel (#10959)
Add new menu item with lightbulb icon that opens the reasoning effort quick panel when clicked
2025-11-03 20:36:52 +08:00
Phantom
714a28ac29 fix(QuickPanel): Hide the options that should be hidden in the quick panel. (#10931)
* feat(QuickPanel): add hidden property to list items

Add support for hiding QuickPanel items by introducing a hidden property. This allows conditional visibility of items like the knowledge base button based on application state.

* docs(types): clarify settings field comment in Assistant type
2025-11-03 20:34:24 +08:00
beyondkmp
0cf81c04c8 chore: update electron-builder.yml to exclude additional configuration files from build (#11129)
* chore: update electron-builder.yml to exclude additional configuration files from build

* delete all hide files
2025-11-03 17:54:29 +08:00
kangfenmao
4186e9c990 feat: add support for TopP in model capabilities and update parameter builder to utilize it 2025-11-03 16:37:12 +08:00
kangfenmao
d8f68a6056 feat: initialize painting model with first available option and update default provider to 'cherryin' 2025-11-03 15:12:58 +08:00
kangfenmao
11bf50e722 fix(i18n): improve label retrieval for paintings image size options 2025-11-03 14:45:21 +08:00
kangfenmao
32a84311aa feat: add SophNet LLM provider 2025-11-03 13:28:40 +08:00
beyondkmp
6eaa2b2461 refactor: remove main window dependency from PythonService and utilize WindowService for window management (#11116)
* refactor: remove main window dependency from PythonService and utilize WindowService for window management

* format code
2025-11-03 13:09:40 +08:00
defi-failure
9f00f00546 chore: update v1.7.0-beta.3 release notes (#11105)
* chore: update v1.7.0-beta.3 release notes

* fix(i18n): Auto update translations for PR #11105

* fix: code lint error

---------

Co-authored-by: GitHub Action <action@github.com>
2025-11-02 22:28:36 +08:00
SuYao
bd94d23343 refactor:Unify the naming of configuration fields in thinking, change to using underscore style. (#11106)
* refactor:Unify the naming of configuration fields in thinking, change to using underscore style.

* fix(i18n): Auto update translations for PR #11106

* chore: lint

* fix: typecheck

---------

Co-authored-by: GitHub Action <action@github.com>
2025-11-02 19:24:23 +08:00
chenxue
5f1c14e2c0 fix(aihubmix): fix default rules missing app code (#11100)
* add imagen

* Update aihubmix.ts

* fix type

---------

Co-authored-by: zhaochenxue <zhaochenxue@bixin.cn>
2025-11-02 17:03:05 +08:00
dependabot[bot]
cdc12d5092 ci(deps): bump actions/stale from 9 to 10 (#11088)
Bumps [actions/stale](https://github.com/actions/stale) from 9 to 10.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v9...v10)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '10'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-02 08:44:53 +08:00
dependabot[bot]
e5967fd874 ci(deps): bump actions/upload-artifact from 4 to 5 (#11089)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-02 08:44:41 +08:00
dependabot[bot]
e2f1d80697 ci(deps): bump actions/setup-node from 4 to 6 (#11090)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-02 08:44:28 +08:00
SuYao
28bc89ac7c perf: optimize QR code generation and connection info for phone LAN export (#11086)
* Increase QR code margin for better scanning reliability

- Change QRCodeSVG marginSize from 2 to 4 pixels
- Maintains same QR code size (160px) and error correction level (Q)
- Improves readability and scanning success rate on mobile devices

* Optimize QR code generation and connection info for phone LAN export

- Increase QR code size to 180px and reduce error correction to 'L' for better mobile scanning
- Replace hardcoded logo path with AppLogo config and increase logo size to 60px
- Simplify connection info by removing candidates array and using only essential IP/port data

* Optimize QR code data structure for LAN connection

- Compress IP addresses to numeric format to reduce QR code complexity
- Use compact array format instead of verbose JSON object structure
- Remove debug logging to streamline connection flow

* feat: 更新 WebSocket 状态和候选者响应类型,优化连接信息处理

* Increase QR code size and error correction for better scanning

- Increase QR code size from 180px to 300px for improved readability
- Change error correction level from L (low) to H (high) for better reliability
- Reduce logo size from 60px to 40px to accommodate larger QR data
- Increase margin size from 1 to 2 for better border clearance

* 调整二维码大小和图标尺寸以优化扫描体验

* fix(i18n): Auto update translations for PR #11086

* fix(i18n): Auto update translations for PR #11086

* fix(i18n): Auto update translations for PR #11086

---------

Co-authored-by: GitHub Action <action@github.com>
2025-11-01 12:13:11 +08:00
fullex
dc06c103e0 chore[lint]: add import type lint (#11091)
chore: add import type lint
2025-11-01 10:40:02 +08:00
SuYao
1f0381aebe Fix/azure embedding (#11044)
* fix: update EmbeddingsFactory to use net.fetch and refactor KnowledgeService to use ModernAiProvider

* fix: remove deprecated @langchain/community dependency from package.json

* fix: add @langchain/community dependency to package.json and update yarn.lock
2025-11-01 01:52:16 +08:00
kangfenmao
fb02a61a48 feat: add AddAssistantOrAgentPopup component and update i18n translations
- Introduced a new AddAssistantOrAgentPopup component for selecting between assistant and agent options.
- Updated English, Simplified Chinese, and Traditional Chinese translations to include descriptions and titles for assistant and agent options.
- Refactored UnifiedAddButton to utilize the new popup for adding assistants or agents.
2025-10-31 23:46:51 +08:00
defi-failure
562fbb3ff7 fix: minor ui tweak of plugin installation interface (#11085)
* fix: use dropdown instead of chip filter

* fix: add padding to avoid scroll bar overlap

* fix: set max card grid col to 2

* fix: minor ui tweak for plugin card

* fix: remove redundant args

* fix(i18n): Auto update translations for PR #11085

* fix: cleanup comments

---------

Co-authored-by: GitHub Action <action@github.com>
2025-10-31 22:28:25 +08:00
Pleasure1234
1018ad87b8 fix: cancel debounced save on file path update (#11069)
Adds cancellation of the debounced save when the active file path is updated after moving a file or folder. This prevents saving to the old path and ensures lastFilePathRef is updated accordingly.
2025-10-31 14:17:06 +00:00
kangfenmao
82ca35fc29 chore: update issue template names by removing language specification
- Modified the names of the issue templates for bug reports, feature requests, and other questions to remove the "(English)" suffix, simplifying the titles for better clarity.
2025-10-31 21:29:29 +08:00
kangfenmao
fe53b0914a feat: add enterprise section and remove license from AboutSettings
- Introduced an "Enterprise" section in the i18n files for English, Simplified Chinese, and Traditional Chinese.
- Removed the "License" section from the AboutSettings component, replacing it with a link to the enterprise website.
- Updated icons in the AboutSettings component to reflect the new structure.
2025-10-31 21:28:30 +08:00
defi-failure
67a379641f fix(agent): resolve edit modal loading race condition (#11084)
* fix(agent): resolve edit modal loading race condition

* fix(i18n): Auto update translations for PR #11084

---------

Co-authored-by: GitHub Action <action@github.com>
2025-10-31 21:00:35 +08:00
kangfenmao
9dbc6fbf67 Revert "feat: 添加路由懒加载组件以优化页面加载性能 (#11042)"
This reverts commit dd8690b592.
2025-10-31 18:54:48 +08:00
kangfenmao
8da43ab794 chore: update release notes for v1.7.0-beta.3
- Added new features including an enhanced tool permission system, plugin management, and support for various AI models.
- Improved UI elements and agent creation processes.
- Fixed multiple bugs related to session models, assistant activation, and various API integrations.
- Updated version in package.json to v1.7.0-beta.3.
2025-10-31 17:20:41 +08:00
槑囿脑袋
2a06c606e1 feat: restore data to mobile App (#10108)
* feat: restore data to App

* fix: i18n check

* fix: lint

* Change WebSocket service port to 11451

- Update default port from 3000 to 11451 for WebSocket connections
- Maintain existing service structure and client connection handling

* Add local IP address to WebSocket server configuration

- Set server path using local IP address for improved network accessibility
- Maintain existing CORS policy with wildcard origin
- Keep backward compatibility with current connection handling

* Remove local IP path and enforce WebSocket transport

- Replace dynamic local IP path with static WebSocket transport configuration
- Maintain CORS policy with wildcard origin for cross-origin connections
- Ensure reliable WebSocket-only communication by disabling fallback transports

* Add detailed logging to WebSocket connection flow

- Enhance WebSocketService with verbose connection logging including transport type and client count
- Add comprehensive logging in ExportToPhoneLanPopup for WebSocket initialization and status tracking
- Improve error handling with null checks for main window before sending events

* Add engine-level WebSocket connection monitoring

- Add initial_headers event listener to log connection attempts with URL and headers
- Add engine connection event to log established connections with remote addresses
- Add startup logs for server binding and allowed transports

* chore: change to use 7017 port

* Improve local IP address selection with interface priority system

- Implement network interface priority ranking to prefer Ethernet/Wi-Fi over virtual/VPN interfaces
- Add detailed logging for interface discovery and selection process
- Remove websocket-only transport restriction for broader client compatibility
- Clean up unused parameter in initial_headers event handler

* Add VPN interface patterns for Tailscale and WireGuard

- Include Tailscale VPN interfaces in network interface filtering
- Add WireGuard VPN interfaces to low-priority network candidates
- Maintain existing VPN tunnel interface patterns for compatibility

* Add network interface prioritization for QR code generation

- Implement `getAllCandidates()` method to scan and prioritize network interfaces by type (Ethernet/Wi-Fi over VPN/virtual interfaces)
- Update QR code payload to include all candidate IPs with priority rankings instead of single host
- Add comprehensive interface pattern matching for macOS, Windows, and Linux systems

* Add WebSocket getAllCandidates IPC channel

- Add new WebSocket_GetAllCandidates enum value to IpcChannel
- Register getAllCandidates handler in main process IPC
- Expose getAllCandidates method in preload script API

* Add WebSocket connection logging and temporary test button

- Add URL and method logging to WebSocket engine connection events
- Implement Socket.IO connect and connect_error event handlers with logging
- Add temporary test button to force connection status for debugging

* Clean up WebSocket logging and remove debug code

- Remove verbose debug logs from WebSocket service and connection handling
- Consolidate connection logging into single informative messages
- Remove temporary test button and force connection functionality from UI
- Add missing "sending" translation key for export button loading state

* Enhance file transfer with progress tracking and improved UI

- Add transfer speed monitoring and formatted file size display in WebSocket service
- Implement detailed connection and transfer state management in UI component
- Improve visual feedback with status indicators, progress bars, and error handling

* Enhance WebSocket service and LAN export UI with improved logging and user experience

- Add detailed WebSocket server configuration with transports, CORS, and timeout settings
- Implement comprehensive connection logging at both Socket.IO and Engine.IO levels
- Refactor export popup with modular components, status indicators, and i18n support

* 移除 WebSocket 连接时的冗余日志记录

* Remove dot indicator from connection status component

- Simplify status style map by removing unused dot color properties
- Delete dot indicator element from connection status display
- Maintain existing border and background color styling for status states

* Refactor ExportToPhoneLanPopup with dedicated UI components and improved UX

- Extract QR code display states into separate components (LoadingQRCode, ScanQRCode, ConnectingAnimation, ConnectedDisplay, ErrorQRCode)
- Add confirmation dialog when attempting to close during active file transfer
- Improve WebSocket cleanup and modal dismissal behavior with proper connection handling

* Remove close button hiding during QR code generation

- Eliminate `hideCloseButton={isSending}` prop to keep close button visible
- Maintain consistent modal behavior throughout export process
- Prevent user confusion by ensuring close option remains available

* auto close

* Extract auto-close countdown into separate component

- Move auto-close countdown logic from TransferProgress to dedicated AutoCloseCountdown component
- Update styling to use paddingTop instead of marginTop for better spacing
- Clean up TransferProgress dependencies by removing autoCloseCountdown

* 添加局域网传输相关的翻译文本,包括自动关闭提示和确认关闭消息

---------

Co-authored-by: suyao <sy20010504@gmail.com>
2025-10-31 16:48:09 +08:00
MyPrototypeWhat
b6dcf2f5fa Feat/add skill tool (#11051)
* feat: add SkillTool component and integrate into agent tools

- Introduced SkillTool component for rendering skill-related functionality.
- Updated MessageAgentTools to include SkillTool in the tool renderers.
- Enhanced MessageTool to recognize 'Skill' as a valid agent tool type.
- Modified handleUserMessage to conditionally handle text blocks based on skill inclusion.
- Added SkillToolInput and SkillToolOutput types for better type safety.

* feat: implement command tag filtering in message handling

- Added filterCommandTags function to remove command-* tags from text content, ensuring internal command messages do not appear in the user-facing UI.
- Updated handleUserMessage to utilize the new filtering logic, enhancing the handling of text blocks and improving user experience by preventing unwanted command messages from being displayed.

* refactor: rename tool prefix constants for clarity

- Updated variable names for tool prefixes in MessageTool and SkillTool components to enhance code readability.
- Changed `prefix` to `builtinToolsPrefix` and `agentPrefix` to `agentMcpToolsPrefix` for better understanding of their purpose.
2025-10-31 16:31:50 +08:00
defi-failure
68e0d8b0f1 feat: add confirmation modal for activating protocol-installed MCP (#11070)
* feat: add confirmation modal for activating protocol-installed MCP

* fix: sync i18n

* fix(i18n): Auto update translations for PR #11070

* chore: verify ci is working

* Revert "chore: verify ci is working"

This reverts commit a2434a397d.

---------

Co-authored-by: GitHub Action <action@github.com>
2025-10-31 16:05:02 +08:00
LiuVaayne
7f1c234ac1 fix(ClaudeCodeService): update environment variable names for models (#11073) 2025-10-31 14:46:24 +08:00
Phantom
c1fd23742f fix: activate assistant/agent when creating new (#11009)
* refactor: remove unused SWITCH_ASSISTANT event and related code

Clean up unused event and associated listener in HomePage component

* feat(agents): improve agent handling and state management

- Return result from useUpdateAgent hook
- Update useActiveTopic to handle null assistantId
- Add state management for active agent and topic in Tabs
- Implement afterSubmit callback in AgentModal
- Refactor agent press handling in AssistantsTab
- Clean up HomePage state management logic
- Add afterCreate callback in UnifiedAddButton

* refactor(agent): update agent and session update functions to return entities

Modify update functions in useUpdateAgent and useUpdateSession hooks to return updated entities.
Update related components to handle the new return types and adjust type definitions accordingly.

* refactor(hooks): simplify active topic hook by using useAssistant

* refactor(agent): consolidate agent update types and functions

Move UpdateAgentBaseOptions and related function types from hooks/agents/types.ts to types/agent.ts
Update components to use new UpdateAgentFunctionUnion type
Simplify component props by removing redundant type definitions

* refactor(agent): update type for plugin settings update function

* refactor(AgentSettings): simplify tooling settings type definitions

Remove unused hooks and use direct type imports instead of ReturnType
2025-10-31 14:41:07 +08:00
LiuVaayne
d792bf7fe0 🐛 fix: resolve tool approval UI and shared workspace plugin inconsistency (#11043)
* fix(ToolPermissionRequestCard): simplify button rendering by removing suggestion handling

*  feat: add CachedPluginsDataSchema for plugin cache file

- Add Zod schema for .claude/plugins.json cache file format
- Schema includes version, lastUpdated timestamp, and plugins array
- Reuses existing InstalledPluginSchema for type safety
- Cache will store metadata for all installed plugins

*  feat: add cache management methods to PluginService

- Add readCacheFile() to read .claude/plugins.json
- Add writeCacheFile() for atomic cache writes (temp + rename)
- Add rebuildCache() to scan filesystem and rebuild cache
- Add listInstalledFromCache() to load plugins from cache with fallback
- Add updateCache() helper for transactional cache updates
- All methods handle missing/corrupt cache gracefully
- Cache auto-regenerates from filesystem if needed

*  feat: integrate cache loading in AgentService.getAgent()

- Add installed_plugins field to GetAgentResponseSchema
- Load plugins from cache via PluginService.listInstalledFromCache()
- Gracefully handle errors by returning empty array
- Use loggerService for error logging

* 🐛 fix: break circular dependency causing infinite loop in cache methods

- Change cache method signatures from agentId to workdir parameter
- Update listInstalledFromCache(workdir) to accept workdir directly
- Update rebuildCache(workdir) to accept workdir directly
- Update updateCache(workdir, updater) to accept workdir directly
- AgentService.getAgent() now passes accessible_paths[0] to cache methods
- Removes AgentService.getAgent() calls from PluginService methods
- Fixes infinite recursion bug where methods called each other endlessly

Breaking the circular dependency:
BEFORE: AgentService.getAgent() → PluginService.listInstalledFromCache(id)
        → AgentService.getAgent(id) [INFINITE LOOP]
AFTER:  AgentService.getAgent() → PluginService.listInstalledFromCache(workdir)
        [NO MORE RECURSION]

* 🐛 fix: update listInstalled() to use agent.installed_plugins

- Change from agent.configuration.installed_plugins (old DB location)
- To agent.installed_plugins (new top-level field from cache)
- Simplify validation logic to use existing plugin structure
- Fixes UI not showing installed plugins correctly

This was causing the UI to show empty plugin lists even though plugins
were correctly loaded in the cache by AgentService.getAgent().

* ♻️ refactor: remove unused updateCache helper

* ♻️ refactor: centralize plugin directory helpers

* feat: Implement Plugin Management System

- Added PluginCacheStore for managing plugin metadata and caching.
- Introduced PluginInstaller for handling installation and uninstallation of plugins.
- Created PluginService to manage plugin lifecycle, including installation, uninstallation, and listing of available plugins.
- Enhanced AgentService to integrate with PluginService for loading installed plugins.
- Implemented validation and sanitization for plugin file names and paths to prevent security issues.
- Added support for skills as a new plugin type, including installation and management.
- Introduced caching mechanism for available plugins to improve performance.

* ♻️ refactor: simplify PluginInstaller and PluginService by removing agent dependency and updating plugin handling
2025-10-31 14:30:50 +08:00
亢奋猫
f8a599322f feat(useAppInit): implement automatic update checks with interval sup… (#11063)
feat(useAppInit): implement automatic update checks with interval support

- Added a function to check for updates, which is called initially and set to run every 6 hours if the app is packaged and auto-update is enabled.
- Refactored the initial update check to utilize the new function for better code organization and clarity.
2025-10-31 13:35:27 +08:00
defi-failure
aa810a7ead fix: notify renderer when api server ready (#11049)
* fix: notify renderer when api server ready

* chore: minor comment update

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: minor ui change to reflect server loading state

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-31 12:13:59 +08:00
Pleasure1234
b586e1796e fix: sort grouped items by saved tags order from Redux (#11065)
Updated useUnifiedGrouping to sort grouped items by the tags order saved in the Redux store, falling back to untagged first. This improves consistency with user-defined tag ordering.
2025-10-31 11:21:10 +08:00
George·Dong
fa2ec69fa9 fix(SettingsTab): Context slider inconsistent (#10943)
* fix(i18n): standardize "max" translation to indicate unlimited

* feat(SettingsTab): add current context

* feat(settings): show proper "max" label for context count

* fix(settings): simplify contextCount value expression

* feat(settings): make context count editable with number input
2025-10-30 20:15:35 +08:00
SuYao
dd8690b592 feat: 添加路由懒加载组件以优化页面加载性能 (#11042) 2025-10-30 16:41:07 +08:00
MyPrototypeWhat
09e6b9741e fix: update GlobTool to count lines instead of files in output (#11036) 2025-10-30 16:14:04 +08:00
ABucket
0767952a6f docs: fix invalid link in the contributing guide (#11038)
docs: fix invalid link
2025-10-29 22:28:38 +08:00
MyPrototypeWhat
72299f833a feat(ReadTool): add function to remove <system-reminder> tags (#11034)
feat(ReadTool): add function to remove <system-reminder> tags from output text

- Introduced `removeSystemReminderTags` function to clean output by removing <system-reminder> tags and their content.
- Updated output processing logic to apply this function for both array and string output types, ensuring consistent formatting.
2025-10-29 22:24:44 +08:00
MyPrototypeWhat
7badaf02b9 fix(TodoWriteTool): remove output rendering from TodoWriteTool component (#11035)
* fix: remove output rendering from TodoWriteTool component

* refactor: remove output parameter from TodoWriteTool component
2025-10-29 20:37:54 +08:00
defi-failure
dfbfc2869c fix: use session model when sending messages (#11028) 2025-10-29 16:32:04 +08:00
Phantom
1575e97168 fix: approved tools (#11025)
* refactor(agent): move permission mode types and constants to config

Move PermissionModeCard type definition to types/agent.ts and relocate permissionModeCards constant from constants/permissionModes.ts to config/agent.ts for better organization and maintainability

* refactor(AgentSettings): simplify state management in ToolingSettings

remove redundant state for selectedMode and derive it from configuration
consolidate permission mode constants import path

* docs(AgentSettings): add jsdoc for computeModeDefaults function

* refactor(AgentSettings): simplify tooling state management with useMemo

remove redundant state for autoToolIds and compute it directly using useMemo

* refactor(AgentSettings): simplify tool approval state management

- Replace useState with useMemo for approvedToolIds to prevent unnecessary state updates
- Remove redundant state transitions and simplify toggle logic
- Ensure consistent tool filtering and merging with defaults

* refactor(AgentSettings): replace useState with useMemo for configuration state

Optimize performance by memoizing agent configuration state to prevent unnecessary re-renders

* perf(AgentSettings): optimize permission_mode computation with useMemo

Prevent unnecessary recalculations of permission_mode by memoizing the value

* refactor(AgentSettings): simplify MCP selection logic and remove unused imports

Remove useEffect for MCP state synchronization and directly use memoized value
Clean up unused imports and simplify toggle handler logic

* refactor: remove unused useAgentClient hook from ToolingSettings
2025-10-29 16:21:29 +08:00
SuYao
e0a2ed0481 Provider Config & anthropic-web-fetch (#10808)
* fix: update AI SDK dependencies to latest versions

* feat: Update provider configurations and API handling

- Refactor provider configuration to support new API types and enhance API host formatting.
- Introduce new utility functions for handling API versions and formatting Azure OpenAI hosts.
- Update system models to include new capabilities and adjust provider types for CherryIN and VertexAI.
- Enhance provider settings UI to accommodate new API types and improve user experience.
- Implement migration logic for provider type updates and default API host settings.
- Update translations for API host configuration tips across multiple languages.
- Fix various type checks and utility functions to ensure compatibility with new provider types.

* fix: update unsupported API version providers and add longcat to compatible provider IDs

* fix: 移除不再使用的 Azure OpenAI API 版本参数,优化 API 主机格式化逻辑
feat: 在选择器组件中添加样式属性,增强可定制性
feat: 更新提供者设置,支持动态选择 API 主机字段

* refactor: 优化测试用例

* 修复: 更新工具调用处理器以支持新的工具调用类型

* feat: 添加TODO注释以改进基于AI SDK的供应商内置工具展示和类型安全处理

* feat: 添加对Google SDK的支持,更新流式参数构建逻辑以包含Google工具的上下文

* feat: 更新web搜索模型判断逻辑,使用SystemProviderIds常量替代硬编码字符串

* feat: 添加对@renderer/store的mock以支持测试环境

* feat: 添加API主机地址验证功能,更新相关逻辑以支持端点提取

* fix: i18n

* fix(i18n): Auto update translations for PR #10808

* Apply suggestion from @EurFelux

Co-authored-by: Phantom <eurfelux@gmail.com>

* Apply suggestion from @EurFelux

Co-authored-by: Phantom <eurfelux@gmail.com>

* Apply suggestion from @EurFelux

Co-authored-by: Phantom <eurfelux@gmail.com>

* refactor: Simplify provider type migration logic and enhance API version validation

* fix: Correct variable name from configedApiHost to configuredApiHost for consistency

* fix: Update package.json to remove deprecated @ai-sdk/google version and streamline @ai-sdk/openai versioning

* fix: 更新 hasAPIVersion 函数中的正则表达式以更准确地匹配 API 版本路径

* fix(api): 简化 validateApiHost 函数逻辑以始终返回 true
fix(yarn): 更新 @ai-sdk/openai 版本至 2.0.53 并添加依赖项

* fix(api): 修正 validateApiHost 函数在使用哈希后缀时的验证逻辑

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Phantom <eurfelux@gmail.com>
2025-10-29 14:47:21 +08:00
LiuVaayne
5790c12011 Feat: Enhanced Tool Permission System with Real-time Approvals #10738 (#10743)
* ⬆️ chore: upgrade claude agent sdk to 0.1.15

*  feat: add initial tool permission approval system

- Add promptForToolApproval function for real-time tool approval UI
- Integrate canUseTool callback into ClaudeCodeService
- Create tool-permissions.ts module for permission handling
- Set foundation for enhanced tool permission system #10738

This provides the basic infrastructure for displaying tool approval
prompts and getting user consent before agents execute potentially
dangerous operations.

* restore to main for

restore to main for

*  feat: implement agent tool permission request system

Add comprehensive tool permission management for Claude Code agents with:
- IPC channels for bidirectional permission requests/responses between main and renderer
- Permission request queue with timeout (30s), abort signal handling, and auto-cleanup
- Auto-approval system via CHERRY_AUTO_ALLOW_TOOLS env var and default allow-list (Read, Glob, Grep)
- New ToolPermissionRequestCard UI component for user approval with input preview
- Redux store (toolPermissions) for tracking pending/resolved permission requests
- User input stream architecture allowing dynamic user messages during agent execution

Key changes:
- packages/shared/IpcChannel.ts: Add AgentToolPermission_* channels
- src/main/services/agents/services/claudecode/: Refactor canUseTool with permission prompts
- src/renderer/src/store/toolPermissions.ts: New Redux slice for permission state
- src/renderer/src/pages/home/Messages/Tools/ToolPermissionRequestCard.tsx: Interactive approval UI

* refactor: simplify ToolPermissionRequestCard by removing unused imports and suggestion handling logic

* feat: add i18n

* fix(i18n): Auto update translations for PR #10743

---------

Co-authored-by: dev <verc20.dev@proton.me>
Co-authored-by: GitHub Action <action@github.com>
2025-10-29 13:37:32 +08:00
LiuVaayne
352ecbc506 feat: add plugin management system for Claude Agent (agents, commands, skills) (#10854)
*  feat: add claude-code-templates via git submodule with build-time copy

- Add git submodule for davila7/claude-code-templates
- Create scripts/copy-templates.js to copy components at build time
- Update package.json build script to include template copying
- Add resources/data/components/ to .gitignore (generated files)

Templates are now automatically synced from external repo to resources/data/components/
during build process, avoiding manual file copying.

To update templates: git submodule update --remote --merge

* fix: update target directory for copying Claude Code templates

*  feat: merge Anthropics skills into template sync

* 📝 docs: add agent plugins management implementation spec

Add comprehensive implementation plan for plugin management feature:
- Security validation and transactional operations
- Plugin browsing, installation, and management UI
- IPC handlers and PluginService architecture
- Metadata caching and database integration

*  feat: add plugin management backend infrastructure

Backend implementation for Claude Code plugin management:

- Add PluginService with security validation and caching
- Create IPC handlers for plugin operations (list, install, uninstall)
- Add markdown parser with safe YAML frontmatter parsing
- Extend AgentConfiguration schema with installed_plugins field
- Update preload bridge to expose plugin API to renderer
- Add plugin types (PluginMetadata, PluginError, PluginResult)

Features:
- Transactional install/uninstall with rollback
- Path traversal prevention and file validation
- 5-minute plugin list caching for performance
- SHA-256 content hashing for integrity checks
- Duplicate plugin handling (auto-replace)

Dependencies added:
- gray-matter: Markdown frontmatter parsing
- js-yaml: Safe YAML parsing with FAILSAFE_SCHEMA

*  feat: add plugin management UI and integration

Complete frontend implementation for Claude Code plugin management:

**React Hooks:**
- useAvailablePlugins: Fetch and cache available plugins
- useInstalledPlugins: List installed plugins with refresh
- usePluginActions: Install/uninstall with loading states

**UI Components (HeroUI):**
- PluginCard: Display plugin with install/uninstall actions
- CategoryFilter: Multi-select chip-based category filter
- InstalledPluginsList: Table view with uninstall confirmation
- PluginBrowser: Search, filter, pagination, responsive grid
- PluginSettings: Main container with Available/Installed tabs

**Integration:**
- Added "Plugins" tab to AgentSettingsPopup
- Full i18n support (English, Simplified Chinese, Traditional Chinese)
- Toast notifications for success/error states
- Loading skeletons and empty states

**Features:**
- Search plugins by name/description
- Filter by category and type (agents/commands)
- Pagination (12 items per page)
- Install/uninstall with confirmation dialogs
- Real-time plugin list updates
- Responsive grid layout (1-3 columns)

All code formatted with Biome and follows existing patterns.

* 🐛 fix: add missing plugin i18n keys at root level

Add plugin translation keys at root 'plugins.*' level to match component usage:
- Search and filter UI strings
- Pluralization support for result counts
- Empty state messages
- Action button labels
- Confirmation dialog text

Translations added for all three locales (en-US, zh-CN, zh-TW).

* 🐛 fix: use getResourcePath() utility for plugin directory resolution

Replace manual path calculation with getResourcePath() utility which correctly
handles both development and production environments. This fixes the issue where
plugins were not loading because __dirname was resolving to the wrong location.

Fixes:
- Plugins now load correctly in development mode
- Path resolution consistent with other resource loading in the app
- Removed unused 'app' import from electron

* 🎨 fix: improve plugin UI scrolling and category filter layout

Fixes two UI issues:

1. Enable scrolling for plugin list:
   - Changed overflow-hidden to overflow-y-auto on tab containers
   - Plugin grid now scrollable when content exceeds viewport

2. Make category filter more compact:
   - Added max-h-24 (96px) height limit to category chip container
   - Enabled vertical scrolling for category chips
   - Prevents category filter from taking too much vertical space

UI improvements enhance usability when browsing large plugin collections.

* 🎨 fix: ensure both agent and command badges have visible backgrounds

Changed Chip variant from 'flat' to 'solid' for plugin type badges.
This ensures both agent (primary) and command (secondary) badges display
with consistent, visible background colors instead of command badges
appearing as text-only.

*  feat: add plugin detail modal for viewing full plugin information

Add modal to display complete plugin details when clicking on a card:

Features:
- Click any plugin card to view full details in a modal
- Shows complete description (not truncated)
- Displays all metadata: version, author, tools, allowed_tools, tags
- Shows file info: filename, size, source path, install date
- Install/uninstall actions available in modal
- Hover effect on cards to indicate clickability
- Button clicks don't trigger card click (event.stopPropagation)

Components:
- New PluginDetailModal component with scrollable content
- Updated PluginCard to be clickable (isPressable)
- Updated PluginBrowser to manage modal state

UI improvements provide better plugin exploration and decision-making.

* 🐛 fix: render plugin detail modal above agent settings modal

Use React portal to render PluginDetailModal directly to document.body,
ensuring it appears above the agent settings modal instead of being
blocked by it.

Changes:
- Import createPortal from react-dom
- Wrap modal content in createPortal(modalContent, document.body)
- Add z-[9999] to modal wrapper for proper layering

Fixes modal visibility issue where plugin details were hidden behind
the parent agent settings modal.

*  feat: add plugin content viewing and editing in detail modal

- Added IPC channels for reading and writing plugin content
- Implemented readContent() and writeContent() methods in PluginService
- Added IPC handlers for content operations with proper error handling
- Exposed plugin content API through preload bridge
- Updated PluginDetailModal to fetch and display markdown content
- Added edit mode with textarea for modifying plugin content
- Implemented save/cancel functionality with optimistic UI updates
- Added agentId prop to component chain for write operations
- Updated AgentConfigurationSchema to include all plugin metadata fields
- Moved plugin types to shared @types for cross-process access
- Added validation and security checks for content read/write
- Updated content hash in DB after successful edits

* 🐛 fix: change event handler from onPress to onClick for uninstall and install buttons

* 📝 docs: update AI Assistant Guide to clarify proposal and commit guidelines

* 📝 docs: add skills support extension spec for agent plugins management

*  feat: add secure file operation utilities for skills plugin system

- Implement copyDirectoryRecursive() with security protections
- Implement deleteDirectoryRecursive() with path validation
- Implement getDirectorySize() for folder size calculation
- Add path traversal protection using isPathInside()
- Handle symlinks securely to prevent attacks
- Add recursion depth limits to prevent stack overflow
- Preserve file permissions during copy
- Handle race conditions and missing files gracefully
- Skip special files (pipes, sockets, devices)

Security features:
- Path validation against allowedBasePath boundary
- Symlink detection and skip to prevent circular loops
- Input validation for null/empty/relative paths
- Comprehensive error handling and logging

Updated spec status to "In Progress" and added implementation progress checklist.

*  feat: add skill type support and skill metadata parsing

Type System Updates (plugin.ts):
- Add PluginType export for 'agent' | 'command' | 'skill'
- Update PluginMetadataSchema to include 'skill' in type enum
- Update InstalledPluginSchema to support skill type
- Update all option interfaces to support skill type
- Add skills array to ListAvailablePluginsResult
- Document filename semantics differences between types

Markdown Parser Updates (markdownParser.ts):
- Implement parseSkillMetadata() function for SKILL.md parsing
- Add comprehensive input validation (absolute path check)
- Add robust error handling with specific PluginErrors
- Add try-catch around file operations and YAML parsing
- Add type validation for frontmatter data fields
- Add proper logging using loggerService
- Handle getDirectorySize() failures gracefully
- Document hash scope decision (SKILL.md only vs entire folder)
- Use FAILSAFE_SCHEMA for safe YAML parsing

Security improvements:
- Path validation to ensure absolute paths
- Differentiate ENOENT from permission errors
- Type validation for all frontmatter fields
- Safe YAML parsing to prevent deserialization attacks

Updated spec progress tracking.

*  feat: implement complete skill support in PluginService

Core Infrastructure:
- Add imports for parseSkillMetadata and file operation utilities
- Add PluginType to imports for type-safe handling

Skill-Specific Methods:
- sanitizeFolderName() - validates folder names (no dots allowed)
- scanSkillDirectory() - scans skills/ for skill folders
- installSkill() - copies folders with transaction/rollback
- uninstallSkill() - removes folders with transaction/rollback

Updated Methods for Skills Support:
- listAvailable() - now scans and returns skills array
- install() - branches on type to handle skills vs files
- uninstall() - branches on type for skill/file handling
- ensureClaudeDirectory() - handles 'skills' subdirectory
- listInstalled() - validates skill folders on filesystem
- writeContent() - updated signature to accept PluginType

Key Implementation Details:
- Skills use folder names WITHOUT extensions
- Agents/commands use filenames WITH .md extension
- Different sanitization rules for folders vs files
- Transaction pattern with rollback for all operations
- Comprehensive logging and error handling
- Maintains backward compatibility with existing code

Updated spec progress tracking.

*  feat: add skill support to frontend hooks and UI components

Frontend Hooks (usePlugins.ts):
- Add skills state to useAvailablePlugins hook
- Return skills array in hook result
- Update install() to accept 'skill' type
- Update uninstall() to accept 'skill' type

UI Components:
- PluginCard: Add 'skill' type badge with success color
- PluginBrowser: Add skills prop and include in plugin list
- PluginBrowser: Update type definitions to include 'skill'
- PluginBrowser: Include skills in tab filtering

Complete frontend integration for skills plugin type.
Updated spec progress tracking.

* ♻️ refactor: remove unused variable in installSkill method

* 📝 docs: mark implementation as complete with summary

Implementation Status: COMPLETE (11/12 tasks)

Completed:
-  File operation utilities with security protections
-  Skill metadata parsing with validation
-  Plugin type system updated to include 'skill'
-  PluginService skill methods (scan, install, uninstall)
-  PluginService updated for skill support
-  IPC handlers (no changes needed - already generic)
-  Frontend hooks updated for skills
-  UI components updated (PluginCard, PluginBrowser)
-  Build check passed with lint fixes

Deferred (non-blocking):
- ⏸️ Session integration - requires further investigation
  into session handler location and implementation

The core skills plugin system is fully implemented and functional.
Skills can be browsed, installed, and uninstalled through the UI.
All security requirements met with path validation and transaction
rollback. Code passes lint checks and follows project patterns.

* 🐛 fix: pass skills prop to PluginBrowser component

Fixed "skills is not iterable" error by:
- Destructuring skills from useAvailablePlugins hook
- Updating type annotations to include 'skill' type
- Passing skills prop to PluginBrowser component

This completes the missing UI wiring for skills support.

*  feat: add Skills tab to plugin browser

Added missing Skills tab to PluginBrowser component:
- Added Skills tab to type tabs
- Added translations for skills in all locales (en-us, zh-cn, zh-tw)
  - English: "Skills"
  - Simplified Chinese: "技能"
  - Traditional Chinese: "技能"

This completes the UI integration for the skills plugin type.

*  feat: add 'skill' type to AgentConfiguration and GetAgentSessionResponse schemas

* ⬆️ chore: upgrade @anthropic-ai/claude-agent-sdk to v0.1.25 with patch

- Updated from v0.1.1 to v0.1.25
- Applied fork/IPC patch to new version
- Removed old patch file
- All tests passing

* 🐛 fix: resolve linting and TypeScript type errors in build check

- Add external/** and resources/data/claude-code-plugins/** to lint ignore patterns
  to exclude git submodules and plugin templates from linting
- Fix TypeScript error handling in IPC handlers by properly typing caught errors
- Fix AgentConfiguration type mismatches by providing default values for
  permission_mode and max_turns when spreading configuration
- Replace control character regex with String.fromCharCode() to avoid ESLint
  no-control-regex rule in sanitization functions
- Fix markdownParser yaml.load return type by adding type assertion
- Add getPluginErrorMessage helper to properly extract error messages from
  PluginError discriminated union types

Main process TypeScript errors: Fixed (0 errors)
Linting errors: Fixed (0 errors from 4397)
Remaining: 4 renderer TypeScript errors in settings components

* ♻️ refactor: improve plugin error handling and reorganize i18n structure

* ⬆️ chore: update @anthropic-ai/claude-agent-sdk to include patch and additional dependencies

* 🗑️ chore: remove unused Claude code plugins and related configurations

- Deleted `.gitmodules` and associated submodules for `claude-code-templates` and `anthropics-skills`.
- Updated `.gitignore`, `.oxlintrc.json`, and `eslint.config.mjs` to exclude `claude-code-plugins`.
- Modified `package.json` to remove the build script dependency on copying templates.
- Adjusted `PluginService.ts` to handle plugin paths without relying on removed resources.

* format code

* delete

* delete

* fix(i18n): Auto update translations for PR #10854

*  feat: enhance PluginService and markdownParser with recursive skill directory search

- Added `findAllSkillDirectories` function to recursively locate directories containing `SKILL.md`.
- Updated `scanSkillDirectory` method in `PluginService` to utilize the new recursive search.
- Modified `PluginDetailModal` to append `/SKILL.md` to the source path for skill plugins.

* fix(i18n): Auto update translations for PR #10854

* remove specs

* update claude code plugins files

---------

Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: beyondkmp <beyondkmp@gmail.com>
Co-authored-by: GitHub Action <action@github.com>
2025-10-29 13:33:11 +08:00
George·Dong
fc4f30feab fix: update Dashscope Anthropic API host and migrate old configs (#10973)
* fix: update Dashscope Anthropic API host and migrate old configs

* fix(migration): remove obsolete dashscope rewrite

* fix(migrate): overwrite Anthropic API host for dashscope provider
2025-10-29 09:20:19 +08:00
Carlton
888a183328 feat(knowledge, preprocess): Add OpenMinerU preprocessor, knowledge base supports using open-source version of MinerU to process documents (#10992)
* feat(knowledge): 为文档处理增加open-mineru的支持

* 移除OpenMineruPreprocessProvider多余的apiKey处理

* Add preprocessProviders migrator for open-mineru

* Remove invalid code from OpenMineruPreprocessProvider

* fix property '"open-mineru"' is missing in PREPROCESS_PROVIDER_CONFIG

* refactor(preprocess): improve OpenMinerU error handling and file cleanup
2025-10-29 09:19:18 +08:00
scientia
9a01e092f6 feat: allow new-topic bindkey to create new session for agent as well (#10862)
* fix: allow new-topic shortcut to create agent sessions

* revert: restore ProxyManager.ts

* fix: make agent session shortcut sidebar-independent

* refactor: centralize default session creation

* feat: add new session button to agent inputbar

* fix: encapsulate agent session creation state

* refactor: remove redundant useMemo in useCreateDefaultSession

The useMemo wrapper around the return object was unnecessary because:
- createDefaultSession is already memoized via useCallback
- creatingSession is a primitive boolean that doesn't need memoization
- The object gets recreated on every creatingSession change anyway

This simplifies the code and removes unnecessary overhead.

---------

Co-authored-by: wangdenghui <wangdenghui@xiaomi.com>
2025-10-28 22:59:44 +08:00
George·Dong
5986800c9d chore(ci): exempt all milestones and assignee from staling (#11008) 2025-10-28 19:20:05 +08:00
槑囿脑袋
56d68276e1 fix(knowledge): force choose knowledge aisdk error (#11006)
fix: aisdk error
2025-10-28 16:37:58 +08:00
Copilot
29c1173365 Fix Qwen3 thinking mode control for Ollama using aiCore middleware (#10947)
* Initial plan

* Fix Qwen3 thinking mode control for Ollama by using reasoning_effort instead of qwenThinkMode

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>

* Refactor: Move Qwen thinking mode control from legacy to aiCore middleware

- Revert changes to legacy OpenAIApiClient.ts
- Create new qwenThinkingMiddleware for handling /think and /no_think suffixes
- Update AiSdkMiddlewareBuilder to add assistant field and apply Qwen middleware
- Middleware automatically handles Qwen models on Ollama, LM Studio, and NVIDIA providers
- This follows the modern aiCore architecture instead of deprecated legacy approach

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>

* Fix: Explicitly pass assistant field to buildAiSdkMiddlewares

Ensure that the assistant field from ModernAiProviderConfig is explicitly passed
to buildAiSdkMiddlewares so that Qwen thinking middleware can access
assistant.settings.reasoning_effort correctly.

Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>

* Fix: Remove unnecessary whitespace in processPostsuffixQwen3Model tests

* Refactor: Simplify user message suffix handling in qwenThinkingMiddleware

* Refactor: Remove processPostsuffixQwen3Model tests to streamline ModelMessageService tests

* refactor: remove logger and debug statement from qwenThinkingMiddleware

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: DeJeune <67425183+DeJeune@users.noreply.github.com>
Co-authored-by: suyao <sy20010504@gmail.com>
2025-10-28 14:26:54 +08:00
Jake Jia
c7ceb3035d fix: align and unify LocalBackupManager footer layout (#10985)
* fix: align and unify LocalBackupManager footer layout

- Use Space component to wrap footer buttons, consistent with S3BackupManager
- Optimize delete button i18n text by using count parameter instead of hardcoded concatenation

* fix: fix the i18n issue in the  delete button text
2025-10-28 13:26:53 +08:00
Phantom
7bcae6fba2 fix(Navbar): adjust min-height calculation for fullscreen mode on Mac (#10990)
Ensure the navbar height is correctly calculated when toggling fullscreen mode on macOS by considering the $isFullScreen prop
2025-10-28 10:29:28 +08:00
987 changed files with 17989 additions and 11126 deletions

View File

@@ -1,4 +1,4 @@
name: 🐛 Bug Report (English)
name: 🐛 Bug Report
description: Create a report to help us improve
title: '[Bug]: '
labels: ['BUG']

View File

@@ -1,4 +1,4 @@
name: 💡 Feature Request (English)
name: 💡 Feature Request
description: Suggest an idea for this project
title: '[Feature]: '
labels: ['feature']

View File

@@ -1,4 +1,4 @@
name: 🤔 Other Questions (English)
name: 🤔 Other Questions
description: Submit questions that don't fit into bug reports or feature requests
title: '[Other]: '
body:

View File

@@ -1,4 +1,4 @@
name: Auto I18N
name: Auto I18N Weekly
env:
TRANSLATION_API_KEY: ${{ secrets.TRANSLATE_API_KEY }}
@@ -7,14 +7,15 @@ env:
TRANSLATION_BASE_LOCALE: ${{ vars.AUTO_I18N_BASE_LOCALE || 'en-us'}}
on:
pull_request:
types: [opened, synchronize, reopened]
schedule:
# Runs at 00:00 UTC every Sunday.
# This corresponds to 08:00 AM UTC+8 (Beijing time) every Sunday.
- cron: "0 0 * * 0"
workflow_dispatch:
jobs:
auto-i18n:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == 'CherryHQ/cherry-studio'
name: Auto I18N
permissions:
contents: write
@@ -24,45 +25,69 @@ jobs:
- name: 🐈‍⬛ Checkout
uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
- name: 📦 Setting Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20
package-manager-cache: false
node-version: 22
- name: 📦 Install dependencies in isolated directory
- name: 📦 Install corepack
run: corepack enable && corepack prepare yarn@4.9.1 --activate
- name: 📂 Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
- name: 💾 Cache yarn dependencies
uses: actions/cache@v4
with:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: 📦 Install dependencies
run: |
# 在临时目录安装依赖
mkdir -p /tmp/translation-deps
cd /tmp/translation-deps
echo '{"dependencies": {"@cherrystudio/openai": "^6.5.0", "cli-progress": "^3.12.0", "tsx": "^4.20.3", "@biomejs/biome": "2.2.4"}}' > package.json
npm install --no-package-lock
# 设置 NODE_PATH 让项目能找到这些依赖
echo "NODE_PATH=/tmp/translation-deps/node_modules" >> $GITHUB_ENV
yarn install
- name: 🏃‍♀️ Translate
run: npx tsx scripts/sync-i18n.ts && npx tsx scripts/auto-translate-i18n.ts
run: yarn sync:i18n && yarn auto:i18n
- name: 🔍 Format
run: cd /tmp/translation-deps && npx biome format --config-path /home/runner/work/cherry-studio/cherry-studio/biome.jsonc --write /home/runner/work/cherry-studio/cherry-studio/src/renderer/src/i18n/
run: yarn format
- name: 🔄 Commit changes
- name: 🔍 Check for changes
id: git_status
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
# Check if there are any uncommitted changes
git reset -- package.json yarn.lock # 不提交 package.json 和 yarn.lock 的更改
if git diff --cached --quiet; then
echo "No changes to commit"
else
git commit -m "fix(i18n): Auto update translations for PR #${{ github.event.pull_request.number }}"
fi
git diff --exit-code --quiet || echo "::set-output name=has_changes::true"
git status --porcelain
- name: 🚀 Push changes
uses: ad-m/github-push-action@master
- name: 📅 Set current date for PR title
id: set_date
run: echo "CURRENT_DATE=$(date +'%b %d, %Y')" >> $GITHUB_ENV # e.g., "Jun 06, 2024"
- name: 🚀 Create Pull Request if changes exist
if: steps.git_status.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v6
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.event.pull_request.head.ref }}
token: ${{ secrets.GITHUB_TOKEN }} # Use the built-in GITHUB_TOKEN for bot actions
commit-message: "feat(bot): Weekly automated script run"
title: "🤖 Weekly Automated Update: ${{ env.CURRENT_DATE }}"
body: |
This PR includes changes generated by the weekly auto i18n.
Review the changes before merging.
---
_Generated by the automated weekly workflow_
branch: "auto-i18n-weekly-${{ github.run_id }}" # Unique branch name
base: "main" # Or 'develop', set your base branch
delete-branch: true # Delete the branch after merging or closing the PR
- name: 📢 Notify if no changes
if: steps.git_status.outputs.has_changes != 'true'
run: echo "Bot script ran, but no changes were detected. No PR created."

View File

@@ -5,7 +5,7 @@ on:
types: [opened]
schedule:
# Run every day at 8:30 Beijing Time (00:30 UTC)
- cron: '30 0 * * *'
- cron: "30 0 * * *"
workflow_dispatch:
jobs:
@@ -54,9 +54,9 @@ jobs:
- name: Setup Node.js
if: steps.check_time.outputs.should_delay == 'false'
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: 22
- name: Process issue with Claude
if: steps.check_time.outputs.should_delay == 'false'
@@ -121,9 +121,9 @@ jobs:
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: 22
- name: Process pending issues with Claude
uses: anthropics/claude-code-action@main

View File

@@ -21,7 +21,7 @@ jobs:
contents: none
steps:
- name: Close needs-more-info issues
uses: actions/stale@v9
uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
only-labels: 'needs-more-info'
@@ -29,8 +29,10 @@ jobs:
days-before-close: 0 # Close immediately after stale
stale-issue-label: 'inactive'
close-issue-label: 'closed:no-response'
exempt-all-milestones: true
exempt-all-assignees: true
stale-issue-message: |
This issue has been labeled as needing more information and has been inactive for ${{ env.daysBeforeStale }} days.
This issue has been labeled as needing more information and has been inactive for ${{ env.daysBeforeStale }} days.
It will be closed now due to lack of additional information.
该问题被标记为"需要更多信息"且已经 ${{ env.daysBeforeStale }} 天没有任何活动,将立即关闭。
@@ -40,12 +42,14 @@ jobs:
days-before-pr-close: -1
- name: Close inactive issues
uses: actions/stale@v9
uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: ${{ env.daysBeforeStale }}
days-before-close: ${{ env.daysBeforeClose }}
stale-issue-label: 'inactive'
exempt-all-milestones: true
exempt-all-assignees: true
stale-issue-message: |
This issue has been inactive for a prolonged period and will be closed automatically in ${{ env.daysBeforeClose }} days.
该问题已长时间处于闲置状态,${{ env.daysBeforeClose }} 天后将自动关闭。

View File

@@ -3,7 +3,7 @@ name: Nightly Build
on:
workflow_dispatch:
schedule:
- cron: '0 17 * * *' # 1:00 BJ Time
- cron: "0 17 * * *" # 1:00 BJ Time
permissions:
contents: write
@@ -56,9 +56,9 @@ jobs:
ref: main
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 22
- name: macos-latest dependencies fix
if: matrix.os == 'macos-latest'
@@ -66,7 +66,7 @@ jobs:
brew install python-setuptools
- name: Install corepack
run: corepack enable && corepack prepare yarn@4.6.0 --activate
run: corepack enable && corepack prepare yarn@4.9.1 --activate
- name: Get yarn cache directory path
id: yarn-cache-dir-path
@@ -208,7 +208,7 @@ jobs:
echo "总计: $(find renamed-artifacts -type f | wc -l) 个文件"
- name: Upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: cherry-studio-nightly-${{ steps.date.outputs.date }}-${{ matrix.os }}
path: renamed-artifacts/*

View File

@@ -24,12 +24,12 @@ jobs:
uses: actions/checkout@v5
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 22
- name: Install corepack
run: corepack enable && corepack prepare yarn@4.6.0 --activate
run: corepack enable && corepack prepare yarn@4.9.1 --activate
- name: Get yarn cache directory path
id: yarn-cache-dir-path

View File

@@ -4,9 +4,9 @@ on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag (e.g. v1.0.0)'
description: "Release tag (e.g. v1.0.0)"
required: true
default: 'v1.0.0'
default: "v1.0.0"
push:
tags:
- v*.*.*
@@ -47,9 +47,9 @@ jobs:
npm version "$VERSION" --no-git-tag-version --allow-same-version
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 22
- name: macos-latest dependencies fix
if: matrix.os == 'macos-latest'
@@ -57,7 +57,7 @@ jobs:
brew install python-setuptools
- name: Install corepack
run: corepack enable && corepack prepare yarn@4.6.0 --activate
run: corepack enable && corepack prepare yarn@4.9.1 --activate
- name: Get yarn cache directory path
id: yarn-cache-dir-path
@@ -127,5 +127,5 @@ jobs:
allowUpdates: true
makeLatest: false
tag: ${{ steps.get-tag.outputs.tag }}
artifacts: 'dist/*.exe,dist/*.zip,dist/*.dmg,dist/*.AppImage,dist/*.snap,dist/*.deb,dist/*.rpm,dist/*.tar.gz,dist/latest*.yml,dist/rc*.yml,dist/beta*.yml,dist/*.blockmap'
artifacts: "dist/*.exe,dist/*.zip,dist/*.dmg,dist/*.AppImage,dist/*.snap,dist/*.deb,dist/*.rpm,dist/*.tar.gz,dist/latest*.yml,dist/rc*.yml,dist/beta*.yml,dist/*.blockmap"
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -22,7 +22,6 @@
"eslint.config.mjs"
],
"overrides": [
// set different env
{
"env": {
"node": true
@@ -36,8 +35,7 @@
"files": [
"src/renderer/**/*.{ts,tsx}",
"packages/aiCore/**",
"packages/extension-table-plus/**",
"resources/js/**"
"packages/extension-table-plus/**"
]
},
{
@@ -55,74 +53,16 @@
"files": ["src/preload/**"]
}
],
// We don't use the React plugin here because its behavior differs slightly from that of ESLint's React plugin.
"plugins": ["unicorn", "typescript", "oxc", "import"],
"rules": {
"constructor-super": "error",
"for-direction": "error",
"getter-return": "error",
"no-array-constructor": "off",
// "import/no-cycle": "error", // tons of error, bro
"no-async-promise-executor": "error",
"no-caller": "warn",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-const-assign": "error",
"no-constant-binary-expression": "error",
"no-constant-condition": "error",
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-else-if": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-empty-static-block": "error",
"no-eval": "warn",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-fallthrough": "warn",
"no-func-assign": "error",
"no-global-assign": "error",
"no-import-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-new-native-nonconstructor": "error",
"no-nonoctal-decimal-escape": "error",
"no-obj-calls": "error",
"no-octal": "error",
"no-prototype-builtins": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-self-assign": "error",
"no-setter-return": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-this-before-super": "error",
"no-unassigned-vars": "warn",
"no-undef": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unsafe-optional-chaining": "error",
"no-unused-expressions": "off", // this rule disallow us to use expression to call function, like `condition && fn()`
"no-unused-labels": "error",
"no-unused-private-class-members": "error",
"no-unused-expressions": "off",
"no-unused-vars": ["warn", { "caughtErrors": "none" }],
"no-useless-backreference": "error",
"no-useless-catch": "error",
"no-useless-escape": "error",
"no-useless-rename": "warn",
"no-with": "error",
"oxc/bad-array-method-on-arguments": "warn",
"oxc/bad-char-at-comparison": "warn",
"oxc/bad-comparison-sequence": "warn",
@@ -134,19 +74,17 @@
"oxc/erasing-op": "warn",
"oxc/missing-throw": "warn",
"oxc/number-arg-out-of-range": "warn",
"oxc/only-used-in-recursion": "off", // manually off bacause of existing warning. may turn it on in the future
"oxc/only-used-in-recursion": "off",
"oxc/uninvoked-array-callback": "warn",
"require-yield": "error",
"typescript/await-thenable": "warn",
// "typescript/ban-ts-comment": "error",
"typescript/consistent-type-imports": "error",
"typescript/no-array-constructor": "error",
// "typescript/consistent-type-imports": "error",
"typescript/no-array-delete": "warn",
"typescript/no-base-to-string": "warn",
"typescript/no-duplicate-enum-values": "error",
"typescript/no-duplicate-type-constituents": "warn",
"typescript/no-empty-object-type": "off",
"typescript/no-explicit-any": "off", // not safe but too many errors
"typescript/no-explicit-any": "off",
"typescript/no-extra-non-null-assertion": "error",
"typescript/no-floating-promises": "warn",
"typescript/no-for-in-array": "warn",
@@ -155,7 +93,7 @@
"typescript/no-misused-new": "error",
"typescript/no-misused-spread": "warn",
"typescript/no-namespace": "error",
"typescript/no-non-null-asserted-optional-chain": "off", // it's off now. but may turn it on.
"typescript/no-non-null-asserted-optional-chain": "off",
"typescript/no-redundant-type-constituents": "warn",
"typescript/no-require-imports": "off",
"typescript/no-this-alias": "error",
@@ -173,20 +111,18 @@
"typescript/triple-slash-reference": "error",
"typescript/unbound-method": "warn",
"unicorn/no-await-in-promise-methods": "warn",
"unicorn/no-empty-file": "off", // manually off bacause of existing warning. may turn it on in the future
"unicorn/no-empty-file": "off",
"unicorn/no-invalid-fetch-options": "warn",
"unicorn/no-invalid-remove-event-listener": "warn",
"unicorn/no-new-array": "off", // manually off bacause of existing warning. may turn it on in the future
"unicorn/no-new-array": "off",
"unicorn/no-single-promise-in-promise-methods": "warn",
"unicorn/no-thenable": "off", // manually off bacause of existing warning. may turn it on in the future
"unicorn/no-thenable": "off",
"unicorn/no-unnecessary-await": "warn",
"unicorn/no-useless-fallback-in-spread": "warn",
"unicorn/no-useless-length-check": "warn",
"unicorn/no-useless-spread": "off", // manually off bacause of existing warning. may turn it on in the future
"unicorn/no-useless-spread": "off",
"unicorn/prefer-set-size": "warn",
"unicorn/prefer-string-starts-ends-with": "warn",
"use-isnan": "error",
"valid-typeof": "error"
"unicorn/prefer-string-starts-ends-with": "warn"
},
"settings": {
"jsdoc": {

View File

@@ -1,13 +0,0 @@
diff --git a/dist/index.mjs b/dist/index.mjs
index 69ab1599c76801dc1167551b6fa283dded123466..f0af43bba7ad1196fe05338817e65b4ebda40955 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -477,7 +477,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
// src/get-model-path.ts
function getModelPath(modelId) {
- return modelId.includes("/") ? modelId : `models/${modelId}`;
+ return modelId?.includes("models/") ? modelId : `models/${modelId}`;
}
// src/google-generative-ai-options.ts

View File

@@ -0,0 +1,26 @@
diff --git a/dist/index.js b/dist/index.js
index cac044aab0255fa72f68b36ecd2c5b12d424c379..ad6ee8ecfc5cbc3ec43ba59a44eda21e8e4d353f 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -471,7 +471,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
// src/get-model-path.ts
function getModelPath(modelId) {
- return modelId.includes("/") ? modelId : `models/${modelId}`;
+ return modelId.includes("models/") ? modelId : `models/${modelId}`;
}
// src/google-generative-ai-options.ts
diff --git a/dist/index.mjs b/dist/index.mjs
index 0793085005d7968638d355f2f1e127939d965165..1c8bf852baf025d56dc35a0691eb95967de7e5c8 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -477,7 +477,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
// src/get-model-path.ts
function getModelPath(modelId) {
- return modelId.includes("/") ? modelId : `models/${modelId}`;
+ return modelId.includes("models/") ? modelId : `models/${modelId}`;
}
// src/google-generative-ai-options.ts

View File

@@ -0,0 +1,74 @@
diff --git a/dist/index.js b/dist/index.js
index 992c85ac6656e51c3471af741583533c5a7bf79f..83c05952a07aebb95fc6c62f9ddb8aa96b52ac0d 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -274,6 +274,7 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazyValidator)(
message: import_v42.z.object({
role: import_v42.z.literal("assistant").nullish(),
content: import_v42.z.string().nullish(),
+ reasoning_content: import_v42.z.string().nullish(),
tool_calls: import_v42.z.array(
import_v42.z.object({
id: import_v42.z.string().nullish(),
@@ -340,6 +341,7 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazyValidator)(
delta: import_v42.z.object({
role: import_v42.z.enum(["assistant"]).nullish(),
content: import_v42.z.string().nullish(),
+ reasoning_content: import_v42.z.string().nullish(),
tool_calls: import_v42.z.array(
import_v42.z.object({
index: import_v42.z.number(),
@@ -785,6 +787,13 @@ var OpenAIChatLanguageModel = class {
if (text != null && text.length > 0) {
content.push({ type: "text", text });
}
+ const reasoning = choice.message.reasoning_content;
+ if (reasoning != null && reasoning.length > 0) {
+ content.push({
+ type: 'reasoning',
+ text: reasoning
+ });
+ }
for (const toolCall of (_a = choice.message.tool_calls) != null ? _a : []) {
content.push({
type: "tool-call",
@@ -866,6 +875,7 @@ var OpenAIChatLanguageModel = class {
};
let metadataExtracted = false;
let isActiveText = false;
+ let isActiveReasoning = false;
const providerMetadata = { openai: {} };
return {
stream: response.pipeThrough(
@@ -923,6 +933,21 @@ var OpenAIChatLanguageModel = class {
return;
}
const delta = choice.delta;
+ const reasoningContent = delta.reasoning_content;
+ if (reasoningContent) {
+ if (!isActiveReasoning) {
+ controller.enqueue({
+ type: 'reasoning-start',
+ id: 'reasoning-0',
+ });
+ isActiveReasoning = true;
+ }
+ controller.enqueue({
+ type: 'reasoning-delta',
+ id: 'reasoning-0',
+ delta: reasoningContent,
+ });
+ }
if (delta.content != null) {
if (!isActiveText) {
controller.enqueue({ type: "text-start", id: "0" });
@@ -1035,6 +1060,9 @@ var OpenAIChatLanguageModel = class {
}
},
flush(controller) {
+ if (isActiveReasoning) {
+ controller.enqueue({ type: 'reasoning-end', id: 'reasoning-0' });
+ }
if (isActiveText) {
controller.enqueue({ type: "text-end", id: "0" });
}

View File

@@ -1,24 +1,24 @@
diff --git a/sdk.mjs b/sdk.mjs
index 461e9a2ba246778261108a682762ffcf26f7224e..44bd667d9f591969d36a105ba5eb8b478c738dd8 100644
index 10162e5b1624f8ce667768943347a6e41089ad2f..32568ae08946590e382270c88d85fba81187568e 100755
--- a/sdk.mjs
+++ b/sdk.mjs
@@ -6215,7 +6215,7 @@ function createAbortController(maxListeners = DEFAULT_MAX_LISTENERS) {
@@ -6213,7 +6213,7 @@ function createAbortController(maxListeners = DEFAULT_MAX_LISTENERS) {
}
// ../src/transport/ProcessTransport.ts
-import { spawn } from "child_process";
+import { fork } from "child_process";
import { createInterface } from "readline";
// ../src/utils/fsOperations.ts
@@ -6473,14 +6473,11 @@ class ProcessTransport {
@@ -6487,14 +6487,11 @@ class ProcessTransport {
const errorMessage = isNativeBinary(pathToClaudeCodeExecutable) ? `Claude Code native binary not found at ${pathToClaudeCodeExecutable}. Please ensure Claude Code is installed via native installer or specify a valid path with options.pathToClaudeCodeExecutable.` : `Claude Code executable not found at ${pathToClaudeCodeExecutable}. Is options.pathToClaudeCodeExecutable set?`;
throw new ReferenceError(errorMessage);
}
- const isNative = isNativeBinary(pathToClaudeCodeExecutable);
- const spawnCommand = isNative ? pathToClaudeCodeExecutable : executable;
- const spawnArgs = isNative ? args : [...executableArgs, pathToClaudeCodeExecutable, ...args];
- this.logForDebugging(isNative ? `Spawning Claude Code native binary: ${pathToClaudeCodeExecutable} ${args.join(" ")}` : `Spawning Claude Code process: ${executable} ${[...executableArgs, pathToClaudeCodeExecutable, ...args].join(" ")}`);
- const spawnArgs = isNative ? [...executableArgs, ...args] : [...executableArgs, pathToClaudeCodeExecutable, ...args];
- this.logForDebugging(isNative ? `Spawning Claude Code native binary: ${spawnCommand} ${spawnArgs.join(" ")}` : `Spawning Claude Code process: ${spawnCommand} ${spawnArgs.join(" ")}`);
+ this.logForDebugging(`Forking Claude Code Node.js process: ${pathToClaudeCodeExecutable} ${args.join(" ")}`);
const stderrMode = env.DEBUG || stderr ? "pipe" : "ignore";
- this.child = spawn(spawnCommand, spawnArgs, {

View File

@@ -1,71 +0,0 @@
diff --git a/dist/utils/tiktoken.cjs b/dist/utils/tiktoken.cjs
index 973b0d0e75aeaf8de579419af31b879b32975413..f23c7caa8b9dc8bd404132725346a4786f6b278b 100644
--- a/dist/utils/tiktoken.cjs
+++ b/dist/utils/tiktoken.cjs
@@ -1,25 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodingForModel = exports.getEncoding = void 0;
-const lite_1 = require("js-tiktoken/lite");
const async_caller_js_1 = require("./async_caller.cjs");
const cache = {};
const caller = /* #__PURE__ */ new async_caller_js_1.AsyncCaller({});
async function getEncoding(encoding) {
- if (!(encoding in cache)) {
- cache[encoding] = caller
- .fetch(`https://tiktoken.pages.dev/js/${encoding}.json`)
- .then((res) => res.json())
- .then((data) => new lite_1.Tiktoken(data))
- .catch((e) => {
- delete cache[encoding];
- throw e;
- });
- }
- return await cache[encoding];
+ throw new Error("TikToken Not implemented");
}
exports.getEncoding = getEncoding;
async function encodingForModel(model) {
- return getEncoding((0, lite_1.getEncodingNameForModel)(model));
+ throw new Error("TikToken Not implemented");
}
exports.encodingForModel = encodingForModel;
diff --git a/dist/utils/tiktoken.js b/dist/utils/tiktoken.js
index 8e41ee6f00f2f9c7fa2c59fa2b2f4297634b97aa..aa5f314a6349ad0d1c5aea8631a56aad099176e0 100644
--- a/dist/utils/tiktoken.js
+++ b/dist/utils/tiktoken.js
@@ -1,20 +1,9 @@
-import { Tiktoken, getEncodingNameForModel, } from "js-tiktoken/lite";
import { AsyncCaller } from "./async_caller.js";
const cache = {};
const caller = /* #__PURE__ */ new AsyncCaller({});
export async function getEncoding(encoding) {
- if (!(encoding in cache)) {
- cache[encoding] = caller
- .fetch(`https://tiktoken.pages.dev/js/${encoding}.json`)
- .then((res) => res.json())
- .then((data) => new Tiktoken(data))
- .catch((e) => {
- delete cache[encoding];
- throw e;
- });
- }
- return await cache[encoding];
+ throw new Error("TikToken Not implemented");
}
export async function encodingForModel(model) {
- return getEncoding(getEncodingNameForModel(model));
+ throw new Error("TikToken Not implemented");
}
diff --git a/package.json b/package.json
index 36072aecf700fca1bc49832a19be832eca726103..90b8922fba1c3d1b26f78477c891b07816d6238a 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,6 @@
"ansi-styles": "^5.0.0",
"camelcase": "6",
"decamelize": "1.2.0",
- "js-tiktoken": "^1.0.12",
"langsmith": ">=0.2.8 <0.4.0",
"mustache": "^4.2.0",
"p-queue": "^6.6.2",

View File

@@ -0,0 +1,68 @@
diff --git a/dist/utils/tiktoken.cjs b/dist/utils/tiktoken.cjs
index c5b41f121d2e3d24c3a4969e31fa1acffdcad3b9..ec724489dcae79ee6c61acf2d4d84bd19daef036 100644
--- a/dist/utils/tiktoken.cjs
+++ b/dist/utils/tiktoken.cjs
@@ -1,6 +1,5 @@
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
const require_utils_async_caller = require('./async_caller.cjs');
-const js_tiktoken_lite = require_rolldown_runtime.__toESM(require("js-tiktoken/lite"));
//#region src/utils/tiktoken.ts
var tiktoken_exports = {};
@@ -11,14 +10,10 @@ require_rolldown_runtime.__export(tiktoken_exports, {
const cache = {};
const caller = /* @__PURE__ */ new require_utils_async_caller.AsyncCaller({});
async function getEncoding(encoding) {
- if (!(encoding in cache)) cache[encoding] = caller.fetch(`https://tiktoken.pages.dev/js/${encoding}.json`).then((res) => res.json()).then((data) => new js_tiktoken_lite.Tiktoken(data)).catch((e) => {
- delete cache[encoding];
- throw e;
- });
- return await cache[encoding];
+ throw new Error("TikToken Not implemented");
}
async function encodingForModel(model) {
- return getEncoding((0, js_tiktoken_lite.getEncodingNameForModel)(model));
+ throw new Error("TikToken Not implemented");
}
//#endregion
diff --git a/dist/utils/tiktoken.js b/dist/utils/tiktoken.js
index 641acca03cb92f04a6fa5c9c31f1880ce635572e..707389970ad957aa0ff20ef37fa8dd2875be737c 100644
--- a/dist/utils/tiktoken.js
+++ b/dist/utils/tiktoken.js
@@ -1,6 +1,5 @@
import { __export } from "../_virtual/rolldown_runtime.js";
import { AsyncCaller } from "./async_caller.js";
-import { Tiktoken, getEncodingNameForModel } from "js-tiktoken/lite";
//#region src/utils/tiktoken.ts
var tiktoken_exports = {};
@@ -11,14 +10,10 @@ __export(tiktoken_exports, {
const cache = {};
const caller = /* @__PURE__ */ new AsyncCaller({});
async function getEncoding(encoding) {
- if (!(encoding in cache)) cache[encoding] = caller.fetch(`https://tiktoken.pages.dev/js/${encoding}.json`).then((res) => res.json()).then((data) => new Tiktoken(data)).catch((e) => {
- delete cache[encoding];
- throw e;
- });
- return await cache[encoding];
+ throw new Error("TikToken Not implemented");
}
async function encodingForModel(model) {
- return getEncoding(getEncodingNameForModel(model));
+ throw new Error("TikToken Not implemented");
}
//#endregion
diff --git a/package.json b/package.json
index a24f8fc61de58526051999260f2ebee5f136354b..e885359e8966e7730c51772533ce37e01edb3046 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,6 @@
"ansi-styles": "^5.0.0",
"camelcase": "6",
"decamelize": "1.2.0",
- "js-tiktoken": "^1.0.12",
"langsmith": "^0.3.64",
"mustache": "^4.2.0",
"p-queue": "^6.6.2",

View File

@@ -1,19 +0,0 @@
diff --git a/dist/embeddings.js b/dist/embeddings.js
index 1f8154be3e9c22442a915eb4b85fa6d2a21b0d0c..dc13ef4a30e6c282824a5357bcee9bd0ae222aab 100644
--- a/dist/embeddings.js
+++ b/dist/embeddings.js
@@ -214,10 +214,12 @@ export class OpenAIEmbeddings extends Embeddings {
* @returns Promise that resolves to an embedding for the document.
*/
async embedQuery(text) {
+ const isBaiduCloud = this.clientConfig.baseURL.includes('baidubce.com')
+ const input = this.stripNewLines ? text.replace(/\n/g, ' ') : text
const params = {
model: this.model,
- input: this.stripNewLines ? text.replace(/\n/g, " ") : text,
- };
+ input: isBaiduCloud ? [input] : input
+ }
if (this.dimensions) {
params.dimensions = this.dimensions;
}

View File

@@ -0,0 +1,17 @@
diff --git a/dist/embeddings.js b/dist/embeddings.js
index 6f4b928d3e4717309382e1b5c2e31ab5bc6c5af0..bc79429c88a6d27d4997a2740c4d8ae0707f5991 100644
--- a/dist/embeddings.js
+++ b/dist/embeddings.js
@@ -94,9 +94,11 @@ var OpenAIEmbeddings = class extends Embeddings {
* @returns Promise that resolves to an embedding for the document.
*/
async embedQuery(text) {
+ const isBaiduCloud = this.clientConfig.baseURL.includes('baidubce.com');
+ const input = this.stripNewLines ? text.replace(/\n/g, " ") : text
const params = {
model: this.model,
- input: this.stripNewLines ? text.replace(/\n/g, " ") : text
+ input: isBaiduCloud ? [input] : input
};
if (this.dimensions) params.dimensions = this.dimensions;
if (this.encodingFormat) params.encoding_format = this.encodingFormat;

View File

@@ -7,11 +7,10 @@ This file provides guidance to AI coding assistants when working with code in th
- **Keep it clear**: Write code that is easy to read, maintain, and explain.
- **Match the house style**: Reuse existing patterns, naming, and conventions.
- **Search smart**: Prefer `ast-grep` for semantic queries; fall back to `rg`/`grep` when needed.
- **Build with HeroUI**: Use HeroUI for every new UI component; never add `antd` or `styled-components`.
- **Log centrally**: Route all logging through `loggerService` with the right context—no `console.log`.
- **Research via subagent**: Lean on `subagent` for external docs, APIs, news, and references.
- **Seek review**: Ask a human developer to review substantial changes before merging.
- **Commit in rhythm**: Keep commits small, conventional, and emoji-tagged.
- **Always propose before executing**: Before making any changes, clearly explain your planned approach and wait for explicit user approval to ensure alignment and prevent unwanted modifications.
- **Write conventional commits**: Commit small, focused changes using Conventional Commit messages (e.g., `feat:`, `fix:`, `refactor:`, `docs:`).
## Development Commands
@@ -40,7 +39,6 @@ This file provides guidance to AI coding assistants when working with code in th
- **Services** (`src/main/services/`): MCPService, KnowledgeService, WindowService, etc.
- **Build System**: Electron-Vite with experimental rolldown-vite, yarn workspaces.
- **State Management**: Redux Toolkit (`src/renderer/src/store/`) for predictable state.
- **UI Components**: HeroUI (`@heroui/*`) for all new UI elements.
### Logging
```typescript

View File

@@ -77,7 +77,7 @@ Please review the following critical information before submitting your Pull Req
Our core team is currently focused on significant architectural updates that involve these data structures. To ensure stability and focus during this period, contributions of this nature will be temporarily managed internally.
* **PRs that require changes to Redux state shape or IndexedDB schemas will be closed.**
* **This restriction is temporary and will be lifted with the release of `v2.0.0`.** You can track the progress of `v2.0.0` and its related discussions on issue [#10162](https://github.com/YOUR_ORG/YOUR_REPO/issues/10162) (please replace with your actual repo link).
* **This restriction is temporary and will be lifted with the release of `v2.0.0`.** You can track the progress of `v2.0.0` and its related discussions on issue [#10162](https://github.com/CherryHQ/cherry-studio/pull/10162).
We highly encourage contributions for:
* Bug fixes 🐞

View File

@@ -82,7 +82,7 @@ Cherry Studio is a desktop client that supports multiple LLM providers, availabl
1. **Diverse LLM Provider Support**:
- ☁️ Major LLM Cloud Services: OpenAI, Gemini, Anthropic, and more
- 🔗 AI Web Service Integration: Claude, Perplexity, Poe, and others
- 🔗 AI Web Service Integration: Claude, Perplexity, [Poe](https://poe.com/), and others
- 💻 Local Model Support with Ollama, LM Studio
2. **AI Assistants & Conversations**:
@@ -238,10 +238,6 @@ The Enterprise Edition addresses core challenges in team collaboration by centra
## ✨ Online Demo
> 🚧 **Public Beta Notice**
>
> The Enterprise Edition is currently in its early public beta stage, and we are actively iterating and optimizing its features. We are aware that it may not be perfectly stable yet. If you encounter any issues or have valuable suggestions during your trial, we would be very grateful if you could contact us via email to provide feedback.
**🔗 [Cherry Studio Enterprise](https://www.cherry-ai.com/enterprise)**
## Version Comparison
@@ -249,7 +245,7 @@ The Enterprise Edition addresses core challenges in team collaboration by centra
| Feature | Community Edition | Enterprise Edition |
| :---------------- | :----------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
| **Open Source** | ✅ Yes | ⭕️ Partially released to customers |
| **Cost** | Free for Personal Use / Commercial License | Buyout / Subscription Fee |
| **Cost** | [AGPL-3.0 License](https://github.com/CherryHQ/cherry-studio?tab=AGPL-3.0-1-ov-file) | Buyout / Subscription Fee |
| **Admin Backend** | — | ● Centralized **Model** Access<br>**Employee** Management<br>● Shared **Knowledge Base**<br>**Access** Control<br>**Data** Backup |
| **Server** | — | ✅ Dedicated Private Deployment |
@@ -262,8 +258,12 @@ We believe the Enterprise Edition will become your team's AI productivity engine
# 🔗 Related Projects
- [new-api](https://github.com/QuantumNous/new-api): The next-generation LLM gateway and AI asset management system supports multiple languages.
- [one-api](https://github.com/songquanpeng/one-api): LLM API management and distribution system supporting mainstream models like OpenAI, Azure, and Anthropic. Features a unified API interface, suitable for key management and secondary distribution.
- [Poe](https://poe.com/): Poe gives you access to the best AI, all in one place. Explore GPT-5, Claude Opus 4.1, DeepSeek-R1, Veo 3, ElevenLabs, and millions of others.
- [ublacklist](https://github.com/iorate/ublacklist): Blocks specific sites from appearing in Google search results
# 🚀 Contributors

View File

@@ -21,7 +21,11 @@
"quoteStyle": "single"
}
},
"files": { "ignoreUnknown": false },
"files": {
"ignoreUnknown": false,
"includes": ["**", "!**/.claude/**"],
"maxSize": 2097152
},
"formatter": {
"attributePosition": "auto",
"bracketSameLine": false,

View File

@@ -1,21 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"aliases": {
"components": "@renderer/ui/third-party",
"hooks": "@renderer/hooks",
"lib": "@renderer/lib",
"ui": "@renderer/ui",
"utils": "@renderer/utils"
},
"iconLibrary": "lucide",
"rsc": false,
"style": "new-york",
"tailwind": {
"baseColor": "zinc",
"config": "",
"css": "src/renderer/src/assets/styles/tailwind.css",
"cssVariables": true,
"prefix": ""
},
"tsx": true
}

View File

@@ -81,7 +81,7 @@ git commit --signoff -m "Your commit message"
我们的核心团队目前正专注于涉及这些数据结构的关键架构更新和基础工作。为确保在此期间的稳定性与专注,此类贡献将暂时由内部进行管理。
* **需要更改 Redux 状态结构或 IndexedDB schema 的 PR 将会被关闭。**
* **此限制是临时性的,并将在 `v2.0.0` 版本发布后解除。** 您可以通过 Issue [#10162](https://github.com/YOUR_ORG/YOUR_REPO/issues/10162) (请替换为您的实际仓库链接) 跟踪 `v2.0.0` 的进展及相关讨论。
* **此限制是临时性的,并将在 `v2.0.0` 版本发布后解除。** 您可以通过 Issue [#10162](https://github.com/CherryHQ/cherry-studio/pull/10162) 跟踪 `v2.0.0` 的进展及相关讨论。
我们非常鼓励以下类型的贡献:
* 错误修复 🐞

View File

@@ -18,13 +18,13 @@ yarn
### Setup Node.js
Download and install [Node.js v20.x.x](https://nodejs.org/en/download)
Download and install [Node.js v22.x.x](https://nodejs.org/en/download)
### Setup Yarn
```bash
corepack enable
corepack prepare yarn@4.6.0 --activate
corepack prepare yarn@4.9.1 --activate
```
### Install Dependencies

View File

@@ -11,6 +11,8 @@ The Test Plan is divided into the RC channel and the Beta channel, with the foll
Users can enable the "Test Plan" and select the version channel in the software's `Settings` > `About`. Please note that the versions in the "Test Plan" cannot guarantee data consistency, so be sure to back up your data before using them.
After enabling the RC channel or Beta channel, if a stable version is released, users will still be upgraded to the stable version.
Users are welcome to submit issues or provide feedback through other channels for any bugs encountered during testing. Your feedback is very important to us.
## Developer Guide

View File

@@ -11,6 +11,8 @@
用户可以在软件的`设置`-`关于`中,开启“测试计划”并选择版本通道。请注意“测试计划”的版本无法保证数据的一致性,请使用前一定要备份数据。
用户选择RC版通道或Beta版通道后若发布了正式版仍旧会升级到正式版。
用户在测试过程中发现的BUG欢迎提交issue或通过其他渠道反馈。用户的反馈对我们非常重要。
## 开发者指南

View File

@@ -21,6 +21,8 @@ files:
- "**/*"
- "!**/{.vscode,.yarn,.yarn-lock,.github,.cursorrules,.prettierrc}"
- "!electron.vite.config.{js,ts,mjs,cjs}}"
- "!.*"
- "!components.json"
- "!**/{.eslintignore,.eslintrc.js,.eslintrc.json,.eslintcache,root.eslint.config.js,eslint.config.js,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,eslint.config.mjs,dev-app-update.yml,CHANGELOG.md,README.md,biome.jsonc}"
- "!**/{.env,.env.*,.npmrc,pnpm-lock.yaml}"
- "!**/{tsconfig.json,tsconfig.tsbuildinfo,tsconfig.node.json,tsconfig.web.json}"
@@ -64,6 +66,12 @@ asarUnpack:
- resources/**
- "**/*.{metal,exp,lib}"
- "node_modules/@img/sharp-libvips-*/**"
# copy from node_modules/claude-code-plugins/plugins to resources/data/claude-code-pluginso
extraResources:
- from: "./node_modules/claude-code-plugins/plugins/"
to: "claude-code-plugins"
win:
executableName: Cherry Studio
artifactName: ${productName}-${version}-${arch}-setup.${ext}
@@ -127,60 +135,50 @@ artifactBuildCompleted: scripts/artifact-build-completed.js
releaseInfo:
releaseNotes: |
<!--LANG:en-->
What's New in v1.7.0-beta.2
What's New in v1.7.0-beta.5
New Features:
- Session Settings: Manage session-specific settings and model configurations independently
- Notes Full-Text Search: Search across all notes with match highlighting
- Built-in DiDi MCP Server: Integration with DiDi ride-hailing services (China only)
- Intel OV OCR: Hardware-accelerated OCR using Intel NPU
- Auto-start API Server: Automatically starts when agents exist
- MCPRouter Provider: Added MCPRouter provider integration with token management and server synchronization
- MCP Marketplace: Enhanced MCP server discovery and management with multi-provider marketplace support
- Agent Permission Mode Display: Visual permission mode cards in empty session states
- Assistant Subscription Settings: Added subscription URL management in assistant presets
Improvements:
- Agent model selection now requires explicit user choice
- Added Mistral AI provider support
- Added NewAPI generic provider support
- Improved navbar layout consistency across different modes
- Enhanced chat component responsiveness
- Better code block display on small screens
- Updated OVMS to 2025.3 official release
- Added Greek language support
- UI Optimization: Sidebar tooltip placement improved on macOS to avoid overlapping window controls
- MCP Server Logos: Display server logos in Agent settings tooling section
- Long Command Handling: Bash command tags now auto-truncate (hover to view full command for commands over 100 chars)
- MCP OAuth Callback: Fixed callback page hanging and added multilingual support (10 languages)
- Error Display: Improved error block display order for better readability
- Plugin Browser: Centered tab alignment for better visual consistency
Bug Fixes:
- Fixed GitHub Copilot gpt-5-codex streaming issues
- Fixed assistant creation failures
- Fixed translate auto-copy functionality
- Fixed miniapps external link opening
- Fixed message layout and overflow issues
- Fixed API key parsing to preserve spaces
- Fixed agent display in different navbar layouts
- Fixed Agent sessions not inheriting allowed_tools configuration
- Fixed Gemini endpoint thinking budget spelling error
- Fixed MCP card description text overflow
- Fixed unnecessary message timestamp updates on UI-only state changes
- Updated dependencies: Bun to 1.3.1, uv to 0.9.5
<!--LANG:zh-CN-->
v1.7.0-beta.2 新特性
v1.7.0-beta.5 新特性
新功能:
- 会话设置:独立管理会话特定的设置和模型配置
- 笔记全文搜索:跨所有笔记搜索并高亮匹配内容
- 内置滴滴 MCP 服务器:集成滴滴打车服务(仅限中国地区)
- Intel OV OCR使用 Intel NPU 的硬件加速 OCR
- 自动启动 API 服务器:当存在 Agent 时自动启动
- MCPRouter 提供商:新增 MCPRouter 提供商集成,支持 token 管理和服务器同步
- MCP 市场:增强 MCP 服务器发现和管理功能,支持多提供商市场
- Agent 权限模式展示:空会话状态显示可视化权限模式卡片
- 助手订阅设置:在助手预设中添加订阅 URL 管理功能
改进:
- Agent 模型选择现在需要用户显式选择
- 添加 Mistral AI 提供商支持
- 添加 NewAPI 通用提供商支持
- 改进不同模式下的导航栏布局一致性
- 增强聊天组件响应式设计
- 优化小屏幕代码块显示
- 更新 OVMS 至 2025.3 正式版
- 添加希腊语支持
- UI 优化macOS 上侧边栏工具提示位置优化,避免与窗口控制按钮重叠
- MCP 服务器标志:在 Agent 设置工具部分显示服务器 logo
- 长命令处理Bash 命令标签自动截断(超过 100 字符时悬停查看完整内容)
- MCP OAuth 回调修复回调页面挂起问题并添加多语言支持10 种语言)
- 错误信息展示:改进错误块显示顺序,提高可读性
- 插件浏览器:标签页居中对齐,视觉效果更统一
问题修复:
- 修复 GitHub Copilot gpt-5-codex 流式传输问题
- 修复助手创建失败
- 修复翻译自动复制功能
- 修复小程序外部链接打开
- 修复消息布局和溢出问题
- 修复 API 密钥解析以保留空格
- 修复不同导航栏布局中的 Agent 显示
- 修复 Agent 会话未继承 allowed_tools 配置
- 修复 Gemini 端点 thinking budget 拼写错误
- 修复 MCP 卡片描述文本溢出问题
- 修复仅 UI 状态变化时消息时间戳不必要的更新
- 依赖更新Bun 升级到 1.3.1uv 升级到 0.9.5
<!--LANG:END-->

View File

@@ -1,6 +1,6 @@
{
"name": "CherryStudio",
"version": "1.7.0-beta.2",
"version": "1.7.0-beta.3",
"private": true,
"description": "A powerful AI assistant for producer.",
"main": "./out/main/index.js",
@@ -78,20 +78,25 @@
"release:aicore": "yarn workspace @cherrystudio/ai-core version patch --immediate && yarn workspace @cherrystudio/ai-core npm publish --access public"
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "patch:@anthropic-ai/claude-agent-sdk@npm%3A0.1.1#~/.yarn/patches/@anthropic-ai-claude-agent-sdk-npm-0.1.1-d937b73fed.patch",
"@anthropic-ai/claude-agent-sdk": "patch:@anthropic-ai/claude-agent-sdk@npm%3A0.1.25#~/.yarn/patches/@anthropic-ai-claude-agent-sdk-npm-0.1.25-08bbabb5d3.patch",
"@libsql/client": "0.14.0",
"@libsql/win32-x64-msvc": "^0.4.7",
"@napi-rs/system-ocr": "patch:@napi-rs/system-ocr@npm%3A1.0.2#~/.yarn/patches/@napi-rs-system-ocr-npm-1.0.2-59e7a78e8b.patch",
"@paymoapp/electron-shutdown-handler": "^1.1.2",
"@strongtz/win32-arm64-msvc": "^0.4.7",
"express": "^5.1.0",
"font-list": "^2.0.0",
"graceful-fs": "^4.2.11",
"gray-matter": "^4.0.3",
"js-yaml": "^4.1.0",
"jsdom": "26.1.0",
"node-stream-zip": "^1.15.0",
"officeparser": "^4.2.0",
"os-proxy-config": "^1.1.2",
"qrcode.react": "^4.2.0",
"selection-hook": "^1.0.12",
"sharp": "^0.34.3",
"socket.io": "^4.8.1",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"tesseract.js": "patch:tesseract.js@npm%3A6.0.1#~/.yarn/patches/tesseract.js-npm-6.0.1-2562a7e46d.patch",
@@ -101,17 +106,17 @@
"@agentic/exa": "^7.3.3",
"@agentic/searxng": "^7.3.3",
"@agentic/tavily": "^7.3.3",
"@ai-sdk/amazon-bedrock": "^3.0.35",
"@ai-sdk/google-vertex": "^3.0.40",
"@ai-sdk/huggingface": "patch:@ai-sdk/huggingface@npm%3A0.0.4#~/.yarn/patches/@ai-sdk-huggingface-npm-0.0.4-8080836bc1.patch",
"@ai-sdk/mistral": "^2.0.19",
"@ai-sdk/perplexity": "^2.0.13",
"@ai-sdk/amazon-bedrock": "^3.0.53",
"@ai-sdk/google-vertex": "^3.0.61",
"@ai-sdk/huggingface": "patch:@ai-sdk/huggingface@npm%3A0.0.8#~/.yarn/patches/@ai-sdk-huggingface-npm-0.0.8-d4d0aaac93.patch",
"@ai-sdk/mistral": "^2.0.23",
"@ai-sdk/perplexity": "^2.0.17",
"@ant-design/v5-patch-for-react-19": "^1.0.3",
"@anthropic-ai/sdk": "^0.41.0",
"@anthropic-ai/vertex-sdk": "patch:@anthropic-ai/vertex-sdk@npm%3A0.11.4#~/.yarn/patches/@anthropic-ai-vertex-sdk-npm-0.11.4-c19cb41edb.patch",
"@aws-sdk/client-bedrock": "^3.840.0",
"@aws-sdk/client-bedrock-runtime": "^3.840.0",
"@aws-sdk/client-s3": "^3.840.0",
"@aws-sdk/client-bedrock": "^3.910.0",
"@aws-sdk/client-bedrock-runtime": "^3.910.0",
"@aws-sdk/client-s3": "^3.910.0",
"@biomejs/biome": "2.2.4",
"@cherrystudio/ai-core": "workspace:^1.0.0-alpha.18",
"@cherrystudio/embedjs": "^0.1.31",
@@ -142,9 +147,10 @@
"@eslint/js": "^9.22.0",
"@google/genai": "patch:@google/genai@npm%3A1.0.1#~/.yarn/patches/@google-genai-npm-1.0.1-e26f0f9af7.patch",
"@hello-pangea/dnd": "^18.0.1",
"@heroui/react": "^2.8.3",
"@kangfenmao/keyv-storage": "^0.1.0",
"@langchain/community": "^0.3.50",
"@langchain/community": "^1.0.0",
"@langchain/core": "patch:@langchain/core@npm%3A1.0.2#~/.yarn/patches/@langchain-core-npm-1.0.2-183ef83fe4.patch",
"@langchain/openai": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
"@mistralai/mistralai": "^1.7.5",
"@modelcontextprotocol/sdk": "^1.17.5",
"@mozilla/readability": "^0.6.0",
@@ -195,6 +201,7 @@
"@types/fs-extra": "^11",
"@types/he": "^1",
"@types/html-to-text": "^9",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.17.5",
"@types/markdown-it": "^14",
"@types/md5": "^2.3.5",
@@ -224,7 +231,7 @@
"@viz-js/lang-dot": "^1.0.5",
"@viz-js/viz": "^3.14.0",
"@xyflow/react": "^12.4.4",
"ai": "^5.0.68",
"ai": "^5.0.90",
"antd": "patch:antd@npm%3A5.27.0#~/.yarn/patches/antd-npm-5.27.0-aa91c36546.patch",
"archiver": "^7.0.1",
"async-mutex": "^0.5.0",
@@ -234,6 +241,7 @@
"check-disk-space": "3.4.0",
"cheerio": "^1.1.2",
"chokidar": "^4.0.3",
"claude-code-plugins": "1.0.3",
"cli-progress": "^3.12.0",
"clsx": "^2.1.1",
"code-inspector-plugin": "^0.20.14",
@@ -340,6 +348,7 @@
"striptags": "^3.2.0",
"styled-components": "^6.1.11",
"swr": "^2.3.6",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.13",
"tar": "^7.4.3",
"tiny-pinyin": "^1.3.2",
@@ -365,12 +374,11 @@
"zod": "^4.1.5"
},
"resolutions": {
"@smithy/types": "4.7.1",
"@codemirror/language": "6.11.3",
"@codemirror/lint": "6.8.5",
"@codemirror/view": "6.38.1",
"@langchain/core@npm:^0.3.26": "patch:@langchain/core@npm%3A0.3.44#~/.yarn/patches/@langchain-core-npm-0.3.44-41d5c3cb0a.patch",
"@langchain/openai@npm:^0.3.16": "patch:@langchain/openai@npm%3A0.3.16#~/.yarn/patches/@langchain-openai-npm-0.3.16-e525b59526.patch",
"@langchain/openai@npm:>=0.1.0 <0.4.0": "patch:@langchain/openai@npm%3A0.3.16#~/.yarn/patches/@langchain-openai-npm-0.3.16-e525b59526.patch",
"@langchain/core@npm:^0.3.26": "patch:@langchain/core@npm%3A1.0.2#~/.yarn/patches/@langchain-core-npm-1.0.2-183ef83fe4.patch",
"app-builder-lib@npm:26.0.13": "patch:app-builder-lib@npm%3A26.0.13#~/.yarn/patches/app-builder-lib-npm-26.0.13-a064c9e1d0.patch",
"app-builder-lib@npm:26.0.15": "patch:app-builder-lib@npm%3A26.0.15#~/.yarn/patches/app-builder-lib-npm-26.0.15-360e5b0476.patch",
"atomically@npm:^1.7.0": "patch:atomically@npm%3A1.7.0#~/.yarn/patches/atomically-npm-1.7.0-e742e5293b.patch",
@@ -386,14 +394,21 @@
"undici": "6.21.2",
"vite": "npm:rolldown-vite@7.1.5",
"tesseract.js@npm:*": "patch:tesseract.js@npm%3A6.0.1#~/.yarn/patches/tesseract.js-npm-6.0.1-2562a7e46d.patch",
"@ai-sdk/google@npm:2.0.20": "patch:@ai-sdk/google@npm%3A2.0.20#~/.yarn/patches/@ai-sdk-google-npm-2.0.20-b9102f9d54.patch",
"@ai-sdk/google@npm:2.0.23": "patch:@ai-sdk/google@npm%3A2.0.23#~/.yarn/patches/@ai-sdk-google-npm-2.0.23-81682e07b0.patch",
"@ai-sdk/openai@npm:^2.0.52": "patch:@ai-sdk/openai@npm%3A2.0.52#~/.yarn/patches/@ai-sdk-openai-npm-2.0.52-b36d949c76.patch",
"@img/sharp-darwin-arm64": "0.34.3",
"@img/sharp-darwin-x64": "0.34.3",
"@img/sharp-linux-arm": "0.34.3",
"@img/sharp-linux-arm64": "0.34.3",
"@img/sharp-linux-x64": "0.34.3",
"@img/sharp-win32-x64": "0.34.3",
"openai@npm:5.12.2": "npm:@cherrystudio/openai@6.5.0"
"openai@npm:5.12.2": "npm:@cherrystudio/openai@6.5.0",
"@langchain/openai@npm:>=0.1.0 <0.6.0": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
"@langchain/openai@npm:^0.3.16": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
"@langchain/openai@npm:>=0.2.0 <0.7.0": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
"@ai-sdk/google@npm:2.0.30": "patch:@ai-sdk/google@npm%3A2.0.30#~/.yarn/patches/@ai-sdk-google-npm-2.0.30-3b31632362.patch",
"@ai-sdk/openai@npm:2.0.64": "patch:@ai-sdk/openai@npm%3A2.0.64#~/.yarn/patches/@ai-sdk-openai-npm-2.0.64-48f99f5bf3.patch",
"@ai-sdk/openai@npm:^2.0.42": "patch:@ai-sdk/openai@npm%3A2.0.64#~/.yarn/patches/@ai-sdk-openai-npm-2.0.64-48f99f5bf3.patch"
},
"packageManager": "yarn@4.9.1",
"lint-staged": {

View File

@@ -36,14 +36,14 @@
"ai": "^5.0.26"
},
"dependencies": {
"@ai-sdk/anthropic": "^2.0.27",
"@ai-sdk/azure": "^2.0.49",
"@ai-sdk/deepseek": "^1.0.23",
"@ai-sdk/openai": "^2.0.48",
"@ai-sdk/openai-compatible": "^1.0.22",
"@ai-sdk/anthropic": "^2.0.43",
"@ai-sdk/azure": "^2.0.66",
"@ai-sdk/deepseek": "^1.0.27",
"@ai-sdk/openai": "patch:@ai-sdk/openai@npm%3A2.0.64#~/.yarn/patches/@ai-sdk-openai-npm-2.0.64-48f99f5bf3.patch",
"@ai-sdk/openai-compatible": "^1.0.26",
"@ai-sdk/provider": "^2.0.0",
"@ai-sdk/provider-utils": "^3.0.12",
"@ai-sdk/xai": "^2.0.26",
"@ai-sdk/provider-utils": "^3.0.16",
"@ai-sdk/xai": "^2.0.31",
"zod": "^4.1.5"
},
"devDependencies": {

View File

@@ -2,7 +2,7 @@
* 中间件管理器
* 专注于 AI SDK 中间件的管理,与插件系统分离
*/
import { LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { LanguageModelV2Middleware } from '@ai-sdk/provider'
/**
* 创建中间件列表

View File

@@ -1,7 +1,7 @@
/**
* 中间件系统类型定义
*/
import { LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { LanguageModelV2Middleware } from '@ai-sdk/provider'
/**
* 具名中间件接口

View File

@@ -2,7 +2,7 @@
* 模型包装工具函数
* 用于将中间件应用到LanguageModel上
*/
import { LanguageModelV2, LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { LanguageModelV2, LanguageModelV2Middleware } from '@ai-sdk/provider'
import { wrapLanguageModel } from 'ai'
/**

View File

@@ -5,7 +5,7 @@
* 集成了来自 ModelCreator 的特殊处理逻辑
*/
import { EmbeddingModelV2, ImageModelV2, LanguageModelV2, LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { EmbeddingModelV2, ImageModelV2, LanguageModelV2, LanguageModelV2Middleware } from '@ai-sdk/provider'
import { wrapModelWithMiddlewares } from '../middleware/wrapper'
import { DEFAULT_SEPARATOR, globalRegistryManagement } from '../providers/RegistryManagement'

View File

@@ -1,7 +1,7 @@
/**
* Creation 模块类型定义
*/
import { LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { ProviderId, ProviderSettingsMap } from '../providers/types'

View File

@@ -1,4 +1,4 @@
import { ExtractProviderOptions, ProviderOptionsMap, TypedProviderOptions } from './types'
import type { ExtractProviderOptions, ProviderOptionsMap, TypedProviderOptions } from './types'
/**
* 创建特定供应商的选项

View File

@@ -10,7 +10,7 @@ import type { AiRequestContext } from '../../types'
import { StreamEventManager } from './StreamEventManager'
import { type TagConfig, TagExtractor } from './tagExtraction'
import { ToolExecutor } from './ToolExecutor'
import { PromptToolUseConfig, ToolUseResult } from './type'
import type { PromptToolUseConfig, ToolUseResult } from './type'
/**
* 工具使用标签配置

View File

@@ -1,6 +1,6 @@
import { ToolSet } from 'ai'
import type { ToolSet } from 'ai'
import { AiRequestContext } from '../..'
import type { AiRequestContext } from '../..'
/**
* 解析结果类型

View File

@@ -1,10 +1,11 @@
import { anthropic } from '@ai-sdk/anthropic'
import { google } from '@ai-sdk/google'
import { openai } from '@ai-sdk/openai'
import { InferToolInput, InferToolOutput, type Tool } from 'ai'
import type { anthropic } from '@ai-sdk/anthropic'
import type { google } from '@ai-sdk/google'
import type { openai } from '@ai-sdk/openai'
import type { InferToolInput, InferToolOutput } from 'ai'
import { type Tool } from 'ai'
import { ProviderOptionsMap } from '../../../options/types'
import { OpenRouterSearchConfig } from './openrouter'
import type { ProviderOptionsMap } from '../../../options/types'
import type { OpenRouterSearchConfig } from './openrouter'
/**
* 从 AI SDK 的工具函数中提取参数类型,以确保类型安全。

View File

@@ -9,7 +9,8 @@ import { openai } from '@ai-sdk/openai'
import { createOpenRouterOptions, createXaiOptions, mergeProviderOptions } from '../../../options'
import { definePlugin } from '../../'
import type { AiRequestContext } from '../../types'
import { DEFAULT_WEB_SEARCH_CONFIG, WebSearchPluginConfig } from './helper'
import type { WebSearchPluginConfig } from './helper'
import { DEFAULT_WEB_SEARCH_CONFIG } from './helper'
/**
* 网络搜索插件

View File

@@ -1,4 +1,4 @@
import { AiPlugin, AiRequestContext } from './types'
import type { AiPlugin, AiRequestContext } from './types'
/**
* 插件管理器

View File

@@ -5,7 +5,7 @@
* 例如: aihubmix:anthropic:claude-3.5-sonnet
*/
import { ProviderV2 } from '@ai-sdk/provider'
import type { ProviderV2 } from '@ai-sdk/provider'
import { customProvider } from 'ai'
import { globalRegistryManagement } from './RegistryManagement'

View File

@@ -4,7 +4,7 @@
* 基于 AI SDK 原生的 createProviderRegistry
*/
import { EmbeddingModelV2, ImageModelV2, LanguageModelV2, ProviderV2 } from '@ai-sdk/provider'
import type { EmbeddingModelV2, ImageModelV2, LanguageModelV2, ProviderV2 } from '@ai-sdk/provider'
import { createProviderRegistry, type ProviderRegistryProvider } from 'ai'
type PROVIDERS = Record<string, ProviderV2>

View File

@@ -10,10 +10,11 @@ import { createGoogleGenerativeAI } from '@ai-sdk/google'
import { createHuggingFace } from '@ai-sdk/huggingface'
import { createOpenAI, type OpenAIProviderSettings } from '@ai-sdk/openai'
import { createOpenAICompatible } from '@ai-sdk/openai-compatible'
import { LanguageModelV2 } from '@ai-sdk/provider'
import type { LanguageModelV2 } from '@ai-sdk/provider'
import { createXai } from '@ai-sdk/xai'
import { createOpenRouter } from '@openrouter/ai-sdk-provider'
import { customProvider, Provider } from 'ai'
import type { Provider } from 'ai'
import { customProvider } from 'ai'
import * as z from 'zod'
/**

View File

@@ -4,7 +4,7 @@ import { type DeepSeekProviderSettings } from '@ai-sdk/deepseek'
import { type GoogleGenerativeAIProviderSettings } from '@ai-sdk/google'
import { type OpenAIProviderSettings } from '@ai-sdk/openai'
import { type OpenAICompatibleProviderSettings } from '@ai-sdk/openai-compatible'
import {
import type {
EmbeddingModelV2 as EmbeddingModel,
ImageModelV2 as ImageModel,
LanguageModelV2 as LanguageModel,

View File

@@ -1,4 +1,4 @@
import { ImageModelV2 } from '@ai-sdk/provider'
import type { ImageModelV2 } from '@ai-sdk/provider'
import { experimental_generateImage as aiGenerateImage, NoImageGeneratedError } from 'ai'
import { beforeEach, describe, expect, it, vi } from 'vitest'

View File

@@ -2,12 +2,12 @@
* 运行时执行器
* 专注于插件化的AI调用处理
*/
import { ImageModelV2, LanguageModelV2, LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { ImageModelV2, LanguageModelV2, LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { LanguageModel } from 'ai'
import {
experimental_generateImage as _generateImage,
generateObject as _generateObject,
generateText as _generateText,
LanguageModel,
streamObject as _streamObject,
streamText as _streamText
} from 'ai'

View File

@@ -11,7 +11,7 @@ export type { RuntimeConfig } from './types'
// === 便捷工厂函数 ===
import { LanguageModelV2Middleware } from '@ai-sdk/provider'
import type { LanguageModelV2Middleware } from '@ai-sdk/provider'
import { type AiPlugin } from '../plugins'
import { type ProviderId, type ProviderSettingsMap } from '../providers/types'

View File

@@ -1,6 +1,13 @@
/* eslint-disable @eslint-react/naming-convention/context-name */
import { ImageModelV2 } from '@ai-sdk/provider'
import { experimental_generateImage, generateObject, generateText, LanguageModel, streamObject, streamText } from 'ai'
import type { ImageModelV2 } from '@ai-sdk/provider'
import type {
experimental_generateImage,
generateObject,
generateText,
LanguageModel,
streamObject,
streamText
} from 'ai'
import { type AiPlugin, createContext, PluginManager } from '../plugins'
import { type ProviderId } from '../providers/types'

View File

@@ -1,8 +1,8 @@
/**
* Runtime 层类型定义
*/
import { ImageModelV2 } from '@ai-sdk/provider'
import { experimental_generateImage, generateObject, generateText, streamObject, streamText } from 'ai'
import type { ImageModelV2 } from '@ai-sdk/provider'
import type { experimental_generateImage, generateObject, generateText, streamObject, streamText } from 'ai'
import { type ModelConfig } from '../models/types'
import { type AiPlugin } from '../plugins'

View File

@@ -1,4 +1,5 @@
import { Extension, Node } from '@tiptap/core'
import type { Node } from '@tiptap/core'
import { Extension } from '@tiptap/core'
import type { TableCellOptions } from '../cell/index.js'
import { TableCell } from '../cell/index.js'

View File

@@ -1,7 +1,7 @@
import { SpanKind, SpanStatusCode } from '@opentelemetry/api'
import { ReadableSpan } from '@opentelemetry/sdk-trace-base'
import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'
import { SpanEntity } from '../types/config'
import type { SpanEntity } from '../types/config'
/**
* convert ReadableSpan to SpanEntity

View File

@@ -1,4 +1,4 @@
import { ReadableSpan } from '@opentelemetry/sdk-trace-base'
import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'
export interface TraceCache {
createSpan: (span: ReadableSpan) => void

View File

@@ -1,5 +1,6 @@
import { ExportResult, ExportResultCode } from '@opentelemetry/core'
import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'
import type { ExportResult } from '@opentelemetry/core'
import { ExportResultCode } from '@opentelemetry/core'
import type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'
export type SaveFunction = (spans: ReadableSpan[]) => Promise<void>

View File

@@ -1,7 +1,9 @@
import { Context, trace } from '@opentelemetry/api'
import { BatchSpanProcessor, BufferConfig, ReadableSpan, Span, SpanExporter } from '@opentelemetry/sdk-trace-base'
import type { Context } from '@opentelemetry/api'
import { trace } from '@opentelemetry/api'
import type { BufferConfig, ReadableSpan, Span, SpanExporter } from '@opentelemetry/sdk-trace-base'
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
import { TraceCache } from '../core/traceCache'
import type { TraceCache } from '../core/traceCache'
export class CacheBatchSpanProcessor extends BatchSpanProcessor {
private cache: TraceCache

View File

@@ -1,6 +1,7 @@
import { Context } from '@opentelemetry/api'
import { BatchSpanProcessor, BufferConfig, ReadableSpan, Span, SpanExporter } from '@opentelemetry/sdk-trace-base'
import { EventEmitter } from 'stream'
import type { Context } from '@opentelemetry/api'
import type { BufferConfig, ReadableSpan, Span, SpanExporter } from '@opentelemetry/sdk-trace-base'
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
import type { EventEmitter } from 'stream'
import { convertSpanToSpanEntity } from '../core/spanConvert'

View File

@@ -1,5 +1,7 @@
import { Context, trace } from '@opentelemetry/api'
import { BatchSpanProcessor, BufferConfig, ReadableSpan, Span, SpanExporter } from '@opentelemetry/sdk-trace-base'
import type { Context } from '@opentelemetry/api'
import { trace } from '@opentelemetry/api'
import type { BufferConfig, ReadableSpan, Span, SpanExporter } from '@opentelemetry/sdk-trace-base'
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
export type SpanFunction = (span: ReadableSpan) => void

View File

@@ -1,5 +1,5 @@
import { Link } from '@opentelemetry/api'
import { TimedEvent } from '@opentelemetry/sdk-trace-base'
import type { Link } from '@opentelemetry/api'
import type { TimedEvent } from '@opentelemetry/sdk-trace-base'
export type AttributeValue =
| string

View File

@@ -1,11 +1,14 @@
import { trace, Tracer } from '@opentelemetry/api'
import type { Tracer } from '@opentelemetry/api'
import { trace } from '@opentelemetry/api'
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'
import { W3CTraceContextPropagator } from '@opentelemetry/core'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { BatchSpanProcessor, ConsoleSpanExporter, SpanProcessor } from '@opentelemetry/sdk-trace-base'
import type { SpanProcessor } from '@opentelemetry/sdk-trace-base'
import { BatchSpanProcessor, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base'
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
import { defaultConfig, TraceConfig } from '../trace-core/types/config'
import type { TraceConfig } from '../trace-core/types/config'
import { defaultConfig } from '../trace-core/types/config'
export class NodeTracer {
private static provider: NodeTracerProvider

View File

@@ -1,4 +1,5 @@
import { Context, ContextManager, ROOT_CONTEXT } from '@opentelemetry/api'
import type { Context, ContextManager } from '@opentelemetry/api'
import { ROOT_CONTEXT } from '@opentelemetry/api'
export class TopicContextManager implements ContextManager {
private topicContextStack: Map<string, Context[]>

View File

@@ -1,4 +1,5 @@
import { Context, context } from '@opentelemetry/api'
import type { Context } from '@opentelemetry/api'
import { context } from '@opentelemetry/api'
const originalPromise = globalThis.Promise

View File

@@ -1,9 +1,11 @@
import { W3CTraceContextPropagator } from '@opentelemetry/core'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { BatchSpanProcessor, ConsoleSpanExporter, SpanProcessor } from '@opentelemetry/sdk-trace-base'
import type { SpanProcessor } from '@opentelemetry/sdk-trace-base'
import { BatchSpanProcessor, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base'
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { defaultConfig, TraceConfig } from '../trace-core/types/config'
import type { TraceConfig } from '../trace-core/types/config'
import { defaultConfig } from '../trace-core/types/config'
import { TopicContextManager } from './TopicContextManager'
export const contextManager = new TopicContextManager()

View File

@@ -96,6 +96,10 @@ export enum IpcChannel {
AgentMessage_PersistExchange = 'agent-message:persist-exchange',
AgentMessage_GetHistory = 'agent-message:get-history',
AgentToolPermission_Request = 'agent-tool-permission:request',
AgentToolPermission_Response = 'agent-tool-permission:response',
AgentToolPermission_Result = 'agent-tool-permission:result',
//copilot
Copilot_GetAuthMessage = 'copilot:get-auth-message',
Copilot_GetCopilotToken = 'copilot:get-copilot-token',
@@ -318,6 +322,7 @@ export enum IpcChannel {
ApiServer_Stop = 'api-server:stop',
ApiServer_Restart = 'api-server:restart',
ApiServer_GetStatus = 'api-server:get-status',
ApiServer_Ready = 'api-server:ready',
// NOTE: This api is not be used.
ApiServer_GetConfig = 'api-server:get-config',
@@ -350,5 +355,21 @@ export enum IpcChannel {
Ovms_StopOVMS = 'ovms:stop-ovms',
// CherryAI
Cherryai_GetSignature = 'cherryai:get-signature'
Cherryai_GetSignature = 'cherryai:get-signature',
// Claude Code Plugins
ClaudeCodePlugin_ListAvailable = 'claudeCodePlugin:list-available',
ClaudeCodePlugin_Install = 'claudeCodePlugin:install',
ClaudeCodePlugin_Uninstall = 'claudeCodePlugin:uninstall',
ClaudeCodePlugin_ListInstalled = 'claudeCodePlugin:list-installed',
ClaudeCodePlugin_InvalidateCache = 'claudeCodePlugin:invalidate-cache',
ClaudeCodePlugin_ReadContent = 'claudeCodePlugin:read-content',
ClaudeCodePlugin_WriteContent = 'claudeCodePlugin:write-content',
// WebSocket
WebSocket_Start = 'webSocket:start',
WebSocket_Stop = 'webSocket:stop',
WebSocket_Status = 'webSocket:status',
WebSocket_SendFile = 'webSocket:send-file',
WebSocket_GetAllCandidates = 'webSocket:get-all-candidates'
}

View File

@@ -9,9 +9,9 @@
*/
import Anthropic from '@anthropic-ai/sdk'
import { TextBlockParam } from '@anthropic-ai/sdk/resources'
import type { TextBlockParam } from '@anthropic-ai/sdk/resources'
import { loggerService } from '@logger'
import { Provider } from '@types'
import type { Provider } from '@types'
import type { ModelMessage } from 'ai'
const logger = loggerService.withContext('anthropic-sdk')

View File

@@ -470,3 +470,6 @@ export const MACOS_TERMINALS_WITH_COMMANDS: TerminalConfigWithCommand[] = [
})
}
]
// resources/scripts should be maintained manually
export const HOME_CHERRY_DIR = '.cherrystudio'

View File

@@ -1,4 +1,4 @@
import { ProcessingStatus } from '@types'
import type { ProcessingStatus } from '@types'
export type LoaderReturn = {
entriesAdded: number
@@ -31,3 +31,16 @@ export type WebviewKeyEvent = {
shift: boolean
alt: boolean
}
export interface WebSocketStatusResponse {
isRunning: boolean
port?: number
ip?: string
clientConnected: boolean
}
export interface WebSocketCandidatesResponse {
host: string
interface: string
priority: number
}

View File

@@ -1,36 +0,0 @@
;(() => {
let messageId = 0
const pendingCalls = new Map()
function api(method, ...args) {
const id = messageId++
return new Promise((resolve, reject) => {
pendingCalls.set(id, { resolve, reject })
window.parent.postMessage({ id, type: 'api-call', method, args }, '*')
})
}
window.addEventListener('message', (event) => {
if (event.data.type === 'api-response') {
const { id, result, error } = event.data
const pendingCall = pendingCalls.get(id)
if (pendingCall) {
if (error) {
pendingCall.reject(new Error(error))
} else {
pendingCall.resolve(result)
}
pendingCalls.delete(id)
}
}
})
window.api = new Proxy(
{},
{
get: (target, prop) => {
return (...args) => api(prop, ...args)
}
}
)
})()

View File

@@ -1,5 +0,0 @@
export function getQueryParam(paramName) {
const url = new URL(window.location.href)
const params = new URLSearchParams(url.search)
return params.get(paramName)
}

View File

@@ -7,7 +7,7 @@ const { downloadWithRedirects } = require('./download')
// Base URL for downloading bun binaries
const BUN_RELEASE_BASE_URL = 'https://gitcode.com/CherryHQ/bun/releases/download'
const DEFAULT_BUN_VERSION = '1.2.17' // Default fallback version
const DEFAULT_BUN_VERSION = '1.3.1' // Default fallback version
// Mapping of platform+arch to binary package name
const BUN_PACKAGES = {

View File

@@ -7,28 +7,29 @@ const { downloadWithRedirects } = require('./download')
// Base URL for downloading uv binaries
const UV_RELEASE_BASE_URL = 'https://gitcode.com/CherryHQ/uv/releases/download'
const DEFAULT_UV_VERSION = '0.7.13'
const DEFAULT_UV_VERSION = '0.9.5'
// Mapping of platform+arch to binary package name
const UV_PACKAGES = {
'darwin-arm64': 'uv-aarch64-apple-darwin.zip',
'darwin-x64': 'uv-x86_64-apple-darwin.zip',
'darwin-arm64': 'uv-aarch64-apple-darwin.tar.gz',
'darwin-x64': 'uv-x86_64-apple-darwin.tar.gz',
'win32-arm64': 'uv-aarch64-pc-windows-msvc.zip',
'win32-ia32': 'uv-i686-pc-windows-msvc.zip',
'win32-x64': 'uv-x86_64-pc-windows-msvc.zip',
'linux-arm64': 'uv-aarch64-unknown-linux-gnu.zip',
'linux-ia32': 'uv-i686-unknown-linux-gnu.zip',
'linux-ppc64': 'uv-powerpc64-unknown-linux-gnu.zip',
'linux-ppc64le': 'uv-powerpc64le-unknown-linux-gnu.zip',
'linux-s390x': 'uv-s390x-unknown-linux-gnu.zip',
'linux-x64': 'uv-x86_64-unknown-linux-gnu.zip',
'linux-armv7l': 'uv-armv7-unknown-linux-gnueabihf.zip',
'linux-arm64': 'uv-aarch64-unknown-linux-gnu.tar.gz',
'linux-ia32': 'uv-i686-unknown-linux-gnu.tar.gz',
'linux-ppc64': 'uv-powerpc64-unknown-linux-gnu.tar.gz',
'linux-ppc64le': 'uv-powerpc64le-unknown-linux-gnu.tar.gz',
'linux-riscv64': 'uv-riscv64gc-unknown-linux-gnu.tar.gz',
'linux-s390x': 'uv-s390x-unknown-linux-gnu.tar.gz',
'linux-x64': 'uv-x86_64-unknown-linux-gnu.tar.gz',
'linux-armv7l': 'uv-armv7-unknown-linux-gnueabihf.tar.gz',
// MUSL variants
'linux-musl-arm64': 'uv-aarch64-unknown-linux-musl.zip',
'linux-musl-ia32': 'uv-i686-unknown-linux-musl.zip',
'linux-musl-x64': 'uv-x86_64-unknown-linux-musl.zip',
'linux-musl-armv6l': 'uv-arm-unknown-linux-musleabihf.zip',
'linux-musl-armv7l': 'uv-armv7-unknown-linux-musleabihf.zip'
'linux-musl-arm64': 'uv-aarch64-unknown-linux-musl.tar.gz',
'linux-musl-ia32': 'uv-i686-unknown-linux-musl.tar.gz',
'linux-musl-x64': 'uv-x86_64-unknown-linux-musl.tar.gz',
'linux-musl-armv6l': 'uv-arm-unknown-linux-musleabihf.tar.gz',
'linux-musl-armv7l': 'uv-armv7-unknown-linux-musleabihf.tar.gz'
}
/**
@@ -56,6 +57,7 @@ async function downloadUvBinary(platform, arch, version = DEFAULT_UV_VERSION, is
const downloadUrl = `${UV_RELEASE_BASE_URL}/${version}/${packageName}`
const tempdir = os.tmpdir()
const tempFilename = path.join(tempdir, packageName)
const isTarGz = packageName.endsWith('.tar.gz')
try {
console.log(`Downloading uv ${version} for ${platformKey}...`)
@@ -65,34 +67,58 @@ async function downloadUvBinary(platform, arch, version = DEFAULT_UV_VERSION, is
console.log(`Extracting ${packageName} to ${binDir}...`)
const zip = new StreamZip.async({ file: tempFilename })
if (isTarGz) {
// Use tar command to extract tar.gz files (macOS and Linux)
const tempExtractDir = path.join(tempdir, `uv-extract-${Date.now()}`)
fs.mkdirSync(tempExtractDir, { recursive: true })
// Get all entries in the zip file
const entries = await zip.entries()
execSync(`tar -xzf "${tempFilename}" -C "${tempExtractDir}"`, { stdio: 'inherit' })
// Extract files directly to binDir, flattening the directory structure
for (const entry of Object.values(entries)) {
if (!entry.isDirectory) {
// Get just the filename without path
const filename = path.basename(entry.name)
const outputPath = path.join(binDir, filename)
console.log(`Extracting ${entry.name} -> ${filename}`)
await zip.extract(entry.name, outputPath)
// Make executable files executable on Unix-like systems
if (platform !== 'win32') {
try {
// Find all files in the extracted directory and move them to binDir
const findAndMoveFiles = (dir) => {
const entries = fs.readdirSync(dir, { withFileTypes: true })
for (const entry of entries) {
const fullPath = path.join(dir, entry.name)
if (entry.isDirectory()) {
findAndMoveFiles(fullPath)
} else {
const filename = path.basename(entry.name)
const outputPath = path.join(binDir, filename)
fs.copyFileSync(fullPath, outputPath)
console.log(`Extracted ${entry.name} -> ${outputPath}`)
// Make executable on Unix-like systems
fs.chmodSync(outputPath, 0o755)
} catch (chmodError) {
console.error(`Warning: Failed to set executable permissions on ${filename}`)
return 102
}
}
console.log(`Extracted ${entry.name} -> ${outputPath}`)
}
findAndMoveFiles(tempExtractDir)
// Clean up temporary extraction directory
fs.rmSync(tempExtractDir, { recursive: true })
} else {
// Use StreamZip for zip files (Windows)
const zip = new StreamZip.async({ file: tempFilename })
// Get all entries in the zip file
const entries = await zip.entries()
// Extract files directly to binDir, flattening the directory structure
for (const entry of Object.values(entries)) {
if (!entry.isDirectory) {
// Get just the filename without path
const filename = path.basename(entry.name)
const outputPath = path.join(binDir, filename)
console.log(`Extracting ${entry.name} -> ${filename}`)
await zip.extract(entry.name, outputPath)
console.log(`Extracted ${entry.name} -> ${outputPath}`)
}
}
await zip.close()
}
await zip.close()
fs.unlinkSync(tempFilename)
console.log(`Successfully installed uv ${version} for ${platform}-${arch}`)
return 0

View File

@@ -1,88 +0,0 @@
const https = require('https')
const { loggerService } = require('@logger')
const logger = loggerService.withContext('IpService')
/**
* 获取用户的IP地址所在国家
* @returns {Promise<string>} 返回国家代码,默认为'CN'
*/
async function getIpCountry() {
return new Promise((resolve) => {
// 添加超时控制
const timeout = setTimeout(() => {
logger.info('IP Address Check Timeout, default to China Mirror')
resolve('CN')
}, 5000)
const options = {
hostname: 'ipinfo.io',
path: '/json',
method: 'GET',
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
'Accept-Language': 'en-US,en;q=0.9'
}
}
const req = https.request(options, (res) => {
clearTimeout(timeout)
let data = ''
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
try {
const parsed = JSON.parse(data)
const country = parsed.country || 'CN'
logger.info(`Detected user IP address country: ${country}`)
resolve(country)
} catch (error) {
logger.error('Failed to parse IP address information:', error.message)
resolve('CN')
}
})
})
req.on('error', (error) => {
clearTimeout(timeout)
logger.error('Failed to get IP address information:', error.message)
resolve('CN')
})
req.end()
})
}
/**
* 检查用户是否在中国
* @returns {Promise<boolean>} 如果用户在中国返回true否则返回false
*/
async function isUserInChina() {
const country = await getIpCountry()
return country.toLowerCase() === 'cn'
}
/**
* 根据用户位置获取适合的npm镜像URL
* @returns {Promise<string>} 返回npm镜像URL
*/
async function getNpmRegistryUrl() {
const inChina = await isUserInChina()
if (inChina) {
logger.info('User in China, using Taobao npm mirror')
return 'https://registry.npmmirror.com'
} else {
logger.info('User not in China, using default npm mirror')
return 'https://registry.npmjs.org'
}
}
module.exports = {
getIpCountry,
isUserInChina,
getNpmRegistryUrl
}

View File

@@ -18,8 +18,10 @@ import { sortedObjectByKeys } from './sort'
// ========== SCRIPT CONFIGURATION AREA - MODIFY SETTINGS HERE ==========
const SCRIPT_CONFIG = {
// 🔧 Concurrency Control Configuration
MAX_CONCURRENT_TRANSLATIONS: 5, // Max concurrent requests (Make sure the concurrency level does not exceed your provider's limits.)
TRANSLATION_DELAY_MS: 100, // Delay between requests to avoid rate limiting (Recommended: 100-500ms, Range: 0-5000ms)
MAX_CONCURRENT_TRANSLATIONS: process.env.TRANSLATION_MAX_CONCURRENT_REQUESTS
? parseInt(process.env.TRANSLATION_MAX_CONCURRENT_REQUESTS)
: 5, // Max concurrent requests (Make sure the concurrency level does not exceed your provider's limits.)
TRANSLATION_DELAY_MS: process.env.TRANSLATION_DELAY_MS ? parseInt(process.env.TRANSLATION_DELAY_MS) : 500, // Delay between requests to avoid rate limiting (Recommended: 100-500ms, Range: 0-5000ms)
// 🔑 API Configuration
API_KEY: process.env.TRANSLATION_API_KEY || '', // API key from environment variable

View File

@@ -1,4 +1,4 @@
import { ApiServerConfig } from '@types'
import type { ApiServerConfig } from '@types'
import { v4 as uuidv4 } from 'uuid'
import { loggerService } from '../services/LoggerService'

View File

@@ -1,5 +1,5 @@
import crypto from 'crypto'
import { NextFunction, Request, Response } from 'express'
import type { NextFunction, Request, Response } from 'express'
import { config } from '../config'

View File

@@ -1,4 +1,4 @@
import { NextFunction, Request, Response } from 'express'
import type { NextFunction, Request, Response } from 'express'
import { loggerService } from '../../services/LoggerService'

View File

@@ -1,4 +1,4 @@
import { Express } from 'express'
import type { Express } from 'express'
import swaggerJSDoc from 'swagger-jsdoc'
import swaggerUi from 'swagger-ui-express'
@@ -171,7 +171,7 @@ const swaggerOptions: swaggerJSDoc.Options = {
}
]
},
apis: ['./src/main/apiServer/routes/*.ts', './src/main/apiServer/app.ts']
apis: ['./src/main/apiServer/routes/**/*.ts', './src/main/apiServer/app.ts']
}
export function setupOpenAPIDocumentation(app: Express) {

View File

@@ -1,7 +1,8 @@
import { loggerService } from '@logger'
import { AgentModelValidationError, agentService, sessionService } from '@main/services/agents'
import { ListAgentsResponse, type ReplaceAgentRequest, type UpdateAgentRequest } from '@types'
import { Request, Response } from 'express'
import type { ListAgentsResponse } from '@types'
import { type ReplaceAgentRequest, type UpdateAgentRequest } from '@types'
import type { Request, Response } from 'express'
import type { ValidationRequest } from '../validators/zodValidator'

View File

@@ -2,7 +2,7 @@ import { loggerService } from '@logger'
import { MESSAGE_STREAM_TIMEOUT_MS } from '@main/apiServer/config/timeouts'
import { createStreamAbortController, STREAM_TIMEOUT_REASON } from '@main/apiServer/utils/createStreamAbortController'
import { agentService, sessionMessageService, sessionService } from '@main/services/agents'
import { Request, Response } from 'express'
import type { Request, Response } from 'express'
const logger = loggerService.withContext('ApiServerMessagesHandlers')

View File

@@ -1,7 +1,8 @@
import { loggerService } from '@logger'
import { AgentModelValidationError, sessionMessageService, sessionService } from '@main/services/agents'
import { ListAgentSessionsResponse, type ReplaceSessionRequest, UpdateSessionResponse } from '@types'
import { Request, Response } from 'express'
import type { ListAgentSessionsResponse, UpdateSessionResponse } from '@types'
import { type ReplaceSessionRequest } from '@types'
import type { Request, Response } from 'express'
import type { ValidationRequest } from '../validators/zodValidator'

View File

@@ -1,4 +1,4 @@
import { Request, Response } from 'express'
import type { Request, Response } from 'express'
import { agentService } from '../../../../services/agents'
import { loggerService } from '../../../../services/LoggerService'

View File

@@ -1,5 +1,6 @@
import { NextFunction, Request, Response } from 'express'
import { ZodError, ZodType } from 'zod'
import type { NextFunction, Request, Response } from 'express'
import type { ZodType } from 'zod'
import { ZodError } from 'zod'
export interface ValidationRequest extends Request {
validatedBody?: any

View File

@@ -1,5 +1,6 @@
import { ChatCompletionCreateParams } from '@cherrystudio/openai/resources'
import express, { Request, Response } from 'express'
import type { ChatCompletionCreateParams } from '@cherrystudio/openai/resources'
import type { Request, Response } from 'express'
import express from 'express'
import { loggerService } from '../../services/LoggerService'
import {

View File

@@ -1,4 +1,5 @@
import express, { Request, Response } from 'express'
import type { Request, Response } from 'express'
import express from 'express'
import { loggerService } from '../../services/LoggerService'
import { mcpApiService } from '../services/mcp'

View File

@@ -1,7 +1,8 @@
import { MessageCreateParams } from '@anthropic-ai/sdk/resources'
import type { MessageCreateParams } from '@anthropic-ai/sdk/resources'
import { loggerService } from '@logger'
import { Provider } from '@types'
import express, { Request, Response } from 'express'
import type { Provider } from '@types'
import type { Request, Response } from 'express'
import express from 'express'
import { messagesService } from '../services/messages'
import { getProviderById, validateModelId } from '../utils'

View File

@@ -1,5 +1,7 @@
import { ApiModelsFilterSchema, ApiModelsResponse } from '@types'
import express, { Request, Response } from 'express'
import type { ApiModelsResponse } from '@types'
import { ApiModelsFilterSchema } from '@types'
import type { Request, Response } from 'express'
import express from 'express'
import { loggerService } from '../../services/LoggerService'
import { modelsService } from '../services/models'

View File

@@ -1,8 +1,10 @@
import { createServer } from 'node:http'
import { loggerService } from '@logger'
import { IpcChannel } from '@shared/IpcChannel'
import { agentService } from '../services/agents'
import { windowService } from '../services/WindowService'
import { app } from './app'
import { config } from './config'
@@ -43,6 +45,13 @@ export class ApiServer {
return new Promise((resolve, reject) => {
this.server!.listen(port, host, () => {
logger.info('API server started', { host, port })
// Notify renderer that API server is ready
const mainWindow = windowService.getMainWindow()
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send(IpcChannel.ApiServer_Ready)
}
resolve()
})

View File

@@ -1,9 +1,10 @@
import OpenAI from '@cherrystudio/openai'
import { ChatCompletionCreateParams, ChatCompletionCreateParamsStreaming } from '@cherrystudio/openai/resources'
import { Provider } from '@types'
import type { ChatCompletionCreateParams, ChatCompletionCreateParamsStreaming } from '@cherrystudio/openai/resources'
import type { Provider } from '@types'
import { loggerService } from '../../services/LoggerService'
import { ModelValidationError, validateModelId } from '../utils'
import type { ModelValidationError } from '../utils'
import { validateModelId } from '../utils'
const logger = loggerService.withContext('ChatCompletionService')

View File

@@ -1,16 +1,12 @@
import mcpService from '@main/services/MCPService'
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp'
import {
isJSONRPCRequest,
JSONRPCMessage,
JSONRPCMessageSchema,
MessageExtraInfo
} from '@modelcontextprotocol/sdk/types'
import { MCPServer } from '@types'
import type { JSONRPCMessage, MessageExtraInfo } from '@modelcontextprotocol/sdk/types'
import { isJSONRPCRequest, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types'
import type { MCPServer } from '@types'
import { randomUUID } from 'crypto'
import { EventEmitter } from 'events'
import { Request, Response } from 'express'
import { IncomingMessage, ServerResponse } from 'http'
import type { Request, Response } from 'express'
import type { IncomingMessage, ServerResponse } from 'http'
import { loggerService } from '../../services/LoggerService'
import { getMcpServerById, getMCPServersFromRedux } from '../utils/mcp'

View File

@@ -1,10 +1,10 @@
import Anthropic from '@anthropic-ai/sdk'
import { MessageCreateParams, MessageStreamEvent } from '@anthropic-ai/sdk/resources'
import type Anthropic from '@anthropic-ai/sdk'
import type { MessageCreateParams, MessageStreamEvent } from '@anthropic-ai/sdk/resources'
import { loggerService } from '@logger'
import anthropicService from '@main/services/AnthropicService'
import { buildClaudeCodeSystemMessage, getSdkClient } from '@shared/anthropic'
import { Provider } from '@types'
import { Response } from 'express'
import type { Provider } from '@types'
import type { Response } from 'express'
const logger = loggerService.withContext('MessagesService')
const EXCLUDED_FORWARD_HEADERS: ReadonlySet<string> = new Set([

View File

@@ -1,6 +1,6 @@
import { isEmpty } from 'lodash'
import { ApiModel, ApiModelsFilter, ApiModelsResponse } from '../../../renderer/src/types/apiModels'
import type { ApiModel, ApiModelsFilter, ApiModelsResponse } from '../../../renderer/src/types/apiModels'
import { loggerService } from '../../services/LoggerService'
import {
getAvailableProviders,

View File

@@ -1,7 +1,7 @@
import { CacheService } from '@main/services/CacheService'
import { loggerService } from '@main/services/LoggerService'
import { reduxService } from '@main/services/ReduxService'
import { ApiModel, Model, Provider } from '@types'
import type { ApiModel, Model, Provider } from '@types'
const logger = loggerService.withContext('ApiServerUtils')

View File

@@ -1,8 +1,9 @@
import { CacheService } from '@main/services/CacheService'
import mcpService from '@main/services/MCPService'
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { CallToolRequestSchema, ListToolsRequestSchema, ListToolsResult } from '@modelcontextprotocol/sdk/types.js'
import { MCPServer } from '@types'
import type { ListToolsResult } from '@modelcontextprotocol/sdk/types.js'
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
import type { MCPServer } from '@types'
import { loggerService } from '../../services/LoggerService'
import { reduxService } from '../../services/ReduxService'

View File

@@ -21,6 +21,7 @@ import { appMenuService } from './services/AppMenuService'
import { configManager } from './services/ConfigManager'
import mcpService from './services/MCPService'
import { nodeTraceService } from './services/NodeTraceService'
import powerMonitorService from './services/PowerMonitorService'
import {
CHERRY_STUDIO_PROTOCOL,
handleProtocolUrl,
@@ -30,6 +31,7 @@ import {
import selectionService, { initSelectionService } from './services/SelectionService'
import { registerShortcuts } from './services/ShortcutService'
import { TrayService } from './services/TrayService'
import { versionService } from './services/VersionService'
import { windowService } from './services/WindowService'
import { initWebviewHotkeys } from './services/WebviewService'
@@ -110,6 +112,10 @@ if (!app.requestSingleInstanceLock()) {
// Some APIs can only be used after this event occurs.
app.whenReady().then(async () => {
// Record current version for tracking
// A preparation for v2 data refactoring
versionService.recordCurrentVersion()
initWebviewHotkeys()
// Set app user model id for windows
electronApp.setAppUserModelId(import.meta.env.VITE_MAIN_BUNDLE_ID || 'com.kangfenmao.CherryStudio')
@@ -127,6 +133,7 @@ if (!app.requestSingleInstanceLock()) {
appMenuService?.setupApplicationMenu()
nodeTraceService.init()
powerMonitorService.init()
app.on('activate', function () {
const mainWindow = windowService.getMainWindow()

View File

@@ -8,10 +8,12 @@ import { generateSignature } from '@main/integration/cherryai'
import anthropicService from '@main/services/AnthropicService'
import { getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/process'
import { handleZoomFactor } from '@main/utils/zoom'
import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core'
import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, UpgradeChannel } from '@shared/config/constant'
import type { SpanEntity, TokenUsage } from '@mcp-trace/trace-core'
import type { UpgradeChannel } from '@shared/config/constant'
import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH } from '@shared/config/constant'
import { IpcChannel } from '@shared/IpcChannel'
import {
import type { PluginError } from '@types'
import type {
AgentPersistedMessage,
FileMetadata,
Notification,
@@ -22,10 +24,12 @@ import {
ThemeMode
} from '@types'
import checkDiskSpace from 'check-disk-space'
import { BrowserWindow, dialog, ipcMain, ProxyConfig, session, shell, systemPreferences, webContents } from 'electron'
import type { ProxyConfig } from 'electron'
import { BrowserWindow, dialog, ipcMain, session, shell, systemPreferences, webContents } from 'electron'
import fontList from 'font-list'
import { agentMessageRepository } from './services/agents/database'
import { PluginService } from './services/agents/plugins/PluginService'
import { apiServerService } from './services/ApiServerService'
import appService from './services/AppService'
import AppUpdater from './services/AppUpdater'
@@ -46,6 +50,7 @@ import * as NutstoreService from './services/NutstoreService'
import ObsidianVaultService from './services/ObsidianVaultService'
import { ocrService } from './services/ocr/OcrService'
import OvmsManager from './services/OvmsManager'
import powerMonitorService from './services/PowerMonitorService'
import { proxyManager } from './services/ProxyManager'
import { pythonService } from './services/PythonService'
import { FileServiceManager } from './services/remotefile/FileServiceManager'
@@ -68,6 +73,7 @@ import {
import storeSyncService from './services/StoreSyncService'
import { themeService } from './services/ThemeService'
import VertexAIService from './services/VertexAIService'
import WebSocketService from './services/WebSocketService'
import { setOpenLinkExternal } from './services/WebviewService'
import { windowService } from './services/WindowService'
import { calculateDirectorySize, getResourcePath } from './utils'
@@ -93,13 +99,34 @@ const vertexAIService = VertexAIService.getInstance()
const memoryService = MemoryService.getInstance()
const dxtService = new DxtService()
const ovmsManager = new OvmsManager()
const pluginService = PluginService.getInstance()
function normalizeError(error: unknown): Error {
return error instanceof Error ? error : new Error(String(error))
}
function extractPluginError(error: unknown): PluginError | null {
if (error && typeof error === 'object' && 'type' in error && typeof (error as { type: unknown }).type === 'string') {
return error as PluginError
}
return null
}
export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
const appUpdater = new AppUpdater()
const notificationService = new NotificationService()
// Initialize Python service with main window
pythonService.setMainWindow(mainWindow)
// Register shutdown handlers
powerMonitorService.registerShutdownHandler(() => {
appUpdater.setAutoUpdate(false)
})
powerMonitorService.registerShutdownHandler(() => {
const mw = windowService.getMainWindow()
if (mw && !mw.isDestroyed()) {
mw.webContents.send(IpcChannel.App_SaveData)
}
})
const checkMainWindow = () => {
if (!mainWindow || mainWindow.isDestroyed()) {
@@ -890,4 +917,124 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
// CherryAI
ipcMain.handle(IpcChannel.Cherryai_GetSignature, (_, params) => generateSignature(params))
// Claude Code Plugins
ipcMain.handle(IpcChannel.ClaudeCodePlugin_ListAvailable, async () => {
try {
const data = await pluginService.listAvailable()
return { success: true, data }
} catch (error) {
const pluginError = extractPluginError(error)
if (pluginError) {
logger.error('Failed to list available plugins', pluginError)
return { success: false, error: pluginError }
}
const err = normalizeError(error)
logger.error('Failed to list available plugins', err)
return {
success: false,
error: {
type: 'TRANSACTION_FAILED',
operation: 'list-available',
reason: err.message
}
}
}
})
ipcMain.handle(IpcChannel.ClaudeCodePlugin_Install, async (_, options) => {
try {
const data = await pluginService.install(options)
return { success: true, data }
} catch (error) {
logger.error('Failed to install plugin', { options, error })
return { success: false, error }
}
})
ipcMain.handle(IpcChannel.ClaudeCodePlugin_Uninstall, async (_, options) => {
try {
await pluginService.uninstall(options)
return { success: true, data: undefined }
} catch (error) {
logger.error('Failed to uninstall plugin', { options, error })
return { success: false, error }
}
})
ipcMain.handle(IpcChannel.ClaudeCodePlugin_ListInstalled, async (_, agentId: string) => {
try {
const data = await pluginService.listInstalled(agentId)
return { success: true, data }
} catch (error) {
const pluginError = extractPluginError(error)
if (pluginError) {
logger.error('Failed to list installed plugins', { agentId, error: pluginError })
return { success: false, error: pluginError }
}
const err = normalizeError(error)
logger.error('Failed to list installed plugins', { agentId, error: err })
return {
success: false,
error: {
type: 'TRANSACTION_FAILED',
operation: 'list-installed',
reason: err.message
}
}
}
})
ipcMain.handle(IpcChannel.ClaudeCodePlugin_InvalidateCache, async () => {
try {
pluginService.invalidateCache()
return { success: true, data: undefined }
} catch (error) {
const pluginError = extractPluginError(error)
if (pluginError) {
logger.error('Failed to invalidate plugin cache', pluginError)
return { success: false, error: pluginError }
}
const err = normalizeError(error)
logger.error('Failed to invalidate plugin cache', err)
return {
success: false,
error: {
type: 'TRANSACTION_FAILED',
operation: 'invalidate-cache',
reason: err.message
}
}
}
})
ipcMain.handle(IpcChannel.ClaudeCodePlugin_ReadContent, async (_, sourcePath: string) => {
try {
const data = await pluginService.readContent(sourcePath)
return { success: true, data }
} catch (error) {
logger.error('Failed to read plugin content', { sourcePath, error })
return { success: false, error }
}
})
ipcMain.handle(IpcChannel.ClaudeCodePlugin_WriteContent, async (_, options) => {
try {
await pluginService.writeContent(options.agentId, options.filename, options.type, options.content)
return { success: true, data: undefined }
} catch (error) {
logger.error('Failed to write plugin content', { options, error })
return { success: false, error }
}
})
// WebSocket
ipcMain.handle(IpcChannel.WebSocket_Start, WebSocketService.start)
ipcMain.handle(IpcChannel.WebSocket_Stop, WebSocketService.stop)
ipcMain.handle(IpcChannel.WebSocket_Status, WebSocketService.getStatus)
ipcMain.handle(IpcChannel.WebSocket_SendFile, WebSocketService.sendFile)
ipcMain.handle(IpcChannel.WebSocket_GetAllCandidates, WebSocketService.getAllCandidates)
}

View File

@@ -1,6 +1,6 @@
import type { BaseEmbeddings } from '@cherrystudio/embedjs-interfaces'
import { TraceMethod } from '@mcp-trace/trace-core'
import { ApiClient } from '@types'
import type { ApiClient } from '@types'
import EmbeddingsFactory from './EmbeddingsFactory'

View File

@@ -1,15 +1,15 @@
import type { BaseEmbeddings } from '@cherrystudio/embedjs-interfaces'
import { OllamaEmbeddings } from '@cherrystudio/embedjs-ollama'
import { OpenAiEmbeddings } from '@cherrystudio/embedjs-openai'
import { AzureOpenAiEmbeddings } from '@cherrystudio/embedjs-openai/src/azure-openai-embeddings'
import { ApiClient } from '@types'
import type { ApiClient } from '@types'
import { net } from 'electron'
import { VoyageEmbeddings } from './VoyageEmbeddings'
export default class EmbeddingsFactory {
static create({ embedApiClient, dimensions }: { embedApiClient: ApiClient; dimensions?: number }): BaseEmbeddings {
const batchSize = 10
const { model, provider, apiKey, apiVersion, baseURL } = embedApiClient
const { model, provider, apiKey, baseURL } = embedApiClient
if (provider === 'voyageai') {
return new VoyageEmbeddings({
modelName: model,
@@ -38,22 +38,13 @@ export default class EmbeddingsFactory {
}
})
}
if (apiVersion !== undefined) {
return new AzureOpenAiEmbeddings({
azureOpenAIApiKey: apiKey,
azureOpenAIApiVersion: apiVersion,
azureOpenAIApiDeploymentName: model,
azureOpenAIEndpoint: baseURL,
dimensions,
batchSize
})
}
// NOTE: Azure OpenAI 也走 OpenAIEmbeddings, baseURL是https://xxxx.openai.azure.com/openai/v1
return new OpenAiEmbeddings({
model,
apiKey,
dimensions,
batchSize,
configuration: { baseURL }
configuration: { baseURL, fetch: net.fetch as typeof fetch }
})
}
}

View File

@@ -1,10 +1,11 @@
import { JsonLoader, LocalPathLoader, RAGApplication, TextLoader } from '@cherrystudio/embedjs'
import type { RAGApplication } from '@cherrystudio/embedjs'
import { JsonLoader, LocalPathLoader, TextLoader } from '@cherrystudio/embedjs'
import type { AddLoaderReturn } from '@cherrystudio/embedjs-interfaces'
import { WebLoader } from '@cherrystudio/embedjs-loader-web'
import { loggerService } from '@logger'
import { readTextFileWithAutoEncoding } from '@main/utils/file'
import { LoaderReturn } from '@shared/config/types'
import { FileMetadata, KnowledgeBaseParams } from '@types'
import type { LoaderReturn } from '@shared/config/types'
import type { FileMetadata, KnowledgeBaseParams } from '@types'
import { DraftsExportLoader } from './draftsExportLoader'
import { EpubLoader } from './epubLoader'

View File

@@ -3,7 +3,8 @@ import { cleanString } from '@cherrystudio/embedjs-utils'
import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters'
import { loggerService } from '@logger'
import md5 from 'md5'
import { OfficeParserConfig, parseOfficeAsync } from 'officeparser'
import type { OfficeParserConfig } from 'officeparser'
import { parseOfficeAsync } from 'officeparser'
const logger = loggerService.withContext('OdLoader')

View File

@@ -4,7 +4,7 @@ import path from 'node:path'
import { loggerService } from '@logger'
import { windowService } from '@main/services/WindowService'
import { getFileExt, getTempDir } from '@main/utils/file'
import { FileMetadata, PreprocessProvider } from '@types'
import type { FileMetadata, PreprocessProvider } from '@types'
import { PDFDocument } from 'pdf-lib'
const logger = loggerService.withContext('BasePreprocessProvider')

Some files were not shown because too many files have changed in this diff Show More