# dsh-skin-market

> 为 DSH Web 提供嵌入设置页的皮肤市场，一键浏览、安装、激活、更新和卸载社区皮肤

## Metadata

- Author: [@kingOfSoySauce](https://github.com/kingOfSoySauce)
- Repo: <https://github.com/kingOfSoySauce/dsh-skin-market.git>
- GitHub: [kingOfSoySauce/dsh-skin-market](https://github.com/kingOfSoySauce/dsh-skin-market)
- Stars: 55
- Language: TypeScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Homepage: <https://kingofsoysauce.github.io/dsh-skin-market/>
- Topics: `deepseek-harness`, `dsh-plugin`, `plugin-market`, `skin-market`, `themes`
- Forks: 6
- Open Issues: 2
- Last push: 2026-08-20T17:38:51.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:kingOfSoySauce/dsh-skin-market
```

## Wiki

## 一句话定位
dsh-skin-market 是 DSH Web 设置页里内嵌的「皮肤市场」，让你像逛应用商店一样浏览、安装、激活、停用、常驻、更新和卸载社区皮肤插件。安装来源固定到具体 commit，遇到失败会自动回滚 profile 文件，最大限度降低外观变更带来的风险。

## 核心能力
- 浏览社区皮肤目录并按名称、标签、明暗模式搜索或排序
- 在 DSH 设置页内一键安装、激活、停用、常驻（pin）、更新、卸载皮肤
- 每 5 分钟静默从 GitHub Pages 拉取最新目录，离线时回退到缓存或内置目录
- 皮肤安装、更新过程显示下载进度、速度和实时阶段，可中途取消
- 提供皮肤市场自身的页面内更新（无需重启 DSH 即可检测新版本）
- 安装/激活失败时自动恢复 profile 的 package.json、cordis.patch.yml、workspace 与 lockfile 快照

## 技术实现
- **语言**: TypeScript（含客户端 React 18）
- **关键依赖**: @deepseek-ai/cordis（peerDependencies，DSH 宿主框架）、@deepseek-ai/dsh-client-ui-primitives（客户端 UI 原语）、yaml（读写 cordis.patch.yml）、ajv（目录 schema 校验）
- **架构模式**: 通过 Cordis 注入 webServer/loader/agents 服务，注册一组 HTTP 路由（`/dsh-skin-market/...`）；客户端通过 slots 注入设置页的 `settings.section` 槽位；通过 child_process 调用 `dsh plugin` 子命令完成实际 pnpm 安装/卸载
- **入口文件**: src/index.ts（Host 端）、src/client/index.ts（Client 端，注入 settings 槽位）

## 适用场景
想把 DSH Web 换个外观，但不想手动复制仓库、改 cordis.patch.yml、跑 pnpm 命令的用户。或者装了多个第三方皮肤想做统一管理、想试装一批皮肤再决定保留哪个的人。如果你只装一款皮肤且以后不再调整，可以直接装单个皮肤插件，不必用本市场。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH Web | 0.1.0-rc.6 | README 与 catalog 中 compatibility 字段均指向该版本；DSH 使用 pnpm 管理 profile 依赖 |
| Node.js | 22 或更高 | README「本地开发」一节声明，源码使用 ESM 与 node:crypto/node:fs 等内置模块 |
| 平台 | macOS / Windows / Linux | 子命令通过 `dsh plugin --profile <name>` 调用，未声明 OS/CPU 限制；Windows 下 pnpm 可能需要同时在 PATH 中放 pnpm.cmd |
| 原生模块 | 无 | 全部依赖均为 JS/YAML 处理，无 native binding |

## 安装方式
```bash
dsh plugin --profile web add github:kingOfSoySauce/dsh-skin-market
```

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `profile` | string | 作用于哪个 DSH profile（不传则从 `--profile` 命令行参数读取，再回退到 `web`） | `web` |
| `DSH_SKIN_MARKET_LOCAL_CATALOG` | 环境变量 | 设置为 `1` 时只使用插件内置的 `data/catalog.json`，跳过远程拉取；用于本地条目调试 | 未设置 |
| `DSH_HOME` | 环境变量 | 覆盖 DSH 用户目录位置，profile 路径解析基于它拼接 `profiles/<name>` | `~/.dsh` |

> 说明：皮肤目录中每个皮肤可能声明自己的 `compatibility.dsh` 和 `install.allowBuild`，但这些是目录条目级属性，不是插件运行时配置。

## 常见问题
**Q: 安装 dsh-skin-market 之前需要做哪些准备？**

A: 建议先关闭其他皮肤类插件以避免冲突，DSH 使用 pnpm 管理 profile 依赖，需确认 pnpm 在 PATH 中。本地开发需要 Node.js 22 或更高版本。

**Q: 皮肤市场安装、更新、卸载一个皮肤会失败吗？**

A: 不会修改你的真实 profile。每一步操作前会先快照 package.json、cordis.patch.yml、pnpm-workspace.yaml 和 pnpm-lock.yaml，出错时会原子恢复并清理半安装状态；遇到 pnpm allowBuilds 审批时只把必要的 key 写入对应字段。

**Q: 列表里的皮肤是怎么获取的，需要每次手动更新插件吗？**

A: 不需要。市场从 GitHub Pages 拉取远程目录 JSON，每 5 分钟或窗口重新获得焦点时静默校验一次。校验通过后会写入 profile 的 IndexedDB 缓存；离线或超时会回退到缓存，再回退到插件内置目录。

**Q: 安装来源为什么不固定到某个分支，而要绑定完整 commit？**

A: 目录中每个皮肤的目标形如 github:<owner>/<repo>#<40位 commit>，必要时带 &path: 子目录。固定 commit 可避免 main 分支后续提交对已收录版本造成意外覆盖，皮肤详情页也能精确显示来源。

**Q: 皮肤市场支持哪些操作？使用流程是怎样的？**

A: 支持 install / activate / deactivate / pin（常驻开启）/ unpin / update / uninstall 七种生命周期操作。每个皮肤可安装、可使用、可常驻；卸载前若仍在使用会自动停用并恢复默认外观，再删除 package。

**Q: 皮肤市场会主动创建 GitHub PR 或读取隐私文件吗？**

A: 不会。浏览器只能提交目录里的 skinId，无法提交任意命令或安装地址；收录流程只在维护者本地的 fork 中通过 PR 提交，并明确不读取 .env、凭据、聊天记录或工作区外的私密文件。

**Q: 安装或激活后界面没变化怎么办？**

A: 多数皮肤需要在 DSH Web 重启后生效。设置 → 皮肤市场 → 选中皮肤 → 点击「使用」→「重启 DSH」。重启时若仍有 Agent 正在运行，会被等待至空闲后再安全重启。

**Q: 页面因皮肤冲突无法操作时怎么恢复？**

A: 先停止 DSH 进程，执行 `~/.dsh/profiles/web/node_modules/.bin/dsh-skin-market-reset --profile web`，会关闭市场管理的所有皮肤并保留包文件；之后重启 DSH 即可。命令使用原子写入，失败会回滚。

## 上手难度
入门 — 用户只需在设置页点点按钮，不需要手动编辑 profile；遇到冲突时也提供一键恢复命令，不要求理解 Cordis 或 pnpm 内部机制。

## 已知问题与限制
- 单个 pnpm 子命令的硬超时为 10 分钟；GitHub 大包下载慢时会触发「插件下载超时」提示（src/commands.ts:30、src/commands.ts:132-139）
- 目录要求远程 `generatedAt` 严格不小于本地已接受版本；远程目录若被回滚到旧时间戳，会被视为非法并保留旧目录（src/catalog.ts:140-143）
- 皮肤市场通过 `.npmrc` 中的 `fetch-timeout=600000` 临时延长 pnpm 下载超时；这是为了规避 pnpm 11 把 `--config.fetchTimeout` 当字符串处理导致报错的边界问题（src/lifecycle.ts:117-118）
- 仅面向 DSH Web `0.1.0-rc.6` 完成实机验证；README 明确该组合已通过 132 条目录校验、70 项自动化测试和 5 分钟静默更新测试，但不代表目录内所有第三方皮肤均经过同等级别审核（README.md:182-190）
- 安装、激活、停用等生命周期操作一次只能运行一个；并发请求会被拒绝（src/lifecycle.ts:241）

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-skin-market](https://deepseek-plugin.org/plugins/kingOfSoySauce/dsh-skin-market)
Wiki generated by AI (model: `MiniMax-M3`)
