# dsh-enhance 设计:Web 设置卡片 + 一键安装脚本 > 状态:设计定稿(brainstorming 产出,2026) > 目标宿主:DeepSeek Harness(`dsh`,Cordis 4 插件体系) > 前置文档:`docs/architecture.md`(v2 重设计)、`AGENTS.md`、`docs/upstream-migration.md`(本设计的 R5 产物,落盘后同步) > 上游参考:`F:\deepseek-harness\packages\client\*`、`packages/settings/settings`(MIT,实测类型定义) ## 1. 理解总结 1. **要做什么**:为 dsh-enhance 增加两个能力—— (a) **Web 设置卡片**:用户在 `dsh web`「设置 → 插件配置」标签页直接编辑 dsh-enhance 配置(`workRules`、6 个开关组、`advisorModel`),替代手写 `cordis.patch.yml`;配置持久化到 dsh settings 通道,重启生效。 (b) **一键安装脚本**:`scripts/install.mjs` 把 dsh-enhance 接入用户 profile(本地 `link:` 目录链接优先),并配套预设复制、验证、重启提示。 2. **定位**:dsh-enhance 之于 DeepSeek Harness ≈ oh-my-pi 之于 Pi agent、LazyCodex 之于 Codex、Reasonix 之于无 dsh 时代的 DeepSeek——dsh 用户生态中的**必备增强层**。面向社区通用插件,受众从个人重度开发者出发、可延伸。 3. **主维度**:UI/产品体验(能力可视化、配置/上手体验、会话内交互)+ 行为层深化。 4. **成功标准(四项全要)**:采用率(装上即长期用)、行为改善(产出质量/效率)、上手体验(低认知负担)、生态影响力(可复制示范)。 5. **产出形态**:先方向筛选 → 聚焦深挖。选定旗舰方向:**Web 设置卡片**(方向 1)。 ## 2. 假设 - **性能**:client bundle 控制在 KB 级(跟随 dsh client 体系惯例),不设专项性能优化。 - **规模**:社区插件起步(用户数千级以下),存储沿用文件方案(`~/.dsh-enhance`、boulder CAS),不引入数据库。 - **安全/隐私**:本地文件存储原则延续;设置持久化走 dsh settings 通道;**不引入遥测**(架构文档 v3 前不做)。 - **可靠性**:客户端只是呈现层,**事实源始终在 Host**;boulder 等共享状态的原子性不因 UI 半侧而削弱。 - **维护**:单人维护为主,接受 UI 工程化成本(自建 clientBundle 等效构建)。 - **上游**:dsh 是 developer preview,存在破坏性变更(官方明示);settings 服务为 dsh 标配(agent-presets 直接依赖)。 ## 3. 决策日志 | # | 决策 | 备选 | 理由 | |---|---|---|---| | D1 | namespace = `'dsh-enhance'` | — | 匹配插件名,小写 kebab 合法(`settingsNamespace` 约束) | | D2 | `applies: 'restart'` | live 热应用 | 配置全部在启动时接线;热应用需可重入接线,YAGNI | | D3 | 卡片自绘 | 复用官方卡片 chrome | bundle-purity gate 禁止跨插件 value import;卡片须自绘、自管草稿与 revision | | D4 | 构建复刻最小化(tsdown) | 完整复刻 clientBundle 预设 | 只复刻 lazy-CJS factory loader 契约,跳过 CSS 管线(最大成本头) | | D5 | 测试分层:Host 单测 / 契约测试 / dsh 实驱 | 仅单测 | 三层分别兜类型、运行时契约、真实链路 | | D6 | **组件策略:自绘极简原生控件** | Ant Design X / ui-primitives | ADX:体积数百 KB、CSS-in-JS 与 `--dsw-*` 双主题体系、组件面向对话非表单;ui-primitives:无 Switch/Textarea(8 字段仅 Input 可复用)、external 有 purity 风险;规模不匹配 | | D7 | 构建工具 = tsdown | esbuild/rollup 手写 | 与官方 `clientBundle` 同款,复刻偏差最小 | | D8 | 零 CSS 管线 | lightningcss CSS Modules 复刻 | 原生控件 + 内联 style 传 `--dsw-alias-*` token(官方规则允许);砍掉复刻成本最大头 | | D9 | 接入声明:`./client` export + `dsh.client` 声明 | — | client module system 的扫描契约 | | D10 | `build = tsc && tsdown` | — | host + client 一次产出 | | D11 | 上游接触面收敛到桥接薄层(R1) | 直接散用上游 API | 收缩易变 API 物理接触面;与架构原则 6 不冲突(桥接是版本卫生,非抽象事件面) | | D12 | 契约探测测试(R2) | 仅 tsc 类型层 | 类型层盖不住运行时契约漂移(loader 形状、槽键可注册性) | | D13 | 版本矩阵 + 升级流程文档(R3/R5) | — | 破坏性变更的快速跟进路径 | | D14 | 降级路径:client 失败不影响 host(R4) | — | loader 懒加载隔离失败 bundle;卡片不渲染、host 全功能照常 | | D15 | 风险三维评估:可能性 × 影响面 × 修复难度,分级承接 | 仅"变更可能性" | 影响面与修复难度决定承接力度(见 §5) | | D16 | 安装脚本 = `scripts/install.mjs`(Node 零依赖) | shell 脚本 | 跨平台(Windows/macOS/Linux);Node 已是 dsh 前置 | | D17 | 安装来源三选(`-s`):`link:`(默认,本地目录链接)/ `github:owner/repo` / npm | 仅 link: | 发布前后一致;link: 开发态实时同步 | | D18 | 脚本配套:预设复制到 `~/.dsh/.agent-presets` + `--dump-config` 验证 + 重启提示 | 只包装 add | 对齐 README 现有手动步骤,一次到位(**2026-10-09 更正**:预设已是补丁里的行,不再复制目录,脚本只需 `--dump-config` 验证 + 重启提示) | | D19 | **名字冲突处置**:npm `dsh-enhance` 已被占(0.1.7);实现期默认 `github:` 直装,scoped npm 名(`@omd/dsh-enhance`)留待发布时定 | — | README/文档明确区分 GitHub 8+ 同名仓库(LaplaceYoung 55★ 等);scoped 名决定会连带 `dsh plugin add` 命令与 README 示例变化。(**2026-10-09 更正**:该"已占"结论与 registry 现状不符——`npm view dsh-enhance` 与 `@dsh-enhance/dsh-enhance` 当日均为 404(未注册,见 `docs/known-issues.md` 的命名条目);当日实际的同名碰撞在 **GitHub**(`vcxmug/dsh-enhance`,另一套 vision/native-web 插件,已被 dshbase / deepseekplugin.org 收录)。v1 的决定是"沿用 `dsh-enhance` 名 + 只发 GitHub 源码安装,npm 留给 v2"。) | | D20 | 脚本语言 Node(零依赖),禁 shell | bash/sh | Windows 开发环境 + 社区跨平台 | ## 4. 最终设计 > ⚠️ **本节(§4–§7)是最初的规划稿,已被 §8 起的实证修订取代**:§4.2 的 `settingsBridge` / `ctx.settings.register` 方案在目标宿主上**不存在**,§4.4 的构建链(tsdown)也未采用。**交付形态以 §10 为准**,机制依据与验收证据在 §8、§9。保留本节只为记录决策演进。 ### 4.1 总体架构与数据流 ``` ┌─ Host 半侧(现有 src/ + 新增 settings-bridge)─────────────┐ │ apply(ctx, config) │ │ scope = settingsBridge.register(ctx, config) │ │ → ctx.settings.register('dsh-enhance', Config, {base}) │ │ applyFeatures(ctx, scope.get()) // defaults+entry+user│ │ scope.watch(→ 提示重启) │ └───────────────────────────────────────────────────────────┘ ▲ wire:descriptor(schema/value/revision/base/user) ┌─ Client 半侧(新增 src/client/)──────────────────────────┐ │ apply(clientCtx) │ │ slots.inject('settings.plugin.item', │ │ register({name, key:'dsh-enhance', locale}, Card)) │ │ Card 经 settingsScope.bind({namespace:'dsh-enhance'}) │ │ set/unset 单字段,revision 防并发覆盖 │ └───────────────────────────────────────────────────────────┘ ``` 数据流:设置页按 served namespace 分发 → 渲染卡片 → 编辑保存(revision-fenced)→ Host 持久化到 `settings.yaml` → 提示重启 → 重启后 `scope.get()` 含用户层。 ### 4.2 Host 半侧 ```ts export const inject = ['skills', 'systemPrompt', 'tools', 'agents', 'llm', 'settings'] export const DSH_ENHANCE_SETTINGS_NS = settingsNamespace('dsh-enhance') export function apply(ctx: Context, config: Config): void { const scope = settingsBridge.register(ctx, DSH_ENHANCE_SETTINGS_NS, Config, config) // D11 桥接层 applyFeatures(ctx, scope.get()) // 现 apply 接线逻辑原样搬入,仅换取值来源 scope.watch(() => ctx.logger.info('dsh-enhance: 配置已变更,重启后生效')) } ``` - **必须读 `scope.get()` 而非 `config`**:settings.yaml 用户层不自动并入 entry config(官方范式 web-search-deepseek 用惰性 `current()` 印证);`inject: ['settings']` 保证 apply 时服务就绪。 - **桥接层 `src/shared/settings-bridge.ts`**(R1):包装 `register`/`watch`,register 失败(契约破坏)时自动回退——`applyFeatures(ctx, config)` 保持现状不回归(配置 UI 降级为只读展示,数据不丢)。 ### 4.3 Client 半侧 ```ts export const inject = ['slots', 'locale', 'connection', 'remote', 'settingsScope'] export function apply(clientCtx: ClientContext): void { clientCtx.slots.inject('settings.plugin.item', () => clientCtx.slots.register({ name: 'settings.plugin.item', key: 'dsh-enhance', locale: 'settings.ohMyDsh', inject: () => card.inject(), }, OhMyDshCard)) } ``` 字段映射(D6 自绘原生控件,内联 style 引用 `--dsw-alias-*` token): | 字段 | 控件 | 说明 | |---|---|---| | `workRules` | `