diff --git a/docs/user-manual.md b/docs/user-manual.md index de84770..bdc87f8 100644 --- a/docs/user-manual.md +++ b/docs/user-manual.md @@ -120,7 +120,7 @@ The configuration editor on the right is divided into several sections. - **Permissions**: default mode, disable `bypassPermissions`, allow / deny / ask rules, additional directories, and recommended rule presets. - **Sandbox**: can be enabled or disabled, with recommended presets to add; complex configurations can switch to JSON mode. - **Hooks**: maintain Claude Code hooks with a summary view, add the built-in garbled-text check preset, and switch complex structures to JSON mode. -- **Plugin marketplaces**: maintain `extraKnownMarketplaces` with support for the official marketplace preset; each marketplace must fully specify the ID, source, repository or URL, path, package name, and install location. +- **Plugin marketplaces**: maintain `extraKnownMarketplaces` with built-in presets for the official marketplace (`claude-plugins-official`) and community marketplace (`claude-community`, repository `anthropics/claude-plugins-community`), available from both marketplace settings and Browse Marketplaces; each marketplace must fully specify the ID, source, repository or URL, path, package name, and install location. - **Plugins**: maintain `enabledPlugins`, split into two tabs, "Configured" and "Browse marketplace". Browsing the marketplace currently supports only the `github` source; you can filter by marketplace / enabled status / category / source, and clicking enable immediately syncs it to the configured list. - **Status line**: configure a custom status line command, and optionally enable the default status line preset (non-Windows writes `~/.claude/statusline.sh`; Windows writes `~/.claude/statusline.ps1` and automatically sets the PowerShell invocation command), and also sets a 60-second refresh interval so countdowns such as the prompt cache expiry keep updating while idle; if the target already exists with different content, you are prompted whether to overwrite. - **Final configuration**: preview the final JSON after merging the provider with the configuration; the source JSON mode lets you maintain the entire settings object directly, and the preview automatically adds the schema URL. diff --git a/docs/user-manual.zh-CN.md b/docs/user-manual.zh-CN.md index ece38ba..d82ff50 100644 --- a/docs/user-manual.zh-CN.md +++ b/docs/user-manual.zh-CN.md @@ -120,7 +120,7 @@ Skills 对应 `~/.claude/skills//SKILL.md`。启用的 Skill 保存在 `~/.c - **权限**:默认模式、禁用 `bypassPermissions`、允许 / 拒绝 / 询问规则、附加目录、推荐规则预设。 - **Sandbox**:可启用或关闭,可添加推荐预设;复杂配置可切换 JSON 模式。 - **Hooks**:维护 Claude Code hooks,支持摘要展示,可添加内置乱码检查预设,复杂结构可切 JSON 模式。 -- **插件市场**:维护 `extraKnownMarketplaces`,支持官方市场预设;每个 Marketplace 需完整填写 ID、来源、仓库或 URL、路径、包名、安装位置。 +- **插件市场**:维护 `extraKnownMarketplaces`,支持官方市场(`claude-plugins-official`)与社区市场(`claude-community`,仓库 `anthropics/claude-plugins-community`)内置预设,可从市场配置或浏览市场一键添加;每个 Marketplace 需完整填写 ID、来源、仓库或 URL、路径、包名、安装位置。 - **插件**:维护 `enabledPlugins`,分"已配置"和"浏览市场"两个 Tab。浏览市场目前仅支持 `github` 来源,可按 Marketplace / 启用状态 / 类别 / 来源筛选,点击启用会立即同步到已配置列表。 - **状态行**:配置自定义状态行命令,可启用默认状态行预设(非 Windows 写入 `~/.claude/statusline.sh`,Windows 写入 `~/.claude/statusline.ps1` 并自动设置 PowerShell 调用命令),同时写入 60 秒刷新间隔,使缓存有效期等倒计时在空闲时也能更新;目标已存在且内容不同时会提示是否覆盖。 - **最终配置**:预览供应商与配置合并后的最终 JSON;源 JSON 模式可直接维护整个 settings 对象,预览自动加入 schema 地址。 diff --git a/src/components/profile-editor/BrowseMarketplaceTab.tsx b/src/components/profile-editor/BrowseMarketplaceTab.tsx index a16f500..fbd479f 100644 --- a/src/components/profile-editor/BrowseMarketplaceTab.tsx +++ b/src/components/profile-editor/BrowseMarketplaceTab.tsx @@ -1,6 +1,6 @@ import { useVirtualizer } from "@tanstack/react-virtual"; import { openUrl } from "@tauri-apps/plugin-opener"; -import { ArrowDown, ArrowUp, ArrowUpDown, CircleCheck, Info, RefreshCw, Store } from "lucide-react"; +import { ArrowDown, ArrowUp, ArrowUpDown, Info, Plus, RefreshCw, Store } from "lucide-react"; import type { KeyboardEvent, ReactNode } from "react"; import { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from "react"; import { useToast } from "@/hooks/useToast"; @@ -25,7 +25,7 @@ import MarketplacePluginRow from "./MarketplacePluginRow"; import type { MarketplacePluginEntry } from "./marketplace-catalog"; import { getProviderAffiliation } from "./marketplace-catalog"; import { estimatePluginRowSize } from "./marketplace-plugin-row-utils"; -import { OFFICIAL_MARKETPLACE_ID, OFFICIAL_MARKETPLACE_REPO } from "./marketplace-presets"; +import { BUILTIN_MARKETPLACES, type BuiltinMarketplace } from "./marketplace-presets"; import { emptyPluginCatalog, loadPluginCatalog, @@ -95,7 +95,7 @@ function getAriaSort(direction: SortDirection): "ascending" | "descending" { // owner/repo 格式校验 const GITHUB_REPO_PATTERN = /^[^/\s]+\/[^/\s]+$/; -// 浏览页快速添加 github 插件市场的轻量 Popover:一键官方 + 自定义仓库 +// 浏览页快速添加 github 插件市场的轻量 Popover:内置市场 + 自定义仓库 function AddMarketplacePopover({ existingMarketplaceIds, onAddMarketplace, @@ -113,7 +113,9 @@ function AddMarketplacePopover({ const [repo, setRepo] = useState(""); const [error, setError] = useState(""); - const officialPresent = existingMarketplaceIds.includes(OFFICIAL_MARKETPLACE_ID); + const availablePresets = BUILTIN_MARKETPLACES.filter( + (preset) => !existingMarketplaceIds.includes(preset.marketplaceId), + ); function handleOpenChange(next: boolean) { setOpen(next); @@ -123,10 +125,10 @@ function AddMarketplacePopover({ } } - function handleAddOfficial() { + function handleAddBuiltin(preset: BuiltinMarketplace) { onAddMarketplace({ - marketplaceId: OFFICIAL_MARKETPLACE_ID, - repo: OFFICIAL_MARKETPLACE_REPO, + marketplaceId: preset.marketplaceId, + repo: preset.repo, ref: "", path: "", }); @@ -168,17 +170,20 @@ function AddMarketplacePopover({
{t("profileEditor.plugins.browse.addMarketplaceTitle")}
- {!officialPresent && ( + {availablePresets.length > 0 && ( <> - + {availablePresets.map((preset) => ( + + ))}
{t("profileEditor.plugins.browse.addMarketplaceOr")} diff --git a/src/components/profile-editor/MarketplaceEditor.tsx b/src/components/profile-editor/MarketplaceEditor.tsx index 51faf54..0d51787 100644 --- a/src/components/profile-editor/MarketplaceEditor.tsx +++ b/src/components/profile-editor/MarketplaceEditor.tsx @@ -18,7 +18,11 @@ import { type MarketplaceSourceType, readObject, } from "./editor-utils"; -import { buildOfficialMarketplaceDraft, OFFICIAL_MARKETPLACE_ID } from "./marketplace-presets"; +import { + BUILTIN_MARKETPLACES, + type BuiltinMarketplace, + buildBuiltinMarketplaceDraft, +} from "./marketplace-presets"; import RequiredBadge from "./RequiredBadge"; interface MarketplaceEditorProps { @@ -265,8 +269,12 @@ function MarketplaceEditor({ value, onChange, onError, showTitle = true }: Marke }, ]; }, [draft, marketplaces]); - const hasOfficialMarketplace = useMemo( - () => marketplaces.some((marketplace) => marketplace.marketplaceId === OFFICIAL_MARKETPLACE_ID), + const availablePresets = useMemo( + () => + BUILTIN_MARKETPLACES.filter( + (preset) => + !marketplaces.some((marketplace) => marketplace.marketplaceId === preset.marketplaceId), + ), [marketplaces], ); @@ -371,15 +379,15 @@ function MarketplaceEditor({ value, onChange, onError, showTitle = true }: Marke resetEditor(buildNewDraft()); } - function handleAddOfficialMarketplace() { + function handleAddBuiltinMarketplace(preset: BuiltinMarketplace) { if (blockIfDirty()) { return; } - if (hasOfficialMarketplace) { + if (marketplaces.some((marketplace) => marketplace.marketplaceId === preset.marketplaceId)) { return; } - const nextMarketplaces = [...marketplaces, buildOfficialMarketplaceDraft()]; + const nextMarketplaces = [...marketplaces, buildBuiltinMarketplaceDraft(preset)]; setMarketplaces(nextMarketplaces); onChange(buildMarketplaceRecord(nextMarketplaces)); setInteractionError(""); @@ -826,12 +834,16 @@ function MarketplaceEditor({ value, onChange, onError, showTitle = true }: Marke
- {!hasOfficialMarketplace ? ( - - ) : null} + ))}