@linxin666/dsh-client-ui-community-plugins 0.2.7 → 0.2.8

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.
package/lib/client.js CHANGED
@@ -783,14 +783,25 @@ window.__ModuleLoader__.load({
783
783
  "npm": "dsh-mnemon",
784
784
  "category": "knowledge"
785
785
  },
786
+ {
787
+ "id": "dsh-plugin-hub",
788
+ "name": "插件中心(dsh-plugin-hub)",
789
+ "nameEn": "Plugin Hub",
790
+ "author": "Noob-stupid",
791
+ "repo": "https://github.com/Noob-stupid/dsh-plugin-hub",
792
+ "description": "插件管理面板:已安装插件一键启用/停用,内置 GitHub dsh-plugin 插件市场(官方/聚合识别、子包浏览、一键安装与本地 AI 兜底修复、删除卸载),版本检测与一键更新、框架一键升级。",
793
+ "descriptionEn": "Plugin management panel: one-click enable/disable, a GitHub dsh-plugin marketplace with official/aggregate detection, subpackage browsing, one-click installs with local-AI fallback repair, uninstall, update detection and one-click framework upgrade.",
794
+ "npm": "@noob-stupid/dsh-plugin-console",
795
+ "category": "tools"
796
+ },
786
797
  {
787
798
  "id": "dsh-genui",
788
799
  "name": "GenUI 生成式 UI",
789
800
  "nameEn": "GenUI",
790
801
  "author": "omdsh-dev",
791
802
  "repo": "https://github.com/omdsh-dev/dsh-genui",
792
- "description": "给模型输出配交互式 UI:助手回复内联渲染 dsh-ui fence(布局、图表、表单、Mermaid、3D),支持流式渲染与面板停靠,组件交互可回传模型。",
793
- "descriptionEn": "Interactive UI inside assistant replies via the dsh-ui fence: layouts, charts, forms, Mermaid and 3D with streaming rendering, panel docking and actions that loop back to the model.",
803
+ "description": "给模型输出配交互式 UI:助手回复内联渲染 dsh-ui 围栏(布局、图表、表格、表单、Mermaid、3D、原生音视频),双通道渲染兼容原版 DSH 与新构建,支持流式渲染、面板停靠与组件交互回传模型。",
804
+ "descriptionEn": "Interactive UI inside assistant replies via the dsh-ui fence: layouts, charts, tables, forms, quizzes, Mermaid, 3D and native audio/video. Dual-channel rendering covers stock DSH and newer builds, with streaming render, panel docking and component actions that loop back to the model.",
794
805
  "category": "ui"
795
806
  },
796
807
  {
@@ -799,8 +810,8 @@ window.__ModuleLoader__.load({
799
810
  "nameEn": "Selection Annotation",
800
811
  "author": "omdsh-dev",
801
812
  "repo": "https://github.com/omdsh-dev/dsh-annotation",
802
- "description": "选中助手文字即可批注,回车随消息发送;自己的气泡只显示问题与「批注 ×N」标签,模型按 Annotation N 逐条对照回复(悬浮芯片)。",
803
- "descriptionEn": "Select text in an assistant reply to annotate it; annotations are sent with your next message, hidden from your own bubble behind an Annotations xN chip, and the model replies per Annotation N with hoverable chips.",
813
+ "description": "选中助手文字即可批注,回车随消息发送;自己的气泡只显示问题与「批注 ×N」标签,模型按 Annotation N 逐条对照回复(悬浮芯片);UI 与批注块跟随 DSH 语言切换 zh/en,Cmd/Ctrl+Enter 可直发纯批注,斜杠命令原样放行。",
814
+ "descriptionEn": "Select text in an assistant reply to annotate it; annotations ride along with your next message, hidden in your own bubble behind an Annotations xN chip, and the model replies per Annotation N with hoverable chips. UI and annotation block follow the DSH locale (zh/en); Cmd/Ctrl+Enter sends annotations alone; slash commands pass through.",
804
815
  "category": "ui"
805
816
  },
806
817
  {
@@ -1037,16 +1048,6 @@ window.__ModuleLoader__.load({
1037
1048
  "descriptionEn": "Claim verification for AI coding agents: enumerate every verifiable claim in design docs and refactoring plans, verify against codebase facts, then escalate behavioral claims to logic-primitive verification (7 structural checks + 7 adversarial probes), with before/after model comparison for refactoring regression detection.",
1038
1049
  "category": "tools"
1039
1050
  },
1040
- {
1041
- "id": "dsh-session-delete",
1042
- "name": "会话删除",
1043
- "nameEn": "Session Delete",
1044
- "author": "xohmai",
1045
- "repo": "https://github.com/xohmai/dsh-session-delete",
1046
- "description": "真正删除会话磁盘日志:归档清理、批量删除、回收站还原;官方归档只隐藏不删盘。",
1047
- "descriptionEn": "Real session deletion with trash and restore, archived cleanup and batch delete. Official archive only hides sessions.",
1048
- "category": "utility"
1049
- },
1050
1051
  {
1051
1052
  "id": "dsh-chatgpt-subscription",
1052
1053
  "name": "子代理管理",
@@ -1057,6 +1058,17 @@ window.__ModuleLoader__.load({
1057
1058
  "descriptionEn": "Use GPT models in DSH through your ChatGPT subscription: PKCE OAuth login, DPAPI/keychain/0600 credential storage, streaming Responses, image generation, Codex search, quota display and subagent management.",
1058
1059
  "npm": "@eddyskywalker/dsh-chatgpt-subscription",
1059
1060
  "category": "integration"
1061
+ },
1062
+ {
1063
+ "id": "dsh-imagegen",
1064
+ "name": "AI 生图",
1065
+ "nameEn": "AI ImageGen",
1066
+ "author": "dickpy",
1067
+ "repo": "https://github.com/dickpy/dsh-imagegen",
1068
+ "description": "AI 生图插件:通过可配置的 OpenAI 兼容端点(gpt-image-2 / gpt-image-1 / dall-e-3)实现文生图与图生图,提供生成历史、提示词模板库与 API 设置卡片。",
1069
+ "descriptionEn": "AI image generation for the DSH Web GUI: text-to-image and image-to-image through a configurable OpenAI-compatible endpoint (gpt-image-2 / gpt-image-1 / dall-e-3), with generation history, a prompt template library and an API settings card.",
1070
+ "npm": "@dickpy/dsh-imagegen",
1071
+ "category": "tools"
1060
1072
  }
1061
1073
  ];
1062
1074
  //#endregion
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["css","css","Modal","Button"],"sources":["../../../packages/dsh-community-plugins/src/client/PluginSettingsCard.tsx","../../../packages/dsh-community-plugins/src/client/settings-form.ts","../../../packages/dsh-community-plugins/src/client/generated/community.ts","../../../packages/dsh-community-plugins/src/client/community-guard.ts","../../../packages/dsh-community-plugins/src/client/plugin-manager-bridge.ts","../../../packages/dsh-community-plugins/src/client/install-source.ts","../../../packages/dsh-community-plugins/src/client/CommunityPluginsCard.tsx","../../../packages/dsh-community-plugins/src/client/locales.ts","../../../packages/dsh-community-plugins/src/client/index.ts"],"sourcesContent":["// Generated by scripts/sync-shared.mjs from shared/client/settings/PluginSettingsCard.tsx. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family-shared chrome for plugin settings cards: a disclosure header naming\n * the plugin and what its settings govern, the controls inside, and the save\n * that writes them. Renders nothing while the namespace is unavailable — a\n * deployment that does not compose the owning plugin should show no trace of\n * it. Inlined into each consumer's client bundle; mirrors the official\n * ui-plugin-config PluginCard in a self-contained slice.\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'\nimport type { CardShell } from './settings-form.ts'\nimport css from './settings-card.module.css'\n\n/** Copy keys the card chrome itself reads; every consumer locale carries this shared vocabulary. */\nexport const CARD_COPY_KEYS = [\n 'settings.collapse',\n 'settings.expand',\n 'settings.notExposed',\n 'settings.unsaved',\n 'settings.readOnly',\n 'settings.saveFailed',\n 'settings.discard',\n 'settings.save',\n 'settings.saving',\n] as const\n\n/** Copy key the card chrome itself reads. */\nexport type CardCopyKey = (typeof CARD_COPY_KEYS)[number]\n\n/** Key domain for the plugin's own copy (inferred per consumer). */\nexport type SettingsCardKey<TKey extends string = string> = TKey | CardCopyKey\n\n/** Card chrome shared by every plugin settings card. */\nexport interface PluginSettingsCardProps<TKey extends string = string> {\n /** Locale reader for this card's copy. */\n t: (key: SettingsCardKey<TKey>, params?: Record<string, string | number>) => string\n /** Locale key of the plugin's name. */\n titleKey: TKey\n /** Locale key of the line describing what this plugin's settings govern. */\n descriptionKey: TKey\n /** The card's form state: availability, writability, and what a save would do. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /**\n * Render the controls expanded on arrival (still collapsible). Defaults to\n * true: promoted first-level sections show their settings immediately.\n */\n defaultOpen?: boolean\n /**\n * Render without the collapse affordance: a static header and an always\n * visible body. Used by first-level settings sections whose nav entry\n * already provides the selection.\n */\n alwaysOpen?: boolean\n /**\n * Hide the save/discard footer: cards whose body applies its own changes\n * immediately (an embedded external settings section) have no staged\n * edits, so the footer would sit there permanently disabled.\n */\n hideFooter?: boolean\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin settings card.\n * @param props - the plugin's copy keys, its form state, and its controls.\n * @returns the card, or nothing while the namespace is still loading.\n */\nexport function PluginSettingsCard<TKey extends string = string>(props: PluginSettingsCardProps<TKey>) {\n const [open, setOpen] = useState(props.defaultOpen ?? true)\n const { state, alwaysOpen } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const description = props.t(props.descriptionKey)\n const blocked = !state.dirty || state.invalid || state.saving\n const expanded = alwaysOpen === true || open\n const cardClass = expanded ? `${css.cardOpen} ${css.card}` : css.card\n // With alwaysOpen the nav entry already provides the selection, so the\n // header is a static title row instead of a disclosure button.\n const header = alwaysOpen === true\n ? (\n <div className={css.headerStatic}>\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n </div>\n )\n : (\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron}\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n )\n // The namespace exists but the Host does not serve it to this client (the\n // official settings allowlist omits third-party namespaces): show a card\n // that explains the gap instead of vanishing, so a missing card never\n // reads as a missing plugin.\n if (!state.exposed) {\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p>\n </div>\n )\n : null}\n </li>\n )\n }\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('settings.readOnly')}</p> : null}\n {props.children}\n {props.hideFooter === true\n ? null\n : (\n <div className={css.footer}>\n {state.failed\n ? (\n <p className={css.failed} role=\"status\">\n {props.t('settings.saveFailed')}{state.failedReason ? ' - ' + state.failedReason : ''}\n </p>\n )\n : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('settings.discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(!state.saving ? 'settings.save' : 'settings.saving')}\n </button>\n </div>\n )}\n </div>\n )\n : null}\n </li>\n )\n}\n\n/** Props every field control needs regardless of its value type. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation rendered under the control. */\n hint: string\n /** Draft text this control renders. */\n text: string\n /** True when saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** True when the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control (read-only document, or an unavailable namespace). */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing what the control accepts. */\n numeric?: boolean\n /** Placeholder shown while the draft is empty. */\n placeholder?: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\nconst NON_SKIN_BODY_MARKERS = new Set(['dshSkinCenter', 'dshSidebarCollapsed'])\n// 检测使用使用皮肤,用了皮肤退回原生select样式,防止样式冲突。默认外观下使用优化后的select样式。\nfunction isSkinActive(): boolean {\n const datasetList = Object.keys(document.body.dataset)\n const isActive = datasetList.some(key => key.startsWith('dsh') && !NON_SKIN_BODY_MARKERS.has(key))\n return isActive\n}\n\ninterface SelectOption {\n value: string\n label: string\n}\n\nconst SELECT_CLOSE_MS = 100\n\n/**\n * The shared dual-mode select control. While an appearance skin is active it\n * renders the legacy native `<select>` untouched, so element-level skin\n * selectors keep working; under the default appearance it renders a\n * self-drawn `role=\"listbox\"` popup whose open/close is transition-animated.\n * Staged cards reach it through BooleanField/ChoiceField; immediate-apply\n * editors (the side-card prefs) bind it directly through onEdit.\n * 双模式下拉框:皮肤激活时用原生 select,默认外观用自绘动画弹层。\n */\nexport function SelectField(props: {\n id: string\n options: ReadonlyArray<SelectOption>\n value: string\n disabled: boolean\n invalid: boolean\n onEdit: (text: string) => void\n}) {\n const { id, options, value } = props\n const [open, setOpen] = useState(false)\n const [closing, setClosing] = useState(false)\n const [phase, setPhase] = useState<'initial' | 'open'>('initial')\n const [activeIndex, setActiveIndex] = useState(0)\n const closeTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const popupRef = useRef<HTMLDivElement | null>(null)\n\n const currentIndex = () => {\n const index = options.findIndex(option => option.value === value)\n return index >= 0 ? index : 0\n }\n\n const close = useCallback(() => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setClosing(true)\n closeTimer.current = setTimeout(() => {\n setClosing(false)\n setOpen(false)\n }, SELECT_CLOSE_MS)\n }, [])\n\n const openPopup = () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setActiveIndex(currentIndex())\n setPhase('initial')\n setClosing(false)\n setOpen(true)\n }\n\n const commit = (index: number) => {\n const option = options[index]\n if (option) props.onEdit(option.value)\n close()\n }\n\n const onTriggerClick = () => {\n if (props.disabled) return\n if (open && !closing) close()\n else openPopup()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (props.disabled) return\n const count = options.length\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp':\n case 'Enter':\n case ' ':\n event.preventDefault()\n if (!open) {\n openPopup()\n } else if (!closing) {\n if (event.key === 'ArrowDown') setActiveIndex(index => (index + 1) % count)\n else if (event.key === 'ArrowUp') setActiveIndex(index => (index - 1 + count) % count)\n else commit(activeIndex)\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation()\n close()\n }\n break\n case 'Tab':\n if (open) close()\n break\n }\n }\n\n useEffect(() => () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n }, [])\n useLayoutEffect(() => {\n if (open && !closing && phase === 'initial') {\n void popupRef.current?.offsetHeight\n setPhase('open')\n }\n }, [open, closing, phase])\n\n useEffect(() => {\n if (!open) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target\n if (target instanceof Node && !wrapRef.current?.contains(target)) close()\n }\n document.addEventListener('pointerdown', onPointerDown)\n return () => document.removeEventListener('pointerdown', onPointerDown)\n }, [open, close])\n\n useEffect(() => {\n if (props.disabled && open) close()\n }, [props.disabled, open, close])\n\n // 使用了皮肤则退回原生select样式防止样式冲突。\n if (isSkinActive()) {\n return (\n <select\n id={id}\n className={css.select}\n value={value}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n {options.map(option => (\n <option key={option.value} value={option.value}>{option.label}</option>\n ))}\n </select>\n )\n }\n\n const label = options.find(option => option.value === value)?.label ?? ''\n const popupClass = closing\n ? `${css.selectPopup} ${css.selectPopupClose}`\n : phase === 'open'\n ? `${css.selectPopup} ${css.selectPopupOpen}`\n : css.selectPopup\n return (\n <div className={css.selectWrap} ref={wrapRef}>\n <button\n type=\"button\"\n id={id}\n className={`${css.select} ${css.selectButton}`}\n disabled={props.disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-activedescendant={open ? `${id}-o${activeIndex}` : undefined}\n aria-invalid={props.invalid || undefined}\n onClick={onTriggerClick}\n onKeyDown={onKeyDown}\n >\n <span className={css.selectLabel}>{label}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.selectChevron} ${css.selectChevronOpen}` : css.selectChevron}\n aria-hidden=\"true\"\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n {open\n ? (\n <div className={popupClass} role=\"listbox\" ref={popupRef}>\n {options.map((option, index) => (\n <div\n key={option.value}\n id={`${id}-o${index}`}\n role=\"option\"\n aria-selected={option.value === value}\n className={`${css.selectOption}${option.value === value ? ` ${css.selectOptionSelected}` : ''}${index === activeIndex && !closing ? ` ${css.selectOptionActive}` : ''}`}\n onClick={() => { commit(index) }}\n >\n {option.label}\n </div>\n ))}\n </div>\n )\n : null}\n </div>\n )\n}\n\n/** A staged boolean field: 继承 / 开 / 关. */\nexport function BooleanField(props: FieldProps & {\n /** Copy for the inherit option. */\n inheritLabel: string\n /** Copy for the on option. */\n onLabel: string\n /** Copy for the off option. */\n offLabel: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[\n { value: '', label: props.inheritLabel },\n { value: 'true', label: props.onLabel },\n { value: 'false', label: props.offLabel },\n ]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n\n/** A staged enumerated field rendered as a select. */\nexport function ChoiceField(props: FieldProps & {\n /** Copy for the inherit option (draft text is the empty string). */\n inheritLabel: string\n /** Choices rendered in order; `value` is the draft/stored text. */\n choices: ReadonlyArray<{ value: string; label: string }>\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[{ value: '', label: props.inheritLabel }, ...props.choices]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/settings-form.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Staged form model behind the plugin settings card. A card stages what the\n * user types and writes it only when they save — the settings write is a\n * durable, revision-fenced document mutation, so staging keeps what is on\n * screen exactly what a save would store. Family-shared slice inlined into\n * each plugin's client bundle; mirrors the official ui-plugin-config\n * card-store pattern.\n */\n\nimport type { SettingsScope, SettingsScopeSnapshot, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** How one field converts between its stored value and its draft text. */\nexport interface FieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /**\n * Whether the Host treats this field as a secret and redacts its value from\n * the read-back (role('secret') in the section schema). Redacted secrets are\n * never compared against the draft on save; the field lands when the scope\n * reports the write succeeded (its secret-set marker under the bridge), so\n * a successful secret save is not misreported as failed.\n */\n secret?: boolean\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/** One field as the card renders it. */\nexport interface FieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean\n}\n\n/** Form state every plugin settings card shares. */\nexport interface CardShell {\n /** False while the namespace is still loading; the card renders nothing. */\n available: boolean\n /**\n * Whether the namespace is actually served to this client. False when the\n * Host deployment does not expose it (e.g. the official apiproxy settings\n * allowlist omits third-party namespaces): the card renders an explanation\n * instead of its form, so a missing namespace never looks like a missing\n * plugin.\n */\n exposed: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits that a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean\n /**\n * The rejection code/message the Host returned for the last failed save,\n * surfaced next to the generic failure text. Undefined while no save has\n * failed (or the failure carried no server reason).\n */\n failedReason?: string\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean\n}\n\n/** One staged edit resolved into the write a save performs. */\ninterface PlannedWrite {\n /** Field this entry writes. */\n field: string\n /** The durable write this entry performs, described for a batched scope. */\n op: BatchedWrite\n /** Perform the write and report whether the Host holds the staged value afterwards. */\n run: (() => Promise<boolean>) | undefined\n}\n\n/** One durable write a batched settings scope performs. */\nexport interface BatchedWrite {\n /** Field this entry writes. */\n field: string\n /** set stores a value; unset drops the leaf. */\n op: 'set' | 'unset'\n /** Value for op set (absent for unset). */\n value?: unknown\n}\n\n/** Per-field outcome of one batched scope write. */\nexport interface BatchedFieldResult {\n /** Field this entry writes. */\n field: string\n /** Whether the Host accepted this field's write (per the read-back view). */\n landed: boolean\n}\n\n/**\n * Result of a batched scope write. The bridge scope posts every planned write\n * in one /mutate so the Host validate hook judges baseURL+model together; a\n * batched refusal fails the whole save rather than per-field.\n */\nexport interface BatchResult {\n /** Whether the whole mutate was accepted. */\n ok: boolean\n /** Per-field success, in the request order (always present when ok). */\n fields: BatchedFieldResult[]\n /** Host rejection code (mutate refused). */\n code?: string\n /** Host rejection message (mutate refused). */\n message?: string\n}\n\n/** The optional batch surface the bridge scope adds over the SettingsScope contract. */\ninterface BatchedSettingsScope {\n /** Write every operation in one scope mutation, reporting per-field success. */\n mutate: (writes: BatchedWrite[]) => Promise<BatchResult>\n}\n\n/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */\nexport interface NumberConstraints {\n /** The accepted value must be a whole number. */\n integer?: boolean\n /** The accepted value must be at least this. */\n min?: number\n}\n\n/** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */\nexport function numberField(field: string, constraints: NumberConstraints = {}): FieldSpec {\n const { integer = false, min } = constraints\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return undefined\n if (integer && !Number.isInteger(parsed)) return undefined\n if (min !== undefined && parsed < min) return undefined\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/** A free-text field. An empty draft clears the field. */\nexport function textField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A free-text field the Host treats as a secret and redacts from the read-back\n * (role('secret') in the section schema). The card still edits it like text,\n * but a save never compares the redacted value back and relies on the scope\n * reporting the write landed.\n */\nexport function secretField(field: string): FieldSpec {\n return { ...textField(field), secret: true }\n}\n\n/** A boolean field, edited through true/false draft text. */\nexport function booleanField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'boolean' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return undefined\n },\n }\n}\n\n/** An enumerated string field; only the listed choices are accepted. An empty draft clears the field. */\nexport function choiceField(field: string, choices: readonly string[]): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' && choices.includes(value) ? value : '',\n parse: (text) => {\n if (text === '') return { kind: 'clear' }\n return choices.includes(text) ? { kind: 'set', value: text } : undefined\n },\n }\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted — its\n * validators own the constraints no schema can express — so the outcome is\n * read back from the section rather than predicted here. A save that did not\n * land keeps its drafts, so the user can correct them instead of retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, FieldSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n /** The scope subscription installed in the constructor; released by dispose(). */\n private readonly disposeScope: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound settings scope for this card's namespace. */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeScope = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the scope subscription and every bound store listener. The card\n * must call this on teardown; later calls are no-ops.\n */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.disposeScope()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status !== 'loading',\n exposed: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n ...this.failedReason === undefined ? {} : { failedReason: this.failedReason },\n }\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): FieldState {\n const spec = this.specOf(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.failedReason = undefined\n this.publish()\n },\n }\n }\n\n /**\n * Write every staged edit, then re-seed from what the Host accepted.\n *\n * When the scope carries the optional batch surface (the dsh-web-ui\n * bridge scope), every planned write rides one mutation so cross-field\n * validate hooks (baseURL+model) judge the batch as a unit instead of\n * deadlocking on per-field writes. Otherwise the per-field loop runs.\n * A field lands only when the Host reports it held the staged value; a\n * landed field's draft is dropped, a failed one stays staged for the user.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter(item => item.run !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n const plannedWrites = valid.map(item => item.op)\n // Snapshot the staged entries this save writes, so an edit staged while it\n // is in flight (which replaces the same key) survives: only delete the key\n // when the entry is still the one this save started from.\n const pending = new Map<string, StagedEdit | undefined>()\n for (const item of plan) pending.set(item.field, this.staged.get(item.field))\n this.saving = true\n this.failed = false\n this.failedReason = undefined\n this.publish()\n const landed = new Set<string>()\n const batch = this.batchedScope()\n if (batch !== undefined) {\n const result = await batch.mutate(plannedWrites)\n if (result.ok) {\n for (const field of result.fields) {\n if (field.landed) landed.add(field.field)\n }\n } else {\n this.failedReason = result.message\n }\n } else {\n for (const item of valid) {\n if (await item.run!()) landed.add(item.field)\n }\n }\n for (const [field, before] of pending) {\n if (landed.has(field) && this.staged.get(field) === before) this.staged.delete(field)\n }\n this.saving = false\n this.failed = landed.size !== pending.size\n this.publish()\n }\n\n /** The scope's batch surface when it supports one; undefined conservatively otherwise. */\n private batchedScope(): BatchedSettingsScope | undefined {\n const candidate = this.scope as unknown as BatchedSettingsScope | undefined\n return typeof candidate?.mutate === 'function' ? candidate : undefined\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n * @returns the planned writes, in the order the fields were staged.\n */\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, op: { field, op: 'unset' }, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n // A redacted secret never appears in the user layer read-back; judging it\n // by value would misreport a successful secret save as failed. The bridge\n // reports secret writes through its secret-set markers (batch path); on\n // the per-field path the scope resolved, so the write is landed.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.failedReason = undefined\n this.publish()\n }\n\n private specOf(field: string): FieldSpec {\n const spec = this.specs.get(field)\n // Every call site names a field this card declared; a missing one is a\n // wiring mistake that must not degrade into a silently inert control.\n if (spec === undefined) throw new Error(`settings card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): SettingsScopeSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * AUTO-GENERATED by scripts/community-index — do not edit by hand.\n * Community plugin index for the settings page: every entry links to the\n * contributor's own repository. This repository never vendors the listed\n * plugins — it only points users at them.\n * Regenerate with `node scripts/community-index`.\n */\n\n/** Stable category ids rendered as marketplace-style filter pills (the runtime guard imports this). */\nexport const COMMUNITY_CATEGORIES = ['ui', 'agent', 'tools', 'knowledge', 'integration', 'security', 'utility'] as const\n\n/** One category id. */\nexport type CommunityPluginCategory = typeof COMMUNITY_CATEGORIES[number]\n\n/** One community plugin entry: contributor metadata plus the repository link. */\nexport interface CommunityPluginEntry {\n /** Stable entry id (unique in community.json). */\n id: string\n /** Display name (zh). */\n name: string\n /** Display name (en). */\n nameEn: string\n /** Contributor (GitHub user or organization). */\n author: string\n /** One-line description (zh). */\n description?: string\n /** One-line description (en). */\n descriptionEn?: string\n /** The contributor's own repository URL. */\n repo: string\n /** npm package name, when the plugin is published there. */\n npm?: string\n /** Category id for the marketplace filter pills. */\n category?: CommunityPluginCategory\n}\n\n/** Every community plugin, in community.json order. */\nexport const COMMUNITY_PLUGINS: readonly CommunityPluginEntry[] = [\n {\"id\":\"dsh-data-agent\",\"name\":\"Data Agent\",\"nameEn\":\"Data Agent\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-data-agent\",\"description\":\"为 DSH 定义专用 Data Agent 预设,让 AI 帮你查询、更新、分析数据。\",\"descriptionEn\":\"Defines a dedicated Data Agent preset for DSH so the AI can query, update and analyze data.\",\"category\":\"agent\"},\n {\"id\":\"dsh-tui\",\"name\":\"dsh-TUI\",\"nameEn\":\"dsh-TUI\",\"author\":\"ccch1mneyyy\",\"repo\":\"https://github.com/ccch1mneyyy/dsh-TUI\",\"description\":\"Claude Code 风格全屏交互终端插件:像素鲸鱼顶栏、实时工作状态行、思考流式展开、双击 Esc 回滚、上下文进度条与 TPS 仪表。\",\"descriptionEn\":\"A Claude Code style fullscreen interactive terminal plugin: pixel-whale header, live working-state line, streaming reasoning expansion, double-Esc rollback, context progress bar and TPS gauges.\",\"category\":\"ui\"},\n {\"id\":\"dsh-tianshu-tui\",\"name\":\"天书 TUI\",\"nameEn\":\"Tianshu TUI\",\"author\":\"huiliyi37\",\"repo\":\"https://github.com/huiliyi37/dsh-tianshu-tui\",\"description\":\"基于官方 DeepSeek Harness 的交互式终端 UI 插件,在官方基础上增加 TDD 与证据门等工作流。\",\"descriptionEn\":\"An interactive terminal UI plugin for DeepSeek Harness that adds TDD and evidence-gate workflows on top of the official base.\",\"category\":\"ui\"},\n {\"id\":\"dsh-chat-summary\",\"name\":\"Chat Summary\",\"nameEn\":\"Chat Summary\",\"author\":\"v833\",\"repo\":\"https://github.com/v833/dsh-chat-summary\",\"description\":\"总结当前对话并导出为 Markdown / DOCX / PDF,可选 LLM 智能总结(用户自配 API Key)。\",\"descriptionEn\":\"Summarize the current conversation and export it as Markdown / DOCX / PDF, with optional LLM summarization using your own API key.\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-builtin-toggles\",\"name\":\"内置能力检查器\",\"nameEn\":\"Built-in Capability Inspector\",\"author\":\"Starfie1d1272\",\"repo\":\"https://github.com/Starfie1d1272/dsh-builtin-toggles\",\"description\":\"Evidence-backed 内置 capability Inspector:展示 DSH Web built-in capability 的 provenance、compatibility 与 structural drift;仅对 9 个经过审阅的 UI leaves 提供 fail-closed 开关。\",\"descriptionEn\":\"Evidence-backed built-in capability Inspector: surfaces provenance, compatibility and structural drift of DSH Web built-ins, with fail-closed toggles for only the nine reviewed UI leaves.\",\"npm\":\"dsh-builtin-toggles\",\"category\":\"tools\"},\n {\"id\":\"dsh-pilot\",\"name\":\"Pilot 浏览器驾驶舱\",\"nameEn\":\"Pilot Browser Cockpit\",\"author\":\"guo6x\",\"repo\":\"https://github.com/guo6x/dsh-pilot\",\"description\":\"给 agent 一双会开车的手:零依赖 CDP 浏览器操控(8 个 pilot_* 工具:导航/点击/输入/按键/JS/截图)+ Web GUI 可拖拽驾驶舱面板,无需 Playwright、无需 API key。\",\"descriptionEn\":\"Give your agent hands: zero-dependency CDP browser control (8 pilot_* tools: navigate/click/type/keys/eval/screenshot) plus a draggable cockpit panel in the Web GUI - no Playwright, no API key.\",\"category\":\"tools\"},\n {\"id\":\"dsh-housekeeper\",\"name\":\"环境管家\",\"nameEn\":\"Environment Housekeeper\",\"author\":\"guo6x\",\"repo\":\"https://github.com/guo6x/dsh-housekeeper\",\"description\":\"管住 agent 的脏手:工具链台账(node/pnpm/git/gh/ffmpeg 等自动探测)、缓存与临时目录扫描 + 白名单安全一键清理、机器规则 AGENTS.md 查看编辑,全在设置面板完成。\",\"descriptionEn\":\"Keep your agent's hands clean: toolchain inventory, scratch/cache scan with whitelist-guarded one-click cleanup, and the machine rules file (AGENTS.md) view/edit - all in the settings panel.\",\"category\":\"utility\"},\n {\"id\":\"dsh-deepread\",\"name\":\"DeepRead 精读助手\",\"nameEn\":\"DeepRead Assistant\",\"author\":\"xiehuan123\",\"repo\":\"https://github.com/xiehuan123/dsh-deepread\",\"description\":\"五种模式精读插件(quick / deep / map / feynman / book),支持公众号链接与文件输入、批量对比、预算预检与后台任务进度透明,导出 md / mm / html,Web UI 提供工具结果卡片与精读面板。\",\"descriptionEn\":\"A five-mode deep reading plugin (quick / deep / map / feynman / book) for links and files, with batch comparison, budget preflight, transparent background-job progress, md / mm / html exports, and Web UI tool-result cards plus a reading panel.\",\"npm\":\"dsh-deepread\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-mnemon\",\"name\":\"Mnemon 记忆系统\",\"nameEn\":\"Mnemon Memory\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-mnemon\",\"description\":\"与 Mnemon CLI 集成的跨 Agent、本地优先持久记忆插件:用户画像 / 工作记忆 / 项目档案与长期 Memory Spaces,支持导入导出。\",\"descriptionEn\":\"A cross-agent, local-first persistent memory plugin integrating the Mnemon CLI: profiles, working memory, project documents and long-term Memory Spaces, with import and export.\",\"npm\":\"dsh-mnemon\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-genui\",\"name\":\"GenUI 生成式 UI\",\"nameEn\":\"GenUI\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-genui\",\"description\":\"给模型输出配交互式 UI:助手回复内联渲染 dsh-ui fence(布局、图表、表单、Mermaid、3D),支持流式渲染与面板停靠,组件交互可回传模型。\",\"descriptionEn\":\"Interactive UI inside assistant replies via the dsh-ui fence: layouts, charts, forms, Mermaid and 3D with streaming rendering, panel docking and actions that loop back to the model.\",\"category\":\"ui\"},\n {\"id\":\"dsh-annotation\",\"name\":\"选中批注\",\"nameEn\":\"Selection Annotation\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-annotation\",\"description\":\"选中助手文字即可批注,回车随消息发送;自己的气泡只显示问题与「批注 ×N」标签,模型按 Annotation N 逐条对照回复(悬浮芯片)。\",\"descriptionEn\":\"Select text in an assistant reply to annotate it; annotations are sent with your next message, hidden from your own bubble behind an Annotations xN chip, and the model replies per Annotation N with hoverable chips.\",\"category\":\"ui\"},\n {\"id\":\"deepseek-harness-auth\",\"name\":\"DeepSeek Harness Auth\",\"nameEn\":\"DeepSeek Harness Auth\",\"author\":\"taichuy\",\"repo\":\"https://github.com/taichuy/deepseek-harness-auth\",\"description\":\"为 DSH Web 公网部署提供登录认证前置代理,支持账号密码、验证码、失败锁定和 IP/CIDR 白名单。\",\"descriptionEn\":\"An authentication proxy for public DSH Web deployments with password login, captcha, failed-attempt locking, and IP/CIDR allowlists.\",\"npm\":\"deepseek-harness-auth\",\"category\":\"security\"},\n {\"id\":\"dsh-cloud-sync\",\"name\":\"云同步服务\",\"nameEn\":\"Cloud Sync\",\"author\":\"dickpy\",\"repo\":\"https://github.com/dickpy/dsh-cloud-sync\",\"description\":\"支持 WebDAV、S3、阿里云 OSS、腾讯云 COS 与 MinIO 的 DSH 云同步插件,可同步 profile、插件配置及本地插件源码归档。\",\"descriptionEn\":\"DSH cloud sync for WebDAV, S3, Alibaba Cloud OSS, Tencent Cloud COS and MinIO, syncing profiles, plugin settings and local plugin source archives.\",\"npm\":\"@dickpy/dsh-cloud-sync\",\"category\":\"integration\"},\n {\"id\":\"dsh-auto-memory\",\"name\":\"自动记忆\",\"nameEn\":\"Auto Memory\",\"author\":\"Aik358\",\"repo\":\"https://github.com/Aik358/dsh-auto-memory\",\"description\":\"三层自动记忆插件:用户级/项目笔记/每日日志自动注入与检索、每轮自动沉淀、AI 时段问候、智能检索、日历与工作区思维导图,支持继承 WorkBuddy/CodeBuddy/Claude Code/Codex 等其他 AI 工具的记忆。\",\"descriptionEn\":\"Three-layer auto memory for DSH: user-level/project-notes/daily-logs with automatic injection and retrieval, per-turn auto-consolidation, AI greetings, smart search, calendar, workspace mind map, and inheritance from WorkBuddy/CodeBuddy/Claude Code/Codex.\",\"npm\":\"@a9i5k4/dsh-auto-memory\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-memoir\",\"name\":\"项目记忆 Memoir\",\"nameEn\":\"Project Memory Memoir\",\"author\":\"Qinling-Melon-Farmers\",\"repo\":\"https://github.com/Qinling-Melon-Farmers/dsh-memoir\",\"description\":\"项目持久化记忆与会话经验沉淀:memoir_record / memoir_read 工具(BM25 相关度排序检索)、每轮工作自动蒸馏、记忆诊断面板与跨项目全局检索,纯本地零外部依赖。\",\"descriptionEn\":\"Project persistent memory and session-lessons distillation: memoir_record / memoir_read tools with BM25-ranked retrieval, per-turn auto-distill, a memory diagnostics panel and cross-project search - fully local, no external dependency.\",\"npm\":\"dsh-memoir\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-worktime-board\",\"name\":\"牛马修仙看板\",\"nameEn\":\"Worktime Cultivation Board\",\"author\":\"spacexun2\",\"repo\":\"https://github.com/spacexun2/dsh-worktime-board\",\"description\":\"DeepSeek Harness 工时统计 × 修仙养成:日/周/月/学年四档汇总 agent 活跃时长、token、输入与工具调用,十二重境界(炼气→宇宙洪荒)量化进度,纯本地存储。\",\"descriptionEn\":\"Worktime statistics meets cultivation: daily / weekly / monthly / yearly agent activity, token, input and tool-call summaries with a twelve-realm progression (Qi Refining to Cosmic Chaos), fully local.\",\"npm\":\"dsh-worktime-board\",\"category\":\"utility\"},\n {\"id\":\"dsh-skill-explorer\",\"name\":\"技能中心(Skill Explorer)\",\"nameEn\":\"Skill Explorer\",\"author\":\"wingsky-1\",\"repo\":\"https://github.com/wingsky-1/dsh-skill-explorer\",\"description\":\"DSH 技能中心:按来源分级浏览已加载 skill(系统内置 / 项目 / 用户 / 自定义 / 运行时),支持启用/禁用、创建与删除(移入 .trash)。\",\"descriptionEn\":\"DSH skill center: browse loaded skills grouped by source (bundled / project / user / custom / runtime), with enable/disable, create and delete (move to .trash).\",\"npm\":\"@linxin666/dsh-client-ui-skill-explorer\",\"category\":\"tools\"},\n {\"id\":\"dsh-friendly-steps\",\"name\":\"过程精简 Friendly Steps\",\"nameEn\":\"Friendly Steps\",\"author\":\"dongwenxiu83-web\",\"repo\":\"https://github.com/dongwenxiu83-web/dsh-friendly-steps\",\"description\":\"面向文字工作者的过程精简:纯 CSS 折叠 Think / 工具调用等技术过程行,右下角浮条「已完成 N 步」一键展开收起,失败步骤红色计数反馈;不注入 React 列表、无全量扫描,零侵入。\",\"descriptionEn\":\"Writer-friendly process collapse: hides Think / tool-call rows via pure CSS behind a floating 'N steps done' pill with red failure counts and one-click expand/collapse. No foreign nodes in React lists, no full-DOM scans — zero interference.\",\"category\":\"ui\"},\n {\"id\":\"dsh-full-remote\",\"name\":\"全功能远程访问\",\"nameEn\":\"Full Remote Access\",\"author\":\"JUANWANG-BUAA\",\"repo\":\"https://github.com/JUANWANG-BUAA/dsh-full-remote\",\"description\":\"令牌门控反向代理:公网隧道或局域网下,在手机等设备上远程使用 DeepSeek Harness,设置、凭据与文件访问保持可用,支持按设备会话。\",\"descriptionEn\":\"Token-gated reverse proxy for remote access: use DeepSeek Harness over public tunnels or LAN from phones and other devices, with settings, credentials and file access kept working and per-device sessions.\",\"npm\":\"dsh-full-remote\",\"category\":\"integration\"},\n {\"id\":\"dsh-palate\",\"name\":\"Palate 品味训练\",\"nameEn\":\"Palate Design Taste\",\"author\":\"guo6x\",\"repo\":\"https://github.com/guo6x/dsh-palate\",\"description\":\"会长大的眼:可积累的设计品味语料库(好/坏例子 + 编码原则),喂得越多评审越准;6 个 palate_* 工具(review/add/learn/list/principles/stats)+ 成长面板,node:sqlite + 人可读 Markdown 镜像,零运行时依赖。\",\"descriptionEn\":\"An eye that grows: an accumulated design-taste corpus (good/bad examples plus codified principles) that sharpens with every example you feed; six palate_* tools (review/add/learn/list/principles/stats) plus a growth panel, node:sqlite with human-readable Markdown mirrors, zero runtime dependencies.\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-archive-manager\",\"name\":\"归档管理\",\"nameEn\":\"Archive Manager\",\"author\":\"z953218350\",\"repo\":\"https://github.com/z953218350/dsh-archive-manager\",\"description\":\"设置页 Codex 风格会话归档管理:按项目分组、搜索筛选、预览对话内容、一键恢复与彻底物理删除,内置 zstd 解压引擎。\",\"descriptionEn\":\"Codex-style archived session manager in settings: group by project, search and filter, preview conversation history, restore to sidebar, and permanently delete from disk; built-in zstd decompression.\",\"npm\":\"@mlgbnb/dsh-archive-manager\",\"category\":\"utility\"},\n {\"id\":\"dsh-history-tree\",\"name\":\"历史树\",\"nameEn\":\"History Tree\",\"author\":\"z953218350\",\"repo\":\"https://github.com/z953218350/dsh-history-tree\",\"description\":\"在聊天消息左侧提供 Codex 风格对话轮次时间线点阵与悬浮历史概览卡片,支持鱼眼放大动效与点击直达对应轮次。\",\"descriptionEn\":\"Codex-style conversation turn timeline rail and hover overview cards beside chat messages, with fish-eye magnification and click-to-jump navigation.\",\"npm\":\"dsh-history-tree\",\"category\":\"ui\"},\n {\"id\":\"dsh-gzip\",\"name\":\"dsh-gzip\",\"nameEn\":\"dsh-gzip\",\"author\":\"wingsky-1\",\"repo\":\"https://github.com/wingsky-1/dsh-plugin-hub/tree/main/packages/dsh-gzip\",\"description\":\"/api 响应 gzip 压缩插件:为远程 / 低带宽链路开启 /api 响应压缩,解决会话历史因大响应无压缩而超时加载失败的问题;SSE / zip / 已编码响应自动豁免,无全局副作用。\",\"descriptionEn\":\"API response gzip plugin for DSH Web GUI: enables gzip on /api responses for remote / low-bandwidth links, fixing session-history loads that fail on the timeout of large uncompressed responses; SSE, zip and already-encoded responses are passed through untouched, with no global side effects.\",\"npm\":\"@wingsky-1/dsh-gzip\"},\n {\"id\":\"dsh-wsl-bridge\",\"name\":\"WSL Windows 桥\",\"nameEn\":\"WSL Windows Bridge\",\"author\":\"ch1bug\",\"repo\":\"https://github.com/ch1bug/dsh-wsl-bridge\",\"description\":\"让 WSL 里的 agent 访问 Windows 侧:读写 C:\\\\ 文件、运行 .exe、Explorer 打开、wslpath 路径互转与盘符枚举(win_ls/read/write/run/open/path/drives)。\",\"descriptionEn\":\"Lets a WSL agent reach the Windows host: read/write C:\\\\ files, run .exe programs, open in Explorer, convert paths via wslpath and list drives (win_ls/read/write/run/open/path/drives).\",\"category\":\"integration\"},\n {\"id\":\"dsh-mimo-agent-tools\",\"name\":\"MiMo 多模态工具\",\"nameEn\":\"MiMo Multimodal Tools\",\"author\":\"ch1bug\",\"repo\":\"https://github.com/ch1bug/dsh-mimo-agent-tools\",\"description\":\"把小米 MiMo API 封装为 agent 工具:联网搜索、图像/音频/视频理解、语音转写、语音合成与音色克隆(mimo_search/vision/audio/video/asr/tts/voiceclone)。\",\"descriptionEn\":\"Turns the Xiaomi MiMo API into agent tools: web search, image/audio/video understanding, speech-to-text, text-to-speech and voice cloning (mimo_search/vision/audio/video/asr/tts/voiceclone).\",\"category\":\"tools\"},\n {\"id\":\"dsh-skill-fuzzy\",\"name\":\"技能模糊搜索\",\"nameEn\":\"Skill Fuzzy Search\",\"author\":\"ch1bug\",\"repo\":\"https://github.com/ch1bug/dsh-skill-fuzzy\",\"description\":\"Codex 风格模糊技能搜索:/bug、/diag、/regression 都能在 / 技能菜单里命中 diagnosing-bugs(名称子序列 + 描述连续子串匹配)。\",\"descriptionEn\":\"Codex-style fuzzy skill search: /bug, /diag and /regression all find diagnosing-bugs in the / skill menu (name subsequence + description substring matching).\",\"category\":\"ui\"},\n {\"id\":\"dsh-secret-redactor\",\"name\":\"敏感信息脱敏\",\"nameEn\":\"Secret Redactor\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-secret-redactor\",\"description\":\"自动掩码工具输出中的 API key、token、JWT、私钥与配置密钥。\",\"descriptionEn\":\"Auto-masks API keys, tokens, JWTs and private keys in tool results shown to the model.\"},\n {\"id\":\"dsh-approve-for-me\",\"name\":\"自动审批审核\",\"nameEn\":\"Approve for Me\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-approve-for-me\",\"description\":\"只读工具自动放行、危险命令自动拒绝,可配置全自动模式。\",\"descriptionEn\":\"Auto-approves read-only tools, auto-denies dangerous commands, optional full-auto mode.\"},\n {\"id\":\"dsh-mcp-client-v2\",\"name\":\"MCP 客户端 v2\",\"nameEn\":\"MCP Client v2\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-mcp-client-v2\",\"description\":\"MCP 客户端增强:分页工具发现、非阻塞启动、工具搜索。\",\"descriptionEn\":\"Enhanced MCP client: paginated tool discovery, non-blocking startup, tool search.\"},\n {\"id\":\"dsh-memories\",\"name\":\"项目记忆\",\"nameEn\":\"Project Memories\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-memories\",\"description\":\"按项目作用域持久化的键值记忆,支持增删查列与搜索。\",\"descriptionEn\":\"Project-scoped persistent key-value memories with set/get/list/delete/search.\"},\n {\"id\":\"dsh-system-proxy\",\"name\":\"系统代理\",\"nameEn\":\"System Proxy\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-system-proxy\",\"description\":\"检测系统代理(scutil/环境变量/PAC)并为子进程导出代理环境变量。\",\"descriptionEn\":\"Detects system proxy (scutil/env/PAC) and exports proxy env for child processes.\"},\n {\"id\":\"dsh-usage-cost\",\"name\":\"用量成本提醒\",\"nameEn\":\"Usage & Cost\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-usage-cost\",\"description\":\"统计会话与每日 token 用量和估算成本,超预算提醒。\",\"descriptionEn\":\"Tracks token usage and estimated cost per session/day with budget alerts.\"},\n {\"id\":\"dsh-notifier\",\"name\":\"dsh-notifier\",\"nameEn\":\"dsh-notifier\",\"author\":\"wingsky-1\",\"repo\":\"https://github.com/wingsky-1/dsh-plugin-hub/tree/main/packages/dsh-notifier\",\"description\":\"审批/完成/错误事件通知:浏览器 Notification + 系统原生 toast(Windows PowerShell WinRT / Linux·macOS notify-send,零依赖);提示音可配、错误同类合并、免打扰时段、通知历史与配置面板;非安全上下文自动降级横幅。\",\"descriptionEn\":\"Approval / completion / error event notifications: browser Notification API plus native OS toasts (Windows PowerShell WinRT, Linux and macOS notify-send, zero dependencies); configurable sound, error merging, quiet hours, notification history and a settings panel; falls back to in-page banners outside secure contexts.\",\"npm\":\"@wingsky-1/dsh-notifier\",\"category\":\"utility\"},\n {\"id\":\"dsh-logicprobe\",\"name\":\"逻辑探针\",\"nameEn\":\"Logic Probe\",\"author\":\"AmethystLuna\",\"repo\":\"https://github.com/AmethystLuna/logicprobe\",\"description\":\"AI 智能体声明核查技能:枚举设计文档与重构计划中的每个可验证声明,对照代码库事实逐条核验;行为类声明升级为逻辑原语验证(7 项结构检查 + 7 项对抗探针),重构前后模型对比做回归检测,输出 file:line 证据。\",\"descriptionEn\":\"Claim verification for AI coding agents: enumerate every verifiable claim in design docs and refactoring plans, verify against codebase facts, then escalate behavioral claims to logic-primitive verification (7 structural checks + 7 adversarial probes), with before/after model comparison for refactoring regression detection.\",\"category\":\"tools\"},\n {\"id\":\"dsh-session-delete\",\"name\":\"会话删除\",\"nameEn\":\"Session Delete\",\"author\":\"xohmai\",\"repo\":\"https://github.com/xohmai/dsh-session-delete\",\"description\":\"真正删除会话磁盘日志:归档清理、批量删除、回收站还原;官方归档只隐藏不删盘。\",\"descriptionEn\":\"Real session deletion with trash and restore, archived cleanup and batch delete. Official archive only hides sessions.\",\"category\":\"utility\"},\n {\"id\":\"dsh-chatgpt-subscription\",\"name\":\"子代理管理\",\"nameEn\":\"Subagent Management\",\"author\":\"Aa728848\",\"repo\":\"https://github.com/Aa728848/dsh-chatgpt-subscription\",\"description\":\"让 DSH 通过 ChatGPT 订阅使用 GPT 系列模型:PKCE OAuth 登录、DPAPI/钥匙串/0600 凭据存储、流式 Responses、图片生成、Codex 搜索、额度展示与子代理管理。\",\"descriptionEn\":\"Use GPT models in DSH through your ChatGPT subscription: PKCE OAuth login, DPAPI/keychain/0600 credential storage, streaming Responses, image generation, Codex search, quota display and subagent management.\",\"npm\":\"@eddyskywalker/dsh-chatgpt-subscription\",\"category\":\"integration\"},\n]\n","/**\n * Runtime guard for the generated community index entries. The index is\n * build-time generated data, but the card renders whatever the module\n * carries; a hand-written narrowing keeps one malformed entry from breaking\n * the whole list at render time.\n */\n\nimport { COMMUNITY_CATEGORIES, type CommunityPluginCategory, type CommunityPluginEntry } from './generated/community.ts'\n\n/** Category ids the card knows how to label; others are treated as uncategorized. */\nconst KNOWN_CATEGORIES: readonly CommunityPluginCategory[] = COMMUNITY_CATEGORIES\n\n/**\n * The install command is pasted into a shell, so repo/npm must be free of\n * shell metacharacters: repo is a plain https URL of path-safe characters,\n * npm a standard (optionally scoped) package name.\n */\nconst REPO_SAFE_RE = /^https:\\/\\/[A-Za-z0-9._~\\/-]+$/\nconst NPM_SAFE_RE = /^(@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/\n\n/** True when the value is a well-formed community plugin entry. */\nexport function isCommunityPluginEntry(value: unknown): value is CommunityPluginEntry {\n if (typeof value !== 'object' || value === null) return false\n const entry = value as Record<string, unknown>\n if (typeof entry.id !== 'string' || entry.id === '') return false\n if (typeof entry.name !== 'string' || typeof entry.nameEn !== 'string') return false\n if (typeof entry.author !== 'string' || entry.author === '') return false\n if (typeof entry.repo !== 'string' || !REPO_SAFE_RE.test(entry.repo)) return false\n if (entry.description !== undefined && typeof entry.description !== 'string') return false\n if (entry.descriptionEn !== undefined && typeof entry.descriptionEn !== 'string') return false\n if (entry.npm !== undefined && (typeof entry.npm !== 'string' || !NPM_SAFE_RE.test(entry.npm))) return false\n if (entry.category !== undefined && (typeof entry.category !== 'string' || !KNOWN_CATEGORIES.includes(entry.category as CommunityPluginCategory))) return false\n return true\n}\n","/**\n * Bridge to the optional 'pluginManager' cordis service provided by the\n * sibling plugin @linxin666/dsh-client-ui-plugin-manager. The service is\n * OPTIONAL: when that plugin is not installed the bridge holds null and the\n * card degrades to the read-only copy-command index, exactly as before.\n *\n * CONTRACT OBSERVATION: the InstalledPluginItem / InstallProgressItem /\n * PluginManagerService shapes below mirror the sibling package's frozen\n * contract (its src/core/protocol.ts and src/core/service.ts). Repository\n * rules forbid cross-package value imports, so this file re-declares the\n * types locally; both sides must stay byte-compatible on the wire.\n */\n\n/**\n * One installed user-plugin row (mirrors the sibling's protocol).\n */\nexport interface InstalledPluginItem {\n id: string\n name: string\n version: string\n source: { kind: 'npm' | 'git'; spec: string }\n installedAt: string\n /** Saved next-start enablement from the managed profile patch row. */\n enabled: boolean\n commit?: string\n}\n\n/** Point-in-time install/update progress reported by the host. */\nexport interface InstallProgressItem {\n kind: 'idle' | 'install' | 'update'\n stage: 'fetch' | 'download' | 'extract' | 'write'\n percent?: number\n}\n\n/**\n * The frozen cross-plugin service contract (cordis service name\n * 'pluginManager'). Kept intentionally narrow: observe and drive the\n * installed-plugin set.\n */\nexport interface PluginManagerService {\n /** Whether this browser has loopback authority over the host routes. */\n readonly isLoopback: boolean\n /** Read the installed snapshot. */\n list(): Promise<InstalledPluginItem[]>\n /** Install one plugin from an npm spec or git URL. */\n install(spec: string): Promise<InstalledPluginItem>\n /** Remove one plugin; resolves with the fresh installed snapshot. */\n uninstall(id: string): Promise<InstalledPluginItem[]>\n /** Read the current install/update progress. */\n status(): Promise<InstallProgressItem>\n /** Subscribe to successful mutations; returns the unsubscribe function. */\n onChange(cb: () => void): () => void\n}\n\nimport type { Context } from '@deepseek-ai/cordis'\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * The plugin-manager face, present only when the sibling\n * dsh-plugin-manager client plugin is installed and active.\n */\n pluginManager?: PluginManagerService\n }\n}\n\n/** Bridge snapshot: the current face (or null) plus a monotonically increasing version. */\nexport interface PluginManagerBridgeSnapshot {\n /** The service face while the sibling plugin provides it, else null. */\n readonly face: PluginManagerService | null\n /** Bumped on every face change (lets consumers detect same-reference swaps). */\n readonly version: number\n}\n\nlet snapshot: PluginManagerBridgeSnapshot = { face: null, version: 0 }\nconst listeners = new Set<() => void>()\n\n/** Replace the held face and notify subscribers. */\nfunction setFace(face: PluginManagerService | null): void {\n snapshot = { face, version: snapshot.version + 1 }\n for (const listener of listeners) listener()\n}\n\n/** Current bridge snapshot (cached reference, safe for useSyncExternalStore). */\nexport function getPluginManagerSnapshot(): PluginManagerBridgeSnapshot {\n return snapshot\n}\n\n/** Subscribe to face changes; returns the unsubscribe function. */\nexport function subscribePluginManager(listener: () => void): () => void {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n}\n\n/**\n * Bridge the optional 'pluginManager' service into the module store. Uses\n * ctx.inject (NOT the plugin's module-level inject array) so the service\n * stays optional: the inner callback runs when the sibling plugin provides\n * the face and is disposed when it goes away, which clears the store.\n * @param ctx - the client root context.\n */\nexport function bridgePluginManager(ctx: Context): void {\n ctx.inject(['pluginManager'], (inner) => {\n inner.effect(() => {\n setFace(inner.pluginManager ?? null)\n return () => { setFace(null) }\n }, 'community-plugins: pluginManager bridge')\n })\n}\n","/**\n * Map a community index entry onto the plugin-manager install surface: the\n * install spec (npm package when published, else the contributor repository\n * URL) and a conservative matcher that tells whether one entry is already\n * present in the installed snapshot the 'pluginManager' service serves.\n */\n\nimport type { CommunityPluginEntry } from './generated/community.ts'\nimport type { InstalledPluginItem } from './plugin-manager-bridge.ts'\n\n/**\n * The spec handed to pluginManager.install(): the npm package name when the\n * entry is published there, else the repository URL (git install).\n * @param entry - the community index entry.\n * @returns the install spec.\n */\nexport function installSpec(entry: CommunityPluginEntry): string {\n return entry.npm ?? entry.repo\n}\n\n/**\n * Normalize a git remote for comparison: lowercase, drop the transport\n * prefix ('git+' wrapper, 'https://', 'http://', 'git://', 'ssh://git@', the\n * scp-style 'git@host:' userinfo, and the pnpm host shorthands 'github:' /\n * 'gitlab:' / 'bitbucket:' that package.json records for shorthand installs),\n * then strip trailing slashes and one trailing '.git'\n * suffix (repeated, so 'x/.git/' and 'x.git' converge). Conservative on\n * purpose: no path rewriting beyond those steps, so distinct repositories\n * never collapse onto each other.\n * @param url - the repository URL as recorded by either side.\n * @returns the comparison key.\n */\nexport function normalizeGitUrl(url: string): string {\n let key = url.trim().toLowerCase()\n // pnpm git wrapper: 'git+https://host/owner/repo' -> 'https://host/owner/repo'.\n key = key.replace(/^git[+]/, '')\n // pnpm host shorthands recorded in package.json: 'github:owner/repo' ->\n // 'github.com/owner/repo' (same for gitlab / bitbucket).\n key = key.replace(/^(github|gitlab):/, '$1.com/')\n key = key.replace(/^bitbucket:/, 'bitbucket.org/')\n // Transport prefixes: 'https://', 'http://', 'git://', 'ssh://git@'.\n key = key.replace(/^(?:https?|git):[/][/]/, '')\n key = key.replace(/^ssh:[/][/]git@/, '')\n // Scp-style ssh remote: 'git@github.com:owner/repo' -> 'github.com/owner/repo'.\n key = key.replace(/^git@([^/:]+):/, '$1/')\n // Strip trailing slashes and a trailing '.git' suffix until stable.\n for (;;) {\n const next = key.replace(/[/]+$/, '').replace(/[.]git$/, '')\n if (next === key) return key\n key = next\n }\n}\n\n/**\n * Match one community entry against the installed snapshot. npm-published\n * entries match on the installed row's package identity (id/name): the npm\n * source spec records the dependency RANGE ('^0.3.2') or an install-time\n * spec, not necessarily the bare package name, so it is only a fallback.\n * Repository entries match on the normalized git URL. An entry with an npm\n * field ONLY matches npm installs — a same-repository git install is a\n * different source and stays unmatched (the card then offers install, which\n * the host reconciles).\n * @param entry - the community index entry.\n * @param installed - the installed snapshot from the pluginManager service.\n * @returns the matching installed row, or null.\n */\nexport function entryInstalled(\n entry: CommunityPluginEntry,\n installed: readonly InstalledPluginItem[],\n): InstalledPluginItem | null {\n if (entry.npm !== undefined) {\n return installed.find(\n item => item.source.kind === 'npm'\n && (item.id === entry.npm || item.name === entry.npm || item.source.spec === entry.npm),\n ) ?? null\n }\n const key = normalizeGitUrl(entry.repo)\n return installed.find(\n item => item.source.kind === 'git' && normalizeGitUrl(item.source.spec) === key,\n ) ?? null\n}\n","/**\n * The community plugin index card: a first-level settings section that is\n * always open. Its own enable switch (backed by the community-plugins\n * settings namespace) gates the list, which is presented marketplace-style:\n * a search box, category filter pills with counts, and a two-column card grid\n * whose entries link to contributors' own repositories — this package only\n * indexes them, it never vendors their code.\n */\n\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, type ReactNode } from 'react'\nimport { Button, Modal } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\n// Type-only: pulls the settings-surface SlotMap merge (the 'settings.section' entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { PluginSettingsCard, BooleanField } from './PluginSettingsCard.tsx'\nimport { CardForm, booleanField, type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts'\nimport { COMMUNITY_PLUGINS, type CommunityPluginCategory, type CommunityPluginEntry } from './generated/community.ts'\nimport { isCommunityPluginEntry } from './community-guard.ts'\nimport {\n getPluginManagerSnapshot,\n subscribePluginManager,\n type InstalledPluginItem,\n type InstallProgressItem,\n type PluginManagerService,\n} from './plugin-manager-bridge.ts'\nimport { entryInstalled, installSpec } from './install-source.ts'\nimport css from './community.module.css'\n\n/** The settings fields this card edits (the namespace's full schema). */\nexport interface CommunityPluginsSettings {\n /** Master switch for the index card. */\n enabled?: boolean\n}\n\n/** What the community plugin card renders. */\nexport interface CommunityPluginsCardState extends CardShell {\n /** Master switch. */\n enabled: CardFieldState\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface CommunityPluginsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useCommunityPluginsCard. */\n communityPluginsCard: SnapshotStore<CommunityPluginsCardState>\n }\n}\n\n/** Bridges the community-plugins scope onto the card's staged form. */\nexport class CommunityPluginsCardController {\n private readonly form: CardForm<CommunityPluginsSettings>\n private readonly store: SnapshotStore<CommunityPluginsCardState>\n\n /** @param scope - the bound settings scope for the community-plugins namespace. */\n constructor(scope: SettingsScope<CommunityPluginsSettings>) {\n this.form = new CardForm(scope, [\n booleanField('enabled'),\n ])\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): CommunityPluginsCardState {\n return {\n ...this.form.shell(),\n enabled: this.form.field('enabled'),\n }\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): CommunityPluginsCardFace {\n return { hooks: { communityPluginsCard: this.store }, ...this.form.actions() }\n }\n\n /**\n * Release the card's scope subscription and bound stores; the slot\n * disposer calls this on teardown.\n */\n dispose(): void {\n this.form.dispose()\n }\n}\n\n/** The one-line install command for an entry: npm package when published, else the contributor repository URL. */\nfunction installCommand(entry: CommunityPluginEntry): string {\n return `dsh plugin --profile web add ${entry.npm ?? entry.repo}`\n}\n\n/** Progress polling cadence while an install is in flight. */\nconst PROGRESS_POLL_MS = 500\n\n/** Extract a displayable reason from an install/uninstall rejection. */\nfunction messageOf(reason: unknown): string {\n return reason instanceof Error ? reason.message : String(reason)\n}\n\n/** One in-flight mutation, keyed by the community entry id (drives per-card state). */\ninterface PendingMutation {\n readonly kind: 'install' | 'uninstall'\n readonly id: string\n}\n\n/**\n * Localized entry copy read through the card's `t`. Falls back to the raw\n * entry field when the key is missing — the dictionary only carries the\n * generated registry, so injected test entries land on the fallback.\n */\nfunction entryCopy(t: (key: string) => string, key: string, fallback: string): string {\n const value = t(key)\n return value === key ? fallback : value\n}\n\n/** Maps a category id onto its locale dictionary key (kept in the generated union). */\nconst CATEGORY_KEY: Record<CommunityPluginCategory, `category.${CommunityPluginCategory}`> = {\n ui: 'category.ui',\n agent: 'category.agent',\n tools: 'category.tools',\n knowledge: 'category.knowledge',\n integration: 'category.integration',\n security: 'category.security',\n utility: 'category.utility',\n}\n\n/** Props the renderer binds for the community plugin card. */\nexport type CommunityPluginsCardProps =\n PropsLocale<'community-plugins'>\n & InjectFace<CommunityPluginsCardFace>\n & {\n /** Index entries; defaults to the generated registry (injected for tests). */\n plugins?: readonly CommunityPluginEntry[]\n /**\n * Plugin-manager face override; undefined reads the bridged cordis\n * service (the default), null forces the degraded copy-command UI\n * (injected for tests).\n */\n pluginManager?: PluginManagerService | null\n }\n\n/**\n * Render the community plugin index card.\n * @param props - locale copy, the card snapshot, its form actions, and the\n * (default-generated) entry list.\n * @returns the card.\n */\nexport function CommunityPluginsCard(props: CommunityPluginsCardProps): ReactNode {\n const { t } = props\n const state = props.useCommunityPluginsCard(snapshot => snapshot)\n // Memoized so the categoryCounts/visiblePlugins caches below only\n // recompute when the registry actually changes, not on every keystroke.\n const plugins = useMemo(() => (props.plugins ?? COMMUNITY_PLUGINS).filter(isCommunityPluginEntry), [props.plugins])\n const [query, setQuery] = useState('')\n const [category, setCategory] = useState<CommunityPluginCategory | null>(null)\n const [copiedId, setCopiedId] = useState<string | null>(null)\n\n // The optional pluginManager service: undefined prop reads the bridge store\n // (populated by ctx.inject in the client apply), an explicit prop wins.\n const bridge = useSyncExternalStore(subscribePluginManager, getPluginManagerSnapshot)\n const face = props.pluginManager !== undefined ? props.pluginManager : bridge.face\n const faceLoopback = face !== null && face.isLoopback\n // A bridge version can change while cordis re-provides the same face\n // reference. Give every committed provision its own lifetime so async\n // completions from the previous one cannot mutate the replacement UI.\n const faceRevision = props.pluginManager !== undefined ? face : bridge.version\n const faceLifetime = useMemo(() => ({ active: true }), [face, faceRevision])\n useLayoutEffect(() => {\n faceLifetime.active = true\n return () => { faceLifetime.active = false }\n }, [faceLifetime])\n\n // Installed snapshot served by the face (null = not loaded / no face).\n const [installed, setInstalled] = useState<readonly InstalledPluginItem[] | null>(null)\n // The one in-flight mutation; while set, every card's mutation buttons disable.\n const [pending, setPending] = useState<PendingMutation | null>(null)\n // Latest polled install progress (only meaningful while an install runs).\n const [progress, setProgress] = useState<InstallProgressItem | null>(null)\n // Per-card inline error lines, keyed by entry id.\n const [errors, setErrors] = useState<Readonly<Record<string, string>>>({})\n // The entry awaiting uninstall confirmation.\n const [uninstallTarget, setUninstallTarget] = useState<CommunityPluginEntry | null>(null)\n // Latest-issued list request wins. An earlier request may complete after a\n // mutation refresh even when the service face itself did not change.\n const listRequestRef = useRef(0)\n\n // Keep the installed snapshot in sync with the face: initial load, plus\n // onChange so edits made in the Plugin manager tab reflect here. Only\n // loopback faces are queried — remote browsers render the read-only index.\n useEffect(() => {\n // An operation belongs to the face that started it. Once that face is\n // replaced, release its local UI lock and discard its dialog/error state;\n // the new face's list request below becomes authoritative.\n setPending(null)\n setProgress(null)\n setErrors({})\n setUninstallTarget(null)\n listRequestRef.current += 1\n if (face === null || !face.isLoopback) {\n setInstalled(null)\n return\n }\n let alive = true\n const refresh = (): void => {\n const request = ++listRequestRef.current\n void face.list().then(\n (list) => {\n if (alive && faceLifetime.active && request === listRequestRef.current) setInstalled(list)\n },\n () => { /* keep the last known snapshot on transient failures */ },\n )\n }\n refresh()\n const unsubscribe = face.onChange(refresh)\n return () => { alive = false; unsubscribe() }\n }, [face, faceLoopback, faceLifetime])\n\n // Poll the host's install progress while an install is in flight; the\n // first poll runs immediately so the stage line appears without delay.\n useEffect(() => {\n if (face === null || pending?.kind !== 'install') {\n setProgress(null)\n return\n }\n let alive = true\n const poll = (): void => {\n void face.status().then(\n (item) => { if (alive && faceLifetime.active) setProgress(item) },\n () => { /* transient poll failure: keep the last known stage */ },\n )\n }\n poll()\n const timer = setInterval(poll, PROGRESS_POLL_MS)\n return () => { alive = false; clearInterval(timer) }\n // Keyed on the boolean, not the entry: restarting the poll per entry is unnecessary.\n }, [face, faceLifetime, pending?.kind === 'install'])\n\n const clearError = (id: string): void => {\n setErrors((previous) => {\n if (!(id in previous)) return previous\n const next = { ...previous }\n delete next[id]\n return next\n })\n }\n\n const onInstall = (entry: CommunityPluginEntry): void => {\n if (face === null || !face.isLoopback || pending !== null) return\n const lifetime = faceLifetime\n clearError(entry.id)\n setPending({ kind: 'install', id: entry.id })\n void (async () => {\n try {\n await face.install(installSpec(entry))\n if (!lifetime.active) return\n const request = ++listRequestRef.current\n const list = await face.list().catch(() => undefined)\n if (lifetime.active && list !== undefined && request === listRequestRef.current) setInstalled(list)\n } catch (reason) {\n if (!lifetime.active) return\n setErrors((previous) => ({ ...previous, [entry.id]: t('installFailed', { reason: messageOf(reason) }) }))\n } finally {\n if (lifetime.active) setPending(null)\n }\n })()\n }\n\n const onUninstallConfirm = (): void => {\n const target = uninstallTarget\n if (face === null || target === null || pending !== null) return\n const item = entryInstalled(target, installed ?? [])\n clearError(target.id)\n if (item === null) {\n // Already gone (e.g. uninstalled from the Plugin manager tab): close quietly.\n setUninstallTarget(null)\n return\n }\n const lifetime = faceLifetime\n setPending({ kind: 'uninstall', id: target.id })\n face.uninstall(item.id).then(\n (list) => {\n if (!lifetime.active) return\n listRequestRef.current += 1\n setInstalled(list)\n setUninstallTarget(null)\n },\n (reason: unknown) => {\n if (!lifetime.active) return\n setErrors((previous) => ({ ...previous, [target.id]: t('uninstallFailed', { reason: messageOf(reason) }) }))\n setUninstallTarget(null)\n },\n ).finally(() => { if (lifetime.active) setPending(null) })\n }\n\n const copyCommand = (id: string, command: string): void => {\n const mark = (): void => { setCopiedId(id) }\n const clipboard = typeof navigator !== 'undefined' ? navigator.clipboard : undefined\n if (clipboard?.writeText !== undefined) {\n void clipboard.writeText(command).then(mark, mark)\n return\n }\n // Fallback for browsers without the async clipboard API (or tests).\n try {\n const area = document.createElement('textarea')\n area.value = command\n area.setAttribute('readonly', '')\n area.style.position = 'fixed'\n area.style.opacity = '0'\n document.body.append(area)\n area.select()\n document.execCommand('copy')\n area.remove()\n } catch { /* the command stays visible to select by hand */ }\n mark()\n }\n const disabled = !state.writable\n // One in-flight install/uninstall locks every card's mutation buttons.\n const mutationsDisabled = disabled || pending !== null\n // The draft text drives the list: '' (inherit) and 'true' keep it visible,\n // 'false' hides it until the switch is turned back on.\n const visible = state.enabled.text !== 'false'\n const fieldProps = {\n overriddenLabel: t('settings.overridden'),\n resetLabel: t('settings.reset'),\n invalidLabel: t('settings.invalidNumber'),\n disabled,\n }\n\n // Category pills in descending count (stable tie-break by id).\n const categoryCounts = useMemo(() => {\n const counts = new Map<CommunityPluginCategory, number>()\n for (const plugin of plugins) {\n if (plugin.category) counts.set(plugin.category, (counts.get(plugin.category) ?? 0) + 1)\n }\n return [...counts.entries()].sort(\n (a, b) => b[1] - a[1] || a[0].localeCompare(b[0]),\n )\n }, [plugins])\n\n // Both the active pill and the search text narrow the list (AND).\n const visiblePlugins = useMemo(() => {\n const needle = query.trim().toLowerCase()\n return plugins.filter((plugin) => {\n if (category !== null && plugin.category !== category) return false\n if (!needle) return true\n const categoryLabel = plugin.category ? t(CATEGORY_KEY[plugin.category]) : ''\n const haystack = [plugin.name, plugin.nameEn, plugin.author, plugin.description, plugin.descriptionEn, plugin.npm ?? '', categoryLabel]\n .join(' ')\n .toLowerCase()\n return haystack.includes(needle)\n })\n }, [plugins, query, category, t])\n\n return (\n <PluginSettingsCard\n t={t}\n titleKey=\"settings.title\"\n descriptionKey=\"settings.description\"\n state={state}\n alwaysOpen\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"settings-community-enabled\"\n label={t('settings.enabled')}\n hint={t('settings.enabledHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.enabled}\n onEdit={(text) => { props.edit('enabled', text) }}\n onReset={() => { props.resetField('enabled') }}\n />\n {visible\n ? (\n <div className={css.market}>\n <div className={css.toolbar}>\n <input\n id=\"settings-community-search\"\n className={css.search}\n type=\"search\"\n placeholder={t('search.placeholder')}\n aria-label={t('search.label')}\n value={query}\n disabled={disabled}\n onChange={(event) => { setQuery(event.target.value) }}\n />\n </div>\n <div className={css.filters} role=\"group\" aria-label={t('filter.all')}>\n <button\n type=\"button\"\n className={category === null ? `${css.pill} ${css.pillActive}` : css.pill}\n aria-pressed={category === null}\n disabled={disabled}\n onClick={() => { setCategory(null) }}\n >\n {t('filter.all')} {plugins.length}\n </button>\n {categoryCounts.map(([id, count]) => (\n <button\n key={id}\n type=\"button\"\n className={category === id ? `${css.pill} ${css.pillActive}` : css.pill}\n aria-pressed={category === id}\n disabled={disabled}\n onClick={() => { setCategory(category === id ? null : id) }}\n >\n {t(CATEGORY_KEY[id])} {count}\n </button>\n ))}\n </div>\n <p className={css.resultCount} role=\"status\">\n {t('result.count', { shown: visiblePlugins.length, total: plugins.length })}\n </p>\n {plugins.length === 0\n ? <p className={css.empty} role=\"status\">{t('empty')}</p>\n : visiblePlugins.length === 0\n ? <p className={css.empty} role=\"status\">{t('noMatch')}</p>\n : (\n <ul className={css.grid}>\n {visiblePlugins.map((plugin) => {\n const command = installCommand(plugin)\n const copied = copiedId === plugin.id\n const name = entryCopy(t, `name.${plugin.id}`, plugin.nameEn || plugin.name)\n const description = entryCopy(t, `desc.${plugin.id}`, plugin.descriptionEn ?? plugin.description ?? '')\n const installedItem = faceLoopback ? entryInstalled(plugin, installed ?? []) : null\n const isInstalling = pending?.kind === 'install' && pending.id === plugin.id\n const isUninstalling = pending?.kind === 'uninstall' && pending.id === plugin.id\n const error = errors[plugin.id]\n return (\n <li key={plugin.id} className={css.card}>\n <span className={css.cardHead}>\n <span className={css.cardName} title={name}>{name}</span>\n <span className={css.cardBadges}>\n {installedItem !== null\n ? <span className={`${css.badge} ${css.badgeInstalled}`}>{t('badge.installed')}</span>\n : null}\n <span\n className={plugin.npm ? `${css.badge} ${css.badgePublished}` : css.badge}\n title={plugin.npm ?? plugin.repo}\n >\n {plugin.npm ? t('badge.published') : t('badge.source')}\n </span>\n </span>\n </span>\n <span className={css.cardMeta}>\n {plugin.category ? <span className={css.cardCategory}>{t(CATEGORY_KEY[plugin.category])}</span> : null}\n {plugin.category ? <span className={css.cardDot} aria-hidden=\"true\">·</span> : null}\n <span className={css.cardAuthor} title={plugin.author}>{plugin.author}</span>\n </span>\n {description ? <p className={css.cardDescription}>{description}</p> : null}\n <span className={css.cardFooter}>\n <span className={css.cardTop}>\n <a className={css.cardLink} href={plugin.repo} target=\"_blank\" rel=\"noreferrer\">{t('repository')}</a>\n <span className={css.cardActions}>\n <button\n type=\"button\"\n className={copied\n ? `${css.installButton} ${css.installButtonCopied}`\n : faceLoopback ? `${css.installButton} ${css.installButtonSecondary}` : css.installButton}\n title={command}\n onClick={() => { copyCommand(plugin.id, command) }}\n >\n {copied ? t('copied') : t('install')}\n </button>\n {faceLoopback && installedItem === null\n ? (\n <button\n type=\"button\"\n className={css.installButton}\n disabled={mutationsDisabled}\n onClick={() => { onInstall(plugin) }}\n >\n {isInstalling ? t('installing') : t('installNow')}\n </button>\n )\n : null}\n {faceLoopback && installedItem !== null\n ? (\n <button\n type=\"button\"\n className={`${css.installButton} ${css.installButtonSecondary}`}\n disabled={mutationsDisabled}\n onClick={() => { setUninstallTarget(plugin) }}\n >\n {isUninstalling ? t('uninstalling') : t('uninstall')}\n </button>\n )\n : null}\n </span>\n </span>\n {isInstalling\n ? (\n <p className={css.progress} role=\"status\">\n {progress !== null && progress.kind !== 'idle'\n ? t(`progress.${progress.stage}`)\n : t('installing')}\n </p>\n )\n : null}\n {error !== undefined ? <p className={css.error} role=\"alert\">{error}</p> : null}\n <code className={css.cardCommand} title={command}>{command}</code>\n </span>\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n : <p className={css.off} role=\"status\">{t('off')}</p>}\n {face === null\n ? <p className={css.installNote} role=\"note\">{t('managerHint')}</p>\n : face.isLoopback\n ? null\n : <p className={css.installNote} role=\"note\">{t('remoteHint')}</p>}\n <p className={css.installNote} role=\"note\">{t('installHint')}</p>\n <p className={css.notice} role=\"note\">{t('notice')}</p>\n <Modal\n open={uninstallTarget !== null}\n onClose={() => { if (pending === null) setUninstallTarget(null) }}\n title={t('uninstallConfirm.title')}\n closeLabel={t('cancel')}\n >\n <p className={css.confirmBody}>\n {t('uninstallConfirm.body', {\n name: uninstallTarget === null\n ? ''\n : entryCopy(t, `name.${uninstallTarget.id}`, uninstallTarget.nameEn || uninstallTarget.name),\n })}\n </p>\n <div className={css.modalActions}>\n <Button variant=\"outline\" disabled={pending !== null} onClick={() => { setUninstallTarget(null) }}>\n {t('cancel')}\n </Button>\n <Button variant=\"primary\" className={css.dangerButton} disabled={pending !== null} onClick={onUninstallConfirm}>\n {pending?.kind === 'uninstall' ? t('uninstalling') : t('uninstallConfirm.confirm')}\n </Button>\n </div>\n </Modal>\n </PluginSettingsCard>\n )\n}\n\n/** Props the settings section binds for the community plugin page. */\nexport type CommunityPluginsSectionProps =\n PropsRuntime<'settings.section'>\n & PropsLocale<'community-plugins'>\n & InjectFace<CommunityPluginsCardFace>\n & {\n /** Index entries; defaults to the generated registry (injected for tests). */\n plugins?: readonly CommunityPluginEntry[]\n /** Plugin-manager face override (injected for tests; undefined reads the bridge). */\n pluginManager?: PluginManagerService | null\n }\n\n/** Render the community plugin index as a first-level settings page. */\nexport function CommunityPluginsSection(props: CommunityPluginsSectionProps): ReactNode {\n const { t, useCommunityPluginsCard, save, discard, edit, resetField, plugins, pluginManager } = props\n return (\n <ul className={css.sectionList}>\n <CommunityPluginsCard t={t} useCommunityPluginsCard={useCommunityPluginsCard} save={save} discard={discard} edit={edit} resetField={resetField} plugins={plugins} pluginManager={pluginManager} />\n </ul>\n )\n}\n","/**\n * The community-plugins locale dictionaries for the index card. Static copy\n * for the card chrome plus one localized name/description pair per index\n * entry (`name.<id>` / `desc.<id>`), so the card localizes data-driven text\n * through the same `t` the rest of the settings UI uses — the document\n * `<html lang>` attribute is not a reliable locale signal in the GUI.\n */\n\nimport { COMMUNITY_PLUGINS } from './generated/community.ts'\n\n/** Simplified Chinese copy for the card chrome (the key-set source of truth). */\nconst STATIC_ZH = {\n 'settings.title': '社区插件',\n 'settings.description': '社区贡献者开发与维护的插件,链接指向作者自己的仓库。',\n 'settings.enabled': '启用社区插件索引',\n 'settings.enabledHint': '此开关只控制索引列表的显示与否,关闭后在这里重新打开。',\n 'settings.inherit': '继承',\n 'settings.on': '开',\n 'settings.off': '关',\n 'settings.overridden': '已覆盖',\n 'settings.reset': '恢复默认',\n 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。',\n 'settings.readOnly': '当前部署的设置只读。',\n 'settings.expand': '展开设置',\n 'settings.collapse': '收起设置',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.discard': '放弃',\n 'settings.unsaved': '未保存',\n 'settings.saveFailed': '部署未接受这些值,已保留供你修改。',\n 'settings.invalidNumber': '请输入数字,留空则使用默认值。',\n 'author': '作者',\n 'repository': '仓库',\n 'copy': '复制',\n 'copied': '已复制',\n 'install': '复制安装命令',\n 'installNow': '安装',\n 'installing': '安装中…',\n 'uninstall': '卸载',\n 'uninstalling': '卸载中…',\n 'cancel': '取消',\n 'badge.installed': '已安装 · 重启后生效',\n 'progress.fetch': '获取插件信息',\n 'progress.download': '下载中',\n 'progress.extract': '解压中',\n 'progress.write': '写入中',\n 'uninstallConfirm.title': '卸载插件',\n 'uninstallConfirm.body': '确定要卸载 {name} 吗?移除将在重启 dsh web 后完全生效。',\n 'uninstallConfirm.confirm': '确认卸载',\n 'installFailed': '安装失败:{reason}',\n 'uninstallFailed': '卸载失败:{reason}',\n 'managerHint': '未检测到「插件管理器」插件:安装 @linxin666/dsh-client-ui-plugin-manager 后,可在本机浏览器中直接从这里安装与卸载。',\n 'remoteHint': '当前是远程浏览器,界面内安装不可用;请在宿主机器的终端执行安装命令。',\n 'noMatch': '没有匹配的社区插件。',\n 'search.placeholder': '搜索名称、作者或简介',\n 'search.label': '搜索社区插件',\n 'filter.all': '全部',\n 'result.count': '显示 {shown} / {total} 个',\n 'badge.published': 'npm 已发布',\n 'badge.source': '仓库安装',\n 'category.ui': '界面与体验',\n 'category.agent': 'Agent 与自动化',\n 'category.tools': '开发者工具',\n 'category.knowledge': '记忆与知识',\n 'category.integration': '集成与分享',\n 'category.security': '安全与运维',\n 'category.utility': '实用工具',\n 'installHint': '在本机浏览器且已安装「插件管理器」插件时,可直接点击卡片上的「安装 / 卸载」;否则复制安装命令到终端执行。安装与卸载在重启 dsh web 后生效,插件自带的开关与配置(若有)会出现在插件配置里。',\n 'empty': '暂无社区插件登记。',\n 'off': '社区插件索引已关闭。',\n 'notice': '条目由贡献者自行登记,与 dsh-web-ui 的发布内容无关;使用前请自行评估。',\n} satisfies Record<string, string>\n\n/** English copy for the card chrome, checked complete against the zh key set. */\nconst STATIC_EN = {\n 'settings.title': 'Community Plugins',\n 'settings.description': \"Plugins developed and maintained by community contributors, linking to each author's own repository.\",\n 'settings.enabled': 'Enable the community plugin index',\n 'settings.enabledHint': 'This switch only controls whether the index list is shown; turn it back on here.',\n 'settings.inherit': 'Inherit',\n 'settings.on': 'On',\n 'settings.off': 'Off',\n 'settings.overridden': 'Overridden',\n 'settings.reset': 'Reset to default',\n 'settings.notExposed': \"This DSH version does not expose this plugin's settings namespace to the configuration page, so the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES allowlist and restart.\",\n 'settings.readOnly': 'This deployment stores settings read-only.',\n 'settings.expand': 'Show settings',\n 'settings.collapse': 'Hide settings',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.discard': 'Discard',\n 'settings.unsaved': 'Unsaved',\n 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'settings.invalidNumber': 'Enter a number, or leave blank to use the default.',\n 'author': 'Author',\n 'repository': 'Repository',\n 'copy': 'Copy',\n 'copied': 'Copied',\n 'install': 'Copy install command',\n 'installNow': 'Install',\n 'installing': 'Installing…',\n 'uninstall': 'Uninstall',\n 'uninstalling': 'Uninstalling…',\n 'cancel': 'Cancel',\n 'badge.installed': 'Installed · restart to take effect',\n 'progress.fetch': 'Fetching plugin info',\n 'progress.download': 'Downloading',\n 'progress.extract': 'Extracting',\n 'progress.write': 'Writing',\n 'uninstallConfirm.title': 'Uninstall plugin',\n 'uninstallConfirm.body': 'Uninstall {name}? The removal fully takes effect after restarting dsh web.',\n 'uninstallConfirm.confirm': 'Confirm uninstall',\n 'installFailed': 'Install failed: {reason}',\n 'uninstallFailed': 'Uninstall failed: {reason}',\n 'managerHint': 'The Plugin manager plugin is not detected: install @linxin666/dsh-client-ui-plugin-manager to install and uninstall entries directly from here in a local browser.',\n 'remoteHint': 'This is a remote browser, so in-GUI install is unavailable; run the install command in a terminal on the host machine.',\n 'noMatch': 'No matching community plugin found.',\n 'search.placeholder': 'Search name, author or description',\n 'search.label': 'Search community plugins',\n 'filter.all': 'All',\n 'result.count': 'Showing {shown} / {total}',\n 'badge.published': 'Published on npm',\n 'badge.source': 'Install from repo',\n 'category.ui': 'UI & Experience',\n 'category.agent': 'Agents & Automation',\n 'category.tools': 'Developer Tools',\n 'category.knowledge': 'Memory & Knowledge',\n 'category.integration': 'Integration & Sharing',\n 'category.security': 'Security & Ops',\n 'category.utility': 'Utilities',\n 'installHint': 'With the Plugin manager plugin present and a local browser, use the Install / Uninstall buttons on each card; otherwise copy the install command into a terminal. Installs and uninstalls take effect after restarting dsh web; once installed, the plugin provides its own switch and config (if any) in the plugin configuration section.',\n 'empty': 'No community plugins registered yet.',\n 'off': 'The community plugin index is turned off.',\n 'notice': 'Entries are contributed by their authors and are separate from dsh-web-ui releases; evaluate before use.',\n} satisfies Record<keyof typeof STATIC_ZH, string>\n\n/** Build the runtime dictionary: static copy plus one localized name/description pair per index entry. */\nfunction build(base: Record<string, string>, lang: 'zh' | 'en'): Record<string, string> {\n const dict: Record<string, string> = { ...base }\n for (const entry of COMMUNITY_PLUGINS) {\n dict[`name.${entry.id}`] = lang === 'zh' ? entry.name : entry.nameEn\n dict[`desc.${entry.id}`] = lang === 'zh'\n ? (entry.description ?? entry.descriptionEn ?? '')\n : (entry.descriptionEn ?? entry.description ?? '')\n }\n return dict\n}\n\n/** Simplified Chinese dictionary for the index card (chrome + per-entry copy). */\nexport const zh = build(STATIC_ZH, 'zh')\n\n/** English dictionary, built from the same key set. */\nexport const en = build(STATIC_EN, 'en')\n\n/** Key union for this namespace (chrome keys plus per-entry name/description keys). */\nexport type CommunityPluginKey = keyof typeof zh\n","/**\n * Community plugin index, browser half. Registers the community-plugins\n * dictionaries and one section into the settings panel's first-level nav\n * (settings.section; the promoted family sections sit beside the built-in\n * general / models / plugins / agent-presets entries). The card carries its\n * own enable switch (backed by the community-plugins settings namespace) and\n * lists community plugins with links to each contributor's own repository.\n * @module @linxin666/dsh-client-ui-community-plugins/client\n */\n\nimport type { ClientContext, SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the settings-surface Context merge (ctx.settingsScope).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the slot-surface types (the settings.section seat).\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { CommunityPluginsCardController, CommunityPluginsSection, type CommunityPluginsSettings } from './CommunityPluginsCard.tsx'\nimport { en, zh, type CommunityPluginKey } from './locales.ts'\nimport { bridgePluginManager } from './plugin-manager-bridge.ts'\n\nexport type { CommunityPluginsCardProps, CommunityPluginsSectionProps } from './CommunityPluginsCard.tsx'\nexport type { InstalledPluginItem, InstallProgressItem, PluginManagerService } from './plugin-manager-bridge.ts'\n\n/** Settings namespace the card's enable switch edits (the Host plugin registers it). */\nconst COMMUNITY_PLUGINS_NS = 'community-plugins'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Community plugin index card copy. */\n 'community-plugins': CommunityPluginKey\n }\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * Optional rc.6 compatibility binder provided by dsh-web-ui-settings;\n * absent when that group plugin is not installed, so callers fall back to\n * the official settings scope.\n */\n webUiSettings?: { bind<S>(spec: SettingsScopeSpec<S>): SettingsScope<S> }\n }\n}\n\n/** Required services. */\nexport const inject = ['slots', 'locale', 'connection', 'settingsScope', 'remote']\n\n/**\n * Register the community plugin index as a first-level settings section, with\n * its own enable switch over the community-plugins settings namespace.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register('community-plugins', { zh, en }), 'community-plugins: dictionaries')\n\n // Bridge the optional 'pluginManager' cordis service (provided by the\n // sibling dsh-plugin-manager plugin) into the card's reactive store. It is\n // deliberately NOT in the module-level inject array: when the sibling is\n // absent this plugin still loads and the card keeps its read-only index UI.\n bridgePluginManager(ctx)\n\n const binder = ctx.get('webUiSettings') ?? ctx.settingsScope\n const settingsScope = binder.bind<CommunityPluginsSettings>({ namespace: COMMUNITY_PLUGINS_NS })\n const controller = new CommunityPluginsCardController(settingsScope)\n\n ctx.slots.inject('settings.section', () => {\n const unregister = ctx.slots.register({\n name: 'settings.section',\n id: 'community-plugins',\n order: 140,\n label: () => ctx.locale.bind('community-plugins')('settings.title'),\n locale: 'community-plugins',\n inject: () => controller.inject(),\n }, CommunityPluginsSection)\n return () => {\n controller.dispose()\n unregister()\n }\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["css","css","Modal","Button"],"sources":["../../../packages/dsh-community-plugins/src/client/PluginSettingsCard.tsx","../../../packages/dsh-community-plugins/src/client/settings-form.ts","../../../packages/dsh-community-plugins/src/client/generated/community.ts","../../../packages/dsh-community-plugins/src/client/community-guard.ts","../../../packages/dsh-community-plugins/src/client/plugin-manager-bridge.ts","../../../packages/dsh-community-plugins/src/client/install-source.ts","../../../packages/dsh-community-plugins/src/client/CommunityPluginsCard.tsx","../../../packages/dsh-community-plugins/src/client/locales.ts","../../../packages/dsh-community-plugins/src/client/index.ts"],"sourcesContent":["// Generated by scripts/sync-shared.mjs from shared/client/settings/PluginSettingsCard.tsx. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family-shared chrome for plugin settings cards: a disclosure header naming\n * the plugin and what its settings govern, the controls inside, and the save\n * that writes them. Renders nothing while the namespace is unavailable — a\n * deployment that does not compose the owning plugin should show no trace of\n * it. Inlined into each consumer's client bundle; mirrors the official\n * ui-plugin-config PluginCard in a self-contained slice.\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'\nimport type { CardShell } from './settings-form.ts'\nimport css from './settings-card.module.css'\n\n/** Copy keys the card chrome itself reads; every consumer locale carries this shared vocabulary. */\nexport const CARD_COPY_KEYS = [\n 'settings.collapse',\n 'settings.expand',\n 'settings.notExposed',\n 'settings.unsaved',\n 'settings.readOnly',\n 'settings.saveFailed',\n 'settings.discard',\n 'settings.save',\n 'settings.saving',\n] as const\n\n/** Copy key the card chrome itself reads. */\nexport type CardCopyKey = (typeof CARD_COPY_KEYS)[number]\n\n/** Key domain for the plugin's own copy (inferred per consumer). */\nexport type SettingsCardKey<TKey extends string = string> = TKey | CardCopyKey\n\n/** Card chrome shared by every plugin settings card. */\nexport interface PluginSettingsCardProps<TKey extends string = string> {\n /** Locale reader for this card's copy. */\n t: (key: SettingsCardKey<TKey>, params?: Record<string, string | number>) => string\n /** Locale key of the plugin's name. */\n titleKey: TKey\n /** Locale key of the line describing what this plugin's settings govern. */\n descriptionKey: TKey\n /** The card's form state: availability, writability, and what a save would do. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /**\n * Render the controls expanded on arrival (still collapsible). Defaults to\n * true: promoted first-level sections show their settings immediately.\n */\n defaultOpen?: boolean\n /**\n * Render without the collapse affordance: a static header and an always\n * visible body. Used by first-level settings sections whose nav entry\n * already provides the selection.\n */\n alwaysOpen?: boolean\n /**\n * Hide the save/discard footer: cards whose body applies its own changes\n * immediately (an embedded external settings section) have no staged\n * edits, so the footer would sit there permanently disabled.\n */\n hideFooter?: boolean\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin settings card.\n * @param props - the plugin's copy keys, its form state, and its controls.\n * @returns the card, or nothing while the namespace is still loading.\n */\nexport function PluginSettingsCard<TKey extends string = string>(props: PluginSettingsCardProps<TKey>) {\n const [open, setOpen] = useState(props.defaultOpen ?? true)\n const { state, alwaysOpen } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const description = props.t(props.descriptionKey)\n const blocked = !state.dirty || state.invalid || state.saving\n const expanded = alwaysOpen === true || open\n const cardClass = expanded ? `${css.cardOpen} ${css.card}` : css.card\n // With alwaysOpen the nav entry already provides the selection, so the\n // header is a static title row instead of a disclosure button.\n const header = alwaysOpen === true\n ? (\n <div className={css.headerStatic}>\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n </div>\n )\n : (\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron}\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n )\n // The namespace exists but the Host does not serve it to this client (the\n // official settings allowlist omits third-party namespaces): show a card\n // that explains the gap instead of vanishing, so a missing card never\n // reads as a missing plugin.\n if (!state.exposed) {\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p>\n </div>\n )\n : null}\n </li>\n )\n }\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('settings.readOnly')}</p> : null}\n {props.children}\n {props.hideFooter === true\n ? null\n : (\n <div className={css.footer}>\n {state.failed\n ? (\n <p className={css.failed} role=\"status\">\n {props.t('settings.saveFailed')}{state.failedReason ? ' - ' + state.failedReason : ''}\n </p>\n )\n : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('settings.discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(!state.saving ? 'settings.save' : 'settings.saving')}\n </button>\n </div>\n )}\n </div>\n )\n : null}\n </li>\n )\n}\n\n/** Props every field control needs regardless of its value type. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation rendered under the control. */\n hint: string\n /** Draft text this control renders. */\n text: string\n /** True when saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** True when the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control (read-only document, or an unavailable namespace). */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing what the control accepts. */\n numeric?: boolean\n /** Placeholder shown while the draft is empty. */\n placeholder?: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\nconst NON_SKIN_BODY_MARKERS = new Set(['dshSkinCenter', 'dshSidebarCollapsed'])\n// 检测使用使用皮肤,用了皮肤退回原生select样式,防止样式冲突。默认外观下使用优化后的select样式。\nfunction isSkinActive(): boolean {\n const datasetList = Object.keys(document.body.dataset)\n const isActive = datasetList.some(key => key.startsWith('dsh') && !NON_SKIN_BODY_MARKERS.has(key))\n return isActive\n}\n\ninterface SelectOption {\n value: string\n label: string\n}\n\nconst SELECT_CLOSE_MS = 100\n\n/**\n * The shared dual-mode select control. While an appearance skin is active it\n * renders the legacy native `<select>` untouched, so element-level skin\n * selectors keep working; under the default appearance it renders a\n * self-drawn `role=\"listbox\"` popup whose open/close is transition-animated.\n * Staged cards reach it through BooleanField/ChoiceField; immediate-apply\n * editors (the side-card prefs) bind it directly through onEdit.\n * 双模式下拉框:皮肤激活时用原生 select,默认外观用自绘动画弹层。\n */\nexport function SelectField(props: {\n id: string\n options: ReadonlyArray<SelectOption>\n value: string\n disabled: boolean\n invalid: boolean\n onEdit: (text: string) => void\n}) {\n const { id, options, value } = props\n const [open, setOpen] = useState(false)\n const [closing, setClosing] = useState(false)\n const [phase, setPhase] = useState<'initial' | 'open'>('initial')\n const [activeIndex, setActiveIndex] = useState(0)\n const closeTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const popupRef = useRef<HTMLDivElement | null>(null)\n\n const currentIndex = () => {\n const index = options.findIndex(option => option.value === value)\n return index >= 0 ? index : 0\n }\n\n const close = useCallback(() => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setClosing(true)\n closeTimer.current = setTimeout(() => {\n setClosing(false)\n setOpen(false)\n }, SELECT_CLOSE_MS)\n }, [])\n\n const openPopup = () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setActiveIndex(currentIndex())\n setPhase('initial')\n setClosing(false)\n setOpen(true)\n }\n\n const commit = (index: number) => {\n const option = options[index]\n if (option) props.onEdit(option.value)\n close()\n }\n\n const onTriggerClick = () => {\n if (props.disabled) return\n if (open && !closing) close()\n else openPopup()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (props.disabled) return\n const count = options.length\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp':\n case 'Enter':\n case ' ':\n event.preventDefault()\n if (!open) {\n openPopup()\n } else if (!closing) {\n if (event.key === 'ArrowDown') setActiveIndex(index => (index + 1) % count)\n else if (event.key === 'ArrowUp') setActiveIndex(index => (index - 1 + count) % count)\n else commit(activeIndex)\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation()\n close()\n }\n break\n case 'Tab':\n if (open) close()\n break\n }\n }\n\n useEffect(() => () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n }, [])\n useLayoutEffect(() => {\n if (open && !closing && phase === 'initial') {\n void popupRef.current?.offsetHeight\n setPhase('open')\n }\n }, [open, closing, phase])\n\n useEffect(() => {\n if (!open) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target\n if (target instanceof Node && !wrapRef.current?.contains(target)) close()\n }\n document.addEventListener('pointerdown', onPointerDown)\n return () => document.removeEventListener('pointerdown', onPointerDown)\n }, [open, close])\n\n useEffect(() => {\n if (props.disabled && open) close()\n }, [props.disabled, open, close])\n\n // 使用了皮肤则退回原生select样式防止样式冲突。\n if (isSkinActive()) {\n return (\n <select\n id={id}\n className={css.select}\n value={value}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n {options.map(option => (\n <option key={option.value} value={option.value}>{option.label}</option>\n ))}\n </select>\n )\n }\n\n const label = options.find(option => option.value === value)?.label ?? ''\n const popupClass = closing\n ? `${css.selectPopup} ${css.selectPopupClose}`\n : phase === 'open'\n ? `${css.selectPopup} ${css.selectPopupOpen}`\n : css.selectPopup\n return (\n <div className={css.selectWrap} ref={wrapRef}>\n <button\n type=\"button\"\n id={id}\n className={`${css.select} ${css.selectButton}`}\n disabled={props.disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-activedescendant={open ? `${id}-o${activeIndex}` : undefined}\n aria-invalid={props.invalid || undefined}\n onClick={onTriggerClick}\n onKeyDown={onKeyDown}\n >\n <span className={css.selectLabel}>{label}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.selectChevron} ${css.selectChevronOpen}` : css.selectChevron}\n aria-hidden=\"true\"\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n {open\n ? (\n <div className={popupClass} role=\"listbox\" ref={popupRef}>\n {options.map((option, index) => (\n <div\n key={option.value}\n id={`${id}-o${index}`}\n role=\"option\"\n aria-selected={option.value === value}\n className={`${css.selectOption}${option.value === value ? ` ${css.selectOptionSelected}` : ''}${index === activeIndex && !closing ? ` ${css.selectOptionActive}` : ''}`}\n onClick={() => { commit(index) }}\n >\n {option.label}\n </div>\n ))}\n </div>\n )\n : null}\n </div>\n )\n}\n\n/** A staged boolean field: 继承 / 开 / 关. */\nexport function BooleanField(props: FieldProps & {\n /** Copy for the inherit option. */\n inheritLabel: string\n /** Copy for the on option. */\n onLabel: string\n /** Copy for the off option. */\n offLabel: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[\n { value: '', label: props.inheritLabel },\n { value: 'true', label: props.onLabel },\n { value: 'false', label: props.offLabel },\n ]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n\n/** A staged enumerated field rendered as a select. */\nexport function ChoiceField(props: FieldProps & {\n /** Copy for the inherit option (draft text is the empty string). */\n inheritLabel: string\n /** Choices rendered in order; `value` is the draft/stored text. */\n choices: ReadonlyArray<{ value: string; label: string }>\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[{ value: '', label: props.inheritLabel }, ...props.choices]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/settings-form.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Staged form model behind the plugin settings card. A card stages what the\n * user types and writes it only when they save — the settings write is a\n * durable, revision-fenced document mutation, so staging keeps what is on\n * screen exactly what a save would store. Family-shared slice inlined into\n * each plugin's client bundle; mirrors the official ui-plugin-config\n * card-store pattern.\n */\n\nimport type { SettingsScope, SettingsScopeSnapshot, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** How one field converts between its stored value and its draft text. */\nexport interface FieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /**\n * Whether the Host treats this field as a secret and redacts its value from\n * the read-back (role('secret') in the section schema). Redacted secrets are\n * never compared against the draft on save; the field lands when the scope\n * reports the write succeeded (its secret-set marker under the bridge), so\n * a successful secret save is not misreported as failed.\n */\n secret?: boolean\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/** One field as the card renders it. */\nexport interface FieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean\n}\n\n/** Form state every plugin settings card shares. */\nexport interface CardShell {\n /** False while the namespace is still loading; the card renders nothing. */\n available: boolean\n /**\n * Whether the namespace is actually served to this client. False when the\n * Host deployment does not expose it (e.g. the official apiproxy settings\n * allowlist omits third-party namespaces): the card renders an explanation\n * instead of its form, so a missing namespace never looks like a missing\n * plugin.\n */\n exposed: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits that a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean\n /**\n * The rejection code/message the Host returned for the last failed save,\n * surfaced next to the generic failure text. Undefined while no save has\n * failed (or the failure carried no server reason).\n */\n failedReason?: string\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean\n}\n\n/** One staged edit resolved into the write a save performs. */\ninterface PlannedWrite {\n /** Field this entry writes. */\n field: string\n /** The durable write this entry performs, described for a batched scope. */\n op: BatchedWrite\n /** Perform the write and report whether the Host holds the staged value afterwards. */\n run: (() => Promise<boolean>) | undefined\n}\n\n/** One durable write a batched settings scope performs. */\nexport interface BatchedWrite {\n /** Field this entry writes. */\n field: string\n /** set stores a value; unset drops the leaf. */\n op: 'set' | 'unset'\n /** Value for op set (absent for unset). */\n value?: unknown\n}\n\n/** Per-field outcome of one batched scope write. */\nexport interface BatchedFieldResult {\n /** Field this entry writes. */\n field: string\n /** Whether the Host accepted this field's write (per the read-back view). */\n landed: boolean\n}\n\n/**\n * Result of a batched scope write. The bridge scope posts every planned write\n * in one /mutate so the Host validate hook judges baseURL+model together; a\n * batched refusal fails the whole save rather than per-field.\n */\nexport interface BatchResult {\n /** Whether the whole mutate was accepted. */\n ok: boolean\n /** Per-field success, in the request order (always present when ok). */\n fields: BatchedFieldResult[]\n /** Host rejection code (mutate refused). */\n code?: string\n /** Host rejection message (mutate refused). */\n message?: string\n}\n\n/** The optional batch surface the bridge scope adds over the SettingsScope contract. */\ninterface BatchedSettingsScope {\n /** Write every operation in one scope mutation, reporting per-field success. */\n mutate: (writes: BatchedWrite[]) => Promise<BatchResult>\n}\n\n/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */\nexport interface NumberConstraints {\n /** The accepted value must be a whole number. */\n integer?: boolean\n /** The accepted value must be at least this. */\n min?: number\n}\n\n/** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */\nexport function numberField(field: string, constraints: NumberConstraints = {}): FieldSpec {\n const { integer = false, min } = constraints\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return undefined\n if (integer && !Number.isInteger(parsed)) return undefined\n if (min !== undefined && parsed < min) return undefined\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/** A free-text field. An empty draft clears the field. */\nexport function textField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A free-text field the Host treats as a secret and redacts from the read-back\n * (role('secret') in the section schema). The card still edits it like text,\n * but a save never compares the redacted value back and relies on the scope\n * reporting the write landed.\n */\nexport function secretField(field: string): FieldSpec {\n return { ...textField(field), secret: true }\n}\n\n/** A boolean field, edited through true/false draft text. */\nexport function booleanField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'boolean' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return undefined\n },\n }\n}\n\n/** An enumerated string field; only the listed choices are accepted. An empty draft clears the field. */\nexport function choiceField(field: string, choices: readonly string[]): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' && choices.includes(value) ? value : '',\n parse: (text) => {\n if (text === '') return { kind: 'clear' }\n return choices.includes(text) ? { kind: 'set', value: text } : undefined\n },\n }\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted — its\n * validators own the constraints no schema can express — so the outcome is\n * read back from the section rather than predicted here. A save that did not\n * land keeps its drafts, so the user can correct them instead of retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, FieldSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n /** The scope subscription installed in the constructor; released by dispose(). */\n private readonly disposeScope: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound settings scope for this card's namespace. */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeScope = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the scope subscription and every bound store listener. The card\n * must call this on teardown; later calls are no-ops.\n */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.disposeScope()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status !== 'loading',\n exposed: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n ...this.failedReason === undefined ? {} : { failedReason: this.failedReason },\n }\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): FieldState {\n const spec = this.specOf(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.failedReason = undefined\n this.publish()\n },\n }\n }\n\n /**\n * Write every staged edit, then re-seed from what the Host accepted.\n *\n * When the scope carries the optional batch surface (the dsh-web-ui\n * bridge scope), every planned write rides one mutation so cross-field\n * validate hooks (baseURL+model) judge the batch as a unit instead of\n * deadlocking on per-field writes. Otherwise the per-field loop runs.\n * A field lands only when the Host reports it held the staged value; a\n * landed field's draft is dropped, a failed one stays staged for the user.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter(item => item.run !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n const plannedWrites = valid.map(item => item.op)\n // Snapshot the staged entries this save writes, so an edit staged while it\n // is in flight (which replaces the same key) survives: only delete the key\n // when the entry is still the one this save started from.\n const pending = new Map<string, StagedEdit | undefined>()\n for (const item of plan) pending.set(item.field, this.staged.get(item.field))\n this.saving = true\n this.failed = false\n this.failedReason = undefined\n this.publish()\n const landed = new Set<string>()\n const batch = this.batchedScope()\n if (batch !== undefined) {\n const result = await batch.mutate(plannedWrites)\n if (result.ok) {\n for (const field of result.fields) {\n if (field.landed) landed.add(field.field)\n }\n } else {\n this.failedReason = result.message\n }\n } else {\n for (const item of valid) {\n if (await item.run!()) landed.add(item.field)\n }\n }\n for (const [field, before] of pending) {\n if (landed.has(field) && this.staged.get(field) === before) this.staged.delete(field)\n }\n this.saving = false\n this.failed = landed.size !== pending.size\n this.publish()\n }\n\n /** The scope's batch surface when it supports one; undefined conservatively otherwise. */\n private batchedScope(): BatchedSettingsScope | undefined {\n const candidate = this.scope as unknown as BatchedSettingsScope | undefined\n return typeof candidate?.mutate === 'function' ? candidate : undefined\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n * @returns the planned writes, in the order the fields were staged.\n */\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, op: { field, op: 'unset' }, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n // A redacted secret never appears in the user layer read-back; judging it\n // by value would misreport a successful secret save as failed. The bridge\n // reports secret writes through its secret-set markers (batch path); on\n // the per-field path the scope resolved, so the write is landed.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.failedReason = undefined\n this.publish()\n }\n\n private specOf(field: string): FieldSpec {\n const spec = this.specs.get(field)\n // Every call site names a field this card declared; a missing one is a\n // wiring mistake that must not degrade into a silently inert control.\n if (spec === undefined) throw new Error(`settings card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): SettingsScopeSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * AUTO-GENERATED by scripts/community-index — do not edit by hand.\n * Community plugin index for the settings page: every entry links to the\n * contributor's own repository. This repository never vendors the listed\n * plugins — it only points users at them.\n * Regenerate with `node scripts/community-index`.\n */\n\n/** Stable category ids rendered as marketplace-style filter pills (the runtime guard imports this). */\nexport const COMMUNITY_CATEGORIES = ['ui', 'agent', 'tools', 'knowledge', 'integration', 'security', 'utility'] as const\n\n/** One category id. */\nexport type CommunityPluginCategory = typeof COMMUNITY_CATEGORIES[number]\n\n/** One community plugin entry: contributor metadata plus the repository link. */\nexport interface CommunityPluginEntry {\n /** Stable entry id (unique in community.json). */\n id: string\n /** Display name (zh). */\n name: string\n /** Display name (en). */\n nameEn: string\n /** Contributor (GitHub user or organization). */\n author: string\n /** One-line description (zh). */\n description?: string\n /** One-line description (en). */\n descriptionEn?: string\n /** The contributor's own repository URL. */\n repo: string\n /** npm package name, when the plugin is published there. */\n npm?: string\n /** Category id for the marketplace filter pills. */\n category?: CommunityPluginCategory\n}\n\n/** Every community plugin, in community.json order. */\nexport const COMMUNITY_PLUGINS: readonly CommunityPluginEntry[] = [\n {\"id\":\"dsh-data-agent\",\"name\":\"Data Agent\",\"nameEn\":\"Data Agent\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-data-agent\",\"description\":\"为 DSH 定义专用 Data Agent 预设,让 AI 帮你查询、更新、分析数据。\",\"descriptionEn\":\"Defines a dedicated Data Agent preset for DSH so the AI can query, update and analyze data.\",\"category\":\"agent\"},\n {\"id\":\"dsh-tui\",\"name\":\"dsh-TUI\",\"nameEn\":\"dsh-TUI\",\"author\":\"ccch1mneyyy\",\"repo\":\"https://github.com/ccch1mneyyy/dsh-TUI\",\"description\":\"Claude Code 风格全屏交互终端插件:像素鲸鱼顶栏、实时工作状态行、思考流式展开、双击 Esc 回滚、上下文进度条与 TPS 仪表。\",\"descriptionEn\":\"A Claude Code style fullscreen interactive terminal plugin: pixel-whale header, live working-state line, streaming reasoning expansion, double-Esc rollback, context progress bar and TPS gauges.\",\"category\":\"ui\"},\n {\"id\":\"dsh-tianshu-tui\",\"name\":\"天书 TUI\",\"nameEn\":\"Tianshu TUI\",\"author\":\"huiliyi37\",\"repo\":\"https://github.com/huiliyi37/dsh-tianshu-tui\",\"description\":\"基于官方 DeepSeek Harness 的交互式终端 UI 插件,在官方基础上增加 TDD 与证据门等工作流。\",\"descriptionEn\":\"An interactive terminal UI plugin for DeepSeek Harness that adds TDD and evidence-gate workflows on top of the official base.\",\"category\":\"ui\"},\n {\"id\":\"dsh-chat-summary\",\"name\":\"Chat Summary\",\"nameEn\":\"Chat Summary\",\"author\":\"v833\",\"repo\":\"https://github.com/v833/dsh-chat-summary\",\"description\":\"总结当前对话并导出为 Markdown / DOCX / PDF,可选 LLM 智能总结(用户自配 API Key)。\",\"descriptionEn\":\"Summarize the current conversation and export it as Markdown / DOCX / PDF, with optional LLM summarization using your own API key.\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-builtin-toggles\",\"name\":\"内置能力检查器\",\"nameEn\":\"Built-in Capability Inspector\",\"author\":\"Starfie1d1272\",\"repo\":\"https://github.com/Starfie1d1272/dsh-builtin-toggles\",\"description\":\"Evidence-backed 内置 capability Inspector:展示 DSH Web built-in capability 的 provenance、compatibility 与 structural drift;仅对 9 个经过审阅的 UI leaves 提供 fail-closed 开关。\",\"descriptionEn\":\"Evidence-backed built-in capability Inspector: surfaces provenance, compatibility and structural drift of DSH Web built-ins, with fail-closed toggles for only the nine reviewed UI leaves.\",\"npm\":\"dsh-builtin-toggles\",\"category\":\"tools\"},\n {\"id\":\"dsh-pilot\",\"name\":\"Pilot 浏览器驾驶舱\",\"nameEn\":\"Pilot Browser Cockpit\",\"author\":\"guo6x\",\"repo\":\"https://github.com/guo6x/dsh-pilot\",\"description\":\"给 agent 一双会开车的手:零依赖 CDP 浏览器操控(8 个 pilot_* 工具:导航/点击/输入/按键/JS/截图)+ Web GUI 可拖拽驾驶舱面板,无需 Playwright、无需 API key。\",\"descriptionEn\":\"Give your agent hands: zero-dependency CDP browser control (8 pilot_* tools: navigate/click/type/keys/eval/screenshot) plus a draggable cockpit panel in the Web GUI - no Playwright, no API key.\",\"category\":\"tools\"},\n {\"id\":\"dsh-housekeeper\",\"name\":\"环境管家\",\"nameEn\":\"Environment Housekeeper\",\"author\":\"guo6x\",\"repo\":\"https://github.com/guo6x/dsh-housekeeper\",\"description\":\"管住 agent 的脏手:工具链台账(node/pnpm/git/gh/ffmpeg 等自动探测)、缓存与临时目录扫描 + 白名单安全一键清理、机器规则 AGENTS.md 查看编辑,全在设置面板完成。\",\"descriptionEn\":\"Keep your agent's hands clean: toolchain inventory, scratch/cache scan with whitelist-guarded one-click cleanup, and the machine rules file (AGENTS.md) view/edit - all in the settings panel.\",\"category\":\"utility\"},\n {\"id\":\"dsh-deepread\",\"name\":\"DeepRead 精读助手\",\"nameEn\":\"DeepRead Assistant\",\"author\":\"xiehuan123\",\"repo\":\"https://github.com/xiehuan123/dsh-deepread\",\"description\":\"五种模式精读插件(quick / deep / map / feynman / book),支持公众号链接与文件输入、批量对比、预算预检与后台任务进度透明,导出 md / mm / html,Web UI 提供工具结果卡片与精读面板。\",\"descriptionEn\":\"A five-mode deep reading plugin (quick / deep / map / feynman / book) for links and files, with batch comparison, budget preflight, transparent background-job progress, md / mm / html exports, and Web UI tool-result cards plus a reading panel.\",\"npm\":\"dsh-deepread\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-mnemon\",\"name\":\"Mnemon 记忆系统\",\"nameEn\":\"Mnemon Memory\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-mnemon\",\"description\":\"与 Mnemon CLI 集成的跨 Agent、本地优先持久记忆插件:用户画像 / 工作记忆 / 项目档案与长期 Memory Spaces,支持导入导出。\",\"descriptionEn\":\"A cross-agent, local-first persistent memory plugin integrating the Mnemon CLI: profiles, working memory, project documents and long-term Memory Spaces, with import and export.\",\"npm\":\"dsh-mnemon\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-plugin-hub\",\"name\":\"插件中心(dsh-plugin-hub)\",\"nameEn\":\"Plugin Hub\",\"author\":\"Noob-stupid\",\"repo\":\"https://github.com/Noob-stupid/dsh-plugin-hub\",\"description\":\"插件管理面板:已安装插件一键启用/停用,内置 GitHub dsh-plugin 插件市场(官方/聚合识别、子包浏览、一键安装与本地 AI 兜底修复、删除卸载),版本检测与一键更新、框架一键升级。\",\"descriptionEn\":\"Plugin management panel: one-click enable/disable, a GitHub dsh-plugin marketplace with official/aggregate detection, subpackage browsing, one-click installs with local-AI fallback repair, uninstall, update detection and one-click framework upgrade.\",\"npm\":\"@noob-stupid/dsh-plugin-console\",\"category\":\"tools\"},\n {\"id\":\"dsh-genui\",\"name\":\"GenUI 生成式 UI\",\"nameEn\":\"GenUI\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-genui\",\"description\":\"给模型输出配交互式 UI:助手回复内联渲染 dsh-ui 围栏(布局、图表、表格、表单、Mermaid、3D、原生音视频),双通道渲染兼容原版 DSH 与新构建,支持流式渲染、面板停靠与组件交互回传模型。\",\"descriptionEn\":\"Interactive UI inside assistant replies via the dsh-ui fence: layouts, charts, tables, forms, quizzes, Mermaid, 3D and native audio/video. Dual-channel rendering covers stock DSH and newer builds, with streaming render, panel docking and component actions that loop back to the model.\",\"category\":\"ui\"},\n {\"id\":\"dsh-annotation\",\"name\":\"选中批注\",\"nameEn\":\"Selection Annotation\",\"author\":\"omdsh-dev\",\"repo\":\"https://github.com/omdsh-dev/dsh-annotation\",\"description\":\"选中助手文字即可批注,回车随消息发送;自己的气泡只显示问题与「批注 ×N」标签,模型按 Annotation N 逐条对照回复(悬浮芯片);UI 与批注块跟随 DSH 语言切换 zh/en,Cmd/Ctrl+Enter 可直发纯批注,斜杠命令原样放行。\",\"descriptionEn\":\"Select text in an assistant reply to annotate it; annotations ride along with your next message, hidden in your own bubble behind an Annotations xN chip, and the model replies per Annotation N with hoverable chips. UI and annotation block follow the DSH locale (zh/en); Cmd/Ctrl+Enter sends annotations alone; slash commands pass through.\",\"category\":\"ui\"},\n {\"id\":\"deepseek-harness-auth\",\"name\":\"DeepSeek Harness Auth\",\"nameEn\":\"DeepSeek Harness Auth\",\"author\":\"taichuy\",\"repo\":\"https://github.com/taichuy/deepseek-harness-auth\",\"description\":\"为 DSH Web 公网部署提供登录认证前置代理,支持账号密码、验证码、失败锁定和 IP/CIDR 白名单。\",\"descriptionEn\":\"An authentication proxy for public DSH Web deployments with password login, captcha, failed-attempt locking, and IP/CIDR allowlists.\",\"npm\":\"deepseek-harness-auth\",\"category\":\"security\"},\n {\"id\":\"dsh-cloud-sync\",\"name\":\"云同步服务\",\"nameEn\":\"Cloud Sync\",\"author\":\"dickpy\",\"repo\":\"https://github.com/dickpy/dsh-cloud-sync\",\"description\":\"支持 WebDAV、S3、阿里云 OSS、腾讯云 COS 与 MinIO 的 DSH 云同步插件,可同步 profile、插件配置及本地插件源码归档。\",\"descriptionEn\":\"DSH cloud sync for WebDAV, S3, Alibaba Cloud OSS, Tencent Cloud COS and MinIO, syncing profiles, plugin settings and local plugin source archives.\",\"npm\":\"@dickpy/dsh-cloud-sync\",\"category\":\"integration\"},\n {\"id\":\"dsh-auto-memory\",\"name\":\"自动记忆\",\"nameEn\":\"Auto Memory\",\"author\":\"Aik358\",\"repo\":\"https://github.com/Aik358/dsh-auto-memory\",\"description\":\"三层自动记忆插件:用户级/项目笔记/每日日志自动注入与检索、每轮自动沉淀、AI 时段问候、智能检索、日历与工作区思维导图,支持继承 WorkBuddy/CodeBuddy/Claude Code/Codex 等其他 AI 工具的记忆。\",\"descriptionEn\":\"Three-layer auto memory for DSH: user-level/project-notes/daily-logs with automatic injection and retrieval, per-turn auto-consolidation, AI greetings, smart search, calendar, workspace mind map, and inheritance from WorkBuddy/CodeBuddy/Claude Code/Codex.\",\"npm\":\"@a9i5k4/dsh-auto-memory\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-memoir\",\"name\":\"项目记忆 Memoir\",\"nameEn\":\"Project Memory Memoir\",\"author\":\"Qinling-Melon-Farmers\",\"repo\":\"https://github.com/Qinling-Melon-Farmers/dsh-memoir\",\"description\":\"项目持久化记忆与会话经验沉淀:memoir_record / memoir_read 工具(BM25 相关度排序检索)、每轮工作自动蒸馏、记忆诊断面板与跨项目全局检索,纯本地零外部依赖。\",\"descriptionEn\":\"Project persistent memory and session-lessons distillation: memoir_record / memoir_read tools with BM25-ranked retrieval, per-turn auto-distill, a memory diagnostics panel and cross-project search - fully local, no external dependency.\",\"npm\":\"dsh-memoir\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-worktime-board\",\"name\":\"牛马修仙看板\",\"nameEn\":\"Worktime Cultivation Board\",\"author\":\"spacexun2\",\"repo\":\"https://github.com/spacexun2/dsh-worktime-board\",\"description\":\"DeepSeek Harness 工时统计 × 修仙养成:日/周/月/学年四档汇总 agent 活跃时长、token、输入与工具调用,十二重境界(炼气→宇宙洪荒)量化进度,纯本地存储。\",\"descriptionEn\":\"Worktime statistics meets cultivation: daily / weekly / monthly / yearly agent activity, token, input and tool-call summaries with a twelve-realm progression (Qi Refining to Cosmic Chaos), fully local.\",\"npm\":\"dsh-worktime-board\",\"category\":\"utility\"},\n {\"id\":\"dsh-skill-explorer\",\"name\":\"技能中心(Skill Explorer)\",\"nameEn\":\"Skill Explorer\",\"author\":\"wingsky-1\",\"repo\":\"https://github.com/wingsky-1/dsh-skill-explorer\",\"description\":\"DSH 技能中心:按来源分级浏览已加载 skill(系统内置 / 项目 / 用户 / 自定义 / 运行时),支持启用/禁用、创建与删除(移入 .trash)。\",\"descriptionEn\":\"DSH skill center: browse loaded skills grouped by source (bundled / project / user / custom / runtime), with enable/disable, create and delete (move to .trash).\",\"npm\":\"@linxin666/dsh-client-ui-skill-explorer\",\"category\":\"tools\"},\n {\"id\":\"dsh-friendly-steps\",\"name\":\"过程精简 Friendly Steps\",\"nameEn\":\"Friendly Steps\",\"author\":\"dongwenxiu83-web\",\"repo\":\"https://github.com/dongwenxiu83-web/dsh-friendly-steps\",\"description\":\"面向文字工作者的过程精简:纯 CSS 折叠 Think / 工具调用等技术过程行,右下角浮条「已完成 N 步」一键展开收起,失败步骤红色计数反馈;不注入 React 列表、无全量扫描,零侵入。\",\"descriptionEn\":\"Writer-friendly process collapse: hides Think / tool-call rows via pure CSS behind a floating 'N steps done' pill with red failure counts and one-click expand/collapse. No foreign nodes in React lists, no full-DOM scans — zero interference.\",\"category\":\"ui\"},\n {\"id\":\"dsh-full-remote\",\"name\":\"全功能远程访问\",\"nameEn\":\"Full Remote Access\",\"author\":\"JUANWANG-BUAA\",\"repo\":\"https://github.com/JUANWANG-BUAA/dsh-full-remote\",\"description\":\"令牌门控反向代理:公网隧道或局域网下,在手机等设备上远程使用 DeepSeek Harness,设置、凭据与文件访问保持可用,支持按设备会话。\",\"descriptionEn\":\"Token-gated reverse proxy for remote access: use DeepSeek Harness over public tunnels or LAN from phones and other devices, with settings, credentials and file access kept working and per-device sessions.\",\"npm\":\"dsh-full-remote\",\"category\":\"integration\"},\n {\"id\":\"dsh-palate\",\"name\":\"Palate 品味训练\",\"nameEn\":\"Palate Design Taste\",\"author\":\"guo6x\",\"repo\":\"https://github.com/guo6x/dsh-palate\",\"description\":\"会长大的眼:可积累的设计品味语料库(好/坏例子 + 编码原则),喂得越多评审越准;6 个 palate_* 工具(review/add/learn/list/principles/stats)+ 成长面板,node:sqlite + 人可读 Markdown 镜像,零运行时依赖。\",\"descriptionEn\":\"An eye that grows: an accumulated design-taste corpus (good/bad examples plus codified principles) that sharpens with every example you feed; six palate_* tools (review/add/learn/list/principles/stats) plus a growth panel, node:sqlite with human-readable Markdown mirrors, zero runtime dependencies.\",\"category\":\"knowledge\"},\n {\"id\":\"dsh-archive-manager\",\"name\":\"归档管理\",\"nameEn\":\"Archive Manager\",\"author\":\"z953218350\",\"repo\":\"https://github.com/z953218350/dsh-archive-manager\",\"description\":\"设置页 Codex 风格会话归档管理:按项目分组、搜索筛选、预览对话内容、一键恢复与彻底物理删除,内置 zstd 解压引擎。\",\"descriptionEn\":\"Codex-style archived session manager in settings: group by project, search and filter, preview conversation history, restore to sidebar, and permanently delete from disk; built-in zstd decompression.\",\"npm\":\"@mlgbnb/dsh-archive-manager\",\"category\":\"utility\"},\n {\"id\":\"dsh-history-tree\",\"name\":\"历史树\",\"nameEn\":\"History Tree\",\"author\":\"z953218350\",\"repo\":\"https://github.com/z953218350/dsh-history-tree\",\"description\":\"在聊天消息左侧提供 Codex 风格对话轮次时间线点阵与悬浮历史概览卡片,支持鱼眼放大动效与点击直达对应轮次。\",\"descriptionEn\":\"Codex-style conversation turn timeline rail and hover overview cards beside chat messages, with fish-eye magnification and click-to-jump navigation.\",\"npm\":\"dsh-history-tree\",\"category\":\"ui\"},\n {\"id\":\"dsh-gzip\",\"name\":\"dsh-gzip\",\"nameEn\":\"dsh-gzip\",\"author\":\"wingsky-1\",\"repo\":\"https://github.com/wingsky-1/dsh-plugin-hub/tree/main/packages/dsh-gzip\",\"description\":\"/api 响应 gzip 压缩插件:为远程 / 低带宽链路开启 /api 响应压缩,解决会话历史因大响应无压缩而超时加载失败的问题;SSE / zip / 已编码响应自动豁免,无全局副作用。\",\"descriptionEn\":\"API response gzip plugin for DSH Web GUI: enables gzip on /api responses for remote / low-bandwidth links, fixing session-history loads that fail on the timeout of large uncompressed responses; SSE, zip and already-encoded responses are passed through untouched, with no global side effects.\",\"npm\":\"@wingsky-1/dsh-gzip\"},\n {\"id\":\"dsh-wsl-bridge\",\"name\":\"WSL Windows 桥\",\"nameEn\":\"WSL Windows Bridge\",\"author\":\"ch1bug\",\"repo\":\"https://github.com/ch1bug/dsh-wsl-bridge\",\"description\":\"让 WSL 里的 agent 访问 Windows 侧:读写 C:\\\\ 文件、运行 .exe、Explorer 打开、wslpath 路径互转与盘符枚举(win_ls/read/write/run/open/path/drives)。\",\"descriptionEn\":\"Lets a WSL agent reach the Windows host: read/write C:\\\\ files, run .exe programs, open in Explorer, convert paths via wslpath and list drives (win_ls/read/write/run/open/path/drives).\",\"category\":\"integration\"},\n {\"id\":\"dsh-mimo-agent-tools\",\"name\":\"MiMo 多模态工具\",\"nameEn\":\"MiMo Multimodal Tools\",\"author\":\"ch1bug\",\"repo\":\"https://github.com/ch1bug/dsh-mimo-agent-tools\",\"description\":\"把小米 MiMo API 封装为 agent 工具:联网搜索、图像/音频/视频理解、语音转写、语音合成与音色克隆(mimo_search/vision/audio/video/asr/tts/voiceclone)。\",\"descriptionEn\":\"Turns the Xiaomi MiMo API into agent tools: web search, image/audio/video understanding, speech-to-text, text-to-speech and voice cloning (mimo_search/vision/audio/video/asr/tts/voiceclone).\",\"category\":\"tools\"},\n {\"id\":\"dsh-skill-fuzzy\",\"name\":\"技能模糊搜索\",\"nameEn\":\"Skill Fuzzy Search\",\"author\":\"ch1bug\",\"repo\":\"https://github.com/ch1bug/dsh-skill-fuzzy\",\"description\":\"Codex 风格模糊技能搜索:/bug、/diag、/regression 都能在 / 技能菜单里命中 diagnosing-bugs(名称子序列 + 描述连续子串匹配)。\",\"descriptionEn\":\"Codex-style fuzzy skill search: /bug, /diag and /regression all find diagnosing-bugs in the / skill menu (name subsequence + description substring matching).\",\"category\":\"ui\"},\n {\"id\":\"dsh-secret-redactor\",\"name\":\"敏感信息脱敏\",\"nameEn\":\"Secret Redactor\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-secret-redactor\",\"description\":\"自动掩码工具输出中的 API key、token、JWT、私钥与配置密钥。\",\"descriptionEn\":\"Auto-masks API keys, tokens, JWTs and private keys in tool results shown to the model.\"},\n {\"id\":\"dsh-approve-for-me\",\"name\":\"自动审批审核\",\"nameEn\":\"Approve for Me\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-approve-for-me\",\"description\":\"只读工具自动放行、危险命令自动拒绝,可配置全自动模式。\",\"descriptionEn\":\"Auto-approves read-only tools, auto-denies dangerous commands, optional full-auto mode.\"},\n {\"id\":\"dsh-mcp-client-v2\",\"name\":\"MCP 客户端 v2\",\"nameEn\":\"MCP Client v2\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-mcp-client-v2\",\"description\":\"MCP 客户端增强:分页工具发现、非阻塞启动、工具搜索。\",\"descriptionEn\":\"Enhanced MCP client: paginated tool discovery, non-blocking startup, tool search.\"},\n {\"id\":\"dsh-memories\",\"name\":\"项目记忆\",\"nameEn\":\"Project Memories\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-memories\",\"description\":\"按项目作用域持久化的键值记忆,支持增删查列与搜索。\",\"descriptionEn\":\"Project-scoped persistent key-value memories with set/get/list/delete/search.\"},\n {\"id\":\"dsh-system-proxy\",\"name\":\"系统代理\",\"nameEn\":\"System Proxy\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-system-proxy\",\"description\":\"检测系统代理(scutil/环境变量/PAC)并为子进程导出代理环境变量。\",\"descriptionEn\":\"Detects system proxy (scutil/env/PAC) and exports proxy env for child processes.\"},\n {\"id\":\"dsh-usage-cost\",\"name\":\"用量成本提醒\",\"nameEn\":\"Usage & Cost\",\"author\":\"DamonKoy\",\"repo\":\"https://github.com/DamonKoy/dsh-plugins/tree/main/packages/dsh-usage-cost\",\"description\":\"统计会话与每日 token 用量和估算成本,超预算提醒。\",\"descriptionEn\":\"Tracks token usage and estimated cost per session/day with budget alerts.\"},\n {\"id\":\"dsh-notifier\",\"name\":\"dsh-notifier\",\"nameEn\":\"dsh-notifier\",\"author\":\"wingsky-1\",\"repo\":\"https://github.com/wingsky-1/dsh-plugin-hub/tree/main/packages/dsh-notifier\",\"description\":\"审批/完成/错误事件通知:浏览器 Notification + 系统原生 toast(Windows PowerShell WinRT / Linux·macOS notify-send,零依赖);提示音可配、错误同类合并、免打扰时段、通知历史与配置面板;非安全上下文自动降级横幅。\",\"descriptionEn\":\"Approval / completion / error event notifications: browser Notification API plus native OS toasts (Windows PowerShell WinRT, Linux and macOS notify-send, zero dependencies); configurable sound, error merging, quiet hours, notification history and a settings panel; falls back to in-page banners outside secure contexts.\",\"npm\":\"@wingsky-1/dsh-notifier\",\"category\":\"utility\"},\n {\"id\":\"dsh-logicprobe\",\"name\":\"逻辑探针\",\"nameEn\":\"Logic Probe\",\"author\":\"AmethystLuna\",\"repo\":\"https://github.com/AmethystLuna/logicprobe\",\"description\":\"AI 智能体声明核查技能:枚举设计文档与重构计划中的每个可验证声明,对照代码库事实逐条核验;行为类声明升级为逻辑原语验证(7 项结构检查 + 7 项对抗探针),重构前后模型对比做回归检测,输出 file:line 证据。\",\"descriptionEn\":\"Claim verification for AI coding agents: enumerate every verifiable claim in design docs and refactoring plans, verify against codebase facts, then escalate behavioral claims to logic-primitive verification (7 structural checks + 7 adversarial probes), with before/after model comparison for refactoring regression detection.\",\"category\":\"tools\"},\n {\"id\":\"dsh-chatgpt-subscription\",\"name\":\"子代理管理\",\"nameEn\":\"Subagent Management\",\"author\":\"Aa728848\",\"repo\":\"https://github.com/Aa728848/dsh-chatgpt-subscription\",\"description\":\"让 DSH 通过 ChatGPT 订阅使用 GPT 系列模型:PKCE OAuth 登录、DPAPI/钥匙串/0600 凭据存储、流式 Responses、图片生成、Codex 搜索、额度展示与子代理管理。\",\"descriptionEn\":\"Use GPT models in DSH through your ChatGPT subscription: PKCE OAuth login, DPAPI/keychain/0600 credential storage, streaming Responses, image generation, Codex search, quota display and subagent management.\",\"npm\":\"@eddyskywalker/dsh-chatgpt-subscription\",\"category\":\"integration\"},\n {\"id\":\"dsh-imagegen\",\"name\":\"AI 生图\",\"nameEn\":\"AI ImageGen\",\"author\":\"dickpy\",\"repo\":\"https://github.com/dickpy/dsh-imagegen\",\"description\":\"AI 生图插件:通过可配置的 OpenAI 兼容端点(gpt-image-2 / gpt-image-1 / dall-e-3)实现文生图与图生图,提供生成历史、提示词模板库与 API 设置卡片。\",\"descriptionEn\":\"AI image generation for the DSH Web GUI: text-to-image and image-to-image through a configurable OpenAI-compatible endpoint (gpt-image-2 / gpt-image-1 / dall-e-3), with generation history, a prompt template library and an API settings card.\",\"npm\":\"@dickpy/dsh-imagegen\",\"category\":\"tools\"},\n]\n","/**\n * Runtime guard for the generated community index entries. The index is\n * build-time generated data, but the card renders whatever the module\n * carries; a hand-written narrowing keeps one malformed entry from breaking\n * the whole list at render time.\n */\n\nimport { COMMUNITY_CATEGORIES, type CommunityPluginCategory, type CommunityPluginEntry } from './generated/community.ts'\n\n/** Category ids the card knows how to label; others are treated as uncategorized. */\nconst KNOWN_CATEGORIES: readonly CommunityPluginCategory[] = COMMUNITY_CATEGORIES\n\n/**\n * The install command is pasted into a shell, so repo/npm must be free of\n * shell metacharacters: repo is a plain https URL of path-safe characters,\n * npm a standard (optionally scoped) package name.\n */\nconst REPO_SAFE_RE = /^https:\\/\\/[A-Za-z0-9._~\\/-]+$/\nconst NPM_SAFE_RE = /^(@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/\n\n/** True when the value is a well-formed community plugin entry. */\nexport function isCommunityPluginEntry(value: unknown): value is CommunityPluginEntry {\n if (typeof value !== 'object' || value === null) return false\n const entry = value as Record<string, unknown>\n if (typeof entry.id !== 'string' || entry.id === '') return false\n if (typeof entry.name !== 'string' || typeof entry.nameEn !== 'string') return false\n if (typeof entry.author !== 'string' || entry.author === '') return false\n if (typeof entry.repo !== 'string' || !REPO_SAFE_RE.test(entry.repo)) return false\n if (entry.description !== undefined && typeof entry.description !== 'string') return false\n if (entry.descriptionEn !== undefined && typeof entry.descriptionEn !== 'string') return false\n if (entry.npm !== undefined && (typeof entry.npm !== 'string' || !NPM_SAFE_RE.test(entry.npm))) return false\n if (entry.category !== undefined && (typeof entry.category !== 'string' || !KNOWN_CATEGORIES.includes(entry.category as CommunityPluginCategory))) return false\n return true\n}\n","/**\n * Bridge to the optional 'pluginManager' cordis service provided by the\n * sibling plugin @linxin666/dsh-client-ui-plugin-manager. The service is\n * OPTIONAL: when that plugin is not installed the bridge holds null and the\n * card degrades to the read-only copy-command index, exactly as before.\n *\n * CONTRACT OBSERVATION: the InstalledPluginItem / InstallProgressItem /\n * PluginManagerService shapes below mirror the sibling package's frozen\n * contract (its src/core/protocol.ts and src/core/service.ts). Repository\n * rules forbid cross-package value imports, so this file re-declares the\n * types locally; both sides must stay byte-compatible on the wire.\n */\n\n/**\n * One installed user-plugin row (mirrors the sibling's protocol).\n */\nexport interface InstalledPluginItem {\n id: string\n name: string\n version: string\n source: { kind: 'npm' | 'git'; spec: string }\n installedAt: string\n /** Saved next-start enablement from the managed profile patch row. */\n enabled: boolean\n commit?: string\n}\n\n/** Point-in-time install/update progress reported by the host. */\nexport interface InstallProgressItem {\n kind: 'idle' | 'install' | 'update'\n stage: 'fetch' | 'download' | 'extract' | 'write'\n percent?: number\n}\n\n/**\n * The frozen cross-plugin service contract (cordis service name\n * 'pluginManager'). Kept intentionally narrow: observe and drive the\n * installed-plugin set.\n */\nexport interface PluginManagerService {\n /** Whether this browser has loopback authority over the host routes. */\n readonly isLoopback: boolean\n /** Read the installed snapshot. */\n list(): Promise<InstalledPluginItem[]>\n /** Install one plugin from an npm spec or git URL. */\n install(spec: string): Promise<InstalledPluginItem>\n /** Remove one plugin; resolves with the fresh installed snapshot. */\n uninstall(id: string): Promise<InstalledPluginItem[]>\n /** Read the current install/update progress. */\n status(): Promise<InstallProgressItem>\n /** Subscribe to successful mutations; returns the unsubscribe function. */\n onChange(cb: () => void): () => void\n}\n\nimport type { Context } from '@deepseek-ai/cordis'\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * The plugin-manager face, present only when the sibling\n * dsh-plugin-manager client plugin is installed and active.\n */\n pluginManager?: PluginManagerService\n }\n}\n\n/** Bridge snapshot: the current face (or null) plus a monotonically increasing version. */\nexport interface PluginManagerBridgeSnapshot {\n /** The service face while the sibling plugin provides it, else null. */\n readonly face: PluginManagerService | null\n /** Bumped on every face change (lets consumers detect same-reference swaps). */\n readonly version: number\n}\n\nlet snapshot: PluginManagerBridgeSnapshot = { face: null, version: 0 }\nconst listeners = new Set<() => void>()\n\n/** Replace the held face and notify subscribers. */\nfunction setFace(face: PluginManagerService | null): void {\n snapshot = { face, version: snapshot.version + 1 }\n for (const listener of listeners) listener()\n}\n\n/** Current bridge snapshot (cached reference, safe for useSyncExternalStore). */\nexport function getPluginManagerSnapshot(): PluginManagerBridgeSnapshot {\n return snapshot\n}\n\n/** Subscribe to face changes; returns the unsubscribe function. */\nexport function subscribePluginManager(listener: () => void): () => void {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n}\n\n/**\n * Bridge the optional 'pluginManager' service into the module store. Uses\n * ctx.inject (NOT the plugin's module-level inject array) so the service\n * stays optional: the inner callback runs when the sibling plugin provides\n * the face and is disposed when it goes away, which clears the store.\n * @param ctx - the client root context.\n */\nexport function bridgePluginManager(ctx: Context): void {\n ctx.inject(['pluginManager'], (inner) => {\n inner.effect(() => {\n setFace(inner.pluginManager ?? null)\n return () => { setFace(null) }\n }, 'community-plugins: pluginManager bridge')\n })\n}\n","/**\n * Map a community index entry onto the plugin-manager install surface: the\n * install spec (npm package when published, else the contributor repository\n * URL) and a conservative matcher that tells whether one entry is already\n * present in the installed snapshot the 'pluginManager' service serves.\n */\n\nimport type { CommunityPluginEntry } from './generated/community.ts'\nimport type { InstalledPluginItem } from './plugin-manager-bridge.ts'\n\n/**\n * The spec handed to pluginManager.install(): the npm package name when the\n * entry is published there, else the repository URL (git install).\n * @param entry - the community index entry.\n * @returns the install spec.\n */\nexport function installSpec(entry: CommunityPluginEntry): string {\n return entry.npm ?? entry.repo\n}\n\n/**\n * Normalize a git remote for comparison: lowercase, drop the transport\n * prefix ('git+' wrapper, 'https://', 'http://', 'git://', 'ssh://git@', the\n * scp-style 'git@host:' userinfo, and the pnpm host shorthands 'github:' /\n * 'gitlab:' / 'bitbucket:' that package.json records for shorthand installs),\n * then strip trailing slashes and one trailing '.git'\n * suffix (repeated, so 'x/.git/' and 'x.git' converge). Conservative on\n * purpose: no path rewriting beyond those steps, so distinct repositories\n * never collapse onto each other.\n * @param url - the repository URL as recorded by either side.\n * @returns the comparison key.\n */\nexport function normalizeGitUrl(url: string): string {\n let key = url.trim().toLowerCase()\n // pnpm git wrapper: 'git+https://host/owner/repo' -> 'https://host/owner/repo'.\n key = key.replace(/^git[+]/, '')\n // pnpm host shorthands recorded in package.json: 'github:owner/repo' ->\n // 'github.com/owner/repo' (same for gitlab / bitbucket).\n key = key.replace(/^(github|gitlab):/, '$1.com/')\n key = key.replace(/^bitbucket:/, 'bitbucket.org/')\n // Transport prefixes: 'https://', 'http://', 'git://', 'ssh://git@'.\n key = key.replace(/^(?:https?|git):[/][/]/, '')\n key = key.replace(/^ssh:[/][/]git@/, '')\n // Scp-style ssh remote: 'git@github.com:owner/repo' -> 'github.com/owner/repo'.\n key = key.replace(/^git@([^/:]+):/, '$1/')\n // Strip trailing slashes and a trailing '.git' suffix until stable.\n for (;;) {\n const next = key.replace(/[/]+$/, '').replace(/[.]git$/, '')\n if (next === key) return key\n key = next\n }\n}\n\n/**\n * Match one community entry against the installed snapshot. npm-published\n * entries match on the installed row's package identity (id/name): the npm\n * source spec records the dependency RANGE ('^0.3.2') or an install-time\n * spec, not necessarily the bare package name, so it is only a fallback.\n * Repository entries match on the normalized git URL. An entry with an npm\n * field ONLY matches npm installs — a same-repository git install is a\n * different source and stays unmatched (the card then offers install, which\n * the host reconciles).\n * @param entry - the community index entry.\n * @param installed - the installed snapshot from the pluginManager service.\n * @returns the matching installed row, or null.\n */\nexport function entryInstalled(\n entry: CommunityPluginEntry,\n installed: readonly InstalledPluginItem[],\n): InstalledPluginItem | null {\n if (entry.npm !== undefined) {\n return installed.find(\n item => item.source.kind === 'npm'\n && (item.id === entry.npm || item.name === entry.npm || item.source.spec === entry.npm),\n ) ?? null\n }\n const key = normalizeGitUrl(entry.repo)\n return installed.find(\n item => item.source.kind === 'git' && normalizeGitUrl(item.source.spec) === key,\n ) ?? null\n}\n","/**\n * The community plugin index card: a first-level settings section that is\n * always open. Its own enable switch (backed by the community-plugins\n * settings namespace) gates the list, which is presented marketplace-style:\n * a search box, category filter pills with counts, and a two-column card grid\n * whose entries link to contributors' own repositories — this package only\n * indexes them, it never vendors their code.\n */\n\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, type ReactNode } from 'react'\nimport { Button, Modal } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\n// Type-only: pulls the settings-surface SlotMap merge (the 'settings.section' entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { PluginSettingsCard, BooleanField } from './PluginSettingsCard.tsx'\nimport { CardForm, booleanField, type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts'\nimport { COMMUNITY_PLUGINS, type CommunityPluginCategory, type CommunityPluginEntry } from './generated/community.ts'\nimport { isCommunityPluginEntry } from './community-guard.ts'\nimport {\n getPluginManagerSnapshot,\n subscribePluginManager,\n type InstalledPluginItem,\n type InstallProgressItem,\n type PluginManagerService,\n} from './plugin-manager-bridge.ts'\nimport { entryInstalled, installSpec } from './install-source.ts'\nimport css from './community.module.css'\n\n/** The settings fields this card edits (the namespace's full schema). */\nexport interface CommunityPluginsSettings {\n /** Master switch for the index card. */\n enabled?: boolean\n}\n\n/** What the community plugin card renders. */\nexport interface CommunityPluginsCardState extends CardShell {\n /** Master switch. */\n enabled: CardFieldState\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface CommunityPluginsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useCommunityPluginsCard. */\n communityPluginsCard: SnapshotStore<CommunityPluginsCardState>\n }\n}\n\n/** Bridges the community-plugins scope onto the card's staged form. */\nexport class CommunityPluginsCardController {\n private readonly form: CardForm<CommunityPluginsSettings>\n private readonly store: SnapshotStore<CommunityPluginsCardState>\n\n /** @param scope - the bound settings scope for the community-plugins namespace. */\n constructor(scope: SettingsScope<CommunityPluginsSettings>) {\n this.form = new CardForm(scope, [\n booleanField('enabled'),\n ])\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): CommunityPluginsCardState {\n return {\n ...this.form.shell(),\n enabled: this.form.field('enabled'),\n }\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): CommunityPluginsCardFace {\n return { hooks: { communityPluginsCard: this.store }, ...this.form.actions() }\n }\n\n /**\n * Release the card's scope subscription and bound stores; the slot\n * disposer calls this on teardown.\n */\n dispose(): void {\n this.form.dispose()\n }\n}\n\n/** The one-line install command for an entry: npm package when published, else the contributor repository URL. */\nfunction installCommand(entry: CommunityPluginEntry): string {\n return `dsh plugin --profile web add ${entry.npm ?? entry.repo}`\n}\n\n/** Progress polling cadence while an install is in flight. */\nconst PROGRESS_POLL_MS = 500\n\n/** Extract a displayable reason from an install/uninstall rejection. */\nfunction messageOf(reason: unknown): string {\n return reason instanceof Error ? reason.message : String(reason)\n}\n\n/** One in-flight mutation, keyed by the community entry id (drives per-card state). */\ninterface PendingMutation {\n readonly kind: 'install' | 'uninstall'\n readonly id: string\n}\n\n/**\n * Localized entry copy read through the card's `t`. Falls back to the raw\n * entry field when the key is missing — the dictionary only carries the\n * generated registry, so injected test entries land on the fallback.\n */\nfunction entryCopy(t: (key: string) => string, key: string, fallback: string): string {\n const value = t(key)\n return value === key ? fallback : value\n}\n\n/** Maps a category id onto its locale dictionary key (kept in the generated union). */\nconst CATEGORY_KEY: Record<CommunityPluginCategory, `category.${CommunityPluginCategory}`> = {\n ui: 'category.ui',\n agent: 'category.agent',\n tools: 'category.tools',\n knowledge: 'category.knowledge',\n integration: 'category.integration',\n security: 'category.security',\n utility: 'category.utility',\n}\n\n/** Props the renderer binds for the community plugin card. */\nexport type CommunityPluginsCardProps =\n PropsLocale<'community-plugins'>\n & InjectFace<CommunityPluginsCardFace>\n & {\n /** Index entries; defaults to the generated registry (injected for tests). */\n plugins?: readonly CommunityPluginEntry[]\n /**\n * Plugin-manager face override; undefined reads the bridged cordis\n * service (the default), null forces the degraded copy-command UI\n * (injected for tests).\n */\n pluginManager?: PluginManagerService | null\n }\n\n/**\n * Render the community plugin index card.\n * @param props - locale copy, the card snapshot, its form actions, and the\n * (default-generated) entry list.\n * @returns the card.\n */\nexport function CommunityPluginsCard(props: CommunityPluginsCardProps): ReactNode {\n const { t } = props\n const state = props.useCommunityPluginsCard(snapshot => snapshot)\n // Memoized so the categoryCounts/visiblePlugins caches below only\n // recompute when the registry actually changes, not on every keystroke.\n const plugins = useMemo(() => (props.plugins ?? COMMUNITY_PLUGINS).filter(isCommunityPluginEntry), [props.plugins])\n const [query, setQuery] = useState('')\n const [category, setCategory] = useState<CommunityPluginCategory | null>(null)\n const [copiedId, setCopiedId] = useState<string | null>(null)\n\n // The optional pluginManager service: undefined prop reads the bridge store\n // (populated by ctx.inject in the client apply), an explicit prop wins.\n const bridge = useSyncExternalStore(subscribePluginManager, getPluginManagerSnapshot)\n const face = props.pluginManager !== undefined ? props.pluginManager : bridge.face\n const faceLoopback = face !== null && face.isLoopback\n // A bridge version can change while cordis re-provides the same face\n // reference. Give every committed provision its own lifetime so async\n // completions from the previous one cannot mutate the replacement UI.\n const faceRevision = props.pluginManager !== undefined ? face : bridge.version\n const faceLifetime = useMemo(() => ({ active: true }), [face, faceRevision])\n useLayoutEffect(() => {\n faceLifetime.active = true\n return () => { faceLifetime.active = false }\n }, [faceLifetime])\n\n // Installed snapshot served by the face (null = not loaded / no face).\n const [installed, setInstalled] = useState<readonly InstalledPluginItem[] | null>(null)\n // The one in-flight mutation; while set, every card's mutation buttons disable.\n const [pending, setPending] = useState<PendingMutation | null>(null)\n // Latest polled install progress (only meaningful while an install runs).\n const [progress, setProgress] = useState<InstallProgressItem | null>(null)\n // Per-card inline error lines, keyed by entry id.\n const [errors, setErrors] = useState<Readonly<Record<string, string>>>({})\n // The entry awaiting uninstall confirmation.\n const [uninstallTarget, setUninstallTarget] = useState<CommunityPluginEntry | null>(null)\n // Latest-issued list request wins. An earlier request may complete after a\n // mutation refresh even when the service face itself did not change.\n const listRequestRef = useRef(0)\n\n // Keep the installed snapshot in sync with the face: initial load, plus\n // onChange so edits made in the Plugin manager tab reflect here. Only\n // loopback faces are queried — remote browsers render the read-only index.\n useEffect(() => {\n // An operation belongs to the face that started it. Once that face is\n // replaced, release its local UI lock and discard its dialog/error state;\n // the new face's list request below becomes authoritative.\n setPending(null)\n setProgress(null)\n setErrors({})\n setUninstallTarget(null)\n listRequestRef.current += 1\n if (face === null || !face.isLoopback) {\n setInstalled(null)\n return\n }\n let alive = true\n const refresh = (): void => {\n const request = ++listRequestRef.current\n void face.list().then(\n (list) => {\n if (alive && faceLifetime.active && request === listRequestRef.current) setInstalled(list)\n },\n () => { /* keep the last known snapshot on transient failures */ },\n )\n }\n refresh()\n const unsubscribe = face.onChange(refresh)\n return () => { alive = false; unsubscribe() }\n }, [face, faceLoopback, faceLifetime])\n\n // Poll the host's install progress while an install is in flight; the\n // first poll runs immediately so the stage line appears without delay.\n useEffect(() => {\n if (face === null || pending?.kind !== 'install') {\n setProgress(null)\n return\n }\n let alive = true\n const poll = (): void => {\n void face.status().then(\n (item) => { if (alive && faceLifetime.active) setProgress(item) },\n () => { /* transient poll failure: keep the last known stage */ },\n )\n }\n poll()\n const timer = setInterval(poll, PROGRESS_POLL_MS)\n return () => { alive = false; clearInterval(timer) }\n // Keyed on the boolean, not the entry: restarting the poll per entry is unnecessary.\n }, [face, faceLifetime, pending?.kind === 'install'])\n\n const clearError = (id: string): void => {\n setErrors((previous) => {\n if (!(id in previous)) return previous\n const next = { ...previous }\n delete next[id]\n return next\n })\n }\n\n const onInstall = (entry: CommunityPluginEntry): void => {\n if (face === null || !face.isLoopback || pending !== null) return\n const lifetime = faceLifetime\n clearError(entry.id)\n setPending({ kind: 'install', id: entry.id })\n void (async () => {\n try {\n await face.install(installSpec(entry))\n if (!lifetime.active) return\n const request = ++listRequestRef.current\n const list = await face.list().catch(() => undefined)\n if (lifetime.active && list !== undefined && request === listRequestRef.current) setInstalled(list)\n } catch (reason) {\n if (!lifetime.active) return\n setErrors((previous) => ({ ...previous, [entry.id]: t('installFailed', { reason: messageOf(reason) }) }))\n } finally {\n if (lifetime.active) setPending(null)\n }\n })()\n }\n\n const onUninstallConfirm = (): void => {\n const target = uninstallTarget\n if (face === null || target === null || pending !== null) return\n const item = entryInstalled(target, installed ?? [])\n clearError(target.id)\n if (item === null) {\n // Already gone (e.g. uninstalled from the Plugin manager tab): close quietly.\n setUninstallTarget(null)\n return\n }\n const lifetime = faceLifetime\n setPending({ kind: 'uninstall', id: target.id })\n face.uninstall(item.id).then(\n (list) => {\n if (!lifetime.active) return\n listRequestRef.current += 1\n setInstalled(list)\n setUninstallTarget(null)\n },\n (reason: unknown) => {\n if (!lifetime.active) return\n setErrors((previous) => ({ ...previous, [target.id]: t('uninstallFailed', { reason: messageOf(reason) }) }))\n setUninstallTarget(null)\n },\n ).finally(() => { if (lifetime.active) setPending(null) })\n }\n\n const copyCommand = (id: string, command: string): void => {\n const mark = (): void => { setCopiedId(id) }\n const clipboard = typeof navigator !== 'undefined' ? navigator.clipboard : undefined\n if (clipboard?.writeText !== undefined) {\n void clipboard.writeText(command).then(mark, mark)\n return\n }\n // Fallback for browsers without the async clipboard API (or tests).\n try {\n const area = document.createElement('textarea')\n area.value = command\n area.setAttribute('readonly', '')\n area.style.position = 'fixed'\n area.style.opacity = '0'\n document.body.append(area)\n area.select()\n document.execCommand('copy')\n area.remove()\n } catch { /* the command stays visible to select by hand */ }\n mark()\n }\n const disabled = !state.writable\n // One in-flight install/uninstall locks every card's mutation buttons.\n const mutationsDisabled = disabled || pending !== null\n // The draft text drives the list: '' (inherit) and 'true' keep it visible,\n // 'false' hides it until the switch is turned back on.\n const visible = state.enabled.text !== 'false'\n const fieldProps = {\n overriddenLabel: t('settings.overridden'),\n resetLabel: t('settings.reset'),\n invalidLabel: t('settings.invalidNumber'),\n disabled,\n }\n\n // Category pills in descending count (stable tie-break by id).\n const categoryCounts = useMemo(() => {\n const counts = new Map<CommunityPluginCategory, number>()\n for (const plugin of plugins) {\n if (plugin.category) counts.set(plugin.category, (counts.get(plugin.category) ?? 0) + 1)\n }\n return [...counts.entries()].sort(\n (a, b) => b[1] - a[1] || a[0].localeCompare(b[0]),\n )\n }, [plugins])\n\n // Both the active pill and the search text narrow the list (AND).\n const visiblePlugins = useMemo(() => {\n const needle = query.trim().toLowerCase()\n return plugins.filter((plugin) => {\n if (category !== null && plugin.category !== category) return false\n if (!needle) return true\n const categoryLabel = plugin.category ? t(CATEGORY_KEY[plugin.category]) : ''\n const haystack = [plugin.name, plugin.nameEn, plugin.author, plugin.description, plugin.descriptionEn, plugin.npm ?? '', categoryLabel]\n .join(' ')\n .toLowerCase()\n return haystack.includes(needle)\n })\n }, [plugins, query, category, t])\n\n return (\n <PluginSettingsCard\n t={t}\n titleKey=\"settings.title\"\n descriptionKey=\"settings.description\"\n state={state}\n alwaysOpen\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"settings-community-enabled\"\n label={t('settings.enabled')}\n hint={t('settings.enabledHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.enabled}\n onEdit={(text) => { props.edit('enabled', text) }}\n onReset={() => { props.resetField('enabled') }}\n />\n {visible\n ? (\n <div className={css.market}>\n <div className={css.toolbar}>\n <input\n id=\"settings-community-search\"\n className={css.search}\n type=\"search\"\n placeholder={t('search.placeholder')}\n aria-label={t('search.label')}\n value={query}\n disabled={disabled}\n onChange={(event) => { setQuery(event.target.value) }}\n />\n </div>\n <div className={css.filters} role=\"group\" aria-label={t('filter.all')}>\n <button\n type=\"button\"\n className={category === null ? `${css.pill} ${css.pillActive}` : css.pill}\n aria-pressed={category === null}\n disabled={disabled}\n onClick={() => { setCategory(null) }}\n >\n {t('filter.all')} {plugins.length}\n </button>\n {categoryCounts.map(([id, count]) => (\n <button\n key={id}\n type=\"button\"\n className={category === id ? `${css.pill} ${css.pillActive}` : css.pill}\n aria-pressed={category === id}\n disabled={disabled}\n onClick={() => { setCategory(category === id ? null : id) }}\n >\n {t(CATEGORY_KEY[id])} {count}\n </button>\n ))}\n </div>\n <p className={css.resultCount} role=\"status\">\n {t('result.count', { shown: visiblePlugins.length, total: plugins.length })}\n </p>\n {plugins.length === 0\n ? <p className={css.empty} role=\"status\">{t('empty')}</p>\n : visiblePlugins.length === 0\n ? <p className={css.empty} role=\"status\">{t('noMatch')}</p>\n : (\n <ul className={css.grid}>\n {visiblePlugins.map((plugin) => {\n const command = installCommand(plugin)\n const copied = copiedId === plugin.id\n const name = entryCopy(t, `name.${plugin.id}`, plugin.nameEn || plugin.name)\n const description = entryCopy(t, `desc.${plugin.id}`, plugin.descriptionEn ?? plugin.description ?? '')\n const installedItem = faceLoopback ? entryInstalled(plugin, installed ?? []) : null\n const isInstalling = pending?.kind === 'install' && pending.id === plugin.id\n const isUninstalling = pending?.kind === 'uninstall' && pending.id === plugin.id\n const error = errors[plugin.id]\n return (\n <li key={plugin.id} className={css.card}>\n <span className={css.cardHead}>\n <span className={css.cardName} title={name}>{name}</span>\n <span className={css.cardBadges}>\n {installedItem !== null\n ? <span className={`${css.badge} ${css.badgeInstalled}`}>{t('badge.installed')}</span>\n : null}\n <span\n className={plugin.npm ? `${css.badge} ${css.badgePublished}` : css.badge}\n title={plugin.npm ?? plugin.repo}\n >\n {plugin.npm ? t('badge.published') : t('badge.source')}\n </span>\n </span>\n </span>\n <span className={css.cardMeta}>\n {plugin.category ? <span className={css.cardCategory}>{t(CATEGORY_KEY[plugin.category])}</span> : null}\n {plugin.category ? <span className={css.cardDot} aria-hidden=\"true\">·</span> : null}\n <span className={css.cardAuthor} title={plugin.author}>{plugin.author}</span>\n </span>\n {description ? <p className={css.cardDescription}>{description}</p> : null}\n <span className={css.cardFooter}>\n <span className={css.cardTop}>\n <a className={css.cardLink} href={plugin.repo} target=\"_blank\" rel=\"noreferrer\">{t('repository')}</a>\n <span className={css.cardActions}>\n <button\n type=\"button\"\n className={copied\n ? `${css.installButton} ${css.installButtonCopied}`\n : faceLoopback ? `${css.installButton} ${css.installButtonSecondary}` : css.installButton}\n title={command}\n onClick={() => { copyCommand(plugin.id, command) }}\n >\n {copied ? t('copied') : t('install')}\n </button>\n {faceLoopback && installedItem === null\n ? (\n <button\n type=\"button\"\n className={css.installButton}\n disabled={mutationsDisabled}\n onClick={() => { onInstall(plugin) }}\n >\n {isInstalling ? t('installing') : t('installNow')}\n </button>\n )\n : null}\n {faceLoopback && installedItem !== null\n ? (\n <button\n type=\"button\"\n className={`${css.installButton} ${css.installButtonSecondary}`}\n disabled={mutationsDisabled}\n onClick={() => { setUninstallTarget(plugin) }}\n >\n {isUninstalling ? t('uninstalling') : t('uninstall')}\n </button>\n )\n : null}\n </span>\n </span>\n {isInstalling\n ? (\n <p className={css.progress} role=\"status\">\n {progress !== null && progress.kind !== 'idle'\n ? t(`progress.${progress.stage}`)\n : t('installing')}\n </p>\n )\n : null}\n {error !== undefined ? <p className={css.error} role=\"alert\">{error}</p> : null}\n <code className={css.cardCommand} title={command}>{command}</code>\n </span>\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n : <p className={css.off} role=\"status\">{t('off')}</p>}\n {face === null\n ? <p className={css.installNote} role=\"note\">{t('managerHint')}</p>\n : face.isLoopback\n ? null\n : <p className={css.installNote} role=\"note\">{t('remoteHint')}</p>}\n <p className={css.installNote} role=\"note\">{t('installHint')}</p>\n <p className={css.notice} role=\"note\">{t('notice')}</p>\n <Modal\n open={uninstallTarget !== null}\n onClose={() => { if (pending === null) setUninstallTarget(null) }}\n title={t('uninstallConfirm.title')}\n closeLabel={t('cancel')}\n >\n <p className={css.confirmBody}>\n {t('uninstallConfirm.body', {\n name: uninstallTarget === null\n ? ''\n : entryCopy(t, `name.${uninstallTarget.id}`, uninstallTarget.nameEn || uninstallTarget.name),\n })}\n </p>\n <div className={css.modalActions}>\n <Button variant=\"outline\" disabled={pending !== null} onClick={() => { setUninstallTarget(null) }}>\n {t('cancel')}\n </Button>\n <Button variant=\"primary\" className={css.dangerButton} disabled={pending !== null} onClick={onUninstallConfirm}>\n {pending?.kind === 'uninstall' ? t('uninstalling') : t('uninstallConfirm.confirm')}\n </Button>\n </div>\n </Modal>\n </PluginSettingsCard>\n )\n}\n\n/** Props the settings section binds for the community plugin page. */\nexport type CommunityPluginsSectionProps =\n PropsRuntime<'settings.section'>\n & PropsLocale<'community-plugins'>\n & InjectFace<CommunityPluginsCardFace>\n & {\n /** Index entries; defaults to the generated registry (injected for tests). */\n plugins?: readonly CommunityPluginEntry[]\n /** Plugin-manager face override (injected for tests; undefined reads the bridge). */\n pluginManager?: PluginManagerService | null\n }\n\n/** Render the community plugin index as a first-level settings page. */\nexport function CommunityPluginsSection(props: CommunityPluginsSectionProps): ReactNode {\n const { t, useCommunityPluginsCard, save, discard, edit, resetField, plugins, pluginManager } = props\n return (\n <ul className={css.sectionList}>\n <CommunityPluginsCard t={t} useCommunityPluginsCard={useCommunityPluginsCard} save={save} discard={discard} edit={edit} resetField={resetField} plugins={plugins} pluginManager={pluginManager} />\n </ul>\n )\n}\n","/**\n * The community-plugins locale dictionaries for the index card. Static copy\n * for the card chrome plus one localized name/description pair per index\n * entry (`name.<id>` / `desc.<id>`), so the card localizes data-driven text\n * through the same `t` the rest of the settings UI uses — the document\n * `<html lang>` attribute is not a reliable locale signal in the GUI.\n */\n\nimport { COMMUNITY_PLUGINS } from './generated/community.ts'\n\n/** Simplified Chinese copy for the card chrome (the key-set source of truth). */\nconst STATIC_ZH = {\n 'settings.title': '社区插件',\n 'settings.description': '社区贡献者开发与维护的插件,链接指向作者自己的仓库。',\n 'settings.enabled': '启用社区插件索引',\n 'settings.enabledHint': '此开关只控制索引列表的显示与否,关闭后在这里重新打开。',\n 'settings.inherit': '继承',\n 'settings.on': '开',\n 'settings.off': '关',\n 'settings.overridden': '已覆盖',\n 'settings.reset': '恢复默认',\n 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。',\n 'settings.readOnly': '当前部署的设置只读。',\n 'settings.expand': '展开设置',\n 'settings.collapse': '收起设置',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.discard': '放弃',\n 'settings.unsaved': '未保存',\n 'settings.saveFailed': '部署未接受这些值,已保留供你修改。',\n 'settings.invalidNumber': '请输入数字,留空则使用默认值。',\n 'author': '作者',\n 'repository': '仓库',\n 'copy': '复制',\n 'copied': '已复制',\n 'install': '复制安装命令',\n 'installNow': '安装',\n 'installing': '安装中…',\n 'uninstall': '卸载',\n 'uninstalling': '卸载中…',\n 'cancel': '取消',\n 'badge.installed': '已安装 · 重启后生效',\n 'progress.fetch': '获取插件信息',\n 'progress.download': '下载中',\n 'progress.extract': '解压中',\n 'progress.write': '写入中',\n 'uninstallConfirm.title': '卸载插件',\n 'uninstallConfirm.body': '确定要卸载 {name} 吗?移除将在重启 dsh web 后完全生效。',\n 'uninstallConfirm.confirm': '确认卸载',\n 'installFailed': '安装失败:{reason}',\n 'uninstallFailed': '卸载失败:{reason}',\n 'managerHint': '未检测到「插件管理器」插件:安装 @linxin666/dsh-client-ui-plugin-manager 后,可在本机浏览器中直接从这里安装与卸载。',\n 'remoteHint': '当前是远程浏览器,界面内安装不可用;请在宿主机器的终端执行安装命令。',\n 'noMatch': '没有匹配的社区插件。',\n 'search.placeholder': '搜索名称、作者或简介',\n 'search.label': '搜索社区插件',\n 'filter.all': '全部',\n 'result.count': '显示 {shown} / {total} 个',\n 'badge.published': 'npm 已发布',\n 'badge.source': '仓库安装',\n 'category.ui': '界面与体验',\n 'category.agent': 'Agent 与自动化',\n 'category.tools': '开发者工具',\n 'category.knowledge': '记忆与知识',\n 'category.integration': '集成与分享',\n 'category.security': '安全与运维',\n 'category.utility': '实用工具',\n 'installHint': '在本机浏览器且已安装「插件管理器」插件时,可直接点击卡片上的「安装 / 卸载」;否则复制安装命令到终端执行。安装与卸载在重启 dsh web 后生效,插件自带的开关与配置(若有)会出现在插件配置里。',\n 'empty': '暂无社区插件登记。',\n 'off': '社区插件索引已关闭。',\n 'notice': '条目由贡献者自行登记,与 dsh-web-ui 的发布内容无关;使用前请自行评估。',\n} satisfies Record<string, string>\n\n/** English copy for the card chrome, checked complete against the zh key set. */\nconst STATIC_EN = {\n 'settings.title': 'Community Plugins',\n 'settings.description': \"Plugins developed and maintained by community contributors, linking to each author's own repository.\",\n 'settings.enabled': 'Enable the community plugin index',\n 'settings.enabledHint': 'This switch only controls whether the index list is shown; turn it back on here.',\n 'settings.inherit': 'Inherit',\n 'settings.on': 'On',\n 'settings.off': 'Off',\n 'settings.overridden': 'Overridden',\n 'settings.reset': 'Reset to default',\n 'settings.notExposed': \"This DSH version does not expose this plugin's settings namespace to the configuration page, so the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES allowlist and restart.\",\n 'settings.readOnly': 'This deployment stores settings read-only.',\n 'settings.expand': 'Show settings',\n 'settings.collapse': 'Hide settings',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.discard': 'Discard',\n 'settings.unsaved': 'Unsaved',\n 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'settings.invalidNumber': 'Enter a number, or leave blank to use the default.',\n 'author': 'Author',\n 'repository': 'Repository',\n 'copy': 'Copy',\n 'copied': 'Copied',\n 'install': 'Copy install command',\n 'installNow': 'Install',\n 'installing': 'Installing…',\n 'uninstall': 'Uninstall',\n 'uninstalling': 'Uninstalling…',\n 'cancel': 'Cancel',\n 'badge.installed': 'Installed · restart to take effect',\n 'progress.fetch': 'Fetching plugin info',\n 'progress.download': 'Downloading',\n 'progress.extract': 'Extracting',\n 'progress.write': 'Writing',\n 'uninstallConfirm.title': 'Uninstall plugin',\n 'uninstallConfirm.body': 'Uninstall {name}? The removal fully takes effect after restarting dsh web.',\n 'uninstallConfirm.confirm': 'Confirm uninstall',\n 'installFailed': 'Install failed: {reason}',\n 'uninstallFailed': 'Uninstall failed: {reason}',\n 'managerHint': 'The Plugin manager plugin is not detected: install @linxin666/dsh-client-ui-plugin-manager to install and uninstall entries directly from here in a local browser.',\n 'remoteHint': 'This is a remote browser, so in-GUI install is unavailable; run the install command in a terminal on the host machine.',\n 'noMatch': 'No matching community plugin found.',\n 'search.placeholder': 'Search name, author or description',\n 'search.label': 'Search community plugins',\n 'filter.all': 'All',\n 'result.count': 'Showing {shown} / {total}',\n 'badge.published': 'Published on npm',\n 'badge.source': 'Install from repo',\n 'category.ui': 'UI & Experience',\n 'category.agent': 'Agents & Automation',\n 'category.tools': 'Developer Tools',\n 'category.knowledge': 'Memory & Knowledge',\n 'category.integration': 'Integration & Sharing',\n 'category.security': 'Security & Ops',\n 'category.utility': 'Utilities',\n 'installHint': 'With the Plugin manager plugin present and a local browser, use the Install / Uninstall buttons on each card; otherwise copy the install command into a terminal. Installs and uninstalls take effect after restarting dsh web; once installed, the plugin provides its own switch and config (if any) in the plugin configuration section.',\n 'empty': 'No community plugins registered yet.',\n 'off': 'The community plugin index is turned off.',\n 'notice': 'Entries are contributed by their authors and are separate from dsh-web-ui releases; evaluate before use.',\n} satisfies Record<keyof typeof STATIC_ZH, string>\n\n/** Build the runtime dictionary: static copy plus one localized name/description pair per index entry. */\nfunction build(base: Record<string, string>, lang: 'zh' | 'en'): Record<string, string> {\n const dict: Record<string, string> = { ...base }\n for (const entry of COMMUNITY_PLUGINS) {\n dict[`name.${entry.id}`] = lang === 'zh' ? entry.name : entry.nameEn\n dict[`desc.${entry.id}`] = lang === 'zh'\n ? (entry.description ?? entry.descriptionEn ?? '')\n : (entry.descriptionEn ?? entry.description ?? '')\n }\n return dict\n}\n\n/** Simplified Chinese dictionary for the index card (chrome + per-entry copy). */\nexport const zh = build(STATIC_ZH, 'zh')\n\n/** English dictionary, built from the same key set. */\nexport const en = build(STATIC_EN, 'en')\n\n/** Key union for this namespace (chrome keys plus per-entry name/description keys). */\nexport type CommunityPluginKey = keyof typeof zh\n","/**\n * Community plugin index, browser half. Registers the community-plugins\n * dictionaries and one section into the settings panel's first-level nav\n * (settings.section; the promoted family sections sit beside the built-in\n * general / models / plugins / agent-presets entries). The card carries its\n * own enable switch (backed by the community-plugins settings namespace) and\n * lists community plugins with links to each contributor's own repository.\n * @module @linxin666/dsh-client-ui-community-plugins/client\n */\n\nimport type { ClientContext, SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the settings-surface Context merge (ctx.settingsScope).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the slot-surface types (the settings.section seat).\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { CommunityPluginsCardController, CommunityPluginsSection, type CommunityPluginsSettings } from './CommunityPluginsCard.tsx'\nimport { en, zh, type CommunityPluginKey } from './locales.ts'\nimport { bridgePluginManager } from './plugin-manager-bridge.ts'\n\nexport type { CommunityPluginsCardProps, CommunityPluginsSectionProps } from './CommunityPluginsCard.tsx'\nexport type { InstalledPluginItem, InstallProgressItem, PluginManagerService } from './plugin-manager-bridge.ts'\n\n/** Settings namespace the card's enable switch edits (the Host plugin registers it). */\nconst COMMUNITY_PLUGINS_NS = 'community-plugins'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Community plugin index card copy. */\n 'community-plugins': CommunityPluginKey\n }\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * Optional rc.6 compatibility binder provided by dsh-web-ui-settings;\n * absent when that group plugin is not installed, so callers fall back to\n * the official settings scope.\n */\n webUiSettings?: { bind<S>(spec: SettingsScopeSpec<S>): SettingsScope<S> }\n }\n}\n\n/** Required services. */\nexport const inject = ['slots', 'locale', 'connection', 'settingsScope', 'remote']\n\n/**\n * Register the community plugin index as a first-level settings section, with\n * its own enable switch over the community-plugins settings namespace.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register('community-plugins', { zh, en }), 'community-plugins: dictionaries')\n\n // Bridge the optional 'pluginManager' cordis service (provided by the\n // sibling dsh-plugin-manager plugin) into the card's reactive store. It is\n // deliberately NOT in the module-level inject array: when the sibling is\n // absent this plugin still loads and the card keeps its read-only index UI.\n bridgePluginManager(ctx)\n\n const binder = ctx.get('webUiSettings') ?? ctx.settingsScope\n const settingsScope = binder.bind<CommunityPluginsSettings>({ namespace: COMMUNITY_PLUGINS_NS })\n const controller = new CommunityPluginsCardController(settingsScope)\n\n ctx.slots.inject('settings.section', () => {\n const unregister = ctx.slots.register({\n name: 'settings.section',\n id: 'community-plugins',\n order: 140,\n label: () => ctx.locale.bind('community-plugins')('settings.title'),\n locale: 'community-plugins',\n inject: () => controller.inject(),\n }, CommunityPluginsSection)\n return () => {\n controller.dispose()\n unregister()\n }\n })\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@linxin666/dsh-client-ui-community-plugins",
3
3
  "description": "Community plugin index card for the dsh web GUI settings page: lists community-contributed plugins with links to each contributor's own repository, gated by its own enable switch in the plugin configuration section.",
4
- "version": "0.2.7",
4
+ "version": "0.2.8",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -11,6 +11,9 @@
11
11
  "./package.json": "./package.json"
12
12
  },
13
13
  "dsh": {
14
+ "engines": {
15
+ "dsh": ">=0.1.1-rc.1"
16
+ },
14
17
  "bundle": {
15
18
  "patch": "./cordis.patch.yml"
16
19
  },
@@ -32,13 +35,13 @@
32
35
  },
33
36
  "devDependencies": {
34
37
  "@deepseek-ai/cordis": "^4.0.1",
35
- "@deepseek-ai/dsh-client-connection": "^0.1.1-rc.1",
36
- "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.1",
37
- "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.1",
38
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.1-rc.1",
39
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.1",
40
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.1-rc.1",
41
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.1",
38
+ "@deepseek-ai/dsh-client-connection": "^0.1.1-rc.2",
39
+ "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.2",
40
+ "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
41
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.1-rc.2",
42
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.2",
43
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.1-rc.2",
44
+ "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
42
45
  "@testing-library/react": "^16.1.0",
43
46
  "@types/node": "^22.20.0",
44
47
  "@types/react": "~18.3.1",