一个小伙伴,住在 DSH web UI…
31.2/100
综合分
2
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/zuoyunlai/dsh-pet-plugin.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 3 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 57 处,展示前 49 条)
- 读取本地文件index.js:312
const raw = await readFile(STATE_FILE, 'utf8') - 写入本地文件index.js:327
await chmod(target, mode) - 写入本地文件index.js:334
await mkdir(PET_DATA_DIR, { recursive: true, mode: 0o700 }) - 写入本地文件index.js:339
await writeFile(tmp, JSON.stringify(state), { encoding: 'utf8', mode: 0o600 }) - 写入本地文件index.js:341
await rename(tmp, STATE_FILE) - 读取本地文件index.js:363
const raw = await readFile(join(PET_DATA_DIR, 'voice.json'), 'utf8') - 读取本地文件index.js:798
const st = await stat(join(ASSET_DIR, name)) - 读取本地文件index.js:804
const buf = await readFile(join(ASSET_DIR, name)) - 读取本地文件index.js:864
const realBase = await realpath(dir) - 读取本地文件index.js:865
const realFile = await realpath(join(dir, name)) - 写入本地文件index.js:1095
await mkdir(TTS_CACHE, { recursive: true, mode: 0o700 }) - 写入本地文件index.js:1167
await mkdir(TTS_CACHE, { recursive: true, mode: 0o700 }) - 发起网络请求client.js:1640
return fetch(stateEndpoint(), { - 发起网络请求client.js:2216
fetch(base + '/dsh-pet/tts/status') - 发起网络请求client.js:2259
const res = await fetch(base + '/dsh-pet/tts', { - 发起网络请求client.js:2473
const res = await fetch(warmBase + '/dsh-pet/tts/warm', { - 发起网络请求client.js:3452
const res = await fetch(url, { - 发起网络请求client.js:5936
const res = await fetch(url, { credentials: 'include', signal: ctrl ? ctrl.signal : undefined }) - 读取本地文件lib/tts.js:71
if (existsSync(join(c, 'edge_tts'))) return c - 读取本地文件lib/tts.js:92
const st = statSync(p) - 读取本地文件lib/tts.js:120
if (existsSync(cand)) { - 读取本地文件lib/tts.js:145
names = readdirSync(root) - 读取本地文件lib/tts.js:164
if (pythonPath && pythonPath !== 'python' && existsSync(pythonPath)) return pythonPath - 执行外部命令来自配置/变量lib/tts.js:212
child = spawn(py, ['-c', code], { - 执行外部命令来自配置/变量lib/tts.js:341
const child = spawn(py, [TTS_WORKER], { stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true, env }) - 写入本地文件lib/tts.js:443
await rename(tmp, file) - 删除本地文件lib/tts.js:445
await unlink(tmp).catch(() => {}) - 读取本地文件lib/tts.js:467
const names = await readdir(TTS_CACHE) - 删除本地文件lib/tts.js:482
await unlink(f.p).catch(() => {}) - 读取本地文件lib/registry.js:60
const st = await stat(abs) - 读取本地文件lib/registry.js:218
const st = await stat(file) - 读取本地文件lib/registry.js:221
raw = await readFile(file, 'utf8') - 执行外部命令来自配置/变量build.mjs:19
const out = execFileSync(process.execPath, ['tools/gen-personas.cjs'], { encoding: 'utf8' }) - 读取本地文件build.mjs:27
const found = readdirSync('locale').filter((f) => f.endsWith('.json')) - 读取本地文件build.mjs:35
const json = JSON.parse(readFileSync('locale/' + f, 'utf8')) - 读取本地文件build.mjs:46
const pkgVersion = JSON.parse(readFileSync('package.json', 'utf8')).version - 读取本地文件build.mjs:48
const parts = readdirSync('src') - 读取本地文件build.mjs:61
let code = readFileSync('src/' + p, 'utf8') - 写入本地文件build.mjs:75
writeFileSync('client.js', out) - 执行外部命令来自配置/变量build.mjs:76
execFileSync(process.execPath, ['--check', 'client.js']) - 读取本地文件build.mjs:82
const lines = readFileSync('src/' + p, 'utf8').split('\n').length - 发起网络请求src/40-settings.js:75
return fetch(stateEndpoint(), { - 发起网络请求src/50-voice.js:144
fetch(base + '/dsh-pet/tts/status') - 发起网络请求src/50-voice.js:187
const res = await fetch(base + '/dsh-pet/tts', { - 发起网络请求src/50-voice.js:401
const res = await fetch(warmBase + '/dsh-pet/tts/warm', { - 发起网络请求src/60-behavior.js:587
const res = await fetch(url, { - 发起网络请求src/99-entry.js:267
const res = await fetch(url, { credentials: 'include', signal: ctrl ? ctrl.signal : undefined }) - 发起网络请求src/99-entry.js:362
if (typeof AbortController !== 'function') return fetch(url, init) - 发起网络请求src/99-entry.js:371
return fetch(url, { credentials: 'include', ...init, signal: c.signal }).finally(() => clearTimeout(t))
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DeepSeek Harness 的写实桌面宠物插件:四种人格、表情与动作、主动说话、神经网络 TTS,还有一个小聊天框,绝不碰你的会话。
README
由 DeepSeek 最新模型翻译生成dsh-pet
一个小伙伴,住在 DSH web UI 的右下角:它会待在那儿,也会随机冒出来,会说话(带语音)、走路、跳舞、害羞或生气,还带一个小输入框,你可以跟它聊天。五个照片级写实人设,各有各的脾气。
范围:这只宠物只活在 DSH 窗口里(挂载到框架的 overlay 插槽)。它无法浮在其他应用之上——那需要单独的 Electron 外壳,而不是插件。
一览
- 语言:界面文案、人设标语和聊天系统提示词跟随浏览器界面语言——已提供 en / zh / es / pt / hi(locale/.json,命名空间 pet;按 DSH 插槽约定,插槽以 locale: 'pet' 注册)。每个人设还附带一套英文台词包,所以非中文界面听到的是英文台词。
- 挂载点:shell.overlay(宠物本体,一个可点击穿透的图层)和 conversation.input.right(输入框旁边的入口按钮)。
- 私密聊天:你在小框里输入的内容永远不会进入你的会话。宿主端暴露 POST /dsh-pet/chat,用一次性的 ctx.llm.stream() 调用作答(不建会话,不写会话日志)。默认:deepseek-account / deepseek-flash;服务商、模型、maxTokens 和 temperature 都是插件配置。
展开完整文档(README 剩余 1 节)
dsh-pet
一个小伙伴,住在 DSH web UI 的右下角:它会待在那儿,也会随机冒出来,会说话(带语音)、走路、跳舞、害羞或生气,还带一个小输入框,你可以跟它聊天。五个照片级写实人设,各有各的脾气。
范围:这只宠物只活在 DSH 窗口里(挂载到框架的 overlay 插槽)。它无法浮在其他应用之上——那需要单独的 Electron 外壳,而不是插件。
一览
- 语言:界面文案、人设标语和聊天系统提示词跟随浏览器界面语言——已提供 en / zh / es / pt / hi(locale/.json,命名空间 pet;按 DSH 插槽约定,插槽以 locale: 'pet' 注册)。每个人设还附带一套英文台词包,所以非中文界面听到的是英文台词。
- 挂载点:shell.overlay(宠物本体,一个可点击穿透的图层)和 conversation.input.right(输入框旁边的入口按钮)。
- 私密聊天:你在小框里输入的内容永远不会进入你的会话。宿主端暴露 POST /dsh-pet/chat,用一次性的 ctx.llm.stream() 调用作答(不建会话,不写会话日志)。默认:deepseek-account / deepseek-flash;服务商、模型、maxTokens 和 temperature 都是插件配置。
- 图标:icon.svg(玫瑰剪影)和输入框按钮共用同一路径。
- 设置面板:分组排列(外观 / 语音 / 显示 / 动作 / 特效),自定义下拉框(原生 弹层是系统白底,深色主题下看不清)和自定义开关;面板相对宠物定位(在她上方,没空间时在她左侧),并在页头下方收进视口内。
- 五个人设(照片级写实,同一套光照;五个各带 5 种表情:默认 / 开心 / 害羞 / 生气 / 困倦):薇(紫罗兰)、绯(绯红)、靛(靛蓝)、雪(银白),外加鲸鱼娘(蔚蓝)——一位鲸鳍女仆,表情集在 1.23.0 加入,有专属的走路 / 跳舞 / 发夹动作。表情切换用交叉淡入(180 ms),不是硬切。
- 动作序列:人设可以声明 actions: { dance: [...], hair: [...], walk: [...] };每组 3–6 帧(3 帧组每帧 340 ms,6 帧组每帧 230 ms;蔚蓝只带视频片段,没有帧组)。四个原版人设都有跳舞 / 甩发 / 走路,各自贴合角色风格;较新的人设可以改用视频片段(VP9 + alpha),片段本身的长度决定动作持续多久。
- 添加素材:把透明 PNG 放进 assets/,在 PERSONAS 里引用(image,或 images: { mood: 'file.png' })。由 /dsh-pet/assets/ 提供(只接受图片和 webm 视频扩展名,只接受文件名)。tools/make-pet-image.py 会去掉绿幕背景(首选),不行再退回渐变抠像。
行为
| 能力 | 做法 |
| 常驻 / 随机 | 在面板里切换;随机模式会在活跃时段内按每小时概率抽取 |
| 活跃时段 | 起止时间,支持跨午夜(22:00 → 03:00) |
| 主动台词 | 按心情分组的台词包,气泡 + 语音 |
| 语音 | 可选:宿主只要有任意 python 带 edge-tts,/dsh-pet/tts 就合成语音(带缓存),/dsh-pet/tts/status 探测可用性;否则回退到系统 speechSynthesis。插件本身零运行时依赖 |
| 小输入框 | 默认隐藏;鼠标悬停在角色上时滑出(1.22.0 起,从角色移到输入框上不会收起)。在设置里关掉「仅悬停」即可固定。消息只发给宠物;一次性模型调用,不写入任何 DSH 会话 |
| 心情 | idle / walk / dance / shy / angry / sleep / talk / happy |
| 拖拽 | 放下后有 60% 概率说一句 drag 台词;五个人格都有(1.24.0 完成),五种语言 |
| 内心独白 | 低频(7%)灰色旁白——只是想法,从不出声;仅限声明了 lines.aside 的人格;五个都有(1.24.0) |
| 视线 | 瞳孔跟随鼠标(只用 CSS 变量,不触发重渲染) |
| 特效 | 墨水 / 彩纸 / 云 / 雾(可擦除)/ 炸弹 + 屏幕裂纹 |
| 事件钩子 | 一轮对话超过 4 s 后撒彩纸;工具调用失败后出现云 |
| 脾气 | 每个人格有各自的权重表,决定它更常做什么 |
| 隐藏 | 面板里的「隐藏 1 小时」 |
安装(本地,不走 registry)
已发布到 npm,包名 dsh-pet-plugin;也可以直接从文件夹安装。
from the registry (after publish)
dsh plugin --profile desktop add dsh-pet-plugin
from a local checkout: quit DSH first, then
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 # or double-click install.cmd
先退出 DSH(配置档的 package.json 被 HMR 监听)。脚本会把 "dsh-pet-plugin": "file:<this dir>" 加进配置档,注册 bundle,运行 pnpm install,然后回读四项事实。update.cmd 只刷新文件,DSH 运行时执行也安全。想要更甜美的神经语音:
pip install edge-tts # any python the host can find
export DSH_PET_PYTHON=/path/to/python # only if auto-discovery misses it
验证
node --check client.js
node tests/smoke.mjs # fake window + React stub, renders every persona/mood
host routes need the harness packages, so run them from the installed copy:
cd <profile>/node_modules/dsh-pet-plugin && node --test tests/host.test.mjs
node <dsh-plugin-guide>/bin/dsh-plugin-dev.js check --cwd . --strict
node <dsh-plugin-guide>/bin/dsh-plugin-dev.js verify --cwd .
自定义
- 客户端 bundle 是生成出来的:改 src/.js,再运行 node build.mjs,它会把各部分拼成 client.js(DSH 唯一加载的文件)。绝不要直接编辑手动改 client.js —— npm test 会先重新构建,再跑冒烟测试。
- 角色、台词和脾气:pets/<id>/pack.json —— images(五种表情)、actions(dance / hair / walk,每个 3–6 帧)、voice、temper,以及 lines / linesEn 台词包。
- UI 文案:改 locale/.json 里的 pet 命名空间,然后跑 node build.mjs —— 字典在构建时注入,所以 locale 文件是唯一事实来源。新增语言:先跑 node tools/gen-locales.cjs 生成骨架,再翻译。
- 情绪和动画:在 src/70-style.js 里加关键帧,在 src/96-overlay.js 里按 mood 映射 class。
- 动作片段:资源包可以带 clips: { dance: "pet-x-dance.webm" } —— 一段带 alpha 通道的 VP9 WebM。片段高度分档(1.25.0):舞台片段 960(从 2K 母版单代重新导出,供 4K 显示器上放大的 dance 用),四个原版的 hair/walk 768(从 768 母版原生导出),其余 640;普通片段约 5.167s,舞台片段约 10.125s。tools/assets-manifest.cjs 记录尺寸、时长、编码、像素格式、alpha 模式、字节大小和 SHA-256;资源测试会校验这些值,并限制总量不超过 20 MB。播放该动作时,宠物渲染一个循环 ,不再逐帧翻静态图 —— 这是拿到真正 24 fps 动态的唯一办法。
- 美术资源:把透明 WebP 丢进 assets/,在 pets/<id>/pack.json 里引用,然后跑 node build.mjs(它会重新生成 src/30-personas.js)。/dsh-pet/assets/ 路由只提供白名单内的图片和 webm 视频扩展名。
运行时扩展(1.21.0)
- 不重新构建也能加自定义角色包:把 $DSH_HOME/dsh-pet/pets/<id>/pack.json 放进去(资源放在旁边;license 是内置资源包的发布门槛 —— 用户资源包在运行时不做 license 检查)—— 宿主启动时扫描它,与内置的五个合并,并通过 /dsh-pet/pets/<id>/… 提供(realpath 包含校验 + 扩展名白名单 + 413 超限)。资源包必须满足渲染契约,否则在加载时整体拒绝(fail-closed,宿主日志里一条警告):name + clips、image(SVG 角色则需完整的 colors 表),以及 —— 当存在 voice / temper 时 —— voice.pitch / voice.rate 为有限数值、temper 为 mood → 正数。客户端通过 GET /dsh-pet/personas 拉取列表,取不到时回退到内置表。
- 台词覆盖:$DSH_HOME/dsh-pet/voice.json ——
{"<personaId>|": {"lines|linesEn|linesEs|linesPt|linesHi": {"<mood>": ["…≤300 chars, ≤200 lines"]}}}。
按情绪合并,任何格式错误的部分都警告并丢弃;文件损坏则忽略并警告,绝不崩溃。
- 让宠物说话:POST /dsh-pet/announce {"text": "…"}(≤300 字符,限速 30 次/分)。轮询 /dsh-pet/ping 获取 phase(working|tool|review|done,15s 新鲜度)和 announce(seq 守卫)——智能体工作时,phase 驱动走路、理毛等微动作。
- 宿主侧状态:GET/POST /dsh-pet/state。两端都带 updatedAt(最新者胜出,所以旧的宿主快照永远无法回滚本地的新改动);每次设置或历史变更后,客户端会防抖 500 ms 再 POST。历史存为 {role, content} 对象——旧的 "[object Object]" 字符串会被丢弃并迁移,而不是写回。设置键在宿主侧有白名单(≤64 项,历史 ≤200 条 × 8000 字符)。
- 静默自动闲聊:设置 statusBubbles: "auto" | "off" 可关闭心情、问候、空闲气泡;点击、拖拽和 announce 仍会说话。
- 许可:每个资源包都声明 license;第三方声明放在 THIRD_PARTY_NOTICES.md;资源测试对两者都做强制校验。
安全模型
- 宿主路由有三重门禁,都不绑定固定端口或域名:Host 必须是回环地址、宿主自身的 origin,或列在 allowedHosts 插件配置里(用于反向代理 / 局域网部署);请求带 Origin 时,必须与该 Host 同源,或为桌面外壳(dsh-app://app、dsh-app://shell);请求带 Sec-Fetch-Site 时,必须是 same-origin 或 none。三者都不发的非浏览器客户端会被放行——这是本地 HTTP 端点的有意限制,见下文。
- 语音合成是 POST 端点,返回音频字节;没有可喂给 的 GET URL,所以页面(或其他本地进程)无法通过把元素指向它来让宿主合成任何内容。
- 合成语音缓存在系统临时目录,带大小上限,每次合成后都会重新检查;写入走随机临时名 + rename,预先埋好的符号链接无法把写入重定向到别处。
- 页面发来的任何内容(设置、聊天历史、persona id)都当作数据处理:校验、限制长度,绝不作为指令或标记插值。
- 神经语音会把朗读文本发到 Microsoft 的 edge-tts 端点。关掉它(或干脆不安装 edge-tts)即可保持全本地;面板上会说明这一点。
已知限制
- 宿主版本:基于 dsh 0.2.1-alpha.2 构建并测试。它需要 webServer 服务和 shell.overlay / conversation.input.right 插槽,这些是 0.2 代 API——在 0.1.x 宿主上能安装但永远不会挂载(控制台会有一行提示)。package.json 里的 engines.dsh 只是声明:安装器不强制执行,插件也刻意不声明 @deepseek-ai/dsh-* 的 peer 范围,所以版本不匹配永远不会阻止安装。
- 神经语音需要宿主 python 装有 edge_tts;否则使用系统 SAPI 语音。
- 浏览器在首次用户手势前会阻止自动播放——点一下页面即可。
- 设置存在 localStorage。调试句柄(globalThis.__dshPet)默认关闭,除非在 localStorage 里设置 dsh-pet.debug=1,或者追加 ?petdebug=1。
- 宠物无法浮在其他应用之上(仅限 overlay 槽位)。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
zuoyunlai/dsh-pet-plugin
一个小伙伴,住在 DSH web UI…
相关插件 · 视觉能力
智能体工作台Devin-AXIS/iPolloWork
企业级、本地优先的智能体工作台,面向个人和智能体团队——一个工作区,容纳多个智能体引擎;一套统一体系,管理插件和技能;支…
★ 7,359已汉化DSH
72
开源设计工作台nexu-io/open-design
OpenDesign:首个协作式 AI 设计智能体工作区
★ 105,514已汉化DSH
71.8
多智能体编码工作区spacering-net/codeg
多智能体协作的 AI 编程工作区:汇总 Claude Code、Codex、OpenCode、Pi、Grok Build 等来源的会话。支持桌面应用、自托管服务器或 Docker。
★ 4,289已汉化DSH
71.6
GPT 图像提示词库freestylefly/awesome-gpt-image-2
Prompt as Code | GPT Image 2 / 2.5 提示词与案例库,530+ 个案例、20+…
★ 34,534已汉化DSH
71.5
架构图生成器tt-a1i/archify
把你想理解、规划或分享的事,变成可以互动的可视化作品。
★ 92,675已汉化DSH
71.2
AI 用量桌面小部件Javis603/token-monitor
EN | 简 | 繁 | KO | JA | PT
★ 3,522已汉化DSH
71
这是你的仓库?认领条目