deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
简体中文 | English
DSH Web UI 右侧小游戏面板:等待模型回复或修 bug 时的摸鱼神器。
registerGame),新增游戏只需实现一个接口。兼容 DSH snapshot0810(snapshots/20260810T155924Z)、snapshot0811(snapshots/20260811T152241Z)与最终快照 snapshot0812(snapshots/20260812T172954Z-final):纯浏览器端 bundle(node half 仅 loader 占位),客户端元数据声明为嵌套 dsh.client——0810 的 ClientModuleHostService 只读该字段,顶层 dshClient 会被静默忽略(无日志无报错,插件不进 boot 图)。0810 实机验证通过;0811 与 0812 最终快照实机 boot 验证通过(见下)。
npm 发版兼容:兼容 DSH npm 发版 @deepseek-ai/dsh@0.0.1-rc.5(dist-tag next,即最终快照 snapshot0812 的 npm 发版;npm exec -p @deepseek-ai/dsh@0.0.1-rc.5 -- dsh --profile web --port <port> 可访问指定版本并启动,lib 生产模式),同时保持兼容 @deepseek-ai/dsh@0.0.1-rc.2(snapshot0811 的 npm 发版)。实测(npm rc.5 基线):dsh web 启动后 window.__DSH_BOOT__ 清单包含 @dsh-external/dsh-minigames,/plugins/@dsh-external/dsh-minigames/client.js 返回 200;typecheck、build 与 201 个单测通过。注意:0811 起 vendored cordis 更名为 @deepseek-ai/cordis(npm 发版不再发布 cordis 名义的 vendored 包)。本插件源码对 cordis 只有 type-only 导入(src/index.ts、src/client/index.tsx、src/invariant.ts),已把类型导入与 peer/devDependencies 迁移至 @deepseek-ai/cordis(peer ^4.0.1-rc.1,npm rc.5 基线上为 4.0.1-rc.4)——构建产物(lib/*.js)零 cordis 运行时导入,纯 npm install 不再报 ERESOLVE,无需 --legacy-peer-deps。
dsh.bundle.patch → cordis.patch.yml 的组合包层机制(本插件的 profile bundles 安装方式照旧),客户端 dsh.client 元数据发现与 window.__ModuleLoader__ 加载协议均未变。cordis@4.0.0-rc.7 更名为 @deepseek-ai/cordis@4.0.1-rc.1。本插件对 cordis 只有 type-only 导入,构建产物零 cordis 运行时导入——更名不影响已构建 bundle 的运行时加载;npm 基线 typecheck 时 cordis 裸导入解析到公开 cordis 包仍可通过,对齐建议见上。snapshots/20260811T152241Z)web 启动后 window.__DSH_BOOT__ 清单包含 @dsh-external/dsh-minigames,/plugins/@dsh-external/dsh-minigames/client.js 返回 200,右侧面板(🎮 小游戏)实测渲染。typecheck 与 201 个单测对 0811 基线通过。src/index.ts、src/client/index.tsx)与 peerDependencies/devDependencies 迁移至 @deepseek-ai/cordis(^4.0.1-rc.1;npm rc.5 基线上为 @deepseek-ai/cordis@4.0.1-rc.4)——构建产物(lib/*.js)零 cordis 运行时导入,npm rc.5 消费者 typecheck 全绿,npm install 无需 --legacy-peer-deps。dsh.bundle.patch → cordis.patch.yml 的组合包层机制,客户端 dsh.client 元数据发现与 window.__ModuleLoader__ 加载协议未变;面板不依赖任何宿主服务与布局槽(纯 document.body portal),与主框架版本解耦。snapshots/20260812T172954Z-final)web 启动后 window.__DSH_BOOT__ 清单包含 @dsh-external/dsh-minigames,/plugins/@dsh-external/dsh-minigames/client.js 返回 200;npm rc.5 consumer dsh web 启动后 boot 清单同样包含本插件。typecheck、build 与 201 个单测对最终快照基线通过。dshClient 迁移为嵌套 dsh.client(inject 原样保留).dmg-body 改为 flex 列布局,游戏区拿到真实可用高度,画布按"工具条+画布+按键提示"整体自适应(此前画布高度由自身内容决定、形成循环测量,窄窗口下画布溢出并触发滚动条)320 + 分数×0.15)直到
760 px/s 上限,越跑越快。得分 = 10 × 消除数²);max(0, 1000 − 用时×2)):用时越短分数越高;over 同时置为胜态)。won),无任何可移动/合并方向时游戏结束;won);max(0, 1000 − 用时×2))上报,面板保留最高分 =
最短通关用时,越快分越高。finished);max(0, 500 − 步数×5))。250 + 关数×20);max(0, 1000 − 用时×2)),
越快分越高,面板保留最短用时。前置:已构建的 DSH 20260808+ 快照、pnpm。
git clone https://github.com/omdsh-dev/dsh-minigames.git # 或直接使用本目录
cd dsh-minigames
pnpm install
pnpm build
# 装入当前 web profile(自动写入依赖并加入 dsh.profile.bundles)
dsh plugin --profile web add /绝对路径/to/dsh-minigames
# 可选:确认组合配置只出现一个插件行
dsh --profile web --dump-config | grep dsh-minigames
插件集合变更在重启 dsh web 后生效。卸载:
dsh plugin --profile web remove @dsh-external/dsh-minigames
本仓库同时携带
dsh.plugin.json(registry 通道清单)与cordis.patch.yml(官方 profile bundle 通道);二选一安装,不要同时启用。
dsh web),页面右缘出现 🎮 小竖条。P 暂停、R(结算后)重开、点「选游戏」返回选择列表。pnpm install
pnpm run typecheck # tsc --noEmit
pnpm run test # vitest 纯逻辑单测(189 个:引擎/棋盘/世界模型/三消/华容道/贪吃蛇/2048/扫雷/翻牌/五子棋/跳一跳/打砖块/打地鼠/黑白棋/Flappy/数独/吃豆人/跟枪/注册表)
pnpm run build # tsc 声明 + tsdown:lib/index.js(node half)+ lib/client.js(浏览器 bundle)
产物结构(随源码提交,与 dsh-web-panel 一致):
lib/index.js —— node half(loader 行实现,仅日志;客户端插件扫描依赖该行存在)。lib/client.js —— 浏览器 bundle,window.__ModuleLoader__.load({ id: '@dsh-external/dsh-minigames', factory }),id 必须与 package.json 的
name 一致(client-modules 以包名作为 compose 键)。lib/types/ —— 声明文件。src/
index.ts node half(loader 行实现)
invariant.ts 不变式伴生文件
client/
index.tsx 客户端插件:DOM portal 挂载面板(ctx.effect 管理生命周期)
app.css 面板样式(全部 dmg- 前缀,随 bundle 注入 <style>)
panel/Panel.tsx 折叠条 / 展开面板 / 游戏选择器 / GameArea 生命周期
games/
types.ts 游戏扩展接口(MiniGameDefinition / MiniGameInstance)
registry.ts 注册表(registerGame / getGames / getGame)
focus.ts 键盘焦点门控(避免劫持聊天输入)
canvas-fit.ts 画布按宿主自适应缩放(devicePixelRatio,防截断)
index.ts 内置游戏注册点
dino/ 纯逻辑(引擎:物理/计分/昼夜/雨天/生成密度)+ 渲染 + 游戏定义
tetris/ 纯逻辑(棋盘:旋转/消行/暂存/等级)+ 渲染 + 游戏定义
tanks/ 纯逻辑(世界:网格/转向吸附/AI/波次/特效)+ 渲染 + 游戏定义
match3/ 纯逻辑(三消:四连通/落体/目标分/关卡)+ 渲染 + 游戏定义
huarong/ 纯逻辑(华容道:滑动/打乱/解状态)+ 渲染 + 游戏定义
snake/ 纯逻辑(贪吃蛇:环面穿越/自撞/成长)+ 渲染 + 游戏定义
game2048/ 纯逻辑(2048:滑动合并/生成/胜负判定)+ 渲染 + 游戏定义
minesweeper/ 纯逻辑(扫雷:布雷/洪水展开/标旗/双击展开)+ 渲染 + 游戏定义
memory/ 纯逻辑(翻牌:配对/步数)+ 渲染 + 游戏定义
gomoku/ 纯逻辑(五子棋:落子/胜负/启发式 AI)+ 渲染 + 游戏定义
hop/ 纯逻辑(跳一跳:蓄力/落地判定/计分)+ 渲染 + 游戏定义
breakout/ 纯逻辑(打砖块:挡板/碰撞/关卡/球速)+ 渲染 + 游戏定义
whack/ 纯逻辑(打地鼠:计时/冒头/得分)+ 渲染 + 游戏定义
othello/ 纯逻辑(黑白棋:翻转/让位/终局/启发式 AI)+ 渲染 + 游戏定义
flappy/ 纯逻辑(Flappy:重力/柱子/碰撞/计分)+ 渲染 + 游戏定义
sudoku/ 纯逻辑(数独:生成/挖洞/冲突/计时)+ 渲染 + 游戏定义
pacman/ 纯逻辑(吃豆人:迷宫/移动/幽灵 AI/力量豆)+ 渲染 + 游戏定义
aimtrack/ 纯逻辑(跟枪:视角转向/三维漂移/射击后坐/晃动/命中率)+ 渲染 + 游戏定义
tests/ 纯逻辑单元测试
面板不依赖任何宿主服务与布局槽(纯 document.body portal),因此:
dsh.client.inject 为空,客户端零 @deepseek-ai 依赖;实现 MiniGameDefinition(src/client/games/types.ts):
import { registerGame, type MiniGameDefinition } from './index.ts'
const myGame: MiniGameDefinition = {
id: 'my-game', // 唯一 id(作为选中记忆与最高分 key)
title: '我的游戏',
icon: '🎯',
description: '一句话介绍',
controls: ['空格:跳跃', 'P:暂停'], // 画布下方的按键图例
create(host, options) {
// 在 host 内创建 <canvas>;返回实例:
return {
start() {}, // 启动/恢复主循环
pause() {}, // 暂停(面板折叠/切标签页/用户暂停时调用)
resume() {}, // 恢复
destroy() {}, // 释放 rAF/键盘监听等
}
},
}
registerGame(myGame)
create 返回的实例由面板驱动生命周期:切换游戏时先 destroy() 旧实例再
create() 新实例;面板折叠、标签页隐藏或用户点暂停时调用 pause()。
分数通过 options.onScore?.(score) 上报(仅在变化时调用),面板负责显示与
最高分持久化。建议把游戏逻辑拆成纯函数模块(不碰 DOM/定时器),与现有游戏
一样用单元测试覆盖。
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。