Repository navigation
Releases: yzi1b/whale-craft
Release list
v0.2.0-beta.3
whale_craft v0.2.0-beta.3
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.2.0-beta.3] - 2026-10-18
预览版,面向 DSH 0.2.0-rc.2 及以上(含 0.2.1-rc.2)。预览版可能存在未知问题,如遇到请向我们反馈。
0.2.0-beta.1 / beta.2 的用户建议升级到本版本。本版本修复了在 0.2.1-rc.2 版本的 DSH 上开始 MC / MC+ 模式会话会报错
unknown prompt variable "{{cwd}}"的问题。相较于 0.1 的变更,详见 0.2.0-beta.1 更新日志。
- 【新增】联网搜索功能。可以在设置中选择是否启用,MC+模式不受限制
- 【新增】网页抓取功能。可以在设置中调整是否启用,指定允许的域名和内容形式。支持下载图片
- 【新增】策略获取工具
mc_kit_rules,助理可以知悉自己可以使用的MC指令和可抓取的网站及内容形式 - 【新增】文件系统工具
mc_kit_fs,助理可以复制、移动、删除文件和新建目录,受权限策略限制 - 【变更】桌面模式文件分享与网页端不同,指定端口分享文件
- 【变更】移除长期记忆工具
mc_kit_memory。现在完全使用文件读写工具编辑记忆。记忆文件夹与既有记忆不受影响 - 【变更】不再自动注入
.whale-craft/README.md记忆索引,由助理主动读取 - 【变更】调整MC模式dsh原生工具暴露面,现在允许调用的工具更多更标准化
- 【修复】在 DSH 0.2.1-rc.2 上新建 MC / MC+ 模式会话直接报错
unknown prompt variable "{{cwd}}"。新版宿主提示词不再使用该变量
v0.2.0-beta.2
whale_craft v0.2.0-beta.2
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.2.0-beta.2] - 2026-10-06
预览版,面向 DSH 0.2.0-rc.2 及以上。相较于 0.1 的变更,详见 0.2.0-beta.1 更新日志。预览版可能存在未知问题,如遇到请向我们反馈。
0.2.0-beta.1 因存在致命问题无法使用,请使用此版本。
- 【修复】从 npm 安装后插件完全不加载(启动只报
dsh: warning: 1 entry did not activate/failed to import)。根因在 DSH 宿主自身的模块解析器(与本插件无关),这一版在插件内加了绕过,registry 安装即可正常加载(issue #5)
v0.2.0-beta.1
whale_craft v0.2.0-beta.1
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.2.0-beta.1] - 2026-10-06
预览版,面向 DSH 0.2.0-rc.2 及以上。0.2.0 正式版功能尚未全部完成,本版本先行发布已完成功能,以及支持 DSH 0.2.0-rc.2 和 DSH Desktop。预览版可能存在未知问题,如遇到请向我们反馈。
- 【新增】现在提供“MC模式”和“MC+模式”。前者专注于MC游戏,只能调用游戏相关工具;后者既可以进行游戏,还可以完成编程等任务,可以另外调用标准模式全部工具
- 【新增】“连接到MC”快速提示词投放功能。现在MC模式、MC+模式窗口中会有“连接到MC”按钮,点击后在打开的窗口中填入服务器信息(或选择本地服务器),选择用户,即可快速发送让助理进入服务器的指令
- 【新增】MC模式和标准模式会话可以迁移到MC+模式。对应会话中末条助手回复下会有“方块”图案的“创建MC+分支”按钮,点击即可
- 【新增】现在宿主“插件”页面可以看到本插件名称、描述等信息,提供“设置”按钮,点击可以进入设置
- 【新增】获取游戏上下文
mc_context、获取在线玩家mc_players、获取高度图mc_height三个工具 - 【新增】MC设置页面在没有选择工作区时也可以进入(通过宿主插件设置页),与工作区有关的配置会标注出来
- 【变更】DSH 版本范围要求
>=0.2.0-rc.2 <0.3.0 - 【变更】MC / MC+ 之外的模式不再暴露
mc_*/mc_kit_*工具 - 【变更】工作区的配置现记录在
.whale-craft/config.json,该配置文件MC模式下的Agent不可更改。旧配置会自动迁移 - 【变更】提示词注入设置现在下放到工作区
- 【变更】
mc_connect/mc_ping工具参数调整,使用单address参数指定地址,版本自动探测 - 【变更】
mc_accounts工具去掉useaction、mc_lan去掉mode参数 - 【变更】
mc_map工具参数调整,dist写文件、reply是否回上下文。取消默认输出目录 - 【变更】
mc_status工具定位调整,现在作为获取连接信息的工具,另外也会返回游戏上下文 - 【变更】移除 MC 26.2 按键上报兼容层,现在不支持 MC 26.2
- 【变更】文件分享不再具有模式,只有开关(
expressEnabled)决定是否开启 - 【变更】调试工具改名
mc_debug_sessions/mc_debug_diag,由MC设置中“调试”>“开放助手调试工具”控制可见性,默认关闭 - 【修复】工具组探针静默失效等 5 处(issue #1)
- 【修复】干净安装 / 官方 dsh-desktop 启动报
failed to import(issue #5) - 【修复】v4 会话里提示词注入、看门狗唤醒整轮失败(PR #2 @swan3146)
- 【修复】看门狗后台任务挂不上、「强制停止」管不到它(PR #2 @swan3146)
- 【修复】其余小问题的修复与清理
破坏性变更
- 插件现要求DSH最低版本为 0.2.0-rc.2,不再支持更低版本。解决方案:将你的DSH升级至 0.2.0-rc.2 及以上版本。
- 除了MC和MC+模式外,其余模式无法再调用MC游戏相关工具。解决方案:将需要使用MC工具的会话迁移到MC+模式,找到助手的最后一个回答,点击“方块”图案的“创建MC+分支”按钮。
- 此前对Minecraft 26.2的临时支持已移除。解决方案:等待后续版本。MineFlayer支持Minecraft 26.2后,我们会及时跟进。
v0.1.7
whale_craft v0.1.7
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.1.7] - 2026-09-20
这一版在 0.1.6 之上修了三个真机问题(都是用户/其他使用者实测报上来的),并订正了几处"状态在撒谎"。
0.1.6 的内容(修皮肤站登录 400)与 0.1.5 的全部内容也都在这一版里,装 0.1.7 就都有了。
🔴 修复(断线后状态不同步:mc_status / 顶部状态条 / AI 都以为还连着)
- 现象(用户):"连接断开了状态没有同步。
mc_status和顶部状态条都不知道连接断开了,AI 也以为连接还在。" - 三处根因(都在,缺一不可):
- core 从来不播报"断线":
b.on('end')里只写一行日志,不emit任何东西 ⇒ 上层根本没机会知道; - 会话不转发:
McSession只把spawn/death/reconnect/chat/system/damage转进事件队列,
没有断线这一类 ⇒mc_events里看不到、AI 也不会被叫醒; - 看门狗没有这条唤醒项,断线后它照旧挂着(
watch.armed还说"在监听"),
前端active也因此继续为真 —— 三处一起撒谎。
- core 从来不播报"断线":
- 修法:
· core 在连接结束时emit('offline', { reason, willReconnect, sub })(原因取lastError,并判断还要不要自动重连);
· 会话把它转进事件队列(mc_events看得见);
· 看门狗新增唤醒项wakeOn.disconnect(默认开):
会重连 → 叫醒 AI 说"连接断了(原因)——正在自动重连,先别再操作角色",
不会重连 → 直接关掉看门狗(关闭通知本来就会告诉 AI"你已不在 MC 里、要用 mc_connect 重新进服");
· 前端:/api/mc/status的active把"正在自动重连"也算上(否则刚断线状态条整个消失,用户以为插件把状态忘了),
状态条新增显示 "重连中…"(配data-mc-reconnecting),不再假装"在游戏中";
并用reconnectPending(掉线置位 → 真重连成功 / 手动mc_connect成功才清)覆盖"正在尝试连接"那一段,
否则那几十秒里状态条会从"重连中…"退回"未上线",看着像插件放弃了;
· 顺手:断线时不再发心跳唤醒(否则会说"我还在游戏里",那是撒谎)。 - 真实场景验收(本地官方 1.21.1 服务端,连上进服后把服务端进程杀掉):
offline事件{reason:"read ECONNRESET", willReconnect:true}→status()回
online:false / ghost:true / reconnecting:true→ 看门狗留档有 offline,并把
「【MC 看门狗|disconnect】连接断了(read ECONNRESET)——插件正在自动重连…」真投给了 AI。 - 自检:新增 10 条断言(唤醒矩阵有 disconnect / 会重连则排队唤醒 / 不会重连则自动关闭 /
断线进留档 / 真 socket 断开时 core 确实发出 offline / 会话转队列 /modeView与
/api/mc/status带reconnecting/ 状态条显示"重连中…")。
🔴 修复(mc_events {waitSec} 把唤醒堵住了:等到消息、提及了也不醒,用户空等很久)
- 现象(用户实测):"等待有时候并不能唤醒!比如等到消息,但是发了消息,就算提及它也没有唤醒,
让用户空等特别久。反倒是等完之后看门狗注入提示词。" - 根因:宿主的
agent.steer语义是「运行中在下一次 step 边界消费」,
而 step 边界要等当前这一步的工具调用返回才算到。
于是mc_events {waitSec:120}一堵,看门狗 2 秒前就组好的唤醒文案被压在等待后面,
直到等待超时才投出去 —— 等待堵住了它正在等的那件事。 - 修法:
· 等待逻辑抽成src/wait.mjs(waitForEvents),多一条收工条件:被唤醒打断;
· 看门狗在所有注入之前(唤醒 / 关闭通知 / 补提醒 / 心跳——都走#inject这一个口子)
调sess.interruptWait(kind)置个标记;等待循环每 250ms 看一眼,见到立刻收工:
工具一返回 → step 结束 → 唤醒文案当场投出去;
· 工具返回里明确告诉 AI:interrupted: true+interruptReason+
「看门狗命中唤醒条件…先别急着再 wait,等那条提示进来」。 - 实测:被打断时等待 126ms 就返回(原来会把 30 秒/120 秒干等满)。
- 顺带改掉描述里的一句谎:原描述写"看门狗记录的一切:…被传送、捡物、上下线",
但那三类不在这个队列里(只在看门狗留档,用mc_watch {action:"log"}看)。
现在描述写清了,并提醒waitSec只是兜底(看门狗会主动叫你)、建议 ≤30。 - 自检:新增 8 条断言(等到事件立刻回 / 被唤醒打断立刻回 / 用户停止立刻回 / 到点才回 /
看门狗注入前真的会打断(stub 会话记录调用)/ 工具侧接线 / 注入口接线 / 描述不再谎称)。
🔴 修复(连 1.21/1.21.1 进服成功、1 秒后被踢:Failed to decode packet 'accept_teleportation')
-
现象(其他用户反馈,已本地用官方 1.21.1 服务端完整复现):进服完全成功(服务端日志
logged in with entity id …+joined the game),紧接着就掉线,服务端报Internal Exception: io.netty.handler.codec.DecoderException: Failed to decode packet 'serverbound/minecraft:accept_teleportation'换端口 / 换地址(localhost、回环、局域网 IP)/ 换版本字符串都一样;而连 26.2 却完全正常。
-
根因:我们的按键上报兼容层(为 26.2 加的、每 50ms 发一次
player_input)是无条件发的,
但 1.21/1.21.1(协议 767)根本没有player_input这个包(1.21.3+ 才有)。
而minecraft-protocol的 protodef 遇到未知包名不报错——实测它写出的字节是write('player_input') → 02 00 00 ← id=0x00、body 为空 write('definitely_not_a_packet') → 02 00 00 ← 和一个瞎编的包名一模一样 write('teleport_confirm') → 03 00 00 07 ← 正常包:id=0x00 + VarInt(7)服务端于是把 id
0x00当成它自己注册表里的accept_teleportation(1.21.x 里确认传送就是 0x00),
去读teleportId时没有字节可读 ⇒ 抛DecoderException⇒ 立刻踢人。
所以错误名与"我们真正发的包"毫无关系,极具误导性。 -
修法:给 core 加一道"发之前先查这个版本的协议数据里有没有这个包"的护栏(
#supportsPacket,
带缓存),player_input只在该版本真有它时才发;顺带在每次 tick 也复查一遍(重连可能换版本)。
查不到的版本会记一行日志说明,而不是硬发。 -
顺带修掉「幽灵在线」:被踢之后 mineflayer 的
bot.entity会残留,而online只看entity,
于是死连接被报成"在线"(工具对着死 socket 干等、世界时间冻结、/list零响应)。
现在online要求连接没结束,status()会明确回ghost: true+ 一句"要回游戏里请重新 mc_connect",
requireBot()也直接说"连接已结束(bot.entity 是残留)"。 -
回归测试(自检 + 真机):
· 自检断言:1.21.1 上一个包都不发、26.2 上照常发、源码里必须留着这道护栏,
以及"幽灵在线"的三条(online变 false /status()标 ghost /requireBot()明确报错)。
· 真机复现与验收(本地官方 1.21.1 服务端):修前 1 秒被踢(错误与反馈逐字一致);
修后稳坐 8 秒不掉线,player_input发出 0 次、服务端日志再无DecoderException。
v0.1.6
whale_craft v0.1.6
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.1.6] - 2026-09-19
这一版在 0.1.5 之上只加了一个修复。0.1.5 的全部内容(P0 崩溃修复 /
mc_lan只留广播 /
新增mc_ping/ 默认行事准则第五版)也都在这一版里,装 0.1.6 就都有了。
🔴 修复(某个皮肤站账号登录一直 400:authenticate 少了 Yggdrasil 必填的 agent 字段)
-
现象(用户实测):某个皮肤站的账户怎么都登不上,一直"认证失败 HTTP 400";
另一个皮肤站(自建、老实现)同一个插件、同一个流程却没事。 -
根因:
/authserver/authenticate的请求体里少了agent——
它是 Yggdrasil 官方协议里 authenticate 的必填字段(authlib-injector 与官方客户端都会发)。
我们一直没发,老实现容忍缺省,但换成新实现Yggdrasil Connect的皮肤站不容忍:
缺字段直接回 400(而不是 401/403),于是错误码落在"认证失败 HTTP 400"上,
看起来像"密码错",其实请求根本没被当成一次登录。 -
实测对照(2026-09-19,真发请求,同一地址只差这一个字段):
认证服 缺 agent带 agent(假账号)出问题的那个( Yggdrasil Connect)400 403(正常走完凭据校验) 一直正常的那个(老实现) 403 401 即:"通不通"的差别就在这一个字段上。
-
修法:
authenticate请求体补上agent: { name: 'Minecraft', version: 1 }(标准值,官方客户端同款),
并给 400 单独补了一句人话提示(区分"请求不合规"与"账号密码不对")。
另外在代码里留了这条事故的说明,防止后人又把agent删掉。 -
回归测试:自检里那个"桩掉
fetch、抓真实请求体"的用例加了两条断言 ——
请求体必须带agent(name=Minecraft / version=1)、且源码里保留"缺 agent 会 400"的说明。
另外真机端到端验过:走插件自己的认证代码打那个皮肤站,现在拿到的是 403(凭据校验),不再是 400。
v0.1.5
whale_craft v0.1.5
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.1.5] - 2026-09-18
🔴🔴 修复(P0:连一个不存在的服务器会把整个 DSH 进程搞崩)
-
现象(用户实测):对 AI 说连一个根本没开的服务器(
127.0.0.1:61631),宿主进程直接死:Error: connect ECONNREFUSED 127.0.0.1:61631 Emitted 'error' event on McBot instance at: src/core.mjs:671 node:events:486 throw er; // Unhandled 'error' event——工具报错可以,但绝不能把宿主带走。
-
根因:
McBot extends EventEmitter,而 EventEmitter 的语义是「emit('error')时若没有监听者就 throw」。
原来那行把 bot 的网络错误原样转发到 McBot 上:b.on('error', (e) => { this.lastError = e.message; this.emit('error', e) }) // ❌
而 McBot 通常没有
'error'监听者(工具层是await抛错返回,不订阅 error)
⇒ 一个"服务器没开"这种再普通不过的错误,就把整个进程带走了。
另一处(认证阶段)写的是try { this.emit('error', err) } catch {}—— 假保护:
抛出来的就是这次emit自己,try/catch拦不住它。
(与 2026-09-17 那次"未处理 Promise 拒绝 → 宿主 fail-loudexit(1)"是同一族:插件里的错误绝不能漏到宿主。) -
修法:把"上报错误"收敛成唯一一个口子
#reportError(e),它保证:- 记
lastError(工具层据此给用户一句人话); - 记一行日志(
mc_diag/ 日志能看到); - 只在真有监听者时才
emit(listenerCount('error') > 0)—— 没人听就到此为止,绝不 throw; - 自己再兜一层
try/catch(监听者回调里抛错也不该带走进程)。
两处调用点(bot 的error转发、认证阶段connect()的 rejection)都改走它。
- 记
-
回归测试(自检里真连一个刚关掉的端口,且故意不订阅
'error'—— 真实工具路径就是这样):
断言"以普通错误结束"、lastError带得上ECONNREFUSED、并且走到后面的断言 = 进程没被带走;
另加静态断言:代码里每一处this.emit('error')都必须带"有监听者才发"的保护
(注释里的事故引用不计)。
默认行事准则(.whale-craft/RULES.md)第五版:新增「较长思考」整节
- 内容换成用户给的全文(第四版 2318 字 → 第五版 5911 字节 / 87 行,十个分节):
宗旨·称呼·记忆·边界信息·登录游戏·看门狗·聊天·建筑须知·较长思考·硬规矩。 - 新加的整节「较长思考」:长时间思考不给响应会让用户以为你卡住了;
建议偶尔简短汇报想法——一方面是给用户交代,另一方面这样事件提示词才有注入时机(否则错过新情况)。 - 「建筑须知」补三条:先把大体结构做完再抠细节 · 每阶段完成要给用户响应并说明还在继续 ·
建造完成后必须复盘(完整性 / 美观 / 与环境融合),发现问题先修再认定任务完成。 - 自检同步:断言"第五版十个分节都在"、"建筑须知补的三条都在"、"较长思考讲到
『长思考要偶尔汇报』『这样事件提示词才有注入时机』"。 ⚠️ 想立刻用上这一版:本次发版会带着 0.1.5 的版本号,"随版本更新"(默认开)会自动替换你工作区里那份;
也可以在「MC设置 → 提示词」里点恢复默认。
🔴 mc_lan 砍掉扫网段:只保留原版那一件事(听局域网公告)
- 起因(用户):"原版都没有,我们凭什么加!一个工具调用半天,用户又说慢!"
- 删掉的行为:曾用"① 听多播公告 + ② 扫本机 /24 的 25565-25569 + 手写 STATUS ping"两条路。
第 ② 条是一个 8.2 秒(实测一个 /24)起步的动作,最坏情况(网段里 TCP 通、但不回 MC 协议)
单个 /24 可到 100 秒级、多网段可到分钟级——而defineTool的timeoutMs在宿主里只是元数据、
没有任何地方真正拿它包超时,所以慢就是真慢。 - 为什么删得起:它多给的"版本 / MOTD / 人数",在
mc_connect进服时本来就会拿到
(mineflayer 传version:false→minecraft-protocol的autoVersion内部就是同一条 STATUS ping);
唯一不可替代的"没开公告的服务器",原版客户端自己也找不到 —— 让用户报地址即可。 - 现在的
mc_lan:只听224.0.2.60:4445上"对局域网开放"的公告
([MOTD]…[/MOTD][AD]端口[/AD],原版/复刻实现的重发周期 1.5 秒),不扫端口、不主动发包,
参数只剩mode(只有broadcast)与seconds(默认 3、上限 15)——
恒定在 seconds 秒内返回,不再是网络扫描器,也再没有分钟级的调用。 - 顺带:
src/lan.mjs从 313 行缩到 ~80 行,连node:net都不再 import(只剩node:dgram);
默认行事准则里那句"先扫描局域网服务器"改成"可以先听一下公告,找不到就直接问用户地址"。 - 回归测试:断言 7 个扫描相关导出全部消失、
lan.mjs里不再出现 TCP/扫描字样、
工具参数只剩mode/seconds、返回里没有scanned字段;
并在回环上真发三条公告(合法 / 垃圾 / 重复)验证"听得到 + 垃圾被丢 + 同 host:port 去重",
以及seconds=1到点就返回、seconds=999被夹到 15 秒。
✨ 新增 mc_ping:已知地址时的单地址探测(通不通 / 版本 / MOTD / 人数 / 延迟)
- 起因(用户):"有没有 ping 的工具?已知地址,测试通透性和 motd 等信息,单地址。"
—— 砍掉扫段之后,"知道地址、但想先看一眼再进服"这件事确实没有工具可用。 - 做什么:发一次 Minecraft STATUS ping(握手
nextState=1+ping_start),拿到:
通不通(能不能拿到状态响应)/ 版本 / 协议号 / MOTD(颜色码已去)/ 在线与上限人数 /
延迟(写ping到收pong的往返)。🔴 不登录、不用账户、不进服,拿到就断。 - 和别的工具的分工:
mc_lan= 不知道地址时听局域网公告;mc_ping= 知道地址时主动探一次;
mc_connect= 真进服(要账户、会掉线重连)。默认行事准则里加了「有明确地址时先mc_ping探一下再进服」。 - 为什么不直接用上游的
mc.ping()(踩过的坑,写下来免得后人再踩):
① 它不暴露 client,想在超时时真掐掉连接就得覆盖options.connect——
而ping.js结尾正是options.connect(client),覆盖掉它 = 谁都不建 socket:
实测四种场景(通的 / 端口没人听 / 只 accept 不回包 / 域名错)全都只能干等自己的硬超时;
② 它的超时是closeTimeout,默认 120 秒,对一次工具调用太长。
所以改成用同一套底层(Client+states+tcpDns,锚在解析到的 mineflayer 上)自己走一遍包序,
超时与清理自己掌握(默认 5 秒、上限 30 秒;无论成功/失败/超时都end()+destroy())。 - 错误说人话:
ECONNREFUSED=端口没人听 ·ENOTFOUND=域名解析不了 ·ETIMEDOUT=连上了没回应 ·
ECONNRESET=被服务端重置……认不出的原样回。任何失败都收敛成{ok:false, error, hint},
绝不把异常冒泡(工具报错可以,带走宿主不行——就是 0.1.5 那条 P0 的教训)。 - 回归测试(自检里真起一个 MC 服务端):起一个
minecraft-protocol服务端(离线模式、1.21.4、
MOTD 带颜色码、max-players=7)在回环上,断言 ping 到版本1.21.4/协议769/人数0/7/
MOTD 颜色码已去;另外断言"端口没人听 → 立刻ECONNREFUSED"、"黑洞连接 → 1.2 秒被硬超时掐掉
(不是等上游 120 秒)"、"域名解析不了 → 指向 DNS";以及地址解析的合法/非法各 4 种写法。
🧹 「MC设置 → 提示词」页去掉两条多余提示
- 起因(用户):"提示词页『还没到投递时机(提示词在发起请求之前现场判定并投递;这个会话还没发过消息)|
「注入工作区 AGENTS.md」是关的』这个提示框多余了,删掉。" - 那行判据里,
本会话注入:MC模式 ✓/✗ | 本提示词 ✓/✗ | 工作区 AGENTS.md ✓/✗已经把答案摆出来了;
再说一遍"还没到投递时机 / 开关是关的"是重复信息。 - 留下的(这些是看不出来、又真的影响投递的原因,不能删):没有 agent 上下文 · 这个会话没选工作区 ·
不是 MC 模式(连 preset 名一起说)· 工作区根目录里根本没有AGENTS.md这个文件 ·
preset 的 persona 压掉了宿主运行期上下文(带怎么修)。 - 于是正常情况那一行整行不再渲染(前端对
notes.length === 0本来就不渲染)。
v0.1.4
whale_craft v0.1.4
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.1.4] - 2026-09-18
默认行事准则(.whale-craft/RULES.md)第二版:新增「建筑须知」整节
- 默认内容换成新一版(1821 → 2318 字):新增整节 「建筑须知」 ——
与环境相互影响/避让改造 · 方块属性与 NBT(楼梯方向、台阶、火把灯笼附着)· 多部分方块(门窗床)·
受连接影响的方块(栅栏栏杆墙)· 细节与功能连通性 · 建成后复盘。 - 「聊天」补明:游戏中用户在聊天时第一时间回复,之后再做深度思考与行动。
⚠️ 版本号没变 ⇒ 插件自带的「随版本更新」不会自动替换你工作区里那份。
想立刻用上这一版:在「MC设置 → 提示词」里点恢复默认(或手动覆盖.whale-craft/RULES.md)。
🔴 修复(提示词晚一步才注入:跟用户那句不在同一批)
- 现象(真机):会话里能看到提示词,但是 LLM 已经跑起来之后才出现的——
用户的原话是"两个全都是 LLM 运行了一半才后知后觉地注入,根本不是用户发送第一条信息后注入"。 - 根因:上一版把投递挂在
agent/pre-step,但塞进了inbox.nextStep队列。
而宿主的顺序是preStep()里先inbox.claim()(把这一步的消息领走)再跑
agent/pre-step瀑布(core/agent-loop/src/agent.ts:244→:249)——
所以那一步塞进队列的提示行这一步用不上,要等下一步才被领走。会话日志实测:
step/start step=1→ 用户那句 →next-step -3→step/start step=2→ 三条提示行。 - 修法:照宿主官方插件
agent-instructions的写法,改写decision.messages
(context/agent-instructions/src/index.ts:313-338):交棒拿回 decision 后,把提示行
并进本步消息的最前面。宿主紧接着在agent.ts:373-377把decision.messages
逐条落成会话日志的user/message并作为请求里的那批消息 —— 既是正规通道(可持久化、可重放),
又能当场生效:提示行与用户那句同一批送给模型,模型第一眼就看到规矩。 - 顺带修掉两个自己埋的 bug(都会被
catch吞掉、表现成"静默不注入",极难查):reconcileNotices的几处提前返回漏了todo字段 ⇒enterWithNotices读.length抛 TypeError;- 用了没导入的
versionPromptHash⇒ ReferenceError。
- 另修:切出 MC 模式时无条件清投递台账(老代码按"队列非空"判断,而现在提示行在本步就送出、
队列通常是空的 ⇒ 漏清 ⇒ 切回来再也不投);并给会话日志划一条"切出时刻"的线,
这样"切出 → 再切回"能正常重投,不会被日志里的旧投递记录误判成"已经投过"。
改进(「MC设置」入口:选中 MC 模式就显示,工作区改到点击时检查)
- 以前:MC 模式但没选工作区时,插件会把「MC设置」入口藏起来——用户只看到"没有按钮",
不知道是为什么。起因是更早的规则"没有工作区就拒绝 MC 模式会话与设置"。 - 现在:只要选中了 MC 模式就显示按钮(有没有工作区都显示),工作区改到点按钮那一刻再检查:
- 有工作区 → 正常打开设置;
- 没工作区 → 弹一句原生提示,告诉用户"请先在这个对话里选择一个工作区",
并说明原因(记忆与提示词都放在工作区的.whale-craft目录里,没有工作区就没地方放)。
- 两个入口(新对话页模式芯片右边、已有会话标题条)口径统一;顺带去掉了一条
"服务端说不显示就不显示"的网络依赖。 - 服务端行为没变:没工作区仍然不套工具白名单、不注入提示词、不建
.whale-craft/;
设置接口在没有工作区时仍然拒绝(400+ 明确原因)。变的只是入口可见性。 /api/mc/mode现在额外报hasWorkspace,并且不再因为"没工作区"把mcMode压成false
(那正是前端藏入口的旧依据);诊断里仍写reason: 'no-workspace'。
🔴 修复(P0:装了这个版本,所有模式的所有会话每一轮都失败)
-
现象:随便发一句话,界面显示
本轮运行失败 Cannot read properties of undefined (reading 'kind');
标准模式、MC 模式一视同仁,等于装了插件就没法对话。会话日志里turn/start之后直接turn/end{kind:"error"},
连step/start都没有。 -
根因(0.1.4 引入):0.1.4 把提示词注入挂到了
agent/pre-step,而这条事件是 cordis 的 waterfall,
监听器必须调用next()交棒。0.1.4 的写法只声明了一个形参、函数体也没有return next():// ❌ 0.1.4(事故写法) ctx.on('agent/pre-step', ({ agent } = {}) => { reconcileNotices(agent) })
cordis 的契约是明确的(
@deepseek-ai/cordis的waterfall()注释原话):
"a listener that does not callnext()vetoes the rest of the chain, including the built-in behavior"
—— 不交棒 ⇒ 否决后面所有监听器和宿主内置行为,且 waterfall 的返回值就是那个监听器的返回值(undefined)。
宿主拿到undefined后紧接着读decision.kind⇒TypeError⇒ 整轮失败。 -
修法:接第二个形参并交棒,且交棒不受对账结果影响(对账挂在
next()返回值的finally上,
内层无论成功失败都保证先交过棒;next不接受参数、载荷沿用原 args,所以原样返回内层结果即可):// ✅ 0.1.5 ctx.on('agent/pre-step', ({ agent } = {}, next) => { const inner = next() ... return inner.finally(() => { try { reconcileNotices(agent) } catch { ... } }) })
-
为什么自检没拦住(补上了):原来的自检全部在插件自己的进程里直接调函数,绕开了宿主的编排,
所以"契约违规"测不出来。现在补了三层:- 替身按宿主契约行事 ——
agent/pre-step的替身在监听器没交棒时当场抛错,
任何一项用到它的断言都会红(旧写法必挂); - 横切静态检查 —— 扫描源码里所有
ctx.on('<事件>', …),凡是宿主已登记的 waterfall 事件
(agent/pre-step、agent/request、tools/execute、system-prompt/assemble等 14 个)
都必须接next并调用它;并带负向验证(把事故写法喂给同一判据,必须判违规); - 真 cordis 集成探针 —— 用宿主实际装的那份 cordis 起一个真
Context,注册插件的监听器,
走一遍waterfall(),断言内层被执行、返回值不是undefined且带kind。
- 替身按宿主契约行事 ——
-
教训:挂到 waterfall 之前先读那个 dispatch 模式的契约,别只看事件签名;"抛错"和"不交棒"一样致命。
修复(提示词注入的挂载点搬到了正确的地方)
- 背景:DSH 的「模式」(agent preset)只允许在对话开始前切换——第一轮一旦跑过,
宿主就拒绝换(agent-preset/locked)。也就是说,模式的最终值是在你发出第一句话、马上要送给模型
的那一刻才定下来的。而插件此前是在会话刚建立 / 你点模式芯片的那一瞬间就把提示词排进了投递队列,
比"定下来"早了一步。 - 后果:在空白会话里先点「MC模式」、又说一句话都没发就点回「普通模式」时,
那三条提示词已经排在队列里等着了 —— 你随后第一次开口,它们就注进了一个普通模式会话
("MC 行事准则 + 版本提示 + 记忆索引"出现在标准模式的对话里,而且会一直留在历史里)。 - 现在:提示词改在
agent/pre-step(宿主那条"消息已被取走、系统提示词已装好、这一步马上发给模型"
的流水线)现场对账后投递 —— 投出去的每一份都对应发起这次请求时这个会话真正在用的模式,
串模式从根上不再可能。- 不是 MC 模式 ⇒ 一条都不投;是 MC 模式且这个模式还没投过 ⇒ 投三条。
- 幂等:按模式记账(同一个模式只投一次)+回读会话日志(进程重启 / 插件重载后,台账没了,
也不会把已经注过的再注一遍)+队列里已有同名提示行就不重复入队;正文变了(改了行事准则 / 记忆索引更新 /
换了插件版本)则就地替换队列里那一条,不会新旧两份同时出现。 - 顺带删掉了旧实现里那段"已经注过的补一条作废声明"的圆场逻辑 —— 不再需要了。
修复(切出模式时漏清投递台账,会导致提示词再也不投)
- 自检里逮到的真 bug:切出 MC 模式时清掉了待投递队列,却没清投递台账 ⇒ 再切回 MC 模式时,
插件误判"这个模式已经投过了",一个字都不再投。现在两者一起清。
修复(🔴 提示词一条都没注入:依赖里少了 @deepseek-ai/dsh-llm)
- 现象(真机报的):
npm装到另一台机器上之后,工具一切正常,但提示词注入了没有 ——
AI 自己都说"没看到",对话窗口里也没有那几行。 - 原因:插件用宿主提供的
createUserMessage()来构造那几条"插件提示行",而这个函数来自
@deepseek-ai/dsh-llm—— 它当时根本没写进依赖声明。在开发机上碰巧能解析到(那份
node_modules里有指向宿主源码的链接),别人正常npm i装出来的插件目录里没有这个包、
往上也找不到 ⇒ 函数拿不到 ⇒ 提示行一条都建不出来。
而"工具白名单/文件边界"那两道只用插件上下文、不碰任何宿主包 ——
所以症状精确地是"工具都在、提示词全无"。更糟的是旧代码在拿不到函数时静默返回,
只在日志里留一行,界面上完全看不出来。 - 修法(两条腿):
- 不再依赖宿主包:消息构造统一收到
src/user-message.mjs—— 优先用宿主实现,
拿不到就用插件自带的等价实现(字段与宿主UserMessage逐个对齐:
role/content/source/id)。提示词注入从此与环境无关;拿不到时明确记一行日志。 - 依赖声明补上
@deepseek-ai/dsh-llm(optional peer + devDependency,范围*),
让有宿主包的环境走宿主实现。
- 不再依赖宿主包:消息构造统一收到
- 同一次事故还有第二处:
mc_watch(看门狗)用同一招构造"有人喊你/你被打了一下"的提示行,
拿不到宿主包时它会退化去调sessionController.prompt—— 那是用户来源消息,
会在对话里冒充你说话。现在它也走user-message.mjs,不再有那条退化路径。 - 自检新增断言:共用模块必须在 · 自带等价实现必须在 · 形状对齐 · 仍优先宿主实现 ·
看门狗也用同一个模块 · 并报出本次跑的是宿主实现还是自带实现。 - 验证方式:造了一个"只有
dsh-llm缺失"的环境(正是那台机器的情形)跑完整自检 ——
全绿(修之前那里有 9 条红:看门狗退化成用户消息),关键投递断言照样通过。
改进(投递失败不再静默)
- 拿不到宿主的消息构造函数时,以前只是静默返回(表现成"工具都好使、提示词一条都没有",
还查不出原因);现在会明确记一行日志说明原因。
v0.1.3
whale_craft v0.1.3
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.1.3] - 2026-09-17
默认行事准则(.whale-craft/RULES.md)更新
- 「称呼」不再写死:默认叫 Master,用户指定了就按用户指定的来("以记忆为准"那条保留)。
- 对 DSH 这个称呼/缩写同样敏感(以前只写"AI 相关称呼")。
- 「看门狗」里的错字改正("一遍在用户提到你时…" → "以便在用户提到你时…")。
- 「聊天」新增一条:用户在游戏里跟你说话时,第一时间先回一句,别让他干等;
之后再做深度思考和行动,必要时干完再回一次。 - 其余不变(记忆、边界信息、登录流程、看门狗单通道、硬规矩)。
修复(部分 DSH 版本上「切不进 MC 模式」)
- 插件自动创建的「MC模式」在部分 DSH 版本上加载失败,切换时报:
无法切换到「MC 模式」:… persona (@deepseek-ai/dsh-persona): invalid config: - $text missing required value。
原因:persona 的"人设正文"字段名跨 DSH 版本变过 —— 老版是text,新版是prefix,
而此前我们写死了prefix。 - 现在两种都支持:键名跟着你那份 DSH 自带的源 preset 走(源用
text就用text,源用prefix
就用prefix),我们只替换它的正文值;绝不新增对方 schema 里没有的键;认不出结构就一行都不动并记日志。 - 启动自检 + 自动修复:每次启动都检查插件自己建的那份 preset,发现 persona 键名与本版本不符
(或complete: true还在)就自动改对 —— 升级插件即可修好老环境,不必手工编辑 preset 文件。
(自建规格MC_PRESET_SPEC升到 6:升级时会把旧规格建的 preset 重建一遍。) - 边界不变:只有插件自己建的 preset 会被动;你手写/改过的那份(无自建标记或组成被改过)一律不碰。
修复(切出 MC 模式后,工具白名单不会撤销)
- 从「MC模式」切回普通模式后,那个会话的工具面仍然停留在 MC 白名单上 —— 表现是普通模式的会话
连 shell 都没有(没有pwsh,也没有subagent/workflow这些),看起来像"标准模式坏了、
命令执行不了"。原因:tools.restrict()造成的可见性限制是黏的(挂在会话自己的 scope 上,
会话不死就不消失),而插件此前只"套用"、从不"撤销"(restrict()返回的撤销手柄被丢掉了)。 - 现在双向:切进 MC模式 → 套白名单;切出 → 撤销,并把该会话从"MC 模式"兜底名单里移出;
再切回来还能重新套上(不会一次撤销就永久不管了)。 - 「管理工具硬锁」与「文件只能读写
.whale-craft/」那两道本来就在每次调用现场判定,
切出模式即刻失效;只有工具白名单是黏的,这次补上了与它对称的撤销。
修复(切出 MC 模式后,MC 提示词与游戏事件仍会灌进普通会话)
- 切到「MC模式」再切回普通模式,MC 的行事准则 / 版本提示 / 记忆索引照样会被注入。
原因:这几条是排队投递的(放进会话的"待投递"队列,到下一条消息进来时才真正投递)。
"切到 MC模式 → 一句话没发 → 切回普通模式"的会话,那几条还躺在队列里等着,你一开口就投进了一个
普通模式的会话。 - 现在切出 MC 模式时撤回它们:还在队列里的直接删掉;已经进过对话(摘不掉)的,
补一条一行作废声明("本会话已退出 MC 模式,上面那条行事准则自此刻起作废"),
免得模型继续按 MC 的规矩办事。切回 MC 模式会重新投递(不是一次撤销就永久不管)。 - 看门狗不再往已退出 MC 模式的会话里灌游戏事件:狗是"黏"的(挂载状态在会话上,切模式不会自动关),
以前切回普通模式后它仍会把"有人叫你 / 你被打了一下"注进会话。现在加了一道模式闸门:
切出即闭嘴、切回自动恢复(不必重新挂载)。 - 说明:bot 本身不会被自动踢下线(避免切一下模式就断开你正在玩的游戏)。
退出 MC 模式后想下线,说一声或调mc_disconnect。
v0.1.2
whale_craft v0.1.2
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.1.2] - 2026-09-17
修复(重要:0.1.1 里有一条会把整个 DSH 带崩的路径)
- 一条没人接的 Promise 拒绝会让 DSH 进程直接退出(控制台表现:
dsh: fatal load failure: Error: ForbiddenOperationException,然后进程没了)。两个成因都堵掉了:- 离线账户被当成"有凭据":连接时会把假令牌递给会话服务器,被认证服拒绝。现在按账户类型给开关:
离线账户不报备(haveCredentials=false),只有皮肤站账户才带令牌去会话服务器。 - 第三方库的回调 / Promise 不兼容:皮肤站令牌失效时,
minecraft-protocol用老式回调调
yggdrasil 的会话 join,而新版join是 async 且不调那个回调 ⇒ 拒绝无人接管。
插件侧补了一层兼容:替它把回调调起来,并保证不再有悬空拒绝。 - 同类风险一并处理:登录后回写账户信息、启动刷凭据索引、preset 自建自检这三处"顺带做的事"
现在都有兜底,失败只记日志。
- 离线账户被当成"有凭据":连接时会把假令牌递给会话服务器,被认证服拒绝。现在按账户类型给开关:
- 认证被拒时给出可执行的指引:不再是天书异常,而是"这个账户的登录状态已失效 ——
请到「MC设置」重新登录它(或点「刷新」)"。 - 新增**"遗言"记录**:万一宿主仍因未处理拒绝退出,插件会在它退出前把那条拒绝的调用栈写进插件日志,
下次不必再靠猜。
其它
- 仓库新增本机发版工具(
npm run publish:npm)与RELEASING.md;CI 的发布工作流不再碰 npm,
产物改 zip、Release 正文取自本文件(不再自动生成 diff 链接)。
v0.1.1
whale_craft v0.1.1
dsh plugin --profile web add github:yzi1b/whale-craft # 或解压附件后:dsh plugin --profile web add link:<目录>装完重启 DSH(服务端插件不热重载)。
[0.1.1] - 2026-09-17
新增
「文件分享」:发布区里的文件怎么给你
- 「MC设置」多了一页「文件分享」,两种模式(默认关闭):
- 关闭:AI 调
mc_kit_express时只会得到一句提示,于是把文件的绝对路径告诉你,你自己打开; - 在线:AI 得到完整 URL,图片可以直接在对话里显示。
- 关闭:AI 调
- 分享地址改为
<base>/api/whale-craft/express/<工作区 uuid>/<相对 .express 的路径>。
用 DSH 工作区注册表里的稳定 id,而不再是目录名 —— 不同父目录下的同名工作区不会撞,
目录改名后链接也不失效,URL 里也不暴露目录名。 - 在线模式需要填
base(你访问这台 DSH 用的地址)。base 那一行有「获取当前」:
一键用你现在访问页面的地址填好并保存;切到「在线」而 base 还空着时也会自动填一次。
不切模式、不点按钮,则不会去动它。 - 「清除分享数据」:二次确认后清空当前工作区
.express/里的所有文件(目录本身重建)。与分享模式无关,随时可点。 - 只有「在线」模式会开启那条访问路由;关闭模式下访问一律 404。
「随版本更新」:提示词跟着插件版本走
- 「MC设置 → 提示词」新增开关,默认开启:插件升级后,用新版本的默认行事准则替换
<工作区>/.whale-craft/RULES.md(会覆盖你的修改)。判定靠记忆目录里的.rules-version标记。 - 想长期保留自己那份,把它关掉即可:关掉后插件永不动它,而且不会"攒着"——
以后再打开也不会突然覆盖。 - 从 0.1.0 升级到 0.1.1 这一次不会替换你的文件(第一次遇到这个开关只记下版本号)。
修复
GET /api/mc/presets在真机上一直返回 404(漏在了设置接口的分派名单之外),
导致界面只能靠内置兜底名单判断哪些 preset 算 MC 模式。现在可达。mc_map的工具说明不再声称"返回值里带现成的 markdown"——那个字段早已移除,
取交付一律走mc_kit_express。
变更(不兼容)
- 「文件分享」的旧地址
/api/mc/whale-craft/<工作区目录名>/…已停用(一律 404),
旧链接请让 AI 重新取一次。 - 原先的「Windows 本地」模式已移除(它只是把绝对路径原样回给 AI,而前端不认本地路径,
点不开也内联不了)——只剩「关闭」和「在线」。 - AI 拿到的交付内容只来自
mc_kit_express那一行;别的工具返回值里不再有任何分享字段。
自检
- 离线断言 512 → 594 条:新增文件分享两种模式、工作区 uuid 解析与查找、
「随版本更新」的四种情形、发布区新路由与信任栅栏、clientOrigin精准取值等。