证据快照复核于 2026-09-16GitHub 数据核对日期: 2026-08-21
证据已验证Plugin Bundle自动化与智能体Web Profiledm Profile

dsh-rp-tools

面向 DeepSeek Harness DM 跑团会话的工具:骰子、按会话隔离的战役状态、本地 ComfyUI 配图和 PNG 故事书导入。

快速了解

它能做什么

面向 DeepSeek Harness DM 跑团会话的工具:骰子、按会话隔离的战役状态、本地 ComfyUI 配图和 PNG 故事书导入。

本站提供的是中文说明,不代表该项目或 Plugin 自身提供中文界面;语言支持请以上游文档为准。

使用场景
自动化与智能体智能体image-understanding工作流自动化
适配技术
deepseek-harnesslocal-comfyui
兼容性

Web Profile, dm Profile
Not declared in supplied evidence

可信度与状态

证据已验证
核对日期 2026/9/13 UTC 14:21

有代码证据的贡献

它为 DSH 增加什么

DM 跑团工具

提供仅限 DM 会话使用的骰子、战役状态、世界书、角色、资源、分镜与配图工具。

机制证据
RP 工具界面

增加设置页、DM 会话 RP 侧栏面板和 PNG 故事书导入入口。

机制证据
DM 预设桥接

包含用于在 dm 预设作用域注册 RP 工具的预设桥接文件。

机制证据

选择前先看

该插件包为 DeepSeek Harness 的 DM 会话加入跑团工具。它支持可复现骰子与随机表、按会话隔离的世界与角色记录、世界书和状态追踪、图片资源、批量分镜,以及导入 SillyTavern PNG 角色卡。配图设计为使用本地 ComfyUI,而非云端生图服务。

适合谁

使用 DeepSeek Harness 主持桌面角色扮演或地下城主会话,并希望在本地管理战役记录及可选配图的用户。

常见任务

  • 掷出透明可核对的骰式、加权抽取、区间和带种子的随机结果。
  • 为每个会话独立保存战役世界、角色、随机表、世界书和当前场景状态。
  • 在 DM 会话中生成并复用本地 ComfyUI 角色立绘、场景和道具图。
  • 将 SillyTavern PNG 角色卡导入 DM 会话,并查看生成的开局引导文件。

权限与数据

插件会在本地保存跑团内容,并连接配置好的本地 ComfyUI 服务生成配图。

权限
  • 在 DeepSeek Harness 中注册 Web 客户端界面和 HTTP 路由。
  • 读取和写入本地战役配置、会话工作区文件、导入卡、资源和快照。
  • 连接配置的 ComfyUI 端点以生成图片和检查状态。
数据处理
  • 文档说明战役世界、角色细节、卡片内容、生成图片和备份均保存在本地文件中。
  • 导入的 PNG 故事书内容会复制到会话工作区文件。
外部服务
  • 未描述云端生图服务;可选配图使用本地 ComfyUI。
凭据
  • 提供的证据未声明需要凭据。

局限

  • 文档说明 RP 工具和 RP 面板仅在 dm 预设会话中可用。
  • 本地配图需要另行配置本地 ComfyUI 及兼容模型文件。
  • 提供的证据未声明 DeepSeek Harness 的版本范围。
  • 记录的 npm 包版本未找到;请使用文档给出的 Git 安装路径。

DSHub 已核对

  • 已捕获不可变源码提交、包清单和 bundle 补丁,且 bundle 结构检查通过。
  • README 记录了 GitHub 安装方式和 DM 预设接线步骤。
  • 存在 MIT 许可证。

DSHub 未核对

  • 提供的证据未实际执行安装、重启、DM 预设配置或运行时功能。
  • 未独立验证 ComfyUI 与模型可用性、生图耗时,以及与特定 Harness 版本的兼容性。

固定版本安装

安装 dsh-rp-tools

这个Plugin Bundle没有 DSH Plugin 安装操作,请根据源码文档使用真实交付方式。

访问源码项目

维护者原文

项目 README

查看 commit c36d6f3 对应的 README
维护者编写的上游内容原文于 2026/9/13README.md 获取,正文和仓库相对媒体固定到 commit c36d6f34ec14,内容哈希为 4c01784af1ec。以下是未经 DSHub 翻译的上游原文,语言可能与当前页面不同;第三方托管的 badge 可能独立更新。

dsh-rp-tools

DeepSeek Harness(dsh)用的 跑团 / DM 工具插件中立随机裁决rp_random)+ 本地 ComfyUI 配图(场景、NPC 立绘、道具线索、氛围图)+ 按会话隔离的战役配置(世界设定 / 角色卡 / 随机表 / 风格偏好)+ 世界书与状态追踪 + PNG 故事书(SillyTavern 角色卡)导入 —— 选一张卡就能开团。

面向通用 DM 活动:任何模组、任何战役都能用;配图完全走本机 ComfyUI,不依赖任何云端服务。

设计取向:只依赖 ComfyUI 本身(直连 POST /prompt + 轮询 /history), 不使用 dsh-comfyui 插件的工作流库,因此两者可以各自独立使用。


特性

🎲 中立随机 rp_random:骰子表达式(2d6+3 / d20 / 3d8+1d4-2)、区间、加权抽取、布尔翻转;seed 可复现,count 可批量(1..20,越界报错而不是静默截断);每一掷都给可核对的逐颗明细(11(2d6[6,2] + 3)),骰式必须整串合法(2dd6 / 2d6++3 一律拒绝)
🖼 本地生图 rp_illustrate:直连本机 ComfyUI,Krea-2 Turbo(8 步 / CFG 1)+ Qwen3-VL 文本编码;1024² 约 13–18 秒,1344×768 约 25 秒
🎨 10 种风格 manga(黑白漫画,默认,无 LoRA)+ 9 个官方 Krea-2 风格 LoRA(水墨 / 点绘 / 蜡笔 / 抽象 / 雨窗 / 复古动画 / 水彩 / 运动模糊 / 塔罗);每个风格 = 一套生图工作流,含触发词 / CFG / 步数 / 尺寸预设
🧑 角色卡 rp_character:登记「名字 + 外观」,之后任何画面描述里提到该名字就自动补外观 —— 保持角色长相一致的主要手段,并可直接出立绘
📖 PNG 故事书导入 工作区那一行的「📖 导入 PNG 故事书」:从本地卡库(SillyTavern PNG 角色卡)选一张 → 世界书追加进本会话自己的 rp-sessions/<会话 id>/rp-worldbook.md、卡全文与卡面落进 rp-sessions/<会话 id>/cards/、角色卡/世界写进会话配置、自动切 dm 预设并把开场指令发给 DM。实测 3269 张卡库:解析 160/160 成功(中位 1 ms)
📚 世界书 会话工作区的 rp-worldbook.md## 分条,keys / constant / order / prob 标记;只有命中的条目进上下文(每轮预算 12 条 / 6000 字),被裁的列标题供按需补读
📌 状态追踪 rp_state:场景 / 时间 / 地点 / 在场 / 线索 + 队伍(状态·持有·伤病·目标)+ 自由旗标;空串即清除;注入在每轮上下文最前
🌍 会话隔离 世界设定 / 角色卡 / 随机表 / 提示词前缀 / 会话默认风格按会话独立,互不干扰;真正全局的只有风格库、ComfyUI 地址、全局负面词、全局默认风格、卡库目录
🎬 整幕批量 rp_scenes:吃 scenes[].panels[] 结构(含每格 positive/seed/宽高),一次出一整幕,单格失败不中断
🎲 随机表 rp_table:遭遇表 / 掉落表 / 情绪表…… 定义(表名 + 骰式 + 条目)、掷表、count/seed;面板上也能掷
🖥 三处界面 设置页「RP工具」(全局配置 + 风格库 + 工具清单);DM 会话头部的「🎲 RP」按钮(右侧栏面板:世界 / 角色卡 / 随机表 / 本会话生图配置;只有 DM 会话看得到这个入口);工作区那一行的「📖 导入 PNG 故事书」
🔒 只进 DM 会话 RP 工具只在 dm 预设作用域注册,其它预设的会话既看不到工具、也没有任何 RP 界面(故事书导入入口只在空白会话或 DM 会话出现 —— 否则没法从零开团)

安装

# 从 GitHub 装
dsh plugin --profile web add github:SiriusWJ/dsh-rp-tools

开发期用本地目录(本仓库即源码):

// profiles/<profile>/package.json
"dependencies": { "dsh-rp-tools": "file:D:/Code/dsh/rp-tools-plugin" }

安装/改动后必须重启 dsh web(宿主代码与客户端 bundle 都只在启动时装载)。

前提:本机 ComfyUI(Comfy Desktop 亦可)

模型放在 ComfyUI 的模型目录(models/):

models/diffusion_models/krea2_turbo_fp8_scaled.safetensors     ← 生图主模型(12.2GB)
models/text_encoders/qwen3vl_4b_fp8_scaled.safetensors         ← 文本编码(4.9GB)
models/vae/qwen_image_vae.safetensors                          ← VAE(0.24GB)
models/loras/krea2_*.safetensors                               ← 9 个风格 LoRA(各约 448MB,可选)

来源:https://huggingface.co/Comfy-Org/Krea-2(国内可用 https://hf-mirror.com/Comfy-Org/Krea-2)。 没有 LoRA 也能跑:manga 风格不使用 LoRA。ComfyUI 地址默认 http://127.0.0.1:8188,可在设置页改。


工具

11 个工具,全部以 rp_ 开头,全部只在 dm 预设作用域注册。设置页「RP工具 → 工具列表」会实时展示同款清单(含每个参数的说明)。

工具 作用 主要参数
rp_random 中立随机裁决(骰子 / 区间 / 抽取 / 布尔) kind? dice? choices? weights? min? max? count? seed?
rp_styles 列出风格(触发词 / CFG / 步数 / 尺寸预设)
rp_illustrate 按风格生成一张图(并自动存进资源库) prompt* style? seed? aspect? width? height? label? tags? kind?
rp_assets 浏览资源库(找回来复用,不必重出) action? kind? characters? tags? q? limit? id? label?
rp_character 角色卡增删查 + 出立绘 action* name? appearance? portrait? style?
rp_state 状态追踪(场景 / 时间 / 地点 / 在场 / 线索 + 队伍 + 旗标) action* field? value? party? party_mode? party_remove? flags?
rp_lore 世界书按条读取 / 生成模板 action* query? limit?
rp_session 本会话设置(世界 / 前缀 / 会话默认风格 / 风格备注 / 战役名) action* world? prompt_prefix? default_style? style_notes? campaign_name?
rp_scenes 按场景文件逐格批量出图(scenes[].scene_id + panels[].panel_id;整幕共享一个组存进资源库) scenesFile* sceneId? style? limit? label? tags?
rp_config 全局配置(负面词 / 全局默认风格 / ComfyUI 地址 / 单个风格的触发词·步数·CFG) action* negative? default_style? base_url? style_key? trigger? steps? cfg?
rp_table 随机表定义与掷表 action* name? dice? entries? count? seed?

* = 必填。


PNG 故事书导入

界面入口在工作区那一行(输入框上方,只在空白会话或 DM 会话出现)。点开 → 在本地卡库里搜卡 → 预览(世界书条数 / 开场白来源 / 世界与性格摘要)→ 「导入并开始」。

导入做的事:

  1. 卡里的 character_book追加合并进会话工作区的 rp-worldbook.md (按标题去重,绝不覆盖你自己写的条目;无 keys 的条目不补 constant —— 运行时用标题当触发词, 而导入来的条目一律标 source: card不占系统提示,命中了才进上下文); 条目名优先用卡给的,卡没给名字时依次用正文里的第一个标题 → 触发词 → 正文首行 (所以不会出现「条目 4」「条目 5」这种认不出是什么的名字);
  2. 卡全文 → <工作区>/rp-sessions/<会话 id>/cards/<slug>.md(世界书有 60 条 / 6 万字预算,超出的设定在这里按需 read);
  3. 卡面 → <工作区>/rp-sessions/<会话 id>/cards/<slug>.png,登记成会话封面(不是某个角色的立绘);
  4. 角色卡 / 世界设定 / 战役名 → 会话配置(creator_notes 里的广告、社群号、CC 协议逐行剔掉, 只有真正的说明才进【世界设定】;整段都是广告就不注入,全文仍留在卡文件里);
  5. 开场引导文件 → <工作区>/rp-sessions/<会话 id>/cards/<slug>.launch.md (选定开场 + 文件清单 + 已写入什么 + 待人工确认),并切成 dm 预设、只把这个路径发给 DM (首条消息约 60 字,绝不内联开场白)。

导入之后要收尾的事全在 launch.md(DM 读那份文件就有全部开局任务):角色字段归位、 世界书过滤(状态/历史类改成触发式、删空壳、补触发词、constant 只留 1–3 条)、 以及按当前语言收拾标题与属性name:名称:gender: Female性别:女条目 4 → 「战斗」这类实义名)。整本一起收拾用 rp_lore(action:"localize") / rp_lore(action:"rename_unnamed"),一次调用做完。 所以面板上没有「属性中文化」「重命名条目」这类按钮 —— 同一件事两个入口会让人以为没做。

注入分层(省 token 的关键)

通道 放什么
system standing(每轮都在、字节稳定) 通用 DM 规则、session.dm.prompt、战役名、世界设定、紧凑人物索引、路径指针、生图策略、手写且在预算内的常驻世界书
runtime context(每轮重新装配) 当前状态、在场人物的详细卡、命中触发词的世界书条目、导入来的条目(含原卡标了 constant 的)
文件(按需 read) 卡全文、全部备用开场白、被预算挡下的条目、导入映射

两条硬规则:导入来的世界书正文不因 constant 自动进系统提示(它按触发词走 runtime); system standing 里的常驻世界书有 6000 字预算,超出的降级为「按需」,而不是截断成残句。 同一个人物若既在世界书里、又作为人物卡在本轮展开,装配时会跳过世界书那份(诊断里记为 character-duplicate),避免同一批正文注入两遍。

卡库位置在设置页 → RP工具 → 卡库目录(默认是会话工作区下的 rp-cards)。 目录结构是 cards/<分类>/*.png;没有私有索引文件时退回按文件名扫目录,功能一样可用。

出图:默认尺寸与立绘复用

出图默认尺寸(设置页「图像」可改):场景 768×432、立绘 512×768、道具 512×512。 出图时间基本正比于像素,而聊天里也渲染不到 1024 宽,所以 1.12.8 起调小了(单张大约 8~14 秒); 老配置里没动过的那一档会跟着换成新值,自己改过的保持原样

立绘复用:常驻段的【本会话设定】里有一行「已有可用图」—— 角色已有的生成立绘、 玩家自己导入的图、以及导入卡的卡面(对角色卡来说那张 PNG 就是它的立绘)都在那里。 DM 第一次出场时直接展示它,不必再花十几秒重出一张;确实没有图时才调 rp_illustrate。 DM 也可以在叙事里直接把这些图摆进回复(零成本),不必为了「让角色露个脸」重新生图。

立绘是纵向的rp_illustrate 不传 width/height/aspect 时,画面里只提到一个已登记角色 就按 portrait(纵向,默认 512×768)出,否则按场景横幅 —— 所以「给某人出一张立绘」不必自己算比例。 DM 出的第一张单人图会自动记成那个角色的立绘(已有立绘时不覆盖)。

角色卡编辑器里可以:生成立绘 / 重新生成(覆盖,纵向)、导入图片(png / jpeg / webp,≤8MB, 存进 <工作区>/rp-sessions/<会话 id>/portraits/)、或直接删掉这个角色(会顺手清掉它的立绘记录)。

资源库:出过的图都留下来,能找回来

只记引用会在几周后变成一堆死链,所以出图后插件会把图真抓一份存进会话目录,并按分类分文件夹:

<工作区>/rp-sessions/<会话 id>/
├── assets.json                    索引:一张图一条(id / 分类 / 标签 / 角色 / 尺寸 / 风格 / 提示词 / 时间)
└── assets/
    ├── portraits/<id>.png         角色
    ├── scenes/<id>.png            场景
    ├── items/<id>.png             道具
    └── other/<id>.png             其他

入库的四个入口:rp_illustrate 出图、rp_scenes 每格(整幕共享一个 group)、 rp_character(portrait:true)、面板「导入图片」。导入卡的卡面不入库 —— 它属于卡库。

按内容去重:入库前比对 sha256,同一个分类里字节完全相同的图复用已有那条(合并标签、不写第二份文件)。 本地出图是「同 seed + 同提示词 → 同一张图」,没有这一步,重出一张一样的就会在库里留下两条只有 id 不同的记录 —— 图墙看着两张、磁盘占两份、人还分不出区别。查重放在写锁内(否则并发归档同一张会各写一份)。

rp_scenes 的场景文件字段名是固定的:幕的 id 是 scene_id(不是 id),分镜是 panel_idsceneId 参数筛的就是它(也兼容 id/title 这类常见写法)。筛不到会直接报错并列出文件里实际有哪些 id —— 不会静默返回 0 张(那看起来像生图服务坏了)。字段名与最小合法示例写在工具的 description 里。

DM 侧rp_assetskind / characters / tags / q 查,返回的每行都带能直接放进 dsh-ui image 组件的地址;常驻段里只报条数资源库:本会话已有 23 张图(角色 6、场景 14、道具 3)) —— 常驻内容是每轮都发的,把上百条列进来会白白吃掉几千字。DM 不能删图,删除是玩家在面板里做的事。

玩家侧面板有一张「资源」卡片:分类筛选 + 搜索 + 图墙(服务端降采样缩略图)+ 点开看原图, 能改名称/标签、显示到对话(拼成 dsh-ui 围栏填进输入框,不自动发送)、 设为某角色的立绘(不复制文件,只改引用;会清掉该角色旧的生成立绘,否则读取端会优先显示旧的)、 删除(连磁盘文件一起删,并自动解除指向它的立绘引用,不留死链)。

⚠️ 索引是 read-modify-write,而 rp_illustrate并发安全的(宿主并行池最多 10 个在飞)—— 所以所有写索引的路径都过一把按会话串行的写队列。没有它,同时出 5 张图可能只入库 2 张, 而且不报错。

需要一次出多张时,DM 会在同一步里并发发出多个 rp_illustrate(插件已把这两个工具声明为 并发安全,宿主才会真的并行调度)。ComfyUI 是单卡队列,GPU 总时长不变 —— 省掉的是每张图 之间那几轮模型往返(长局里一步就是几万 input token)。

⚠️ 实测结论(3269 张卡,见 docs/PNG-CARD-DECODE.md):first_mes 100% 被广告污染deepseektavern.com),所以导入一律改用 alternate_greetings 的第一条; 40% 的卡正文只在 character_book 里,所以导入的主战场是世界书而不是角色字段。


备份 / 会话包

长一点的团需要最低限度的保障。会话配置在全局数据目录、世界书与资源图在工作区 —— 两处分离,手工备份必漏一半,所以插件把它们打成一个 zip:

MANIFEST.json          格式与版本 / 导出时间 / 原会话 id / 每个文件的 sha256
session.json           会话配置
rp-worldbook.md        世界书(可能没有)
assets.json            资源库索引
assets/<分类>/<id>.<ext>   出过的图与导入的图(1.13.0 起真存了一份,所以包是自包含的)
cards/<slug>.{md,json,launch.md,png}   导入卡产物(含卡面与开局引导)
  • 导出:面板「备份 / 会话包 → 导出会话包」是一个 <a download>,浏览器自己存盘。
  • 快照:同一个卡片里的「拍快照」把包写进 <工作区>/rp-sessions/<id>/snapshots/只保留最近 5 个;只管自己写的 snapshot-*.zip,你放进这个目录的别的包不会被当成快照、也不会被删。
  • 导入:选一个 zip。默认不覆盖 —— 目标会话已有内容时宿主回 409,界面问一句, 确认后才带 overwrite:true 重来,而且覆盖前会自动拍一个快照兜底。
  • 包是 STORE(不压缩) 的 zip:里面装的是已经压过的 PNG,再压一遍没意义。 用别的工具重新打包时会默认压缩 → 导入会明确报「只支持 STORE 包」,不会给你一堆乱码。

⚠️ 解包是外部输入:条目名可能带 ../(zip-slip)。所以每个条目名都要过 safeEntryName()(逐段判定 ../绝对路径/盘符),落盘时再做一次目标路径前缀校验 —— 两道锁都留着,单点失效不至于写穿会话目录。清单里的 sha256 也会逐个核对。


轻量地图(可选)

只在模组本身有地点结构时才用(地牢、宅邸、城镇)。没有地图就正常叙事 —— 不给每个场景造图。

<工作区>/rp-sessions/<会话 id>/
├── rp-map.json         静态结构:nodes(id/label/public)+ edges(id/a/b/label/state)
└── rp-map-state.json   运行时:node 当前节点 / revealed 已揭示 / edges 变化的边 / tokens 标记位置

首版不加 rp_map 工具:两个文件都由 DM 用通用的 read/write 读写。插件只做两件事:

  1. 每轮注入一行摘要(跟在「本场当前状态」之后): 【地图】旧钟旅店·大堂|已揭示 4/5|可走:厨房(木门)、二楼客房(楼梯)|队伍@大堂、老板@大堂 —— 实测 64 字/轮。DM 不必为了看一眼「我在哪、能去哪」去读整个文件。
  2. 结构出问题时把话说明白(而不是静默或渲染垃圾): 【地图】⚠ node="nope" 不是 rp-map.json 里的节点。两条纪律都是踩出来的: 文件坏了 ≠ 还没建(状态文件存在但 JSON 坏了时,不能说「还没初始化」,否则 DM 会覆盖一份 本可救回的文件);坏数据不渲染摘要(拿 node="nope" 画出一行看起来正常的地图, 比什么都不显示更危险)。

为什么状态不放进 rp_state.flagsapplyStateUpdates 写旗标时是 String(value) → 对象直接变成 "[object Object]"(写进去了、不报错、永久丢失),数组被压成逗号串; 再叠上 FLAG_VALUE_CHARS = 120 的截断与 FLAGS_MAX_SHOWN = 16 的显示上限 (20 个地图键会把剧情旗标挤到对 DM 不可见)。实测:

写 flags:map_edge_states=[object Object];map_tokens=[object Object]   ← 第一回合就死

两个地图文件都计入会话包(导出/快照会带上)。DM 侧的约定(何时建图、怎么画、 按钮只从当前节点的邻接边生成、action 命名 <地图id>:move:<节点id>)写在 dm 预设的 「## 地图」小节里。


数据与配置

~/.dsh/data/dsh-rp-tools/
├── styles.json                 全局:风格库 + 全局负面词 + ComfyUI 地址 + 全局默认风格 + 卡库目录
├── sessions/<sessionId>.json   会话级:世界设定 / 角色卡 / 随机表 / 前缀 / 会话默认风格 / 状态 / 立绘登记
├── dm-sessions.json            DM 会话登记表(界面据此决定是否显示 RP 入口)
└── _agent-probe.json           诊断用:agent/created 事件里可读到的字段快照

<会话工作区>/
├── rp-worldbook.md             世界书(可手写;导入的故事书条目也追加在这里)
└── rp-sessions/<会话 id>/
    ├── cards/<slug>.{md,json,png}      导入产物:卡全文 / 规范化结果 / 卡面
    ├── assets.json                     资源库索引(一张图一条)
    ├── assets/<分类>/<id>.<ext>        出过的图与导入的图(portraits / scenes / items / other)
    └── snapshots/snapshot-<时间>.zip   恢复点(只保留最近 5 个;只删自己写的那些)

styles.json 关键字段:

{
  "comfyui": { "baseUrl": "http://127.0.0.1:8188", "dshOrigin": "http://127.0.0.1:3080" },
  "defaultStyle": "manga",
  "negative": "low quality, worst quality, blurry, ... , lowres",   // 全局负面词(预置一套)
  "styles": {
    "manga": { "label": "黑白漫画", "workflow": "krea2", "lora": null, "cfg": 1, "steps": 8,
               "trigger": "black and white manga panel, screentone shading, crisp ink lineart, ...",
               "sizes": { "scene": [1344,768], "portrait": [768,1024], "item": [1024,1024] } }
  }
}

⚠️ 负面词与 CFG:Krea-2 Turbo 建议 CFG=1,此时负向条件在数学上不参与计算(官方模板也如此)。 想让全局负面词真正生效,把对应风格的 cfg 调到 1.5~2.5(过高会让 turbo 模型过曝/崩坏)。


DM 预设接线(关键,否则工具不出现)

RP 工具只在 dm 预设作用域注册。需要在预设目录做两件事:

1. 放行工具~/.dsh/.agent-presets/dm/agent.cordis.yml)—— 该预设默认 deny 掉所有全局工具,只保留白名单:

- id: dm-filter
  name: ./session-filter.mjs
  config:
    keepGlobalTools:
      - render_ui
      - validate_dsh_ui
      - web_search

全部 rp_* 工具现在都在本预设作用域注册(由 rp-bridge.mjs 调用 registerRpTools), 所以白名单里不再需要放行任何 rp_* —— 它只用于保留少数几个全局工具。

2. 挂桥接插件(把 RP 工具注册进本会话 + 登记 DM 会话):

- id: rp-bridge
  name: ./rp-bridge.mjs

rp-bridge.mjs 的副本见本仓库 preset/rp-bridge.mjs


架构

dsh-rp-tools/
├── lib/index.js        宿主半侧(ESM)
│   ├── apply(ctx)              全局:**不注册任何模型工具**,只挂 HTTP 路由 + 监听 session/created(fork 继承、记录工作区)
│   ├── registerRpTools(ctx)    dm 作用域(由 rp-bridge 调用):全部 10 个 rp_ 工具 + 两条提示词注入通道
│   ├── 生图链路                 组装 API 工作流 → ComfyUI POST /prompt → 轮询 /history → 同源媒体 URL
│   └── 配置层                  styles.json(全局) / sessions/<id>.json(会话)
├── lib/card-png.js     PNG 角色卡解码(tEXt / iTXt / zTXt,ccv3 优先,截断容错)
├── lib/card-import.js  卡 → 会话配置的映射(丢广告开场白、无 keys 条目补 constant、限量 + 全文导出)
├── client/client.js    客户端半侧(plain JS + React.createElement,无构建)
│   ├── settings.section「RP工具」                全局配置 + 风格库 + 卡库目录 + 工具清单
│   ├── conversation.session.header.utilities    仅 DM 会话渲染的「🎲 RP」按钮(打开右侧栏面板)
│   │                                            右侧栏标签**类型**随该按钮挂载/卸载注册与注销(引用计数),
│   │                                            因此非 DM 会话连空面板的引导页里也看不到这个入口
│   └── conversation.input.dock「📖 导入 PNG 故事书」  空白会话 / DM 会话里的故事书导入入口
├── preset/rp-bridge.mjs    dm 预设作用域桥接插件(副本,供安装参考)
├── cordis.patch.yml        bundle 补丁层
└── docs/                   交接文档(HANDOFF)/ 状态(STATUS)/ 卡格式实测(PNG-CARD-DECODE)

HTTP 路由(POST 全部同源保护,Origin 必须等于 Host):

路由 方法 用途
/rp-tools/state GET 全局配置 + 风格摘要(同时学习浏览器 origin,用于拼媒体 URL)
/rp-tools/config POST 写全局配置(含 negative / baseUrl / cards.root / 风格字段与增删)
/rp-tools/reset POST 恢复默认全局配置
/rp-tools/check GET ComfyUI 连通性(版本 / GPU / 显存)
/rp-tools/inject GET 注入自检:某个会话被注入什么(只读,不参与运行)
/rp-tools/loras GET 本地 LoRA 清单(读 ComfyUI /object_info
/rp-tools/session GET/POST 读写某个会话的 RP 配置(角色卡 / 世界 / 随机表 / 状态 / 立绘)
/rp-tools/dm-mark POST 登记某会话为 DM 会话
/rp-tools/tools GET 工具清单 + 参数说明(设置页用)
/rp-tools/roll POST 掷随机表(面板用)
/rp-tools/media GET 同源媒体代理:把 ComfyUI /view 转成同源,图片才能在聊天里渲染
/rp-tools/portrait POST 登记/清除某个角色的立绘(只存 ComfyUI 三要素,媒体仍走 /rp-tools/media;保存时也会归档进资源库)
/rp-tools/portrait-upload POST 导入外部立绘(/rp-tools/asset-upload 的别名,等价于 kind=portrait + 角色名)
/rp-tools/portrait-image GET 登记过的导入立绘发回浏览器(只认会话配置里的相对路径 + 会话目录前缀校验)
/rp-tools/assets GET/POST 资源库:列出(可筛分类/角色/标签/关键词)/ 改名称与标签 / 删除 / 设为某角色的立绘
/rp-tools/asset-upload POST 导入外部图进资源库(data URL → assets/<分类>/<id>.<ext>,只收 png/jpeg/webp、≤8MB)
/rp-tools/asset-image GET 发资源图(按 idthumb=1&width=N 走服务端降采样,图墙用它)
/rp-tools/export GET 下载会话包(STORE-only zip:配置 + 世界书 + 资源库 + 导入卡产物)
/rp-tools/snapshots GET 列恢复点(只列自己写的 snapshot-*.zip
/rp-tools/snapshot POST 拍一个恢复点并修剪到最近 5 个;删不掉的如实报在 failed
/rp-tools/import POST 导入会话包(path=会话目录内的包,或 dataUrl);默认不覆盖,覆盖前自动拍快照
/rp-tools/preview POST 试出一张(设置页 / 面板用,可带 sessionId;sizeKey 选场景/立绘/道具档)
/rp-tools/cards GET 列卡库(服务端搜索 / 分类 / 分页)
/rp-tools/card GET 解析单张卡 → 摘要与预览(不落盘)
/rp-tools/card-import POST 导入到某个会话(写世界书 / 卡全文 / 卡面 + 更新会话配置,返回开场指令)
/rp-tools/card-image GET 卡面图(只服务卡库内的 .png

⚠️ /rp-tools/card* 三条会把磁盘内容交给浏览器,路径一律经 safeCardPath()resolve 后前缀比对卡库根 + 只认 .png); 逃逸 / 绝对路径 / 非 png 全部 400。 /rp-tools/portrait-image 同理,而且是双锁:只发会话配置里登记过的那张, 再把相对路径解析到会话目录下做前缀校验;文件名由宿主用 portraitFileSlug() 生成(用户给的名字不进路径)。


开发

所有改动都在这个 git 仓库里做D:\Code\dsh\rp-tools-plugin,它本身就是 github.com/SiriusWJ/dsh-rp-tools 的克隆)。不要改 profile 里那份安装副本~/.dsh/profiles/web/node_modules/dsh-rp-tools)—— 它是重装时会被覆盖的产物, 改了既不进版本库,下次安装就没了。

node --check lib/index.js && node --check client/client.js      # 语法检查

这个插件在 profile 里是从 GitHub 装的"dsh-rp-tools": "github:SiriusWJ/dsh-rp-tools"), 所以「本地源码 → GitHub → profile」是一条链,本地不再是权威副本

# 1) 改完 → 提交并推送(profile 装的就是 push 上去的那个 commit)
git -C D:\Code\dsh\rp-tools-plugin add -A
git -C D:\Code\dsh\rp-tools-plugin commit -m "feat(x): …"
git -C D:\Code\dsh\rp-tools-plugin push origin main

# 2) 重装,让 profile 跟上新 commit(不重装的话它还停在旧 commit)
dsh plugin --profile web add github:SiriusWJ/dsh-rp-tools

# 3) 改的是 dm 预设那一半,还要同步**活动预设目录**(它不属于这个包,只能手动拷)
Copy-Item preset\agent.cordis.yml     "$env:USERPROFILE\.dsh\.agent-presets\dm\agent.cordis.yml" -Force
Copy-Item preset\session-filter-v2.mjs "$env:USERPROFILE\.dsh\.agent-presets\dm\session-filter-v2.mjs" -Force
Copy-Item preset\rp-bridge.mjs         "$env:USERPROFILE\.dsh\.agent-presets\dm\rp-bridge.mjs" -Force

重启 dsh web 后生效(lib/preset/ 在启动时装载;client/ 只需刷新页面)。

只改了文档(docs/README.md)时第 2 步可以跳过 —— 安装副本里的文档不参与运行。

想跳过「push + 重装」这两步(改成改完即生效):把依赖换成 dsh plugin --profile web add link:D:/Code/dsh/rp-tools-plugin。 代价是 profile 直接读源码目录,与「商店里声明的是 GitHub」不一致 —— 二选一。

⚠️ 本机到 codeload.github.com(GitHub 打包下载域名)吞吐只有 ~25KB/s,且 Node 的 fetch 比系统下载慢十倍量级 —— 仓库 tarball 必须保持小(这也是 temp_output/ 被移出仓库的原因: 四张试出图占了 4.3MB,会让 github: 安装卡满超时)。

测试:

node tools/smoke-dm.mjs        # 宿主:作用域隔离 / 路由 / 世界书 / 状态 / 风格库 / 卡库导入
node tools/smoke-card.mjs      # PNG 卡解码 + 映射 + 开场指令 / 引导文件(合成 PNG 字节)
node tools/smoke-client.mjs    # 客户端 bundle:样式注入时机 / 槽位注册 / 面板渲染
node tools/verify-roundtrip.mjs <card-import.js>   # 导入↔解析往返(需 profile 里那份)
node tools/probe-cardlib.mjs   # 真卡库探针(只读 + 临时目录,手动跑)

当前开发状态、验证记录、已知问题与路线图见 docs/STATUS.md, 给新会话的交接文档见 docs/HANDOFF.md

License

MIT

有意识地管理

安装与管理

前置条件与目标 Profile

目标 Web Profile, dm Profile

交付方式 Git Bundle — SiriusWJ/dsh-rp-tools#c36d6f34ec14c459c8938f0a81c65004367e9fe5

验证、更新与移除

显示生命周期命令
验证
dsh plugin --profile web list

兼容性与访问范围

DeepSeek Harness bundle with web client and DM preset integration Not declared in supplied evidence

检查兼容性证据

风险事实

local_data_storage

Stores campaign configuration, imported cards, worldbook content, generated images, and snapshots on local disk.

证据
local_service_connection

Connects to a locally configured ComfyUI server for image generation; the documented default is localhost.

证据
license

Licensed under MIT; provided without warranty.

证据
证据与编辑审查Manifest、Bundle patch、分发与新鲜度

不可变证据

审查状态与源码活动

AI 已审查

请使用固定提交的 Git bundle 路径。若战役包含敏感材料,启用前应评估本地存储和 ComfyUI 配置带来的影响。

AI 审查于 2026/9/13 UTC 14:22GitHub 事实核对日期: 2026/9/13 UTC 14:22

自当前证据基线以来,没有记录到重要源码变化。

下一步

按 Plugin 安装流程操作

订阅重要变化: dsh-rp-tools