# 跨平台安装与卸载
当前目标 DSH 为 `0.1.5-rc.1`;从较早 DSH 坐标格式迁移现有周目时,先按 [升级指南](DSH_0.1.5_MIGRATION.md) 操作。该 DSH 版本要求 Node `^22.19.0 || >=24.0.0`,不能只依据 Tavern 的 Node 20 声明。
[English](INSTALLATION_en.md)
本文面向 Tavern `2.3.1`,运行时验收目标是 DSH `0.1.5-rc.1`。根目录默认 [README](../README.md) 为中文;英文落地页是 [README_en.md](../README_en.md)(无截图)。本文是当前安装生命周期、验收与恢复合同。其他版本请切换到对应 tag,并阅读该 tag 内的安装说明。
脚本以 Node.js 为统一入口,并规范化 Windows、macOS 和 Linux 路径。macOS/Linux 直接执行 `dsh`。Windows 会安全定位 npm 的 `dsh.ps1` shim,再通过系统 PowerShell 以参数数组调用,因此路径不会被拼回 shell 命令文本。请在 `dsh-tavern` 检出目录中运行脚本,并准备 Node.js 20 或更高版本,以及位于 `PATH` 上的目标 DSH `0.1.5-rc.1`;启动 Host 时需满足上面的 Node 要求。
只安装仓库根包。`packages/tavern-format`、`packages/preset` 和 `packages/tavern-loader` 是随同一插件发布的内部边界,不要单独把它们加进 dsh。格式层可通过根包导出作为 JavaScript 库使用,但它本身故意没有把内容发给 agent 的效果。
## 安装 2.3.1
从 GitHub 安装 `2.3.1` 到默认 `web` profile,请使用固定版本标签:
```text
dsh plugin --profile web add github:Player-MINEPIG/dsh-tavern#v2.3.1
```
### 从源码安装和验收
使用独立测试 profile/home,安装前停止该 Host。检出 `v2.3.1` 标签后从源码安装:
```sh
git clone --branch v2.3.1 https://github.com/Player-MINEPIG/dsh-tavern.git
cd dsh-tavern
npm ci --legacy-peer-deps
node scripts/install.mjs --dsh-home /absolute/path/to/test-home --profile web
```
用同一个 `DSH_HOME` 启动 DSH `0.1.5-rc.1`,再按 [开发验证指南](TESTING.md)检查。
只升级 CLI 不会更新 profile 中的插件。用 `git rev-parse HEAD` 记录所验收构建。
### DSH 提供官方运行依赖
`package.json` 当前把 `@deepseek-ai/dsh-util-crypto` 的 `0.1.2-rc.1 || 0.1.5-rc.1` 与 `@deepseek-ai/cordis` 的 `4.0.2` 声明为必需 `peerDependencies`,由 DSH 运行时提供,避免插件安装第二份。源码构建和测试使用 `devDependencies` 中固定的 `0.1.2-rc.1` crypto 包。浏览器合同由 `dsh.client.inject` 声明并由 DSH 提供,不随 Tavern 打包。
DSH profile 使用 `nodeLinker: hoisted` 和 `autoInstallPeers: false` 时,会在启动期通过 `/profiles/node_modules` 提供自身安装所携带的包,供插件按 Node 的父目录规则解析。因此 `dsh plugin add` 或 `pnpm peers check` 可能报告这两个包缺失:该静态检查不识别 DSH 的启动期依赖提供机制。运行时仍必须能从 DSH 安装目录解析这两个包。
若重启后仍出现 `ERR_MODULE_NOT_FOUND`,则不是可忽略的安装警告;请检查 `PATH` 中的 DSH 是否为目标 `0.1.5-rc.1`、安装是否完整及实际模块解析路径。不要为消除警告把必需 peer 标成 optional。精确 peer 声明约束的是对应包,不是自动检查整个 DSH 版本的启动门禁。
### 数据与源码安装
首次启动时,Tavern 会在 `/pmp-dsh-tavern/` 自动创建持久目录,不要求用户选择内部存储位置。普通 `dsh plugin remove` 只移除 profile 中的软件包,保留该目录,但不会调用项目的备份逻辑或创建卸载前快照;需要快照时请按下文检出仓库并使用 `npm run plugin:uninstall`。
从源码开发、从旧版包内 `data/` 安全迁移,或准备使用下文的备份卸载流程时,先检出仓库并安装一次依赖:
```text
npm install --cache .npm-cache
npm run plugin:install
```
安装器会构建 `dist/client.js`,不经过 shell 调用 `dsh plugin ... add`,并打印重启提醒。审查前请重启当前正在运行的 `dsh web`。
更新已有安装前,先停止目标 `dsh web`。持久目录位于软件包之外,重复安装不会触碰它。为支持仍使用旧版包内 `data/` 的安装,脚本还会在 remove/add 前把该旧目录暂存到 `/backups/pmp-dsh-tavern/pending-refresh-/`,add 成功后恢复到新包;新 Host 首次启动时,若外部目录为空,就通过同目录临时副本把旧数据原子发布到 `/pmp-dsh-tavern/`,写入迁移标记并保留旧副本。若外部目录已有数据则绝不覆盖,只记录告警。若 remove/add 失败,错误信息会打印 pending 路径;下一次运行安装器会修复中断的依赖注册并继续恢复。恢复尚未完成时,不要删除该目录。
刷新仍会把当前 worktree 声明的 `files` 条目物化为独立副本,以规避 pnpm 的旧目录快照和硬链接混合版本问题;它不触碰 pnpm 管理的嵌套 `node_modules`,并在替换文件前确认安装目标仍位于所选 profile。省略 `--store-dir` 时,更新器读取该 profile 的 `node_modules/.modules.yaml` 中已记录的 store,以避免 `ERR_PNPM_UNEXPECTED_STORE`。
常用参数:
```text
node scripts/install.mjs --profile web
node scripts/install.mjs --skip-build
node scripts/install.mjs --dsh-home /absolute/test/home
node scripts/install.mjs --store-dir /absolute/pnpm/store
node scripts/install.mjs --dry-run
```
传参数时请直接用 `node` 形式,以免不同 npm 版本和 PowerShell 在 `npm run` 之后转发参数不一致。
Windows 路径可按本机写法传入,例如:
```text
node scripts/install.mjs --dsh-home .\test-envs\review
```
## 发布验收
打包或安装当前源码前,运行发布验证命令(命令名仍为 `verify:2.0`):
```text
npm run verify:2.0
```
该命令覆盖 Trace v3 与真实 AgentLoop、session 坐标 codec、history/游标守卫、受管文档与 CAS、import claim/lineage、chrome/slot 所有权、本地化和安装边界,随后构建已跟踪的浏览器 bundle 并执行 `npm pack --dry-run`。
将 `DSH_TAVERN_COMPAT_ROOT` 和 `DSH_TAVERN_PROMPT_COMPAT_ROOT` 指向目标 DSH 安装的依赖根目录才能启用真实运行时检查;未设置时对应测试明确跳过。另运行 `npm run check` 覆盖全套测试。
这些命令不能替代 [目标 Host 与浏览器的运行时验证](TESTING.md)。
## 卸载
```text
npm run plugin:uninstall
```
在调用 `dsh plugin ... remove` 之前,卸载器会把默认持久目录复制到:
```text
/backups/pmp-dsh-tavern//
```
默认源目录是 `/pmp-dsh-tavern/`。它包含预设、归一化角色卡、从 PNG 导入时留在 `character-artifacts/` 的封面图、`world-books/` 下的独立世界书、`users/` 下的三字段用户资源、`tavern-trace-records.json` 中的 schema 4 Trace metadata/官方历史引用,以及 per-session 资源选择。升级目录还可能保留只读的旧 `tavern-traces.json` 元数据与旧 `tavern-assemblies.json` schema 3 正文快照;后者可能含敏感提示词。备份时复制整个目录;只复制 `presets/` 会丢失其他资源、审计 metadata 和绑定。同一棵树里还有 `state.json`、`character-state.json`、`user-world-book-bindings.json`、`resource-world-book-bindings.json`、`session-templates.json`、`chrome.json`、`play-workspace.json`、`import-context-bindings.json`、`ui-settings.json`(语言、外层 UI 缩放、绑卡跟随 RP)、`conversation-settings.json`(魔丸 RP 正文与消息动作缩放),以及可选的 `rp-policy.json`。
`play-workspace.json` 只是指针。所选 DSH RP 工作区才拥有真正的 `catalog.json`、各周目 `timeline.json`、显示正则文档和导入上下文文件;timeline 引用的会话正文与分支历史仍在对应 `DSH_HOME` 的官方 session 日志中。若周目必须可恢复,请同时备份 Tavern 持久目录、RP 工作区和对应 DSH 数据(包括会话日志及继承依赖);ST JSONL 导出只保留当前选中的线性对话和已知 swipe,不能保存完整的 Tavern 分支拓扑。
选择其他备份目录,或明确跳过备份:
```text
node scripts/uninstall.mjs --backup-dir /absolute/backup/path
node scripts/uninstall.mjs --storage-dir /absolute/custom/storage
node scripts/uninstall.mjs --no-backup
```
`--storage-dir` 让卸载器为显式配置的自定义存储目录创建快照。`--no-backup` 只跳过这次快照;普通卸载仍保留默认或自定义持久目录,也不删除当初用于导入的外部 ST 源文件。若用户明确要清除数据,应在确认备份后单独删除持久目录,而不是把“卸载软件包”与“清空用户内容”合并为一个隐式动作。
卸载同样支持这些常用参数:`--profile`、`--dsh-home`、`--store-dir`、`--storage-dir` 和 `--dry-run`。完整命令摘要见 `--help`。