Saltar al contenido principal
H

codex-pet-Astra-Yao

hongxin-y/codex-pet-astra-yao

An Astra Yao desktop pet for the DeepSeek Harness web GUI that renders the Codex v2 8x11 sprite atlas, follows session state through thinking, running, waiting and failed, shows a status bubble with the running tool and a DeepSeek balance readout (on by default, can be switched off), and quotes her own voice lines while idle.

Instalar

dsh plugin --profile web add github:hongxin-y/codex-pet-astra-yao

README

Astra Yao · DSH 桌宠插件

把 Codex Pet: Astra Yao 的像素桌宠做成了 DeepSeek Harness(DSH)可以识别的插件:装进 profile 之后,Astra Yao 会以悬浮小人的形式待在 DSH Web 界面 右下角,跟着会话状态换动作——思考时翻谱、执行命令时小跑、等你确认时托腮等待、出错时躺平。

头顶还有一个状态气泡:写着当前状态、正在跑的工具、报错原文,可选显示 DeepSeek 账户余额和今日消耗。

  • 角色:深墨绿长发、红黑外套、白裙、金色环形麦克风立杖的舞台歌手像素小人
  • 素材:spritesheet.webp,1536×2288,Codex v2 atlas(8 列 × 11 行,单帧 192×208),透明背景
  • 形态:一个标准的 DSH 插件包(package.json 里的 dsh.bundle + dsh.client), 服务端一半负责会话状态与 HTTP 接口,浏览器一半负责把 sprite 画到页面上

两个身份

这个仓库同时是两样东西,互不干扰:

你是谁怎么用需要的文件
DSH 用户dsh plugin --profile desktop add <本仓库路径>(见下文「安装」)package.json、cordis.patch.yml、src/、lib/
Codex 用户把仓库里的 pet.json + spritesheet.webp 复制到 %USERPROFILE%\.codex\pets\astra-yao\(见 USAGE.md)仍然只有 pet.json + spritesheet.webp

Codex 只认这两个文件,所以 DSH 那套 package.json、src/、test/ 放在同一层不影响它; 反过来,DSH 的 sprite 也直接读根目录的 spritesheet.webp,没有第二份拷贝。

English: Astra Yao is a Codex v2 sprite-atlas pet for the DeepSeek Harness web GUI. One 1536×2288 atlas (8×11 frames of 192×208) drives nine animations; the server half follows session events, so the pet idles, thinks, runs while tools are working and waits on approvals. The browser half paints it in a shadow-root widget with drag-to-move, a status bubble, a right-click menu and pointer-look that follows a nearby cursor. The bubble keeps a stage-flavoured status line and rotates backstage quips while the pet is idle, and can also show the DeepSeek account balance and today's spend. Install with dsh plugin --profile desktop add <path-to-this-repo>.

目录

pet-astra-yao/
|-- package.json          # DSH 插件清单:dsh.bundle / dsh.client / exports
|-- cordis.patch.yml      # 插件行:装进 profile 的那一条 insert
|-- src/
|   |-- index.js          # 服务端插件:会话跟踪、配置、/plugins/dsh-pet-astra-yao/* 接口
|   |-- state.js          # 会话事件 → 桌宠状态(纯函数,便于测试)
|   |-- atlas.js          # Codex atlas 契约:行列、帧数、方向、取帧算法
|   |-- balance.js        # DeepSeek 余额查询 + 今日消耗记账
|   |-- account.js        # 账户钱包(充值 + 赠金)→ 余额的纯映射
|   |-- config.js         # 配置归一化与 PATCH 校验
|   `-- client.core.js    # 浏览器端源码(影子 DOM、拖拽、气泡、右键菜单、轮询)
|-- scripts/
|   |-- build-client.mjs  # 把 client.core.js 打包成 lib/client.js
|   |-- verify.mjs        # 安装前自检:清单、补丁、bundle、atlas
|   `-- audit-atlas.py    # 图集体检:帧数、行内高度、脚底基线(Pillow)
|-- docs/atlas-brief.md   # 给画图方的重制需求:现状问题 + 一致性规则 + 验收
|-- lib/client.js         # 构建产物(已提交,DSH 启动时直接加载)
|-- test/                 # node:test 单测(atlas / state / config / balance / account / client / host / server)
|-- assets/icon-180.png   # 插件市场图标(从图集待机帧裁出来)
|-- pet.json              # Codex 宠物清单(保留,Codex 端仍可用)
|-- spritesheet.webp      # 图集,同时被 DSH 插件以 /assets 接口提供
|-- USAGE.md              # 原 Codex 桌面端安装说明
`-- README.md

安装到 DSH

DSH 的插件是「profile 里的一个依赖 + 一条 bundle 记录」。本仓库根目录就是插件包,所以有两种装法。

方式一:命令行(推荐,路径换成你本地的仓库位置)

dsh plugin --profile desktop add D:\Repos\pet-astra-yao

这一步把包装进 profile 的 node_modules,并把包名追加到 profile 的 dsh.profile.bundles。 如果你用的 DSH 版本没自动追加,就在 %USERPROFILE%\.dsh\profiles\desktop\package.json 里手动补一行:

"dsh": {
  "profile": {
    "bundles": [ "...原有的那些 bundle...", "dsh-pet-astra-yao" ]
  }
}

("...原有的那些 bundle..." 用文件里原本的条目替换,别把别的插件挤掉。)

方式二:图形界面

打开 DSH Web 的「设置 → 插件」,用「从本地路径安装」填本仓库的绝对路径,装完点「立即启用」。 插件页会读到 cordis.patch.yml,把配置渲染成表单。

方式三:直接从 GitHub 装(不用先克隆)

dsh plugin --profile desktop add github:hongxin-y/codex-pet-Astra-Yao

pnpm 会拉仓库、跑 prepare 重新生成 lib/client.js。这样装的是独立副本,改代码不会热更新, 开发时用方式一(link: 指向工作区)。

装好后刷新页面:右下角出现 Astra Yao 即成功。它和别的桌宠插件(例如 dsh-pet-remielle)可以同时存在, 各自记住自己的位置。

改完代码或换了 spritesheet.webp 之后:重启一次 DSH(host 与浏览器两半都在启动时装载), 之后刷新页面即可。图集文件本身按 mtime + ETag 校验,替换图片不需要清浏览器缓存; 只有 host 代码变更才需要重启。

DSH 0.2.1-rc.3 起 cordis 会拒绝读取未经 inject 声明的服务(cannot get property "x" without inject), 直接读 ctx.credentials 会让 host 半边在启动时静默失败——表现是桌宠只剩气泡、写着「未连接」。 本插件(0.1.1+)改成全部通过 ctx.inject([...], scoped => …) 取服务,缺服务时功能降级而不是报错。

交互

操作效果
拖动移动位置(拖动时播放左右跑),松手后坐标存回配置;locked 时不可拖
单击戳一下:原地挥手(图集第 3 行 4 帧),气泡应一句「在呢~/叫我?」;若当前是报错状态,则点一下即「我知道了」,回到待机
右键打开菜单:显示桌宠、大小、不透明度、动画速度、锁定位置、左右镜像、跟随光标、状态气泡、显示余额、回右下角、我知道了
隐藏后右下角留一个小圆点,点它把桌宠叫回来
鼠标移动待机时、且光标距离桌宠 280 px 以内,沿图集第 9–10 行的 16 个屏幕方向环绕看向光标(上、右、下、左);光标停住约 2.5 秒或离开范围后回到待机动画。可在菜单里关掉「跟随光标」

状态在「思考 ↔ 执行」之间抖动时,动画不会跟着一秒一重启:升级(执行、等待、报错)立刻切换, 回落要等当前动作播满 1.5 秒,所以小跑会连续跑下去,而不是原地抽动。

状态映射

服务端订阅 DSH 的会话事件,折算成一个状态后再喂给客户端:

DSH 会话桌宠
turn/start构思中(review,托腮)
tool/call(有工具在跑)执行中(running,小跑)
ask_user_question / exit_plan_mode / approval/asked候场中(waiting,托腮)
turn/end 且 reason.kind === "completed"后台待机 + 谢幕跳一下(jumping,5 秒内一次)
工具报错 / 异常结束破音了(failed,低头),点一下或开始下一轮对话后恢复
turn/end 且 blocked候场中
turn/end 且 aborted / disposed后台待机

子会话默认被忽略;把 includeSubagents 打开后,子代理的活动也会驱动桌宠。

状态气泡与余额

桌宠头顶的气泡会写三行:当前状态、细节(正在跑的工具 / 等你确认的类型 / 报错原文)、当前会话的项目和标题。 状态用她的口吻:后台待机 / 构思中 / 执行中 / 候场中 / 破音了——只有「执行中」保留直白说法, 免得看不出是在跑工具。待机时整块换成她的台词,每 9 秒轮换一句:

今夜,星光灿烂。 / 这个世界上最闪亮的东西,当然是爱! / 一段安宁的间奏,正好休息~ / 短暂的停顿,会让旋律更甜。 / 要不要听首歌?咳—— / 让旋律带着你走~

前两句出自官方角色介绍与角色 PV 标题,其余取自她的游戏内语音(待机 / 都市漫游),英文语音的条目由本插件译为中文。 任务完成那几秒会先显示「完美谢幕~」。 气泡贴着桌宠所在那一侧的边缘展开,底部的小尖角始终指向桌宠;贴到屏幕顶端放不下时自动翻到桌宠下方。 最小宽度 128 px、最大 240 px,文案变长时换行而不是把气泡撑到半个屏幕。 右键菜单里的「状态气泡」可以整个关掉它。

「显示余额」打开后,第三行换成 DeepSeek 账户余额和今日消耗:

  • 余额有两个来源,按顺序尝试:先用 DSH 自己的 deepseekAccount 账户服务读登录账户的钱包 (账户登录不需要 API Key);读不到账户钱包时再退到 credentials 里的 DEEPSEEK_API_KEY, 最后才退到环境变量 DEEPSEEK_API_KEY。都没配置时显示「未配置 Key」,不会假装有数字。 接口是 https://api.deepseek.com/user/balance(Key 模式),60 秒缓存,浏览器端每 60 秒最多拉一次 (GET /balance?refresh=1 可以强制刷新)。
  • 账户里的「充值余额」和「赠金」是两个钱包、各自扣款,所以余额按币种求和后显示, 鼠标悬停能看到 充值 50.00 + 赠金 2.73 的拆分。
  • 今日消耗按「余额下降」累计,账本存在 %USERPROFILE%\.dsh\.dsh-pet-astra-yao-usage.json,跨天自动归零; 充值导致余额上升时不会记成负消耗。它只能统计观测到之后的下降,所以悬停提示里会写明 「今日 ¥0.90(13:02 起观测)」——今天中途才开始跑的话,这个数字只覆盖那之后的部分, 过了零点就会自动变成完整的一天。
  • 没配置 Key、或者当前 DSH 没有暴露 credentials / deepseekAccount 服务时,气泡显示「余额不可用:未配置 API Key」, 桌宠其它功能不受影响。DSH 的凭据服务里没有这个 Key 时,服务端会退一步读环境变量 DEEPSEEK_API_KEY,所以在启动 DSH 的环境里导出它同样能显示余额。
  • 余额只从你的机器直连 DeepSeek,不经过 DSH 的服务器;接口本身也只接受本机回环请求。

脚下余额条

「余额条」默认打开:桌宠脚下多一条药丸形状的小横条,写 ¥12.34 · 今日 ¥0.56,点一下立刻刷新(跳过 60 秒缓存)。 它跟着桌宠移动,缩放、拖拽、换位置都会重新贴合;没配 Key 时显示「未配置 Key」并变成暖色,不会假装有数字。 悬停会列出钱包拆分、今日消耗的观测起点和余额来源(登录账户 / API Key)。 右键菜单里的「余额条」可以单独关掉它,与气泡第三行的「显示余额」互不影响。

配置

配置存在 profile 的 cordis.patch.yml(也就是插件页表单背后的那份),字段如下:

字段默认说明
enabledtrue是否启用这个插件
scale1缩放,0.5–2
opacity1不透明度,0.3–1
speed1动画速度,0.5–1.6(0.5 最慢,1.6 最快)
mirrorfalse左右镜像
lookAtPointertrue光标靠近时沿 360° 屏幕方向看向光标;可在菜单里关掉
lockedfalse锁定位置,禁止拖动
hiddenfalse隐藏(留一个小圆点)
pausedfalse暂停逐帧动画,只画当前帧
showBubbletrue显示头顶状态气泡
showBubbleUsagefalse气泡里显示余额和今日消耗
showBalanceBartrue脚下显示一条余额小横条(点击刷新)
includeSubagentsfalse子代理是否也驱动桌宠
posX / posYnull上次拖到的位置,null 表示贴右下角

拖拽、菜单里的改动会 PATCH 回服务端,服务端再写进配置作用域;下次打开页面自动恢复。

HTTP 接口

都挂在 /plugins/dsh-pet-astra-yao 下,只接受本机回环地址(非回环、Host/Origin 不匹配一律 403):

方法路径用途
GET/state一次快照:插件版本、配置、图集描述、当前会话状态
GET PATCH POST/config读配置 / 合并式改配置(未知字段 400)
POST/ack清掉报错状态(桌宠「我知道了」)
GET/balance余额 + 今日消耗(?refresh=1 跳过 60 秒缓存)
GET/spritesheet图集本体,image/webp(带 ETag,按 mtime 校验,换图即生效)
GET/manifestpet.json(同样带 ETag)

客户端不依赖任何前端框架,只用 DSH 的基线模块,所以 dsh.client.inject 是空数组。

服务端对 @deepseek-ai/schemastery 是「有则用、无则跳」:dsh plugin add <本地路径> 的 link 安装不会装这个包的 依赖,拿不到布局描述(schema)时插件照常跑,只是「设置 → 插件」里没有表单;registry 安装则会正常解析。

开发

npm run build     # 改完 src/client.core.js 后重新生成 lib/client.js
npm run build:atlas # 从已审阅的动作源图重新打包图集(开发依赖 sharp)
npm run verify    # 自检:清单字段、补丁行、bundle、图集尺寸(1536×2288 / v2)
npm test          # node:test:atlas / config / state / balance / client / host / server
npm run test:atlas # Pillow:图集审计脚本的回归用例

# 换图集之后先跑这个(需要 Pillow):格式、透明度、连续帧数、含道具的占用边界
python scripts/audit-atlas.py spritesheet.webp

lib/client.js 是提交进仓库的构建产物:DSH 启动时直接读它,不会帮你编译,所以改完源码记得 npm run build 再一起提交。

要重新生成图集,把 docs/atlas-brief.md 直接发给画图方:里面写了交付规格、 11 行各自该画什么,以及结构检查与动画目检的验收范围。OK 只代表结构通过, 不能证明人物比例、脚掌接地或动作连贯。此次修复方式及复查记录见 docs/atlas-review.md。

自己写桌宠时可以直接复用 src/atlas.js:它只描述 Codex atlas 的几何与动画表(行、帧数、间隔、朝向), 不碰 DOM,也没有依赖。

原 Codex 用法

pet.json + spritesheet.webp 仍然是合法的 Codex 桌宠包,复制到 %USERPROFILE%\.codex\pets\astra-yao 即可在 Codex Desktop 里使用,细节见 USAGE.md。

素材说明

像素美术与角色形象来自原仓库,角色「Astra Yao(耀嘉音)」及相关设定的权利归原权利人所有; 本仓库只做桌宠资源的整理与 DSH 插件化,未附带额外许可证。

图集原先存在跑动混跪姿、失败突然躺平、挥手换画、跨行比例变化和方向帧语义不完整等问题。 2026-10 的重绘后,python scripts/audit-atlas.py spritesheet.webp 结构性检查全部通过 (站立帧高约 198 px、脚底基线 203、方向两行中位高度 198/198 px、16 向面部像素变化 73%),Codex 直接使用图片时也能得到修好的动作:

位置当前状态播放
第 1 行(向右跑)独立生成的向右跑全身帧;法杖仍固定在画面左侧原生第 1 行,8 帧;不再额外 flip
第 5 行(failed)完整全身站立低落、叹气,无躺平或局部拼贴完整 8 帧,不跳过任何一列
第 7 行(工作中)复用第 2 行的 6 个不同跑步相位 [0,1,3,4,5,7]6 帧,120 ms
第 8 行(review)完整全身托腮思考,保持站姿,细微目光变化和眨眼完整 6 帧,360 ms
第 3 行(挥手)完整全身连续挥手,法杖固定在画面左侧,脚底对齐单击播完整 4 帧,200 ms
第 9–10 行(16 朝向)360° 屏幕方向注视:上 → 右 → 下 → 左;头颈和上身自然跟随,下身与脚底稳定默认跟随光标(280 px 内),每 22.5° 一格,2.5° 迟滞,可关闭

新绘动作使用内置 imagegen,提示词保存在 docs/atlas-generation-prompts.md, 源图位于 assets/atlas-source/,由 scripts/pack-atlas.mjs 统一重建全部 11 行后输出 lossless WebP; 各姿势不单独拉伸,也不裁切人物。

判定标准写在 docs/atlas-brief.md:跨行动作共用同一人物设定,持杖手固定在画面左侧;16 格方向按屏幕坐标顺时针环绕,四个主方向不能反转。python scripts/audit-atlas.py spritesheet.webp 会打印各行高度、宽度、基线、方向两行高度差及面部区域变化;客户端使用 2.5° 边界迟滞,避免在格子边界来回闪。

Plugins relacionados