# dsh-piggy 维护交接文档(2026-10-18 更新,稳定游戏 0.37.0 / 外壳 0.6.6) > 给接手维护的 DeepSeek / 任何 agent / 开发者。最短的入口是仓库根目录的 [AGENTS.md](../AGENTS.md)(红线和文档地图),这一页是完整的现状和流程。 > 本页取代 [2026-10-03 的交接记录](archive/HANDOFF-2026-10-03.md)(那份停在 v0.27,只作历史参考)。 > 有冲突时以:用户最新的话 > 本页当前状态 > 其它文档 > 旧任务卡 为准。部署步骤保留作流程参考,具体版本状态以本节为准。 --- ## 1. 先读这里(五分钟版) ### 当前状态(2026-10-18) - **0.37.1-rc.2 集成候选已就绪,未发布**:集成分支 `rc/0.37.1-rc.2` 已合并存档导入导出(`9523a86`,含 pi/DSH 两侧复核修复)和桌面动作形状修复(`8504838`);游戏/别名包 `0.37.1-rc.2`、外壳 `0.6.7-rc.2`,存档 v14 不变。主机全量 **1231/1231**、build/typecheck 与 `git diff --check` 通过,`client.js` 已重建。未 push、未打标签、未发布;等待维护者验收后按第 9 节执行,npm 仍由维护者手动发。 - **晚间 RC 已发布**:游戏/别名源码 `0.37.1-rc.1`、外壳 `0.6.7-rc.1`,存档 v14 不变;[GitHub RC](https://github.com/CLICGGER-TYPES/dsh-piggy/releases/tag/v0.37.1-rc.1) 与 [Gitee RC](https://gitee.com/clicgger/dsh-piggy/releases/tag/v0.37.1-rc.1) 均已发布,农场 4.0.9 / 矿洞 3.0.1 两渠道正常 UI 在线安装通过。主机全量 1154/1154,Windows 125% + Electron DPR2 对照、本体/面板摸摸和退出重开通过,实际系统 200% 未覆盖;Linux rootless/macOS 限制保留。GitHub provider 在各 release 下使用 latest 清单,Gitee generic 使用 rc;首次 GitHub 检查假设错误已修正,原标签补构建全绿,未移动标签。#12/#13/#14/#15/#16/#17/#18 均已按各自范围回复,README 与发行说明已感谢贡献者。npm 未发布,维护者明早手动使用预发布 dist-tag。当前状态以 [ROADMAP](ROADMAP.md) 为准。 ### 此前阶段记录(历史状态) 以下条目保留当时的版本、哈希与验收数字;“未提交/未发布”等描述仅适用于对应阶段,当前交付状态以上节为准。 - **整合阶段主线**:`code/` 的 main 已快进纳入作者复核的完整候选 `1e46ef3`,整合前基线为 `c20ab95`。游戏版本仍为 0.37.0、外壳 0.6.6、`STATE_VERSION` 14;尚未创建新版本标签或发版。 - **PR #12/#13 整合**:A/B/C、关闭恢复与安装保存失败重试、Esc 和动画命中修复均已进入 main。复核基点保留在 [`codex/runtime-037-candidate`](https://github.com/CLICGGER-TYPES/dsh-piggy/tree/codex/runtime-037-candidate) 的 `1e46ef3`;main 随后只更新交接文档。该阶段客户端 SHA-256 为 `5476f34e95817e2aa28d09886572b5159dacb7d5ecfb66dac5eed0fb8008b8be`,主机全量 1124/1124、build/typecheck 通过;作者另在原生 Windows / Node 24.21.0 独立复核完整候选 1124/1124、构建及类型检查通过。完整阶段提交、独立复核来源和限制见[整合验证记录](guides/agent-adapters-validation.md)。 - **当前已实测路径**:真实 DSH 14 项通过;Linux 原生新存档孵化、双焦点 Esc、空白点击穿透、固定 356×284 拖动与正常退出,拖动窗口位移与输入精确一致。Linux 284 帧录制约 49.9fps、最大间隔 34ms,未见猪丢失、反向步或重影;严格分析器仍因待机约 3.5px 位移报 FAIL。Windows 125% 原生购买 494/1、双焦点 Esc、底部 motion reserve 空白点击穿透、固定视口拖动与退出重启持久化通过;当前原生 132 帧约 21.66fps、最大间隔 78.26ms,逐帧未见白块/第二只猪,但仍不足以排除单帧残影。新版全新存档三次原生点击孵化已通过。macOS 未实机验证。 - **目录整理**:已按迁移计划执行并核验 11 项;8 棵 Git 工作树 HEAD 与脏文件 SHA 均保留。活动 PR #12 物理路径保留,`worktrees/pr12-source` 为兼容入口。旧 `rightclick` 的四个未提交文件仍须保留。证据位于本机总目录 `tasks/results/directory-migration/`。目录迁移时 `code/` 保持干净且位于 `c20ab95`;随后按用户授权将完整候选整合到 main。 - **2026-10-16 桌面体验修复候选**:独立工作树 `worktrees/desktop-ux-20261016/` 修复分数缩放回读误差导致的相同目标重复设置。Windows 125% 原生静止按住对照中,约 1.6 秒的同目标 setBounds 从 93 次降为 0;45 个移动步骤对应 45 次设置,实际位移保持 (-176,-72) DIP(物理输入 -220,-90)。主机 1132/1132、build/typecheck 通过;新 8 条行为回归原代码 1/8、修后 8/8。Linux 同版原生孵化、静止按住后拖到边缘、Esc、正常退出及实际存档锁创建/释放通过;498 帧拖动片段为 52.41fps、最大间隔 34ms,主代理逐帧审阅。该项生产改动仅在外壳,不改客户端、玩法或存档;修改尚未提交或推送。此结论不代表白块或单帧残影已修复。 - **后续菜园焦点候选**:扩展 4.0.9 修复购买/铲除确认的焦点进入、Tab 限制和返回;共享客户端 `a0b806a` 修复宿主轮询再次丢焦点。主机 1136/1136、build/typecheck 通过,Windows 125% 实际便携测试包与 DSH 网页复验通过。Linux 旧宿主客户端加 4.0.9 的原生流程已过,但新宿主客户端复验遇到两次 Xwayland/pixman_blt 崩溃,未计通过,需先诊断。修改、4.0.9 双渠道目录/官方清单和测试包均未发布;未提交或推送。只在本机隔离工作树,具体证据及下一步以 [ROADMAP](ROADMAP.md) 为准。 - **继续验收结果**:主机再次1136/1136、build/typecheck通过。Windows独立身份的实际NSIS安装、孵化/购买、正常退出重开(494金币/1苹果)和卸载通过,原安装/快捷方式未变;125%宿主QMP scanout录制540帧约90fps、最大14.43ms,抽查未见白块/第二只猪,不能据此宣称残影根因已修。Linux私有rootful隔离启动对照与15分钟稳定运行完成,但原rootless pixman崩溃仍未解决;前置误用XTest段已排除,不作完整QMP验收。证据在本机总目录 `tasks/results/experience-finish-20261016/ACCEPTANCE.md`;后续纯QMP与主代理未插桩候选复核已覆盖Linux私有rootful的焦点、退出重开/锁和540帧拖动;仍不替代原rootless条件。一次子代理误启动默认配置目录无基线,无法保证未写入,未擅自删除/回滚;具体影响边界和私有窗口二次退出点测限制见报告及ROADMAP。 - **RC 与 README 准备**:用户同意先准备 RC;独立工作树现为游戏/别名包 `0.37.1-rc.1`、外壳 `0.6.7-rc.1`,存档仍 v14、菜园候选仍 4.0.9。README 已重排安装、玩法、稳定版/RC 状态,并替换为隔离 DSH 实拍的主菜单、小农场和大农场;见[截图来源](screenshots/readme-rc-capture.md)。RC 更新清单与 Gitee 清理回归已通过;主代理全量 1140/1140、build/typecheck 通过,游戏包、扩展双渠道校验及 npm 打包预览通过。未提交、推送、打标签或发布;线上稳定入口未改。具体进度和发布顺序仍以 [ROADMAP](ROADMAP.md) 为准。 - **当前工作顺序与体验待办**:以 [ROADMAP](ROADMAP.md) 为唯一清单;完整执行证据见本机总目录 `tasks/2026-10-15-runtime-integration-and-cleanup.md`。 动画命中范围的当前结论:追蝴蝶、旋转 `dp-spin` 与跳跃 `dp-jump` 已用整段 CSS 动画扫掠纳入测量;旋转修前 roll20/67 越界最大 30.206px、cure14/59 最大 29.51px,修后分别 0/67、0/59;追蝴蝶修后 0/61。窗口轮廓只随尺寸固定预留,待机时不把预留扩张成点击区;Darwin 保持原 footprint,尚未修复。探针是强制动画的几何验证,不等同于自然用户复现或 macOS 实机验收。证据:本机总目录 `tasks/results/rotation-hit-probe/`。 DSH 面板浏览器实测在用户授权后使用 Playwright 1.63 + Chromium headless 独立 profile 完成;未使用个人 profile 或真实 `DSH_HOME`。`Continue`、右键打开面板、孵化、购买苹果后金额 500→494 且苹果 0→1,刷新和重启 DSH 后仍为 494/1;仅有主动拦截 Google Fonts 引起的 3 条 console 加载错误,无其他 app error。Linux Esc 原生流程在 pet focus 和 panel focus 两态均关闭面板;菜园 dialog/popup 依次从 1/1 到 0/1、0/0、扩展关闭,panel focus 保持 true。证据路径见本机总目录 `tasks/results/runtime-c-dsh-ui/run-20261015T063137Z/result.json` 和 `tasks/results/runtime-c-linux-ui/ux-results.json`。 - **是什么**:一只「QQ 宠物」式的电子猪。同一份代码有两种形态:**DSH 插件**(住在 DeepSeek Harness 网页里)和**桌面版**(Electron,Windows / Linux / macOS)。 - **稳定代码入口**:项目总目录中的 `code/`(当前 main);已复核候选另保留在总目录 `worktrees/runtime-c/`。远端 GitHub `CLICGGER-TYPES/dsh-piggy` 和 Gitee `clicgger/dsh-piggy` 的发布仍按第 9 节流程执行。 - **每次改完必跑**:`npm run build && npm test && npm run typecheck`(历史整合主机全量 1124 项;最新候选结果以本页当前状态与对应验证记录为准)。 - **「怎么加 X」先看 `docs/guides/`**:[开发新功能(总则)](guides/adding-features.md)、[写扩展](guides/writing-extensions.md)、[加台词](guides/adding-lines.md)、[加成就](guides/adding-achievements.md)、[界面规范](guides/ui-style.md)、[桌面架构与 IPC](guides/desktop-architecture.md)。 - **用户报问题时先让他导出日志**:「设置 → 日志 → 导出日志」,一份文件里同时有宿主、浏览器和桌面外壳三边的现场(见 [日志与导出](design/log-export.md))。 - **发版**:改版本号 + 写 CHANGELOG → 提交 → 推 `v*` 标签 → GitHub Actions 发 GitHub、并构建 Gitee 渠道的包 → **本机**跑 `scripts/gitee-publish.sh` 推 Gitee → npm 由人手动发。详见第 9 节。 - **最重要的三条规矩**:数值/玩法设计先问用户再做;提交信息用中文、不加 AI 署名;改了界面一定要在真实浏览器 / 桌面窗口里看一眼(测试通过 ≠ 显示正确)。 --- ## 2. 项目是什么 复刻 QQ 宠物 70–80% 的单机玩法:养成(饥饿 / 清洁 / 心情 / 健康 / 体重)、成长 60 级与形态、上学和 33 种职业、疾病和 20 种药、旅行、钓鱼、番茄钟、签到礼包、日记、图鉴、换肤与自定义皮肤包、加冕 / 恶魔签约,以及可在线下载的扩展玩法(盲盒寻访、扭蛋、菜园、矿洞)。规则全文:[玩法与养成规则](guides/gameplay.md)、[设计说明](DESIGN.md)。 | 形态 | 怎么跑 | 存档 | |---|---|---| | DSH 插件 | npm 包 `dsh-piggy`(社区目录别名 `dsh-plugin-piggy`),DSH 的 web profile 加载 | `$DSH_HOME/dsh-piggy/state.json` | | 桌面版 | Electron 外壳(`apps/desktop/`)+ 游戏包(可热更新) | Electron userData 下 `dsh-piggy/state.json`;Linux `~/.config/dsh-piggy-desktop/`,Windows `%APPDATA%\dsh-piggy-desktop\`,macOS `~/Library/Application Support/dsh-piggy-desktop/` | 两边各养各的猪,桌面版托盘菜单可以导入 DSH 的存档。 --- ## 3. 仓库与目录 本机总目录 `/zyx/DSH/workspaces/dsh-piggy/`(见同目录 README):`code/` 代码、`skins-source/` 皮肤原稿、`feedback/` 用户报错截图录屏、`videos/` 宣传片工程、`design-refs/qqpet-ref/` QQ 宠物参考图(数值和疾病链的设计来源)、`archive/` 旧分支备份和历史快照。 > ⚠️ `/zyx/DSH/workspaces/dsh-pig` 是指向 `code/` 的旧链接,本机 DSH 已改成直接加载 `code/`(`~/.dsh/profiles/web/package.json` 里 `"dsh-piggy": "link:/zyx/DSH/workspaces/dsh-piggy/code"`)。 `code/` 里主要的东西: | 路径 | 是什么 | |---|---| | `index.js` | DSH 插件入口:注册路由(`routes.js`)、斜杠命令 `/pig`(`commands.js`)、客户端脚本 | | `snapshot.js` | 把存档整理成面板用的「快照」(客户端只读快照,不自己算规则) | | `environment.js` | 版本号与环境说明(日志表头用);`PACKAGE_VERSION` 的唯一定义处 | | `routes.js` | HTTP 接口:`/dsh-piggy/state`(取快照)、`/dsh-piggy/act`(所有操作,body `{action, ...}`)、`/dsh-piggy/art`、`/dsh-piggy/ext/*` | | `packages/pet-core/src/` | **领域库**:`data/`(数值表)、`core/`(纯函数规则)。根目录 `core.js` / `data.js` 只是再导出 | | `store/` | 存档读写(原子写)、迁移、扩展运行时 `ext-runtime.js`、运行日志 `journal.js` | | `src/client/` | 面板前端源码(原生 JS + DOM,不用框架)→ `npm run build` 打成根目录 `client.js`(**产物要提交**) | | `extensions/` | 可下载扩展(`blindbox` `gacha` `farm` `mine`)+ 在线目录 `registry.json` / `registry-gitee.json` | | `assets/` | 立绘 SVG(形态、皮肤、动作、App 图标) | | `apps/desktop/` | 桌面外壳(Electron):`main.js`、`preload.cjs`、`lib/`、`renderer/`、打包脚本 | | `channels/` + `channel.js` | 发布渠道(github / gitee)的地址,见第 9.4 节 | | `packages/dsh-plugin-piggy/` | npm 别名包(给社区目录检索用,只依赖 `dsh-piggy`) | | `cordis.patch.yml` | DSH 加载插件用的配置层;`name` 必须和 package.json 的 `name` 一致 | | `docs/` | 文档;`docs/ROADMAP.md` 路线图和待办,`docs/numbers/` 用户确认过的数值单,`docs/ASSETS.md` 素材总表,`docs/archive/` 历史文档(旧交接、各轮任务卡) | | `test/`、`apps/desktop/test/` | node:test 测试 | | `tools/` | 预览页(`tools/preview.html`)、字体工具等 | --- ## 4. 架构 ### 4.1 分层(硬规定,见 [CONVENTIONS](CONVENTIONS.md)) 依赖只能从外向内:`data/` → `core/` → `store/` → 组装层(`index.js` `snapshot.js` `routes.js` `commands.js`)→ `src/client/`。 - `core/` 是纯函数 `(state, ..., nowMs) => result`:**时间作参数传入,随机数用 `core/random.js`(种子在 `state.seed`),禁止 `Math.random()` / `Date.now()`**。 - 数值都在 `data/`,逻辑里不写裸数字。 - 业务拒绝返回 `{ ok: false, reason }`,不抛异常;系统异常要记日志并保留现场(`.bak`)。 - 客户端只渲染快照,不重算规则。 ### 4.2 存档 - 当前 `STATE_VERSION = 14`(`packages/pet-core/src/core/constants.js`)。改存档结构:`core/upgrades.js` 表尾加一级 + 版本 +1 + 迁移测试。**不要随便升版本**;只是加字段就用 `ensureXxx(state)` 补默认值。 - 写文件原子化(`store/state-file.js`):临时文件 → fsync → rename。旧档要能自动迁移,不丢数据。 - 时间推进是分段结算(离线一段时间后打开会按段补算)。 ### 4.3 扩展系统 - **内置扩展**:番茄钟、钓鱼——可在「设置 → 🧩 扩展」开关 / 删除,注册表在 `packages/pet-core/src/data/extensions.js`。关掉后对应 App、商品、图鉴分区都隐藏,数据保留。 - **下载扩展**:`extensions//` 里 `manifest.json` + `server.js` + `client.js`。运行时 `store/ext-runtime.js`: - 只从本渠道的在线目录读(`CHANNEL.registry`),每个文件核对 sha256,`minGame` 高于当前游戏版本不装; - 扩展只能改自己的 `state.extData[key]`,其它一律走 `api`:`now`、`coins()`、`spend()`、`earn()`、`give()`、`say()`、`count()`、`take()`、`emit()`(成就事件)、`exert()`(玩累了扣饱食)、`wallet`(自己的币,见 4.5); - `view()` 可以返回 `shelf`(往商店加货架)、`dex`(往图鉴加分区,`style: 'holo'` 是闪卡); - 出错只影响它自己。 - 写法和发布步骤:[写一个在线扩展](guides/writing-extensions.md);设计背景:[扩展删除与在线下载](design/extension-download.md)、[扩展成就](design/extension-achievements.md)、[盲盒设计](design/blindbox.md)、数值单 `docs/numbers/X1–X4`。 ### 4.4 桌面版:外壳和游戏包分开 - **外壳**(`apps/desktop/`,当前稳定版 **0.6.6**):两个窗口(猪 / 面板)、托盘、更新器。改了 `main.js` / `preload.cjs` / `lib/` / `renderer/` 才需要升外壳版本,用户要重装或外壳自更新。结构和全部 IPC 见 [桌面架构](guides/desktop-architecture.md)。 - **游戏包**(= 插件那份代码,`apps/desktop/scripts/pack-game.mjs` 复制、`release-game.mjs` 打成 `game-<版本>.json.gz` + manifest):在「设置 → 更新」里直接下载切换、可回退,不用重装。 - 窗口摆放、可点区域、桌面样式都放在游戏包里(`src/client/desktop/`),所以这类修复走游戏包更新就到。 - 详见 [更新机制](guides/updates.md)、[桌面版指南](guides/desktop.md)、`docs/DEVELOPMENT.md`「桌面程序和游戏包怎么分工」。 ### 4.5 经济体系(0.35.0 起,[设计](design/economy.md)) - **金币只走一个入口**:`core/economy.js` 的 `earnCoins` / `spendCoins` / `refundCoins`,每笔按来源记账(调试页「经济」能看)。直接写 `state.coins +=` 会被 `test/economy.test.js` 拦下。 - **扩展币钱包**:钱包在宿主 `state.wallets[扩展名]`,扩展在 manifest 声明 `economy.currency`(名字、图标、汇率;`buyable: false` 表示只能挣不能用金币买),用 `api.wallet` 加减。换成金币不收费、用金币买多收 5%;删扩展时按存着的汇率自动结清。 - **不设每天上限**,靠「玩累了」(`exert`)和收入区间控节奏:主动玩法 300~2500 金币/小时,挂机 60~1200。改数值先跑 `node tools/economy-sim.mjs` 看区间,各玩法的区间测试会守着。 - 当前数字:[J1 数值单](numbers/J1-economy.md);扩展自动化(K1,交给 codex):[design/automation.md](design/automation.md)。 --- ## 5. 开发环境 ```bash cd /zyx/DSH/workspaces/dsh-piggy/code # 构建工具不写进依赖清单(--no-save),装一次即可 npm install --no-save --package-lock=false esbuild@0.28.2 typescript@5.9.3 @types/node@20.19.43 # 桌面版依赖 cd apps/desktop && npm ci # 新版 npm 可能拦下安装脚本,导致 Electron 本体没下载:手动补一下 node node_modules/electron/install.js ``` - 项目运行要求 Node ≥ 20;本轮主机全量验证使用 Node 26.11.1,Linux CLI 与 Windows 11 CLI 使用 Node 24.21.0,Linux GUI 环境系统 Node 22。没有框架、没有 TypeScript 编译:JS + JSDoc + `// @ts-check`,`npm run typecheck` 用 tsc 只做检查。 - 本机 DSH 源码在 `/zyx/DSH/deepseek-harness`(`master` 分支,2026-10-06 更新到 0.2.1-alpha.1;更新后要 `pnpm install && pnpm build`)。 --- ## 6. 开发流程 1. 开工:`git status` 干净、`git pull` 到最新 `main`。多人 / 多 agent 同时做时,每人一个分支 + `git worktree`,做完合回 `main` 后删掉分支和工作目录(别再堆一堆旧分支)。 2. 改 bug:**先写能复现的失败测试**,再修。新功能覆盖正常路径和边界。 3. 改了 `src/client/` 一定 `npm run build`,把新的 `client.js` 一起提交(`test/bundle.test.js` 会检查它和源码一致)。 4. `npm run build && npm test && npm run typecheck` 全绿。 5. **界面改动要在真实环境看**:网页版起一个隔离 DSH 实例(第 8 节),桌面版启动真窗口截图看像素;只看代码或只量坐标不算验收。 6. 提交:中文、一个提交只做一件事、不加 AI 署名(不要 `Co-Authored-By: Claude/AI`)、用户能感知的变化写进 `CHANGELOG.md`、功能变了同步改 `README.md` 和玩家文档。 7. 新玩法 / 改数值:先出**数值确认单**(放 `docs/numbers/`)给用户确认,确认过的数字不要擅自改。 --- ## 7. 开发规范补充(完整版见 [CONVENTIONS.md](CONVENTIONS.md)) - 源码文件 ≤ 400 行(`client.js` 产物豁免),函数 ≤ 40 行、≤ 3 参数、嵌套 ≤ 3 层;超了就拆。 - 命名:camelCase / PascalCase / UPPER_SNAKE;新文件名 kebab-case;同一概念全项目一个词。 - 注释只写「为什么」;代码标识符 / 注释 / 日志 / 提交信息不用 emoji(游戏数据、界面文案、README、CHANGELOG 可以)。 - 禁止空 `catch`、吞错;错误信息带上下文参数。 - 界面风格:动森手机风(奶油底、圆角卡片、青绿按钮、App 方块主菜单),面板要简洁——不加刻度条和说明废话,跳转后返回原处。改布局前先问用户。 - 扩展的界面写在扩展自己的 `client.js` 里(`window.dshPiggyExtensions.register(key, { render })`,拿到 `app.el / app.button / app.send / app.rerender / app.data`)。 --- ## 8. 调试与测试环境 > **界面验证去虚拟机里做**(用户 2026-10-09):别在维护者自己正用的电脑上开桌面版窗口截图——会打扰用户工作。Linux、Windows 各有一台测试虚拟机,账号和地址不进仓库,问维护者。纯逻辑照旧 `npm test`。 ### 8.1 网页版(DSH 插件)——用隔离实例,别碰用户正在用的 DSH ```bash # 复制一份 DSH_HOME,把 profile 里的 dsh-piggy 链到要测的代码 cp -a ~/.dsh /tmp/pig-home && ln -sfn /zyx/DSH/workspaces/dsh-piggy/code /tmp/pig-home/profiles/web/node_modules/dsh-piggy cd /zyx/DSH/deepseek-harness && DSH_HOME=/tmp/pig-home node --import tsx/esm apps/cli/src/bin.ts web --no-open --port 3087 # 日志第一行给出带 token 的地址 ``` - 用户自己的 DSH 一般跑在 3080 端口(终端里 `pnpm dsh web`),测试用 3084 以上的端口。 - 接口可以直接调:`fetch('/dsh-piggy/act', {method:'POST', body: JSON.stringify({action:'hatch'})})`;`/dsh-piggy/state` 看快照。 - **调试模式**:主菜单底下的版本号 3 秒内连点 7 次,出现「调试」App(改数值、快进时间、切形态 / 体重档等)。接口 `{action:'dev', patch:{...}}`。 - 不支持的改动(比如扩展数据):停服 → 改 `state.json` → 再启动。 - **排障先看日志**:设置 → 日志 → 导出日志。也可以直接 `curl /dsh-piggy/logs/export` 看那一份纯文本;落盘的那份在存档目录 `logs/dsh-piggy.log`(一行一条 JSON,满 1.5 MB 轮转)。 ### 8.2 桌面版 ```bash cd apps/desktop && npm start # 先打游戏包再启动 # 常用环境变量: PIGGY_USERDATA=/tmp/pig-ud # 用独立数据目录(别碰真存档) PIGGY_DEVTOOLS=1 # 自动打开开发者工具 PIGGY_RELEASES_URL=... # 换更新源(测试用) PIGGY_WAYLAND=1 # Linux 强制走 Wayland(默认在 Wayland 下自动加 --ozone-platform=x11) PIGGY_SHAPE=1 # Windows 退回旧的窗口形状做法(对比排查) PIGGY_CAPTURE=<文件> / PIGGY_CAPTURE_STEPS # 截图自检模式 PIGGY_BUNDLED_GAME=/不存在的目录 # 模拟「安装包不带游戏」(Gitee Windows 包),走首次下载 PIGGY_GAME_PIN= # 首次下载用的清单(scripts/write-game-pin.mjs 生成,可指本机 http 服务) # 加 --remote-debugging-port=9333 可以用 Playwright 连上去操作页面 ``` - 日志:外壳的窗口 / 更新记录写在 userData 下 `piggy.log`(Windows `%APPDATA%\dsh-piggy-desktop\piggy.log`);**这些行现在也会同步进游戏日志**,所以让用户「设置 → 日志 → 导出日志」一份就够,不用再手工找两个文件。 - Linux:Wayland 下 `--ozone-platform=x11` 必须在命令行带(代码里已自动重启带上);`capturePage()` 截到图不代表窗口真的显示了,要看真实屏幕像素。 - Windows:透明全屏窗口拖动会卡整机,窗口要开到内容大小;分数缩放下 `getBounds` 和 `setBounds` 会差 1px(已有 2px 容差)。 ### 8.3 测试 - `npm test` 跑根目录 `test/**` 和 `apps/desktop/test/*`。历史整合版本主机/Linux CLI/Windows CLI 各 1106 项通过,Esc 阶段 host 1115,追蝴蝶阶段 host 1118;当前客户端 host 全量 1124,Windows Node24 动画相关 9/9。上述平台计数对应不同阶段,不代表最新候选三平台均跑过 1124 项。原生 GUI 实测另行记录。客户端测试用假 DOM(`test/helpers/bundle.js`)。 - 测试不依赖真时钟、网络、执行顺序。 --- ## 9. 构建与发版 ### 9.1 版本号 | 什么 | 在哪 | 什么时候改 | |---|---|---| | 游戏版本 | 根 `package.json` `version` | 每次发版 | | 别名包 | `packages/dsh-plugin-piggy/package.json` 的 `version` 和 `dependencies.dsh-piggy` | 和游戏版本同步 | | 桌面外壳 | `apps/desktop/package.json` `version` | 只有改了外壳代码才升(当前稳定版 0.6.6;加基础动作时同时升 `src/client/desktop/index.js` 的 `DESKTOP_VERSION`) | | 存档 | `STATE_VERSION` | 只有存档结构变了才升(配迁移) | | 扩展 | `extensions//manifest.json` | 扩展改了就升,`minGame` 写需要的最低游戏版本 | 测试版用 `x.y.z-rc.N`(会自动标成预发布)。别频繁发包:一批改完自查完只出一个测试版,用户验收通过再发正式版。 ### 9.2 正式发版步骤 1. 改上表里的版本号;在 `CHANGELOG.md` 写 `## [x.y.z] — 日期 · 主题` 小节(发布说明从这里取,写全改动);README 同步。 2. `npm run build && npm test && npm run typecheck` → 提交(如 `release: v0.33.1 — 一句话`)→ 推 main。 3. 打标签推送:`git tag v0.33.1 && git push origin v0.33.1`。两条工作流自动跑: - `.github/workflows/release.yml` → **GitHub Release**:游戏包 + Windows 安装 / 便携版 + Linux AppImage + macOS dmg + 更新清单; - `.github/workflows/release-gitee.yml` → **只构建** Gitee 渠道的游戏包和 Windows 安装包,存成 artifact,不往 Gitee 推。 然后在**本机**:`GITEE_TOKEN=<令牌> bash scripts/gitee-publish.sh vX.Y.Z`(推代码和标签、建发行版、传附件、核对、删旧安装包,见 9.4)。 4. 等两边都绿,核对两边的附件齐全(GitHub `gh release view vX`;Gitee 看发行版页面)。 5. **npm 手动发**(CI 不发): ```bash cd code && npm login && npm publish --access public && npm view dsh-piggy version cd packages/dsh-plugin-piggy && npm publish --access public && npm view dsh-plugin-piggy version ``` 以上命令用于正式版。预发布(例如 `0.37.1-rc.1`)两包均用 `npm publish --access public --tag rc`,不要覆盖稳定 `latest`;先主包、再别名包。已经发过的版本号不能再发。 ### 9.3 在线扩展发版 1. 改扩展、升 `manifest.json` 版本。 2. 用 `node scripts/extension-entry.mjs `(及 `--host gitee`)更新两份目录,再运行 `node scripts/official-extensions.mjs`;用 `node scripts/extension-bundle.mjs ` 生成 `dist/ext--<版本>.piggyext`。先在候选提交上发布附件,核验后再公开 main 的目录。 3. GitHub 使用 `gh release create ext--<版本> dist/ext--<版本>.piggyext --target <候选提交> --prerelease --latest=false`;Gitee 从本机推对应标签,再用 `scripts/gitee-release.mjs ensure` / `upload` 发布。同[扩展指南](guides/writing-extensions.md#发版):`minGame >= 0.36.1` 只传一个 `.piggyext`;兼容更旧游戏的版本还必须上传 `manifest.json`、`server.js`、`client.js`,并将声明的图片平铺为附件。GitHub 扩展始终预发布且不设 latest,不能抢游戏正式版入口。 4. 提交两个 registry 文件和官方清单、推 main(GitHub 和 Gitee 的 main 都要有:本机 `git push gitee main`)。 5. 新附件刚传上去约 1 分钟后才能下载;用全新存档实际在线装一次验证。 ### 9.4 两个发布渠道(GitHub / Gitee) - 规则:**GitHub 那套保持原样;Gitee 是独立的一套**——Gitee 发出去的游戏包和外壳,检查更新、下载游戏包、在线扩展只走 gitee.com,不能依赖 GitHub(用户明确要求)。 - 地址集中在 `channels/github.js`、`channels/gitee.js`;`node scripts/set-channel.mjs ` 复制成 `channel.js` 和 `apps/desktop/lib/channel.js`。**仓库里提交的永远是 github**(`test/channel.test.js` 守着)。 - Gitee 工作流先用默认渠道跑测试,再切 gitee 打包,构建后用 `scripts/scan-channel.mjs` 扫描,发现 GitHub 地址就失败。 - Gitee 限制:发行版附件**单个 ≤ 100MiB(104,857,600 字节,实测)**、单仓库附件**总量 ≤ 1GB**。所以 Gitee 安装包另有瘦身:`apps/desktop/electron-builder.gitee.cjs`(最大压缩、只留中英文语言包)、`tools/slim-emoji-font.py`(emoji 字体只留用到的)。**Gitee 只发 Windows 安装包**(用户 2026-10-10:「gitee 不发 linux 和 mac 了」),Linux / macOS 只在 GitHub;游戏包照样每版都发,已装 Gitee 版的 Linux / mac 外壳仍能在 App 里更新游戏。当前大小(0.35.0 / 外壳 0.6.4):Windows 92.7MiB(**不带游戏**,见下)。0.35.0 是最后一个在 Gitee 带 Linux / mac 安装包的版本,下次发版的清理步骤会把它们当旧安装包删掉。超限的文件 CI 不上传并给警告。发版后自动删除旧版本的安装包附件(游戏包保留)。 - **Gitee 一律从维护者本机推**(用户 2026-10-07 定):GitHub Actions 不再碰 Gitee(机房连 Gitee 经常卡死或被重置,旧流程的清理步骤还在上传失败时删了旧安装包,Gitee 一段时间没有安装包可下)。 流程:CI 构建出 artifact(`gitee-game`、`gitee-dist-<系统>`)→ 本机 `GITEE_TOKEN=<令牌> bash scripts/gitee-publish.sh vX.Y.Z`: 等构建成功、下载 artifact、核对 `latest*.yml` 的 sha512 和安装包一致 → `git push gitee main` 和标签 → 建发行版、传游戏包和安装包、最后传更新清单 → 核对 Gitee 上每个附件的名字和大小 → **全对了才**删旧版本的安装包。某次构建上传那步被取消但产物还在时,用 `--run ` 指定。 令牌由维护者在命令里给,不存文件、不放 GitHub Secrets 之外的地方。 - **Gitee 的 Windows 安装包不带游戏**(2026-10-09 用户定,外壳 0.6.3 起):Windows 包离 100MiB 只剩约 0.5MiB,加图就超。 CI 的 Windows 任务先取本次的 `gitee-game`,用 `apps/desktop/scripts/write-game-pin.mjs` 写 `game-pin.json`(版本、manifest、 `/v<版本>/<文件>`)放进安装包(`electron-builder.gitee.cjs` 里 win 只带它,linux/mac 照旧带 `game/`)。 外壳启动时没有能跑的游戏就弹下载窗口(`apps/desktop/first-run.js`),装好再开猪;换外壳版本时继续用已下载的游戏(没有自带的可回)。 ⚠️ 所以 **Gitee 发行版必须先把游戏包传上去**,不然新装的 Windows 用户第一次打开会 404(`gitee-publish.sh` 本来就先传游戏包)。 - **游戏包分卷**:`release-game.mjs` 生成的整包超过 95MiB 时自动拆成 `game-<版本>.part-01.gz`…,manifest 里 `parts` 记顺序和校验值, minShell 自动抬到 0.6.3;`gitee-publish.sh` 按 `game-*` 一起上传。外壳逐卷下载、逐卷校验、拼起来再校验整包。 - Gitee 的原始文件地址(raw)会 302 跳到 `raw.giteeusercontent.com`,附件会跳到 `foruda.gitee.com`,fetch 默认跟随即可。 --- ## 10. 账号、密钥、外部服务 | 什么 | 在哪 / 谁管 | |---|---| | GitHub 仓库 | `CLICGGER-TYPES/dsh-piggy`(用户账号,本机 `gh` 已登录) | | Gitee 仓库 | `clicgger/dsh-piggy`(公开) | | `GITEE_TOKEN` | Gitee 私人令牌,维护者本机发 Gitee 时在命令里给(GitHub Secrets 里那份已不再被工作流使用,可以删)。**不要写进仓库、文档或日志** | | npm | 包 `dsh-piggy`、`dsh-plugin-piggy`,由用户在本机 `npm login` 后手动发布 | | 社区目录 | [dsh-plugin.org](https://dsh-plugin.org) 收录 Issue、[awesome-dsh-plugin](https://github.com/bruc3van/awesome-dsh-plugin) 自荐 PR(第三方维护,不是官方市场) | | 音乐素材 | 宣传片 BGM 用 Mixkit 免费曲库(Mixkit Stock Music Free License) | --- ## 11. 和用户协作的约定(历次反馈总结) - **先设计、再动手**:大功能先出完整设计 / 数值单给用户确认;修 bug 的版本只修 bug,新功能不要预留或半做。 - **数值、玩法、台词必须用户拍板**;确认过的数字不改,有意见写在任务卡里等用户定。 - **不擅自改界面排版**:规则变了不顺手改布局;改布局先问。界面改版要有肉眼可见的变化,最好出两三个方向让用户挑。 - **面板要简洁**:不加刻度条、说明性废话;状态条只在货架里;跳转后返回来处。 - **说话要实**:没核实的事别说「已完成」;自测(真实浏览器 / 桌面像素)过再报完工;做不到、没做的要直说。 - **给路径用绝对路径**,并说明在哪个分支 / 目录。 - **验收通过后再发版**;别频繁发测试版;能不升外壳就不升。 - **提交规矩**:`type(scope): 中文描述`、不加 AI 署名、功能变了改 README、发版写全 CHANGELOG(见 [CONVENTIONS](CONVENTIONS.md)「Git」)。 - 用户自己常在 3080 的 DSH 里玩,测试别占它的端口、别改它的存档。 --- ## 12. 已知问题与待办 **统一记在 [ROADMAP.md](ROADMAP.md)**(当前版本、进行中、待用户决定、技术待办、未解决的用户反馈、已定下来别再改的事)。这里不再另记,免得两边对不上。 --- ## 13. 常见坑 - `client.js` 忘了重建 → `test/bundle.test.js` 失败。 - 改了扩展的 `manifest.json` / `server.js` / `client.js` 却没升版本、没重算目录 → 校验值对不上,玩家下载失败。用 `node scripts/extension-entry.mjs [--host gitee]` 重算两份目录里那一条。 - 游戏里加了新 emoji 没重新裁网页版字体 → 网页上显示系统表情或方框。`test/emoji-coverage.test.js` 会报,按它开头的命令重新裁。 - 往桌面测试虚拟机 rsync 代码会把 Electron 的 `chrome-sandbox` 权限冲掉,启动报 SUID sandbox:要 `sudo chown root` 加 `chmod 4755` 改回来。 - `cordis.patch.yml` 的 `name` 和 package.json `name` 不一致 → 插件前端静默不挂载。 - 网页里 `window.confirm()` 会冻住页面;DSH 面板里不要用原生弹窗。 - 在线扩展 GitHub Release 忘了 `--prerelease --latest=false` → 「最新正式版」被扩展抢走,更新检查出错。 - 桌面版改了外壳代码却没升外壳版本 → 用户只更新游戏包拿不到修复。 - 截图验证大文件要等几秒再截,否则截到加载中的空白。 - DSH 本身更新后要 `pnpm install && pnpm build`,否则启动时会报找不到 `lib/*.js`。 - **桌面版几何的验收只看一条:猪的屏幕点有没有动**(点猪、开关面板、重启前后差 ≤2px)。「窗口在工作区内」「核对 0 次不符」「测试全绿」都不等于猪没动——2026-10-06 就是这么三次误判「修好了」。改完跑 `tools/desktop-geometry-check.mjs`,它跑不过就是没修好;在 GNOME(Wayland)桌面上它会用 `tools/gnome-pointer.py` 真鼠标拖(别在自己正用的机器上跑真拖,放虚拟机)。多屏、Windows 还要人工在真机上试。 - 桌面版是两个窗口(`docs/archive/tasks/I-round.md` 第 15 节):面板改动不许影响猪窗口的大小;猪窗口里「家」模型(第 13 节)仍然是每轮从头算窗口,**不要再加「记住上一轮」「核对补正」之类的记账**。 - 桌面拖动的验收要**真鼠标拖 + 录屏逐帧看**(`tools/drag-film.py`):只看起止坐标看不出「拖到边上猪停住、松手瞬移」「拖动中猪消失一段」,这两个都是只在中间帧里出现的真 bug(2026-10-07)。 - 桌面页面里 `piggyShell.place({})` 回读的窗口尺寸在 setBounds 后立刻就是新的,但页面要等 resize 才重排:两者对不上的那一拍不能量(`index.js` 的 `layoutStale`),否则算出的猪位置差一个尺寸变化量。 --- ## 14. 文档索引 - 玩家:[怎么玩](guides/gameplay.md) · [桌面版](guides/desktop.md) · [更新机制](guides/updates.md) · [换肤](guides/skins.md) · [做皮肤](guides/creating-skins.md) · [皮肤包格式](guides/skin-pack-format.md) - 入口:[AGENTS.md](../AGENTS.md) - 怎么加 X:[写扩展](guides/writing-extensions.md) · [加台词](guides/adding-lines.md) · [加成就](guides/adding-achievements.md) · [界面规范](guides/ui-style.md) · [桌面架构与 IPC](guides/desktop-architecture.md) - 开发:[开发指南](DEVELOPMENT.md) · [编码规范](CONVENTIONS.md) · [设计说明](DESIGN.md) · [美术规格](ART-SPEC.md) · [扩展下载](design/extension-download.md) · [扩展成就](design/extension-achievements.md) · [扩展中心设计](design/extension-center.md) · [日志与导出](design/log-export.md) - 规划与素材:[路线图与待办](ROADMAP.md) · [素材总表](ASSETS.md) · [数值单](numbers/) · [经济设计](design/economy.md) · [扩展自动化(K1)](design/automation.md) - 历史:[CHANGELOG](../CHANGELOG.md) · [任务卡](archive/tasks/README.md) · [数值单](numbers/) · [开发过程记录](archive/PROCESS.md) · [旧交接 2026-10-03](archive/HANDOFF-2026-10-03.md)