Files
CherryHQ-cherry-studio/scripts
SuYao 6b9daa749e feat: add plugin package installation from ZIP,directory, remote (#12426)
* feat: add plugin install

* fix: some bug

* fix: i18n

* refactor: rename 'active-directory' to 'resource'

* feat(plugin): support remote fetch plugin

* refactor: improve error display

* feat: add cache protocol

* fix(plugin): address code review issues for PR #12426

- Fix command injection vulnerability by adding -- separator before
  positional arguments in git clone and ls-remote commands
- Extract duplicate file helpers (directoryExists, fileExists, pathExists)
  to shared @main/utils/file utility
- Add depth limit (MAX_PLUGIN_ROOT_DEPTH=10) to findPluginRoots to
  prevent infinite recursion from symlink cycles
- Rename InstallFromZipResult to InstallFromSourceResult with type alias
  for backward compatibility
- Extract duplicate loadFirstPage logic in useMarketplaceBrowser hook
- Add documentation for intentionally disabled readContent and
  invalidateCache methods explaining API compatibility reasons

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

* docs(plugin): add documentation for marketplace API and telemetry

- Document MARKETPLACE_API_BASE_URL with API endpoints and usage
- Add TODO for China mainland accessibility testing
- Document reportSkillInstall telemetry behavior and data transmitted

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

* fix(plugin): fix skill installation and improve UI

- Fix skill installation using v2 resolve API endpoint
- Extract base repo URL from GitHub tree/blob URLs
- Fix skill card type label (skill -> skills key mapping)
- Split plugin settings into "Available Plugins" and "Installed Plugins" tabs
- Fix refresh button styling with aspect-square
- Add card vertical spacing with pb-4
- Add unit tests for extractBaseRepoUrl and extractResolvedSkill

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

* refactor(plugin): use useTimer for search debounce

Replace manual setTimeout/clearTimeout with useTimer hook for better
timer management and automatic cleanup on component unmount.

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

* style(plugin): use explicit unknown type in catch blocks

Change all catch blocks from `catch (error)` to `catch (error: unknown)`
for better type safety and code clarity.

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

* fix(plugin): only show content section for installed plugins

- Skip content fetching for marketplace plugins since readContent
  always fails for remote plugins
- Only display the Content section when viewing installed plugins
- Change catch (error) to catch (error: unknown) for type safety

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

* refactor(plugin): use Zod schemas for marketplace API responses

- Add PluginResolveResponseSchema for plugin resolution API
- Add ResolvedSkillSchema and SkillsResolveResponseSchema for v2 skills API
- Refactor extractRepositoryUrl to use Zod safeParse instead of manual type checking
- Refactor resolveSkillV2 to validate response with Zod and return typed array
- Update extractResolvedSkill to accept typed array directly
- Update tests to match new function signatures

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

* refactor(plugin): simplify code and reduce duplication

- Merge runCommand and captureCommand into executeCommand in PluginService
- Combine URL regex patterns and use constant map for plugin directories
- Create generic response parser factory in MarketplaceService
- Extract buildSkillSourceKey helper in useMarketplaceBrowser
- Remove unused displayedEntries variable in PluginBrowser
- Consolidate category config into single object in useResourcePanel
- Extract ensureCacheData helper method in PluginCacheStore

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

* fix(plugin): remove dead readContent and invalidateCache methods

Remove methods that were non-functional (always throwing or no-op):
- Remove invalidateCache() no-op method from PluginService
- Remove readContent() method that always throws
- Remove corresponding IPC handlers and preload bindings
- Remove IpcChannel enum entries for both methods
- Remove content section from PluginDetailModal (relied on readContent)
- Remove agentId prop from PluginBrowser (no longer needed)

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

* refactor(plugin): update plugin settings and UI components

- Change default page size in useMarketplaceBrowser from 100 to 40 for improved performance.
- Add titles to the installed plugins section in multiple language files for better clarity.
- Refactor AgentSettings components to improve structure and readability, including the introduction of a new PluginsSettings component.
- Update modal widths in AgentSettingsPopup and SessionSettingsPopup for better UI consistency.
- Integrate Scrollbar component in SettingsContainer for enhanced scrolling experience.

* refactor(settings): improve Scrollbar import and enhance type safety

- Change Scrollbar import to use type-only import for ScrollbarProps.
- Update handleVirtualChange function to handle null scrollOffset for better type safety.

* fix(plugin): install only selected plugin and fix uninstall lookup

Bug fixes:
- Install only the specific requested plugin from marketplace repo
  instead of installing all plugins found in the repository
- Use actual installed filename for uninstall instead of marketplace
  metadata filename (which differs due to sanitization)

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

* feat(plugin): support skill upload via drag-and-drop

Extended installFromSourceDir to detect and install skills:
- Check for plugin roots first (with .claude-plugin/plugin.json)
- If none found, search for skill directories (with SKILL.md)
- Install whichever type is detected

Added new methods:
- installSkillRoots: Install multiple skill directories
- installSkillFromDirectory: Install a single skill folder

Now users can drag-and-drop skill folders or ZIPs containing
skills to install them, not just plugin packages.

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

* test(browser): add beforeEach to reset mock state

Add vi.clearAllMocks() in beforeEach to prevent state leakage
between tests, which could cause flaky test failures in CI.

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: kangfenmao <kangfenmao@qq.com>
2026-02-04 14:26:37 +08:00
..
2025-05-11 00:37:01 +08:00