DeepSeek Harness 插件

dsh-pet-fetwtgra

A Codex/Shimeji-style desktop pet for DeepSeek Harness: a transparent, always-on-top, draggable companion that reacts to dsh's live work state.(英文原文)

跳到安装方式

来源信息

GitHub 仓库
fetwtgrah/dsh-pet
最近更新
2026年8月15日
分类
趣味扩展
GitHub stars
0
载体类型
plugin
目录证据
上游声明已找到 dsh.bundle
证据路径
package.json#dsh.bundle
核对版本
0.1.0-rc.8
上游核对日期
2026-08-20

该证据由上游目录提供。本站没有安装、运行或安全审核这个插件。

安装

默认先复制一段 Prompt,让 Agent 读 GitHub 仓库和源码;需要自己装时再切到命令。

复制这段 Prompt,发给 DSH、Codex 或其他 Agent,让它先读 GitHub 仓库和源码。

请先不要安装或执行任何命令。阅读这个插件的 GitHub 仓库、README 和关键源码,然后用清楚、直接的方式回答以下问题,帮助我判断它是否适合我的需求:

1. 这个插件是什么,解决什么问题;
2. 适合哪些用户和典型使用场景;
3. 安装后如何使用,并给出一个最小使用示例;
4. 有哪些已知限制,以及隐私、安全、兼容性或维护风险;
5. 给出“推荐 / 有条件推荐 / 不推荐”的明确建议和理由。

请区分仓库明确说明、根据源码推断和未知信息。证据不足时请明确说明,不要猜测或照抄 README。

GitHub:https://github.com/fetwtgrah/dsh-pet
插件名:dsh-pet-fetwtgra
作者:fetwtgrah

检查来源文件

安装前先看这个插件目录里的 README 和其他文件。

文件资源管理器3 个文件
README.md来源说明 · 只读预览

dsh-pet

一个 DeepSeek Harness桌面宠物 插件(Codex / Shimeji 风格):一个透明、置顶、可拖拽的小家伙,实时感知 dsh 的工作状态并切换动作与表情,让枯燥的终端 agent 变得有「陪伴感」。

  • 待机 idle —— 待在角落呼吸、偶尔眨眼/伸懒腰。
  • 忙碌 busy 及子状态 —— dsh 在跑工具调用时,按工具类型切换具体动作(读文件/写代码/跑命令/联网搜索/卡住/排队)。
  • 开心 happy —— 任务成功完成。
  • 沮丧 sad —— 出错/失败,弹一句简短错误摘要(不是完整堆栈)。
  • 打盹 sleep —— 长时间无活动自动入睡。

宠物是独立 Electron 进程detached 拉起),dsh 主机退出后它仍继续存活,直到你手动关闭——这是「陪伴感」的重点。

目录

  • [安装](#安装)
  • [使用](#使用)
  • [内置皮肤](#内置皮肤)
  • [皮肤格式](#皮肤格式)
  • [台词池](#台词池)
  • [busy 子状态与工具映射](#busy-子状态与工具映射)
  • [配置](#配置)
  • [架构](#架构)
  • [开发](#开发)
  • [常见问题](#常见问题)

安装

dsh plugin --profile web add <dsh-pet 的绝对路径>
# 或在本目录下:
dsh plugin --profile web add .

dsh plugin add 会转发给 profile 目录下的 pnpm,并自动把本插件(声明了 dsh.bundle.patch)注册进 bundle 列表。若 profile 正在运行,需重启一次让它加载新 bundle。

一次性:给宠物窗口装 Electron

Electron 刻意放进插件根目录的依赖里,这样 dsh plugin add 保持轻量(只依赖 ws)。装一次 Electron:

cd <path/to/dsh-pet>/pet-process
pnpm install          # 下载 Electron

pnpm 可能会要求你用 pnpm approve-builds 批准 Electron 的 post-install(二进制下载)——这是本插件唯一的、预期内的审批。也可以用已有的 Electron:

# 在 profile 的 cordis.patch.yml 里针对 dsh-pet 这一行覆盖:
- id: dsh-pet
  config:
    electronPath: 'C:/path/to/electron.exe'
# 或设置环境变量 DSH_PET_ELECTRON

使用

插件在所有 dsh 界面(Web / TUI / headless)注册了一个人类命令 pet

/pet start [--skin <名字|路径>]    启动桌面宠物
/pet stop                          停止桌面宠物
/pet status                        查看宠物进程状态
/pet help                          查看帮助

--skin 支持裸名字(自动解析到 skins/ 目录下,如 pixel-v1pixel-human-v1default)或绝对路径。

说明:

  • start 幂等——若已有存活 pid 会提示「已在运行」而不是重复拉起。
  • stop 可靠地杀掉整个 Electron 进程树(Windows:taskkill /T /F;POSIX:SIGTERM→SIGKILL),并清除 pid 文件。
  • 宠物在 dsh 主机退出后继续存活。主机重启后需 /pet stop/pet start 重新挂载到新主机。

右键菜单

  • 对话气泡 —— 开关气泡。
  • 静音(不打扰) —— 关掉宠物所有「碎嘴」(俏皮话 + 场景台词);错误摘要仍会显示。
  • 切换皮肤 —— 在 skins/ 下所有皮肤之间切换。
  • 打开设置 —— 打开持久化设置 JSON(位置、皮肤、开关)。
  • 退出 —— 退出宠物。

点击(不拖动)宠物会随机触发一句 idle_click 俏皮话。

内置皮肤

皮肤类型说明
skins/defaultemoji 占位最早的兜底皮肤,零图片资源
skins/pixel-v1程序化像素史莱姆64×64、描边 + 分色块阴影 + 抖动过渡,代码生成
skins/pixel-human-v1程序化像素小人戴兜帽的小码农/法师,有独立手臂腿,代码生成

三套皮肤都对齐同一套 11 状态状态机(idle / busy / reading / writing / executing / searching / stuck / happy / sad / queued / sleep)。

重新生成像素皮肤(零外部美术依赖,纯 Node 内置 zlib 写 PNG):

node scripts/generate-skin.mjs           # 重新生成 skins/pixel-v1
node scripts/generate-human-skin.mjs     # 重新生成 skins/pixel-human-v1

每个皮肤目录里都有:

  • manifest.json —— 皮肤描述与各状态帧数/fps;
  • preview.png —— 每行标注状态名的彩色预览图;
  • *-comparison.png —— 黑白剪影对比图(轮廓辨识度核对用)。

皮肤格式

皮肤 = 一个文件夹,含 manifest.json(以及可选的 sprite sheet + lines.json):

{
  "name": "my-pixel-pet",
  "version": 1,
  "size": { "width": 64, "height": 64 },   // 单帧像素尺寸
  "scale": 2,                              // 窗口放大倍数(像素画用 image-rendering: pixelated)
  "anchor": { "x": 0.5, "y": 1.0 },        // 脚底居中锚点(信息性)
  "emoji": "🐣",                           // 某状态无 sheet 时的 emoji 兜底
  "fps": 4,                                // 默认播放速率
  "states": {
    "idle":      { "sheet": "idle.png",      "frames": 6, "fps": 2 },
    "busy":      { "sheet": "busy.png",      "frames": 6, "fps": 6 },
    "reading":   { "sheet": "reading.png",   "frames": 5, "fps": 4 },
    "writing":   { "sheet": "writing.png",   "frames": 6, "fps": 7 },
    "executing": { "sheet": "executing.png", "frames": 6, "fps": 6 },
    "searching": { "sheet": "searching.png", "frames": 5, "fps": 4 },
    "stuck":     { "sheet": "stuck.png",     "frames": 5, "fps": 3 },
    "happy":     { "sheet": "happy.png",     "frames": 6, "fps": 8 },
    "sad":       { "sheet": "sad.png",       "frames": 4, "fps": 3 },
    "queued":    { "sheet": "queued.png",    "frames": 4, "fps": 3 },
    "sleep":     { "sheet": "sleep.png",     "frames": 4, "fps": 1 }
  }
}
  • sheet 是相对皮肤目录的图片路径;帧水平排列,每帧 size.width × size.height;实际显示尺寸为 size × scale
  • 某状态没有 sheet(或图片缺失)时回退到 emoji + CSS 动画——default 皮肤就是这么零资源工作的。
  • 皮肤可自带 lines.json 覆盖台词池;否则使用 pet-process/renderer/lines.json

台词池

lines.json 是「场景 → 台词数组」的对象,每个触发点随机抽一句,纯装饰、不接 LLM:

场景触发时机
idle_click点击宠物
task_start任务开始(进入忙碌)
task_success任务成功(happy)
task_fail任务失败(sad,与错误摘要合并显示)
idle_too_long空闲约 60% 时长,每次空闲段触发一次
sleep_wake从 sleep 醒来
random_ambient空闲时每随机 3–8 分钟自动弹一句

旧的扁平字符串数组格式仍兼容,会被包成 idle_click

busy 子状态与工具映射

busy 被拆成子状态,映射到实际调用的工具。映射表在 tool-behavior-map.json(独立于代码,加/删工具名无需重新构建):

{
  "reading":   ["read", "read_image", "glob", "grep", "ssh_list"],
  "writing":   ["write", "edit", "str_replace_editor"],
  "executing": ["bash", "pwsh", "ssh_exec", "ssh_cluster", "ssh_upload", "ssh_download", "ssh_tunnel"],
  "searching": ["web_search", "web_fetch"]
}
子状态触发说明
reading读文件/搜索代码类工具翻书/扫视
writing写文件/编辑类工具打字
executingshell / ssh 类工具抡锤/举臂
searching联网搜索/抓取类工具举天线
stuck某工具调用超过 stuckThresholdMs(默认 20s)仍未返回抓头
busy未映射的陌生工具通用忙碌兜底
  • 宿主侧状态机用「在飞调用栈」跟踪:最新调用驱动当前子状态;顶调用超时则切 stuck,调用结束后回到 happy/sad。
  • queued 未接线:dsh 事件总线没有暴露工具调度队列长度,没有诚实的触发信号,所以不做伪造数据触发。queued 的 sprite sheet 已生成,等以后有队列信号即可启用。

配置

配置都在 dsh-pet 这一行(见 cordis.patch.yml),可在 profile 自己的 cordis.patch.yml 里按 id 覆盖:

key默认含义
idleTimeoutMs600000无活动多久后打盹
stuckThresholdMs20000工具调用超过该时长切 stuck
bubbleOnErrortrue失败时显示错误摘要气泡
electronPathElectron 二进制绝对路径
skin内置 skins/default默认皮肤目录

架构

dsh 主机(本插件)                            Electron 宠物(detached)
┌──────────────────────────────┐  WebSocket  ┌──────────────────────────────┐
│ src/index.ts  apply(ctx)      │(回环随机端口│ pet-process/main.js          │
│   ├─ /pet start|stop|status   │  + token)  │   ├─ 透明置顶窗口             │
│   ├─ tools/execute → busy 子状态│ ─────────► │   ├─ WS 客户端(断线重连)     │
│   ├─ tools/result  → happy/sad│            │   ├─ 原生右键菜单             │
│   ├─ jobs.onJobDone → happy/sad│            │   └─ 光标轮询式鼠标穿透/拖拽    │
│   └─ jobs.onJobsChanged → busy │            │ renderer/                    │
│ src/state.ts  情绪状态机(子状态+stuck)      │   ├─ skin-loader.js(精灵表)  │
│ src/ipc.ts    WS 服务端                    │   └─ pet.js(情绪/气泡/台词)    │
└──────────────────────────────┘            └──────────────────────────────┘

用到的状态信号(已对照实际发布的包核实,非臆测):

信号来源含义
tools/execute(waterfall)@deepseek-ai/dsh-tools工具开始 → 按工具名切 busy 子状态
tools/result(emit)@deepseek-ai/dsh-tools工具结束 → happy / sad
ctx.jobs.onJobDone@deepseek-ai/dsh-jobs后台 job 结束 → happy / sad
ctx.jobs.onJobsChanged@deepseek-ai/dsh-jobsjob 注册表变化 → 有界 busy 脉冲

进程生命周期:pid/port/token 记录在 $DSH_HOME/dsh-pet.json(缺省 ~/.dsh)。start 复用存活 pid;stop 杀掉记录的 pid 并清文件。Electron 窗口的位置/皮肤/开关存在它自己的 userData 目录。

开发

# 宿主侧:TypeScript 源码在 src/,发布入口是已编译的 lib/
pnpm install                          # 装 dev 依赖(typescript、@types/*)
pnpm build                            # tsc: src/*.ts -> lib/*.js
node scripts/smoke-lib.mjs            # 冒烟测试(状态机 + IPC + 接线,跑编译后的 lib)

# 像素皮肤(零依赖,纯 Node zlib PNG 编码器)
node scripts/generate-skin.mjs        # 重新生成 skins/pixel-v1
node scripts/generate-human-skin.mjs  # 重新生成 skins/pixel-human-v1
node scripts/generate-silhouette-comparison.mjs   # 史莱姆剪影对比(旧脚本)
node scripts/ascii-preview.mjs <state>            # 把生成的帧转成字符画核对
node scripts/frame-diff.mjs           # 逐帧像素差异,检查动画是否真的在动

# 宠物侧(需要 pet-process 里装好 Electron)
cd pet-process && pnpm start                        # 单独跑窗口
node scripts/pet-demo-substates.mjs --skin pixel-human-v1   # 演示全部 11 状态(--skin <名字>)
node scripts/pet-demo.mjs pixel-v1                  # 演示 5 种基础情绪(位置参数皮肤名)
node scripts/pet-boot-test.mjs pixel-v1             # 对 mock 宿主做启动/握手测试(位置参数皮肤名)
node scripts/pet-restart.mjs pixel-v1               # 原地重启真实宠物并切换皮肤(位置参数皮肤名)
node scripts/pet-observe.mjs                        # 直连宿主抓取真实状态帧(验证分类)

lib/ 已提交入库,是 dsh plugin add 实际加载的入口;只有改了 src/*.ts 才需要重新 pnpm build

常见问题

  • 装 Electron 卡在 approve-buildspnpm approve-builds 批准 electron,或改用 npm install(npm 默认执行 postinstall),或用 electronPath / DSH_PET_ELECTRON 指向已有 Electron。
  • 切皮肤后还是老样子:先 /pet stop/pet start --skin <名字>start 对已运行的宠物不会热切换。
  • 路径含中文/空格:皮肤路径会自动做 file:// 百分号编码,正常解析;--skin 用裸名字最省事。
  • 改了代码要生效src/*.ts 改完需 pnpm build 并重启 dsh 主机;pet-process/skins/ 改完只需重启宠物(pet-restart.mjs/pet stop + /pet start)。

License

[MIT](./LICENSE)