dsh-plugin 0.1.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.en.md +56 -28
  2. package/README.md +56 -28
  3. package/client/client.js +2282 -230
  4. package/client/client.js.map +1 -1
  5. package/lib/http/routes.js +432 -0
  6. package/lib/index.js +17 -8
  7. package/lib/services/install-types.js +11 -0
  8. package/lib/services/install.js +4 -0
  9. package/lib/services/installed-versions.js +66 -0
  10. package/lib/services/loader.js +98 -0
  11. package/lib/services/npm-resolve.js +67 -0
  12. package/lib/services/pending-restart.js +34 -0
  13. package/lib/services/preflight.js +94 -0
  14. package/lib/services/profile.js +88 -0
  15. package/lib/services/progress.js +50 -0
  16. package/lib/services/task-queue.js +457 -0
  17. package/lib/types/http/routes.d.ts +23 -0
  18. package/lib/types/index.d.ts +27 -0
  19. package/lib/types/services/install-types.d.ts +69 -0
  20. package/lib/types/services/install.d.ts +18 -0
  21. package/lib/types/services/installed-versions.d.ts +24 -0
  22. package/lib/types/services/loader.d.ts +43 -0
  23. package/lib/types/services/npm-resolve.d.ts +6 -0
  24. package/lib/types/services/pending-restart.d.ts +13 -0
  25. package/lib/types/services/preflight.d.ts +6 -0
  26. package/lib/types/services/profile.d.ts +24 -0
  27. package/lib/types/services/progress.d.ts +17 -0
  28. package/lib/types/services/task-queue.d.ts +82 -0
  29. package/package.json +27 -6
  30. package/src/client/components/CatalogControls.tsx +104 -0
  31. package/src/client/components/CatalogHeader.tsx +78 -0
  32. package/src/client/components/CatalogList.tsx +75 -0
  33. package/src/client/components/CategoryTabs.tsx +35 -0
  34. package/src/client/components/Dropdown.tsx +80 -0
  35. package/src/client/components/NotificationsModal.tsx +243 -0
  36. package/src/client/components/PluginCard.tsx +104 -0
  37. package/src/client/components/PluginHubSection.tsx +342 -0
  38. package/src/client/components/ProgressView.tsx +23 -0
  39. package/src/client/components/icons.tsx +125 -0
  40. package/src/client/components/modals.tsx +368 -0
  41. package/src/client/hooks/useCatalog.ts +202 -0
  42. package/src/client/hooks/useTaskQueue.ts +502 -0
  43. package/src/client/index.tsx +8 -422
  44. package/src/client/lib/catalog.ts +240 -0
  45. package/src/client/lib/env.ts +16 -0
  46. package/src/client/lib/failures.ts +165 -0
  47. package/src/client/lib/format.ts +22 -0
  48. package/src/client/locales.ts +188 -18
  49. package/src/client/styles/Dropdown.module.css +123 -0
  50. package/src/client/styles/Header.module.css +432 -0
  51. package/src/client/styles/List.module.css +324 -0
  52. package/src/client/styles/Modal.module.css +1006 -0
  53. package/src/client/styles/tokens.module.css +91 -0
  54. package/src/client/types.ts +80 -0
  55. package/src/server/http/routes.ts +432 -0
  56. package/src/server/index.ts +35 -0
  57. package/src/server/services/install-types.ts +69 -0
  58. package/src/server/services/install.ts +18 -0
  59. package/src/server/services/installed-versions.ts +84 -0
  60. package/src/server/services/loader.ts +110 -0
  61. package/src/server/services/npm-resolve.ts +67 -0
  62. package/src/server/services/pending-restart.ts +36 -0
  63. package/src/server/services/preflight.ts +97 -0
  64. package/src/server/services/profile.ts +89 -0
  65. package/src/server/services/progress.ts +48 -0
  66. package/src/server/services/task-queue.ts +492 -0
  67. package/src/client/Section.module.css +0 -589
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","useRef","useMemo","h","styles"],"sources":["../src/client/locales.ts","../src/client/index.tsx"],"sourcesContent":["/** zh/en dictionaries for the DSH-Plugin Hub settings section. */\nexport const zh = {\n nav: '插件中心',\n title: 'DSH-Plugin Hub for DeepSeek Harness',\n // 收录/精选数量由组件从官网 /api/stats.json 实时拉取填充({total}/{verified}),不写死\n tagline: 'DSH plugin 插件中心:收录 {total} 个 DeepSeek Harness 插件,人工精选验证 {verified},每日更新 · 免费安装',\n adBadge: '推荐',\n ad: 'DSH-Plugin 插件中心:收录 {total} 个 DeepSeek Harness 插件,其中 {verified} 人工精选验证,每日更新,免费按分类浏览、搜索、下载与安装,人工验证、来源可溯',\n search: '搜索插件名称、描述、标签…',\n all: '全部',\n sortStars: 'Star 最多',\n sortUpdated: '最近更新',\n sortNewest: '最新收录',\n open: '在浏览器中打开',\n openHint: '打开 dsh-plugin.org',\n openBtn: 'DSH-Plugin 官网',\n toEn: 'Switch to English',\n fork: 'Fork',\n loading: '正在加载插件数据…',\n failed: '插件数据加载失败',\n failedDesc: '请稍后重试,或点击右上角按钮在浏览器中打开插件中心。',\n retry: '重试',\n copy: '复制安装命令',\n toastCopied: '安装命令已复制,去 dsh 终端粘贴即可安装',\n detail: '打开详情',\n noResult: '没有找到匹配的插件',\n noResultDesc: '换个关键词试试,或前往网站浏览全部插件。',\n today: '今天更新',\n daysAgo: '更新于 {days} 天前',\n monthsAgo: '更新于 {months} 个月前',\n yearsAgo: '更新于 {years} 年前',\n pluginsTotal: '共 {n} 个插件',\n filteredCount: '匹配 {n} 个',\n more: '还有 {n} 个插件,去网站查看全部',\n browseAll: '浏览全部 {n} 个插件',\n verified: '已验证',\n empty: '该分类暂无插件',\n dataFrom: '数据源 dsh-plugin.org · 每日人工更新',\n}\n\nexport const en = {\n nav: 'Plugin Hub',\n title: 'DSH-Plugin Hub for DeepSeek Harness',\n // Plugin counts are filled from the live /api/stats.json ({total}/{verified}), never hardcoded\n tagline: 'DSH plugin marketplace · {total} DeepSeek Harness plugins indexed · {verified} human-verified · updated daily · free to install',\n adBadge: 'Featured',\n ad: 'DSH-Plugin Hub: {total} DeepSeek Harness plugins indexed, {verified} of which are human-verified. Updated daily — browse, search & install for free.',\n search: 'Search plugins by name, description, tags…',\n all: 'All',\n sortStars: 'Most stars',\n sortUpdated: 'Recently updated',\n sortNewest: 'Newest added',\n open: 'Open in browser',\n openHint: 'Open dsh-plugin.org',\n openBtn: 'dsh-plugin.org',\n toZh: 'Switch to Chinese',\n fork: 'Fork',\n loading: 'Loading plugin data…',\n failed: 'Failed to load plugin data',\n failedDesc: 'Please retry, or open the hub in your browser with the button above.',\n retry: 'Retry',\n copy: 'Copy install command',\n toastCopied: 'Install command copied — paste it in your dsh terminal',\n detail: 'Open details',\n noResult: 'No plugins match your search',\n noResultDesc: 'Try another keyword, or browse all plugins on the website.',\n today: 'updated today',\n daysAgo: 'updated {days}d ago',\n monthsAgo: 'updated {months}mo ago',\n yearsAgo: 'updated {years}y ago',\n pluginsTotal: '{n} plugins',\n filteredCount: '{n} matched',\n more: '{n} more on the website',\n browseAll: 'Browse all {n} plugins',\n verified: 'Verified',\n empty: 'No plugins in this category yet',\n dataFrom: 'Data from dsh-plugin.org · curated daily',\n}\n","/**\n * dsh-plugin client: a native \"Plugin Hub\" settings section that renders\n * the community marketplace (dsh-plugin.org) as a first-class catalog —\n * category tabs (11 categories + All), search, sorting and one-click\n * install-command copy. Plugin data is fetched live from dsh-plugin.org,\n * so the browser bundle stays small and always in sync with the site.\n *\n * Built by tsdown into the __ModuleLoader__ factory bundle at client/client.js.\n */\nimport { createElement as h, useEffect, useMemo, useRef, useState } from 'react'\nimport styles from './Section.module.css'\nimport { en, zh } from './locales.ts'\n\nconst NS = 'dsh-plugin'\nconst SITE_URL = 'https://dsh-plugin.org/'\n\ntype LocaleId = 'zh' | 'en'\n\n/** The subset of the locale service this plugin touches. */\ninterface LocaleService {\n register(namespace: string, dicts: { zh: Record<string, string>; en: Record<string, string> }): unknown\n bind(namespace: string): (key: string, params?: Record<string, string | number>) => string\n getSnapshot(): { active: LocaleId }\n subscribe(fn: () => void): () => void\n}\n\n/** The subset of the slots service this plugin touches. */\ninterface SlotsService {\n inject(slot: string, register: () => unknown): void\n register(meta: Record<string, unknown>, component: () => unknown): unknown\n}\n\n/** The client cordis context shape this plugin relies on (structural). */\ninterface HubClientContext {\n effect(callback: () => unknown, label?: string): void\n slots: SlotsService\n locale: LocaleService\n}\n\ninterface SectionProps {\n t: (key: string, params?: Record<string, string | number>) => string\n locale: LocaleService\n}\n\n/** Slim projection of the site's DirectoryPlugin entries. */\ninterface HubPlugin {\n /** 作者小写 key,与 slug 共同构成唯一身份(两级路径 /plugins/{ownerSlug}/{slug});旧数据可能缺省 */\n ownerSlug?: string\n slug: string\n displayName?: string\n category?: string\n topics?: string[]\n features?: string[]\n description?: string\n source?: { repo?: string }\n compatibility?: { status?: string }\n dates?: { repoUpdatedAt?: string; addedAt?: string }\n stats?: { stargazers_count?: number; forks_count?: number }\n}\n\nconst CATEGORY_ORDER = [\n 'interface', 'session', 'memory', 'tools', 'agent', 'workflow',\n 'integration', 'model', 'dev', 'knowledge', 'fun',\n]\n\n/**\n * 归一化在线 API(dsh-plugin.org/api/plugins.{lang}.json)返回的短 key 结构\n * (s/o/n/c/t/f/d/r/v/u/a/sg/fk),统一为 HubPlugin,保证渲染逻辑只认一种结构。\n */\nfunction normalize(raw: Record<string, unknown>): HubPlugin {\n if (typeof raw.s === 'string') {\n return {\n slug: raw.s,\n ownerSlug: typeof raw.o === 'string' ? raw.o : undefined,\n displayName: typeof raw.n === 'string' ? raw.n : undefined,\n category: typeof raw.c === 'string' ? raw.c : undefined,\n topics: Array.isArray(raw.t) ? (raw.t as string[]) : undefined,\n features: Array.isArray(raw.f) ? (raw.f as string[]) : undefined,\n description: typeof raw.d === 'string' ? raw.d : undefined,\n source: typeof raw.r === 'string' ? { repo: raw.r } : undefined,\n compatibility: typeof raw.v === 'string' ? { status: raw.v } : undefined,\n dates: {\n repoUpdatedAt: typeof raw.u === 'string' ? raw.u : undefined,\n addedAt: typeof raw.a === 'string' ? raw.a : undefined,\n },\n stats: {\n stargazers_count: typeof raw.sg === 'number' ? raw.sg : undefined,\n forks_count: typeof raw.fk === 'number' ? raw.fk : undefined,\n },\n }\n }\n return raw as unknown as HubPlugin\n}\n\nconst CATEGORY_LABELS: Record<string, { zh: string; en: string }> = {\n interface: { zh: '界面与体验', en: 'UI & Experience' },\n session: { zh: '会话与消息', en: 'Sessions & Messages' },\n memory: { zh: '记忆与上下文', en: 'Memory & Context' },\n tools: { zh: '工具与能力', en: 'Tools & Capabilities' },\n agent: { zh: '技能与智能体', en: 'Skills & Agents' },\n workflow: { zh: '工作流与自动化', en: 'Workflow & Automation' },\n integration: { zh: '集成与连接', en: 'Integrations & Connections' },\n model: { zh: '模型与推理', en: 'Models & Reasoning' },\n dev: { zh: '开发与运维', en: 'Development & Operations' },\n knowledge: { zh: '数据与知识', en: 'Data & Knowledge' },\n fun: { zh: '娱乐', en: 'Entertainment' },\n}\n\nconst CATEGORY_SHORT_LABELS: Record<string, { zh: string; en: string }> = {\n interface: { zh: '界面体验', en: 'UI Exp' },\n session: { zh: '会话消息', en: 'Sessions' },\n memory: { zh: '记忆上下文', en: 'Memory' },\n tools: { zh: '工具能力', en: 'Tools' },\n agent: { zh: '技能智能体', en: 'Agents' },\n workflow: { zh: '工作流', en: 'Workflow' },\n integration: { zh: '集成连接', en: 'Integrations' },\n model: { zh: '模型推理', en: 'Models' },\n dev: { zh: '开发运维', en: 'Dev' },\n knowledge: { zh: '数据知识', en: 'Knowledge' },\n fun: { zh: '娱乐', en: 'Fun' },\n}\n\nconst SORTS = ['sortStars', 'sortUpdated', 'sortNewest'] as const\ntype SortKey = (typeof SORTS)[number]\n\nfunction fmtStars(count?: number): string {\n if (!count || count <= 0) return '0'\n if (count < 1000) return String(count)\n const k = count / 1000\n return `${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\\.0$/, '')}k`\n}\n\nfunction relTime(iso: string | undefined, t: SectionProps['t']): string {\n if (!iso) return ''\n const days = Math.floor((Date.now() - new Date(iso).getTime()) / 86400000)\n if (days <= 0) return t('today')\n if (days < 30) return t('daysAgo', { days })\n if (days < 365) return t('monthsAgo', { months: Math.floor(days / 30) })\n return t('yearsAgo', { years: Math.floor(days / 365) })\n}\n\nfunction PluginHubSection({ t: _hostT, locale }: SectionProps) {\n const [lang, setLang] = useState<LocaleId>(locale.getSnapshot().active)\n const [plugins, setPlugins] = useState<HubPlugin[] | null>(null)\n /** 收录/精选统计(官网 /api/stats.json 实时拉取) */\n const [stats, setStats] = useState<{ total: number; verified: number } | null>(null)\n const [failed, setFailed] = useState(false)\n const [reloadKey, setReloadKey] = useState(0)\n const [category, setCategory] = useState('all')\n const [query, setQuery] = useState('')\n const [sort, setSort] = useState<SortKey>('sortStars')\n const [copied, setCopied] = useState<string | null>(null)\n /** 全局复制成功 Toast:{id} 用于重复点击时重新触发入场动画 */\n const [toast, setToast] = useState<{ id: number } | null>(null)\n /** 列表滚动容器:分类/搜索切换后列表内容替换但 scrollTop 保留,会让用户误以为列表没更新,需重置回顶部 */\n const listRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n listRef.current?.scrollTo({ top: 0 })\n }, [category])\n\n useEffect(() => locale.subscribe(() => setLang(locale.getSnapshot().active)), [locale])\n\n useEffect(() => {\n let cancelled = false\n setPlugins(null)\n setStats(null)\n setFailed(false)\n const apply = (data: unknown) => {\n if (cancelled) return\n // 在线 API 已只返回 verified;再过滤一次,保证只展示人工验证通过的插件。\n const list = (Array.isArray(data) ? data : []).map((item) => normalize(item as Record<string, unknown>))\n setPlugins(list.filter((p) => p.compatibility?.status === 'verified'))\n }\n const fail = () => {\n if (!cancelled) setFailed(true)\n }\n const fetchData = (url: string): Promise<unknown> =>\n fetch(url).then((res) => {\n if (!res.ok) throw new Error(String(res.status))\n return res.json()\n })\n // 在线拉取最新数据(dsh-plugin.org,走 CDN 缓存),插件不发布也能拿到每日更新。\n const remote = `https://dsh-plugin.org/api/plugins.${lang}.json`\n fetchData(remote).then(apply).catch(fail)\n // 收录/精选统计:实时拉取官网 /api/stats.json。\n const applyStats = (s: { total: number; verified: number }) => {\n if (!cancelled && s && typeof s.total === 'number' && typeof s.verified === 'number') setStats(s)\n }\n fetchData('https://dsh-plugin.org/api/stats.json')\n .then((s) => applyStats(s as { total: number; verified: number }))\n .catch(() => {})\n return () => { cancelled = true }\n }, [lang, reloadKey])\n\n const visible = useMemo(() => {\n if (!plugins) return []\n const q = query.trim().toLowerCase()\n const list = plugins.filter((p) => {\n if (category !== 'all' && p.category !== category) return false\n if (!q) return true\n return (\n (p.displayName ?? '').toLowerCase().includes(q) ||\n (p.description ?? '').toLowerCase().includes(q) ||\n (p.topics ?? []).some((topic) => topic.toLowerCase().includes(q))\n )\n })\n return [...list].sort((a, b) => {\n if (sort === 'sortStars') return (b.stats?.stargazers_count ?? 0) - (a.stats?.stargazers_count ?? 0)\n if (sort === 'sortNewest') return (b.dates?.addedAt ?? '').localeCompare(a.dates?.addedAt ?? '')\n return (b.dates?.repoUpdatedAt ?? '').localeCompare(a.dates?.repoUpdatedAt ?? '')\n })\n }, [plugins, category, query, sort])\n\n const langKey: LocaleId = lang === 'en' ? 'en' : 'zh'\n // dsh-plugin.org keeps zh pages under the /zh/ prefix; en is the root.\n const langPath = lang === 'zh' ? 'zh/' : ''\n\n // 插件界面语言由组件自身 lang 控制(左上角 EN/中文 按钮),宿主的 t() 绑定宿主 locale、\n // 不跟随组件内 lang,因此这里基于本地字典自建翻译函数,保证切换语言后所有文本即时刷新。\n // (settings.section 的导航 label 仍在 apply 里用宿主 t(),跟随宿主语言。)\n const dict: Record<string, string> = langKey === 'en' ? en : zh\n const t = (key: string, params?: Record<string, string | number>): string => {\n const raw = dict[key] ?? key\n return params ? raw.replace(/\\{(\\w+)\\}/g, (_, k) => String(params[k] ?? '')) : raw\n }\n const catLabel = (map: Record<string, { zh: string; en: string }>, key: string): string =>\n map[key]?.[langKey] ?? key\n\n const copyInstall = async (repo: string) => {\n const text = `dsh plugin add ${repo}`\n let ok = false\n try {\n await navigator.clipboard.writeText(text)\n ok = true\n } catch {\n // Clipboard API unavailable (permissions/iframe) — fall back to the\n // legacy hidden-textarea trick, which works in any context.\n const ta = document.createElement('textarea')\n ta.value = text\n ta.style.position = 'fixed'\n ta.style.opacity = '0'\n document.body.appendChild(ta)\n ta.select()\n try {\n ok = document.execCommand('copy')\n } catch {\n ok = false\n }\n document.body.removeChild(ta)\n }\n if (ok) {\n setCopied(repo)\n setToast({ id: Date.now() })\n window.setTimeout(() => setCopied((cur) => (cur === repo ? null : cur)), 1600)\n window.setTimeout(() => setToast(null), 1800)\n } else {\n setCopied(null)\n }\n }\n\n const total = plugins?.length ?? 0\n const count = visible.length\n\n // 统计数字:官网 /api/stats.json 优先;拉取失败时用已加载列表兜底,避免展示 undefined。\n const statsTotal = stats?.total ?? total\n const statsVerified = stats?.verified ?? 0\n\n // Per-category plugin counts shown on the category chips.\n const categoryCounts = useMemo(() => {\n const counts: Record<string, number> = { all: total }\n for (const p of plugins ?? []) {\n if (p.category) counts[p.category] = (counts[p.category] ?? 0) + 1\n }\n return counts\n }, [plugins, total])\n\n return h('div', { className: styles.root },\n h('div', { className: styles.header },\n h('div', { className: styles.brand },\n h('div', { className: styles.brandText },\n // 市场主标题即本区块的 H1:与官网首页 H1 同文案(DSH-Plugin Hub for DeepSeek\n // Harness),命中品牌词 DSH-Plugin + 产品词 DeepSeek Harness;关键词落在 tagline。\n h('h1', { className: styles.title }, t('title')),\n h('div', { className: styles.tagline }, t('tagline', { total: statsTotal, verified: statsVerified })),\n ),\n ),\n h('div', { className: styles.controls },\n h('input', {\n className: styles.search,\n type: 'search',\n placeholder: t('search'),\n value: query,\n spellCheck: false,\n onInput: (e: React.FormEvent<HTMLInputElement>) =>\n setQuery((e.target as HTMLInputElement).value),\n }),\n h('select', {\n className: styles.sort,\n value: sort,\n onChange: (e: React.FormEvent<HTMLSelectElement>) =>\n setSort((e.target as HTMLSelectElement).value as SortKey),\n }, SORTS.map((key) => h('option', { key, value: key }, t(key)))),\n h('button', {\n className: styles.langBtn,\n title: lang === 'zh' ? t('toEn') : t('toZh'),\n onClick: () => setLang(lang === 'zh' ? 'en' : 'zh'),\n }, lang === 'zh' ? 'EN' : '中文'),\n h('a', {\n className: styles.openBtn,\n href: `${SITE_URL}${langPath}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('openHint'),\n }, t('openBtn'), h('span', { className: styles.openArrow }, '\\u2197')),\n ),\n ),\n\n h('a', {\n className: styles.adBanner,\n href: `${SITE_URL}${langPath}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n },\n h('span', { className: styles.adBadge }, t('adBadge')),\n h('span', { className: styles.adText }, t('ad', { total: statsTotal, verified: statsVerified })),\n h('span', { className: styles.adArrow }, '\\u2197')),\n\n h('div', { className: styles.tabs },\n h('button', {\n key: 'all',\n className: category === 'all' ? styles.tabActive : styles.tab,\n onClick: () => setCategory('all'),\n },\n t('all'),\n h('span', { className: category === 'all' ? styles.tabCountActive : styles.tabCount }, total)),\n CATEGORY_ORDER.map((id) => h('button', {\n key: id,\n className: category === id ? styles.tabActive : styles.tab,\n onClick: () => setCategory(id),\n },\n catLabel(CATEGORY_SHORT_LABELS, id),\n h('span', { className: category === id ? styles.tabCountActive : styles.tabCount }, categoryCounts[id] ?? 0))),\n ),\n\n h('div', { className: styles.body },\n h('div', { ref: listRef, className: styles.list },\n plugins === null && !failed && h('div', { className: styles.state }, t('loading')),\n failed && h('div', { className: styles.state },\n h('div', { className: styles.stateTitle }, t('failed')),\n h('div', { className: styles.stateDesc }, t('failedDesc')),\n h('button', { className: styles.retryBtn, onClick: () => setReloadKey((k) => k + 1) }, t('retry')),\n ),\n plugins !== null && !failed && count === 0 && h('div', { className: styles.state },\n h('div', { className: styles.stateTitle }, t('noResult')),\n h('div', { className: styles.stateDesc }, t('noResultDesc')),\n ),\n plugins !== null && !failed && visible.map((p) => {\n const repo = p.source?.repo ?? ''\n const isCopied = copied === repo\n return h('div', {\n // 唯一 key:数据重构后同一 slug 可能对应多个作者仓库,仅用 slug 会撞 key,\n // 导致切换分类时 React 复用旧 DOM、列表不刷新。\n key: p.ownerSlug ? `${p.ownerSlug}/${p.slug}` : p.slug,\n className: styles.card,\n },\n h('div', { className: styles.cardMain },\n h('div', { className: styles.cardHead },\n h('div', { className: styles.cardTitle, title: p.description ?? '' }, p.displayName ?? p.slug),\n p.category ? h('span', { className: styles.categoryBadge }, catLabel(CATEGORY_LABELS, p.category)) : null,\n p.compatibility?.status === 'verified'\n ? h('span', { className: styles.verified }, t('verified'))\n : null,\n ),\n // 英文模式下隐藏仍为中文的描述:站点英文数据缺翻译时 description 会回退成中文,\n // 不显示可保证界面语言一致,不残留中文字符。\n p.description && (langKey === 'zh' || !/[\\u4e00-\\u9fff]/.test(p.description))\n ? h('p', { className: styles.desc }, p.description)\n : null,\n (p.topics?.length ?? 0) > 0\n ? h('div', { className: styles.topics },\n p.topics!.slice(0, 3).map((topic) => h('span', { key: topic, className: styles.topic }, topic)),\n )\n : null,\n ),\n h('div', { className: styles.cardSide },\n h('div', { className: styles.stats },\n h('span', { className: styles.star }, '\\u2605 ', fmtStars(p.stats?.stargazers_count)),\n h('span', { className: styles.fork }, t('fork'), ' ', fmtStars(p.stats?.forks_count)),\n h('span', { className: styles.date }, relTime(p.dates?.repoUpdatedAt, t)),\n ),\n repo\n ? h('div', { className: styles.actions },\n h('a', {\n className: styles.detailBtn,\n // 两级路径:/plugins/{ownerSlug}/{slug};旧数据缺 ownerSlug 时从 repo 推导\n href: `${SITE_URL}${langPath}plugins/${p.ownerSlug ?? repo.split('/')[0]?.toLowerCase() ?? ''}/${p.slug}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n title: p.slug,\n }, t('detail')),\n h('button', {\n className: isCopied ? styles.installBtnCopied : styles.installBtn,\n // 文字恒定避免按钮宽度变化导致卡片跳动;成功反馈 = 蓝底高亮 + 右下角 Toast\n onClick: () => copyInstall(repo),\n }, t('copy')),\n )\n : null,\n ),\n )\n }),\n ),\n plugins !== null && !failed && h('div', { className: styles.footer },\n h('span', { className: styles.footText }, count === total ? t('pluginsTotal', { n: total }) : t('filteredCount', { n: count })),\n h('a', {\n className: styles.footLink,\n href: `${SITE_URL}${langPath}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n }, t('browseAll', { n: total })),\n ),\n ),\n // 复制成功提示条:右下角纯黑色文字条,1800ms 后自动消失\n toast && h('div', { key: toast.id, className: styles.toast }, t('toastCopied')),\n )\n}\n\nexport const name = NS\nexport const inject = ['slots', 'locale']\n\nexport function apply(ctx: HubClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-plugin: dictionaries')\n const t = ctx.locale.bind(NS)\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: NS,\n order: 60,\n label: () => t('nav'),\n locale: NS,\n inject: () => ({ t, locale: ctx.locale }),\n }, () => h(PluginHubSection, { t, locale: ctx.locale })))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useState","useMemo","useState","useRef","h","modalStyles","headerStyles","h","styles","h","styles","h","styles","h","Fragment","styles","h","styles","useState","useRef","h","styles","h","Fragment","styles","h","styles","useRef","h","styles","useState","h","styles","h"],"sources":["../src/client/locales.ts","../src/client/lib/failures.ts","../src/client/lib/catalog.ts","../src/client/lib/env.ts","../src/client/hooks/useCatalog.ts","../src/client/hooks/useTaskQueue.ts","../src/client/components/icons.tsx","../src/client/components/ProgressView.tsx","../src/client/components/modals.tsx","../src/client/components/NotificationsModal.tsx","../src/client/components/CatalogHeader.tsx","../src/client/components/CategoryTabs.tsx","../src/client/components/Dropdown.tsx","../src/client/components/CatalogControls.tsx","../src/client/lib/format.ts","../src/client/components/PluginCard.tsx","../src/client/components/CatalogList.tsx","../src/client/components/PluginHubSection.tsx","../src/client/index.tsx"],"sourcesContent":["/** zh/en dictionaries for the DSH-Plugin Hub settings section. */\nexport const zh = {\n nav: '插件中心',\n title: 'DSH-Plugin Hub',\n // 收录/精选数量由组件从官网 /api/stats.json 实时拉取填充({total}/{verified}),不写死\n tagline: 'DSH-Plugin 插件中心:面向 DeepSeek Harness 插件收录平台,人工审验、来源可溯,免费安装',\n adBadge: '推荐',\n // 紫色广告横幅:突出数量(显眼)+ 更新节奏,与 tagline 职责分开、不重复\n ad: 'DSH-Plugin 插件中心:收录 {total} 款插件,{verified} 款人工精选验证,每日更新',\n search: '搜索插件名称、描述、标签…',\n all: '全部',\n sortStars: 'Star 最多',\n sortForks: 'Fork 最多',\n sortUpdated: '最近更新',\n sortNewest: '最新收录',\n openHint: '打开 dsh-plugin.org',\n toggleLangHint: '切换界面语言',\n fork: 'Fork',\n loading: '正在加载插件数据…',\n failed: '插件数据加载失败',\n failedDesc: '请稍后重试,或点击右上角按钮在浏览器中打开插件中心。',\n retry: '重试',\n install: '安装',\n toastCopied: '安装命令已复制,去 dsh 终端粘贴即可安装',\n installed: '已安装',\n notInstalled: '未安装',\n filterAllHint: '显示全部插件',\n filterInstalledHint: '筛选当前分类下的已安装插件',\n filterNotInstalledHint: '筛选当前分类下的未安装插件',\n filterInstalledNone: '当前分类下没有已安装插件',\n filterNotInstalledNone: '当前分类下没有未安装插件',\n uninstall: '卸载',\n uninstalling: '卸载中…',\n uninstallTitle: '确认卸载',\n uninstallDesc: '将从当前环境卸载该插件。',\n uninstallDone: '卸载成功',\n uninstallFail: '卸载失败,请稍后重试',\n uninstallResultTitle: '卸载完成',\n uninstallResultDesc: '插件已从当前环境移除。',\n confirmTitle: '确认安装',\n confirmDesc: '安装前请前往插件仓库仔细阅读源码,确认可信后再安装',\n confirmPlugin: '插件',\n confirmSource: '来源',\n confirmCommand: '安装命令',\n copyInstallCommand: '复制安装命令',\n copyCmdLabel: '复制',\n copyUninstallCommand: '复制卸载命令',\n installNow: '直接安装',\n installing: '安装中…',\n installDone: '安装成功',\n installResultTitle: '插件安装成功',\n installResultDesc: '',\n // 更新语义:已安装插件点「更新」走同一条 add 命令原位覆盖重装,弹窗文案区分安装/更新\n confirmUpdateTitle: '确认更新',\n updateNow: '直接更新',\n updating: '更新中…',\n queuedUpdateTitle: '已加入更新排队',\n updateResultTitle: '更新完成',\n updateResultDesc: '插件已更新到最新版本。',\n installFail: '安装失败',\n confirmCancel: '取消',\n doneBtn: '完成',\n // 结果视图:部分插件需重启后才挂载,提供「立即重启 / 稍后重启」选择\n restartNow: '立即重启',\n restartLater: '稍后重启',\n restarting: '正在重启…',\n restartHint: '部分插件(如插件市场、顶层 bundle)需重启后才会生效。',\n // 待重启:装完没重启的插件常驻提醒,直到宿主真正重启\n restartPendingHint: '安装成功,重启后生效',\n restartPendingHintUninstall: '卸载成功,重启后移除',\n sectionPendingRestart: '待重启',\n sectionInProgress: '进行中',\n // 串行队列:安装/卸载弹窗内可后台关闭,排队任务自动串行执行\n queuedTitle: '已加入安装排队',\n queuedUninstallTitle: '已加入卸载排队',\n queuedHint: '已加入排队,前序任务完成后将自动开始,可关闭本窗口继续浏览。',\n cancelTask: '取消任务',\n cancelling: '正在取消…',\n errorTitle: '操作失败',\n errorTitleInstall: '安装失败',\n errorTitleUninstall: '卸载失败',\n errorPlugin: '插件',\n errorClose: '知道了',\n errorCopy: '复制错误信息',\n errCopied: '错误信息已复制',\n // 任务通知中心:安装/卸载的成败自动落盘,随时可回来查看\n notifications: '通知',\n // 通知入口按钮文字:工具栏空间有限,与弹窗标题(notifications)区分,短文案不截断\n notificationsBtn: '通知',\n notificationsHint: '查看安装/卸载通知(含失败记录)',\n notificationsDesc: '安装、卸载任务的成败都会记录在这里,即使错过提示也能随时回来查看。',\n notificationsEmpty: '暂无通知记录',\n notificationsClear: '清空通知',\n removeNotification: '删除这条通知',\n failCopy: '复制完整错误信息',\n failIssueHint: '带着错误日志去作者仓库一键提交 Issue(正文含官网收录链接)',\n failIssueBig: '一键提交 BUG 到 GitHub Issue 为开源作贡献',\n // prepare 构建脚本实际执行失败(git 分发缺子模块/构建产物):插件打包分发问题,应提 Issue\n failPrepareHint: '该插件安装时的构建脚本执行失败(git 分发常缺失子模块或构建产物),属插件打包分发问题。请向作者仓库提交 Issue 反馈。',\n // 安装前预检 / 装后校验拦截([packaging]):git 分发缺构建产物、入口文件不存在 = 插件未适配官方默认安装方式\n failPackagingHint: '该插件不支持官方默认安装方式:其 git 分发缺少构建产物(package.json 声明的入口文件在仓库中不存在),说明作者未适配官方安装流程。请到作者仓库提交 Issue 反馈,请其提交构建产物或发布 npm 版。',\n // 原生依赖构建脚本被 pnpm 默认拦截(如 node-pty 的 ERR_PNPM_IGNORED_BUILDS):只影响带原生模块的插件,属插件依赖打包问题,应提 Issue\n failIgnoredBuild: '该插件依赖了需要编译的原生模块(如 node-pty),pnpm 默认拦截这类构建脚本导致安装失败 —— 其他插件不受影响,属该插件的依赖/打包问题。建议向作者仓库一键反馈,请作者改用预编译版本(如 node-pty-prebuilt-multiarch)。',\n reportIssue: '去插件仓库提交 Issue',\n detail: '打开详情',\n noResult: '没有找到匹配的插件',\n noResultDesc: '换个关键词试试,或前往网站浏览全部插件。',\n today: '今天更新',\n daysAgo: '更新于 {days} 天前',\n monthsAgo: '更新于 {months} 个月前',\n yearsAgo: '更新于 {years} 年前',\n pluginsTotal: '结果 {n} 条插件',\n // 分类按钮不带数量,选中分类后在列表头部显示筛选结果数\n filterResults: '结果 {n} 条插件',\n more: '还有 {n} 个插件,去网站查看全部',\n browseAll: '浏览全部 {n} 个插件',\n verified: '已验证',\n // 版本与更新:有 release 比版本号;无 release 的仓库比仓库最近更新时间(有新提交即提示更新)\n version: '版本',\n update: '可更新',\n updateAvailable: '有更新',\n updateAvailableHint: '检测到更新:有版本号的仓库比对版本号,无版本号的仓库比对仓库最近更新时间',\n empty: '该分类暂无插件',\n dataFrom: '数据源 dsh-plugin.org · 每日人工更新',\n}\n\nexport const en = {\n nav: 'Plugin Hub',\n title: 'DSH-Plugin Hub',\n // Plugin counts are filled from the live /api/stats.json ({total}/{verified}), never hardcoded\n tagline: 'DSH-Plugin Hub: a human-verified, free marketplace for DeepSeek Harness plugins',\n adBadge: 'Featured',\n ad: 'DSH-Plugin Hub: {total} plugins indexed, {verified} human-verified, updated daily',\n search: 'Search plugins by name, description, tags…',\n all: 'All',\n sortStars: 'Most stars',\n sortForks: 'Most forks',\n sortUpdated: 'Recently updated',\n sortNewest: 'Newest added',\n openHint: 'Open dsh-plugin.org',\n toggleLangHint: 'Switch language',\n githubHint: 'View source on GitHub',\n fork: 'Fork',\n loading: 'Loading plugin data…',\n failed: 'Failed to load plugin data',\n failedDesc: 'Please retry, or open the hub in your browser with the button above.',\n retry: 'Retry',\n install: 'Install',\n toastCopied: 'Install command copied — paste it in your dsh terminal',\n installed: 'Installed',\n notInstalled: 'Not installed',\n filterAllHint: 'Show all plugins',\n filterInstalledHint: 'Filter to installed plugins in this category',\n filterNotInstalledHint: 'Filter to uninstalled plugins in this category',\n filterInstalledNone: 'No installed plugins in this category',\n filterNotInstalledNone: 'No uninstalled plugins in this category',\n uninstall: 'Uninstall',\n uninstalling: 'Removing…',\n uninstallTitle: 'Confirm uninstall',\n uninstallDesc: 'The plugin will be removed from this environment.',\n uninstallDone: 'Uninstalled',\n uninstallFail: 'Removal failed — try again',\n uninstallResultTitle: 'Removed',\n uninstallResultDesc: 'The plugin has been removed from this environment.',\n confirmTitle: 'Confirm install',\n confirmDesc: 'Review the plugin repository source code carefully before installing.',\n confirmPlugin: 'Plugin',\n confirmSource: 'Source',\n confirmCommand: 'Command',\n copyInstallCommand: 'Copy install command',\n copyCmdLabel: 'Copy',\n copyUninstallCommand: 'Copy uninstall command',\n installNow: 'Install',\n installing: 'Installing…',\n installDone: 'Installed',\n installResultTitle: 'Plugin installed successfully',\n installResultDesc: '',\n // Update semantics: the \"update\" action re-runs add in place — copy differentiates install vs update\n confirmUpdateTitle: 'Confirm update',\n updateNow: 'Update',\n updating: 'Updating…',\n queuedUpdateTitle: 'Queued for update…',\n updateResultTitle: 'Updated',\n updateResultDesc: 'The plugin has been updated to the latest version.',\n installFail: 'Install failed — copy the command instead',\n confirmCancel: 'Cancel',\n doneBtn: 'Done',\n // Result view: some plugins need a restart to mount — offer restart now / later\n restartNow: 'Restart now',\n restartLater: 'Later',\n restarting: 'Restarting…',\n restartHint: 'Some plugins (such as plugin markets / top-level bundles) only take effect after a restart.',\n restartPendingHint: 'Installed — takes effect after restart',\n restartPendingHintUninstall: 'Removed — cleaned up after restart',\n sectionPendingRestart: 'Pending restart',\n sectionInProgress: 'In progress',\n queuedTitle: 'Queued…',\n queuedUninstallTitle: 'Queued for removal…',\n queuedHint: 'Queued — starts automatically after earlier tasks finish. You may close this window.',\n cancelTask: 'Cancel task',\n cancelling: 'Cancelling…',\n errorTitle: 'Operation failed',\n errorTitleInstall: 'Install failed',\n errorTitleUninstall: 'Removal failed',\n errorPlugin: 'Plugin',\n errorClose: 'Got it',\n errorCopy: 'Copy error',\n errCopied: 'Error copied',\n // Task notification center: install/remove results are auto-logged, viewable later\n notifications: 'Notifications',\n // Entry button label: toolbar space is tight, keep it short so it never truncates; the modal title stays full\n notificationsBtn: 'Notice',\n notificationsHint: 'View install/remove notifications (including failures)',\n notificationsDesc: 'Every install and remove result is logged here — even if you missed the prompt, you can always check back.',\n notificationsEmpty: 'No notifications yet',\n notificationsClear: 'Clear notifications',\n removeNotification: 'Remove this notification',\n failCopy: 'Copy full log',\n failIssueHint: 'Open a pre-filled issue on the author repo with this error log (includes catalog links)',\n failIssueBig: 'Report this bug to GitHub — contribute to open source',\n // prepare script actually failed (git tarball misses submodules/build output): a packaging issue of the plugin itself — file an issue\n failPrepareHint: 'This plugin failed while running its build scripts during install (git tarballs often miss submodules or build output). This is a packaging issue of the plugin itself — please report it to the author repository.',\n // Pre-install / post-install guard hit ([packaging]): git distribution lacks build output, entry file missing = not adapted to the official default install method\n failPackagingHint: 'This plugin does not support the official default install method: its git distribution lacks the build output (the entry file declared in package.json is not in the repository), so it has not been adapted to the official install flow. Please file an Issue on the author\\'s repo asking for committed build output or an npm release.',\n // native-module build scripts ignored by pnpm by default (e.g. node-pty, ERR_PNPM_IGNORED_BUILDS): only affects plugins with native deps — a dependency/packaging issue of the plugin itself, file an issue\n failIgnoredBuild: 'This plugin depends on a native module (e.g. node-pty) whose build script pnpm blocks by default, so the install fails — other plugins are unaffected. This is a dependency/packaging issue of the plugin itself. Please report it to the author repository and ask the author to switch to a prebuilt variant (e.g. node-pty-prebuilt-multiarch).',\n reportIssue: 'Report an Issue to the plugin repo',\n detail: 'Open details',\n noResult: 'No plugins match your search',\n noResultDesc: 'Try another keyword, or browse all plugins on the website.',\n today: 'updated today',\n daysAgo: 'updated {days}d ago',\n monthsAgo: 'updated {months}mo ago',\n yearsAgo: 'updated {years}y ago',\n pluginsTotal: 'Results: {n} plugins',\n // Category chips carry no counts; the filtered result count shows in the list header\n filterResults: 'Results: {n} plugins',\n more: '{n} more on the website',\n browseAll: 'Browse all {n} plugins',\n verified: 'Verified',\n // Version & updates: repos with a release are compared by tag; repos without one by last push time (new commits → update)\n version: 'Version',\n update: 'Update',\n updateAvailable: 'Update available',\n updateAvailableHint: 'An update was detected: repos with a release are compared by tag, repos without one by last push time',\n empty: 'No plugins in this category yet',\n dataFrom: 'Data from dsh-plugin.org · curated daily',\n}\n","/**\n * Persistent install/remove notifications.\n *\n * Every settled task — success or failure — is appended to localStorage the\n * moment the backend reports it, so a result is never lost even when the\n * dialog was dismissed or nobody was watching the progress strip. Newest\n * first, capped at MAX entries. Failures keep their full output for the\n * issue-filing flow; successes are lightweight (no log).\n */\nexport interface NotificationRecord {\n id: number\n kind: 'install' | 'uninstall'\n /** true = 成功(轻量记录);false = 失败(message 携带完整错误日志) */\n ok: boolean\n /** owner/repo(可能为空:请求层失败但拿不到仓库时) */\n repo: string\n /** 失败时的完整错误日志;成功记录为空串 */\n message: string\n /** 实际执行的安装/卸载命令(issue 预填时如实展示);历史记录可能缺失 */\n command?: string\n /** 尝试过的安装方式(npm registry 反查 + 实际执行命令,按先后顺序):失败提 Issue 时贴给作者,便于反推正确的 npm 包名 */\n attempts?: string[]\n /** 结束时间(epoch ms) */\n at: number\n}\n\nconst KEY = 'gro.ngilp-hsd.failure-records'\nconst MAX = 50\n\nexport type FailureKind = 'pnpmIgnoredBuild' | 'pluginPrepare' | 'repo'\n\n/**\n * 失败归类,三态。无论底层机制如何(pnpm 白名单拦截 / 构建脚本被忽略 / prepare 失败),\n * 对用户而言结果都一样 —— 当前安装通道(npm 或 git)装不上,就是插件分发/依赖的问题,\n * 一律引导提 Issue:\n * - pnpmIgnoredBuild:插件依赖里的原生模块构建脚本被 pnpm 默认拦截(如 node-pty,\n * `ERR_PNPM_IGNORED_BUILDS`)。只影响带原生模块的插件,其他插件不受影响 —— 差异在\n * 插件的依赖选择,属插件依赖/打包问题 → 引导去仓库提 Issue(建议改用预编译版本)\n * - pluginPrepare:插件的 prepare/构建脚本实际执行失败(git tarball 常因缺失子模块或\n * 构建产物导致)—— 属插件打包/分发问题,应引导去仓库提 Issue\n * - repo:其余失败(含 git prepare 被 pnpm 白名单拦截等),默认按插件仓库问题引导提 Issue\n */\nexport function classifyFailure(message: string): FailureKind {\n // 装后校验拦截(服务端 verifyInstalledEntry 标记):入口文件缺失 = git 分发缺构建产物,\n // 与 pluginPrepare 同类(插件打包/分发问题),引导去仓库提 Issue\n if (/\\[packaging\\]|entry file missing/i.test(message)) return 'pluginPrepare'\n // 原生模块构建被忽略(IGNORED_BUILDS)要在 prepare 判定之前:dsh 尾部固定提示语带\n // allowBuilds/pnpm-workspace.yaml,不能据此把插件自身问题误判成通用失败\n if (/ERR_PNPM_IGNORED_BUILDS|Ignored build scripts:/i.test(message)) return 'pnpmIgnoredBuild'\n // 再判 prepare 实际执行失败:只有构建脚本真的跑挂了才是插件问题\n if (/ERR_PNPM_PREPARE_PACKAGE|ELIFECYCLE|Command failed|prepare-guard/i.test(message)) return 'pluginPrepare'\n // 其余失败(含 git prepare 被 pnpm 白名单拦截):当前通道装不上 = 插件分发/依赖的问题,一律提 Issue\n return 'repo'\n}\n\n/** 核心行特征:错误代码 / 生命周期脚本失败 / prepare 失败 / 描述性报错(子模块缺失、找不到等)/ 退出与宿主提示信息。 */\nconst CORE_LINE_RE = /ERR_[A-Z_]+|ELIFECYCLE|Command failed|prepare-guard|Failed to prepare|exit code|\\bprepare\\b|pnpm failed in profile|git-hosted plugins build|submodule|not found|cannot find|no such|unable to|fatal|missing|error/i\n/** 提交 issue 时正文里错误摘要的上限字符数。GitHub 请求行上限 8192 字节,\n * 固定模板与 URL 编码开销约 1~2K,核心错误(以 ASCII 日志为主)可安全带到 ~5K;\n * 仍超长时 pluginIssueUrl 会逐档缩小核心预算,最终 URL 不会超限。 */\nexport const MAX_CORE_CHARS = 5000\n/** 摘要里单行上限:允许构建 key 等长行也被截短。 */\nconst MAX_LINE_CHARS = 400\n\n/**\n * 核心错误收集器:从完整安装输出里挑出真正说明问题的行(错误代码、构建脚本失败、\n * 退出与宿主提示),去重后拼接,单行与总量都截断 —— 只把「重点 + 原因」带进 issue 正文,\n * 避免完整日志塞进 URL 导致请求过长。无关键行时退化为「头部 + 尾部」快照。\n * maxChars 可由调用方按最终 URL 长度收紧(pluginIssueUrl 超限时逐档缩小)。\n */\nexport function summarizeError(message: string, maxChars: number = MAX_CORE_CHARS): string {\n const seen = new Set<string>()\n const core: string[] = []\n for (const raw of message.split(/\\r?\\n/)) {\n const line = raw.trim()\n if (!line || !CORE_LINE_RE.test(line)) continue\n const short = line.length > MAX_LINE_CHARS ? `${line.slice(0, MAX_LINE_CHARS)}…` : line\n if (!seen.has(short)) {\n seen.add(short)\n core.push(short)\n }\n }\n let out: string\n if (core.length === 0) {\n // 无关键行时退化为「头部 + 尾部」快照:优先保尾部完整,头部按预算压缩,总长不超上限\n const tail = message.trimEnd().slice(-1000)\n const sep = '\\n…\\n'\n const headBudget = Math.max(maxChars - tail.length - sep.length, 0)\n const head = message.slice(0, 500).trim()\n out = `${head.length > headBudget ? head.slice(0, headBudget) : head}${sep}${tail}`\n } else {\n out = core.join('\\n')\n }\n return out.length > maxChars ? `${out.slice(0, maxChars)}\\n… (truncated)` : out\n}\n\n/** 提取首个错误代码(如 ERR_PNPM_PREPARE_PACKAGE),无则 null。 */\nexport function coreErrorCode(message: string): string | null {\n const m = message.match(/\\[?ERR_[A-Z_]+\\]?/)\n return m ? m[0].replace(/^\\[|\\]$/g, '') : null\n}\n\n/** 运行时 localStorage 访问:类型上不依赖 DOM lib(Node 测试环境也能编译),浏览器里取 window。 */\nconst storage = (): Storage | undefined =>\n (globalThis as { localStorage?: Storage }).localStorage\n\n/** 读取本地通知记录(损坏/不可用时返回空列表,不抛错)。列表最新在前,全部保留,只由「清空」按钮手动移除。 */\nexport function loadNotifications(): NotificationRecord[] {\n try {\n const raw = storage()?.getItem(KEY)\n if (!raw) return []\n const list = JSON.parse(raw) as unknown\n if (!Array.isArray(list)) return []\n return list\n .filter((r): r is NotificationRecord =>\n !!r && typeof r === 'object' && typeof (r as { message?: unknown }).message === 'string')\n // 历史失败记录没有 ok 字段:缺省按失败渲染,保证旧数据照常可查\n .map((r) => ({ ...r, ok: r.ok === true }))\n } catch {\n return []\n }\n}\n\nfunction save(list: NotificationRecord[]): void {\n try {\n storage()?.setItem(KEY, JSON.stringify(list))\n } catch {\n /* storage full / unavailable:仅保留内存态,界面仍可查看 */\n }\n}\n\n/** 追加一条通知记录并持久化,返回更新后的完整列表(最新在前,超上限裁剪)。\n * 每次成功/失败都各自留痕:同一插件的安装/卸载记录都完整保留、只由「清空」按钮手动移除,\n * 不会因后续操作被自动覆盖清除。 */\nexport function addNotification(record: Omit<NotificationRecord, 'id' | 'at'>): NotificationRecord[] {\n const prev = loadNotifications()\n let id = Date.now()\n while (prev.some((r) => r.id === id)) id += 1\n const next = [{ ...record, id, at: id }, ...prev].slice(0, MAX)\n save(next)\n return next\n}\n\n/** 记录一次失败:携带完整错误日志,供通知中心查看/复制/提 Issue。 */\nexport function addFailure(record: Omit<NotificationRecord, 'id' | 'at' | 'ok'>): NotificationRecord[] {\n return addNotification({ ...record, ok: false })\n}\n\n/** 记录一次成功:轻量记录,不带日志。 */\nexport function addSuccess(record: Omit<NotificationRecord, 'id' | 'at' | 'ok' | 'message'>): NotificationRecord[] {\n return addNotification({ ...record, ok: true, message: '' })\n}\n\n/** 清空全部通知记录,返回空列表。 */\nexport function clearNotifications(): NotificationRecord[] {\n save([])\n return []\n}\n\n/** 按 id 删除单条通知记录,返回更新后的列表(仅移除该条,不影响其余记录)。 */\nexport function removeNotification(id: number): NotificationRecord[] {\n const next = loadNotifications().filter((r) => r.id !== id)\n save(next)\n return next\n}\n","/**\n * Catalog constants and normalizers: site URLs, category metadata, sort keys\n * and the mapping from the online API's short-key payloads to HubPlugin.\n */\nimport type { EnvInfo, HubPlugin, LocaleId } from '../types.ts'\nimport { MAX_CORE_CHARS, classifyFailure, coreErrorCode, summarizeError } from './failures.ts'\n\n/** 插件中心官网地址。 */\nexport const SITE_URL = 'https://dsh-plugin.org/'\n\n/** 插件中心源码仓库:头部右上角 GitHub 图标的跳转地址 */\nexport const GITHUB_URL = 'https://github.com/dshplugin/dsh-plugin-hub'\n\n/** 构建时由 tsdown 从 package.json 注入的插件版本号(见 tsdown.config.ts define)。 */\ndeclare const __PLUGIN_VERSION__: string\n\n/**\n * 插件当前版本号,供头部标题展示「DSH-Plugin Hub v0.1.1」。\n * tsdown 构建时用 define 把 __PLUGIN_VERSION__ 替换成 package.json 的版本号;\n * node --test 直接 import 本模块时该标识符不存在,typeof 守卫兜底为空串。\n */\nexport const PLUGIN_VERSION: string =\n typeof __PLUGIN_VERSION__ === 'string' ? __PLUGIN_VERSION__ : ''\n\n/** dsh-plugin.org 中文页挂在 /zh/ 前缀下,英文在根路径。 */\nexport function langPathOf(lang: LocaleId): string {\n return lang === 'zh' ? 'zh/' : ''\n}\n\n/**\n * 官网详情页两级路径:/plugins/{ownerSlug}/{slug};\n * 旧数据缺 ownerSlug 时从 repo 推导(卡片详情按钮与弹窗来源行共用)。\n */\nexport function pluginDetailUrl(plugin: HubPlugin, langPath: string): string {\n const repo = plugin.source?.repo ?? ''\n return `${SITE_URL}${langPath}plugins/${plugin.ownerSlug ?? repo.split('/')[0]?.toLowerCase() ?? ''}/${plugin.slug}`\n}\n\n/**\n * 失败弹窗里仓库地址的跳转目标:官网详情页(含插件收录信息),\n * 与 issue 正文的 Catalog 链接同一形式(单级 /plugins/{repo})。\n */\nexport function pluginSiteUrl(repo: string): string {\n return `${SITE_URL}plugins/${repo}`\n}\n\n/**\n * 一键反馈 GitHub Issue 的预填链接:标题带「来自 dsh-plugin.org」标识,正文只带\n * 核心信息 —— 原因判定 + 关键错误代码 + 尝试过的安装方式 + 宿主机器环境快照 +\n * 错误核心摘要(完整日志太长,塞进 URL 会被 GitHub 以「request URL too long」拒绝,\n * 故只收集重点)。错误弹窗、失败记录共用此逻辑。\n * env 取不到时为 null,链接照常生成、只是少环境段。\n * attempts(尝试过的安装方式,npm 反查 + 实际执行命令):作者看到我们查过/试过的命令,\n * 组织 scope 与 GitHub 用户名不一致时也能直接指认正确的 npm 包名。\n */\nexport function pluginIssueUrl(repo: string, message: string, env?: EnvInfo | null, command?: string, attempts?: string[]): string {\n const title = `[dsh-plugin.org | dsh-plugin-hub] Install/Remove failed: ${repo}`\n // 原因判定:让作者一眼知道这是不是自己插件的问题。\n // [packaging](预检/装后校验拦截)单独列:无论走 npm 还是 git 通道,都是分发物不完整\n // (package.json 声明的入口文件在发布物里缺失),作者照此补齐即可。\n const kind = classifyFailure(message)\n const reason = /\\[packaging\\]/i.test(message)\n ? 'plugin distribution is incomplete — the entry file declared in package.json is missing from the published package (github tarball or npm package); please commit build output or publish a complete package'\n : kind === 'pluginPrepare'\n ? 'plugin prepare/build script failed during install (packaging/distribution issue)'\n : kind === 'pnpmIgnoredBuild'\n ? 'plugin depends on a native module whose build script pnpm blocks by default (use a prebuilt variant)'\n : 'plugin-side install failure'\n const code = coreErrorCode(message)\n // 按给定核心摘要预算构建完整预填 URL(含 URL 编码);预算可调,供超长时逐档缩小\n const build = (coreChars: number): string => {\n const body = [\n '## Summary',\n `- Cause: ${reason}`,\n ...(code ? [`- Key error: \\`${code}\\``] : []),\n '',\n // 来源说明:标题(链官网)+ 一句来源(链仓库)+ 实际执行的安装命令(含 --profile)与执行结果,链接由常量动态拼接\n `## [DSH-Plugin 插件中心](${SITE_URL}) · 安装 Plugin 失败错误信息`,\n `本错误信息由 [dsh-plugin-hub](${GITHUB_URL}) 插件中心的安装程序自动生成,随本次安装失败一并提交。`,\n `- 实际执行的安装命令:\\`${command ?? `dsh plugin${env?.profile ? ` --profile ${env.profile}` : ''} add github:${repo}`}\\``,\n `- 执行结果:安装失败,未能安装该插件。`,\n // 尝试过的安装方式(npm 反查 + 实际执行命令,按先后顺序):作者据此反推正确的\n // npm 包名 —— 组织 scope 与 GitHub 用户名不一致时仅凭仓库名猜不到,作者看到我们\n // 查过/试过的命令就能直接指认\n ...(attempts && attempts.length > 0\n ? ['', '## Attempted install channels(已尝试的安装方式)', ...attempts.map((a) => `- ${a}`)]\n : []),\n // [packaging] 场景:说明两种官方安装通道(npm 包 / git 直装),当前插件在对应通道下分发不完整\n ...(/\\[packaging\\]/i.test(message)\n ? [\n '',\n '## 安装方式说明',\n 'DSH 插件支持两种官方安装通道:`dsh plugin add <npm-package>`(npm 分发,需发布完整构建产物)与 `dsh plugin add github:owner/repo`(git 直装,仓库需提交构建产物或在 package.json 提供 `prepare` 脚本)。当前插件的分发物缺少 package.json 声明的入口文件,请按所用通道补齐后重新发布。',\n ]\n : []),\n '',\n '## Environment',\n `- Plugin: \\`${repo}\\``,\n // 宿主机器环境快照:便于作者本地复现;某字段缺失时如实写 unknown,不编造\n ...(env\n ? [\n `- DSH: ${env.dshVersion ? `v${env.dshVersion}` : 'unknown'}`,\n `- Plugin Hub: v${PLUGIN_VERSION}`,\n `- Node: ${env.nodeVersion}`,\n `- OS: ${env.platform} ${env.arch} (${env.release})`,\n `- Profile: \\`${env.profile}\\``,\n `- DSH Home: \\`${env.dshHome}\\``,\n ]\n : []),\n // 该插件在插件中心的收录位置(详情页链接)\n `- Catalog: [${pluginSiteUrl(repo)}](${pluginSiteUrl(repo)})`,\n '',\n '## Error (core)',\n '',\n '```',\n // 核心错误收集器:只挑关键行(错误代码/构建失败/退出信息),去重截断,URL 才不至于超长\n summarizeError(message, coreChars),\n '```',\n '',\n '---',\n // 底部署名:报错来自内置在 DeepSeek Harness 里的 dsh-plugin-hub 安装程序\n `This error was produced by the [dsh-plugin-hub](${GITHUB_URL}) installer bundled with DeepSeek Harness.`,\n ].join('\\n')\n return `https://github.com/${repo}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`\n }\n // GitHub 请求行上限 8192 字节:先用宽松预算(最多 ~5K 核心错误)构建,超长再逐档缩小,保证最终 URL 不超限\n const MAX_URL_CHARS = 7600\n let url = build(MAX_CORE_CHARS)\n if (url.length > MAX_URL_CHARS) {\n for (const budget of [4000, 2500, 1400, 800, 400]) {\n url = build(budget)\n if (url.length <= MAX_URL_CHARS) break\n }\n }\n return url\n}\n\nexport const CATEGORY_ORDER = [\n 'interface', 'session', 'memory', 'tools', 'agent', 'workflow',\n 'integration', 'model', 'dev', 'knowledge', 'fun',\n]\n\n/** 分类标签按界面语言取词;未知 key 原样返回。 */\nexport function categoryLabel(\n map: Record<string, { zh: string; en: string }>,\n key: string,\n lang: LocaleId,\n): string {\n return map[key]?.[lang] ?? key\n}\n\n/**\n * 归一化在线 API(dsh-plugin.org/api/plugins.{lang}.json)返回的短 key 结构\n * (s/o/n/vr/c/t/f/d/r/v/u/a/sg/fk),统一为 HubPlugin,保证渲染逻辑只认一种结构。\n */\nexport function normalize(raw: Record<string, unknown>): HubPlugin {\n if (typeof raw.s === 'string') {\n return {\n slug: raw.s,\n ownerSlug: typeof raw.o === 'string' ? raw.o : undefined,\n displayName: typeof raw.n === 'string' ? raw.n : undefined,\n version: typeof raw.vr === 'string' ? raw.vr : undefined,\n category: typeof raw.c === 'string' ? raw.c : undefined,\n topics: Array.isArray(raw.t) ? (raw.t as string[]) : undefined,\n features: Array.isArray(raw.f) ? (raw.f as string[]) : undefined,\n description: typeof raw.d === 'string' ? raw.d : undefined,\n // 投影输出两种形态:老数据 source 是 repo 字符串;新数据是 { repo, npmPackage }\n source: typeof raw.r === 'string'\n ? { repo: raw.r }\n : raw.r !== null && typeof raw.r === 'object'\n ? {\n repo: typeof (raw.r as { repo?: unknown }).repo === 'string' ? (raw.r as { repo: string }).repo : undefined,\n npmPackage: typeof (raw.r as { npmPackage?: unknown }).npmPackage === 'string' ? (raw.r as { npmPackage: string }).npmPackage : undefined,\n }\n : undefined,\n compatibility: typeof raw.v === 'string' ? { status: raw.v } : undefined,\n dates: {\n repoUpdatedAt: typeof raw.u === 'string' ? raw.u : undefined,\n addedAt: typeof raw.a === 'string' ? raw.a : undefined,\n },\n stats: {\n stargazers_count: typeof raw.sg === 'number' ? raw.sg : undefined,\n forks_count: typeof raw.fk === 'number' ? raw.fk : undefined,\n },\n }\n }\n return raw as unknown as HubPlugin\n}\n\n/**\n * 安装通道决策(用户无感知):目录探测到 npm 包名 → 用 npm 包名安装\n * (走 npm registry tarball,更快、与 GitHub 网络无关);无 npm 包名 → git 直装。\n * 返回值 target 即传给后端 /install 的安装目标(npm 包名 或 owner/repo)。\n */\nexport function installTargetOf(p: HubPlugin): { target: string; via: 'npm' | 'github' } {\n const pkg = (p.source?.npmPackage ?? '').trim()\n const repo = (p.source?.repo ?? '').trim()\n if (pkg && repo) return { target: pkg, via: 'npm' }\n return { target: repo, via: 'github' }\n}\n\n/** 展示用安装命令(复制/弹窗):npm 通道显示包名,git 通道显示 github: 源。 */\nexport function installCommandOf(p: HubPlugin, withProfile = false): string {\n const { target, via } = installTargetOf(p)\n return via === 'npm'\n ? `dsh plugin${withProfile ? ' --profile web' : ''} add ${target}`\n : `dsh plugin${withProfile ? ' --profile web' : ''} add github:${target}`\n}\n\nexport const CATEGORY_LABELS: Record<string, { zh: string; en: string }> = {\n interface: { zh: '界面与体验', en: 'UI & Experience' },\n session: { zh: '会话与消息', en: 'Sessions & Messages' },\n memory: { zh: '记忆与上下文', en: 'Memory & Context' },\n tools: { zh: '工具与能力', en: 'Tools & Capabilities' },\n agent: { zh: '技能与智能体', en: 'Skills & Agents' },\n workflow: { zh: '工作流与自动化', en: 'Workflow & Automation' },\n integration: { zh: '集成与连接', en: 'Integrations & Connections' },\n model: { zh: '模型与推理', en: 'Models & Reasoning' },\n dev: { zh: '开发与运维', en: 'Development & Operations' },\n knowledge: { zh: '数据与知识', en: 'Data & Knowledge' },\n fun: { zh: '娱乐', en: 'Entertainment' },\n}\n\n/** 分类 Tab 的紧凑标签(英文模式空间受限时使用)。 */\nexport const CATEGORY_SHORT_LABELS: Record<string, { zh: string; en: string }> = {\n interface: { zh: '界面体验', en: 'UI Exp' },\n session: { zh: '会话消息', en: 'Sessions' },\n memory: { zh: '记忆上下文', en: 'Memory' },\n tools: { zh: '工具能力', en: 'Tools' },\n agent: { zh: '技能智能体', en: 'Agents' },\n workflow: { zh: '工作流', en: 'Workflow' },\n integration: { zh: '集成连接', en: 'Integrations' },\n model: { zh: '模型推理', en: 'Models' },\n dev: { zh: '开发运维', en: 'Dev' },\n knowledge: { zh: '数据知识', en: 'Knowledge' },\n fun: { zh: '娱乐', en: 'Fun' },\n}\n\nexport const SORTS = ['sortStars', 'sortForks', 'sortUpdated', 'sortNewest'] as const\nexport type SortKey = (typeof SORTS)[number]\n","/**\n * One-shot host environment snapshot for bug reports. Fetched lazily and\n * cached at module level: issue URLs embed this info, and the environment\n * does not change during a session. A failed fetch degrades to null so the\n * issue links still work — they just ship without the environment block.\n */\nimport type { EnvInfo } from '../types.ts'\n\nlet envPromise: Promise<EnvInfo | null> | null = null\n\nexport function getEnv(): Promise<EnvInfo | null> {\n envPromise ??= fetch('/dsh-plugin-hub/env', { cache: 'no-store' })\n .then((res) => (res.ok ? (res.json() as Promise<EnvInfo>) : null))\n .catch(() => null)\n return envPromise\n}\n","/**\n * Catalog data + view state for the Plugin Hub section.\n *\n * Owns the online-data pipeline (live fetch from dsh-plugin.org), the local\n * installed-plugin table, and the filter/search/sort/install-status view\n * state, exposing the derived visible list and per-category counts.\n */\nimport { useEffect, useMemo, useState } from 'react'\nimport type { HubPlugin, LocaleId } from '../types.ts'\nimport { normalize } from '../lib/catalog.ts'\nimport type { SortKey } from '../lib/catalog.ts'\n\nconst PLUGINS_URL = (lang: LocaleId) => `https://dsh-plugin.org/api/plugins.${lang}.json`\nconst STATS_URL = 'https://dsh-plugin.org/api/stats.json'\n\nexport function useCatalog(lang: LocaleId) {\n /** 目录插件(仅保留人工验证通过的条目) */\n const [plugins, setPlugins] = useState<HubPlugin[] | null>(null)\n /** 收录/精选统计(官网 /api/stats.json 实时拉取) */\n const [stats, setStats] = useState<{ total: number; verified: number } | null>(null)\n const [failed, setFailed] = useState(false)\n const [reloadKey, setReloadKey] = useState(0)\n const [category, setCategory] = useState('all')\n const [query, setQuery] = useState('')\n const [sort, setSort] = useState<SortKey>('sortStars')\n /** 列表安装状态筛选:全部 / 已安装 / 未安装(分段按钮,单列表内切换,不引入第二个列表) */\n const [installedFilter, setInstalledFilter] = useState<'all' | 'installed' | 'notInstalled'>('all')\n /** 当前 profile 已安装插件:npm 包名 -> manifest spec(来自宿主本地路由) */\n const [installed, setInstalled] = useState<Record<string, string>>({})\n /** 安装时记录的目录信号:repo(小写) -> { version, updatedAt }(来自宿主本地路由);\n * npmPackage 为 npm 优先通道反查命中的包名映射(目录数据未下发时客户端靠它把依赖 key 匹配回仓库) */\n const [versions, setVersions] = useState<Record<string, { version: string; updatedAt: string; npmPackage?: string }>>({})\n\n // 拉取目录 + 统计。在线 API 已只返回 verified;再过滤一次,保证只展示人工验证通过的插件。\n useEffect(() => {\n let cancelled = false\n setPlugins(null)\n setStats(null)\n setFailed(false)\n const fetchData = (url: string): Promise<unknown> =>\n fetch(url, { cache: 'no-store' }).then((res) => {\n if (!res.ok) throw new Error(String(res.status))\n return res.json()\n })\n fetchData(PLUGINS_URL(lang)).then((data) => {\n if (cancelled) return\n const list = (Array.isArray(data) ? data : []).map((item) => normalize(item as Record<string, unknown>))\n setPlugins(list.filter((p) => p.compatibility?.status === 'verified'))\n }).catch(() => {\n if (!cancelled) setFailed(true)\n })\n fetchData(STATS_URL).then((s) => {\n const stats = s as { total?: number; verified?: number }\n if (!cancelled && stats && typeof stats.total === 'number' && typeof stats.verified === 'number') {\n setStats({ total: stats.total, verified: stats.verified })\n }\n }).catch(() => {})\n return () => { cancelled = true }\n // lang 必须进依赖:切换界面语言要重新拉对应语言的数据文件,\n // 否则英文模式仍停留在 plugins.zh.json,描述/名称全是中文\n }, [reloadKey, lang])\n\n /** 刷新当前 profile 已安装插件表;宿主未挂本地路由时静默降级为空表。 */\n const refreshInstalled = async () => {\n try {\n const res = await fetch('/dsh-plugin-hub/installed', { cache: 'no-store' })\n if (!res.ok) return\n const data = await res.json() as { installed?: Record<string, string>; versions?: Record<string, { version: string; updatedAt: string; npmPackage?: string }> }\n setInstalled(data.installed ?? {})\n setVersions(data.versions ?? {})\n } catch {\n // host without the plugin's server routes — keep the empty table\n }\n }\n\n // 首次进入拉取已安装表(依赖宿主 webServer 服务)\n useEffect(() => { refreshInstalled() }, [])\n\n /** 插件是否已安装:匹配 installed spec 中的 `github:<owner>/<repo>`,或 npm 通道安装的依赖包名;命中返回 npm 包名。 */\n const installedName = (p: HubPlugin): string | null => {\n const repo = p.source?.repo\n if (!repo) return null\n const needle = `github:${repo.toLowerCase()}`\n for (const [name, spec] of Object.entries(installed)) {\n if (spec.toLowerCase().includes(needle)) return name\n }\n // npm 通道安装:profile 依赖 key 直接是 npm 包名。包名来源两处——目录数据(npmPackage),\n // 或服务端 npm 优先反查持久化的映射(versions[repo].npmPackage,覆盖组织 scope 与 GitHub\n // 用户名不一致、目录未下发包名的场景);命中任一并依赖 key 真实存在即视为已安装\n const pkg = ((p.source?.npmPackage || versions[repo.toLowerCase()]?.npmPackage) ?? '').toLowerCase()\n if (pkg) {\n for (const name of Object.keys(installed)) {\n if (name.toLowerCase() === pkg) return name\n }\n }\n return null\n }\n\n /** 该插件安装时记录的目录版本(无记录/未安装 → null)。 */\n const installedVersion = (p: HubPlugin): string | null => {\n const repo = p.source?.repo\n if (!repo) return null\n return versions[repo.toLowerCase()]?.version ?? null\n }\n\n /**\n * 是否有更新:仅对已安装插件有意义。\n * 双信号判定——有 release 版本的比版本;无版本(repo 不打 tag)的比仓库最近更新时间\n * (repoUpdatedAt,ISO 字符串字典序 = 时间序),更新时间变新说明有新提交。\n */\n const hasUpdate = (p: HubPlugin): boolean => {\n if (installedName(p) === null) return false\n const repo = p.source?.repo\n if (!repo) return false\n const rec = versions[repo.toLowerCase()]\n if (!rec) return false\n if (p.version) return p.version !== rec.version\n const current = p.dates?.repoUpdatedAt\n return Boolean(current && rec.updatedAt && current > rec.updatedAt)\n }\n\n /** 当前分类下的插件(「全部」时为整个目录)。 */\n const categoryPlugins = useMemo(() => {\n if (!plugins) return []\n if (category === 'all') return plugins\n return plugins.filter((p) => p.category === category)\n }, [plugins, category])\n\n /** 当前分类下已安装插件数:已安装/未安装按钮上的计数跟随分类,不再用全局口径。 */\n const installedCountInCategory = useMemo(() => {\n return categoryPlugins.reduce((n, p) => n + (installedName(p) !== null ? 1 : 0), 0)\n }, [categoryPlugins, installed])\n\n /** 当前分类下未安装插件数。 */\n const notInstalledCountInCategory = Math.max(0, categoryPlugins.length - installedCountInCategory)\n\n // 自动重置:切换分类(或已安装表变化)后,若当前安装状态筛选在新分类下无结果,\n // 自动退回「全部」,避免列表空置死胡同、也避免 0 计数按钮被误触。\n useEffect(() => {\n if (installedFilter === 'all') return\n const count = installedFilter === 'installed'\n ? installedCountInCategory\n : notInstalledCountInCategory\n if (count === 0) setInstalledFilter('all')\n }, [installedFilter, installedCountInCategory, notInstalledCountInCategory])\n\n const visible = useMemo(() => {\n if (!plugins) return []\n const q = query.trim().toLowerCase()\n const list = plugins.filter((p) => {\n if (category !== 'all' && p.category !== category) return false\n if (installedFilter === 'installed' && installedName(p) === null) return false\n if (installedFilter === 'notInstalled' && installedName(p) !== null) return false\n if (!q) return true\n return (\n (p.displayName ?? '').toLowerCase().includes(q) ||\n (p.description ?? '').toLowerCase().includes(q) ||\n (p.topics ?? []).some((topic) => topic.toLowerCase().includes(q))\n )\n })\n return [...list].sort((a, b) => {\n if (sort === 'sortStars') return (b.stats?.stargazers_count ?? 0) - (a.stats?.stargazers_count ?? 0)\n if (sort === 'sortForks') return (b.stats?.forks_count ?? 0) - (a.stats?.forks_count ?? 0)\n if (sort === 'sortNewest') return (b.dates?.addedAt ?? '').localeCompare(a.dates?.addedAt ?? '')\n return (b.dates?.repoUpdatedAt ?? '').localeCompare(a.dates?.repoUpdatedAt ?? '')\n })\n }, [plugins, category, query, sort, installed, installedFilter])\n\n /** Per-category plugin counts shown on the category chips. */\n const categoryCounts = useMemo(() => {\n const counts: Record<string, number> = {}\n for (const p of plugins ?? []) {\n if (p.category) counts[p.category] = (counts[p.category] ?? 0) + 1\n }\n return counts\n }, [plugins])\n\n return {\n plugins,\n stats,\n failed,\n reload: () => setReloadKey((k) => k + 1),\n installed,\n installedName,\n installedVersion,\n hasUpdate,\n refreshInstalled,\n category,\n setCategory,\n query,\n setQuery,\n sort,\n setSort,\n installedFilter,\n setInstalledFilter,\n visible,\n total: plugins?.length ?? 0,\n installedCountInCategory,\n notInstalledCountInCategory,\n categoryCounts,\n }\n}\n","/**\n * Background install/remove task queue for the Plugin Hub.\n *\n * Mirrors the server-side FIFO active queue by polling /active, settles\n * vanished tasks against /status, and exposes the queue actions (install,\n * uninstall, cancel) plus the modal task lookups used by the dialogs.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { HubPlugin, Translate } from '../types.ts'\nimport { installCommandOf, installTargetOf } from '../lib/catalog.ts'\n\n/** 客户端任务队列项:镜像服务端 active 任务(running 在前、pending 在后)。 */\nexport interface QueueTask {\n id: number\n kind: 'install' | 'uninstall'\n /** 展示目标:owner/repo(安装)或 npm 包名(卸载) */\n target: string\n /** 插件中文简介(入队时从插件数据带过来,轮询合并时保留):展示在仓库名下方,让人知道排队的到底是什么 */\n desc?: string\n /** 所属插件仓库(owner/repo):失败时错误弹窗据此提供「去仓库反馈」入口;卸载为 null */\n repo: string | null\n /** 安装时的目录信号快照(版本 + 仓库更新时间):任务成功后在本地记录,供「有更新」比对 */\n version?: string\n updatedAt?: string\n /** pending 排队中 / running 执行中 / cancelling 取消中(客户端乐观过渡态) */\n status: 'pending' | 'running' | 'cancelling'\n progress: number\n lines: string[]\n /** 乐观入队条目:点击安装后立即显示「正在安装中」,等 POST 响应回来再换成真实任务 id。\n * 服务端还没登记(preflight 中),轮询合并/消失检测都必须跳过,避免被当作已结束任务收尾。 */\n optimistic?: boolean\n /** 实际执行的安装命令(npm/git 通道随插件数据决定):失败时 issue 预填如实展示 */\n command?: string\n /** 尝试过的安装方式(npm registry 反查 + 实际执行命令,按先后顺序):失败时 issue 预填一并贴给作者 */\n attempts?: string[]\n}\n\n/** 客户端待重启项:镜像服务端内存列表 + 本地补齐的展示信息(简介/版本)。 */\nexport interface PendingRestart {\n /** owner/repo(展示用,已去 github: 前缀) */\n target: string\n /** 待重启语义:install 装完等挂载 / uninstall 卸完等清理 */\n kind: 'install' | 'uninstall'\n at: number\n desc?: string\n version?: string\n}\n\nexport interface TaskQueueOptions {\n t: Translate\n refreshInstalled: () => void\n /** 任务成功完成:viaModal 表示任务对应当前打开弹窗(弹窗切结果视图),否则走 Toast;repo 供成功通知记录。 */\n onInstallDone: (viaModal: boolean, repo: string | null) => void\n onUninstallDone: (viaModal: boolean, repo: string | null) => void\n /** 任务失败:完整输出或兜底文案 + 所属插件仓库 + 操作类型(安装/卸载)+ 实际执行的安装命令(issue 预填用,可缺省)+ 尝试过的安装方式(npm 反查/执行命令,可缺省)。 */\n onError: (message: string, repo: string | null, kind: 'install' | 'uninstall', command?: string, attempts?: string[]) => void\n /** 当前打开的安装/卸载弹窗插件:用于在弹窗内匹配进行中的任务。 */\n installPlugin: HubPlugin | null\n uninstallPlugin: HubPlugin | null\n installedName: (p: HubPlugin) => string | null\n /** 待重启项展示信息补齐:按 owner/repo 从插件目录解析简介/版本;找不到返回 null。 */\n resolvePending: (repo: string) => { desc?: string; version?: string } | null\n}\n\nexport function useTaskQueue(opts: TaskQueueOptions) {\n const {\n t, refreshInstalled, onInstallDone, onUninstallDone, onError,\n installPlugin, uninstallPlugin, installedName, resolvePending,\n } = opts\n const [queue, setQueue] = useState<QueueTask[]>([])\n const queueRef = useRef<QueueTask[]>([])\n /** 待重启列表(服务端内存态 + 本地展示信息补齐);与 queue 一样以 ref 为唯一事实来源。 */\n const [pendingRestarts, setPendingRestarts] = useState<PendingRestart[]>([])\n const pendingRef = useRef<PendingRestart[]>([])\n /** 本次会话内安装成功插件的展示信息(目标 → 简介/版本):轮询合并待重启列表时补齐,刷新后由 resolvePending 兜底。 */\n const pendingInfoRef = useRef<Map<string, { desc?: string; version?: string }>>(new Map())\n /** 保持最新的 resolvePending:轮询闭包捕获的是调用那一刻的目录状态,目录晚加载时也能补齐。 */\n const resolvePendingRef = useRef(resolvePending)\n resolvePendingRef.current = resolvePending\n /** 当前打开弹窗所对应的任务 id:该任务完成时弹窗切换为结果视图 */\n const modalTaskRef = useRef<number | null>(null)\n /** 已开始收尾但尚未结束的任务 id(服务端 /active 已消失 → 查 /status 中):并发轮询时跳过,避免重复收尾 */\n const settlingRef = useRef<Set<number>>(new Set())\n /** 轮询定时器句柄(队列清空/组件卸载时清理) */\n const pollRef = useRef<number | null>(null)\n /** 请求在途的目标集合(同步防重):双击安装/卸载时第二击直接忽略。\n * 本地队列任务要等 fetch 返回后才入队,仅靠 queueRef 检查拦不住请求窗口内的重复点击。 */\n const submittingRef = useRef<Set<string>>(new Set())\n /** 乐观入队临时 id 计数器:递减产生唯一负数,与服务端自增正数 id 永不冲突。 */\n const tempIdRef = useRef(0)\n /** 请求在途标记:弹窗据此禁用确认按钮,避免等待响应期间被再次点击。 */\n const [submitting, setSubmitting] = useState(false)\n\n /** 停止后台任务轮询(任务结束或组件卸载时清理)。 */\n const stopPoll = () => {\n if (pollRef.current !== null) {\n window.clearInterval(pollRef.current)\n pollRef.current = null\n }\n }\n\n /** 队列与待重启都清空才停轮询:待重启期间持续轮询,宿主一重启(内存列表清空)立刻感知并消失。 */\n const maybeStopPoll = () => {\n if (queueRef.current.length === 0 && pendingRef.current.length === 0) stopPoll()\n }\n\n // 组件卸载时兜底清理轮询定时器\n useEffect(() => stopPoll, [])\n\n /** 更新队列(同步镜像到 ref:queueRef 是唯一事实来源,state 只负责触发渲染,\n * 避免依赖 React updater 的异步调度时序导致 gone/stopPoll/防重复入队读到旧值)。 */\n const applyQueue = (updater: (prev: QueueTask[]) => QueueTask[]) => {\n const next = updater(queueRef.current)\n queueRef.current = next\n setQueue(next)\n }\n\n /** 解析服务端待重启列表(`github:` 前缀已去掉,与安装任务的 target 对齐)。 */\n const parsePendingRestarts = (value: unknown): PendingRestart[] => {\n if (!Array.isArray(value)) return []\n const out: PendingRestart[] = []\n for (const x of value) {\n if (typeof x !== 'object' || x === null) continue\n const target = (x as { target?: unknown }).target\n if (typeof target !== 'string' || target === '') continue\n const at = (x as { at?: unknown }).at\n out.push({\n target: target.replace(/^github:/, ''),\n kind: (x as { kind?: unknown }).kind === 'uninstall' ? 'uninstall' : 'install',\n at: typeof at === 'number' ? at : 0,\n })\n }\n return out\n }\n\n /** 合并服务端待重启列表:保留已有展示信息,缺失时用会话内记录 / 目录解析补齐。 */\n const applyPending = (raw: PendingRestart[]) => {\n const prev = pendingRef.current\n const next = raw.map((p) => {\n const old = prev.find((q) => q.target === p.target)\n if (old?.desc !== undefined) return { ...p, desc: old.desc, version: old.version }\n const info = pendingInfoRef.current.get(p.target) ?? resolvePendingRef.current?.(p.target) ?? null\n return info ? { ...p, desc: info.desc, version: info.version } : p\n })\n pendingRef.current = next\n setPendingRestarts(next)\n }\n\n /** 向宿主记录某插件的安装时目录信号(version + updatedAt);version 为空时清除记录(卸载)。 */\n const syncInstalledVersion = async (repo: string | null, version: string | undefined, updatedAt: string | undefined) => {\n if (!repo) return\n try {\n await fetch('/dsh-plugin-hub/installed-version', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ repo, version: version ?? null, updatedAt }),\n })\n } catch {\n // 宿主未挂本地路由:静默忽略,仅本机展示受影响\n }\n }\n\n /** 后台任务结束(active 中消失后查终态确认):完成 → 刷新安装表 + 结果视图/toast;失败 → 完整错误弹窗 */\n const finishQueueTask = (ok: boolean, q: QueueTask, lines: string[]) => {\n applyQueue((prev) => prev.filter((x) => x.id !== q.id))\n if (ok) {\n refreshInstalled()\n if (q.kind === 'uninstall') {\n // 卸载成功:清掉本地版本记录\n void syncInstalledVersion(q.repo, undefined, undefined)\n onUninstallDone(modalTaskRef.current === q.id, q.repo)\n } else {\n // 安装成功:记录安装时的目录信号(版本 + 仓库更新时间),供「有更新」比对;\n // 同时缓存展示信息,待重启列表(服务端已登记)合并时直接补齐简介/版本\n void syncInstalledVersion(q.repo, q.version, q.updatedAt)\n pendingInfoRef.current.set(q.target, { desc: q.desc, version: q.version })\n onInstallDone(modalTaskRef.current === q.id, q.repo)\n }\n } else {\n // 失败:完整展示全部输出行(最新在前,逆序为日志阅读顺序),不裁剪\n const detail = lines.length > 0\n ? [...lines].reverse().join('\\n')\n : q.kind === 'uninstall' ? t('uninstallFail') : t('installFail')\n onError(detail, q.repo, q.kind, q.command, q.attempts)\n }\n maybeStopPoll()\n }\n\n /** 卸载成功收尾前的进度过渡:任务已在服务端结束,但保留本地展示,\n * 让进度条在 ~2.4s 内缓缓跑到 100% 再切结果/Toast,给用户一个交互过程,\n * 而不是命令一执行进度条就一闪消失。 */\n const settleDone = (q: QueueTask, lines: string[]) => {\n // 收尾动画期间停止轮询:任务已从服务端 /active 消失,无需再查;\n // 停掉可避免 pollQueue 的 gone 检测把它当「再消失一次」而重复收尾\n stopPoll()\n const from = Math.min(q.progress, 90) // 起点最多 90,给进度条留出跑满的缓冲空间\n const steps = 20\n const stepMs = 120 // 20 步 × 120ms = 2.4s\n let step = 0\n // 动画期间固定显示「卸载中」:任务实已结束,但进度在跑,与「排队中」文案更协调\n applyQueue((prev) => prev.map((x) => (x.id === q.id ? { ...x, status: 'running' as const } : x)))\n const timer = window.setInterval(() => {\n step += 1\n const progress = Math.round(from + (100 - from) * (step / steps))\n applyQueue((prev) => prev.map((x) => (x.id === q.id ? { ...x, progress } : x)))\n if (step >= steps) {\n window.clearInterval(timer)\n finishQueueTask(true, q, lines)\n // 队列若还有其它已在排队/执行的任务,恢复轮询继续盯;已清空则自然停住\n if (queueRef.current.length > 0) pollQueue()\n }\n }, stepMs)\n }\n\n /** 任务在 /active 中消失 = 已结束:查 /status 拿终态并收尾(cancelled 静默移除)。 */\n const settleTask = async (q: QueueTask) => {\n let status = 'failed'\n let lines: string[] = []\n let attempts: string[] | undefined\n try {\n const res = await fetch(`/dsh-plugin-hub/status?task=${q.id}`, { cache: 'no-store' })\n if (res.ok) {\n const data = await res.json() as { task?: { status?: string; lines?: string[]; attempts?: string[] } }\n status = data.task?.status ?? 'failed'\n lines = data.task?.lines ?? []\n attempts = Array.isArray(data.task?.attempts) ? data.task.attempts : undefined\n }\n } catch { /* 服务端不可达:按失败处理 */ }\n if (status === 'done') {\n // 卸载成功走进度过渡动画;安装成功直接收尾\n if (q.kind === 'uninstall') settleDone(q, lines)\n else finishQueueTask(true, q, lines)\n }\n else if (status === 'failed') {\n // 服务端终态带出的尝试记录覆盖本地:以实际执行为准\n finishQueueTask(false, { ...q, attempts }, lines)\n }\n else {\n applyQueue((prev) => prev.filter((x) => x.id !== q.id)) // cancelled / 未知\n maybeStopPoll()\n }\n }\n\n /** 轮询整个队列:合并服务端 /active(running 在前、pending 在后),\n * 消失的任务查终态收尾;队列清空即停止轮询。 */\n const pollQueue = () => {\n stopPoll()\n pollRef.current = window.setInterval(async () => {\n try {\n const res = await fetch('/dsh-plugin-hub/active', { cache: 'no-store' })\n if (!res.ok) throw new Error(`active ${res.status}`)\n const data = await res.json() as {\n tasks?: { id?: unknown; action?: unknown; target?: unknown; status?: unknown; progress?: unknown; lines?: unknown; attempts?: unknown }[]\n pendingRestarts?: unknown\n }\n const active = (data.tasks ?? []).filter((a) => typeof a.id === 'number')\n const byId = new Map(active.map((a) => [a.id as number, a]))\n // 先捕获旧队列:gone 是「旧队列里服务端已消失的任务」的差集,必须在 applyQueue 更新前取\n const prevQueue = queueRef.current\n // 待重启列表同步(服务端内存态:宿主重启后自然变空,这里随之清空 UI)\n applyPending(parsePendingRestarts(data.pendingRestarts))\n // 合并:running 在前、pending 在后(与服务端一致),新出现任务补入队列\n applyQueue((prev) => {\n const next: QueueTask[] = []\n for (const a of active) {\n const id = a.id as number\n const prevTask = prev.find((q) => q.id === id)\n const isRemove = a.action === 'remove'\n next.push({\n id,\n kind: isRemove ? 'uninstall' : 'install',\n target: typeof a.target === 'string' ? a.target.replace(/^github:/, '') : (prevTask?.target ?? ''),\n desc: prevTask?.desc,\n repo: prevTask?.repo ?? (isRemove ? null : (typeof a.target === 'string' ? a.target.replace(/^github:/, '') : null)),\n // 安装时快照的目录信号:轮询合并时保留,任务成功后记录到本地\n version: prevTask?.version,\n updatedAt: prevTask?.updatedAt,\n status: a.status === 'running' ? 'running' : 'pending',\n progress: typeof a.progress === 'number' ? a.progress : prevTask?.progress ?? 0,\n lines: Array.isArray(a.lines) ? (a.lines as string[]) : (prevTask?.lines ?? []),\n attempts: Array.isArray(a.attempts) ? (a.attempts as string[]) : (prevTask?.attempts ?? []),\n })\n }\n // 保留乐观条目:服务端尚未登记(preflight 中),无真实 id,不能因 active 缺它就被合并吞掉\n const keepOpt = prev.filter((q) => q.optimistic && !next.some((x) => x.id === q.id))\n if (keepOpt.length > 0) next.push(...keepOpt)\n // 保留「已从服务端消失、但尚未收尾」的任务:收尾(settleTask)负责移除。\n // 若在这里提前摘除,卸载/安装完成的那一瞬队列会先变空,弹窗闪回「确认」态\n // (busy=false 且未 done),表现为「卸载中 → 卸载 → 卸载完成」的中间回退。\n const keepGone = prev.filter((q) =>\n !byId.has(q.id) && !next.some((x) => x.id === q.id) && q.status !== 'cancelling' && !q.optimistic)\n if (keepGone.length > 0) next.push(...keepGone)\n return next\n })\n // 本地有、服务端已消失 → 已结束:逐个查终态收尾\n // (cancelling 是客户端乐观过渡态,交给 cancelTask 的定时移除,不在轮询里提前收敛;\n // optimistic 是点击后尚未登记的占位,服务端 /status 查不到,跳过免误判成失败;\n // settling 是上一轮已开始收尾的任务,并发轮询直接跳过,避免重复收尾)\n const gone = prevQueue.filter((q) =>\n !byId.has(q.id) && q.status !== 'cancelling' && !q.optimistic && !settlingRef.current.has(q.id))\n for (const q of gone) {\n // 防御:同 id 任务可能已被上一轮收尾移除(极端时序下轮询合并出的重复条目),跳过避免重复收尾\n if (!queueRef.current.some((x) => x.id === q.id)) continue\n settlingRef.current.add(q.id)\n try { await settleTask(q) } finally { settlingRef.current.delete(q.id) }\n }\n } catch {\n // 服务端暂不可达:静默等待下一轮\n }\n }, 600)\n }\n\n // 刷新后恢复任务队列与待重启列表:任务注册表在服务端内存里,只要宿主进程没重启就还在;\n // 重新拉取 /active(数组)继续轮询,界面上显示「进行中」状态条,可展开查看实时输出。\n useEffect(() => {\n let cancelled = false\n const restore = async () => {\n try {\n const res = await fetch('/dsh-plugin-hub/active', { cache: 'no-store' })\n if (!res.ok) return\n const data = await res.json() as {\n tasks?: { id?: unknown; action?: unknown; target?: unknown; status?: unknown; progress?: unknown; lines?: unknown; attempts?: unknown }[]\n pendingRestarts?: unknown\n }\n if (cancelled) return\n // 待重启:装完没重启的持久提醒,刷新页面也要恢复\n applyPending(parsePendingRestarts(data.pendingRestarts))\n const items: QueueTask[] = (data.tasks ?? [])\n .filter((a) => typeof a.id === 'number')\n .map((a) => {\n const isRemove = a.action === 'remove'\n // 服务端任务的 target:github:repo(git 安装)/ npm 包名(npm 安装/卸载)。\n // 恢复展示统一用 displayTarget(owner/repo,服务端固定传):npm 安装时 target 是包名,\n // 直接展示会让用户看到「安装方式」的内部细节,违背无感知原则;卸载保持包名(匹配已装表)。\n const display = typeof (a as { displayTarget?: unknown }).displayTarget === 'string' ? (a as { displayTarget: string }).displayTarget.replace(/^github:/, '') : ''\n const fallback = typeof a.target === 'string' ? a.target.replace(/^github:/, '') : ''\n return {\n id: a.id as number,\n kind: (isRemove ? 'uninstall' : 'install') as 'install' | 'uninstall',\n target: isRemove ? fallback : (display || fallback),\n repo: isRemove ? null : (display || fallback),\n status: a.status === 'running' ? 'running' : 'pending',\n progress: typeof a.progress === 'number' ? a.progress : 0,\n lines: Array.isArray(a.lines) ? (a.lines as string[]) : [],\n attempts: Array.isArray((a as { attempts?: unknown }).attempts) ? ((a as { attempts: string[] }).attempts) : [],\n }\n })\n if (items.length > 0 || pendingRef.current.length > 0) {\n applyQueue((prev) => [...prev, ...items.filter((n) => !prev.some((p) => p.id === n.id))])\n // 刷新后恢复的任务同样保持折叠:摘要条提示进行中,点开才看明细/日志\n pollQueue()\n }\n } catch { /* host without the plugin's server routes */ }\n }\n void restore()\n return () => { cancelled = true }\n }, [])\n\n /** 弹窗动作:直接安装。请求宿主本地路由,任务进入服务端队列(FIFO),弹窗内实时显示进度。 */\n const installNow = async (p: HubPlugin, opts?: { update?: boolean }) => {\n const repo = p.source?.repo ?? ''\n if (!repo) return\n // 安装通道决策(用户无感知):有 npm 包名 → 走 npm;否则 git 直装。\n // 队列条目一律用仓库名展示/防重,只有发给后端的实际安装目标随通道变化。\n const { target } = installTargetOf(p)\n if (!target) return\n // 防重复入队:同一目标已在排队/执行中则忽略\n if (queueRef.current.some((q) => q.kind === 'install' && q.target === repo)) return\n // 请求在途防重:任务要等响应回来才进本地队列,这之前再次点击(双击)直接忽略\n if (submittingRef.current.has(repo)) return\n submittingRef.current.add(repo)\n // 乐观入队:点击安装立即显示「正在安装中」,不等 POST 响应。\n // 服务端 /install 会先跑预检(preflight,可能耗时数秒)再入队,若等响应才入队列,\n // 用户点完安装立刻去通知中心会看不到任务 —— 只有刷新后 restore 才拉回来。\n // 用负临时 id 占位,响应回来换成真实 task id;失败/出错则移除该占位。\n tempIdRef.current -= 1\n const tempId = tempIdRef.current\n modalTaskRef.current = tempId\n applyQueue((prev) => [...prev, {\n id: tempId, kind: 'install', target: repo, repo, desc: p.description,\n version: p.version, updatedAt: p.dates?.repoUpdatedAt,\n status: 'running', progress: 0, lines: [], optimistic: true,\n command: installCommandOf(p, true),\n // 服务端登记后 /active 会带回真实尝试记录(npm 反查 + 执行命令),先占位空列表\n attempts: [],\n }])\n setSubmitting(true)\n try {\n const res = await fetch('/dsh-plugin-hub/install', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ repo: target, display: repo, mode: opts?.update ? 'update' : undefined }),\n })\n const data = await res.json() as { ok?: boolean; task?: number; error?: string; attempts?: string[] }\n if (!data.ok || typeof data.task !== 'number') {\n // 请求层失败(重复安装 409 / 参数错误等):移除乐观条目 + 完整错误弹窗\n applyQueue((prev) => prev.filter((x) => x.id !== tempId))\n // 同步 400(如预检拦截)服务端会附上已尝试的安装方式,issue 预填一并展示\n onError(data.error ?? `HTTP ${res.status}`, repo, 'install', installCommandOf(p, true), data.attempts)\n return\n }\n const taskId = data.task\n modalTaskRef.current = taskId\n // 用真实任务 id 替换乐观占位,解除 optimistic 标记(此后归正常收尾/轮询处理)\n applyQueue((prev) => prev.map((x) => (x.id === tempId\n ? { ...x, id: taskId, optimistic: undefined }\n : x)))\n // 提前缓存展示信息:安装成功后服务端登记待重启,轮询合并时不用等目录解析\n pendingInfoRef.current.set(repo, { desc: p.description, version: p.version })\n // 摘要条常驻顶部(含实时进度),明细面板保持折叠,想看时再点开\n pollQueue()\n } catch {\n // 网络异常:移除乐观条目 + 兜底错误弹窗\n applyQueue((prev) => prev.filter((x) => x.id !== tempId))\n onError(t('installFail'), repo, 'install', installCommandOf(p, true))\n } finally {\n submittingRef.current.delete(repo)\n setSubmitting(false)\n }\n }\n\n /** 弹窗动作:直接卸载。与安装同一队列机制,弹窗内实时显示进度。 */\n const uninstallNow = async (p: HubPlugin) => {\n const name = installedName(p)\n if (!name) return\n const repo = p.source?.repo ?? null\n if (queueRef.current.some((q) => q.kind === 'uninstall' && q.target === name)) return\n // 请求在途防重:与安装一致,响应回来前再次点击直接忽略\n if (submittingRef.current.has(name)) return\n submittingRef.current.add(name)\n setSubmitting(true)\n try {\n const res = await fetch('/dsh-plugin-hub/uninstall', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name, repo: repo ?? undefined }),\n })\n const data = await res.json() as { ok?: boolean; task?: number; error?: string }\n if (!data.ok || typeof data.task !== 'number') {\n onError(data.error ?? `HTTP ${res.status}`, repo, 'uninstall')\n return\n }\n const taskId = data.task\n modalTaskRef.current = taskId\n applyQueue((prev) => [...prev, { id: taskId, kind: 'uninstall', target: name, desc: p.description, repo, status: 'pending', progress: 0, lines: [] }])\n // 摘要条常驻顶部(含实时进度),明细面板保持折叠,想看时再点开\n pollQueue()\n } catch {\n onError(t('uninstallFail'), repo, 'uninstall')\n } finally {\n submittingRef.current.delete(name)\n setSubmitting(false)\n }\n }\n\n /** 取消任务:排队中立即出队,执行中终止子进程;先标记「正在取消」短暂过渡后再移除。 */\n const cancelTask = async (id: number) => {\n if (modalTaskRef.current === id) modalTaskRef.current = null\n // 乐观标记「正在取消」,给用户一个可见反馈,而不是瞬间消失\n applyQueue((prev) => prev.map((q) => (q.id === id ? { ...q, status: 'cancelling' as const } : q)))\n try {\n await fetch('/dsh-plugin-hub/cancel', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n })\n } catch { /* 服务端不可达:仍按取消处理,稍后移除 */ }\n // 短暂展示「正在取消」后移除;队列清空则停止轮询\n window.setTimeout(() => {\n applyQueue((prev) => prev.filter((x) => x.id !== id))\n maybeStopPoll()\n }, 700)\n }\n\n /** 打开新弹窗前清空任务匹配:避免旧任务 id 误匹配到新弹窗。 */\n const clearModalTask = () => { modalTaskRef.current = null }\n\n // 弹窗对应任务:优先当前弹窗发起任务,其次按目标匹配(重新打开弹窗 / 目标已在队列时也能展示实时进度)\n // 排除 cancelling:取消中的任务不再关联到弹窗,弹窗回到「确认」态可重新操作\n const installModalTask = installPlugin\n ? (queue.find((q) => q.id === modalTaskRef.current && q.status !== 'cancelling')\n ?? queue.find((q) => q.kind === 'install' && q.target === (installPlugin.source?.repo ?? '') && q.status !== 'cancelling')\n ?? null)\n : null\n const uninstallModalTask = uninstallPlugin\n ? (queue.find((q) => q.id === modalTaskRef.current && q.status !== 'cancelling')\n ?? queue.find((q) => q.kind === 'uninstall' && q.target === (installedName(uninstallPlugin) ?? '') && q.status !== 'cancelling')\n ?? null)\n : null\n\n return {\n queue,\n pendingRestarts,\n installModalTask,\n uninstallModalTask,\n submitting,\n installNow,\n uninstallNow,\n cancelTask,\n clearModalTask,\n }\n}\n","/**\n * Inline SVG icons used across the client. Icons inherit currentColor so\n * they adapt to themes and disabled states automatically.\n */\nimport { createElement as h } from 'react'\nimport headerStyles from '../styles/Header.module.css'\nimport modalStyles from '../styles/Modal.module.css'\n\n/** 弹窗右上角关闭按钮图标:内联 SVG 十字(stroke 继承 currentColor),随按钮禁用态一起变淡。 */\nexport function CloseIcon() {\n return h('svg', {\n className: modalStyles.modalCloseIcon,\n viewBox: '0 0 16 16',\n width: 14,\n height: 14,\n fill: 'none',\n 'aria-hidden': 'true',\n }, h('path', {\n d: 'M3 3l10 10M13 3L3 13',\n stroke: 'currentColor',\n strokeWidth: 1.6,\n strokeLinecap: 'round',\n }))\n}\n\n/** 来源链接图标:链节(stroke 继承 currentColor),弹窗里官网收录地址旁提示「可点击跳转」。 */\nexport function LinkIcon() {\n return h('svg', {\n className: modalStyles.linkIcon,\n viewBox: '0 0 24 24',\n width: 13,\n height: 13,\n fill: 'none',\n 'aria-hidden': 'true',\n },\n h('path', {\n d: 'M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71',\n stroke: 'currentColor',\n strokeWidth: 1.8,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n }),\n h('path', {\n d: 'M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71',\n stroke: 'currentColor',\n strokeWidth: 1.8,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n }))\n}\n\n/** 品牌 logo 图标:蓝紫渐变圆角方块 + 白色拼图块(2x2 错落),标题左侧的品牌标识。 */\nexport function LogoIcon() {\n return h('svg', {\n className: headerStyles.logoIcon,\n viewBox: '0 0 24 24',\n width: 20,\n height: 20,\n 'aria-hidden': 'true',\n },\n h('defs', null,\n h('linearGradient', { id: 'dshLogoGrad', x1: '0', y1: '0', x2: '1', y2: '1' },\n h('stop', { offset: '0%', stopColor: '#4f46e5' }),\n h('stop', { offset: '100%', stopColor: '#7c3aed' }),\n ),\n ),\n h('rect', { x: 1, y: 1, width: 22, height: 22, rx: 6, fill: 'url(#dshLogoGrad)' }),\n h('rect', { x: 5.5, y: 5.5, width: 5.5, height: 5.5, rx: 1.5, fill: '#ffffff' }),\n h('rect', { x: 13, y: 5.5, width: 5.5, height: 5.5, rx: 1.5, fill: '#ffffff', opacity: 0.55 }),\n h('rect', { x: 5.5, y: 13, width: 5.5, height: 5.5, rx: 1.5, fill: '#ffffff', opacity: 0.55 }),\n h('rect', { x: 13, y: 13, width: 5.5, height: 5.5, rx: 1.5, fill: '#ffffff' }),\n )\n}\n\n/** GitHub 图标:官方 GitHub Mark(octocat),fill 继承 currentColor,头部右上角源码链接用。 */\nexport function GitHubIcon() {\n return h('svg', {\n className: headerStyles.githubIcon,\n viewBox: '0 0 24 24',\n width: 18,\n height: 18,\n fill: 'currentColor',\n 'aria-hidden': 'true',\n }, h('path', {\n d: 'M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12',\n }))\n}\n\n/** 复制图标:双层矩形(stroke 继承 currentColor),手动命令旁的复制按钮用。 */\nexport function CopyIcon() {\n return h('svg', {\n className: headerStyles.copyIcon,\n viewBox: '0 0 16 16',\n width: 12,\n height: 12,\n fill: 'none',\n 'aria-hidden': 'true',\n },\n h('rect', {\n x: 5.5, y: 5.5, width: 7, height: 7, rx: 1.5,\n stroke: 'currentColor', strokeWidth: 1.4,\n }),\n h('path', {\n d: 'M10.5 5.5v-2a1.5 1.5 0 0 0-1.5-1.5H4.5A1.5 1.5 0 0 0 3 3.5v4A1.5 1.5 0 0 0 4.5 9h1',\n stroke: 'currentColor', strokeWidth: 1.4, strokeLinecap: 'round',\n }),\n )\n}\n\n/** 下拉箭头图标:向下 V 形(stroke 继承 currentColor),下拉框触发器右侧提示可展开。 */\nexport function ChevronDownIcon() {\n return h('svg', {\n viewBox: '0 0 16 16',\n width: 12,\n height: 12,\n fill: 'none',\n 'aria-hidden': 'true',\n }, h('path', {\n d: 'M3.5 5.5L8 10l4.5-4.5',\n stroke: 'currentColor',\n strokeWidth: 1.6,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n }))\n}\n","/**\n * Inline progress block shared by the install and uninstall dialogs:\n * a real percentage bar (server-estimated, client-polled). No live terminal\n * window — pnpm emits nothing during git clone/build, so a log pane would be\n * empty for most of the run; failures surface their full output in ErrorModal.\n */\nimport { createElement as h } from 'react'\nimport styles from '../styles/Modal.module.css'\nimport type { TaskState } from '../types.ts'\n\nexport function ProgressView({ task }: { task: TaskState }) {\n return h('div', { className: styles.progress },\n h('div', { className: styles.progressHead },\n h('span', { className: styles.progressText }, `${Math.round(task.progress)}%`),\n ),\n h('div', { className: styles.progressTrack },\n h('div', {\n className: task.status === 'failed' ? `${styles.progressFill} ${styles.progressFillFail}` : styles.progressFill,\n style: { width: `${task.progress}%` },\n }),\n ),\n )\n}\n","/**\n * Dialog layer for the Plugin Hub: the install-confirm dialog, the uninstall\n * dialog and the global toast. Both dialogs lock themselves while a mutation\n * or restart is running, then switch to a result view offering an immediate\n * restart or a \"later\" deferral.\n */\nimport { createElement as h } from 'react'\nimport type { MouseEvent } from 'react'\nimport styles from '../styles/Modal.module.css'\nimport type { EnvInfo, HubPlugin, TaskState, ToastState, Translate } from '../types.ts'\nimport { CloseIcon, CopyIcon, LinkIcon } from './icons.tsx'\nimport { ProgressView } from './ProgressView.tsx'\nimport { installCommandOf, pluginDetailUrl, pluginIssueUrl, pluginSiteUrl } from '../lib/catalog.ts'\nimport { classifyFailure } from '../lib/failures.ts'\n\n/** 完成结果视图:绿色对勾 + 标题/描述 + 「稍后重启 / 立即重启」按钮对(部分插件需重启后才会挂载) */\nfunction ResultView({\n title, desc, t, restarting, onRestart, onClose,\n}: {\n title: string\n desc: string\n t: Translate\n restarting: boolean\n onRestart: () => void\n onClose: () => void\n}) {\n return h('div', { className: styles.result },\n h('div', { className: styles.resultCheck },\n h('svg', {\n className: styles.resultCheckIcon,\n viewBox: '0 0 16 16',\n width: 20,\n height: 20,\n fill: 'none',\n 'aria-hidden': 'true',\n }, h('path', {\n d: 'M2.5 8.5l3.5 3.5 7.5-7.5',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n })),\n ),\n h('div', { className: styles.resultTitle }, title),\n desc ? h('div', { className: styles.resultDesc }, desc) : null,\n h('div', { className: styles.resultRestarting }, restarting ? t('restarting') : t('restartHint')),\n h('div', { className: styles.modalActions },\n h('button', { className: styles.restartLater, onClick: onClose, disabled: restarting }, t('restartLater')),\n h('button', { className: styles.restartNow, onClick: onRestart, disabled: restarting },\n restarting ? t('restarting') : t('restartNow')),\n ),\n )\n}\n\nexport interface InstallModalProps {\n plugin: HubPlugin\n done: boolean\n task: TaskState | null\n t: Translate\n langPath: string\n restarting: boolean\n /** 已安装插件的覆盖更新(走同一条 add 命令原位重装,文案区分安装/更新) */\n update: boolean\n /** 安装请求在途(fetch 等待响应):此时任务尚未入队,需禁用确认按钮防止二次点击 */\n submitting: boolean\n onClose: () => void\n onCopy: () => void\n onInstall: () => void\n onRestart: () => void\n}\n\n/**\n * 信任确认弹窗:安装进入后台队列后弹窗仍可关闭(任务继续),\n * 只在本任务执行中展示实时进度;完成后切换为结果视图,与卸载一致。\n */\nexport function InstallModal(props: InstallModalProps) {\n const { plugin, done, task, t, langPath, restarting, submitting, update, onClose, onCopy, onInstall, onRestart } = props\n const busy = submitting || (task !== null && (task.status === 'pending' || task.status === 'running'))\n // 进行中标题带上插件名(中文「XX 插件安装中」;英文状态词在前更自然),并用状态色区分\n const name = plugin.displayName ?? plugin.slug\n const busyTitle = (label: string) => langPath === 'zh/' ? `${name} 插件${label}` : `${label} ${name}`\n const title = busy\n ? task && task.status === 'pending'\n ? busyTitle(update ? t('queuedUpdateTitle') : t('queuedTitle'))\n : busyTitle(update ? t('updating') : t('installing'))\n : done\n ? update ? t('updateResultTitle') : t('installResultTitle')\n : update ? t('confirmUpdateTitle') : t('confirmTitle')\n return h('div', {\n className: styles.overlay,\n onClick: (e: MouseEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget) onClose()\n },\n },\n h('div', { className: styles.modal, role: 'dialog', 'aria-modal': 'true' },\n h('div', { className: styles.modalHead },\n h('div', {\n className: busy\n ? `${styles.modalTitle} ${task && task.status === 'pending' ? styles.modalTitleQueued : styles.modalTitleBusy}`\n : styles.modalTitle,\n }, title),\n h('button', {\n className: styles.modalClose,\n 'aria-label': t('confirmCancel'),\n onClick: () => onClose(),\n }, h(CloseIcon)),\n ),\n done\n // 安装完成:结果视图(成功即生效,仅「完成」关闭);更新时标题/描述区分语义\n ? h(ResultView, {\n title: update ? t('updateResultTitle') : t('installResultTitle'),\n desc: update ? t('updateResultDesc') : t('installResultDesc'),\n t,\n restarting,\n onRestart,\n onClose,\n })\n // 确认/进行中:来源行 + 安装命令 + 实时进度 + 操作按钮\n : h('div', { className: styles.modalBody },\n h('div', { className: styles.trustHint }, t('confirmDesc')),\n h('div', { className: styles.modalRow },\n h('span', { className: styles.modalLabel }, t('confirmPlugin')),\n h('span', { className: styles.modalValue, title: plugin.displayName ?? plugin.slug },\n plugin.displayName ?? plugin.slug),\n ),\n plugin.source?.repo ? h('div', { className: styles.modalRow },\n h('span', { className: styles.modalLabel }, t('confirmSource')),\n // 来源仓库:可点击跳转官网收录详情页(新窗口打开)\n h('a', {\n className: styles.modalLink,\n href: pluginDetailUrl(plugin, langPath),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: plugin.source.repo,\n }, h(LinkIcon), plugin.source.repo),\n ) : null,\n // 手动命令条:整条点击即复制,右侧再放一个显式复制按钮\n h('div', {\n className: styles.modalCmd,\n onClick: onCopy,\n title: t('copyInstallCommand'),\n role: 'button',\n tabIndex: 0,\n },\n h('span', { className: styles.modalCmdText }, installCommandOf(plugin)),\n h('span', { className: styles.modalCmdCopy }, h(CopyIcon), t('copyCmdLabel')),\n ),\n task && task.status === 'pending' ? h('div', { className: styles.queuedHint }, t('queuedHint')) : null,\n task ? h(ProgressView, { task }) : null,\n h('div', { className: styles.modalActions },\n h('button', {\n className: styles.modalCopy,\n disabled: busy,\n onClick: onCopy,\n }, t('copyInstallCommand')),\n h('button', {\n className: styles.modalInstall,\n disabled: busy,\n onClick: onInstall,\n }, busy\n ? (task && task.status === 'pending'\n ? (update ? t('queuedUpdateTitle') : t('queuedTitle'))\n : (update ? t('updating') : t('installing')))\n : (update ? t('updateNow') : t('installNow'))),\n ),\n ),\n ),\n )\n}\n\nexport interface UninstallModalProps {\n plugin: HubPlugin\n done: boolean\n task: TaskState | null\n t: Translate\n langPath: string\n restarting: boolean\n /** 卸载请求在途(fetch 等待响应):此时任务尚未入队,需禁用确认按钮防止二次点击 */\n submitting: boolean\n onClose: () => void\n onCancel: () => void\n onCopyCommand: () => void\n onConfirm: () => void\n onRestart: () => void\n}\n\n/** 卸载确认弹窗:确认/进行中(后台队列,可关闭);完成后切换为结果视图(成功即生效,仅「完成」关闭)。 */\nexport function UninstallModal(props: UninstallModalProps) {\n const { plugin, done, task, t, langPath, restarting, submitting, onClose, onCancel, onCopyCommand, onConfirm, onRestart } = props\n const busy = submitting || (task !== null && (task.status === 'pending' || task.status === 'running'))\n // 进行中标题带上插件名,与安装弹窗一致,并用状态色区分\n const name = plugin.displayName ?? plugin.slug\n const busyTitle = (label: string) => langPath === 'zh/' ? `${name} 插件${label}` : `${label} ${name}`\n const title = busy\n ? task && task.status === 'pending' ? busyTitle(t('queuedUninstallTitle')) : busyTitle(t('uninstalling'))\n : done ? t('uninstallResultTitle') : t('uninstallTitle')\n return h('div', {\n className: styles.overlay,\n onClick: (e: MouseEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget) onClose()\n },\n },\n h('div', { className: styles.modal, role: 'dialog', 'aria-modal': 'true' },\n h('div', { className: styles.modalHead },\n h('div', {\n className: busy\n // 注意 task 判空:submitting(请求在途)时任务尚未入队,task 为 null,不能直接解引用\n ? `${styles.modalTitle} ${task !== null && task.status === 'pending' ? styles.modalTitleQueued : styles.modalTitleBusy}`\n : styles.modalTitle,\n }, title),\n h('button', {\n className: styles.modalClose,\n 'aria-label': t('confirmCancel'),\n onClick: () => onClose(),\n }, h(CloseIcon)),\n ),\n done\n // 卸载完成:结果视图(成功即生效,仅「完成」关闭)\n ? h(ResultView, {\n title: t('uninstallResultTitle'),\n desc: t('uninstallResultDesc'),\n t,\n restarting,\n onRestart,\n onClose,\n })\n // 确认/进行中:来源行 + 实时进度 + 操作按钮\n : h('div', { className: styles.modalBody },\n h('div', { className: styles.modalDesc }, t('uninstallDesc')),\n h('div', { className: styles.modalRow },\n h('span', { className: styles.modalLabel }, t('confirmPlugin')),\n h('span', { className: styles.modalValue, title: plugin.displayName ?? plugin.slug },\n plugin.displayName ?? plugin.slug),\n ),\n // 显示仓库来源:github 用户名 + 仓库名,让用户确认卸载的是哪一个仓库\n plugin.source?.repo ? h('div', { className: styles.modalRow },\n h('span', { className: styles.modalLabel }, t('confirmSource')),\n // 来源仓库:可点击跳转官网收录详情页(新窗口打开)\n h('a', {\n className: styles.modalLink,\n href: pluginDetailUrl(plugin, langPath),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: plugin.source.repo,\n }, h(LinkIcon), plugin.source.repo),\n ) : null,\n task && task.status === 'pending' ? h('div', { className: styles.queuedHint }, t('queuedHint')) : null,\n task ? h(ProgressView, { task }) : null,\n h('div', { className: styles.modalActions },\n h('button', {\n className: styles.modalCancel,\n onClick: onCancel,\n }, t('confirmCancel')),\n // 复制卸载命令:万一直接卸载失败,可去终端手动执行\n h('button', {\n className: styles.modalCopy,\n disabled: busy,\n onClick: onCopyCommand,\n }, t('copyUninstallCommand')),\n h('button', {\n className: styles.uninstallConfirm,\n disabled: busy,\n onClick: onConfirm,\n }, busy ? (task && task.status === 'pending' ? t('queuedUninstallTitle') : t('uninstalling')) : t('uninstall')),\n ),\n ),\n ),\n )\n}\n\n/** 预填插件仓库的 GitHub Issue 链接:标题带插件名,正文附完整错误信息,方便用户一键反馈。 */\n/** 安装/卸载失败弹窗:布局与失败记录一致(类型徽标 + 仓库超链接 + 隐蔽复制按钮),报错完整展示,底部一键提交 Issue。 */\nexport function ErrorModal({ message, repo, kind, command, attempts, t, env, onCopy, onClose }: {\n message: string\n repo: string | null\n kind: 'install' | 'uninstall'\n command?: string\n /** 尝试过的安装方式(npm 反查 + 实际执行命令):issue 预填一并贴给作者,便于反推正确的 npm 包名 */\n attempts?: string[]\n t: Translate\n env: EnvInfo | null\n onCopy: (text: string) => void\n onClose: () => void\n}) {\n // 失败归类:当前安装通道(npm/git)装不上 = 插件分发/依赖的问题,一律引导提 Issue\n const failureKind = classifyFailure(message)\n return h('div', {\n className: styles.overlay,\n onClick: (e: MouseEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget) onClose()\n },\n },\n h('div', { className: styles.errorModal, role: 'dialog', 'aria-modal': 'true' },\n h('div', { className: styles.modalHead },\n // 标题按操作类型明确区分:安装失败 / 卸载失败\n h('div', { className: styles.errorTitle }, kind === 'install' ? t('errorTitleInstall') : t('errorTitleUninstall')),\n h('button', {\n className: styles.modalClose,\n 'aria-label': t('errorClose'),\n onClick: onClose,\n }, h(CloseIcon)),\n ),\n h('div', { className: styles.modalBody },\n // 与失败记录一致的布局:类型徽标 + 仓库超链接 + 顶部隐蔽复制按钮\n h('div', { className: styles.failRow },\n h('div', { className: styles.failHead },\n h('span', {\n className: kind === 'install' ? styles.failKindInstall : styles.failKindUninstall,\n }, kind === 'install' ? t('install') : t('uninstall')),\n // 仓库地址(用户名/仓库)统一显示为可点击超链接,跳转到官网详情页(含插件收录信息),而非直接跳 GitHub\n repo ? h('a', {\n className: styles.failRepo,\n href: pluginSiteUrl(repo),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: repo,\n }, repo) : null,\n // 复制按钮放最上面、浅灰隐蔽;报错正文不允许鼠标选择复制,只能点这里\n h('button', { className: styles.errorCopySoft, onClick: () => onCopy(message) }, t('errorCopy')),\n ),\n // 报错信息完整展示(可滚动),比失败记录的预览看得更多\n h('pre', { className: styles.errorBox }, message),\n // 插件问题(prepare 构建失败 / 原生依赖构建被拦截 / git 分发缺产物):都是插件打包分发问题 —— 先说明原因,按钮在下方引导提 Issue\n failureKind === 'pluginPrepare' || failureKind === 'pnpmIgnoredBuild'\n ? h('div', null, [\n // [packaging](预检/装后校验拦截:git 分发缺产物)与\n // prepare 构建脚本实际执行失败 / 原生依赖构建被 pnpm 拦截:都是插件打包分发问题 —— 先说明原因,按钮在下方提交\n h('div', { className: styles.failPrepareHint }, failureKind === 'pnpmIgnoredBuild'\n ? t('failIgnoredBuild')\n : /\\[packaging\\]/i.test(message) ? t('failPackagingHint') : t('failPrepareHint')),\n repo ? h('a', {\n className: styles.failBigIssue,\n href: pluginIssueUrl(repo, message, env, command, attempts),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('failIssueHint'),\n }, t('failIssueBig')) : null,\n ])\n : repo ? h('a', {\n className: styles.failBigIssue,\n href: pluginIssueUrl(repo, message, env, command, attempts),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('failIssueHint'),\n }, t('failIssueBig')) : null,\n ),\n h('div', { className: styles.modalActions },\n h('button', { className: styles.restartLater, onClick: onClose }, t('errorClose')),\n ),\n ),\n ),\n )\n}\n\n/** 全局反馈 Toast:复制成功(反色)/ 安装完成(反色)/ 安装失败(红色)/ 卸载结果 */\nexport function Toast({ toast, t }: { toast: ToastState; t: Translate }) {\n const text = toast.kind === 'copied' ? t('toastCopied')\n : toast.kind === 'errCopied' ? t('errCopied')\n : toast.kind === 'done' ? t('installDone')\n : toast.kind === 'fail' ? t('installFail')\n : toast.kind === 'removed' ? t('uninstallDone')\n : t('uninstallFail')\n const fail = toast.kind === 'fail' || toast.kind === 'removeFail'\n return h('div', {\n key: toast.id,\n className: fail ? `${styles.toast} ${styles.toastFail}` : styles.toast,\n }, text)\n}\n","/**\n * Notification-center dialog: a persistent log of every settled install /\n * remove task — successes and failures alike.\n *\n * Records are written to localStorage at settle time (see lib/failures.ts),\n * so a result is never lost even when the dialog was dismissed or the user\n * was away. Each entry carries a circular status badge (green check for\n * success, red cross for failure) with white glyph and message text;\n * failures keep their copy / fix / file-an-issue actions. Opened from the\n * header entry button.\n */\nimport { createElement as h } from 'react'\nimport type { MouseEvent } from 'react'\nimport styles from '../styles/Modal.module.css'\nimport type { EnvInfo, Translate } from '../types.ts'\nimport type { NotificationRecord } from '../lib/failures.ts'\nimport { classifyFailure } from '../lib/failures.ts'\nimport type { PendingRestart, QueueTask } from '../hooks/useTaskQueue.ts'\nimport { pluginIssueUrl, pluginSiteUrl } from '../lib/catalog.ts'\nimport { CloseIcon } from './icons.tsx'\n\n/** 记录时间完整展示:YYYY-MM-DD HH:mm:ss(每条通知都带精确到秒的时间戳)。 */\nfunction fmtTime(at: number): string {\n const d = new Date(at)\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`\n}\n\n/** 圆形状态徽标内的白色图形:成功为对勾、失败为叉。 */\nfunction BadgeGlyph({ ok }: { ok: boolean }) {\n return h('svg', {\n className: styles.noticeBadgeIcon,\n viewBox: '0 0 16 16',\n width: 12,\n height: 12,\n fill: 'none',\n 'aria-hidden': 'true',\n }, ok\n ? h('path', {\n d: 'M3 8.5l3.5 3.5 6.5-6.5',\n stroke: '#ffffff',\n strokeWidth: 2,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n })\n : h('path', {\n d: 'M4 4l8 8M12 4L4 12',\n stroke: '#ffffff',\n strokeWidth: 2,\n strokeLinecap: 'round',\n }))\n}\n\nexport function NotificationsModal({ records, tasks, pendingRestarts, t, env, onClose, onCopy, onClear, onRemove, cancelTask, restarting, onRestart }: {\n records: NotificationRecord[]\n /** 进行中的安装/卸载任务(实时进度,与队列弹窗同一数据源) */\n tasks: QueueTask[]\n /** 待重启插件:装完没重启的常驻提醒 */\n pendingRestarts: PendingRestart[]\n t: Translate\n env: EnvInfo | null\n onClose: () => void\n onCopy: (text: string) => void\n onClear: () => void\n /** 删除单条通知记录 */\n onRemove: (id: number) => void\n cancelTask: (id: number) => void\n restarting: boolean\n onRestart: () => void\n}) {\n return h('div', {\n className: styles.overlay,\n onClick: (e: MouseEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget) onClose()\n },\n },\n h('div', { className: styles.errorModal, role: 'dialog', 'aria-modal': 'true' },\n h('div', { className: styles.modalHead },\n h('div', { className: styles.modalTitle }, t('notifications')),\n h('button', {\n className: styles.modalClose,\n 'aria-label': t('errorClose'),\n onClick: onClose,\n }, h(CloseIcon)),\n ),\n h('div', { className: styles.modalBody },\n h('div', { className: styles.errorHint }, t('notificationsDesc')),\n // 进行中的安装/卸载任务实时进度也进通知中心:与队列弹窗同一套行结构,\n // 关掉任务弹窗后仍可在这里盯着进度;待重启插件可在此直接触发重启\n (tasks.length > 0 || pendingRestarts.length > 0)\n ? h('div', null, [\n pendingRestarts.length > 0\n ? h('div', { className: styles.queueSection },\n h('div', { className: styles.queueSectionTitle }, t('sectionPendingRestart')),\n pendingRestarts.map((p) => h('div', { key: `restart-${p.target}`, className: styles.queueRow },\n h('div', { className: styles.queueRowHead },\n h('span', {\n className: `${styles.failKind} ${p.kind === 'uninstall' ? styles.failKindUninstall : styles.failKindInstall}`,\n }, p.kind === 'uninstall' ? t('uninstall') : t('install')),\n h('span', { className: styles.queueRowTarget, title: p.target }, p.target),\n ),\n p.desc ? h('div', { className: styles.queueRowDesc, title: p.desc }, p.desc) : null,\n h('div', { className: styles.queueRowBody },\n h('span', { className: styles.pendingRowStatus },\n p.kind === 'uninstall' ? t('restartPendingHintUninstall') : t('restartPendingHint')),\n h('span', { className: styles.pendingRowActions },\n h('button', {\n className: styles.restartLater,\n disabled: restarting,\n onClick: onClose,\n }, t('restartLater')),\n h('button', {\n className: styles.restartNow,\n disabled: restarting,\n onClick: onRestart,\n }, restarting ? t('restarting') : t('restartNow')),\n ),\n ),\n )),\n )\n : null,\n tasks.length > 0\n ? h('div', { className: styles.queueSection },\n h('div', { className: styles.queueSectionTitle }, t('sectionInProgress')),\n tasks.map((q) => h('div', { key: q.id, className: styles.queueRow },\n h('div', { className: styles.queueRowHead },\n h('span', {\n className: `${styles.failKind} ${q.kind === 'install' ? styles.failKindInstall : styles.failKindUninstall}`,\n }, q.kind === 'install' ? t('install') : t('uninstall')),\n h('span', { className: styles.queueRowTarget, title: q.target }, q.target),\n h('button', {\n className: styles.stripCancel,\n disabled: q.status === 'cancelling',\n onClick: (e: MouseEvent<HTMLButtonElement>) => { e.stopPropagation(); cancelTask(q.id) },\n }, t('cancelTask')),\n ),\n q.desc ? h('div', { className: styles.queueRowDesc, title: q.desc }, q.desc) : null,\n h('div', { className: styles.queueRowBody },\n h('span', { className: styles.queueRowStatus },\n q.status === 'running'\n ? (q.kind === 'install' ? t('installing') : t('uninstalling'))\n : q.status === 'cancelling'\n ? t('cancelling')\n : (q.kind === 'install' ? t('queuedTitle') : t('queuedUninstallTitle'))),\n h('div', { className: `${styles.progressTrack} ${styles.queueRowTrack}` },\n h('div', { className: styles.progressFill, style: { width: `${q.progress}%` } }),\n ),\n h('span', { className: styles.queueRowPct }, `${q.progress}%`),\n ),\n )),\n )\n : null,\n ])\n : null,\n records.length === 0\n ? h('div', { className: styles.failEmpty }, t('notificationsEmpty'))\n : h('div', { className: styles.noticeList },\n records.map((r) => {\n return h('div', { key: r.id, className: styles.noticeRow },\n h('div', { className: styles.noticeRowMain },\n h('div', {\n className: r.ok ? styles.noticeBadgeOk : styles.noticeBadgeFail,\n }, h(BadgeGlyph, { ok: r.ok })),\n h('div', { className: styles.noticeMain },\n h('div', { className: styles.noticeHead },\n h('span', {\n className: r.ok ? styles.noticeTextOk : styles.noticeTextFail,\n }, r.ok\n ? (r.kind === 'install' ? t('installDone') : t('uninstallDone'))\n : (r.kind === 'install' ? t('errorTitleInstall') : t('errorTitleUninstall'))),\n r.repo\n ? h('a', {\n className: styles.failRepo,\n // 跳转到官网详情页(含插件收录信息),不在通知弹窗直接跳 GitHub\n href: pluginSiteUrl(r.repo),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: r.repo,\n }, r.repo)\n : null,\n !r.ok && h('button', {\n className: styles.failCopy,\n onClick: () => onCopy(r.message),\n }, t('failCopy')),\n // 每条通知右侧的删除按钮:单独移除这一条\n h('button', {\n className: styles.noticeRemove,\n 'aria-label': t('removeNotification'),\n title: t('removeNotification'),\n onClick: (e: MouseEvent<HTMLButtonElement>) => { e.stopPropagation(); onRemove(r.id) },\n }, h(CloseIcon)),\n ),\n // 每条失败记录是一个独立卡片:头部(状态/仓库/时间/复制完整日志)→ 修复或提 Issue 动作。\n // 卡片不展示错误日志预览,完整日志靠「复制完整日志」按钮带走,避免每条卡片被日志撑高\n !r.ok && (() => {\n const kind = classifyFailure(r.message)\n if (kind === 'pluginPrepare' || kind === 'pnpmIgnoredBuild') {\n // [packaging](预检/装后校验拦截:git 分发缺产物)与\n // prepare 构建脚本实际执行失败 / 原生依赖构建被 pnpm 拦截:都是插件打包分发问题 —— 先说明原因,按钮在下方提交\n return h('div', null, [\n h('div', { className: styles.failPrepareHint }, kind === 'pnpmIgnoredBuild'\n ? t('failIgnoredBuild')\n : /\\[packaging\\]/i.test(r.message) ? t('failPackagingHint') : t('failPrepareHint')),\n r.repo ? h('a', {\n className: styles.failBigIssue,\n href: pluginIssueUrl(r.repo, r.message, env, r.command, r.attempts),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('failIssueHint'),\n }, t('failIssueBig')) : null,\n ])\n }\n return r.repo ? h('a', {\n className: styles.failBigIssue,\n href: pluginIssueUrl(r.repo, r.message, env, r.command, r.attempts),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('failIssueHint'),\n }, t('failIssueBig')) : null\n })(),\n ),\n ),\n // 每条通知右下角:完整年月日时分秒时间戳(独立一行,不参与徽标垂直居中)\n h('div', { className: styles.noticeFoot },\n h('span', {\n className: styles.noticeTime,\n title: new Date(r.at).toLocaleString(),\n }, fmtTime(r.at)),\n ),\n )\n }),\n ),\n h('div', { className: styles.modalActions },\n records.length > 0 ? h('button', {\n className: styles.failClear,\n onClick: onClear,\n }, t('notificationsClear')) : null,\n h('button', { className: styles.restartNow, onClick: onClose }, t('errorClose')),\n ),\n ),\n ),\n )\n}\n","/**\n * Section header: brand title row (H1 + open-site button) + tagline, followed\n * by the purple ad banner that promotes the catalog stats.\n */\nimport { createElement as h, Fragment } from 'react'\nimport styles from '../styles/Header.module.css'\nimport type { Translate } from '../types.ts'\nimport { GITHUB_URL, PLUGIN_VERSION, SITE_URL } from '../lib/catalog.ts'\nimport { GitHubIcon, LogoIcon } from './icons.tsx'\n\nexport function CatalogHeader({ t, langPath, statsTotal, statsVerified, onToggleLang }: {\n t: Translate\n langPath: string\n statsTotal: number\n statsVerified: number\n onToggleLang: () => void\n}) {\n return h(Fragment, null,\n h('div', { className: styles.header },\n // 第一行:logo + 标题(官网链接)与 GitHub 源码图标同行,GitHub 顶到标题行末尾\n h('div', { className: styles.headerTitleRow },\n h('a', {\n className: styles.brandTitle,\n href: `${SITE_URL}${langPath}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('openHint'),\n 'aria-label': t('openHint'),\n },\n h(LogoIcon),\n h('h1', { className: styles.title },\n t('title'),\n h('span', { className: styles.version }, ` v${PLUGIN_VERSION}`),\n ),\n ),\n // 右侧控件组:语言切换 + GitHub 源码图标(独立链接,brandTitle 是官网 <a> 不能嵌套),\n // 一起 space-between 顶到标题行最右\n h('div', { className: styles.headerRight },\n // 语言切换:按钮文字始终显示「要切到的语言」,点击即切,无需图标\n h('button', {\n className: styles.langBtn,\n type: 'button',\n onClick: onToggleLang,\n title: t('toggleLangHint'),\n 'aria-label': t('toggleLangHint'),\n }, langPath === 'zh/' ? 'EN' : '中文'),\n h('a', {\n className: styles.githubLink,\n href: GITHUB_URL,\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('githubHint'),\n 'aria-label': t('githubHint'),\n }, h(GitHubIcon)),\n ),\n ),\n // 第二行:副标题仍是官网链接,点击跳 dsh-plugin.org\n h('a', {\n className: styles.taglineLink,\n href: `${SITE_URL}${langPath}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n title: t('openHint'),\n },\n h('div', { className: styles.tagline }, t('tagline', { total: statsTotal, verified: statsVerified })),\n ),\n ),\n h('a', {\n className: styles.adBanner,\n href: `${SITE_URL}${langPath}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n },\n h('span', { className: styles.adBadge }, t('adBadge')),\n h('span', { className: styles.adText }, t('ad', { total: statsTotal, verified: statsVerified })),\n h('span', { className: styles.adArrow }, '\\u2197')),\n )\n}\n","/**\n * Category tabs: an \"all\" chip followed by one chip per catalog category.\n * The \"all\" chip carries the total plugin count; the per-category chips\n * carry no counts so their widths stay uniform.\n */\nimport { createElement as h } from 'react'\nimport styles from '../styles/Header.module.css'\nimport type { LocaleId } from '../types.ts'\nimport { CATEGORY_ORDER, CATEGORY_SHORT_LABELS, categoryLabel } from '../lib/catalog.ts'\n\nexport function CategoryTabs({ category, setCategory, allLabel, totalCount, langKey }: {\n category: string\n setCategory: (value: string) => void\n allLabel: string\n totalCount: number\n langKey: LocaleId\n}) {\n return h('div', { className: styles.tabs },\n // 第一个按钮固定为「全部」:展示全部分类,直接显示插件总数;\n // 其余分类按钮不带数量,保持排版整齐\n h('button', {\n key: 'all',\n className: category === 'all' ? styles.tabActive : styles.tab,\n onClick: () => setCategory('all'),\n },\n allLabel,\n h('span', { className: styles.tabCount }, totalCount)),\n CATEGORY_ORDER.map((id) => h('button', {\n key: id,\n className: category === id ? styles.tabActive : styles.tab,\n onClick: () => setCategory(id),\n },\n categoryLabel(CATEGORY_SHORT_LABELS, id, langKey))),\n )\n}\n","/**\n * Custom dropdown (native <select> replacement).\n *\n * macOS/浏览器原生下拉无法跟随宿主主题,这里自绘:触发器按钮 + 绝对定位面板,\n * 点外部/Esc 关闭;选项 hover 加重底色、激活项深色实心高亮,全部走 --dsw-alias-* 主题变量。\n */\nimport { createElement as h, useEffect, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport styles from '../styles/Dropdown.module.css'\nimport { ChevronDownIcon } from './icons.tsx'\n\nexport interface DropdownOption<T extends string> {\n value: T\n label: string\n /** 可选计数徽标(如「已安装 12」) */\n count?: number\n}\n\ninterface DropdownProps<T extends string> {\n value: T\n options: DropdownOption<T>[]\n onChange: (value: T) => void\n title?: string\n}\n\nexport function Dropdown<T extends string>({ value, options, onChange, title }: DropdownProps<T>): JSX.Element {\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n\n // 面板展开时:点面板外部或按 Esc 关闭。\n useEffect(() => {\n if (!open) return\n const onDoc = (e: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(e.target as Node)) setOpen(false)\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false)\n }\n document.addEventListener('mousedown', onDoc)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onDoc)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n const current = options.find((o) => o.value === value)\n\n return h('div', { className: styles.dropdown, ref: rootRef },\n h('button', {\n className: styles.dropdownBtn,\n type: 'button',\n title,\n 'aria-haspopup': 'listbox',\n 'aria-expanded': open,\n onClick: () => setOpen((v) => !v),\n },\n h('span', { className: styles.dropdownLabel }, current?.label ?? value),\n h('span', { className: open ? styles.dropdownArrowOpen : styles.dropdownArrow }, h(ChevronDownIcon)),\n ),\n open && h('div', { className: styles.dropdownPanel, role: 'listbox' },\n options.map((o) => h('button', {\n key: o.value,\n type: 'button',\n role: 'option',\n 'aria-selected': o.value === value,\n className: o.value === value ? styles.dropdownItemActive : styles.dropdownItem,\n onClick: () => {\n onChange(o.value)\n setOpen(false)\n },\n },\n h('span', { className: styles.dropdownItemLabel }, o.label),\n typeof o.count === 'number'\n ? h('span', { className: o.value === value ? styles.dropdownCountActive : styles.dropdownCount }, o.count)\n : null,\n )),\n ),\n )\n}\n","/**\n * Toolbar above the list: search input + sort dropdown + installed / not\n * installed filter buttons + the notifications entry. All buttons share the\n * same size (24px high, like the notification entry button).\n */\nimport { createElement as h, Fragment } from 'react'\nimport type { FormEvent } from 'react'\nimport styles from '../styles/Header.module.css'\nimport type { Translate } from '../types.ts'\nimport { SORTS } from '../lib/catalog.ts'\nimport type { SortKey } from '../lib/catalog.ts'\nimport { Dropdown } from './Dropdown.tsx'\n\nexport function CatalogControls({ query, setQuery, sort, setSort, installedFilter, setInstalledFilter, installedCount, notInstalledCount, t, resultText, noticeCount, onOpenNotifications }: {\n query: string\n setQuery: (value: string) => void\n sort: SortKey\n setSort: (value: SortKey) => void\n installedFilter: 'all' | 'installed' | 'notInstalled'\n setInstalledFilter: (value: 'all' | 'installed' | 'notInstalled') => void\n installedCount: number\n notInstalledCount: number\n t: Translate\n resultText: string | null\n noticeCount: number\n onOpenNotifications: () => void\n}) {\n return h(Fragment, null,\n h('div', { className: styles.searchRow },\n h('input', {\n className: styles.search,\n type: 'search',\n placeholder: t('search'),\n value: query,\n spellCheck: false,\n onInput: (e: FormEvent<HTMLInputElement>) =>\n setQuery((e.target as HTMLInputElement).value),\n }),\n ),\n h('div', { className: styles.controls },\n // 筛选结果数:位于排序下拉之前,选中分类后提示「筛选出 N 条插件」;\n // 数字单独等宽显示并预留 5 位宽度,数字变化时整行不左右跳动\n resultText ? h('span', { className: styles.filterResults },\n ...resultText.split(/(\\d+)/).map((part, i) =>\n /^\\d+$/.test(part)\n ? h('span', { key: i, className: styles.resultCount }, part)\n : part)) : null,\n // 全部 / 已安装 / 未安装:互斥单选组,点击直接切换选中态,「全部」即默认恢复项;\n // 已安装/未安装计数跟随当前分类,为 0 时置灰不可点\n h('button', {\n className: installedFilter === 'all'\n ? styles.installedBtnActive\n : styles.installedBtn,\n onClick: () => setInstalledFilter('all'),\n title: t('filterAllHint'),\n 'aria-pressed': installedFilter === 'all',\n }, t('all')),\n // 排序下拉框:紧跟「全部」之后,按需切换排序方式\n Dropdown<SortKey>({\n value: sort,\n options: SORTS.map((key) => ({ value: key, label: t(key) })),\n onChange: setSort,\n }),\n h('button', {\n className: installedFilter === 'installed'\n ? styles.installedBtnActive\n : installedCount === 0\n ? styles.installedBtnDisabled\n : styles.installedBtn,\n onClick: () => setInstalledFilter('installed'),\n disabled: installedCount === 0,\n title: installedCount === 0 ? t('filterInstalledNone') : t('filterInstalledHint'),\n 'aria-pressed': installedFilter === 'installed',\n },\n t('installed'),\n h('span', {\n className: installedFilter === 'installed' ? styles.segCountActive : styles.segCount,\n }, installedCount)),\n h('button', {\n className: installedFilter === 'notInstalled'\n ? styles.installedBtnActive\n : notInstalledCount === 0\n ? styles.installedBtnDisabled\n : styles.installedBtn,\n onClick: () => setInstalledFilter('notInstalled'),\n disabled: notInstalledCount === 0,\n title: notInstalledCount === 0 ? t('filterNotInstalledNone') : t('filterNotInstalledHint'),\n 'aria-pressed': installedFilter === 'notInstalled',\n },\n t('notInstalled'),\n h('span', {\n className: installedFilter === 'notInstalled' ? styles.segCountActive : styles.segCount,\n }, notInstalledCount)),\n // 通知中心入口:整行控件最右侧、贴右对齐;有任何通知时右上角悬浮红圈白字计数;\n // 按钮文字用短文案(notificationsBtn),避免英文长标题挤占工具栏空间被截断\n h('button', {\n className: styles.failBtn,\n onClick: onOpenNotifications,\n title: t('notificationsHint'),\n 'aria-label': t('notificationsHint'),\n }, t('notificationsBtn'), noticeCount > 0 ? h('span', { className: styles.failBadge }, noticeCount) : null),\n ),\n )\n}\n","/**\n * Presentation formatters shared across the catalog list and the cards.\n */\nimport type { Translate } from '../types.ts'\n\n/** 星数/分支数的紧凑展示:<1k 原样;千级 1.2k;十万级取整。 */\nexport function fmtStars(count?: number): string {\n if (!count || count <= 0) return '0'\n if (count < 1000) return String(count)\n const k = count / 1000\n return `${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\\.0$/, '')}k`\n}\n\n/** 相对时间:今天 / N 天前 / N 个月前 / N 年前。 */\nexport function relTime(iso: string | undefined, t: Translate): string {\n if (!iso) return ''\n const days = Math.floor((Date.now() - new Date(iso).getTime()) / 86400000)\n if (days <= 0) return t('today')\n if (days < 30) return t('daysAgo', { days })\n if (days < 365) return t('monthsAgo', { months: Math.floor(days / 30) })\n return t('yearsAgo', { years: Math.floor(days / 365) })\n}\n","/**\n * One plugin card in the catalog list: name/category/verified badge,\n * description + topics, star/fork/date stats, and the detail/install/\n * uninstall actions.\n */\nimport { createElement as h } from 'react'\nimport styles from '../styles/List.module.css'\nimport type { HubPlugin, LocaleId, Translate } from '../types.ts'\nimport { CATEGORY_LABELS, categoryLabel, pluginDetailUrl } from '../lib/catalog.ts'\nimport { fmtStars, relTime } from '../lib/format.ts'\n\nexport function PluginCard({ plugin: p, copied, installedName, installedVersion, hasUpdate, t, langKey, langPath, onInstall, onUninstall }: {\n plugin: HubPlugin\n copied: string | null\n installedName: (p: HubPlugin) => string | null\n /** 已安装版本号(安装时从目录信号记录;无 release 的仓库为空,无版本号可展示) */\n installedVersion: (p: HubPlugin) => string | null\n /** 已安装且目录有更新(有版本比版本、无版本比仓库更新时间) */\n hasUpdate: (p: HubPlugin) => boolean\n t: Translate\n langKey: LocaleId\n langPath: string\n /** 第二个参数标记「更新」(已安装目标的覆盖安装):按钮/弹窗据此走更新语义 */\n onInstall: (p: HubPlugin, opts?: { update?: boolean }) => void\n onUninstall: (p: HubPlugin) => void\n}) {\n const repo = p.source?.repo ?? ''\n const isCopied = copied === repo\n const pkg = installedName(p)\n const isInstalled = pkg !== null\n const update = hasUpdate(p)\n // 版本号展示:已安装 → 当前已装版本(最能反映用户状态);未安装 → 目录最新版本\n const versionShown = isInstalled ? installedVersion(p) : p.version\n\n return h('div', { className: styles.card },\n h('div', { className: styles.cardMain },\n h('div', { className: styles.cardHead },\n h('div', { className: styles.cardTitle, title: p.description ?? '' }, p.displayName ?? p.slug),\n // 版本号紧跟插件名称:有版本才显示(无 release 的仓库不展示版本号)\n versionShown ? h('span', { className: styles.versionBadge, title: t('version') }, versionShown) : null,\n // 已安装且有更新:醒目提示(有 release 比版本号、无 release 比仓库最近更新时间)\n update ? h('span', { className: styles.updateBadge, title: t('updateAvailableHint') }, t('updateAvailable')) : null,\n p.category ? h('span', { className: styles.categoryBadge }, categoryLabel(CATEGORY_LABELS, p.category, langKey)) : null,\n p.compatibility?.status === 'verified'\n ? h('span', { className: styles.verified }, t('verified'))\n : null,\n ),\n // 描述始终显示:站点英文数据缺翻译时 description 回退成中文也照常展示,\n // 描述是了解插件的第一入口,比隐藏更实用(不再为求语言一致而砍内容)。\n p.description ? h('p', { className: styles.desc }, p.description) : null,\n (p.topics?.length ?? 0) > 0\n ? h('div', { className: styles.topics },\n p.topics!.slice(0, 3).map((topic) => h('span', { key: topic, className: styles.topic }, topic)),\n )\n : null,\n ),\n h('div', { className: styles.cardSide },\n h('div', { className: styles.stats },\n h('span', { className: styles.star }, '\\u2605 ', fmtStars(p.stats?.stargazers_count)),\n h('span', { className: styles.fork }, t('fork'), ' ', fmtStars(p.stats?.forks_count)),\n h('span', { className: styles.date }, relTime(p.dates?.repoUpdatedAt, t)),\n ),\n repo\n ? h('div', { className: styles.actions },\n // 查看详情:未安装/已安装都始终显示,跳转官网详情页\n h('a', {\n className: styles.detailBtn,\n // 两级路径:/plugins/{ownerSlug}/{slug};旧数据缺 ownerSlug 时从 repo 推导\n href: pluginDetailUrl(p, langPath),\n target: '_blank',\n rel: 'noopener noreferrer',\n title: p.slug,\n }, t('detail')),\n isInstalled\n // 已安装且有更新:按钮变「可更新」,点击直接覆盖安装(安装完成自动记录新版本)\n ? (update\n ? h('button', {\n className: styles.installBtnUpdate,\n title: t('updateAvailableHint'),\n onClick: () => onInstall(p, { update: true }),\n }, t('update'))\n : h('button', {\n className: styles.installBtnInstalled,\n disabled: true,\n title: t('installed'),\n }, t('installed')))\n : h('button', {\n className: isCopied ? styles.installBtnCopied : styles.installBtn,\n // 文字恒定避免按钮宽度变化导致卡片跳动;点击先弹信任确认,\n // 弹窗内可选择复制命令或直接安装\n onClick: () => onInstall(p),\n }, t('install')),\n isInstalled\n // 已安装:卸载按钮(危险色),保留明确状态语义\n ? h('button', {\n className: styles.uninstallBtn,\n onClick: () => onUninstall(p),\n }, t('uninstall'))\n : null,\n )\n : null,\n ),\n )\n}\n","/**\n * Catalog list: the scrollable container with the loading / failed / empty\n * states, the plugin cards, and the count footer. Resets scroll position when\n * the category or install-status filter changes so the replaced content is\n * not mistaken for a no-op update.\n */\nimport { createElement as h, useEffect, useRef } from 'react'\nimport styles from '../styles/List.module.css'\nimport type { HubPlugin, LocaleId, Translate } from '../types.ts'\nimport { SITE_URL } from '../lib/catalog.ts'\nimport { PluginCard } from './PluginCard.tsx'\n\nexport function CatalogList({ plugins, failed, visible, total, t, langPath, reload, category, installedFilter, copied, installedName, installedVersion, hasUpdate, langKey, onInstall, onUninstall }: {\n plugins: HubPlugin[] | null\n failed: boolean\n visible: HubPlugin[]\n total: number\n t: Translate\n langPath: string\n reload: () => void\n category: string\n installedFilter: 'all' | 'installed' | 'notInstalled'\n copied: string | null\n installedName: (p: HubPlugin) => string | null\n installedVersion: (p: HubPlugin) => string | null\n hasUpdate: (p: HubPlugin) => boolean\n langKey: LocaleId\n onInstall: (p: HubPlugin, opts?: { update?: boolean }) => void\n onUninstall: (p: HubPlugin) => void\n}) {\n /** 列表滚动容器:分类/搜索切换后列表内容替换但 scrollTop 保留,会让用户误以为列表没更新,需重置回顶部 */\n const listRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n listRef.current?.scrollTo({ top: 0 })\n }, [category, installedFilter])\n\n return h('div', { className: styles.body },\n h('div', { ref: listRef, className: styles.list },\n plugins === null && !failed && h('div', { className: styles.state }, t('loading')),\n failed && h('div', { className: styles.state },\n h('div', { className: styles.stateTitle }, t('failed')),\n h('div', { className: styles.stateDesc }, t('failedDesc')),\n h('button', { className: styles.retryBtn, onClick: () => reload() }, t('retry')),\n ),\n plugins !== null && !failed && visible.length === 0 && h('div', { className: styles.state },\n h('div', { className: styles.stateTitle }, t('noResult')),\n h('div', { className: styles.stateDesc }, t('noResultDesc')),\n ),\n plugins !== null && !failed && visible.map((p) => h(PluginCard, {\n // 唯一 key:数据重构后同一 slug 可能对应多个作者仓库,仅用 slug 会撞 key,\n // 导致切换分类时 React 复用旧 DOM、列表不刷新。\n key: p.ownerSlug ? `${p.ownerSlug}/${p.slug}` : p.slug,\n plugin: p,\n copied,\n installedName,\n installedVersion,\n hasUpdate,\n t,\n langKey,\n langPath,\n onInstall,\n onUninstall,\n })),\n ),\n plugins !== null && !failed && h('div', { className: styles.footer },\n h('a', {\n className: styles.footLink,\n href: `${SITE_URL}${langPath}`,\n target: '_blank',\n rel: 'noopener noreferrer',\n }, t('browseAll', { n: total })),\n ),\n )\n}\n","/**\n * Plugin Hub section: wires the catalog data pipeline, the background task\n * queue and the feedback state together. Data/queue logic lives in hooks/,\n * rendering is delegated to the small presentational components in this\n * folder; only the dialogs/toast and the section-level copy actions remain.\n */\nimport { createElement as h, useEffect, useState } from 'react'\nimport styles from '../styles/Header.module.css'\nimport { en, zh } from '../locales.ts'\nimport type { EnvInfo, HubPlugin, LocaleId, SectionProps, ToastState } from '../types.ts'\nimport { langPathOf, installCommandOf } from '../lib/catalog.ts'\nimport { getEnv } from '../lib/env.ts'\nimport { useCatalog } from '../hooks/useCatalog.ts'\nimport { useTaskQueue } from '../hooks/useTaskQueue.ts'\nimport { ErrorModal, InstallModal, UninstallModal, Toast } from './modals.tsx'\nimport { NotificationsModal } from './NotificationsModal.tsx'\nimport { addFailure, addSuccess, clearNotifications, loadNotifications, removeNotification } from '../lib/failures.ts'\nimport type { NotificationRecord } from '../lib/failures.ts'\nimport { CatalogHeader } from './CatalogHeader.tsx'\nimport { CategoryTabs } from './CategoryTabs.tsx'\nimport { CatalogControls } from './CatalogControls.tsx'\nimport { CatalogList } from './CatalogList.tsx'\n\nexport function PluginHubSection({ t: _hostT, locale }: SectionProps) {\n /** 界面语言:默认跟随宿主(系统)语言;右上角按钮可手动切换,切换后以手动选择为准 */\n const [manualLang, setManualLang] = useState<LocaleId | null>(null)\n const lang: LocaleId = manualLang ?? locale.getSnapshot().active\n const langKey: LocaleId = lang === 'en' ? 'en' : 'zh'\n // dsh-plugin.org keeps zh pages under the /zh/ prefix; en is the root.\n const langPath = langPathOf(lang)\n\n // 界面语言跟随宿主(系统)locale 自动切换;宿主的 t() 绑定宿主 locale,\n // 这里基于本地字典自建翻译函数,与宿主 locale 保持一致。\n // (settings.section 的导航 label 仍在 apply 里用宿主 t(),跟随宿主语言。)\n const dict: Record<string, string> = langKey === 'en' ? en : zh\n const t = (key: string, params?: Record<string, string | number>): string => {\n const raw = dict[key] ?? key\n return params ? raw.replace(/\\{(\\w+)\\}/g, (_, k) => String(params[k] ?? '')) : raw\n }\n\n const catalog = useCatalog(lang)\n\n /** 全局反馈 Toast:{id} 用于重复触发时重新走入场动画,kind 决定文案与配色 */\n const [toast, setToast] = useState<ToastState | null>(null)\n /** 复制反馈:记录刚复制安装命令的仓库,按钮短暂切换为「已复制」样式 */\n const [copied, setCopied] = useState<string | null>(null)\n /** 信任确认弹窗:记录待安装的插件,确认后才执行复制 */\n const [confirmPlugin, setConfirmPlugin] = useState<HubPlugin | null>(null)\n /** 弹窗动作是否为「更新」:已安装插件点「更新」→ 走同一条 add 命令原位覆盖重装,文案区分安装/更新 */\n const [confirmIsUpdate, setConfirmIsUpdate] = useState(false)\n /** 卸载确认弹窗:记录待卸载的插件 */\n const [uninstallPlugin, setUninstallPlugin] = useState<HubPlugin | null>(null)\n /** 安装/卸载完成后的结果视图:停留弹窗内,点「完成」关闭 */\n const [installDone, setInstallDone] = useState(false)\n const [uninstallDone, setUninstallDone] = useState(false)\n /** 结果视图「立即重启」:请求宿主重启后进入等待,服务回来后整页刷新 */\n const [restarting, setRestarting] = useState(false)\n /** 操作失败完整信息 + 所属插件仓库 + 失败类型(决定弹窗标题「安装失败/卸载失败」)+ 实际执行的安装命令 + 尝试过的安装方式(issue 预填用) */\n const [errorMsg, setErrorMsg] = useState<{ message: string; repo: string | null; kind: 'install' | 'uninstall'; command?: string; attempts?: string[] } | null>(null)\n /** 安装/卸载任务通知记录:localStorage 持久化,成败即落盘,即使错过弹窗也能回来查看 */\n const [notifications, setNotifications] = useState<NotificationRecord[]>(() => loadNotifications())\n const [showNotifications, setShowNotifications] = useState(false)\n /** 宿主机器环境快照:提交 bug 的 issue 正文附带;取不到为 null(链接少环境段,不阻塞) */\n const [env, setEnv] = useState<EnvInfo | null>(null)\n useEffect(() => {\n let alive = true\n void getEnv().then((info) => { if (alive) setEnv(info) })\n return () => { alive = false }\n }, [])\n\n const queue = useTaskQueue({\n t,\n refreshInstalled: catalog.refreshInstalled,\n onInstallDone: (viaModal, repo) => {\n if (viaModal) setInstallDone(true)\n else setToast({ id: Date.now(), kind: 'done' })\n // 安装成功也写入通知记录:通知中心里成功与失败都能看到\n setNotifications(addSuccess({ kind: 'install', repo: repo ?? '' }))\n },\n onUninstallDone: (viaModal, repo) => {\n if (viaModal) setUninstallDone(true)\n else setToast({ id: Date.now(), kind: 'removed' })\n setNotifications(addSuccess({ kind: 'uninstall', repo: repo ?? '' }))\n },\n onError: (message, repo, kind, command, attempts) => {\n setErrorMsg({ message, repo, kind, command, attempts })\n // 失败自动写入通知记录:任务在后台结束时没人盯着也能留痕\n setNotifications(addFailure({ kind, repo: repo ?? '', message, command, attempts }))\n },\n installPlugin: confirmPlugin,\n uninstallPlugin,\n installedName: catalog.installedName,\n // 待重启项展示信息补齐:从目录按 owner/repo 解析插件简介/版本(找不到返回 null,行内只显示仓库名)\n resolvePending: (repo) => {\n const p = catalog.plugins?.find((x) => x.source?.repo === repo)\n return p ? { desc: p.description, version: p.version } : null\n },\n })\n\n // 信任/卸载/通知记录弹窗打开时按 Esc 关闭;任务进入后台队列后可随时关闭(任务继续)\n useEffect(() => {\n if (!confirmPlugin && !uninstallPlugin && !showNotifications) return\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setConfirmPlugin(null)\n setUninstallPlugin(null)\n setUninstallDone(false)\n setShowNotifications(false)\n }\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [confirmPlugin, uninstallPlugin, showNotifications])\n\n // Toast 统一自动消失\n useEffect(() => {\n if (!toast) return\n const timer = window.setTimeout(() => setToast(null), 2400)\n return () => window.clearTimeout(timer)\n }, [toast])\n\n /** 复制文本到剪贴板,返回是否成功(Clipboard API + 隐藏 textarea 兜底)。 */\n const doCopy = async (text: string): Promise<boolean> => {\n try {\n await navigator.clipboard.writeText(text)\n return true\n } catch {\n // Clipboard API unavailable (permissions/iframe) — fall back to the\n // legacy hidden-textarea trick, which works in any context.\n const ta = document.createElement('textarea')\n ta.value = text\n ta.style.position = 'fixed'\n ta.style.opacity = '0'\n document.body.appendChild(ta)\n ta.select()\n let ok = false\n try {\n ok = document.execCommand('copy')\n } catch {\n ok = false\n }\n document.body.removeChild(ta)\n return ok\n }\n }\n\n /** 弹窗动作一:复制安装命令到剪贴板,引导去终端粘贴执行(npm 通道显示包名命令)。 */\n const copyCommand = async (p: HubPlugin) => {\n const repo = p.source?.repo ?? ''\n const ok = await doCopy(installCommandOf(p))\n if (ok) {\n setCopied(repo)\n setToast({ id: Date.now(), kind: 'copied' })\n window.setTimeout(() => setCopied((cur) => (cur === repo ? null : cur)), 1600)\n }\n setConfirmPlugin(null)\n }\n\n /** 卸载弹窗动作:复制卸载命令,万一直接卸载失败可去终端手动执行。 */\n const copyUninstallCommand = async () => {\n const name = uninstallPlugin ? catalog.installedName(uninstallPlugin) : null\n if (!name) return\n const ok = await doCopy(`dsh plugin remove ${name}`)\n if (ok) setToast({ id: Date.now(), kind: 'copied' })\n }\n\n /** 「立即重启」:POST 同源 /restart,宿主进程自杀重启;随后轮询服务恢复后整页刷新。 */\n const requestRestart = async () => {\n if (restarting) return\n setRestarting(true)\n try {\n // 响应可能在宿主进程被 kill 前返回,也可能直接断连 —— 两种都属正常\n await fetch('/dsh-plugin-hub/restart', { method: 'POST' })\n } catch {\n /* 服务已终止,无需处理 */\n }\n // 轮询同源端点,服务恢复后整页 reload(让新挂载的 bundle 完全初始化)\n let attempts = 0\n const poll = async () => {\n attempts += 1\n try {\n const res = await fetch('/dsh-plugin-hub/active', { method: 'GET', cache: 'no-store' })\n if (res.ok) {\n window.location.reload()\n return\n }\n } catch {\n /* 服务尚未恢复 */\n }\n if (attempts < 60) {\n window.setTimeout(poll, 1000)\n } else {\n setRestarting(false)\n setToast({ id: Date.now(), kind: 'fail' })\n }\n }\n window.setTimeout(poll, 1200)\n }\n\n const { total, installedName, installedVersion, hasUpdate } = catalog\n // 统计数字:官网 /api/stats.json 优先;拉取失败时用已加载列表兜底,避免展示 undefined。\n const statsTotal = catalog.stats?.total ?? total\n const statsVerified = catalog.stats?.verified ?? 0\n\n const count = catalog.visible.length\n\n return h('div', { className: styles.root },\n h(CatalogHeader, {\n t,\n langPath,\n statsTotal,\n statsVerified,\n onToggleLang: () => setManualLang(lang === 'en' ? 'zh' : 'en'),\n }),\n h(CategoryTabs, {\n category: catalog.category,\n setCategory: catalog.setCategory,\n allLabel: t('all'),\n totalCount: catalog.total,\n langKey,\n }),\n h(CatalogControls, {\n query: catalog.query,\n setQuery: catalog.setQuery,\n sort: catalog.sort,\n setSort: catalog.setSort,\n installedFilter: catalog.installedFilter,\n setInstalledFilter: catalog.setInstalledFilter,\n // 已安装/未安装按钮计数跟随当前分类:切到某分类即显示该分类下的已装/未装数量\n installedCount: catalog.installedCountInCategory,\n notInstalledCount: catalog.notInstalledCountInCategory,\n t,\n // 列表头部「筛选出 N 条」:分类/搜索/安装状态筛选后的结果数;全部视图且未筛选时显示总数\n resultText: catalog.plugins === null || catalog.failed\n ? null\n : catalog.category === 'all' && count === total\n ? t('pluginsTotal', { n: count })\n : t('filterResults', { n: count }),\n // 通知入口计数:历史通知记录数 + 进行中任务数 + 待重启数 ——\n // 待重启不可清除,装完等重启时必须持续亮着提示「必须重启」,不能因为队列空了就归零\n // 红圈白字数字(进行中的任务见通知中心「进行中」分区,待重启见「待重启」分区)\n noticeCount: notifications.length + queue.queue.length + queue.pendingRestarts.length,\n onOpenNotifications: () => setShowNotifications(true),\n }),\n h(CatalogList, {\n plugins: catalog.plugins,\n failed: catalog.failed,\n visible: catalog.visible,\n total,\n t,\n langPath,\n reload: catalog.reload,\n category: catalog.category,\n installedFilter: catalog.installedFilter,\n copied,\n installedName,\n installedVersion,\n hasUpdate,\n langKey,\n onInstall: (p, opts) => {\n setInstallDone(false)\n setConfirmIsUpdate(opts?.update ?? false)\n // 与卸载一致:重置弹窗关联任务,避免新弹窗误匹配到进行中的任务而禁用安装按钮\n queue.clearModalTask()\n setConfirmPlugin(p)\n },\n onUninstall: (p) => {\n setUninstallDone(false)\n queue.clearModalTask()\n setUninstallPlugin(p)\n },\n }),\n // 安装确认弹窗:锁定/进度/结果视图逻辑收敛在 modals.tsx;更新与安装同入口,仅标记 update\n confirmPlugin && h(InstallModal, {\n plugin: confirmPlugin,\n done: installDone,\n task: queue.installModalTask,\n t,\n langPath,\n restarting,\n update: confirmIsUpdate,\n submitting: queue.submitting,\n onClose: () => setConfirmPlugin(null),\n onCopy: () => copyCommand(confirmPlugin),\n onInstall: () => queue.installNow(confirmPlugin, confirmIsUpdate ? { update: true } : undefined),\n onRestart: () => { void requestRestart() },\n }),\n // 卸载确认弹窗:确认/进度/结果视图逻辑收敛在 modals.tsx\n uninstallPlugin && h(UninstallModal, {\n plugin: uninstallPlugin,\n done: uninstallDone,\n task: queue.uninstallModalTask,\n t,\n langPath,\n restarting,\n submitting: queue.submitting,\n onClose: () => {\n setUninstallDone(false)\n setUninstallPlugin(null)\n },\n onCancel: () => setUninstallPlugin(null),\n onCopyCommand: copyUninstallCommand,\n onConfirm: () => queue.uninstallNow(uninstallPlugin),\n onRestart: () => { void requestRestart() },\n }),\n toast && h(Toast, { toast, t }),\n // 操作失败:完整错误弹窗(重复安装、CLI 失败、请求错误等),可复制并去插件仓库反馈\n errorMsg && h(ErrorModal, {\n message: errorMsg.message,\n repo: errorMsg.repo,\n kind: errorMsg.kind,\n command: errorMsg.command,\n attempts: errorMsg.attempts,\n t,\n env,\n onCopy: (text: string) => {\n doCopy(text)\n setToast({ id: Date.now(), kind: 'errCopied' })\n },\n onClose: () => setErrorMsg(null),\n }),\n // 安装/卸载任务通知记录:本地持久化的成败清单,随时可回来查看/复制/清空;\n // 进行中的任务(实时进度)与待重启插件也一并展示,关掉任务弹窗后仍可盯着\n showNotifications && h(NotificationsModal, {\n records: notifications,\n tasks: queue.queue,\n pendingRestarts: queue.pendingRestarts,\n t,\n env,\n onClose: () => setShowNotifications(false),\n onCopy: (text) => {\n doCopy(text)\n setToast({ id: Date.now(), kind: 'errCopied' })\n },\n onClear: () => setNotifications(clearNotifications()),\n onRemove: (id: number) => setNotifications(removeNotification(id)),\n cancelTask: queue.cancelTask,\n restarting,\n onRestart: () => { void requestRestart() },\n }),\n )\n}\n","/**\n * dsh-plugin client entry: wires the Plugin Hub into the host settings via\n * the module-loader bundle (see tsdown.config.ts). All UI logic lives in\n * PluginHubSection; this file only performs the cordis apply wiring.\n */\nimport { createElement as h } from 'react'\nimport type { HubClientContext } from './types.ts'\nimport { en, zh } from './locales.ts'\nimport { PluginHubSection } from './components/PluginHubSection.tsx'\nimport './styles/tokens.module.css'\n\nconst NS = 'dsh-plugin'\n\nexport const name = NS\nexport const inject = ['slots', 'locale']\n\nexport function apply(ctx: HubClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), `${NS}: dictionaries`)\n const t = ctx.locale.bind(NS)\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: NS,\n order: 60,\n label: () => t('nav'),\n locale: NS,\n inject: () => ({ t, locale: ctx.locale }),\n }, () => h(PluginHubSection, { t, locale: ctx.locale })))\n}\n"],"mappings":"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"}