npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@neystan/dsh-pet

v0.1.16

Published

鲸鱼娘宠物插件 for the dsh web GUI: a soft healing whale-girl companion with model-activity animations, petting/feeding interactions, shared affinity, and one validated custom-pet import slot

Readme

dsh-pet — Whale-girl pet plugin

English | 中文

A soft, healing whale-girl who works alongside you in DeepSeek Harness.

While the model thinks, you wait — she swims. She follows official session activity and switches animations while waiting, thinking, using tools, composing a reply, celebrating completion, or reporting failure; you can also pat her head, feed her dried fish, and watch her grow from a baby whale into your deep-sea bond.

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

| Feature | Description | |---|---| | State animation | Official session activity → whale-girl animation: thinking → running, tool → running-right, review → review, waiting → waiting, done → jumping, failed → failed | | Head-pat interaction | Click the whale-girl → bubble feedback + affinity +1 (10s cooldown) | | Feeding | Hover panel "喂食" (Feed) → consumes 1 dried fish + affinity +5 (30s cooldown) | | Treat economy | Dried-fish stock (cap 20): +1 every 3 rounds of work, +1 every 30 minutes; when low it prompts "多陪鲸鱼娘工作一会儿" (Work with the whale-girl a bit more) | | Affinity | +1 per round completed; 4 levels: 幼鲸 (baby whale) → 伙伴 (companion) → 挚友 (close friend) → 深海羁绊 (deep-sea bond, capped at 100) | | Custom naming | Hover panel "改名" (Rename) → 1–20 characters, persisted, echoed in the summon button/panel | | Dragging | Hold and drag the whale-girl to reposition; position persisted | | Hide/Summon | Hover panel "隐藏" (Hide); after hiding, a "召唤{name}" (Summon {name}) button appears in the input selector row | | Status bubble | Shows the current session stage or tool name; transient interaction feedback temporarily takes priority | | Multi-session activity | The pet is host-global: the most recent meaningful event controls its display, while completed turns from every session contribute affinity and treats | | Custom pet | Select pet.json and spritesheet.webp separately in Settings, validate and preview a candidate, then switch without a page refresh; the official and custom cards share the name, affinity, treats, size, and position |

Custom pet (MVP)

Settings → Pet → Pet appearance shows the official whale girl and one custom-pet card. The custom pair must use the existing asset contract:

  • pet.json: id, displayName, description, spritesheetPath: "spritesheet.webp", and fixed frame counts [6, 8, 8, 4, 5, 8, 6, 6, 6].
  • spritesheet.webp: transparent WebP, 1536×1872, 8 columns × 9 rows, 192×208 cells; rows are idle, running-right, running-left, waving, jumping, failed, waiting, running, review.

Choose the two files separately. The browser checks dimensions, transparent pixels, valid frames, and empty tail cells. Import creates a “Pending apply” preview; “Use selected pet” performs the switch without refreshing the page. Custom files live in the single current/candidate layout under $DSH_HOME/pet/custom. Switching back to the official pet or deleting custom files keeps the shared progression data.

Use “Copy generation prompt” to give an Agent the prompt together with one clear, full-body, unobstructed pet reference image. The prompt uses only the repository-relative template path packages/dsh-pet/assets/whale and asks for exactly pet.json and spritesheet.webp. The first version does not call AI, convert still images, accept archives, or manage multiple custom pets.

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:

| idle | waiting | running | jumping | |---|---|---|---| | idle | waiting | running | jumping |

| waving | review | failed | move left/right | |---|---|---|---| | waving | review | failed | running-left running-right |

Architecture

dsh-pet/
|-- src/
|   |-- index.ts        # host half: plugin entry (cordis apply, route registration)
|   |-- service.ts      # PetService: pet state machine + affinity + config (HTTP API service face)
|   |-- state.ts        # pet state machine: projected session activity → 9 state animations
|   |-- affinity.ts     # affinity ledger (pure functions + cooldowns)
|   |-- treats.ts       # dried-fish stock ledger
|   |-- persist.ts      # persistence ($DSH_HOME/pet.json, atomic write)
|   |-- routes.ts       # /api/pet/* JSON API + /pet/whale/* static asset routes
|   `-- client/         # browser half
|       |-- index.ts    # global mount (createRoot → body) + polling (800ms) + interaction wiring (fetch)
|       |-- PetDockEntry.tsx  # global floating entry (document.body, always shown: no session / new session / mid-session)
|       |-- WhalePet.tsx      # floating component (portal + rAF frame animation + dragging)
|       |-- spritesheet.ts    # atlas geometry + per-state animation tracks (frames/duration)
|       `-- pet.module.css
|-- assets/whale/       # whale-girl assets (pet.json + spritesheet.webp + animation previews)
`-- cordis.patch.yml    # bundle patch: inserts the pet plugin row

Data flow

official session events (turn/step/chunk/tool) ----\
                                                    > PetService (host)
optional legacy activity/status ------------------/
                                                              | /api/pet/* JSON
global React root (createRoot → document.body) <-- polling 800ms -- pet-client (browser)
                                                              |
                                                   WhalePet floating layer (portal + rAF)
  • Status source: the host projects official turn/start, step/start, assistant/chunk, assistant/message, tool/call, tool/result, and turn/end events into waiting/thinking/tool/review/done/failed states. Optional legacy activity/status events remain a compatibility input.
  • Multi-session semantics: the API and browser mount are host-global and expose no foreground-session identity, so the most recent meaningful event wins the display. Every session's completed turns are still rewarded independently, and disposing a non-current session does not reset the visible state.
  • Mount point: document.body (global React root, always shown: no session / new session / mid-session — the old mount point conversation.composer.dock only rendered in an active session, hiding the pet in new sessions); the component uses createPortal internally to render the global floating layer.
  • Rendering: CSS sprite (background-position) per-frame animation, frame durations from the track definitions in spritesheet.ts.
  • Communication: browser ↔ host over the same-origin /api/pet/* JSON endpoints (state/interact/set-visible/set-config); the atlas loads from /pet/whale/spritesheet.webp — both the RPC domain and the /plugins/ static service are platform-registered, and the plugin self-sufficiently provides its own API and assets (the same pattern as the family RPC domains).

Install

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

### Install from npm (recommended)
dsh plugin --profile web add @neystan/dsh-pet

### 从仓库安装(开发调试)
git clone https://github.com/neystan/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 — the whale-girl 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 (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 <style data-plugin>.

Sprites and animation-track calibration

The 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 actual frame count and rhythm of each row are defined in TRACKS in src/client/spritesheet.ts. If the artwork is redone and the frame count changes, only that table needs updating (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