zhu1090093659/dsh-web-ui--packages-dsh-pet3.6k

@linxin666/dsh-pet

DSH 网页 GUI 的多宠物陪伴插件:注册表驱动的悬浮宠物,可对模型活动做出反应,支持命名、抚摸/喂食互动及亲密度积分

AI 分析

在 DSH 网页界面右下角添加互动桌面宠物。适合希望在等待模型思考时进行趣味互动、提升使用体验的用户。

套件
@linxin666/dsh-pet
版本
0.1.19
授權
Apache-2.0
最近更新
2026年8月17日

安裝

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:zhu1090093659/dsh-web-ui#aeaaca8692376f442a1761e56273c574027ce96d&path:packages/dsh-pet

dsh-pet — Multi-pet companion plugin

English | 中文

A registry-driven desktop companion for DeepSeek Harness — the built-in whale girl plus any pet you drop in.

While the model thinks, you wait — your pet swims. It follows official session activity and switches animations while waiting, thinking, using tools, composing a reply, celebrating completion, or reporting failure; you can also pat its head, feed it dried fish, and watch its affinity grow. Pets are registry entries, not code: every pet is one pet.json manifest plus one atlas image, and the host discovers them at startup.

Re-implemented from the pet feature of the Codex desktop app, as an official DSH plugin shape (cordis bundle: host half + client half in one package).

Features

FeatureDescription
Multi-pet registryThe host scans built-in assets/, the hatch-pet custom pets directory, and composed config entries; each pet is a manifest plus an atlas
Pet selection in settingsThe plugin settings card lists every registered pet; switching persists and the sprite swaps immediately
Per-pet namingRename from the hover panel; each pet keeps its own name (stored per pet id, migrated from the legacy flat name)
State animationOfficial session activity → 9-state animation: thinking → running, tool → running-right, review → review, waiting → waiting, done → jumping, failed → failed
Head-pat interactionClick the pet → bubble feedback + affinity +1 (10s cooldown)
FeedingHover panel 喂食 (Feed) → consumes 1 dried fish + affinity +5 (30s cooldown)
Treat economyDried-fish stock (cap 20): +1 every 30 rounds of work, +1 every 300 minutes (5 hours) — 10x rarer than the original cadence
Affinity+1 per round completed; 9 levels: 幼鲸 → 伙伴 → 挚友 → 深海羁绊 → 心有灵犀 → 传说羁绊 → 神话羁绊 → 永恒之契 → 鲸生共渡 (capped at 999,999,999)
DraggingHold and drag the pet to reposition; position persisted
Hide/SummonHover panel 隐藏 (Hide); after hiding, a 召唤{name} (Summon {name}) button appears
Witty remarksBuilt-in remark library (10 lines per event) plus per-pet custom lines from a manifest remarks block — community PRs give their pet its own voice
Status bubblesEach concurrently active top-level session gets its own bubble, stacked above the pet (up to 12); subagent sessions report through their spawning conversation and never occupy a bubble of their own; click a bubble to jump to its session; transient interaction feedback temporarily takes priority
Multi-session activityThe pet is host-global: the most recent meaningful event drives the sprite animation while every active top-level session reports its own state in a separate bubble; completed turns from every session (subagents included) contribute affinity and treats

Pet contract

A pet is a directory holding one pet.json manifest and one atlas image. Nothing else is required — no host or client code changes.

{
  "id": "whale-girl",                     // unique lowercase kebab id
  "displayName": "鲸鱼娘",                 // shown in the settings selector and panel
  "description": "A soft healing whale-girl.", // optional
  "spritesheetPath": "spritesheet.webp",   // atlas, relative to the manifest
  "cell": { "width": 192, "height": 208 }, // optional; defaults to the Codex contract
  "columns": 8,                            // optional; default 8
  "frames": [6, 8, 8, 4, 5, 8, 6, 6, 6],   // optional per-row frame counts
  "tracks": {                              // optional per-track rhythm overrides
    "idle": { "durations": [400, 400, 500, 400, 400, 500] }
  },
  "remarks": {                             // optional witty remarks (one line or a pool per slot)
    "pet": "摸摸水獭的头~",
    "feed": ["小鱼干真香", "再来一条~"]
  }
}
  • The atlas is an 8-column × 9-row grid (192×208 cells by default); rows are fixed in this order: 0 idle, 1 running-right, 2 running-left, 3 waving, 4 jumping, 5 failed, 6 waiting, 7 running, 8 review. Unused cells stay fully transparent.
  • The optional remarks block overrides the reaction bubbles the pet speaks on pet / petCooldown / feed / feedCooldown / noTreats events. Each slot accepts one line or a pool of lines (cycled round-robin); a declared slot replaces the built-in pool for that slot only. This is how community contributions give their pet its own witty voice.
  • frames counts the used columns per row (defaults to the hatch-pet contract table [6, 8, 8, 4, 5, 8, 6, 6, 6]); tracks overrides per-frame durations (cycled to the row's frame count), loop, and fallback per animation (defaults: everything loops; jumping and failed hold their last frame, then fall back to idle).

Where pets come from (later sources override earlier ones on id collision):

  1. Built-in: assets//pet.json in this package.
  2. Custom pets: ${CODEX_HOME:-~/.codex}/pets/ /pet.json — the hatch-pet pipeline stages its output there, so a hatched pet appears in the selector with no further wiring.
  3. Composed: PetConfig.pets manifest entries passed to the plugin by the embedding application.

The registry is built once at host startup; add or change a pet, then restart dsh web.

Animation preview

The sprites are an 8-column × 9-row atlas (192×208 cells) generated by the hatch-pet pipeline; below are previews of each state:

idlewaitingrunningjumping
idlewaitingrunningjumping
wavingreviewfailedmove left/right
wavingreviewfailedrunning-left running-right

Architecture

dsh-pet/
|-- src/
|   |-- index.ts             # host half: plugin entry (registry build, settings section, routes)
|   |-- registry.ts          # multi-pet contract: manifest scan + normalization (assets + custom pets)
|   |-- service.ts           # PetService: pet selection + state machine + affinity + config
|   |-- state.ts             # pet state machine: projected session activity → 9 state animations
|   |-- remarks.ts           # witty-remark library: built-in pools + per-pet overrides + picker
|   |-- affinity.ts          # affinity ledger (pure functions + cooldowns)
|   |-- treats.ts            # dried-fish stock ledger
|   |-- persist.ts           # persistence ($DSH_HOME/pet.json: selection + per-pet names, atomic write)
|   |-- routes.ts            # /api/pet/* JSON API + /pet//* asset routes
|   `-- client/             # browser half
|       |-- index.ts         # global mount (createRoot → body) + registry fetch + polling + wiring
|       |-- PetDockEntry.tsx # global floating entry (document.body, always shown)
|       |-- PetSprite.tsx    # definition-driven floating sprite (portal + rAF + dragging)
|       |-- PetSettingsCard.tsx # settings card: pet selector + display layout
|       |-- spritesheet.ts   # atlas geometry helpers + track trimming
|       `-- pet.module.css
|-- assets/whale/            # built-in whale-girl (pet.json + spritesheet.webp + previews)
`-- cordis.patch.yml         # bundle patch: inserts the pet plugin row

Data flow

official session events (turn/step/chunk/tool) ----\
                                                    > PetService (host) /` — the plugin self-sufficiently provides its own API and assets (the same pattern as dsh-remote-web-ui's `/api/pair`).

## Install

Install the family aggregate package `@linxin666/dsh-web-ui-all` (all plugins and skins in one) or this plugin alone:

```sh
### From npm (recommended)
dsh plugin --profile web add @linxin666/dsh-pet

### From the repository (development)
git clone https://github.com/zhu1090093659/dsh-web-ui.git
cd dsh-web-ui
pnpm install && pnpm -r build
dsh plugin --profile web add link:$(pwd)/packages/dsh-pet

After installing, restart dsh web — your selected pet appears at the bottom-right of the interface. In link mode, pnpm build and refresh the page after a code change; no reinstall needed.

Development

pnpm build        # tsc -b (types+declarations) && tsdown (node half + browser bundle)
pnpm test         # vitest unit/component tests (registry / event projection / state / UI / ledgers)
pnpm prepare      # transpile-only build (no type checking, for consumer installs)
pnpm typecheck    # type check only

The browser bundle rides the window.__ModuleLoader__.load contract; React/cordis and so on resolve from the loader's module table (external); CSS Modules are inlined by lightningcss as ``.

Sprites and animation-track calibration

The built-in whale-girl atlas is generated by the hatch-pet pipeline as 9 states × 8 columns: assets/whale/spritesheet.webp (1536×1872, 8 columns × 9 rows of 192×208 cells) + assets/whale/pet.json. The frame count and rhythm of each row live in that manifest's frames and tracks fields — the whale girl carries its own slower healing durations, while pets without overrides follow the hatch-pet contract rhythm. Redoing artwork therefore only edits assets/whale/pet.json (row-order contract: 0 idle / 1 running-right / 2 running-left / 3 waving / 4 jumping / 5 failed / 6 waiting / 7 running / 8 review).

License

BSD-3-Clause