让 Live2D 桌宠跟随会话状态变脸并陪聊
29.6/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Luo-fengyi/dsh-pet该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · desktop
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 42 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 110 处,展示前 91 条)
- 读取本地文件main.js:25
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')) - 读取本地文件main.js:29
try { return JSON.parse(fs.readFileSync(STATE_PATH, 'utf8')) } catch (_) { return {} } - 写入本地文件main.js:49
fs.writeFileSync(STATE_PATH, JSON.stringify({ - 写入本地文件main.js:80
fs.appendFileSync(LOG_PATH, '[' + stamp + ':' + process.pid + '] ' + line + '\n') - 读取本地文件main.js:86
if (!fs.existsSync(LOG_PATH)) return - 读取本地文件main.js:87
const lines = fs.readFileSync(LOG_PATH, 'utf8').split('\n') - 写入本地文件main.js:88
if (lines.length > 300) fs.writeFileSync(LOG_PATH, lines.slice(-200).join('\n')) - 写入本地文件main.js:125
fs.writeFileSync(path.join(demoDir, 'demo_' + name + '.png'), image.toPNG()) - 写入本地文件main.js:154
fs.writeFileSync(out, shot.jpeg) - 写入本地文件main.js:170
fs.mkdirSync(outDir, { recursive: true }) - 读取本地文件main.js:587
try { return JSON.parse(fs.readFileSync(path.join(ROOT, 'assets', 'model', 'manifest.json'), 'utf8')) } catch (e) { return null } - 读取本地文件src/status-watcher.js:62
try { dirs = fs.readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()) } catch (_) { return null } - 读取本地文件src/status-watcher.js:66
try { sessions = fs.readdirSync(projDir, { withFileTypes: true }).filter((x) => x.isDirectory()) } catch (_) { continue } - 读取本地文件src/status-watcher.js:70
try { files = fs.readdirSync(sessionDir) } catch (_) { continue } - 读取本地文件src/status-watcher.js:75
try { st = fs.statSync(full) } catch (_) { continue } - 读取本地文件src/settings-store.js:21
return JSON.parse(fs.readFileSync(configPath(root), 'utf8')) - 写入本地文件src/settings-store.js:25
fs.writeFileSync(configPath(root), JSON.stringify(next, null, 2), 'utf8') - 读取本地文件src/settings-store.js:34
try { return JSON.parse(fs.readFileSync(secretsPath(root), 'utf8')) } catch (_) { return {} } - 写入本地文件src/settings-store.js:38
fs.writeFileSync(secretsPath(root), JSON.stringify(next, null, 2), 'utf8') - 读取本地文件src/vision.js:43
const text = fs.readFileSync(file, 'utf8') - 读取密钥环境变量src/vision.js:47
return process.env.DEEPSEEK_API_KEY || null - 发起网络请求src/vision.js:137
const res = await fetch(api.endpoint, { method: 'POST', headers, body: JSON.stringify(body) }) - 读取本地文件src/zstd-frame.js:49
const size = fs.statSync(filePath).size - 执行外部命令固定命令src/foreground.js:25
execFile( - 读取本地文件src/chat.js:41
const st = JSON.parse(fs.readFileSync(this.statePath, 'utf8')) - 写入本地文件src/chat.js:61
fs.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2), 'utf8') - 读取本地文件src/chat.js:114
try { return fs.readFileSync(this.memoryPath, 'utf8').trim() } catch (_) { return '' } - 写入本地文件src/chat.js:127
try { fs.writeFileSync(this.memoryPath, next, 'utf8') } catch (_) { return false } - 读取本地文件_tools/analyze_expressions.js:14
const cdi = JSON.parse(fs.readFileSync(path.join(DS, 'c_0120.cdi3.json'), 'utf8')) - 读取本地文件_tools/analyze_expressions.js:31
const files = fs.readdirSync(DS).filter((f) => f.endsWith('.exp3.json')).sort((a, b) => a.localeCompare(b, 'zh')) - 读取本地文件_tools/analyze_expressions.js:40
try { json = JSON.parse(fs.readFileSync(path.join(DS, f), 'utf8')) } catch (e) { lines.push(label + ' 解析失败'); continue } - 写入本地文件_tools/analyze_expressions.js:64
fs.writeFileSync(OUT, lines.join('\n'), 'utf8') - 读取本地文件_tools/analyze_motions.js:7
const cdi = JSON.parse(fs.readFileSync(path.join(M, 'c_0120.cdi3.json'), 'utf8')) - 读取本地文件_tools/analyze_motions.js:16
for (const f of fs.readdirSync(motionDir).filter((x) => x.endsWith('.json'))) { - 读取本地文件_tools/analyze_motions.js:17
const m = JSON.parse(fs.readFileSync(path.join(motionDir, f), 'utf8')) - 写入本地文件_tools/analyze_motions.js:48
fs.writeFileSync(path.join(__dirname, 'motion_analysis.txt'), out.join('\n'), 'utf8') - 写入本地文件_tools/build_assets.js:23
fs.mkdirSync(p, { recursive: true }) - 读取本地文件_tools/build_assets.js:27
if (fs.existsSync(p)) fs.rmSync(p, { recursive: true, force: true }) - 读取本地文件_tools/build_assets.js:31
if (!fs.existsSync(SRC)) throw new Error('找不到源模型目录: ' + SRC) - 读取本地文件_tools/build_assets.js:41
if (!fs.existsSync(from)) throw new Error('缺少文件: ' + f) - 写入本地文件_tools/build_assets.js:42
fs.copyFileSync(from, path.join(OUT, f)) - 读取本地文件_tools/build_assets.js:49
const textures = fs.readdirSync(texSrc).filter((f) => f.toLowerCase().endsWith('.png')).sort() - 写入本地文件_tools/build_assets.js:50
for (const f of textures) fs.copyFileSync(path.join(texSrc, f), path.join(texDst, f)) - 读取本地文件_tools/build_assets.js:58
const obj = JSON.parse(fs.readFileSync(from, 'utf8')) - 写入本地文件_tools/build_assets.js:60
fs.writeFileSync(to, JSON.stringify(obj, null, 2), 'utf8') - 读取本地文件_tools/build_assets.js:63
for (const f of fs.readdirSync(motionSrc).filter((x) => x.endsWith('.motion3.json'))) { - 写入本地文件_tools/build_assets.js:87
fs.copyFileSync(path.join(SRC, f), path.join(OUT, 'exp', ascii + '.exp3.json')) - 写入本地文件_tools/build_assets.js:119
fs.writeFileSync(path.join(OUT, 'ds-pet.model3.json'), JSON.stringify(model3, null, 2), 'utf8') - 读取本地文件_tools/fetch_core.js:10
if (fs.existsSync(OUT) && fs.statSync(OUT).size > 1000) { - 发起网络请求_tools/fetch_core.js:15
const res = await fetch(URL) - 写入本地文件_tools/fetch_core.js:18
fs.mkdirSync(path.dirname(OUT), { recursive: true }) - 写入本地文件_tools/fetch_core.js:19
fs.writeFileSync(OUT, buf) - 读取本地文件_tools/fetch_electron.js:9
const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')) - 读取本地文件_tools/fetch_electron.js:18
if (fs.existsSync(exePath)) { - 发起网络请求_tools/fetch_electron.js:31
const res = await fetch(url) - 写入本地文件_tools/fetch_electron.js:34
fs.writeFileSync(tmpZip, buf) - 删除本地文件_tools/fetch_electron.js:39
fs.rmSync(tmpDir, { recursive: true, force: true }) - 执行外部命令固定命令_tools/fetch_electron.js:41
execFileSync('powershell.exe', [ - 写入本地文件_tools/fetch_electron.js:45
fs.mkdirSync(distDir, { recursive: true }) - 读取本地文件_tools/fetch_electron.js:47
const entries = fs.readdirSync(tmpDir) - 读取本地文件_tools/fetch_electron.js:48
const inner = entries.length === 1 && fs.statSync(path.join(tmpDir, entries[0])).isDirectory() - 读取本地文件_tools/fetch_electron.js:51
for (const f of fs.readdirSync(inner)) { - 写入本地文件_tools/fetch_electron.js:54
fs.writeFileSync(path.join(electronDir, 'path.txt'), process.platform === 'win32' ? 'electron.exe' : 'electron') - 发起网络请求_tools/fetch_file.js:14
const res = await fetch(url, { redirect: 'follow' }) - 写入本地文件_tools/fetch_file.js:17
fs.mkdirSync(path.dirname(out), { recursive: true }) - 写入本地文件_tools/fetch_file.js:18
fs.writeFileSync(out, buf) - 写入本地文件_tools/fetch_file.js:19
fs.writeFileSync(info, 'OK ' + res.status + ' ' + buf.length + ' bytes\n' + url + '\n') - 写入本地文件_tools/fetch_file.js:21
fs.mkdirSync(path.dirname(info), { recursive: true }) - 写入本地文件_tools/fetch_file.js:22
fs.writeFileSync(info, 'FAIL ' + (e && e.message) + '\n' + url + '\n') - 读取密钥环境变量_tools/gh_api.js:3
const token = process.env.GH_TOKEN - 请求外部主机api.github.com_tools/gh_api.js:10
const res = await fetch('https://api.github.com' + path, Object.assign({}, opts, { - 发起网络请求_tools/gh_api.js:10
const res = await fetch('https://api.github.com' + path, Object.assign({}, opts, { - 读取本地文件_tools/probe_events.js:47
const raw = fs.readFileSync(src) - 写入本地文件_tools/probe_events.js:77
fs.writeFileSync(out, outLines.join('\n'), 'utf8') - 读取本地文件_tools/test_assistant.js:10
const cfg = JSON.parse(fs.readFileSync(path.join(ROOT, 'config.json'), 'utf8')) - 读取本地文件_tools/test_assistant.js:23
if (fs.existsSync(imgPath)) { - 读取本地文件_tools/test_assistant.js:24
const img = fs.readFileSync(imgPath) - 写入本地文件_tools/test_assistant.js:52
fs.writeFileSync(path.join(__dirname, 'assistant_test_result.txt'), out.join('\n'), 'utf8') - 读取本地文件_tools/test_prompt_leak.js:10
const cfg = JSON.parse(fs.readFileSync(path.join(ROOT, 'config.json'), 'utf8')) - 写入本地文件_tools/test_prompt_leak.js:45
fs.writeFileSync(path.join(__dirname, 'prompt_leak_result.txt'), out.join('\n'), 'utf8') - 读取本地文件_tools/test_status.js:9
const cfg = JSON.parse(fs.readFileSync(path.join(ROOT, 'config.json'), 'utf8')) - 读取本地文件_tools/test_status.js:39
if (real && fs.existsSync(real)) { - 写入本地文件_tools/test_status.js:52
fs.writeFileSync(dest, out.join('\n'), 'utf8') - 读取本地文件_tools/test_vision.js:15
const yaml = fs.readFileSync(CRED, 'utf8') - 发起网络请求_tools/test_vision.js:27
const res = await fetch(URL, { method: 'POST', headers, body: JSON.stringify(body) }) - 读取本地文件_tools/test_vision.js:43
const b64 = fs.readFileSync(IMG).toString('base64') - 读取本地文件_tools/test_vision_params.js:10
const yaml = fs.readFileSync(CRED, 'utf8') - 读取本地文件_tools/test_vision_params.js:15
const b64 = fs.readFileSync(IMG).toString('base64') - 发起网络请求_tools/test_vision_params.js:41
const res = await fetch(URL, { - 发起网络请求renderer/renderer.js:333
const res = await fetch('../assets/model/' + e.file) - 发起网络请求renderer/renderer.js:472
const res = await fetch(MANIFEST_URL)
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库
涉及外部主机:api.github.com
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 跟随会话状态变脸
- 屏幕查看
- 聊天与长期记忆
DS娘桌宠:Live2D 桌面宠物,跟随 DSH 会话状态变脸,能看屏幕、聊天、长期记忆
README
由 DeepSeek 最新模型翻译生成dsh-pet · DS娘桌宠
把 Live2D 模型变成常驻桌面的小桌宠,并且跟着 DeepSeek Harness(DSH)的会话状态实时变脸;她还能看你的屏幕、跟你聊天、记住你说过的事。
Windows / Electron / 纯本地运行,不依赖任何云服务(除了你自己配的模型接口)。
默认适配的模型:B 站 UP 主 氵六青 发布的 DS娘模型(视频地址)。
模型版权归原作者所有,本仓库只做资源整理与程序适配,不随仓库分发模型文件。
关于代码是怎么来的:整个项目——从 Live2D 渲染、DSH 状态联动、看屏幕,到设置窗等等——都是在 DeepSeek Harness(DSH) 里由 deepseek-v4.1-flash 完成的,所以这是一份 AI 写出来的工程:主要功能都实测跑通过,但大概率还藏着不少没被发现的 bug。用的时候请多留个心眼;遇到问题欢迎提 issue。
功能
状态联动(读 DSH 会话日志,不需要 DSH 配合)
| DSH 里发生的事 | 桌宠表现 |
| 收到你的消息 | 感叹号 +「收到啦~」 |
| 模型在思考 | 呆呆眼 +「思考中…」 |
| 正在调工具 | 圆眼镜 +「正在用 终端…」(工具名自动中文化) |
| 等你审批 / 回答 | 问号 +「在等你确认哦」 |
| 正在输出回复 | 开心兴奋 +「正在说话…
展开完整文档(README 剩余 1 节)
dsh-pet · DS娘桌宠
把 Live2D 模型变成常驻桌面的小桌宠,并且跟着 DeepSeek Harness(DSH)的会话状态实时变脸;她还能看你的屏幕、跟你聊天、记住你说过的事。
Windows / Electron / 纯本地运行,不依赖任何云服务(除了你自己配的模型接口)。
默认适配的模型:B 站 UP 主 氵六青 发布的 DS娘模型(视频地址)。
模型版权归原作者所有,本仓库只做资源整理与程序适配,不随仓库分发模型文件。
关于代码是怎么来的:整个项目——从 Live2D 渲染、DSH 状态联动、看屏幕,到设置窗等等——都是在 DeepSeek Harness(DSH) 里由 deepseek-v4.1-flash 完成的,所以这是一份 AI 写出来的工程:主要功能都实测跑通过,但大概率还藏着不少没被发现的 bug。用的时候请多留个心眼;遇到问题欢迎提 issue。
功能
状态联动(读 DSH 会话日志,不需要 DSH 配合)
| DSH 里发生的事 | 桌宠表现 |
| 收到你的消息 | 感叹号 +「收到啦~」 |
| 模型在思考 | 呆呆眼 +「思考中…」 |
| 正在调工具 | 圆眼镜 +「正在用 终端…」(工具名自动中文化) |
| 等你审批 / 回答 | 问号 +「在等你确认哦」 |
| 正在输出回复 | 开心兴奋 +「正在说话…」 |
| 一轮结束 | 星星眼 + 吹泡泡,并按回复内容的情绪挑表情 |
| 报错 / 中断 | 晕晕 +「出错了…」 |
| 文件长时间没动 | 收回表情,安静待机 |
看屏幕:每 60 秒截一次屏(缩到 1280 宽转 JPEG),和上一张比对;有明显变化才发给模型说一句,没变化就随机静默 4~8 轮——省钱也不聒噪。
聊天:桌宠窗口上半部分有个半透明回复框,打字回车即可。她会连"刚看到的屏幕"一起理解,回复显示在气泡里并同步切表情。
记忆:她觉得值得记的事会写进 memory.txt(纯文本一整条),跨会话保留。
装扮:模型自带的头饰、眼镜、桌面道具等配件可以自由组合(六个分类各挑一件,能叠加)。右键一键随机,也能让每次启动都随机换一套。
其他:拖动改位置、点击有反应、右键菜单(大小 / 置顶 / 设置 / 新开会话 / 看一眼桌面)、窗口位置与大小自动记住。
环境要求
- Windows 10 / 11(x64)
- Node.js 20 或更高(只在安装依赖时用得到)
- 可选:DeepSeek Harness(装了才有状态联动;不装也能当普通桌宠用)
快速开始
1. 装依赖
npm install
会自动下载 Electron 运行时(约 215MB)。如果卡住或没下下来(公司网络/代理常见),手动补:
用 npmmirror 镜像直接下 zip,解压到 node_modules/electron/dist 下载地址形如: https://registry.npmmirror.com/-/binary/electron//electron-v-win32-x64.zip
node _tools/fetch_electron.js
2. 准备模型
本项目不带模型(模型版权归各作者所有)。你需要自备一个 Live2D Cubism 4 模型。
默认适配的模型是 B 站 UP 主 氵六青 制作的 DS娘模型(视频地址)——就是那种 VTube Studio 导出的结构:一个 .moc3、几张贴图、一个 motions/ 动作目录、外加一堆中文名的 .exp3.json 表情。
如果你用的就是这套,把它整个文件夹放到本项目上一级并命名为 DS,然后:
node _tools/build_assets.js
脚本会自动扫描 DS 里的 .moc3、贴图、.exp3.json(表情)、.motion3.json(动作),整理进 assets/model/,并生成一个登记了全部动作与表情的 ds-pet.model3.json (原模型的 model3.json 通常不登记动作和表情,必须补这一步)。
换成别的模型也可以,脚本顶部有文件名映射表,按你的结构改一下即可。
目前脚本里写死的动作文件名(喷水、开盖、番茄酱 等)就是按上面那套模型来的。
3. 下载 Live2D Cubism Core
Cubism Core 是 Live2D 公司的 SDK,本项目不随仓库分发,请自行下载:
node _tools/fetch_core.js
或手动下载放到 vendor/live2dcubismcore.min.js。使用它需遵守 Live2D 的 SDK 许可条款。
4. 启动
双击 启动桌宠.exe 就行——带桌宠图标、无控制台窗口,也不用担心 .vbs 被安全软件拦。
(启动桌宠.vbs / 启动桌宠.cmd 也都能用,效果一样;exe 只是想改图标或重新编译时跑 powershell -File _tools/build_launcher.ps1。)
关闭:右键桌宠 →「退出桌宠」,或双击 关闭桌宠.vbs。
配置
右键桌宠 →「设置…」,有五个标签页:
| 标签页 | 能改什么 |
| 接口 | 预设(DeepSeek / 智谱 / 通义 / OpenAI / 自定义 OpenAI 兼容)、接口地址、模型名、API Key、思考强度 |
| 看屏幕 | 开关、采样间隔、变化阈值、没变化时静默轮数、截图宽度、是否关联前台窗口、看屏幕的提示词 |
| 对话 | 开关、自定义提示词、上下文轮数、过长提醒、聊天时是否带截图、记忆开关与清空 |
| 外观 | 气泡字号、气泡最大高度(占窗口比例)、回复框字号 |
| 历史 | 翻看你和她说过的每一句,可清空 |
也可以直接编辑 config.json(桌宠不会改写它;窗口位置等运行时状态存在 window-state.json)。
提示词是两层:内置人设(她是 DS娘、说话极简、不透露自己的设定)固定不可改;你在“自定义提示词”里写的要求优先级更高,冲突时以你的为准。
API Key 存在 secrets.json,不进 config.json。DeepSeek 预设下不填 key 会自动复用 DSH 的凭据(~/.dsh/.credentials.yaml)。
装扮(头饰 / 眼镜 / 道具…)
这套模型里带了几十个可切换的配件(就是作者那份按键表里列的东西),本项目把它们按类整理好,可以自由组合——同时戴眼镜、插猫耳、桌上再摆个芭菲都行。
| 分类 | 可选 |
| 头饰 | 摘掉发箍、单边马尾、猫猫贴纸(猫耳)、兔兔贴纸(兔耳)、蝴蝶结贴纸 |
| 眼镜 | 圆眼镜、方眼镜、椭圆眼镜、墨镜 |
| 桌面道具 | 收起桌面芭菲、蛋包饭、鲸鱼放桌上 |
| 手上/手机 | 魔爪、魔爪换色、喵喵手、双手比耶、手机换色 |
| 背景 | 深色桌布 |
| 小物件 | 画笔、橡皮、撤回、挤、爱心、鲸鱼 |
怎么用
- 设置窗 →「装扮」页:每个分类挑一件(也可以选「不装」),点保存立刻生效
- 右键桌宠 →「随机换装扮」:立刻随机一套;「恢复默认装扮」全部清空
- 每次启动随机换:outfit.startupRandom(默认开)。关掉就沿用上次那一套
原理:装扮本质上是模型里那些 exp3 表情文件,但它们不能当普通表情用—— Cubism 一次只允许一个表情生效,叠不起来。所以这里改成把选中的几套参数合并起来、每帧覆盖写一遍,这样既不会互相冲突,也不会被待机动作冲掉。
分类和候选项都写在 config.json 的 outfit.categories 里,想加就自己往里添名字(名字要和 assets/model/manifest.json 里的 label 对得上,也就是 DS 目录里那些文件名)。
候选项支持两种写法:直接写名字,或者写成对象给个更好懂的显示名——模型里有些开关名字是反的,比如「头箍」这个参数实际控制的是摘掉发箍(模型默认戴着),所以写成了:
{ "label": "头箍", "name": "摘掉发箍(默认是戴着的)" }
label 是文件名(必须对得上),name 只是设置窗里显示的文字。
常用命令
node _tools/build_assets.js # 重新整理模型资源(换了模型就跑一次)
node _tools/fetch_core.js # 下载 Cubism Core
node _tools/analyze_motions.js # 分析每个动作驱动了哪些参数(模型调试用)
node _tools/test_status.js # 状态机自测(合成用例 + 真实会话)
node _tools/test_vision.js # 单测视觉接口能不能用(不碰你的屏幕)
node _tools/test_prompt_leak.js # 验证提示词优先级与"不泄密"
目录结构
dsh-pet/
main.js Electron 主进程:透明置顶窗口、菜单、拖动、设置窗 preload.js 安全桥 config.json 全部可调项(只读配置) settings.html / .js 设置窗 renderer/ 页面:Live2D 渲染、气泡、回复框、点击交互 src/ status-watcher.js DSH 会话日志 → 状态机 zstd-frame.js zstd 分帧解码(DSH 日志是逐帧追加的) mood.js 文字 → 情绪(用于挑表情) screen.js 截屏 + 缩放 + 画面变化比对 vision.js 调接口(Anthropic 格式 / OpenAI 兼容) chat.js 会话、上下文、长期记忆、内置人设 assistant.js 定时看屏幕 / 聊天调度 / 记忆写入 settings-store.js 配置读写(key 单独存) foreground.js 取当前前台窗口(借 PowerShell + P/Invoke) assets/model/ 模型资源(自己生成,不入库) vendor/ Cubism Core + PIXI + pixi-live2d-display _tools/ 构建与自测脚本启动桌宠.exe 双击启动(C# 启动器,源码 _tools/launcher.cs,重编译见 build_launcher.ps1)启动桌宠.vbs / 关闭桌宠.vbs pet.log 运行日志(排查用)
常见问题
桌宠不出现 / 白屏看 pet.log,里面有渲染进程的报错。
状态不跟着 DSH 变确认 config.json 里 watch.sessionsRoot 指向你的 DSH 会话目录(留空会自动探测 ~/.dsh/sessions),并且 DSH 确实在写 session.v3.jsonl.zstd。
被别的窗口盖住已在用最高置顶层级 + 每 1.5 秒刷新。独占全屏的游戏/播放器仍然盖不住,这是 Windows 的限制。
接口报错设置窗 →「测试连接」会直接显示 HTTP 状态和错误原文。
隐私开着看屏幕功能时,每次采样都会把整屏截图发给你配置的接口。不想用就在设置里关掉总开关,或把间隔调大、阈值调高。她也会把认为重要的事写进 memory.txt,可以随时清空。
致谢
- 模型:DS娘模型由 B 站 UP 主 氵六青 制作并公开分享,版权归原作者所有。本项目的资源整理脚本默认按其发布的结构适配;模型文件不随仓库分发,使用与再分发请以原作者的说明为准。若你把这个模型用在自己的项目里,记得署名原作者。
- 渲染:Live2D Cubism SDK(Core 需按官方条款自行下载)、 PIXI.js、pixi-live2d-display
- 桌面外壳:Electron
声明
- 代码以 MIT 协议开源,见 LICENSE。
- 本项目不包含任何 Live2D 模型。模型版权归各自作者所有,请自行准备并遵守其使用条款。
- 本项目不包含 Live2D Cubism Core。它由 Live2D 公司提供,使用需接受其 SDK 许可条款。
- vendor/ 里的 PIXI 与 pixi-live2d-display 均为 MIT 协议。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Luo-fengyi/dsh-pet
让 Live2D 桌宠跟随会话状态变脸并陪聊
相关插件 · 桌面端
Codex 任务面板chuspeeism/dashi-taskboard
现代化可灵活嵌入的任务面板,支持 Codex、DeepSeek Harness
★ 3,409已汉化DSH
71.7
多智能体自进化开发平台Prism-Shadow/penguin-harness
统一、稳定的 Agent 自进化框架全自动优化:任意模型 · 任意算法 · 任意 Benchmark
★ 3,125已汉化DSH
71.1
桌面宠物PC2005-cloud/dsh-pet
DSH 桌面宠物:一行命令装好即用的透明动画小桌宠,支持多开、大小位置随心配置;还内置 DIY 素材链,能用 AI…
★ 5,465已汉化DSH
71
多端 Agent 工作台GCWing/OpenBitFun
OpenBitFun 是一个高度可定制的开源 Agent 工作台,让任务按你的方式持续推进。
★ 3,457已汉化DSH
70.8
DSH Desktopanywhere-labs/dsh-desktop
为 DeepSeek Harness DSH 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。
★ 34,710已汉化DSH
70.7
桌面宠物伴侣OpenPetsHQ/openpets
桌面伴侣平台,带宠物、插件,还能选配本地智能体集成。
★ 1,378已汉化DSH
70.2
这是你的仓库?认领条目