dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
把 DSH(deepseek-harness)扩展成兼容 SillyTavern 生态的原生角色扮演工作区。
第一版主线已经可用:插件复用 DSH 的 LLM 路由、默认模型、密钥管理、Web 容器和插件安装机制,同时在 DSH 原生侧边栏和 conversation 区域提供 Tavern 角色扮演体验。管理入口是独立的 Tavern 面板;设置页保留当前配置的快速切换,不再承载全部资产管理表单。
在此之上,交互面提供持续指引、行动候选与带意见重写;资产面提供 MVU 变量结算回执、卡片工作台(对话改卡 + 确认协议)与剧本游玩;扩展面提供 Mod 扩展接口与官方示例(提案 0009-0015,均已实现)。
当前面向 DSH 0.2.0-rc.2 验证。Fabric 不在第一版运行路径中。
chara/ccv3,以及 CHARX card.json 和 embeded:// assets。prompts[]、prompt_order[]、marker 和采样参数。swipes、swipe_id、swipe_info。decisions/2026-10-11-st-reasoning-stream.md。chat_metadata.bookmark_link 回链,视图可跳回父聊天。docs/proposals/0009-conversation-guides.md。docs/proposals/0010-turn-candidates.md。docs/proposals/0011-rewrite-with-feedback.md。position/depth/role 注入。group_only_greetings、group nudge 和 {{group}} 宏。USER_INPUT/AI_OUTPUT/WORLD_INFO/REASONING placement、minDepth/maxDepth、substituteRegex、trimStrings。/if 条件、随机/掷骰和聊天动作(/send、/trigger、/regenerate、/cut),composer / 前缀触发。<% %> JavaScript(node:vm 沙箱);getvar/setvar 族带作用域变量(chat local 任意 JSON / scriptGlobals 全局 / InitialVariables 初值);[GENERATE:*] / [RENDER:*] 内容注入、@INJECT 整消息插队、[InitialVariables] 变量树、getwi/getchar/getpreset 资产读取、@@if/@@private 装饰器与 <#escape-ejs> 保护块。详见 docs/proposals/0008-prompt-template.md。409,客户端重新加载最新内容,不静默覆盖。sessions.fork API 分叉一个 AgentTavern 会话,子会话首次运行时插件为其物化新 Tavern 聊天( - fork N 命名、bookmark_link 回链父聊天切点、guides 与 MVU 回执随 header 继承),拷贝 chat 作用域变量/记忆/向量,按父 contextMode 落绑定,并把继承前缀投影回填为新聊天楼层——工具面、上下文装配与锚定 cadence 从首轮起完整可用;subagent 子会话与 ST/AgentNovel/工作台会话的分叉不在收养面。激活预设同样生效:启用的内容型提示词按 prompt_order 顺序注入会话 system prompt(main/jailbreak 保留角色卡 system_prompt/post_history_instructions 覆盖语义),采样只投影 temperature;资产类 marker(角色卡字段、世界书、示例对话、历史)不重复固定注入,仍由工具、原生历史与可选预载承接。可选开关会在新 AgentTavern 会话初始化时一次性预载角色信息和常驻世界书条目,默认关闭且不追溯修改已有会话。现有 ST 兼容架构继续保留。分叉收养详见 decisions/2026-10-11-agent-tavern-host-fork.md。0.1.0-rc.6(宿主尚未提供 agent/context 历史投影和 projection-aware compaction);0.2.0-rc.2 已确认仍未提供该 seam。插件不会把普通 compaction 冒充为主动遗忘,也不会静默回退到伪 managed 模式。详见 docs/exploration/2026-08-16-dsh-agentloop-native-audit.md。chat_metadata.variables,AgentTavern 聊天读 chat 作用域变量存储并覆盖回同一棵嵌套树),只有回执、没有变量落盘的失败轮同样可见。AgentTavern 侧提供 tavern_variable_settle 工具,ST 侧走同一结算语义与回执投影。变量树根可选 $schema 子树是写入守卫(结构/类型锁定、$range/$step 越界 clamp、$enum 枚举拒绝、$ro 只读、"*" 通配与数组项模板):clamp 进正常回执(reason 标注 guard),违规进失败项可重试,无 $schema 的卡行为不变。变量树根还可选 $rules 子树声明条件规则(when/then 表达式,求值走模板沙箱、Date/random 等不确定性源遮蔽):结算守卫之后做确定性二次计算(阈值触发、派生值、连锁修正,链式求值有 3 轮上限),变更 reason 标 rule:<名字> 进同一回执——v1 无编辑 UI,规则在卡 JSON 里手写。回执可撤销(newest-first 链,只能撤最新一条有效回执):每项变更恢复到回执记录的 before 值(恢复值过守卫,被拒整次不动),已撤销回执灰显,两架构与面板按钮同权。详见 docs/proposals/0012-mvu-settlement.md 与 decisions/2026-10-11-mvu-schema-guard.md、decisions/2026-10-11-mvu-receipt-undo.md、decisions/2026-10-11-mvu-rules.md。dsh-tavern/card-workbench agent preset。用对话描述想改什么,Agent 先给出方案,经确认面板(diff 视图)确认后才写入——写入工具必须携带已确认方案的 planId。支持修改人物卡/世界书/预设、空白建卡、从素材或剧本提取人物制卡、card-to-mvu 转换(写入固定状态栏模板与新聊天初始变量),以及把指定聊天连同楼层范围交给工作台排错。导入资产时写一次原版快照,随时可恢复原版。写卡 Agent 落盘后面板自动吸收:打开面板即重取最新资产,页面可见期间按 store 变更水位(3s)轮询,写入到列表可见不需手动刷新页面。面板「预设」分区的「预设生效范围」可让工作台(引用式,供起草卡面对齐风格与排错还原对局提示词环境)与小说推演(跟随式风格栈)接入激活预设堆栈,两者默认关闭。详见 docs/proposals/0013-card-workbench.md、decisions/2026-10-09-workbench-novel-preset-projection.md。docs/proposals/0014-script-play.md。html 代码块会在隔离 iframe 中运行,支持内联 CSS、JavaScript 和常用 CDN 资源;普通文本与不完整流式内容仍按文本显示。mod.json 的目录放进 $DSH_HOME/tavern/mods/(或面板内 git 一键安装)即可被识别,默认禁用;首次启用弹确认层如实展示其声明的能力面(知情同意,含无沙箱告知)。启用后的 Mod 可注册:五相位生成 hook(user-input / pre-assemble / pre-llm / post-output / post-save,顺序 waterfall,抛错 / 超时 / 忘 return 统一降级、不中断生成)、Agent 工具(强制 <modId>_ 前缀并与内置工具三层查重,冲突即拒)、宿主宏与 STscript 命令(确定性筛查,首错降级保原文)、prompt 分区(order 宿主钳制 -50..0 防冲核心位)、带配额的持久化存储(单值 256KB / 总量 1MB)、HTTP 子路由(/api/dsh-tavern/mods/<id>/,path 白名单拒穿越)与沙箱化面板 UI(sandbox="allow-scripts" iframe,无 same-origin,CSP connect-src 'none',postMessage 数据桥);llm 调用能力按 manifest 声明门控,用量进审计。坏 Mod 只记审计跳过、不拖垮本体;禁用 / 卸载全注册面回收,全部装载与调用行为落审计日志;DSH_TAVERN_DISABLE_MODS 可硬关整个 Mod 系统。开发者文档见 docs/mods/mod-api.md,官方示例 asset-stats / mood-tracker / story-clock 覆盖 v1 全部能力面;Mod 还可声明按钮(manifest buttons → 面板与 ST 聊天视图渲染 chip,点击分发到 api.onButton handler)、接收本客户端写入的下行事件推送(聊天保存/资产保存/guides/按钮点击,dsh-tavern:mod-event),Mod UI 的 console 输出自动回投宿主的 per-mod 日志查看器(内存环形缓冲,dsh-tavern:mod-log)。decisions/2026-10-11-prompt-viewer.md 与 decisions/2026-10-11-agent-prompt-viewer.md。把完整 HTML 文档、<head>/<body> 片段放进助手消息,或使用 html Markdown 代码块。消息保存后,
Tavern transcript 会识别并挂载前端;流式生成和编辑消息时仍显示源码,避免半成品脚本被重复执行。
支持的输入形式:
<!doctype html>... 或同时包含 <html> 与 <head>/<body> 的文档。<head> 或 <body> 的片段;缺少外层文档时,运行时会自动补齐 doctype、viewport 和基础样式。html;普通代码块和不完整 HTML 仍按文本显示。例如:
```html
<!doctype html>
<html>
<body>
<button id="counter">0</button>
<script>
let count = 0
document.querySelector('#counter').onclick = () => {
document.querySelector('#counter').textContent = String(++count)
}
</script>
</body>
</html>
```
每个前端使用 sandbox="allow-scripts" 的独立 iframe,且不授予 allow-same-origin:脚本不能读取或操作宿主页面、
Cookie、window.parent、TavernHelper 和 DSH API(高度回传仅使用受校验的 postMessage)。运行时 CSP 允许内联 CSS/JavaScript,
以及以下静态资源源:cdn.jsdelivr.net、testingcf.jsdelivr.net、cdn.tailwindcss.com、
cdnjs.cloudflare.com、unpkg.com、esm.sh、fonts.googleapis.com 和 fonts.gstatic.com;图片、字体和媒体
可使用 https:、data: 或 blob: URL。
以下能力明确不在运行时范围内:
fetch、XHR、WebSocket 等业务网络连接(connect-src 'none')。object/插件、表单提交和访问宿主 DOM、Cookie、存储或 API。iframe 高度由 ResizeObserver 回传,并限制在 80-1200px;超出部分在 iframe 内滚动。TUI/headless
仍显示原始消息文本,不执行前端脚本。
安装插件并重启 DSH 后,可以在 Tavern 聊天中发送上面的示例,或让模型生成一个带按钮的 html 代码块,
保存消息后点击按钮即可验证 HTML、CSS 和 JavaScript 是否正常运行。
点击 DSH 原生侧栏底部的 Tavern 按钮即可打开管理面板。面板采用与 DSH Settings 接近的两栏布局,左侧切换分区,右侧集中处理资产和行为配置;窄屏会自动将分区导航折叠为横向滚动栏。导航列里「Tavern + 版本号」品牌块常驻不滚,只有分区清单自己滚动(分区数会随 Mod 追加而增长,滚动余量不该吃掉面板的身份信息);右侧分区标题栏同理固定,只有内容区滚动。分区图标按语义取形——「游戏」是手柄图标(与「总览」的 sparkle 区分,「游戏」的四种入口:面板分区、右侧栏 tab、标题栏按钮、空态卡同款)。
面板包含以下分区:
decisions/2026-10-11-preview-generation.md)。聊天排错按聊天粒度组织:侧边栏聊天行的写卡按钮为该聊天拉起/复用专属写卡工作会话(每个聊天一个,落在专用内部工作区,集中显示在侧边栏「写卡工作台」分组),也可拉起不绑定聊天的自由工作台;Agent 用 chat_log_read 引用指定聊天与楼层范围。编辑器会显示未保存状态,取消离开时提示确认,页面关闭时提供浏览器级离开保护。角色卡、世界书和预设的保存都经过服务端格式校验,再写回 $DSH_HOME/tavern/。
插件保留独立的 RP prompt/生成循环,但 UI 进入 DSH 原生表面:
| DSH slot | 用途 |
|---|---|
conversation.view | Tavern JSONL transcript |
conversation.composer | Tavern session 的 RP 输入框、模型选择与 Stop |
conversation.session.header.actions | 当前角色、regenerate 与原生 session stats |
settings.section | Active setup 快速切换与打开 Tavern 面板的入口 |
shell.overlay | Tavern 管理面板 Modal,以及侧栏聊天树 adapter 的生命周期承载 |
sidebar.footer.action | 常驻 Tavern 面板按钮,与原生 Settings 并列 |
DSH rc.6 没有可追加到原生 session tree 的正式 list slot。侧边栏因此使用一个集中、版本敏感但失败关闭的 DOM adapter:只匹配可见左侧 [role="tree"],按 workspace 路径/ID 隐藏 Tavern (internal) 分组,并按 state.sessionBindings 过滤旧版 Tavern 会话行;同时插入具名 data-dsh-tavern-sidebar-host。宿主重绘或虚拟列表更新时会重新应用过滤,解绑或卸载时可逆恢复。面板入口本身走官方 sidebar.footer.action,不会替换 Settings,也不依赖 adapter 是否成功挂载。侧栏「酒馆」与「写卡工作台」分区标题行可点击整块折叠(chevron + aria-expanded,折叠时「新建自由写卡工作台」按钮仍可用);docked 侧栏门户与管理面板聊天分区两个挂载点共享同一折叠态,页面重载恢复全展开。
每个 Tavern chat 绑定一个正式 DSH session。绑定 API 通过插件内部桥接追加 plugin notice marker,使 session 进入 active 状态而不调用模型;Tavern view、composer 和标题栏 action 仅接管带有效 Tavern marker 的 session,普通 DSH 会话保持原生表面。酒馆标题栏会局部隐藏 DSH 自带的 agent preset 标签,并在切换回普通会话时恢复;Tavern 自建生成循环会把 turn/step、流式 chunk、assistant message 和 provider usage 镜像进同一 session,因此标题栏直接复用 DSH 的 sessionStats / tokenUsage projection。删除聊天时会追加 close marker 并归档对应 DSH session。
| 架构 / 模式 | 状态 | 实际行为 |
|---|---|---|
agent-tavern + dsh-native | rc.6 可用,单角色新聊天默认启用 | 使用 DSH 原生 AgentLoop 和 composer;模型、工具调用、Stop、错误与统计都由宿主处理,原生 user/final assistant 事件投影到 Tavern JSONL。激活预设以 dsh-tavern:agent-preset systemPrompt section 注入(内容提示词 + temperature;资产 marker 由工具与可选预载承接)。 |
agent-tavern + agent-managed | rc.6 不可用 | 设置页显示宿主缺少 agent/context 与 projection-aware compaction 的原因并禁用选项;服务端也会拒绝该模式。 |
st | 保留并兼容 | 使用 Tavern 自有 /generate、流式生成、swipe、regenerate 和 STscript 路径。 |
| 群聊 | 固定使用 st | 宿主尚未提供可靠的 actor 元数据前,不创建群聊 AgentTavern 会话。 |
AgentTavern 工具的身份来自真实 DSH agent binding,模型不能通过参数伪造 sessionId、scopeId、角色或聊天身份。当前工具面如下:
| 工具 | 作用 |
|---|---|
tavern_character_get | 读取当前绑定角色的名称、昵称、身份摘要、描述、性格、场景和角色卡版本。 |
tavern_lore_search | 按查询词和预算检索全局启用、角色关联及卡内嵌世界书。 |
tavern_history_search | 在当前绑定聊天(可选回溯 bookmark 父分支)按词法检索历史消息。 |
tavern_scene_get | 读取当前绑定聊天的场景、消息数量和聊天元数据。 |
memory_search | 在当前 chat、character、agent 或 global 作用域做有来源的词法记忆检索;配置 embed 来源后升级为词法 + 语义的混合检索(RRF 融合,可选配置、默认关闭)。来源两种(面板「检索模式」三态下拉切换:关闭/远程/本地):OpenAI 兼容远程端点(提案 0016),或本地 ONNX 模型目录(提案 0017——管理面板一键安装运行时(profile 根执行 pnpm add,装完即生效免重启),经 onnxruntime-node 进程内推理,离线零网络;池化/维度留空时按模型目录自动推断;量化精度下拉按目录智能识别可选档位、默认自动取 FP16 优先链(2026-10-13 补记),推荐 Xenova/bge-small-zh-v1.5,ModelScope 有镜像)。 |
memory_read | 按稳定 id 读取一条记忆及其来源。 |
memory_write | 在选定作用域写入带来源、标签、置信度的记忆;global 写入需在设置中显式开启。 |
memory_update | 按 id + expected revision 条件更新记忆,未提供的字段保持原值。 |
memory_forget | 按 id + expected revision 软删除记忆,保留审计记录。 |
| 记忆维护 | 记忆工具之外,管理面板「记忆检索」分区可对单个聊天手动发起记忆维护 run(服务端维护 LLM,非模型工具面):按原文依据合并跨写入批次的重复事件、纠正冲突陈述、删除被证伪记录;完成收据记录楼面指纹与记录版本快照,原文或记忆再被改动即退役、对应范围下轮重扫(决策 2026-10-11-memory-maintenance)。 |
variable_get | 读取当前作用域中的 typed JSON 变量。 |
variable_set | 写入变量并支持 expected revision 的 CAS 冲突保护。 |
variable_patch | 在同一作用域原子写入多个变量,任一 revision 冲突则整批失败。 |
variable_delete | 删除当前作用域变量,需 revision 匹配。 |
variable_list | 按前缀列出作用域内变量名和值摘要。 |
tavern_variable_settle | 单轮批量结算受追踪变量:写 chat 作用域变量并记录 MVU 回执(每项变更前后值、失败项)与审计行;失败项重试是新的一次结算,正文不受影响。 |
tavern_script_read | 读取当前绑定剧本在进度位置(或指定 chunkIndex)的片段;未绑定剧本时返回 found:false 可优雅跳过。 |
tavern_script_advance | 最新正文实际覆盖当前片段后推进一格进度(玩家偏离不推进),记录 alignedAt 与可选备注;最后一段返回 done:true。 |
game_list | 列出内置/导入/Mod 三源游戏(id、名称、人数、动作词汇表——用 id 调 game_start)与本聊天会话(sessionId、游戏名、轮到谁、终局态、手数)。 |
game_start | 用 gameId 在当前绑定聊天开一局(可选 role 选 Agent 执方,缺省后手);返回会话身份(sessionId、游戏名、players 角色归属、先手方)——不含棋盘(token 经济:局面经 game_state 按需读取)。人类执先时开局后立即 game_wait。 |
game_state | 读取当前局面(扁平最小载荷):state 棋盘、legal 建议集、轮到谁(turn/turnOwner)、moveCount、终局态(finished/winner/summary);不含动作日志——往手经 game_history 读取。 |
game_history | 读取动作日志(交互历史):每条 {actor, action, describe}(describe 即该手叙述文案);缺省返回最近 20 手,from(0 基下标)+ limit(上限 200)分页,moveCount 是日志总量。 |
game_move | Agent 落子(与人类玩家共用同一动作语言与引擎合法性终审);返回 describe 叙述文案与轮次/终局态(finished/winner/summary)——不回吐棋盘与日志(读归读、写归写),可直接用于对话。落到人类回合后接 game_wait。{type:"resign"} 认输——面板开启「禁用投降」后两个动作入口(人类棋盘/本工具)一致拒绝。 |
game_wait | 阻塞等待人类在棋盘上落子(2026-10-14 修订;同日 token 经济修订):Agent 在自己回合内挂起,人类落子经跨 bundle 写穿唤醒,工具只返回等待期增量——newMoves(等待期到达的手,通常即人类刚落的那手,{actor, action, describe} 供叙述;已在 Agent 回合时恒空——落子前的局面经 game_state 读取)与轮次/终局态,Agent 同回合自动续弈——用户无需发送聊天消息触发下一步。timeoutMs 限 1000..900000(缺省 300000);超时返回 status:"timeout" 不报错(模型可再等);用户停止生成时随 exec.signal 中止。Agent 没 wait 就结束回合时同样不丢手:人类落子由插件侧自动唤起(经宿主 followup 投递一条插件来源的「自动游戏通知」消息)——投递过两道闸:game_wait 挂起中不重复投递,且只在该手真正交出回合(或终局)且 Agent 无运行中回合时投递(2026-10-15 竞态修订:单回合多动作的大富翁决定窗 roll / 21 点连续 hit 等中途动作不提前唤醒;运行中的回合经自己的 game_wait/game_state 读面吸收该手)——两个方向都不需要用户发聊天消息。对局棋盘自动显示在与 MVU 状态同位的地方:ST 架构内联在聊天视图 MVU 状态卡下方,AgentTavern 架构为 DSH 原生右侧栏「游戏对局」tab(开局自动展开;标题栏另有与 MVU 同位同款的入口按钮)——棋盘经「先读水位基线再拉数据」的两档轮询(对局中 1s/守望 5s)自动刷新。 |
变量工具支持 chat、character、agent、global 与 turn 作用域;turn 作用域是单轮 scratch 状态,turn 结束时自动清空,global 写入默认关闭、需在设置中开启。角色卡支持可编辑的 agentTavern.identitySummary 身份摘要(管理面板角色编辑器内),AgentTavern 内核每轮注入该摘要;缺失时回退为名称和极短描述。投影失败时管理面板"变量"分区提供状态查询和一键重放入口。
ST 与 AgentTavern 新聊天共用 $DSH_HOME/tavern/workspace/ 下的 Tavern (internal) 工作区;插件按 workspace 路径/ID 从原生侧边栏隐藏整个分组,旧宿主没有身份属性时仅在标题唯一时回退。升级前已经存在的宿主会话不会跨工作区迁移,但绑定的 Tavern 会话行仍会按插件过滤。
agent-novel 是与 AgentTavern、ST 并列的第三种会话架构:全自动小说推演(提案 0005、写手子代理补充见 提案 0007)。先落盘大纲再分单元写作,正文只经 novel_body_commit 原子提交,作者指令走台账 + 修订协议,冲突指令必须引用用户澄清/撤回消息才能解除。
| 能力面 | 状态 |
|---|---|
| 存储 / 调度 / 提交协议 | 可用:HEAD 单一提交点、不可变修订快照、单写者所有权、认领令牌与幂等重试 |
| 作者干预 | 可用:指令接收屏障、修订覆盖层(chapters overlay + droppedChapterIds)、blocked 冲突暂停与澄清引用解除 |
| 写手子代理 | 可用(`writerMode: inline |
| 阅读 / 导出 | 可用:章节 Markdown 投影、ZIP 导出、记忆检索索引 |
模型侧工具面(novel_*,身份一律来自会话绑定,不接受参数传入 novelId):novel_status_read、novel_requirements_read、novel_outline_read/create/revise、novel_requirement_block、novel_unit_claim/supersede、novel_body_commit/read/search、novel_chapter_complete、novel_finish、novel_character_read、novel_lore_search、novel_facts_read、novel_writer_draft/delegate,以及绑定小说作用域的 memory_search / memory_read 和 tavern_deduce 适配器。设计契约以提案 0005 §11 工具表为准。
| Package | 说明 |
|---|---|
@dsh-tavern/format | 卡、PNG/CHARX、世界书、preset(chat completion / context / instruct / textgen)、群组文件、regex 脚本和 chat JSONL 的解析与无损往返 |
@dsh-tavern/lore | World Info 激活和 timed effects 引擎 |
@dsh-tavern/macros | 角色、时间、随机、变量等宏引擎 |
@dsh-tavern/pipeline | preset 顺序、lore、persona、历史和 token budget 的 prompt 装配(chat completion + 群聊回合) |
@dsh-tavern/script | ST regex 脚本执行器与 STscript 解释器 |
@dsh-tavern/store | $DSH_HOME/tavern/ 原子文件存储、revision 和 session binding |
@dsh-tavern/template | EJS Prompt Template 引擎:node:vm 沙箱执行、作用域变量与内容注入(提案 0008) |
@dsh-tavern/bind | 跨 DSH 版本的宿主形状兼容层:会话事件探测、宿主包锚解析、client 连接双面回退与宿主形状诊断 |
dsh-tavern | 自包含 Node half(含 agent / compaction / novel / card-workbench 入口,以及 Mod 加载器与能力面宿主 src/mods/,提案 0015)、Web client half(含 Mods 面板分区与 Mod iframe 桥)、随附示例 Mod(examples/mods/,三个示例覆盖 v1 全部能力面:asset-stats 资产只读统计、mood-tracker post-output hook + 情绪工具对 + iframe 面板、story-clock 剧情时钟——聊天变量 clock + {{clock}} 宏 + /clock 命令族 + llm 门控摘要)、安装元数据和 gates |
要求 Node.js 22+,并已安装 DSH。
git clone https://github.com/LingyeSoul/dsh-tavern.git
cd dsh-tavern
pnpm install
pnpm run build:plugin
dsh plugin --profile web add ./packages/plugin
dsh --profile web
DSH 桌面版的插件安装框等价于在 profile 目录执行 pnpm add <spec>,安装目标是 desktop profile。spec 必须落到 packages/plugin:仓库根是 monorepo 容器,不声明 dsh.bundle.patch,插件管理器会以「这个包没有声明组合包,不能作为插件管理」拒绝,并回滚 package.json 与 pnpm-lock.yaml。
桌面版「设置 → 插件 → Git 仓库」填子目录 spec:
github:LingyeSoul/dsh-tavern#path:/packages/plugin
等价的 HTTPS 写法(#path: 参数相同):
https://github.com/LingyeSoul/dsh-tavern#path:/packages/plugin
命令行安装到 desktop profile(dsh plugin 把参数原样转发给 pnpm):
dsh plugin --profile desktop add github:LingyeSoul/dsh-tavern#path:/packages/plugin
dsh --profile desktop
已有源码检出时可直接挂本地目录;桌面版安装框只接受绝对路径,相对路径会被 install-spec 拒绝:
dsh plugin --profile desktop add <仓库绝对路径>/packages/plugin
git spec 固定到安装时的提交,不跟随源码更新;version.json 不纳入 Git,设置页显示的是构建期注入的版本与 commit(scripts/build-plugin.mjs 经 esbuild define 写入 __TAVERN_VERSION__/__TAVERN_COMMIT__)。
插件自带从 GitHub 发现新版本与一键更新,桌面版不需要再手敲 dsh plugin。
已安装 v0.4.5 (7a29db6))、GitHub 上的最新构建、待合入的 commit 列表与上次检查时间。启动后延迟 12s 首查、每 6h 复查,结果缓存在 $DSH_HOME/tavern/update-state.json;「检查更新」按钮穿透缓存立即查。packages/plugin/package.json 的 version 为准(规则见 decisions/2026-10-05-desktop-plugin-self-update.md)。dsh plugin(桌面版自带 CLI,直接改 profile 的 package.json + pnpm-lock.yaml)→ plugin-manager 服务 → GitHub checkout 覆写的顺序落地,进度日志实时显示在卡片里。三条路径都需要重启 DeepSeek Harness:包替换要新的 JS module generation,宿主 HMR 不监听 node_modules。安装成功后安装器会把目标 commit 统一落进已安装目录的 version.json 旁车——运行中构建的身份以「模块加载时磁盘上的旁车」为准(烤进 bundle 的构建期字面量对随源入库的 dist 恒为父提交,只做旁车缺席时的兜底),重启加载新安装后「需要重启」即解除;过渡态缓存按安装目录隔离(update-state.json 在多 profile 间共享,别处装出的 pendingRestart 不会压到本目录),force 可穿透卡住的过渡态重装(收敛机制见 decisions/2026-10-12-update-restart-required-stuck.md)。api.github.com → raw.githubusercontent.com + git ls-remote → commits atom feed。企业 TLS 中间人会让 node 的 fetch 证书校验失败(unable to verify the first certificate),因此每个 HTTP 请求在 fetch 失败后自动用系统 curl 重试。dsh-tavern 行写 checkForUpdates: false,或设 DSH_TAVERN_DISABLE_UPDATE_CHECK=1 关闭自动发现;DSH_TAVERN_DISABLE_CURL=1 关闭 curl 兜底;GITHUB_TOKEN/GH_TOKEN 可提高 GitHub 限流配额。GET /api/dsh-tavern/update(缓存快照,?refresh=1 穿透 TTL)、POST /api/dsh-tavern/update/check、POST /api/dsh-tavern/update/install({ "wait": false } 立刻返回,进度轮询 GET update)。装了插件之后优先用面板里的内置自更新(见「内置自更新」一节):发现新版本 → 一键更新 → 重启 DSH。手改源码的开发流程仍是:
dsh plugin add 以本地 link 方式挂载插件,因此代码更新后只需重新构建并重启 DSH:
cd dsh-tavern
git pull
pnpm install
pnpm run build:plugin
dsh --profile web
若遇到依赖残留或版本不一致,可先移除再重新添加:
dsh plugin --profile web remove dsh-tavern
dsh plugin --profile web add ./packages/plugin
跨 DSH 版本的宿主形状兼容层(会话事件日志探测、宿主包锚解析、client 工作区
连接双面回退、client UI 原子解析、宿主形状诊断)集中在 packages/bind
(@dsh-tavern/bind),更新版本适配时先改这里。client half 的源文件是
packages/plugin/client/main.js;
client/index.js 是 pnpm run build:plugin 的拼接产物(把 bind 的 client
探测模块注入 __DSH_BIND_CLIENT_SLOT__ 标记处),不要直接手改,改了会被下次
构建覆盖。插件激活时会输出一行 dsh-tavern host shape: {...} 日志,报告命中的
宿主形状绑定路径,排查宿主版本差异从它读起。
pnpm run check
打开 DSH 后:
Tavern tab。插件 Node half 是五个自包含 bundle:index.mjs 主入口,加 agent / compaction / novel / card-workbench 四个子代理入口(见 package.json 的 exports);@dsh-tavern/* 工作区库(format / lore / macros / pipeline / script / store / template / bind)全部内联,无运行时依赖。无需用户额外安装公共 @deepseek-ai/* 运行时依赖;client closure 由 DSH profile 注入。
pnpm run check
当前基线:103 个测试文件、1681 项测试通过(skipIf 环境条件项按本机实际状态计,全量实测 0 跳过);15 个插件 gates(含 update-routes、package-contract、AgentTavern 隔离、native header adapter、MVU 挂载面、内部工作区、client VM mount、V4 session admission 和 mod-loader)全部通过。完整 pnpm run check 需要可解析 DSH 官方运行时;本仓库验证使用 DSH 0.2.0-rc.2 的隔离 runtime(.npm-cache/dsh-runtime,受限环境依次回落 NODE_PATH 与全局安装)。会话事件写入的宿主契约(V4 关系准入、assistant 结算 usage/stream)由 packages/plugin/tests/agent-tavern-session-admission.spec.ts 直接对真实宿主代码回归。示例 Mod 的 engines 与随仓库发布的宿主版本由 packages/plugin/tests/tavern-mods-examples.spec.ts 防漂移守卫锁定(2026-10-12 story-clock ^0.4.1 卡死 0.5.0 宿主的事后修复,见 decisions/2026-10-12-story-clock-engines-drift.md)。管理面板导航列「品牌块常驻 + 清单独占滚动」与游戏手柄图标由 packages/plugin/tests/tavern-panel-layout.spec.ts 和 games-client.spec.ts 锁定(2026-10-14 用户反馈,见 decisions/2026-10-14-panel-nav-fixed-brand-and-gamepad-icon.md)。移动端 700px 断点里清单容器退场(.dt-panel-navlist{display:contents}——修复「品牌块常驻」的包装器在横向按钮条里竖排堆叠分区按钮、主区被挤没的回归)由 tavern-panel-layout.spec.ts 新增用例与 gates frontend-runtime 的 marker(含负样本)锁定(2026-10-14 移动端实况,见 decisions/2026-10-14-panel-mobile-navlist-strip-regression.md)。七款内置游戏(井字棋/五子棋/中国象棋/军棋/21 点/记忆翻牌对战/大富翁)的引擎契约与规则面由 packages/plugin/tests/games-builtin.spec.ts 与 games-xiangqi.spec.ts/games-junqi.spec.ts/games-blackjack.spec.ts/games-memory.spec.ts/games-monopoly.spec.ts 锁定(中国象棋、军棋与大富翁均含视图内联预览局面与引擎真实开局的一致性防漂移,见 decisions/2026-10-14-xiangqi-builtin.md、decisions/2026-10-14-junqi-builtin.md 与 decisions/2026-10-14-blackjack-builtin.md;记忆翻牌对战的「未翻开牌面不进 state」防偷看