Files
ChronicleOfTheImmortalClan/AGENTS.md
T
thzxx c09395a6d4 v0.1.8: 万物皆是插件 + 全应用审计修复(60+ 缺陷歼灭)
插件协议:
- CotycPlugin Manifest(dependencies/conflicts/protected/install/uninstall)
- PluginManager:安装序确定性/依赖拒绝/异常回滚/追踪型上下文(卸载全摘钩子)
- 三核心插件常驻(Systems/Data/Events);插件清单/安装移除/启停广播
- EventPoolRegistry 多池合并;facade about/query('plugins')/plugin 订阅
- 设置页插件清单(含卸载按钮、核心保护);examplePlugin 开发范本入仓

全应用审计修复(引擎 39 + UI/主进程 40 双路清单,P0→P2 歼灭):
- P0:单亲 rollRoots 崩/插件事件软锁(findEvent 查池)/fire 覆盖幸存事件/
  facade 未赋值(act 目录 6/24 生效→全量接通)/packOverride 死实现真接管/
  4 能力卡无接线(trib/apprentice/tournament/season)/读档 rowid 方言崩溃/
  buildApprentice 空候选崩/插件安装无回滚/trait 加成从未消费/DEV 双跑破坏时序
- P1:定时器幸存/advance in-flight 闸/battle 暂停/tournament 点将真传/
  史书 memo 依赖/面板 hooks 顺序违规/远征 squad 残留 id/跨档状态残留/
  toast 自清除/读档错误提示/导入后重载世界/pendingEvent 读档回填
- P2:版本三处统一/NewGame 随机收编/学费错误文案/姓氏池去重/
  功法品阶错位(凡阶哨兵)/功法定价对齐/market 白名单校验/
  战利功法去重/回声漏封缄/clock 迭代快照/core 事件池保护/
  渡劫陨落走真突破/寄读 desc 诚实化/doas 死代码清理等 30 项

测试 239→256;金钟罩复验(防御批零漂移)
2026-08-23 09:58:15 +08:00

5.8 KiB
Raw Blame History

AGENTS.md

仙途家族志 · Chronicle of the Immortal Clan — Electron + React + TS 家族修仙模拟器。全部 UI 与文案为中文。

命令

npm test              # vitest 引擎测试(tests/*.test.ts,全部纯 Node,无 DOM/DB 依赖)
npx vitest run tests/world.test.ts     # 单文件测试
npm run typecheck     # tsc --noEmitnpm 会打 warn 噪音,用 npx tsc --noEmit 更干净)
npm run dev           # electron-vite 热更新(开发期 origin 为 http://localhost:5173
npm run build         # 产物到 out/
npm run package       # build + electron-builderLinux 打 win 包可出产物,但未签名,Windows 上可能被 SmartScreen 静默拦截;正规发布在 Windows 侧重跑此命令)

端到端冒烟(渲染 + OPFS 数据库 + 开局推进 + 可选截图):

npm run build
SMOKE_TEST=1 npx electron out/main/index.js --no-sandbox --disable-gpu   # 退出码 0 = 全通
SMOKE_TEST=1 SMOKE_SHOTS_DIR=/tmp/opencode/shots npx electron ...        # 附带 UI 截图

冒烟会写真实用户数据目录(Linux 下 ~/.config/Electron),跑完删掉该目录以免脏数据。 无显示环境(WSLg 掉线)会打印 [SMOKE-TIMEOUT] 退出码 2 而非卡死;GUI 冒烟必须在 X11/WSLg 在线时跑(引擎与存储逻辑的回归请靠 vitest,不要依赖 GUI)。另注意:npx electron 可能拉取新版 electron 缓存版(与本仓库 33.x 不同),二进制安装以 node_modules/electron 为准。

环境坑

  • npm 12 拦截 postinstall:首次安装后须 npm install-scripts approve electron esbuild,否则 Electron 二进制缺失。
  • npm rebuild electron esbuild 会删掉 node_modules/electron/dist/electronLinux 二进制),修复: ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ node node_modules/electron/install.js
  • 私有 registry 的 _auth token 只在用户级 ~/.npmrc;项目 .npmrc 只保留 registry 映射,不要把 token 写进仓库。
  • Linux 无 emoji 字体:所有图标一律用汉字印章字符renderer/ui/styles.css 的 .s-icon/.res-icon/.bld-icon),不要引入 emoji。

插件架构(0.1.8 起)

  • 万物皆是插件core/plugin.ts 协议(Manifest/dependencies/conflicts/install/uninstall);engine/pluginManager.ts 安装管线(依赖校验、异常回滚、追踪型上下文——插件注册的时轮钩子卸载时全摘);engine/plugin-bootstrap.ts 三枚常驻核心插件(core-systems/core-data/core-eventsprotected 不可卸)。
  • 事件多池world.eventPoolscore 池受保护不可删)+ eventRoll 聚合抽样;第三方插件 ctx.addEventPool(id, events) 即注入内容。注意 findEvent 必须带 world 参数查池events.ts),否则未知事件直接软锁。
  • 能力卡engine/capabilities.ts 12 张;时钟注册走 viaCaptournament/tribulation/apprentice/season 四卡各自内部检查 w.sysEnabled(无独立钩子,勿直接调)。
  • 门面engine/api.ts GameFacadeact 24 项/query 6 类/subscribe 退订协议/about);UI store 的 facade 字段必须通过 openState/startNewGame 赋值,否则 act 走残缺 fallback。
  • 金钟罩:0.1.8 修复批次后三指纹 9af71ecb / 63cede89 / ebfec4a4(受控变更已在注释记录)。

架构要点

  • src/renderer/game/:纯 TS 游戏引擎(无 React/DOM import),可被 vitest 直接测试;types/domain.ts 是全量领域类型,改状态结构先看它。
  • 统一时轮 core/clock.ts:月度 phaseproduction/aging/cultivation/missions/events/diplomacy/epilogue+ 年首钩子均注册于 engine/clocks.ts新增系统 = 注册一行,禁止手改 advanceMonth 本体
  • 统一随机 core/rng.ts:引擎只经 World.rng(含 nextCount 审计);UI 播种用 RngHub.rollSeed()、音效白噪用 RngHub.audioNoise01()不要在逻辑里引入 Math.random()。
  • 金钟罩 tests/clock.test.ts:3 枚固定 seed 560 月指纹常驻(0.1.8 基线:9af71ecb/63cede89/ebfec4a4)。任何改动若破坏确定性立即红;有意变更时序时三枚指纹一并小重算并在注释注明原因(0.1.6 加时节、0.1.8 加特征/利己/飞升窗口时曾受控重算)。
  • src/renderer/ui/React + zustandui/store.ts)。World 的 game state 是 mutableadvance 后 revision++ 触发重渲染;订阅 revision 是面板刷新惯例。
  • 引擎 = 种子随机数(sfc32core/rng.ts+ 不可变快照存 state.rng,同 seed 全程可重放(tests/world.test.ts 有确定性用例,改任何 tick 顺序都要保证仍然确定性)。
  • 建档开头成员 id 硬编码 x1~x5tests 依赖。

MetonaSqlark@metona-team/metona-sqlark 0.7.4)陷阱

  • SQL 方言为自有实现(不是 SQLite):建表列类型写 string|number|boolean|date|json不是 INTEGER/TEXT;不支持 INSERT OR REPLACEON CONFLICTrowid——用「SELECT 判断 → UPDATE/INSERT」或直接 DELETE+INSERT
  • aria 引擎同库一个 tab 只能建一次连接(Web Locks → ARIA_LOCKED):存取必须走 game/storage/db.ts 的单例 getSaveSlot(slot) / getSlotManager()禁止每次 new SaveSlot/new SlotManager
  • 数据在浏览器 OPFSrenderer 内),main 进程无 DB 逻辑;开发与打包后的 origin 不同,两环境存档不互通。
  • 存储层通过 SaveDbDriver 抽象(storage/slots.ts),node 环境下无 OPFS,测试只覆盖引擎不覆盖 DB。

工作流约定

  • 提交前:npm test + npm run typecheck 必须绿(改存储/SQL 后再跑一次冒烟)。
  • 平衡数值集中在 game/data/realms/pacing/buildings/events...),调平衡不改引擎流程。
  • 发布产物 release/out/ 均已 gitignore,勿入库。