# dsh-tavern 使用指南

> 适用版本：**2.8.0**（配套 DSH 桌面版 / `dsh web`）
> 数据都在本机 `~/.dsh` 下，插件不上传任何内容。

---

## 0. 三分钟上手

1. 装好插件后**重启 DSH**（新增服务端路由必须重启才生效，只点"重载"不够）。
2. 打开酒馆面板：点左侧栏「新会话」下面的 **🍺 酒馆**（也可以走 设置 → 🍺 酒馆管理）。
3. **角色卡**：把 SillyTavern 的卡（`.png` 或 `.json`）拖进「内容 → 角色卡」。
4. **世界书**（可选）：把世界书 `.json` 拖进「内容 → 世界书」。
5. **选预设**：在这张卡所属的预设上点一下（本页「🎭 当前 Agent 预设」下拉，或聊天顶部的预设选择器）。
6. **新开一个会话**，在顶部选中同一个预设，然后发第一句话。
7. 想要开场白：等这个会话**跑过至少一个回合**，回到「内容 → 📌 开场白」，选角色卡与版本，点「➕ 注入」。

> 面板顶部那张「🚀 快速上手」会按当前数据自检这四步，卡住时看它就行。

---

## 1. 入口

两个入口，内容一模一样：

- **侧边栏「🍺 酒馆」**（推荐）：就在「新会话」下面，和 MUV 表格 / 插件 / 自动化任务 排在一起。
- **设置 → 🍺 酒馆管理**：老入口，保留。

侧边栏打开的是**独立面板**，可以随便摆：

| 操作 | 怎么做 |
|---|---|
| 移动 | 按住顶部标题栏拖 |
| 放大 / 缩小 | 拖右下角的小三角 |
| 最大化 / 还原 | 双击标题栏 |
| 关闭 | Esc，或点面板外的灰色区域 |

位置和大小会记住，下次打开还是你摆的那个样子；把窗口缩小后会自动夹回屏幕内。
**关闭只是隐藏，面板里没保存的编辑还在。**

---

## 2. 面板结构

分类是**顶部一条下划线式页签**，和下面的内容连成一片（不再是一个独立的方框）。

| 分类 | 里面有什么 |
|---|---|
| 🎭 会话 | 当前 Agent 预设（下拉 + 新建 / 复制 / 重命名 / 删除）、当前会话绑定、世界书注入量 |
| 📚 内容 | 角色卡、世界书、开场白、写作模块、**导出**、技能、**显示正则** |
| 🎲 玩法 | 剧情选项、成人向提示段、全局正则 |
| ⚙️ 增强 | 故事背景、记忆与总结、写作辅助、关系网、回复体检；底部是 AI 工具 / 联网 / 反八股开关与「💾 保存预设」 |

底部「💾 保存预设」写的是 `agent.cordis.yml` 与预设目录里的数据文件。

---

## 3. 角色卡

- 拖入 `.png`（ST 卡直接读内嵌数据）或 `.json`；可导入多张，逐张启用/停用/删除。
- **备选开场白**：导入时会保留 ST 的 `alternate_greetings`。
  ⚠️ 旧版本导入的卡在导入时就把备选丢了，**需要把同一张卡重导一次**（同名会提示替换）才能选备选开局。
- 「插入当前对话」= 把卡的文本塞进聊天输入框（方便手动引用），**不是**注入，也不写会话日志。

---

## 4. 世界书

- 拖入 `.json`；按世界书分组，条目可单独启用/停用、可新增条目。
- **注入模式**（省 token 的关键）：
  - **跟随规则 / 关键词触发**：只注入命中触发词的条目（推荐）；
  - **全量注入**：每轮把所有启用条目都塞进去（怕漏设定时用）。
- 两个层级：
  - 全局默认：**会话页签 → 📚 世界书注入量**；
  - 单会话覆盖：**🔗 当前会话绑定 → 📚 本会话设定注入**（🪶 跟随规则 / 💯 全量注入）。
- 三层优先级：本会话指定 > 全局默认 > 世界书自己的模式。

---

## 5. 预设 vs 写作模块（最容易混的地方，先看这段）

DSH 里有两个完全不同的东西：

| 名字 | 是什么 | 在哪 |
|---|---|---|
| **DSH 预设**（agent preset） | 一个目录 = 一张卡（角色卡 + 世界书 + 写作模块 + 记忆） | 聊天顶部选择器 / 本插件「🎭 当前 Agent 预设」下拉 |
| **写作模块** | 这张卡内部的**写作要求**（ST chat-completion 预设导入到这里） | 「内容 → 写作模块」卡片 |

### 导入写作模块（ST 预设）

**先选好「🎭 当前 Agent 预设」，再导入** —— 写作模块是挂在某个预设里的，没有"全局"的写作模块。

1. 在顶部下拉里点一下你要往里加东西的那个预设（面板上「当前 Agent 预设」那行就是它）。
2. 「📚 内容 → 📝 写作模块」→ 把 SillyTavern 的预设 JSON 拖进虚线框，或点「选择文件」。
3. 导入的是**一个包**（能在列表里展开成几十条词条）：启用的条目直接启用，
   被 ST 关掉的变体保留为未勾选，结构占位（Chat History 这类）和 JS 配置块会被丢掉，
   丢了多少条会写在状态行里。
4. 同名包不会覆盖：第二份会叫 `名字 (2)`，两份可以并存对比。

> 2.7.29 之前这里有个 bug：导入时会**偷偷新建一个 Agent 预设**，当前预设的写作模块里当然什么都没有
> （看起来像"导入不进去"）。现在导入只会往当前预设追加。

### 管理预设

- 下拉里每行右侧：**✎ 重命名** / **🗑 删除** —— **不用先切过去**就能改；只对酒馆预设开放，
  内置与其它自定义预设标「只读」。
- **新会话页面顶部**那个「Agent 预设」下拉（DSH 自己渲染的那个）现在也能直接改：
  酒馆预设每一行右侧有 **✎ / 🗑**（鼠标移上去才显示）。同样只对酒馆预设开放，
  内置 / 第三方预设一个都不碰 —— 那是 DSH 的资产，误删没法恢复。
- 还有名称筛选框；删除当前预设会把本会话自动绑到剩下的第一个酒馆预设（避免下一轮静默不注入）。
- 新建 / 复制：会建一个独立目录，卡、世界书、模块都跟着目录走。

### 切换预设的两个注意点

1. **会话已经开跑**后，DSH 会锁住角色卡本体 —— 此时切换只让**世界书 / 记忆 / 关系网**跟随，
   想换卡请**新开会话**并在顶部选新预设。
2. 「插入/生效范围」那类旧概念在 2.7.19 之后已不参与注入：**顶部预设是唯一闸门**，
   没在顶部选酒馆预设的会话，一个字都不注入。

---

## 6. 开场白（含备选开局）

**为什么是手动注入**：插件曾经在新会话自动播种开场白，那会把会话日志写坏（首个 surface 事件必须是
`system/message`），所以现在只在**已经跑过一回合**的会话上、由你点按钮追加。

用法：

1. 「内容 → 📌 开场白」，下拉里选**角色卡**（启用中的卡）；
2. 再选**版本**：`第一开场白` / `备选 1` / `备选 2`…（来自卡的 `alternate_greetings`）；
3. 看一眼「开头预览」，点「➕ 注入开场白」；
4. 回到会话刷新即可看到。同一会话**只能注入一次**（再点会提示已存在）。

---

## 7. 导出（角色卡 / 世界书 / 预设）

「内容 → 📤 导出」：

1. 勾选要导出的内容（角色卡 / 世界书 / 预设，默认全勾）；
2. 选范围：**当前预设** 或 **全部酒馆预设**；
3. 点「📁 选择文件夹并导出」→ 弹**系统原生**的文件夹选择框 → 选一个目录。

落盘结构：

```
<你选的目录>/酒馆导出-<时间戳>/<预设名>/
├── 角色卡/characters.json        原生（面板可直接再导入）
├── 角色卡/<卡名>.json            ST chara_card_v2（含备选开场白）
├── 世界书/worldbooks.json        原生
├── 世界书/<书名>.json            {name, entries[]}
├── 世界书/<书名>.st.json         ST world info
└── 预设/preset.yml · agent.cordis.yml · presets.json · st-preset.json
```

根目录另带 `manifest.json` 与 `说明.txt`（写明怎么导回来）。导出**只读**预设目录，不改任何原文件。

**怎么导回来**

- 面板导入：角色卡拖 `角色卡/<卡名>.json`；世界书拖 `世界书/<书名>.json`；写作要求拖 `预设/st-preset.json`。
- 整预设恢复：把 `预设/` 里的 `preset.yml`、`agent.cordis.yml`、`presets.json` 复制到
  `<DSH_HOME>/.agent-presets/<预设目录>/` 下。

---

## 8. 技能（Skill）

- 「内容 → 🎓 技能」：**保存预设时自动生成**一份 `SKILL.md`（也可手动点生成/删除）。
- **形态**：
  - 📝 **写作指令**（默认）：把预设里启用中的写作要求原文写进技能；
  - 🔍 **设定索引**：只列角色/世界书名，省 token。
- **设定优先级**（技能卡片上的下拉）：
  - `preset`（默认）：角色卡 / 世界书 / 写作模块优先，skill 只补流程与工艺；
  - `skill`：skill 的流程 / 文风 / 禁令优先，角色卡 / 世界书只提供事实设定。
  安全红线在两种模式下都有效。
- 三个开关：保存时自动生成 / 附录世界书全文 / 会话里提示"有此技能"。
- 手动绑定别的 skill：在清单里勾选 →「💾 保存手动绑定」。
- 文件位置：`<DSH_HOME>/skills/<技能名>/SKILL.md`（DSH 会监视该目录，生成后免重启）。
- **技能里带什么**（2.7.26 起）：启用中的写作要求 + **角色卡正文**（`desc` / `text`）+
  独立一节**开场白**（当语气范本，不当设定陈述）。与 persona 完全重复的模块只留一行指针，
  不再抄第二遍（实测曾让 SKILL.md 一半是重复）。开场白外的 `<content>` 草稿容器标签会被剥掉。
- ⚠️ 角色卡本体**仍以 system prompt 注入为准**：技能是"照此扮演"的副本，不是替代品。
  会话没挂酒馆预设时，system prompt 里依旧没有卡（见 §10「卡不见了」）。

---

## 9. 显示正则（2.7.26 新增）

「内容 → 🧹 显示正则」：一张 ST 式的**输出侧脚本**表，每行「查找(正则) / 替换 / 启用」，
整表一起存。出厂自带一条 **unicode 反转义**（`\uXXXX → 原文`），默认开启。

- **它解决什么**：预设里的「防截断」常要求模型把露骨内容写成 `\uXXXX`。模型会照做，
  于是界面上就是一片 `\u55b5\u545c…`。这条规则把它们还原成中文。
- **只改显示**：作用对象是消息里的文本节点；**不进提示词、不改会话日志**，
  也不影响导出（导出的仍是模型原始输出）。
- 查找框是**正则**，替换框支持 `$1` 反向引用；写坏的正则会被**单条丢弃**，不会带崩整页。
- 导入 ST 卡时，卡里携带的输出侧 `regex_scripts` 会自动收进来；
  `promptOnly` / `disabled` 的脚本跳过（它们不属于显示层）。
- 规则存在 `tavern-state.json` 的 `displayRules` 里（仅本机）。关掉开关 ⇒ 一个字符都不改。

### 9.1 角色卡自带的状态栏 / 折叠块（2.8.0）

卡里的 `regex_scripts` 现在**跟着卡一起导入、一起生效**了。也就是说：

- 卡写「`<StatusPlaceHolderImpl/>` → 状态栏 HTML」，消息末尾就会出现那张状态栏；
- 卡写「`<UpdateVariable>…</UpdateVariable>` → 折叠块」，变量更新就会收起，点开能看全文；
- 卡写「选项卡片 / 思维链折叠」，同样按卡自己的样式出。

**样式与脚本都跑在独立沙盒里**（`iframe sandbox="allow-scripts"`，不给同源），所以：

- 卡里的 `body{background:…}` / `*{…}` **不会**漏到消息和面板上（这就是以前"代码外溢"的来源）；
- 不同卡的美化方案互不干扰，切换会话不会残留上一张卡的样式；
- 沙盒里的 JS 拿不到本页的会话、配置和接口。

状态栏右上角悬停会出现 **⤢**：点一下把同一个状态栏开成**浮窗**（拖动标题栏移动、
拖右下角缩放、Esc 关闭，位置和大小会记住）。浮窗和内嵌是同一份内容，只是外壳不同。

模型偶尔会漏写占位符（整条回复没有状态栏）。这时插件会用**卡自己的**脚本补一次；
卡里没有状态栏脚本就什么都不做，不会硬塞一个空框。

> 提示词侧也会按卡里的 `promptOnly` 脚本裁剪历史：上一条回复里的变量块、状态栏占位符
> 不再原样喂回模型（省上下文，也避免模型照着上一轮的变量 JSON 再抄一遍）。
> 出问题时可在 `tavern-state.json` 里设 `"cardRegex": false` 一键关掉整条链路。

---

## 10. 记忆 / 总结 / 关系网 / 故事背景 / 回复体检

都在「⚙️ 增强」页签里：

- **故事背景**：从历史会话读取内容 → 设为故事背景 → 保存后进系统提示。
- **记忆与总结**：API 设置（DSH 连接或手动填 URL/Key/模型）、玩家名、自动总结、手动总结、记忆保存/读取/清除。
  记忆是**会话级**的，新对话不继承。
- **关系网**：总结时自动提取，可手动编辑 JSON，也可「软注入」只提醒模型"有关系网"。
- **写作辅助**：违禁词列表（进提示词的"词汇禁令"段）。
- **回复体检**：判断上一条回复是模型拒答、还是插件没注入。

---

## 11. 玩法

- **🎭 剧情选项**：要求模型在结尾给可选行动，并渲染成可点按钮。
- **🔞 成人向提示段**：插件只提供"槽位 + 开关"，正文由你自己填，存在本机 `tavern-state.json`，不进代码/发布包。
- **🧩 全局正则**：导入 ST 的正则脚本（依赖 `dsh-muv-engine`；引擎没装/没重启时整卡降级提示）。

---

## 12. 常见问题

**设置里找不到「🍺 酒馆管理」入口？**
先**完全退出** DSH（托盘右键 → 退出）再打开。新增服务端路由必须重启；只关窗口可能只是隐藏。
仍不出现时，检查插件目录是否完整（`lib/server/*.js` 齐全，尤其新增文件），
以及多个 profile 是否都更新了（见下一条）。

**机器上有多个 profile（`web` / `desktop`）？**
它们共用同一份插件文件，但目录之间是**逐文件硬链接**：覆盖已有文件会两边一起变，
**新增文件只落在你写入的那一边**。手工更新后务必对比两侧文件清单，否则缺文件的一侧会在启动时
`ERR_MODULE_NOT_FOUND`，整个插件挂载失败（表现就是入口消失）。

**插件市场更新报 `already-installed`？**
这是市场更新路径对带依赖的插件的老问题（与插件版本无关）。可先忽略；
需要更新时用正规安装（市场/`dsh plugin`）或手工覆盖后重启。

**世界书"没生效"？**
按顺序查：① 会话顶部是否选了酒馆预设；② 「本会话设定注入」是不是"跟随规则"而触发词没出现；
③ 条目是否启用；④ 「回复体检」里看本轮注入了多少字。

**角色卡里的 `{{user}}` / `{{char}}`？**
导入和保存时会被替换/清理（DSH 不认识 ST 宏），这是预期行为。

**「一让模型读 skill，我的卡就不见了」？**
先确认**不是** skill 的锅：skill 只是副本，卡本体走 system prompt。
按顺序查：① 会话**顶部选择器**选的是不是酒馆预设（`standard` 就是没有卡）；
② 会话是否**已开跑**（开跑后 DSH 锁死卡本体，只能新开会话）；
③ 面板「回复体检」看本轮注入字数；④ 2.7.26 起 skill 里也会带卡正文，
   如果 skill 里也没有，说明这张卡根本没启用（`characters.json` 里 `enabled: false`）。

**界面上一片 `\u55b5\u545c…` 反斜杠乱码？**
这是预设里的「防截断」要求模型把内容写成 `\uXXXX`（模型照做了，不是编码坏了）。
「内容 → 🧹 显示正则」里确认 **unicode 反转义** 那条是启用状态即可还原成中文；
会话记录本身仍是转义形态（插件不改写会话日志）。

---

## 13. 数据与配置位置

```
<DSH_HOME>/.agent-presets/            # 默认 ~/.dsh/.agent-presets
├── presets.json                      # 预设注册表（名字/模式/构成）
├── session-bindings.json             # 会话绑定
├── tavern-state.json                 # 全局开关（含成人段正文、玩家名等，仅本机）
└── <预设目录>/
    ├── preset.yml                    # 预设元数据（名字/描述）
    ├── agent.cordis.yml              # 角色卡正文（合并后）
    ├── characters.json               # 角色卡列表（含 alternates 备选开场白）
    ├── worldbooks.json               # 世界书（v2 结构）
    ├── presets.json                  # 写作要求模块
    └── memory.md / relations.json    # 预设级记忆与关系（历史兼容）

<DSH_HOME>/tavern-data/sessions/<sessionId>/   # 会话级记忆与关系
<DSH_HOME>/skills/<技能名>/SKILL.md            # 生成的技能
```
