dsh-survival-mode
Manifest validSurvival mode: all sessions share one satiety/health pool — each model step burns satiety, starvation freezes tool calls until fed, with an MC mini-game for gathering food.
dsh-survival-mode · 生存模式
给 DeepSeek Harness(DSH)加一条命:整个 DSH 全局共享一份饱食度与生命。
模型每思考一步就消耗饱食度,吃饱了才干活;饿到归零开始掉血;
血空了全局工具被冻结——只剩对话能力,喂食才能复活。
~~越flash死得越快~~
🍗🍗🍗🍗🍗🍗🍗🍗⬜⬜ 饱食 120/150 ❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️🖤🖤 生命 10/12
一句话概括设计意图:让"停止执行任务"和"拒绝用户说话"彻底分开。 饿死冻结的是工具,对话永远通畅。
🚀 安装
包名:dsh-survival-mode · 仓库:X1A0BAN/dsh-survival-mode
Windows
dsh plugin --profile web add "github:X1A0BAN/dsh-survival-mode"
Windows 用户请照抄上面这条。
dsh plugin在 win32 经cmd.exe转发参数,而&是命令分隔符,所以不要写成#main&path:/...形式——那样会以ERR_PNPM_INVALID_DEPENDENCY_NAME失败。
macOS / Linux
dsh plugin --profile web add "github:X1A0BAN/dsh-survival-mode"
需要钉到某个提交时(POSIX):
dsh plugin --profile web add "github:X1A0BAN/dsh-survival-mode#<commit>&path:/"
本地目录安装(开发时)
git clone https://github.com/X1A0BAN/dsh-survival-mode
cd dsh-survival-mode && npm run build
dsh plugin --profile web add .
本仓库已把构建产物(lib/)提交入库,所以 github: 源安装不需要跑构建、也不需要任何额外的 registry 配额——这是刻意的分发选择。
卸载
dsh plugin --profile web remove dsh-survival-mode
🎮 它到底做了什么
| 机制 | 行为 |
|---|---|
| 思考计费 | 每个模型步骤(step)消耗饱食度,按 (会话, turn, step) 去重——重试不会重复扣 |
| 归零掉血 | 饱食度归零的那一刻立刻 −1 生命,之后按预设节奏持续掉血 |
| 饿死停摆 | 生命归零后,所有会话的工具调用被拒绝(survival_feed 除外);对话不受影响 |
| 喂食复活 | 面板上喂食;饿死状态下只有金苹果能复活(+饱食 / +生命),苹果面包救不回来 |
| 对话抢救 | 饿死状态下用户每发一条消息,会小幅回血并解除饿死——保证你永远不会被锁在会话之外 |
| 全局共享 | 所有会话共用一个池:多开会话会共同抽干同一条饱食度 |
🎚 三档预设
面板顶部的 [简单] [普通] [困难] 一键切换整组规则(不是只改一个数字):
| | 简单 | 普通 | 困难 | |---|---|---|---| | 每步思考扣除 | 4 | 6 | 10 | | 饱食度上限 | 200 | 150 | 80 | | 满饱食可思考 | 50 步 | 25 步 | 8 步 | | 生命上限 | 16 | 12 | 8 | | 掉血节奏 | 6 秒/−1❤ | 4 秒/−1❤ | 2 秒/−1❤ | | 归零后存活窗口 | 96 秒 | 48 秒 | 16 秒 | | 消息抢救量 | +45 / +4❤ | +30 / +3❤ | +18 / +2❤ |
上限是按实际能干多少活定的:一次自主目标回合可能连续思考 30 步以上(本项目开发期间实测烧掉 32 步),所以简单模式必须明显高于这个量级,否则"简单"在长任务里名不副实。
⚙ 面板自定义
点面板右上 ⚙ 可改四项并保存:每步思考扣除、饱食度上限、生命上限、掉血间隔(秒)。 手动改过任意一项后档位显示为「自定义」,三个预设按钮不再高亮——避免显示与真实参数不一致。
改上限不会免费送饭:抬高上限只是抬高上限,当前饱食度不会被回填;调低上限则会把当前值夹到新上限。
🍎 食物
| 食物 | 效果 | 获取方式 | |---|---|---| | 🍎 苹果 | +15 饱食 | 小游戏里的树定时结出(每 20 秒 1 个,最多挂 3 个),点击收获 | | 🍞 面包 | +45 饱食 | 小游戏里点村民概率获得(25%) | | ✨ 金苹果 | +100 饱食、+4 生命(饿死时按钮变为「复活」) | 工作台合成:8 块金锭 + 1 个苹果;金锭由点金矿小概率(20%)挖到 |
食物都存放在全局背包里,喂食从背包消耗 1 个,没有存货的按钮会变灰。面板上「⛏ 打开 MC 采集小游戏」可打开 2D 横板场景:草地上有一棵树、一个村民和一个工作台,地下埋着金矿,底部热键栏实时显示背包数量。
数值是按产出速率算出来的,不是拍脑袋(改之前先读这段)
| | 每分钟产出 | 换算饱食 | 普通模式每分钟消耗 | |---|---|---|---| | 收苹果 | 3 个(20 秒 1 个,挂满 3 个等收获) | 45 | 90 | | 点村民 | ≈5 个(爆率 25%,冷却 500ms) | 225 | 90 | | 挖金矿 | ≈12 块(爆率 20%,冷却 500ms) | — | 需要 8 块 / 个金苹果 |
- 苹果 +15 就必须低于面包 +45:苹果是树下稳定产出,一旦追平面包,面包和整条金苹果合成链都没有存在意义。
- 苹果单独吃不够活:只站在树下收苹果 = 45 饱食/分钟 < 90 的消耗,必须出去找村民或挖矿。
- 村民爆率不得高于 0.3:500ms 冷却下 0.6 的爆率等于每分钟 27 个面包(1620 饱食),食物会彻底失去意义。
- 这三条关系由
test/host.test.mjs的「平衡关系」用例守住,改数值时测试会拦你。
喂食规则
- 没饱就能喂:苹果、面包只要饱食度没满、背包有货,随时可喂。
- 满饱食不吃:饱食度和生命都满时,喂食会被拒绝(
state.feed直接挡掉,不只靠按钮变灰)——留给掉饿了再吃。 - 饿死只有金苹果:生命归零后,苹果与面包一律无效(宿主侧拒绝,面板侧变灰),金苹果按钮变为「复活」,喂下即解除饿死。
早期版本有一条「饱食度 ≥2 步余量就禁用苹果面包」的防误喂门槛,实测症状是饱食度 60/150 时两个按钮全灰、点了没反应,被当成"苹果和面包用不了"。防误喂的收益抵不过这个困惑,已改成只在满饱食度时禁用。同一版本里任意食物都能复活,导致面包(+45)比金苹果更划算、金苹果的合成价值归零,现在复活只认金苹果。
🎨 贴图:是 Minecraft 原版贴图,不是手绘仿制
小游戏刚做出来时贴图是代码里手绘的 16×16 字符画(pixelTexture() 调色板拼 SVG),
方块色偏和花纹都跟原版对不上。现在场景、热键栏、合成界面、面板图标全部换成原版素材。
npm run textures # 重新生成原版贴图(默认钉在 1.21.4)
管线做的事(scripts/vanilla-textures.mjs):
- 取官方版本清单 → 版本 json →
downloads.client,从 piston-data.mojang.com 下客户端 jar; - 用自写的零依赖 ZIP 读取器(
scripts/zip.mjs)从 jar 里取assets/minecraft/textures/**; - 用自写的零依赖 PNG 编解码(
scripts/png.mjs)处理,产出 data URI 写进assets/vanilla/textures.json; scripts/build.mjs构建期把它注入lib/client.js—— 所以运行期依旧零网络请求,产物自包含 (npm 的files白名单里没有assets/,但内联后不影响安装)。
三个值得记的坑:
- 贴图不在资源索引里。 现代 MC 的公开
assetIndex只有音效/语言/字体(4000+ 条), 方块与物品贴图是直接打在客户端 jar 内的。别照着resources.download.minecraft.net找贴图。 - 树叶是带噪声的灰度图。 原版
oak_leaves.png是等生物群系染色的灰度图,但带有 ±4 的编码噪声 (实测185,188,185、104,100,104)。严格r==g==b判定会把树叶当成彩色图、跳过染色, 结果场景里树叶发白。isGrayscale()因此带 8 的容差。 - 村民没有「正面站立图」。 村民在原版是实体模型,得按模型 UV 从 64×64 皮肤裁正面面片拼成 16×32。
UV 公式里竖直偏移是
v+dz(深度)不是v+dh;写错会让整张图各面片下移 2–6 像素, 拼出来的「村民」身体是一块灰墙。test/vanilla-textures.test.mjs用结构性断言守住这一点。 - 手臂是独立盒体,漏了它村民就没有手。
VillagerModel里手臂是texOffs(44,22)的 4×8×4 盒体, 正面片(44+4, 22+4) = (48,26)尺寸 4×8,而且两条手臂共用同一个 texOffs(模型里是两个盒体、 贴图偏移相同),所以左右两处同源。判定它属于哪块区域的办法:数皮肤上的像素范围——顶面+底面是一道 8×4 的横带(cols 48–55 / rows 22–25),四个侧面是 16×8 的一片(cols 44–59 / rows 26–33), 宽度正好2×(dw+dz)=16,与 4×8×4 唯一吻合。 - 竖直比例不能靠重叠硬塞。 模型竖直方向是头
-10…0、身0…12、腿12…24,总高 34 单位; 村民模型整体缩放 0.9375,所以 34 单位 ≈ 31.9 像素,正好是一条 32 行画布。把「头 10 + 袍 12 + 腿 12」 用 2 行重叠压进 32 行是错的(实测症状:袍和腿各长约 1 行、腿整体上移 2 行,"各部位比例不对")。 正确做法是把 34→32 的压缩按部位摊掉:头 0–9 行、袍 10–20 行、腿 21–31 行,每块 1:1 取面片、 不重采样也不重叠;袍让掉的是被头压住的领口接缝,腿让掉的是被袍子压住的顶端,底部腰带/鞋面都保留。 手臂按模型y=1…9挂在肩线(袍子顶行之下 1 行)起 8 行,鼻子按模型y=-6…-2落在第 4–7 行。
版权提醒。 原版贴图是 Mojang 的版权素材,内联进公开仓库属于再分发,官方 usage guidelines 并不允许这么做。本仓库按所有者要求保留,你若不想公开分发:把
assets/vanilla/加进.gitignore, 同时删掉test/vanilla-textures.test.mjs里依赖贴图产物的用例——src/与构建脚本一行都不用改, 客户端会自动回退到内置的手绘像素画(TEX = HAND_TEX + VANILLA_TEX,两层键集对齐)。 缺失的键(如原版没找skull贴图)由icon()逐个退回 emoji,不会出现半张图。
🤖 模型侧接口
插件注册了一个模型可调用的工具:
survival_feed({ food })—apple/bread/golden_apple(从背包消耗,没存货会失败)
并注入两段提示词:
- 静态段落:说明生存模式规则;
- 动态上下文:每步携带真实数值(饱食度 / 生命 / 累计步数)与行为指令(状态良好 / 偏低请收尾并催饭 / 归零请停下喊人 / 已饿死只能报告)。
动态上下文永远返回字符串。提示词渲染器会把解析结果直接喂给
text.indexOf('{{'),一旦返回undefined,整个提示词装配会抛错、所有会话的回合一起失败。这是本项目开发中真实踩过的坑。
🛠 开发
零运行时依赖,构建与测试只用 Node 内置模块(无 npm install 也能跑)。
node test/host.test.mjs # 14 个状态机行为测试
node test/host-contract.test.mjs # 真实 defineTool 编译工具 schema + 包文件清单
node scripts/build.mjs # 产出 lib/(注入 assets/vanilla/textures.json)
node scripts/verify.mjs # 产物自检 29 项(发布前必跑)
npm run textures # 拉官方客户端 jar 重新生成原版贴图(需要外网)
npm test # 上面两个测试串行跑
用
node test/host.test.mjs而不是node --test test/:后者会为每个测试文件 spawn 子进程,在受限沙箱里会以EPERM失败。
host-contract.test.mjs 会从 DSH 部署目录里找真实的 @deepseek-ai/dsh-tools,用它编译本插件的工具定义——parameters 根开放性与 output.schema 值根必填这两条规则只有让真正的编译器跑一次才能验证(本项目在这上面失败过两次)。找不到官方包时该测试会 skip,不会把机器相关路径变成硬失败。
验证过的安装链路(在真实 profile 上完整走通过一遍,供你判断"卡在哪一步")
dsh plugin --profile web add . # → + dsh-survival-mode link:…
dsh --profile web --dump-config # → 启动图内出现 id/name: dsh-survival-mode
装完后在运行中的 DSH 里实测到的事实:
- Host 半体已挂载且工具已注册:
survival_feed出现在模型的工具列表中。这一点比"文件都在"有力得多——apply()是在注册完服务、三个事件钩子与两段提示词之后才注册工具的,所以工具出现意味着前面那些调用都没有抛错。 - 客户端半体可被服务端读取:
profiles/<p>/node_modules/dsh-survival-mode/lib/client.js存在,且首行就是window.__ModuleLoader__.load({,也就是浏览器模块系统要求的包裹形态。 - 官方包由 profile 解析:
@deepseek-ai/dsh-tools不在 profile 的node_modules/@deepseek-ai/下,而是经.dsh-module-fallback/node_modules解析——所以不要把官方包写进dependencies,那会让公开 npm 解析失败。
两个容易踩的坑:
dsh plugin add与dsh --dump-config都不是只读命令。 前者写 profile 的dependencies与dsh.profile.bundles,后者会重写 profile 的cordis.yml(prepareProfile→writeFileSync)。在受限沙箱/只读环境里都会以EPERM失败——错误信息指向 profile 目录,而不是插件本身。npm pack --dry-run会写 npm 缓存,在这类环境里同样EPERM。所以本仓库改用test/host-contract.test.mjs里的文件清单断言来复刻 npm 的files匹配规则,不依赖该命令。
结构
src/config.mjs 三档预设、边界、食物表
src/state.mjs 核心状态机(纯逻辑、零依赖,可直接脱离 DSH 测试)
src/tool.mjs survival_feed 工具定义(接受 defineTool,因此可被真实编译器验证)
src/index.mjs Host 半体:服务、事件钩子、提示词注入
src/client/index.js 客户端半体:shell.overlay 上的 HUD 面板 + MC 采集小游戏
scripts/build.mjs 零依赖构建器(包裹 __ModuleLoader__ 闭包工厂,注入原版贴图)
scripts/vanilla-textures.mjs 原版贴图管线(官方客户端 jar → data URI)
scripts/png.mjs 零依赖 PNG 编解码 + 栅格操作(染色 / 叠加 / 放大 / 裁切)
scripts/zip.mjs 零依赖 ZIP 读取(从客户端 jar 里取贴图)
scripts/verify.mjs 产物自检
assets/vanilla/ 原版贴图原件与产物(textures.json 入库;cache/ 是 jar,已 ignore)
lib/ 构建产物(已入库)
三个关键实现约定(改代码前请务必阅读)
- 计费挂在
agent/request,不是agent/status。 后者只在idle ⇄ running迁移时派发,一个 turn 只触发一次,会表现为"扣一次就不动了"。agent/request在每步模型调用前派发,重试会重复派发,所以由状态机按(agent, turn, step)去重。 - 绝不用
agent/pre-step返回reject来"停止任务"。 pre-step 的messages就是用户刚提交的输入,reject会连人带话一起丢弃,把会话锁死到喂食为止。停摆要落在工具上(tools/pre-execute返回deny)。 - 状态全局唯一。 不要退回按会话分状态 + "最后活跃会话"指针的方案——那会让喂食喂错对象,表现为"这个会话的血莫名回满"。
⚠️ 已知限制
- 状态保存在内存中:DSH 重启后回到满值,不跨进程持久化。
- 只统计模型思考步骤,待机不会掉饱食度(不挂"饥饿钟")。
- 面板注册在
shell.overlay,这是全局浮层——如果你装了其他同样占据右下角的插件,需要拖动标题栏错开。
MIT © X1A0BAN
Compatibility
Versions
| Latest version | Published | Size |
|---|---|---|
| 0.1.0 | — | — |
Similar plugins
Always-on ADHD-friendly output shaping: one system-prompt section makes replies action-first with numbered steps and concrete time estimates; adhd_on / adhd_off / adhd_status tools persist the mode ac
★ 0
↓ 100/wk
dsh plugin --profile web add dsh-i-have-adhdDSH session workflows for packaging verifiable capsules, evaluating reusable Skills, and comparing controlled session trajectories.
★ 0
dsh plugin --profile web add dsh-session-labAuto-injects user-chosen skills into every DSH session, per prompt or once at session start, with a settings page, a composer indicator, and log-deduplicated session-start stamps; verified against DSH
★ 0
dsh plugin --profile web add dsh-spiderModel Health panel in Settings: lists every model configured in settings.yaml and batch-tests availability and latency for each.
★ 0
dsh plugin --profile web add dsh-model-healthOne-time Full access switch for DeepSeek Harness: new sessions (workspaces and conversations) start with danger-full-access and skip the per-session Full access confirmation; installable as a dsh bund
★ 0
dsh plugin --profile web add dsh-full-access-switchHand off focused context without waiting for or interrupting the active Agent: freeze a bounded Session snapshot, summarize it asynchronously with an isolated no-tool LLM, and deliver a provenance-bea
★ 0
dsh plugin --profile web add dsh-sideband