dsh-pet
PC2005-cloud/dsh-petDSH Web UI 桌面宠物,Windows / macOS / Linux 三端可用:浏览器浮层或透明置顶桌面窗口,106 个透明动画、带挤压与粒子的甩抛反弹物理、随会话事件实时联动的工作状态气泡、碎碎念与带持久记忆的对话、余额展示、表情包配图、多开同屏,并支持直接放入的自定义动画与宠物种类(pet pack)。
成就与游戏化插件:按回合、工具调用、会话、连续天数与编码行为(编辑/读取/测试)解锁徽章,带徽章墙、解锁 toast 与 ctx.achievements SDK。
A gamification layer for DeepSeek Harness (DSH): 102 achievements across seven five-tier growth lines, session behavior badges, trajectory chains and a Harness-native layer (Token / Context, Code Mode, Compaction, Workspace) — with real-time unlock toasts, a badge wall in the settings page, shareable cards, Agent Wrapped and a public SDK for third-party packs. Zero core changes.
| Achievements panel: profile card, rarity stats, lifetime counters and the grouped badge wall | Expanded cards: icon, rarity, description, progress, XP and unlock timestamp |
|---|---|
common → uncommon → rare → epic → legendary), 10 session behavior badges, 20 session trajectory achievements across four extra chains (one of them fully hidden), and 34 Harness-native achievements (Token / Context, Code Mode, Compaction, Workspace). Every unlock earns XP, raises your level and persona, and is timestamped on the badge wall.session/event seam: turn/end, step/start, assistant/message, step/end, tool/call, tool/result, Code Mode's tool/code-dispatch-start / tool/code-dispatch, compaction/summary, plus the read-only workspaceRegistry projection. All read-only signals; no core patches, no forks of the runtime.profile + per-session buckets) persists as a JSON file in the DSH home directory; v1 states migrate losslessly. Lifetime counters live on the profile and never depend on the 64-session retention window, with a conservative lower-bound backfill on upgrade; already-satisfied milestones are silently reconciled at startup (no reducer, no session attribution, no broadcast).step/start, assistant/message, step/end, settled tool calls); per-token chunks are never consumed or persisted.<details> (trajectory/timing, token/context, tools/files, Code Mode/compaction). A recent-session history (last 10, touch order) and 10 lifetime personal records (profile.sessionRecords, independent of the 64-session retention window) complete the picture.sessionId / path / command.ctx.achievements.register / registerPack and share the exact same evaluation path as the built-ins; duplicate ids throw immediately. Other client plugins read state through ctx.achievementsState.Achievements fall into two tracks. Each of the seven lifetime growth lines has five tiers, always common → uncommon → rare → epic → legendary (new-milestone XP: 10 / 30 / 75 / 175 / 400):
| Line | Common | Uncommon | Rare | Epic | Legendary | |---|---|---:|---:|---:|---:|---:| | 🎬 Turns | 1 | 25 | 50 | 100 | 500 | | 🔧 Tool calls | 1 | 25 | 100 | 500 | 2000 | | 💬 Sessions | 1 | 10 | 50 | 200 | 500 | | 🌅 Active days | 1 | 7 | 30 | 100 | 365 | | 📖 File reads | 10 | 100 | 500 | 2500 | 10000 | | ✏️ File edits | 1 | 10 | 50 | 250 | 1000 | | 🧪 Test runs | 1 | 10 | 50 | 250 | 1000 |
Special achievements — daily streaks (streak-3 / streak-7), the early ten-turns bonus, and ten per-session behavior badges:
| Achievement | Condition |
|---|---|
| 🔁 Déjà Vu | edit the same file 5 times in one session |
| 🕳 Rabbit Hole | read 20 files before your first edit |
| 💣 YOLO | edit 8 files before your first test |
| 🔥 It Works Eventually | pass after 5 failed tests |
| 🎰 Surely This Time | same test command fails 5 times in a row |
| 🎯 One Shot | pass the first test after a single edit |
| 📚 Librarian | read 30 distinct files in one session |
| 🌱 Touch Grass | 100 tool calls in one session |
| 🦴 Dependency Archaeologist | read a file inside a dependency directory |
| 🗿 Gigachad | read, edit and pass a test within 5 tool calls |
P7 trajectory chains (20 achievements, rarity strictly common → uncommon → rare → epic → legendary, XP 10 / 20 / 40 / 70 / 120). They read only low-frequency boundaries and never persist per-token chunks:
| Chain | Metric | Five thresholds |
|---|---|---|
| 💬 Session Marathon | distinct closed-step turns in one session | 5 / 20 / 50 / 100 / 200 |
| 🪜 Turn Depth | closed steps within a single turn | 5 / 20 / 50 / 100 / 500 |
| 🔧 Tool Barrage | settled tool calls within a single step (incl. Code Mode sub-calls) | 5 / 10 / 25 / 50 / 100 |
| ⏳ Time Anomaly | single model-request think duration (step/start → assistant/message, hidden) | 30s / 100s / 300s / 500s / 1000s |
P8 Harness-native (34 achievements) — facts that only exist inside DeepSeek Harness. Token / Context and Code Mode are session-scoped; Workspace is lifetime. max-tokens-hit and context-pressure-* stay hidden + low XP on purpose (no badge for wasting tokens):
| Group | Chains | Thresholds |
|---|---|---|
| 🧠 Token / Context | Reasoning Depth · Cache Reuse · Context Pressure (hidden) · Hit the Ceiling (hidden) | 4096/8192/16384 · 8192/32768/65536 · 70%/90% · 1 turn |
| 👯 Code Mode | Parallelism · Dispatch Marathon | 2/4/8/10 · 5/10/25/50/100 |
| 🧹 Compaction | Memory Maintenance · Compression Scale · Manual Housekeeping | 1/3/5 · 20k/50k tokens · 1 manual |
| 🏠 Workspace | Workspace Explorer · Project History | 1/3/5/10/20 · 5/10/25/50/100 sessions |
DSH session/event (turn/end, step/start, assistant/message, step/end, tool/call, tool/result,
tool/code-dispatch-start, tool/code-dispatch, compaction/summary) + workspaceRegistry
→ src/events.ts classifier — raw payload → standardized AchievementEvent + ToolSummary
→ src/reducer.ts reducer — pure reduceState: profile + per-session behavior + P7/P8 facts
→ src/achievements.ts evaluate — applyEvent: buildContext + evaluate every still-locked def
→ src/index.ts Host — persist JSON → SSE push (unlock) + read-only HTTP API; startup reconcile
→ src/client/ Browser — EventSource + 30s polling → badge panel + unlock toasts
The three layers are fully decoupled and independently unit-tested; the rules layer never reads raw Harness tool payloads. The browser bundle can only import modules that are safe for it (a purity gate in tsdown.config.ts blocks any node:* import from leaking in).
Prereqs: DSH (dsh web works), Node ≥ 22.19.
# From GitHub (prebuilt lib/ is committed, no allowBuilds needed)
dsh plugin --profile web add "github:luumod/dsh-achievements#main"
# From a local checkout (npm pack is the reliable path on Windows; avoid `link:`)
cd dsh-achievements && npm install --legacy-peer-deps && npm run build
npm pack --ignore-scripts
dsh plugin --profile web add "<absolute path to>\dsh-achievements-0.1.0.tgz"
Restart dsh web after installing, then just use it — the first completed turn unlocks the first achievement (all counting rides the official event seam, so simply chatting works).
assets/unlock.m4a) — overwrite that file to use your own.??? until unlocked;<details> (trajectory/timing, Token/Context, tools/files, Code Mode/Compaction), plus a collapsible 🏅 Personal Records list and the 📚 recent-session history (last 10, touch order);ctx.achievements SDKRegister your own achievements from a Host plugin — built-ins and third-party packs share one evaluation path and one registry (duplicate ids throw):
export const inject = ['achievements']
export function apply(ctx: Context): void {
ctx.achievements.register({
id: 'python-first-run',
icon: '🐍',
title: { zh: '蟒蛇出洞', en: 'First Python Run' },
description: { zh: '首次运行 Python', en: 'Run Python for the first time' },
rarity: 'uncommon',
xp: 20,
scope: 'session',
evaluate: ctx => ({ unlocked: ctx.session.toolCalls >= 1 }),
})
}
Or register a whole pack: ctx.achievements.registerPack({ id, version, name, achievements }). Registrations reconcile immediately, so an already-satisfied lifetime pack unlocks without waiting for the next live event. See docs/SDK.md for the full guide and examples/python-pack.ts for a runnable pack.
On the browser side, other client plugins read state via ctx.achievementsState.refresh() / ctx.achievementsState.unlockedIds().
npm install --legacy-peer-deps
$env:DSH_NODE_MODULES = "$env:USERPROFILE\.dsh\profiles\node_modules" # PowerShell; local runtime symlinks
npm run setup:dsh-workspace
npm run verify # ★ one-shot gate: clean + typecheck + test + build (incl. the browser purity gate)
npm test # vitest — 23 files / 373 tests (engine rules, streaks, idempotency, SDK, manifest…)
Note: if
npm run buildfails withFailed to import module "unrun", runnpm install --no-save unrunonce (tsdown optional peer, Node ≥ 22.19 recommended).
dsh-achievements/
├── package.json # dual contract: dsh.bundle.patch + dsh.client
├── cordis.patch.yml # bundle patch layer
├── tsdown.config.ts # client bundle + browser purity gate
├── scripts/ # build / clean / setup-dsh-workspace / verify
├── docs/SDK.md # third-party authoring guide
├── examples/python-pack.ts # runnable sample pack
├── src/
│ ├── index.ts # Host half: event wiring, registry, persistence, HTTP + SSE, SDK
│ ├── events.ts # ★ event classifier (standard AchievementEvent + ToolSummary)
│ ├── reducer.ts # ★ pure reducer (reduceState / buildContext)
│ ├── achievements.ts # ★ pure engine (applyEvent) + domain model + 102 built-ins
│ ├── state.ts # State v2 (profile + sessions), migration, JSON persistence
│ ├── sdk.ts # createAchievementRegistry + AchievementPack
│ ├── code-mode-tracker.ts # Host transient Code Mode run tracker (never persisted)
│ ├── workspace-facts.ts # workspace snapshot projection + order-insensitive fingerprint
│ ├── gamification.ts # levelOf / xpForLevel / RARITY_META (browser-safe)
│ ├── profile.ts # Profile ViewModel + persona + rarity summary (browser-safe)
│ ├── session-report.ts # Session Report V2 + highlights + personal records (browser-safe)
│ ├── share.ts # share cards / Agent Wrapped / chains (browser-safe, privacy-safe)
│ ├── api.ts # API path constants + SSE frame format (browser-safe)
│ └── client/ # Browser half
│ ├── index.ts # apply: ctx.achievementsState + polling + SSE + slot injection
│ ├── achievements-client.ts # state HTTP client
│ ├── badge-panel.tsx # badge wall (settings.section), grouped from the chain model
│ ├── badge-panel-model.ts # chain-derived grouping + status filter (pure)
│ ├── session-report-panel.tsx # Session Report V2 / history / personal records panel
│ ├── toast.ts # unlock toast (zero-dependency DOM)
│ └── unlock-tracker.ts # toast baseline dedup (pure)
└── tests/ # 23 spec files: classifier / reducer / evaluate / state / SDK / chains / session-report…
dsh-soundscape — Host drives a pure engine off the official event seams; the browser half is a client plugin (settings.section + state polling).ctx.effect registrations. A fork of Blaczz/dsh-achievements, extended with behavior + trajectory achievements, the SDK and the sharing layer.MIT © 2026 Blaczz (upstream). An independent community plugin, not affiliated with DeepSeek Harness.