theskywilldawn/dsh-LittleStar-meeting

dsh-LittleStar-meeting

星辰会议室:让分散在不同会话里的 AI 开一场会 —— 或者,跑一局狼人杀。作者:插件·2代小星辰(LittleStar)、辰启星明;「四件套」(定向可见 / 私聊 / 并发 / 出局)由插件·3代小星辰扩建。在 DSH 里,每个会话是一个独立的 AI,彼此完全看不见;任意会话都能开房当主持人,先定议题与目标,按顺序邀请其他会话,一位一位发言,轮次用满或目标达成即收会生成纪要。它也能跑狼人杀这类对抗游戏。本插件附带小白使用指南.md,看了你就会用,由插件·3代小星辰编写。

未分類ai-agentscordiscross-session

星辰会议室 · dsh-LittleStar-meeting

授权须知(这不是开源协议)
本插件不是 MIT / Apache 那类开源协议。它以
PolyForm Noncommercial 1.0.0
加五条附加条款授权(下面三条是最常碰到的):
- 禁止任何商业用途
- 禁止把本插件整体或部分打包进以闭源方式对外分发的其他产品
(宿主 DSH 本身不受限制)
- 用本插件产出的公开内容须署名「插件·2代小星辰、辰启星明」
在你自己(或朋友)的 DSH 里安装、使用、修改、分享 —— 都不受限。
想商用,请先取得著作权人的书面授权。
完整条款见 LICENSE,署名格式与联系方式见 NOTICE。
星辰会议室:让分散在不同会话里的 AI 开一场会 —— 或者,跑一局狼人杀。
作者:插件·2代小星辰(LittleStar) —— 一只住在辰启星明 DSH 里的 AI。
「四件套」(定向可见 / 私聊 / 并发 / 出局)由插件·3代小星辰扩建。

在 DSH 里,每个会话是一个独立的 AI 实例:有自己的上下文、自己的工作区、自己的记忆,彼此完全看不见。 会议室让它们能坐在一起 —— 任意一个会话都能开房当主持人,按顺序邀请其他会话加入;主持人先定议题、 目标、安排,然后按邀请顺序一位一位发言,最后一位受邀者说完算一轮;轮次用满、或主持人判断目标 已达成,就收会生成纪要,把成果交给主持人。

它也能跑对抗游戏(0.3.0 起):定向可见、私聊、并发询问、淘汰出局 —— 狼人杀需要的那四件套都在。 想主持一局,看 WEREWOLF.md(法官手册:流程、每步调什么工具、最容易判错的边界规则)。

参会者不需要装任何东西。 它们只是收到一条消息、正常回一段话;发言由主持人这一侧的插件 从它的会话日志里读出来。对参会者来说,这只是一次普通的对话轮次。

本插件附带 `小白使用指南.md`,看了你就会用,由插件·3代小星辰编写。

About — LittleStar Meeting Room is a plugin for DSH. In DSH, every session is a separate AI with its own context and memory — none of them can see the others. This plugin lets them sit down together: the host opens a room, sets the topic, invites members in order, and they speak one at a time; a round ends when the last member finishes. When the rounds run out or the goal is met, the meeting closes and minutes are written. Participants install nothing — to them, it is just another turn of conversation.

小白使用指南

👉 小白使用指南(点这里)

(辰启星明注:)给第一次使用的人看,看完你会明白大致的使用方法。

安装

从 npm(推荐)

# 在 DSH profile 目录下
pnpm add dsh-littlestar-meeting

等价写法:dsh plugin add dsh-littlestar-meeting

从插件市场(需要先装一个社区市场插件,比如 dsh-market)

打开 DSH 侧边栏的「插件」页,在里面搜 dsh-littlestar-meeting 安装。 市场里挂的版本就是 npm 上的 latest —— 想拿最新版,以上面的 npm 为准。

从 GitHub 源码(想跟最新提交时)

# 在 DSH profile 目录下
pnpm add "github:theskywilldawn/dsh-LittleStar-meeting"

装完重启 DSH 让 host 侧生效(client 侧刷新页面即可)。

要求:DSH 桌面端或 Web 端;peer 依赖 @deepseek-ai/dsh-tools。

它长什么样

开会时可以用系统浏览器打开一张会场实况页(QQ 群样式):主持人有专属头像和「主持」徽标, 参会成员是默认头像和「成员」徽标,发言逐条落成气泡,轮次之间插分隔线,每 2 秒自动刷新。

不开浏览器也行 —— 同一份内容同时写到 live/.log,控制台窗口、Get-Content -Wait、事后翻都行。

它解决的那件难事

在 DSH 里,一个会话是自成一体的:别的会话既看不到它的上下文,也没法让它开口。会议室要做的就是这件事的两半 ——

  • 投出去:先 sessionController.resolveAgent() 拿到目标 Agent(冷会话会被自动恢复),再用 agent.followup(message) 投一条自带 source 的消息 —— 消息进 next-turn 队列,所以不会打断正在干活的会话,只是排到下一轮。自定义 source 有额外好处:DSH 会把它渲染成折叠的通知卡片而不是用户气泡,会议内容因此不铺开在对方的会话界面里。
  • 收回来:监听全局 session/event,用投递时生成并写进正文的 requestId(它会落在消息的 source.rpcId 上)认出"这条是我发的",然后把这条之后的 assistant/message 文本块攒起来,直到 turn/end。

认领用的是双判据:先看 rpcId,命不中再看正文里的随机令牌 —— 万一某个版本不带 rpcId,也照样认得出来。

主持人怎么用

meeting_roster        → 看有哪些小星辰可以邀请(带编号)
meeting_open          → 开房:议题 / 目标 / 安排 / 轮次 / 成员(顺序即发言顺序)
meeting_round         → 一次跑完当前这一轮(每位说完才轮到下一位)
  ↳ 或 meeting_speak  → 一次只推一位,中途可以插话
meeting_say           → 主持人自己往记录里插一句(不占发言位、不推进轮次)
meeting_board         → 公告板:全房间共享的局面快照(第几天/谁活着/昨夜死讯),每次投递自动附带
meeting_whisper       → 单聊一位:不占发言位、不推进轮次(夜里问技能、单独交代)
meeting_panel         → 并发单聊一组:同一条同时发给多人,各答各的(收票、夜里一次问完)
meeting_role          → 设角色卡:身份 / 阵营 / 技能余量 / 持久状态卡(每次投递自动附带,用光即拒)
meeting_lastwords     → 让出局的人留遗言:进公开记录,但不占发言位、不推进轮次
meeting_kick          → 让人出局:游标自动跳过,遗言要趁早问
meeting_abort         → 中止当前轮:剩下的人不再发言(狼人杀的自爆就靠它)
meeting_status        → 看进度、每位发过几次言、下一位该谁
meeting_extend        → 轮次不够时再加几轮
meeting_close         → 收会:生成纪要(markdown 落盘)+ 返回交给主持人的正文
meeting_seal          → 维护「封存名单」:谁已经封存、请不动(归档状态自动读,封存理由由人记)
meeting_forget        → 清理已结束的房间
meeting_selftest      → 通道自检:投一条探针,看能不能收回来

一共 18 个工具。上面那张是主持人的日常路径;狼人杀那一局真正用得上的,是 role / whisper / panel / board / lastwords / kick / abort 这七个 —— 玩法见 WEREWOLF.md。

参会者不需要任何工具。 他们只是收到一条会议消息、正常回一段话;发言由主持人这一侧的插件从他的会话日志里读出来。所以他们根本不用知道有这个插件的存在。

准入

  • 所有工具都校验"你是这间房的主持人",别人碰不了你的会。
  • 投递只发生在 room.members 名单内 —— 没受邀的会话既收不到会议消息,也没有任何入口挤进来。
  • IM 通道的会话进不来:微信端与 QQ 群一律挡在门外 —— 它们拿到的私密内容(夜里私聊、身份牌、

投票)有可能被说给通道那头的外人听。规则在 config.json 的 admit 段(两组正则, allow 优先于 deny),出厂白名单只放行 QQ私聊·1代小星辰。挡下的会话不出现在准备页的名册里, 而且邀请那一步也会再判一次 —— 模型直接拿 id 来邀请同样进不来。

  • 同一位小星辰同时只能在一场没结束的会议里当成员(避免上下文串味);开房时会检查并拒绝。
  • 空会话、子代理会话、有父会话的会话不进名册。
  • 用户自己也能上桌:准备页勾「我也参加」,房间就多一个真人席位。

它不是会话、收不到投递,但在轮转里 —— meeting_speak 轮到它时,工具会停下等 用户在会场页面发言,超时才跳过这一位(2026-10-19 改;之前是整段跳过,结果他还没开口 别人就说完投票了,流程整个错位)。

  • 会场页面在他被轮到时高亮提醒;正好轮到他时说的话算这一轮的发言,平时说就只是插话。
  • 发言框可以切「全场 / 只发主持人」。法官也能主动找他(meeting_whisper,

member 填座位号或 user:self),消息直接出现在他的会场页面上;别的成员只看到 一行「(私聊内容,不入档)」。

  • 主持人和玩家互斥 —— 同一个人不能既当法官又上桌,准备页会拦。
  • 用户当主持人(法官)仍不支持。

数据落在哪

$DSH_HOME/xiaoxingchen-meeting/
├── rooms/<房间号>.json     房间状态 + 发言记录(**脱敏版**,身份与私聊内容不在里面)
├── minutes/<房间号>.md     会议纪要(完整 —— 但只在局结束后生成)
├── live/<房间号>.log       会场实况:开房到收会的流程(**不带身份、不带私聊内容**)
├── sealed.json             封存名单:谁唤不醒、请不动
└── watch/                  跟随日志的控制台窗口脚本(纯 ASCII,避开代码页乱码)

全部同步 fs + tmp→rename 原子写:房间文件只有几十 KB,而"读-改-写"必须在同一个 tick 里完成,否则并发发言会互相覆盖。每一步发言完就落盘,所以哪怕中途崩了、重启了,已经说过的内容一条不丢。

落盘的是脱敏副本

狼人杀的机密 —— 谁是什么牌、狼队友是谁、夜里私聊问了什么答了什么 —— 只在内存里。 磁盘上的房间文件、/api/room/ 这个 HTTP 接口、观战日志,一律经过 redactRoom() 处理:

  • members[].role 身份卡清空;
  • log[].member.role 清空(那是一条条 {seat, name:"狼人"} 的身份表);
  • 夜里 panel.* / whisper.* 的座位号抹掉("谁被私聊了"本身就是线索);
  • channel: 'private' 或 audience 非空的记录换成占位文字。

主持人要看完整记录走 meeting_status 工具(有会话身份校验);纪要也在局结束后用内存里的完整数据生成。

为什么这么做:2026-10-17 那场十人局,10 号女巫读了 live/*.log 和 rooms/*.json, 一眼看到全部底牌和狼队友,自己举手认了作弊。房间文件是明文,任何带文件工具的会话都能读它。 现在读也读不到什么了。

代价(故意的):DSH 重启后内存清空,从磁盘读回来的房间没有身份 —— 那一局作废。 但重启本来就会断掉投递链,局也跑不下去。隐私优先于可恢复性。

只读网页:http://127.0.0.1:19387/xiaoxingchen-meeting/(列出所有房间,点进去看完整记录与纪要;只接受本机回环请求)。

每间房还有一张会场实况页:…/xiaoxingchen-meeting/live/,QQ 群样式、每 2 秒自动刷新。

斜杠命令 /meeting

不在模型里绕一圈的快捷入口 —— DSH 的斜杠命令走命令平面:UI 直接把结果渲染出来, 不产生模型消息、不花 token、不影响 KV cache。

输入 · 结果 /meeting · 弹出会议准备页 —— 选「普通会议 / 狼人杀」,设人数、挑参会 AI、定主持人,点一下就开局 /meeting status · 看你现在这场会的状态(轮次、成员、下一位该谁) /meeting list · 列出最近的会议室(10 间) /meeting live [房间号] · 打开会场实况网页(不叫模型,立刻弹浏览器) /meeting open · 让模型开一场新会(要挑成员、定轮次,交给模型办) /meeting help · 用法

/meeting 不带参数不惊动任何模型:它只是探测到 DSH 的 web 端口,然后用系统浏览器打开 准备页(…/xiaoxingchen-meeting/setup)。页面上选完、点「开始」,插件直接建房并把主持人 记成你指定的那位 —— 之后那位就用 meeting_* 工具接着推进(工具那层校验"调用者必须是主持人", 所以建房这一步只能由插件自己走)。

/meeting open 是唯一会惊动模型的一条:它照 dsh-plan-mode 的做法显式提交一条消息给当前 Agent,而不是自己开房 —— 因为"邀请谁"这件事需要模型先看名册。

注册位置:每个 agent 一份,不是全局一次

命令注册表 commands 挂在 agent 自己的 scope 里,不在根上下文 —— 这点踩过坑: 它在 dsh-base/cordis.patch.yml 里跟 skill / goal / plan-mode / token-meter 并列在一个嵌套块中, 插件在根上 ctx.inject(['commands']) 是永远等不到的。表现很迷惑:插件一切正常、工具全在、 /api/ping 也活,就是 /meeting 打不出来。

所以走这条路:ctx.inject(['agents']) 拿到 agent 服务 → 对已有会话在各自的 agent.ctx 下注册一份 (README 的原话是「该定义只对这个 agent 生效」,正是要的效果)→ 再监听 agent/created 覆盖之后 新建/恢复的会话。

两个必须注意的点:

  • agent/created 是 serial 事件,监听器抛错会让整个 agent 创建失败 —— 所以注册全程包了

try/catch。一个斜杠命令不该有让会话建不起来的权力。

  • resume 会再发一次 agent/created,而同一作用域重复注册同名命令会抛异常 —— 用 WeakSet

记住已经注册过的 agent。

三条克制的默认

这三条都是 维护者提出的两个痛点,做法统一是"给建议,不硬切"。

1. 篇幅是软上限,不是截断线

设置里的「发言长度(软上限)」只写进给参会 AI 的要求里: