diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index bdac378..7af2af1 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -547,37 +547,46 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 7. 数据端缺陷修复 | 15/16 | Complete(07-16 superseded) | - | | 8. 测试重构与接口对齐 | 11/11 | Complete | 2026-10-08 | | 9. 最小浏览器可运行版本 | 15/16 | In Progress| | -| 10. 文档重构 | 0/20 | Planned | - | +| 10. 文档重构 | 17/27 | In Progress | - | ### Phase 10: 文档重构 -**Goal:** 重构过老、结构不佳、新人难懂的项目文档,面向多背景读者(完全新手 / 不懂代码的作者 / 有基础的作者 / AI Agent)提供分层指南。本阶段采用「伞阶段 + 增量派发」:每次只规划执行一个已派发的具体小任务。**第一批已派发 = 中级教程(`docs/intermediate/`,24 篇中文 markdown)+ 在 VitePress 站点注册它们 + 旧内容清空(D-04 并入本批)**(D-01..D-44)。**第二批已派发 = 高级教程 I(`docs/advanced/`,7 篇数据端文档)+ 站点注册 + 独立读者人格审阅 + 用户主导修订循环**(D-53..D-57)。 -**Requirements**: (无专属需求 ID;以 `10-CONTEXT.md` 的 D-01..D-57 为需求基线,验收锚在 D-09:用户人工审阅 + 链接全部有效 + 构建通过) +**Goal:** 重构过老、结构不佳、新人难懂的项目文档,面向多背景读者(完全新手 / 不懂代码的作者 / 有基础的作者 / AI Agent)提供分层指南。本阶段采用「伞阶段 + 增量派发」:每次只规划执行一个已派发的具体小任务。**第一批已派发 = 中级教程(`docs/intermediate/`,24 篇中文 markdown)+ 在 VitePress 站点注册它们 + 旧内容清空(D-04 并入本批)**(D-01..D-44)。**第二批已派发 = 高级教程 I(`docs/advanced/`,7 篇数据端文档)+ 站点注册 + 独立读者人格审阅 + 用户主导修订循环**(D-53..D-57)。**第三批已规划(暂定,待用户批准后执行)= 高级教程 II「深入定制」(`docs/advanced/ii/`,9 篇数据端文档)+ 站点注册 + 独立读者人格审阅 + 用户主导修订循环**(D-67)。 +**Requirements**: (无专属需求 ID;以 `10-CONTEXT.md` 的 D-01..D-67 为需求基线,验收锚在 D-09:用户人工审阅 + 链接全部有效 + 构建通过) **Depends on:** Phase 9 -**Plans:** 20 plans(第一批:中级教程 24 篇 + 站点注册 + D-09 复审修订;第二批:高级 I 7 篇 + 注册 + 读者审阅 + 用户修订循环) +**Plans:** 17/27 completed(第一批:中级教程 24 篇 + 站点注册 + D-09 复审修订;第二批:高级 I 7 篇 + 注册 + 读者审阅 + 用户修订循环;第三批:高级 II 9 篇 + 注册 + 读者审阅 + 用户修订循环)。**未完成 10 个**:`10-06`(中级全批验收)、`10-11`(中级读者审阅)、`10-12`(中级最终验收)——其范围已被后续 D-09 修订与高级 I 期间的最终状态覆盖,缺独立 SUMMARY,待补跑或并入后续验收;`10-21`..`10-27`(高级 II)为暂定规划,待用户确认文件名、侧边栏分组名后执行。 Plans: -- [ ] 10-01-PLAN.md — Wave 0:旧内容清空 + 站点注册(删除 `docs/guide`、`docs/dev`、`docs/logger`、`docs/api` 与首页 `docs/index.md`;清理 `config.ts` 旧 nav/sidebar 键并解除 apiSidebar/api 依赖;`api.ts` 加缺失目录守卫;新增 nav 入口 + `sidebar['/intermediate/']` 4 组/24 条;报告并等待 checkpoint) -- [ ] 10-02-PLAN.md — 概念与导航 4 篇(`data-vs-render` / `src-tour` / `code-basics` / `hooks`) -- [ ] 10-03-PLAN.md — 基础接口 8 篇(`data-state-overview` … `flags`) -- [ ] 10-04-PLAN.md — 战斗 9 篇(`combat-overview` + 8 篇子系统;N-1/N-2/N-3/N-7 留余地) -- [ ] 10-05-PLAN.md — 其他 3 篇(`events` / `replay-commands` / `data-plugins`) +- [x] 10-01-PLAN.md — Wave 0:旧内容清空 + 站点注册(删除 `docs/guide`、`docs/dev`、`docs/logger`、`docs/api` 与首页 `docs/index.md`;清理 `config.ts` 旧 nav/sidebar 键并解除 apiSidebar/api 依赖;`api.ts` 加缺失目录守卫;新增 nav 入口 + `sidebar['/intermediate/']` 4 组/24 条;报告并等待 checkpoint) +- [x] 10-02-PLAN.md — 概念与导航 4 篇(`data-vs-render` / `src-tour` / `code-basics` / `hooks`) +- [x] 10-03-PLAN.md — 基础接口 8 篇(`data-state-overview` … `flags`) +- [x] 10-04-PLAN.md — 战斗 9 篇(`combat-overview` + 8 篇子系统;N-1/N-2/N-3/N-7 留余地) +- [x] 10-05-PLAN.md — 其他 3 篇(`events` / `replay-commands` / `data-plugins`) - [ ] 10-06-PLAN.md — 全批验收(构建通过 + 链接有效 + 交付 D-09 人工审阅) -- [ ] 10-07-PLAN.md — 目标性修正:D-09 复审 finding 1/3/4(讲清 `state` 获取、清除 legacy 泄漏 + 全批扫描、纠正修饰器定位;仅改 4 篇) -- [ ] 10-08-PLAN.md — 战斗组引导式·入门友好重写 finding 2/5(`combat-overview` 讲清「计算后怪物 / 为什么要 buildup / 为什么分阶段」+ 7 篇子系统;8 篇) -- [ ] 10-09-PLAN.md — 概念组 + 「其他」组引导式重写 finding 5(`src-tour`/`code-basics`/`hooks`/`events`/`replay-commands`/`data-plugins`;6 篇) -- [ ] 10-10-PLAN.md — 基础接口组引导式重写 finding 5(`hero-items`/`hero-equipment`/`hero-location`/`map-structure`/`map-tiles`/`flags`;6 篇) +- [x] 10-07-PLAN.md — 目标性修正:D-09 复审 finding 1/3/4(讲清 `state` 获取、清除 legacy 泄漏 + 全批扫描、纠正修饰器定位;仅改 4 篇) +- [x] 10-08-PLAN.md — 战斗组引导式·入门友好重写 finding 2/5(`combat-overview` 讲清「计算后怪物 / 为什么要 buildup / 为什么分阶段」+ 7 篇子系统;8 篇) +- [x] 10-09-PLAN.md — 概念组 + 「其他」组引导式重写 finding 5(`src-tour`/`code-basics`/`hooks`/`events`/`replay-commands`/`data-plugins`;6 篇) +- [x] 10-10-PLAN.md — 基础接口组引导式重写 finding 5(`hero-items`/`hero-equipment`/`hero-location`/`map-structure`/`map-tiles`/`flags`;6 篇) - [ ] 10-11-PLAN.md — 读者视角审阅(persona 子代理)→ 问题清单 → 迭代修正(≤3 轮)→ 复审清零 - [ ] 10-12-PLAN.md — 最终验收:修订后重跑全批验收 + D-09 复审(重跑 10-06 Task 2 门禁) -- [ ] 10-13-PLAN.md — 高级 I 第一篇:声明式 vs 命令式接口(地基;旧样板命令式 vs 新样板声明式 + 通用模板) -- [ ] 10-14-PLAN.md — 高级 I 第二篇:插件系统(自定义插件、插件互调、依赖排序、生命周期、id 稳定性与迁移) -- [ ] 10-15-PLAN.md — 高级 I 第三篇:可存档内容(`ISaveableContent`、三级压缩、注册、存档顺序 / 执行器、跨对象引用、structured-cloneable) -- [ ] 10-16-PLAN.md — 高级 I 第四、五篇:录像一致性(`@shouldReplay` / `@ignoreReplay`)+ data-common 的 Store(内容层原始数据、运行时只读) -- [ ] 10-17-PLAN.md — 高级 I 第六篇:钩子深入(多对象 / 身份校验 / 复用 / 注册移除 / 异步钩子) -- [ ] 10-18-PLAN.md — 高级 I 导览 + 站点注册(`docs/advanced/index.md`、`config.ts` 的 nav / sidebar、六篇互链收口 + 全量构建) -- [ ] 10-19-PLAN.md — 高级 I 独立读者人格审阅(不同于中级人格)→ 问题清单 → 迭代修正(≤3 轮)→ 复审清零 -- [ ] 10-20-PLAN.md — 高级 I 用户主导修订循环 → 用户确认 → 最终格式 / 构建 / SUMMARY 收尾 +- [x] 10-13-PLAN.md — 高级 I 第一篇:声明式 vs 命令式接口(地基;旧样板命令式 vs 新样板声明式 + 通用模板) +- [x] 10-14-PLAN.md — 高级 I 第二篇:插件系统(自定义插件、插件互调、依赖排序、生命周期、id 稳定性与迁移) +- [x] 10-15-PLAN.md — 高级 I 第三篇:可存档内容(`ISaveableContent`、三级压缩、注册、存档顺序 / 执行器、跨对象引用、structured-cloneable) +- [x] 10-16-PLAN.md — 高级 I 第四、五篇:录像一致性(`@shouldReplay` / `@ignoreReplay`)+ data-common 的 Store(内容层原始数据、运行时只读) +- [x] 10-17-PLAN.md — 高级 I 第六篇:钩子深入(多对象 / 身份校验 / 复用 / 注册移除 / 异步钩子) +- [x] 10-18-PLAN.md — 高级 I 导览 + 站点注册(`docs/advanced/index.md`、`config.ts` 的 nav / sidebar、六篇互链收口 + 全量构建) +- [x] 10-19-PLAN.md — 高级 I 独立读者人格审阅(不同于中级人格)→ 问题清单 → 迭代修正(≤3 轮)→ 复审清零 +- [x] 10-20-PLAN.md — 高级 I 用户主导修订循环 → 用户确认 → 最终格式 / 构建 / SUMMARY 收尾 +- [ ] 10-21-PLAN.md — 高级 II 基础篇:自定义范围对象(`IRange` / 参数 / 绑定宿主)+ 静态与动态图块(含点事件与图块事件) +- [ ] 10-22-PLAN.md — 高级 II 系统篇:勇士的装备系统(实例仓 / 修饰器 / 排序器 / `compareEquip` / 装备事件)+ 自定义录像指令(指令码 / `IReplayCommand` / 主动被动 / 沙盒) +- [ ] 10-23-PLAN.md — 高级 II 流程与属性篇:自动寻路(只讲流程)+ 新增勇士属性(攻速 / 护甲接入伤害计算) +- [ ] 10-24-PLAN.md — 高级 II 怪物篇:新增怪物属性 + 怪物上下文与战斗深入(buildup / 优先级 / 脏标记 / 伤害系统) +- [ ] 10-25-PLAN.md — 高级 II 导览 + 侧边栏注册(`/advanced/ii/` 九篇、分组名待用户确认)+ 互链与全量构建 +- [ ] 10-26-PLAN.md — 高级 II 独立读者人格审阅(高代码能力人格,不同于高级 I)→ 问题清单 → 迭代修正(≤3 轮)→ 复审清零 +- [ ] 10-27-PLAN.md — 高级 II 用户主导修订循环 → 用户确认 → 最终格式 / 构建 / SUMMARY 收尾 **说明:** 每篇中级教程遵循 `10-CONTEXT.md` D-21..D-44 的逐篇要点与阅读顺序(4/8/9/3)。**旧内容删除已并入本批(D-04,Wave 0 / 10-01)**:删除 `docs/guide/*`、`docs/dev/*`、`docs/logger/*`、`docs/api/*` 与首页 `docs/index.md`,并清理 `docs/.vitepress/config.ts` 的旧 `nav`/`sidebar` 键。文档改动为 `docs/intermediate/*.md`(新增)、`docs/.vitepress/config.ts` 与 `docs/.vitepress/api.ts`(缺失目录守卫,保留按包生成机制)。构建命令 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`;`init.ts` 在 `docs/api/` 缺失时安全跳过。本机 PowerShell 禁止 `pnpm.ps1`,命令经 `cmd /c "..."` 执行。 **高级 I 说明:** 第二批(10-13..10-20)只写**数据端**内容,不含渲染端;七篇文件名与侧边栏显示名以各计划 Task 0 的用户确认为准(D-13)。指向高级 II / III 的内容一律使用代码 span 或 HTML 注释占位,不写真实链接(D-47)。每篇保留「怎么验证」小节,并按 D-48 六步 / D-49 改内置优先 / D-50 模板独立 / D-51 落点与副作用 / D-52 加粗边界执行。构建命令同上;10-18 负责站点注册与全量链接收口,10-19 / 10-20 分别执行独立读者人格审阅与用户主导修订循环,**用户明确确认后方可收尾**(D-46 第 2 阶段 / D-57)。 + +**高级 II 说明(暂定):** 第三批(10-21..10-27)按 D-67 定位为「深入定制」难度层,只写**数据端**内容;拟建 `docs/advanced/ii/` 九篇(导览 + 8 个主题),文件名与侧边栏分组名以各计划 Task 0 的用户确认为准(D-13),当前建议分组名为「高级 II · 深入定制」。写作按 D-59 库文档风格(不套用中级六步)、D-60 简洁、D-61 主干与边界分离、D-62 代码块完整、D-63 模板顺序、D-64 只在需实现接口时给模板、D-65 注释充足、D-66 并列功能分开示例;不写中级特有的「改内置还是自己写」提示(D-58),新增系统优先插件(D-55)。渲染端、编辑器、状态栏与怪物图鉴按 D-47 用非断链占位;高级 III 只用代码 span 或 `TODO(advanced-III)` 注释。10-25 负责导览、站点注册与全量链接收口;10-26 使用比高级 I 更高的独立读者人格(能读懂引擎源码、想做系统级定制但不熟悉具体系统实现),10-27 执行用户主导修订循环,**用户明确确认后方可收尾**(D-46 第 2 阶段)。构建命令同上。 diff --git a/.planning/STATE.md b/.planning/STATE.md index 6cdaf1e..512c04e 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,19 +1,19 @@ --- gsd_state_version: "1.0" milestone: v1.0 -current_phase: 9 -current_phase_name: 最小浏览器可运行版本 +current_phase: 10 +current_phase_name: 文档重构 status: executing -stopped_at: Phase 08 complete, ready to plan Phase 1 -last_updated: "2026-10-09T06:58:38.694Z" -last_activity: 2026-10-08 -last_activity_desc: Phase 08 complete, transitioned to Phase 1 +stopped_at: Phase 10 进行中:中级教程 24 篇 + 高级 I 7 篇已收尾;10-06/10-11/10-12 待补 +last_updated: "2026-10-20T00:00:00.000Z" +last_activity: 2026-10-20 +last_activity_desc: 高级 I(docs/advanced 7 篇)完成并经用户确认收尾 state_head: dbbcf533dce2f22078a82d26817f36b85865da62 progress: - total_phases: 9 + total_phases: 10 completed_phases: 3 - total_plans: 102 - completed_plans: 97 + total_plans: 122 + completed_plans: 114 milestone_name: milestone --- @@ -24,16 +24,16 @@ milestone_name: milestone See: .planning/PROJECT.md (updated 2026-09-17) **Core value:** 引擎能完整跑通一部魔塔——开局到结局,存档、战斗、地图、事件、剧情全链路可玩。 -**Current focus:** Phase 08 — 测试重构与接口对齐 +**Current focus:** Phase 10 — 文档重构 ## Current Position -Phase: 9 (最小浏览器可运行版本) — READY TO EXECUTE -Plan: Not started -Status: Ready to execute -Last activity: 2026-10-08 — Phase 08 complete, transitioned to Phase 1 +Phase: 10 (文档重构) — IN PROGRESS +Plan: 第一批(中级教程 24 篇)与第二批(高级 I 7 篇)已收尾;10-06 / 10-11 / 10-12 待补 +Status: In Progress +Last activity: 2026-10-20 — 高级 I 完成并经用户确认收尾 -Progress: [████░░░░░░] 38% +Progress: Phase 10 · 17/20 plans(中级 + 高级 I 已收尾;总览 / 初级 / 高级 II·III / API / Agent 参考仍待推进) ## Performance Metrics @@ -266,6 +266,7 @@ Recent decisions affecting current work: - Phases 4/5/6 marked obsolete (2026-10-08): 渲染适配与双布局 / Legacy 移植 / 单元测试 的原规划不再合理,由 Phase 9 承接;仅文本标注,未删除阶段目录、已执行 PLAN/SUMMARY 或代码 - Phase 9 added (2026-10-08): 最小浏览器可运行版本(在已完成且 Node 可运行/回放验证的数据端之上完成渲染端框架,并验证可在浏览器上运行);Depends on Phase 8 - Phase 10 added (2026-10-14): 文档重构(重构过老、结构不佳、新人难懂的项目文档,面向新人/不懂代码的作者/有基础作者等多背景读者提供分层指南,并专门为 AI Agent 编写参考文档);Depends on Phase 9 +- Phase 10 第一批(中级教程 24 篇 + 旧内容清空 + 站点注册 + D-09 修订 + 读者/用户修订循环)已完成并收尾(2026-10-20);第二批(高级 I 7 篇 + 站点注册 + 独立读者审阅 + 用户 6 轮修订)已完成并经用户确认收尾(2026-10-20)。遗留 `10-06` / `10-11` / `10-12` 缺独立 SUMMARY,其范围已被后续修订覆盖 ### Pending Todos diff --git a/.planning/phases/10-docs-restructure/10-13-PLAN.md b/.planning/phases/10-docs-restructure/10-13-PLAN.md index ffd15ce..d022b06 100644 --- a/.planning/phases/10-docs-restructure/10-13-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-13-PLAN.md @@ -76,7 +76,7 @@ Output: 1 个新 markdown 文件。 Task 0: 向用户汇报本计划并等待「可以执行」 - 向用户汇报:**要做什么**(新建 `docs/advanced/` 并编写 `declarative-vs-imperative.md`,即「声明式 vs 命令式接口」)、**为什么**(这是高级 I 的地基,后续插件、存档、录像、钩子都依赖「执行时机由谁决定」这一层理解)、**大致怎么做**(先用旧样板命令式与新样板声明式并排对照,再用怪物特殊属性/光环、伤害计算器、道具效果、可存档对象、钩子五组事实说明「声明什么、引擎何时执行」,最后给通用模板、常见误区与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认两个新名称:文件名 `declarative-vs-imperative.md`、页面标题「声明式 vs 命令式接口」(D-13:文档目录/文件名与显示名须先获批)。停下等待用户明确回复「可以执行」四个字;未收到前不得创建目录或写任何文件。 + 向用户汇报:**要做什么**(新建 `docs/advanced/` 并编写 `declarative-vs-imperative.md`,即「声明式 vs 命令式接口」)、**为什么**(这是高级 I 的地基,后续插件、存档、录像、钩子都依赖「执行时机由谁决定」这一层理解)、**大致怎么做**(先用旧样板命令式与新样板声明式并排对照,再用怪物特殊属性/光环、伤害计算器、道具效果、可存档对象、钩子五组事实说明「声明什么、引擎何时执行」,最后给通用模板、常见误区与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认两个新名称:文件名 `declarative-vs-imperative.md`、页面标题「声明式 vs 命令式接口」(D-13:文档目录/文件名与显示名须先获批)。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的 `docs/advanced/declarative-vs-imperative.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得创建目录或写任何文件。 本计划内容:高级 I 第一篇「声明式 vs 命令式接口」。 阅读上面的「要做什么 / 为什么 / 大致怎么做 / 影响范围」四段,并确认文件名与页面标题;如不同意请直接给出替代名称。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 diff --git a/.planning/phases/10-docs-restructure/10-14-PLAN.md b/.planning/phases/10-docs-restructure/10-14-PLAN.md index 003009d..4a96557 100644 --- a/.planning/phases/10-docs-restructure/10-14-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-14-PLAN.md @@ -21,7 +21,7 @@ must_haves: - "讲清插件间调用:依赖参数收到的已解析插件对象、`state.getDataPlugin(id)` 的返回形状与状态判断;`dependencies` 是 id 字符串数组,方法参数是插件对象数组" - "讲清依赖排序与失败语义:拓扑序、独立插件的登记顺序、循环依赖、缺失依赖、下游被阻断;不把排序细节写成猜测" - "讲清生命周期进阶点:`awake` 在主对象构造期同步执行、`initialize` 在加载前、`afterLoad` 在加载后;两个异步阶段可阻塞加载" - - "讲清插件 id 稳定性与版本迁移:id 被依赖与存档标识引用,不能随意改名或复用;给出迁移时的最小做法" + - "讲清插件 id 稳定性与版本迁移:插件 id 会被其他插件的 `dependencies` 引用,不能随意改名或复用;区分插件 id(如 `data-shop-plugin`)与可存档 id(如 `@plugin/shop`)两套命名;给出迁移时的最小做法" - "含独立的「模板:一个插件的最小骨架」小节与至少一个基于现有插件的示例;class + new;写明「不懂代码优先改内置」;含「怎么验证」" - "数据端 only(正文不出现 `src/client`);高级 II/III 只用非断链占位;构建 green、dead link = 0" artifacts: @@ -74,7 +74,7 @@ Output: 1 个新 markdown 文件。 Task 0: 向用户汇报本计划并等待「可以执行」 - 向用户汇报:**要做什么**(编写 `docs/advanced/plugin-system.md`,把插件系统从中级的基础用法展开到能自行设计与维护插件)、**为什么**(D-53 把插件定为高级 I 的核心,后续存档、录像、钩子都挂在插件上)、**大致怎么做**(先讲最小插件与三个生命周期,再讲 `dependencies` 排序与失败语义、插件互调、注册与存档、id 稳定性与迁移,最后给独立模板、现有插件示例与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认文件名 `plugin-system.md` 与页面标题「插件系统」(D-13)。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 + 向用户汇报:**要做什么**(编写 `docs/advanced/plugin-system.md`,把插件系统从中级的基础用法展开到能自行设计与维护插件)、**为什么**(D-53 把插件定为高级 I 的核心,后续存档、录像、钩子都挂在插件上)、**大致怎么做**(先讲最小插件与三个生命周期,再讲 `dependencies` 排序与失败语义、插件互调、注册与存档、id 稳定性与迁移,最后给独立模板、现有插件示例与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认文件名 `plugin-system.md` 与页面标题「插件系统」(D-13)。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的 `docs/advanced/plugin-system.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 本计划内容:高级 I 第二篇「插件系统」。 阅读上面的四段说明,并确认文件名与页面标题;如不同意请给出替代名称。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 @@ -87,7 +87,7 @@ Output: 1 个新 markdown 文件。 Task 1: 编写 plugin-system.md 正文 docs/advanced/plugin-system.md - (1) 写 `docs/advanced/plugin-system.md`,单 H1 为「插件系统」。(2) 正文顺序:①插件解决什么问题——把一组相关对象与生命周期收拢,随数据端启动加装;回指 10-13 的「声明规则、引擎在合适时机执行」。②最小插件:`IDataPluginDefine` 成员表(`id`、`dependencies`、`awake`、`initialize`、`afterLoad`),一段 class 骨架;说明 `dependencies` 是依赖插件的 id 字符串数组,三个方法收到的是解析后的插件对象数组;说明 register 在 `src/data/plugin/list.ts` 的 `dataPlugins`。③三个生命周期进阶:结合 `CoreState` 的构造与 `load()` 讲清——`awake` 在主对象构造期同步执行(不能 `await`,适合装配对象、注册可存档内容);`initialize` 在加载开始前、可返回 Promise 并阻塞加载;`afterLoad` 在主对象加载完毕后、适合依赖加载内容的初始化;三个阶段都按依赖顺序执行。④`dependencies` 与排序:拓扑序;无依赖关系的插件按登记顺序进入同一阶段;循环依赖与缺失依赖会被记录并阻断,依赖它们的下游插件也不会初始化;不要在运行时改依赖;依赖尽量少。⑤插件之间怎么调用:优先用方法参数里的依赖插件对象;没有声明依赖时用 `state.getDataPlugin(id)`,注意返回 `null` 与 `status`;给一段读取依赖插件并调用其方法的短示例。⑥插件 id 稳定性与版本迁移:id 被其他插件的 `dependencies` 引用,也常被用作可存档 id 的一部分(如 `@plugin/...`);改名会让依赖找不到、旧存档找不到对应可存档内容;不要复用旧 id 表示新语义;迁移时保留旧 id 或提供迁移路径,不要悄悄改名。⑦注册与目录:插件放在 `src/data/plugin/` 下的独立目录(`plugin.ts` / `types.ts` / `state.ts` / `manager.ts` / `system.ts` / `index.ts` 是现有形状);在 `list.ts` 里 `new` 后加入数组;说明这是少数必须新建文件/目录的场景,因为插件本身就是一个独立单元。⑧「模板:一个插件的最小骨架」独立小节:`[模板]` / `[需改]` 标注 id、dependencies、awake 里的对象装配与 `state.addSaveableContent`、initialize/afterLoad 的用途;不要把商店插件当模板。⑨「示例:读一个现有插件」:以 `DataShopPlugin` 为真实例子逐段说明 `awake` 做了什么、为什么注册 `@plugin/shop`;以 `MainDataPlugin` 说明 `afterLoad` 读取加载后配置的用法;再给一个「插件 B 依赖插件 A 并调用 A 的方法」的短示例,标 `[需改]`。⑩「改内置还是自己写」:如果只是给现有插件加行为,优先改现有插件;只有独立成组的功能才新建插件;写明「如果你不怎么懂代码,建议直接改内置」。⑪常见错误:在 `awake` 里 `await`、把 `dependencies` 写成对象、依赖循环、用 `state.getDataPlugin` 却不判空、把插件 id 当显示名随意改、在插件里直接改其他系统的内部字段。⑫「怎么验证」:把插件加进 `dataPlugins` 后启动,确认三个时机按预期发生(可用 `state.emitTip` 或控制台输出做可观察信号);用 `state.getDataPlugin` 取回插件并检查 `status`;存档后读档,确认插件注册的可存档内容恢复;把依赖写错一次,确认插件没有被初始化并在控制台看到错误,然后改回。 (3) 适当加 3–5 处链接,只链已存在页面:`../intermediate/data-plugins.md`、`../intermediate/data-state-overview.md`、`./declarative-vs-imperative.md`。高级 II/III 的内容(如排序算法内部、插件生命周期与加载器的深层关系)用代码 span 或 HTML 注释,不写真实链接。(4) CRLF、单 H1、数据端 only、加粗符合 flanking。完成后运行 prettier `--write`。Commit:`docs(10-14): 编写插件系统`。 + (1) 写 `docs/advanced/plugin-system.md`,单 H1 为「插件系统」。(2) 正文顺序:①插件解决什么问题——把一组相关对象与生命周期收拢,随数据端启动加装;回指 10-13 的「声明规则、引擎在合适时机执行」。②最小插件:`IDataPluginDefine` 成员表(`id`、`dependencies`、`awake`、`initialize`、`afterLoad`),一段 class 骨架;说明 `dependencies` 是依赖插件的 id 字符串数组,三个方法收到的是解析后的插件对象数组;说明 register 在 `src/data/plugin/list.ts` 的 `dataPlugins`。③三个生命周期进阶:结合 `CoreState` 的构造与 `load()` 讲清——`awake` 在主对象构造期同步执行(不能 `await`,适合装配对象、注册可存档内容);`initialize` 在加载开始前、可返回 Promise 并阻塞加载;`afterLoad` 在主对象加载完毕后、适合依赖加载内容的初始化;三个阶段都按依赖顺序执行。④`dependencies` 与排序:拓扑序;无依赖关系的插件按登记顺序进入同一阶段;循环依赖与缺失依赖会被记录并阻断,依赖它们的下游插件也不会初始化;不要在运行时改依赖;依赖尽量少。⑤插件之间怎么调用:优先用方法参数里的依赖插件对象;没有声明依赖时用 `state.getDataPlugin(id)`,注意返回 `null` 与 `status`;给一段读取依赖插件并调用其方法的短示例。⑥插件 id 稳定性与版本迁移:插件 id 会被其他插件的 `dependencies` 引用(如 `data-shop-plugin`);改名会让依赖它的插件找不到它;不要复用旧 id 表示新语义;迁移时保留旧 id 或提供迁移路径,不要悄悄改名。注意插件 id 与可存档 id 是两套命名:插件 id 如 `data-shop-plugin`,它注册的可存档内容另有自己的 id(如 `@plugin/shop`),不要把两者混为一谈,也不要从插件 id 推断存档 id。⑦注册与目录:插件放在 `src/data/plugin/` 下的独立目录(`plugin.ts` / `types.ts` / `state.ts` / `manager.ts` / `system.ts` / `index.ts` 是现有形状);在 `list.ts` 里 `new` 后加入数组;说明这是少数必须新建文件/目录的场景,因为插件本身就是一个独立单元。⑧「模板:一个插件的最小骨架」独立小节:`[模板]` / `[需改]` 标注 id、dependencies、awake 里的对象装配与 `state.addSaveableContent`、initialize/afterLoad 的用途;不要把商店插件当模板。⑨「示例:读一个现有插件」:以 `DataShopPlugin` 为真实例子逐段说明 `awake` 做了什么、为什么注册 `@plugin/shop`;以 `MainDataPlugin` 说明 `afterLoad` 读取加载后配置的用法;再给一个「插件 B 依赖插件 A 并调用 A 的方法」的短示例,标 `[需改]`。⑩「改内置还是自己写」:如果只是给现有插件加行为,优先改现有插件;只有独立成组的功能才新建插件;写明「如果你不怎么懂代码,建议直接改内置」。⑪常见错误:在 `awake` 里 `await`、把 `dependencies` 写成对象、依赖循环、用 `state.getDataPlugin` 却不判空、把插件 id 当显示名随意改、在插件里直接改其他系统的内部字段。⑫「怎么验证」:把插件加进 `dataPlugins` 后启动,确认三个时机按预期发生(可用 `state.emitTip` 或控制台输出做可观察信号);用 `state.getDataPlugin` 取回插件并检查 `status`;存档后读档,确认插件注册的可存档内容恢复;把依赖写错一次,确认插件没有被初始化并在控制台看到错误,然后改回。 (3) 适当加 3–5 处链接,只链已存在页面:`../intermediate/data-plugins.md`、`../intermediate/data-state-overview.md`、`./declarative-vs-imperative.md`。高级 II/III 的内容(如排序算法内部、插件生命周期与加载器的深层关系)用代码 span 或 HTML 注释,不写真实链接。(4) CRLF、单 H1、数据端 only、加粗符合 flanking。完成后运行 prettier `--write`。Commit:`docs(10-14): 编写插件系统`。 $ErrorActionPreference='Stop'; $p='docs/advanced/plugin-system.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(? non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "MISSING-CONTENT", "RENDERER-CONTENT", "BOLD-FLANK", or "DEAD-LINK"; or output lacks "STATIC-OK" @@ -98,7 +98,7 @@ Output: 1 个新 markdown 文件。 Task 2: 源码核对、格式与构建收口 docs/advanced/plugin-system.md - 逐条核对正文与源码:`packages-user/data-state/src/types.ts`(`IDataPluginDefine` 的三个方法签名、`PluginStatus` 四个状态、`getDataPlugin` 的返回类型)、`packages-user/data-state/src/plugin.ts`(排序返回的 `order` / `cyclic` / `missing` 与阻断逻辑)、`packages-user/data-state/src/core.ts`(构造器里 `awake` 的调用点、`load()` 的三段顺序、重复 id 的错误码)、`src/data/plugin/list.ts`、`src/data/plugin/shop/plugin.ts`、`src/data/initialize.ts`。确认没有把「三个方法收到的依赖参数」写成 id 数组;确认没有把「所有插件都按登记顺序」写成绝对结论(同阶段有依赖时先依赖后依赖者);确认没有把插件 id 的存档关系写反。确认没有渲染端内容、没有死链、没有把商店插件当通用模板。再跑 prettier `--write` 与构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。Commit:`docs(10-14): 核对源码并收口插件文档`。 + 逐条核对正文与源码:`packages-user/data-state/src/types.ts`(`IDataPluginDefine` 的三个方法签名、`PluginStatus` 四个状态、`getDataPlugin` 的返回类型)、`packages-user/data-state/src/plugin.ts`(排序返回的 `order` / `cyclic` / `missing` 与阻断逻辑)、`packages-user/data-state/src/core.ts`(构造器里 `awake` 的调用点、`load()` 的三段顺序、重复 id 的错误码)、`src/data/plugin/list.ts`、`src/data/plugin/shop/plugin.ts`、`src/data/initialize.ts`。确认没有把「三个方法收到的依赖参数」写成 id 数组;确认没有把「所有插件都按登记顺序」写成绝对结论(同阶段有依赖时先依赖后依赖者);确认没有把插件 id 与可存档 id 混为一谈,也没有把插件 id 写成可存档 id。确认没有渲染端内容、没有死链、没有把商店插件当通用模板。再跑 prettier `--write` 与构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。Commit:`docs(10-14): 核对源码并收口插件文档`。 $ErrorActionPreference='Continue'; $pf = cmd /c "node node_modules/prettier/bin/prettier.cjs --check docs/advanced/plugin-system.md" 2>&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'GATE-OK' non-zero exit, or output contains "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "GATE-OK" diff --git a/.planning/phases/10-docs-restructure/10-15-PLAN.md b/.planning/phases/10-docs-restructure/10-15-PLAN.md index aec4774..5b213e3 100644 --- a/.planning/phases/10-docs-restructure/10-15-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-15-PLAN.md @@ -75,7 +75,7 @@ Output: 1 个新 markdown 文件。 Task 0: 向用户汇报本计划并等待「可以执行」 - 向用户汇报:**要做什么**(编写 `docs/advanced/saveable-content.md`,系统讲可存档内容与存档一致性)、**为什么**(高级定制最容易在存档/读档上出错;插件、地图、战斗状态都需要可存档)、**大致怎么做**(先讲什么该存与 `ISaveableContent`,再讲三级压缩、注册、存档顺序与 `bindSaveableExecuter`、跨对象引用、structured-cloneable 约束,最后给独立模板、插件计数器示例与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认文件名 `saveable-content.md` 与页面标题「可存档内容」(D-13)。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 + 向用户汇报:**要做什么**(编写 `docs/advanced/saveable-content.md`,系统讲可存档内容与存档一致性)、**为什么**(高级定制最容易在存档/读档上出错;插件、地图、战斗状态都需要可存档)、**大致怎么做**(先讲什么该存与 `ISaveableContent`,再讲三级压缩、注册、存档顺序与 `bindSaveableExecuter`、跨对象引用、structured-cloneable 约束,最后给独立模板、插件计数器示例与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认文件名 `saveable-content.md`、页面标题「可存档内容」,以及示例中会出现的标识:可存档 id `@plugin/example-counter`、方法名 `add` / `get`、字段 `values`(D-13:命名须先获批;如不同意请给出替代名)。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的 `docs/advanced/saveable-content.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 本计划内容:高级 I 第三篇「可存档内容」。 阅读上面的四段说明,并确认文件名与页面标题;如不同意请给出替代名称。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 diff --git a/.planning/phases/10-docs-restructure/10-16-PLAN.md b/.planning/phases/10-docs-restructure/10-16-PLAN.md index 7ecc564..2abc8ba 100644 --- a/.planning/phases/10-docs-restructure/10-16-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-16-PLAN.md @@ -23,6 +23,11 @@ must_haves: - "录像篇讲清检测机制与边界:收集区间由 `beginReplaySafetyCollection` / `endReplaySafetyCollection` 控制;读档期间 `loadState` 被 `disable` / `revert` 包裹,执行器不被包裹;自定义录像行为指向高级 II、深层原理指向高级 III(非断链)" - "Store 篇逐个讲清 `tileStore` / `itemStore` / `mapStore` / `eventStore` 存什么、键是什么、常用读取接口是什么" - "Store 篇明确它们是内容层原始数据,运行时一般只读;修改 `add*` 很可能绕过存档/录像/一致性,且不会更新已存在的运行时对象;给出正确注册位置(插件/加载期)与风险对照表" + - "录像篇含独立小节「模板:给方法加录像标记」,给出可复制的 `@shouldReplay` / `@ignoreReplay` 装饰器骨架,并用 `[需改]` 标出方法名、消息与忽略理由;模板与具体示例分开(D-50)" + - "两篇都含 D-48 六步实操块(目标 → 改哪里 → 复制什么 → 改什么 → 怎么验证 → 注意);录像篇落在「给一个改状态的方法补录像标记」,Store 篇落在「在加载期注册 Store 原始数据」" + - "Store 篇含「模板:在加载期注册 Store 原始数据」小节,并在其中说明 Store 注册为什么没有逐对象模板(`add*` 是逐条登记原始定义,不是实现接口)" + - "两篇都逐字写明「如果你不怎么懂代码,建议直接改内置,而不是自己写新的类。」(D-49.3)" + - "Store 篇说明 `eventStore.getEvent` 返回的是存储的实例,不要修改它" - "两篇都含「怎么验证」;数据端 only;高级 II/III 只用非断链占位;构建 green、dead link = 0" artifacts: - "docs/advanced/replay-consistency.md" @@ -37,7 +42,7 @@ must_haves: 编写高级 I 第四、五篇:`replay-consistency.md`(录像一致性)与 `data-stores.md`(data-common 的 Store)。前者讲两个录像装饰器该写在哪、保证与不保证什么;后者讲四个 Store 各存什么、为什么运行时应当只读。 -Purpose: 这两个主题都是「看起来能用、用错就很难查」的底层约束。读者需要能判断一个方法该不该标记、一个 Store 能不能改,而不是靠试。 +Purpose: 这两个主题都是「看起来能用、用错就很难查」的底层约束。两篇都按 D-54 面向使用者:读者要能判断一个方法该不该标记、一个 Store 能不能改,而不是靠试;因此每篇都提供 D-50 的独立机制模板与 D-48 的可分步实操,并写明 D-49.3 的「优先改内置」建议。 Output: 2 个新 markdown 文件。 @@ -87,7 +92,7 @@ Output: 2 个新 markdown 文件。 Task 0: 向用户汇报本计划并等待「可以执行」 - 向用户汇报:**要做什么**(编写两篇:`replay-consistency.md` 与 `data-stores.md`)、**为什么**(录像装饰器与内容层 Store 都是「用错很难查」的底层约束;高级 I 必须让读者能判断该不该标记、能不能改)、**大致怎么做**(录像篇讲装饰器落点、保证与不保证、检测边界,并先核对收集入口的调用点;Store 篇逐个讲四个 Store 存什么、为什么运行时只读、改 `add*` 的风险与正确注册位置;两篇都给「怎么验证」)、**影响范围**(仅新增 2 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认两个文件名 `replay-consistency.md` / `data-stores.md` 与页面标题「录像一致性」/「data-common 的 Store」(D-13)。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 + 向用户汇报:**要做什么**(编写两篇:`replay-consistency.md` 与 `data-stores.md`)、**为什么**(录像装饰器与内容层 Store 都是「用错很难查」的底层约束;高级 I 必须让读者能判断该不该标记、能不能改)、**大致怎么做**(录像篇讲装饰器落点、保证与不保证、检测边界,并先核对收集入口的调用点;Store 篇逐个讲四个 Store 存什么、为什么运行时只读、改 `add*` 的风险与正确注册位置;两篇都给「怎么验证」)、**影响范围**(仅新增 2 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认两个文件名 `replay-consistency.md` / `data-stores.md` 与页面标题「录像一致性」/「data-common 的 Store」(D-13)。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的两篇 `docs/advanced/*.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 本计划内容:高级 I 第四、五篇「录像一致性」与「data-common 的 Store」。 阅读上面的四段说明,并确认两个文件名与页面标题;如不同意请给出替代名称。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 @@ -100,32 +105,32 @@ Output: 2 个新 markdown 文件。 Task 1: 编写 replay-consistency.md docs/advanced/replay-consistency.md - (1) 写 `docs/advanced/replay-consistency.md`,单 H1 为「录像一致性」。(2) 正文顺序:①录像一致性要解决什么——重放同一条录像要得到同样的数据端结果;核心原则仍是「玩家直接产生、会影响最终成绩的行为必须计入录像」;回指中级 `replay-commands.md`。②两个装饰器的职责:`@shouldReplay(message)` 把方法标记为「应该计入录像」,在检测区间内登记一条路径;`@ignoreReplay(reason)` 把整段检测标记为忽略;强调 `@ignoreReplay` 不是「只忽略这个方法」,而是当前收集区间内全局生效,所以不要用它掩盖告警。③该写在哪:写在会被玩家动作走到、并且真的会改变游戏状态的方法上(内置例子:`FlagSystem.setField` / `deleteField`、`HeroItems.addItem` / `useItem`、`HeroEquipment.equip` / `unequip`、`MapLayer.setBlock` 等);不要写在只读方法、纯计算/试算方法、会被反复调用做展示或临界搜索的方法上;`@ignoreReplay` 只用于确实不该计入录像的异步/被动路径,并说明理由。④能保证什么、不能保证什么:保证的是「这段区间里如果没有任何新录像步,就告警并列出登记过的路径」;不保证逻辑正确、参数正确、顺序正确、记录的指令与操作一一对应;`@shouldReplay` 本身不写录像,真正记录仍要调用 `record` 或走内置的录制入口。⑤检测机制与边界:`beginReplaySafetyCollection` 记录录像长度,`endReplaySafetyCollection` 比较长度并输出登记路径;读档期间 `CoreState.loadState` 对每个对象的 `loadState` 用 `disable` / `revert` 包裹,避免读档产生意外记录;执行器不在包裹内,确实可能记录。写作前先核对这两个入口在当前源码里的调用点;若没有生产调用,只描述「收集区间开启时」的口径,不臆造自动检测时序。⑥自定义录像行为(新增指令、主动/被动录像、沙盒)指向高级 II;录像格式与深层原理指向高级 III;都用代码 span 或 HTML 注释。⑦常见错误:给计算器/只读查询加 `@shouldReplay`、用 `@ignoreReplay` 压掉告警、以为加了装饰器就会自动记录、在异步回调里记录却没有处理顺序、在 `loadState` 里产生录像。⑧「怎么验证」:找一个玩家动作入口,故意不记录,观察控制台是否给出缺失记录告警与路径;补上记录后确认告警消失;再检查参数与顺序是否真的正确(装饰器不会替你验证这些);用录像回放确认结果一致。 (3) 适当加 3–5 处链接,只链已存在页面:`../intermediate/replay-commands.md`、`../intermediate/data-vs-render.md`、`./saveable-content.md`、`./declarative-vs-imperative.md`。不写指向高级 II/III 的真实链接。(4) CRLF、单 H1、数据端 only、加粗符合 flanking。完成后运行 prettier `--write`。Commit:`docs(10-16): 编写录像一致性`。 + (1) 写 `docs/advanced/replay-consistency.md`,单 H1 为「录像一致性」。(2) 正文顺序:①录像一致性要解决什么——重放同一条录像要得到同样的数据端结果;核心原则仍是「玩家直接产生、会影响最终成绩的行为必须计入录像」;回指中级 `replay-commands.md`。②两个装饰器的职责:`@shouldReplay(message)` 把方法标记为「应该计入录像」,在检测区间内登记一条路径;`@ignoreReplay(reason)` 把整段检测标记为忽略;强调 `@ignoreReplay` 不是「只忽略这个方法」,而是当前收集区间内全局生效,所以不要用它掩盖告警。③该写在哪:写在会被玩家动作走到、并且真的会改变游戏状态的方法上(内置例子:`FlagSystem.setField` / `deleteField`、`HeroItems.addItem` / `useItem`、`HeroEquipment.equip` / `unequip`、`MapLayer.setBlock` 等);不要写在只读方法、纯计算/试算方法、会被反复调用做展示或临界搜索的方法上;`@ignoreReplay` 只用于确实不该计入录像的异步/被动路径,并说明理由。④能保证什么、不能保证什么:保证的是「这段区间里如果没有任何新录像步,就告警并列出登记过的路径」;不保证逻辑正确、参数正确、顺序正确、记录的指令与操作一一对应;`@shouldReplay` 本身不写录像,真正记录仍要调用 `record` 或走内置的录制入口。⑤检测机制与边界:`beginReplaySafetyCollection` 记录录像长度,`endReplaySafetyCollection` 比较长度并输出登记路径;读档期间 `CoreState.loadState` 对每个对象的 `loadState` 用 `disable` / `revert` 包裹,避免读档产生意外记录;执行器不在包裹内,确实可能记录。写作前先核对这两个入口在当前源码里的调用点;若没有生产调用,只描述「收集区间开启时」的口径,不臆造自动检测时序。⑥自定义录像行为(新增指令、主动/被动录像、沙盒)指向高级 II;录像格式与深层原理指向高级 III;都用代码 span 或 HTML 注释。⑦常见错误:给计算器/只读查询加 `@shouldReplay`、用 `@ignoreReplay` 压掉告警、以为加了装饰器就会自动记录、在异步回调里记录却没有处理顺序、在 `loadState` 里产生录像。⑧「模板:给方法加录像标记」独立小节(D-50):说明这是录像标记的机制模板,不是某个具体指令的示例;给出 class 内方法装饰器骨架——`@shouldReplay('说明这个方法为什么会改变状态')` 标在真正会改状态的方法上,`@ignoreReplay('说明为什么这段不该计入录像')` 只用于确实被动的路径;用 `[需改]` 标出方法名、消息文本与忽略理由,并提醒不要照抄示例消息。⑨ D-48 六步实操「给一个内置方法补录像标记」:①目标——让一个会改状态的玩家动作入口被检测到;②改哪里——`packages-user/data-base/src/flag/system.ts` 这类已有实现文件中对应方法之前;③复制什么——只复制装饰器那一行,不含 `import`,并在文中说明「顶部通常已有这些 import,不要再粘;若报缺少 X,再在顶部补 `import ...`」;④改什么——把消息改成该方法实际改变了什么状态;⑤怎么验证——走一次玩家动作,观察缺失记录的告警是否消失;⑥注意——只加在真正改状态的方法上,别加在只读、纯计算或会被反复调用的方法上。⑩「改内置还是自己写」:装饰器应加在已有实现文件的方法上,只有确实需要新的录像入口时才考虑新写类;逐字写明「如果你不怎么懂代码,建议直接改内置,而不是自己写新的类。」⑪「怎么验证」:找一个玩家动作入口,故意不记录,观察控制台是否给出缺失记录告警与路径;补上记录后确认告警消失;再检查参数与顺序是否真的正确(装饰器不会替你验证这些);用录像回放确认结果一致。并在回指 `../intermediate/replay-commands.md` 的位置加一行提示:录像安全收集的入口 `beginReplaySafetyCollection` / `endReplaySafetyCollection` 目前只在测试中调用,不要指望引擎自动检测。 (3) 适当加 3–5 处链接,只链已存在页面:`../intermediate/replay-commands.md`、`../intermediate/data-vs-render.md`、`./saveable-content.md`、`./declarative-vs-imperative.md`。不写指向高级 II/III 的真实链接。(4) CRLF、单 H1、数据端 only、加粗符合 flanking。完成后运行 prettier `--write`。Commit:`docs(10-16): 编写录像一致性`。 - $ErrorActionPreference='Stop'; $p='docs/advanced/replay-consistency.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(? + $ErrorActionPreference='Stop'; $p='docs/advanced/replay-consistency.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(? non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "MISSING-CONTENT", "RENDERER-CONTENT", "BOLD-FLANK", or "DEAD-LINK"; or output lacks "STATIC-OK" - 录像篇存在、CRLF、单 H1;装饰器落点、保证与不保证、检测边界、常见错误与「怎么验证」齐全;无渲染端内容;无死链。 + 录像篇存在、CRLF、单 H1;装饰器落点、保证与不保证、检测边界、常见错误、「模板:给方法加录像标记」独立小节、D-48 六步实操、D-49.3 原句与「怎么验证」齐全;无渲染端内容;无死链。 Task 2: 编写 data-stores.md docs/advanced/data-stores.md - (1) 写 `docs/advanced/data-stores.md`,单 H1 为「data-common 的 Store」。(2) 正文顺序:①Store 是什么——数据端公共层(L0)里存放**内容层原始定义**的注册表,不是游戏运行时状态;它们由内容数据在加载/初始化时填入,运行时主要用来查询。②逐个讲四个 Store:`tileStore`(图块数字到 `ITileRawData`,含 id、默认事件、类型、通行性;读取接口 `getData` / `getEvent` / `getType` / `num` / `id` / `identity`);`itemStore`(道具图块数字到 `IItemRawData`,含分类、名称、描述、效果、装备数据;`getData` / `getCategory`);`mapStore`(`floorId` 到 `IMapRawData`,含宽、地图数组、图层别名、事件;`getMap`);`eventStore`(事件 id 到事件实例;`getEvent`)。用一张表收束:Store / 存什么 / 键 / 常用读取 / 写入接口。③Store 与运行时状态的区别:`tileStore` 的图块定义 vs 图层上的实际图块(`mapLayer.getBlock`);`itemStore` 的原始道具定义 vs 勇士背包里的道具实例;`mapStore` 的原始地图数据 vs `state.maps` 的运行时楼层;`eventStore` 的事件实例 vs 地图点上的事件视图。每对都给一句「改哪个会影响什么」。④运行时为什么只读:`add*` 只是登记原始定义,不带 `@shouldReplay`,也不进存档;在游戏进行中调用它,不会更新已经创建的对象,不会让录像重放得到同样结果,读档也不会恢复;因此会绕过存档/录像/一致性。⑤正确注册位置:内容层加载期、插件 `awake` / `initialize` / `afterLoad`(按是否需要加载内容选择),或专门的初始化函数;不要在每个玩家动作、每帧、事件回调里调用 `add*`。⑥什么时候可以读:查表、提示文本、UI、计算前查定义都可以;读取返回的原始对象也不要就地修改(`getEvent` 返回的是拷贝,其他多为直接引用)。⑦`enemyStore` 的说明:`data-common` 里还有 `EnemyStore` 类,但它不在 `IDataCommon` 上;除非核对到明确暴露点,不要把它写成 `state` 上的直接成员,只说明它是额外的原始数据表。⑧「怎么验证」:读一个图块/道具/地图定义,确认能查到;在游戏进行中调用 `add*` 改一个定义,检查已存在的对象是否变化、存档/读档后是否保留、录像重放是否一致——用这三个观察说明为什么不该在运行时改;把注册改到插件 `awake` 后重跑,确认行为稳定。 (3) 适当加 3–5 处链接,只链已存在页面:`../intermediate/data-state-overview.md`、`../intermediate/map-tiles.md`、`../intermediate/tile-store.md`、`./plugin-system.md`、`./saveable-content.md`。高级 II/III 的内容(如加载管线、内容层设计)用代码 span 或 HTML 注释,不写真实链接。(4) CRLF、单 H1、数据端 only、加粗符合 flanking。完成后运行 prettier `--write`。Commit:`docs(10-16): 编写 data-common 的 Store`。 + (1) 写 `docs/advanced/data-stores.md`,单 H1 为「data-common 的 Store」。(2) 正文顺序:①Store 是什么——数据端公共层(L0)里存放**内容层原始定义**的注册表,不是游戏运行时状态;它们由内容数据在加载/初始化时填入,运行时主要用来查询。②逐个讲四个 Store:`tileStore`(图块数字到 `ITileRawData`,含 id、默认事件、类型、通行性;读取接口 `getData` / `getEvent` / `getType` / `num` / `id` / `identity`);`itemStore`(道具图块数字到 `IItemRawData`,含分类、名称、描述、效果、装备数据;`getData` / `getCategory`);`mapStore`(`floorId` 到 `IMapRawData`,含宽、地图数组、图层别名、事件;`getMap`);`eventStore`(事件 id 到事件实例;`getEvent`)。用一张表收束:Store / 存什么 / 键 / 常用读取 / 写入接口。③Store 与运行时状态的区别:`tileStore` 的图块定义 vs 图层上的实际图块(`mapLayer.getBlock`);`itemStore` 的原始道具定义 vs 勇士背包里的道具实例;`mapStore` 的原始地图数据 vs `state.maps` 的运行时楼层;`eventStore` 的事件实例 vs 地图点上的事件视图。每对都给一句「改哪个会影响什么」。④运行时为什么只读:`add*` 只是登记原始定义,不带 `@shouldReplay`,也不进存档;在游戏进行中调用它,不会更新已经创建的对象,不会让录像重放得到同样结果,读档也不会恢复;因此会绕过存档/录像/一致性。⑤正确注册位置:内容层加载期、插件 `awake` / `initialize` / `afterLoad`(按是否需要加载内容选择),或专门的初始化函数;不要在每个玩家动作、每帧、事件回调里调用 `add*`。⑥什么时候可以读:查表、提示文本、UI、计算前查定义都可以;读取返回的原始对象也不要就地修改(`eventStore.getEvent` 返回的是存储的实例,不要修改它;其他多为直接引用)。⑦`enemyStore` 的说明:`data-common` 里还有 `EnemyStore` 类,但它不在 `IDataCommon` 上;除非核对到明确暴露点,不要把它写成 `state` 上的直接成员,只说明它是额外的原始数据表。⑧「模板:在加载期注册 Store 原始数据」独立小节(D-50):写明 Store 注册没有逐对象模板,因为 `addTile` / `addItem` / `addMap` / `addEvent` 是逐条登记原始定义,而不是让你实现某个接口;因此这里给的是「在加载期集中登记」的机制骨架——在插件 `awake` / `initialize` / `afterLoad` 或专门的初始化函数里,把同一来源的 `add*` 调用集中成一段,用 `[需改]` 标出要登记的 id 与原始数据来源。⑨ D-48 六步实操「把一批自定义内容注册进 Store」:①目标——让新增图块/道具/地图/事件在加载后可查询;②改哪里——内容层加载期或插件 `awake` 的注册段;③复制什么——只给 `add*` 调用那一段,不含 `import`,并说明「顶部通常已有这些 import,不要再粘;若报缺少 X,再在顶部补 `import ...`」;④改什么——把 id 与原始数据字段换成自己的;⑤怎么验证——启动后读回刚登记的内容,确认 `getData` / `getMap` / `getEvent` 能查到;⑥注意——不要在玩家动作、事件回调或每帧里登记,运行时改不会传播到已创建对象。⑩「改内置还是自己写」:优先在既有加载/注册位置补条目,不要为一批原始数据新造 Store 或扩展 `IDataCommon`;逐字写明「如果你不怎么懂代码,建议直接改内置,而不是自己写新的类。」⑪「怎么验证」:读一个图块/道具/地图定义,确认能查到;在游戏进行中调用 `add*` 改一个定义,检查已存在的对象是否变化、存档/读档后是否保留、录像重放是否一致——用这三个观察说明为什么不该在运行时改;把注册改到插件 `awake` 后重跑,确认行为稳定。 (3) 适当加 3–5 处链接,只链已存在页面:`../intermediate/data-state-overview.md`、`../intermediate/map-tiles.md`、`../intermediate/tile-store.md`、`./plugin-system.md`、`./saveable-content.md`。高级 II/III 的内容(如加载管线、内容层设计)用代码 span 或 HTML 注释,不写真实链接。(4) CRLF、单 H1、数据端 only、加粗符合 flanking。完成后运行 prettier `--write`。Commit:`docs(10-16): 编写 data-common 的 Store`。 - $ErrorActionPreference='Stop'; $p='docs/advanced/data-stores.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(? + $ErrorActionPreference='Stop'; $p='docs/advanced/data-stores.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(? non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "MISSING-CONTENT", "RENDERER-CONTENT", "BOLD-FLANK", or "DEAD-LINK"; or output lacks "STATIC-OK" - Store 篇存在、CRLF、单 H1;四个 Store 的存储内容、键、读取接口、只读原因、正确注册位置与「怎么验证」齐全;`enemyStore` 未被误写成 `state.enemyStore`;无渲染端内容;无死链。 + Store 篇存在、CRLF、单 H1;四个 Store 的存储内容、键、读取接口、只读原因、正确注册位置、「模板:在加载期注册 Store 原始数据」、D-48 六步实操、D-49.3 原句与「怎么验证」齐全;`eventStore.getEvent` 的返回语义正确;`enemyStore` 未被误写成 `state.enemyStore`;无渲染端内容;无死链。 Task 3: 两篇源码核对、格式与构建收口 docs/advanced/replay-consistency.md, docs/advanced/data-stores.md - 逐条核对:录像篇对照 `packages-user/data-common/src/replay/func.ts`(`shouldReplay` 的嵌套登记、`ignoreReplay` 的全局标记、`endReplaySafetyCollection` 的三个提前返回条件)与 `packages-user/data-state/src/core.ts`(`loadState` 的 `disable` / `revert` 包裹、执行器位置),并核对收集入口的实际调用点;若只有测试调用,按「收集区间开启时」的措辞改写任何「每步自动」的断言。Store 篇对照 `packages-user/data-common/src/store/types.ts`、`tileStore.ts`、`itemStore.ts`、`mapStore.ts`、`eventStore.ts`、`enemyStore.ts` 与 `packages-user/data-common/src/types.ts`(`IDataCommon` 的四个 Store 字段),逐字核对接口名、参数顺序与返回形状;确认它没有被写成 `state` 上的直接成员。两篇都确认无渲染端内容、无死链、无把具体示例当通用模板。再跑 prettier `--write` 与构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。Commit:`docs(10-16): 核对源码并收口录像与 Store 文档`。 + 逐条核对:录像篇对照 `packages-user/data-common/src/replay/func.ts`(`shouldReplay` 的嵌套登记、`ignoreReplay` 的全局标记、`endReplaySafetyCollection` 的三个提前返回条件)与 `packages-user/data-state/src/core.ts`(`loadState` 的 `disable` / `revert` 包裹、执行器位置),并核对收集入口的实际调用点;若只有测试调用,按「收集区间开启时」的措辞改写任何「每步自动」的断言。Store 篇对照 `packages-user/data-common/src/store/types.ts`、`tileStore.ts`、`itemStore.ts`、`mapStore.ts`、`eventStore.ts`、`enemyStore.ts` 与 `packages-user/data-common/src/types.ts`(`IDataCommon` 的四个 Store 字段),逐字核对接口名、参数顺序与返回形状;确认它没有被写成 `state` 上的直接成员。额外核对:两篇的 `模板:` 小节与 D-48 六步块齐全;D-49.3 原句逐字存在;Store 篇写的是 `eventStore.getEvent` 返回存储的实例,并确认没有把 `getEvent` 写成返回副本。两篇都确认无渲染端内容、无死链、无把具体示例当通用模板。再跑 prettier `--write` 与构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。Commit:`docs(10-16): 核对源码并收口录像与 Store 文档`。 - $ErrorActionPreference='Continue'; $pf = cmd /c "node node_modules/prettier/bin/prettier.cjs --check docs/advanced/replay-consistency.md docs/advanced/data-stores.md" 2>&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; if(([IO.File]::ReadAllText((Resolve-Path 'docs/advanced/data-stores.md'))) -match 'state\.enemyStore'){ Write-Error "ENEMY-STORE-EXPOSED" }; Write-Output 'GATE-OK' - non-zero exit, or output contains "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE", "DEAD-LINK", or "ENEMY-STORE-EXPOSED"; or output lacks "GATE-OK" + $ErrorActionPreference='Continue'; $pf = cmd /c "node node_modules/prettier/bin/prettier.cjs --check docs/advanced/replay-consistency.md docs/advanced/data-stores.md" 2>&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; $dr=[IO.File]::ReadAllText((Resolve-Path 'docs/advanced/replay-consistency.md')); foreach($needle in @('模板:给方法加录像标记','如果你不怎么懂代码')){ if($dr -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-REPLAY-TEMPLATE $needle" } }; $ds=[IO.File]::ReadAllText((Resolve-Path 'docs/advanced/data-stores.md')); foreach($needle in @('模板:在加载期注册 Store 原始数据','如果你不怎么懂代码','返回的是存储的实例')){ if($ds -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-STORE-TEMPLATE $needle" } }; if($ds -match '返回的是拷贝'){ Write-Error "EVENT-STORE-COPY-CLAIM" }; if($ds -match 'state\.enemyStore'){ Write-Error "ENEMY-STORE-EXPOSED" }; Write-Output 'GATE-OK' + non-zero exit, or output contains "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE", "DEAD-LINK", "MISSING-REPLAY-TEMPLATE", "MISSING-STORE-TEMPLATE", "EVENT-STORE-COPY-CLAIM", or "ENEMY-STORE-EXPOSED"; or output lacks "GATE-OK" 两篇接口名、参数顺序、返回形状与源码一致;录像篇未把未接线的检测写成既成事实;Store 篇未把 `enemyStore` 写成 `state` 入口;prettier 通过;构建 green、`build complete`、dead link = 0。 @@ -152,7 +157,7 @@ Output: 2 个新 markdown 文件。 - 结构门禁:两文件存在、kebab-case、CRLF、单 H1。 -- 内容门禁:录像装饰器落点、保证/不保证、检测边界;四个 Store 的存储内容与只读风险均有源码依据。 +- 内容门禁:录像装饰器落点、保证/不保证、检测边界;四个 Store 的存储内容与只读风险均有源码依据;两篇各含独立 `模板:` 小节与 D-48 六步实操,并逐字含 D-49.3 原句;`eventStore.getEvent` 返回语义与源码一致。 - 链接门禁:只链已存在页面;高级 II/III 不产生真实链接。 - 边界门禁:无渲染端内容;不改 `config.ts` 与生产代码。 - 构建门禁:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过,`build complete`,dead link = 0。 @@ -161,6 +166,7 @@ Output: 2 个新 markdown 文件。 - 读者能给一个方法判断该不该加 `@shouldReplay` / `@ignoreReplay`,并知道装饰器不保证逻辑正确。 - 读者能说出四个 Store 各存什么、为什么运行时不该改、该在什么时机注册。 +- 读者能照着「模板:给方法加录像标记」与「模板:在加载期注册 Store 原始数据」两节抄出骨架,并知道 D-49.3 的「优先改内置」建议。 - 构建通过,无死链、无渲染端内容。 diff --git a/.planning/phases/10-docs-restructure/10-17-PLAN.md b/.planning/phases/10-docs-restructure/10-17-PLAN.md index 7ad7063..c1d3a33 100644 --- a/.planning/phases/10-docs-restructure/10-17-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-17-PLAN.md @@ -2,7 +2,7 @@ phase: 10-docs-restructure plan: 17 type: execute -wave: 3 +wave: 2 depends_on: [10-13] files_modified: - docs/advanced/hooks-in-depth.md @@ -78,7 +78,7 @@ Output: 1 个新 markdown 文件。 Task 0: 向用户汇报本计划并等待「可以执行」 - 向用户汇报:**要做什么**(编写 `docs/advanced/hooks-in-depth.md`,讲多对象场景下的钩子身份校验、复用、注册移除与异步时序)、**为什么**(同一个钩子会被多个 map / layer 触发;不会判断触发者就会把效果加到错误对象上)、**大致怎么做**(先回顾钩子实例与注册机制,再讲地图/图层的身份来源、两种身份校验做法、共享 vs 每对象一个实例、注册移除与重复注册、异步钩子的并发等待,最后给独立模板、示例与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认文件名 `hooks-in-depth.md` 与页面标题「钩子深入」(D-13)。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 + 向用户汇报:**要做什么**(编写 `docs/advanced/hooks-in-depth.md`,讲多对象场景下的钩子身份校验、复用、注册移除与异步时序)、**为什么**(同一个钩子会被多个 map / layer 触发;不会判断触发者就会把效果加到错误对象上)、**大致怎么做**(先回顾钩子实例与注册机制,再讲地图/图层的身份来源、两种身份校验做法、共享 vs 每对象一个实例、注册移除与重复注册、异步钩子的并发等待,最后给独立模板、示例与「怎么验证」)、**影响范围**(仅新增 1 个 `docs/advanced/*.md`;不改 `config.ts`、不改生产代码、不新增外链)。同时请用户确认文件名 `hooks-in-depth.md`、页面标题「钩子深入」,以及示例中会出现的成员名:构造时保存的目标图层 `readonly layer` 与地图级钩子里用于比较的 `targetLayer`(D-13:命名须先获批;如不同意请给出替代名)。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的 `docs/advanced/hooks-in-depth.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得写任何文件。 本计划内容:高级 I 第六篇「钩子深入」。 阅读上面的四段说明,并确认文件名与页面标题;如不同意请给出替代名称。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 diff --git a/.planning/phases/10-docs-restructure/10-18-PLAN.md b/.planning/phases/10-docs-restructure/10-18-PLAN.md index 1f0f16d..93fc52f 100644 --- a/.planning/phases/10-docs-restructure/10-18-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-18-PLAN.md @@ -85,7 +85,7 @@ Output: `index.md`、`config.ts` 的注册,以及七篇之间的可解析链 Task 0: 向用户汇报本计划并等待「可以执行」 - 向用户汇报:**要做什么**(编写 `docs/advanced/index.md` 高级 I 导览;在 `docs/.vitepress/config.ts` 增加「高级教程」导航与 `/advanced/` 侧边栏;把七篇互相链接起来并做全量构建)、**为什么**(六篇内容需要站点入口;导览要讲清 I/II/III 分层、阅读路径与 D-55 的「优先插件」原则)、**大致怎么做**(先写导览,再改 `nav` / `sidebar`,最后做链接与构建收口;高级 II/III 只留空分组,不产生死链)、**影响范围**(新增 `index.md`;修改 `config.ts` 的 `nav` / `sidebar`;轻微编辑六篇的互链与返回导览链接;不改生产代码、不新增外链)。同时请用户确认三个新显示名:「高级教程」(导航)、「高级 I · 扩展基础」「高级 II · 系统实现」「高级 III · 原理与架构」(侧边栏分组),以及导览文件名 `index.md`、页面标题「高级 I 导览」(D-13)。停下等待用户明确回复「可以执行」四个字;未收到前不得改任何文件。 + 向用户汇报:**要做什么**(编写 `docs/advanced/index.md` 高级 I 导览;在 `docs/.vitepress/config.ts` 增加「高级教程」导航与 `/advanced/` 侧边栏;把七篇互相链接起来并做全量构建)、**为什么**(六篇内容需要站点入口;导览要讲清 I/II/III 分层、阅读路径与 D-55 的「优先插件」原则)、**大致怎么做**(先写导览,再改 `nav` / `sidebar`,最后做链接与构建收口;高级 II/III 只留空分组,不产生死链)、**影响范围**(新增 `index.md`;修改 `config.ts` 的 `nav` / `sidebar`;轻微编辑六篇的互链与返回导览链接;不改生产代码、不新增外链)。同时请用户确认三个新显示名:「高级教程」(导航)、「高级 I · 扩展基础」「高级 II · 系统实现」「高级 III · 原理与架构」(侧边栏分组),以及导览文件名 `index.md`、页面标题「高级 I 导览」(D-13)。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的导览、六篇正文与 `docs/.vitepress/config.ts` 的 nav / sidebar,执行者不内联修改文件。停下等待用户明确回复「可以执行」四个字;未收到前不得改任何文件。 本计划内容:高级 I 导览 + 站点注册 + 六篇互链收口。 阅读上面的四段说明,并确认三个分组显示名、导航名与导览标题;如不同意请给出替代名称。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 diff --git a/.planning/phases/10-docs-restructure/10-19-PLAN.md b/.planning/phases/10-docs-restructure/10-19-PLAN.md index 4472b6f..34e2e66 100644 --- a/.planning/phases/10-docs-restructure/10-19-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-19-PLAN.md @@ -23,10 +23,10 @@ estimate: confidence: low must_haves: truths: - - "读者人格**不是**中级教程用过的「不懂代码的游戏作者」,而是「有一定编程基础、已读完中级教程、想为引擎做深度定制、能读懂代码但不熟悉引擎内部架构的作者」;该人格在 Task 0 已经用户确认" + - "读者人格是「对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构、已读完中级教程的作者」——不预设高代码水平,也不是完全不懂代码;记录以「未复用中级人格」标记说明与中级人格的区别(允许提及中级人格名称,不要求全文禁出现,也不设全局禁语),该人格在 Task 0 已经用户确认" - "`10-19-READER-REVIEW.md` 存在,逐字记录人格提示词、审阅范围(高级 I 七篇)、问题清单,并按**阻断性**与**非阻断**归类、定位到文件与章节" - "阻断性问题被迭代修正(上限 3 轮);每轮后构建 green、`build complete`、dead link = 0;达到上限仍有阻断问题时停下交用户,不无限循环" - - "迭代结束再派发一个独立子代理(同一人格)复审,`10-19-READER-REVIEW.md` 逐条标注「已消除」或「仍存在」;阻断性问题为 0(或余项已交用户)" + - "迭代结束再派发一个独立子代理(同一人格)复审,`10-19-READER-REVIEW.md` 逐条标注「已消除」或「仍存在」;结束标记为「阻断性问题 = 0」或「阻断性问题余项:已交用户」(后者须列出余项与用户处置)" - "只改 `docs/advanced/*.md` 与新增的审阅记录;不改 `config.ts` 与生产代码;被改文件保持 kebab-case、CRLF、单 H1" - "非阻断问题只记录、不擅自扩大范围(D-14);不因读者提问删掉 D-53..D-57 要求的内容" artifacts: @@ -39,7 +39,7 @@ must_haves: --- -执行高级 I 的独立读者审阅:派发一个与中级教程**不同人格**的独立子代理(有一定编程基础、读完中级教程、想做深度定制、能读懂代码但不熟悉引擎内部架构的作者),通读七篇高级 I,产出问题清单;据此迭代修正阻断性问题,最后再派一个同人格独立子代理复审,直到阻断性问题为零或把余项交给用户。 +执行高级 I 的独立读者审阅:派发一个与中级教程**不同人格**的独立子代理(对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构、已读完中级教程的作者),通读七篇高级 I,产出问题清单;据此迭代修正阻断性问题,最后再派一个同人格独立子代理复审,直到阻断性问题为零或把余项交给用户。 Purpose: D-57 明确要求高级 I 必须走读者修订循环,且不能复用中级教程使用过的读者人格。高级 I 的读者会真的照文档写插件、写可存档对象,所以问题集中在「概念之间的连接」「照着做会不会卡住」「代码放哪」这些层面。 Output: `10-19-READER-REVIEW.md`(人格、问题、迭代、复审)与针对阻断问题的文档修正。 @@ -65,11 +65,11 @@ Output: `10-19-READER-REVIEW.md`(人格、问题、迭代、复审)与针对 @docs/intermediate/data-plugins.md **人格设定(D-57,不得复用中级教程人格):** -> 假设你是一位有一定编程基础、已经读完本样板中级教程、想做深度定制、能读懂代码但不熟悉引擎内部架构的游戏作者。你正在阅读高级教程 I,想判断自己能不能照着文档完成扩展。 +> 假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程 I,想判断自己能不能照着文档完成插件等扩展。 **与中级审阅的区别:** -- 中级人格是「不懂代码的游戏作者」(见 `10-11-READER-REVIEW.md`),本计划**禁止**复用该人格或该提示词。 -- 高级 I 读者能读懂代码,所以问题不再是「变量是什么」,而是「这段代码该放哪」「两个系统怎么接」「照做之后为什么没有效果」「存档/录像/钩子之间怎么互相影响」。 +- 中级人格是「不懂代码的游戏作者」(见 `10-11-READER-REVIEW.md`),本计划**禁止**复用该人格或该提示词;该短语只作为差异说明出现,不据此设置全文禁语门禁。 +- 高级 I 读者了解基本语法、能看懂简单代码,但**不预设高代码水平**;问题不再是「变量是什么」,而是「这段代码该放哪」「两个系统怎么接」「照做之后为什么没有效果」「存档/录像/钩子之间怎么互相影响」。 - 审阅对象是 `docs/advanced/` 的七篇,不是中级教程。 **流程约定:** @@ -84,7 +84,7 @@ Output: `10-19-READER-REVIEW.md`(人格、问题、迭代、复审)与针对 Task 0: 向用户汇报读者审阅计划并确认人格 - 向用户汇报:**要做什么**(派发独立子代理,以「有一定编程基础、已读完中级教程、想做深度定制、能读懂代码但不熟悉引擎内部架构的作者」人格通读高级 I 七篇,产出问题清单,据此迭代修正并复审)、**为什么**(D-57 要求高级 I 走读者修订循环,且不能复用中级教程使用过的读者人格)、**大致怎么做**(Task 1 派发 persona 子代理并落清单;Task 2 按清单修阻断问题,最多 3 轮、每轮构建;Task 3 复跑同人格审阅确认阻断清零)、**影响范围**(可能修改 `docs/advanced/*.md` 中确有阻断问题的篇目 + 新增 `.planning` 下的审阅记录;不改站点配置与生产代码)。请用户逐字确认人格提示词:「假设你是一位有一定编程基础、已经读完本样板中级教程、想做深度定制、能读懂代码但不熟悉引擎内部架构的游戏作者。你正在阅读高级教程 I,想判断自己能不能照着文档完成扩展。」并等待用户明确回复「可以执行」四个字;未收到前不得派发子代理或改任何文件。 + 向用户汇报:**要做什么**(派发独立子代理,以「对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构、已读完中级教程的作者」人格通读高级 I 七篇,产出问题清单,据此迭代修正并复审)、**为什么**(D-57 要求高级 I 走读者修订循环,且不能复用中级教程使用过的读者人格)、**大致怎么做**(Task 1 派发 persona 子代理并落清单;Task 2 按清单修阻断问题,最多 3 轮、每轮构建;Task 3 复跑同人格审阅确认阻断清零)、**影响范围**(可能修改 `docs/advanced/*.md` 中确有阻断问题的篇目 + 新增 `.planning` 下的审阅记录;不改站点配置与生产代码)。请用户逐字确认人格提示词:「假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程 I,想判断自己能不能照着文档完成插件等扩展。」汇报中明确:该人格不预设高代码水平,只要求了解基本语法(变量/函数/类/import),代码能力一般也算符合;它不是完全不懂代码,也不是高级开发者。并等待用户明确回复「可以执行」四个字。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `docs/advanced/*.md` 中存在阻断问题的篇目与 `.planning/.../10-19-READER-REVIEW.md`,执行者不内联修改文档。未收到前不得派发子代理或改任何文件。 本计划内容:高级 I 独立读者人格审阅 → 问题清单 → 迭代修正 → 复审确认。 阅读上面的四段说明;确认人格提示词与中级教程不同、审阅范围是高级 I 七篇、迭代上限 3 轮;如对人格有修改请直接给出。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 @@ -97,10 +97,10 @@ Output: `10-19-READER-REVIEW.md`(人格、问题、迭代、复审)与针对 Task 1: 派发独立读者子代理并产出问题清单 .planning/phases/10-docs-restructure/10-19-READER-REVIEW.md - 派发一个**独立子代理**(不与执行者共享上下文),其人格与任务设定逐字为:「假设你是一位有一定编程基础、已经读完本样板中级教程、想做深度定制、能读懂代码但不熟悉引擎内部架构的游戏作者。你正在阅读高级教程 I,想判断自己能不能照着文档完成扩展。」让子代理按 `docs/advanced/index.md` 的推荐顺序通读七篇(导览、声明式 vs 命令式、插件系统、可存档内容、录像一致性、data-common 的 Store、钩子深入),然后回答:「读完后你有哪些问题?哪些地方你照做会卡住、会做错,或者会把系统边界理解错?」子代理**只以读者身份提问**、不修改文件、不代入引擎作者视角。把原始提问与执行者的归类写进 `.planning/phases/10-docs-restructure/10-19-READER-REVIEW.md`:开头逐字记录人格提示词与审阅范围;每条问题附文件与章节定位;按**阻断性**与**非阻断**分组。阻断性口径:读者据此无法完成操作,或会对概念/系统边界产生实质误解。**本轮不改文档**。Commit:`docs(10-19): 记录高级 I 读者问题清单`。 + 派发一个**独立子代理**(不与执行者共享上下文),其人格与任务设定逐字为:「假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import 等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程 I,想判断自己能不能照着文档完成插件等扩展。」该人格**不预设高代码水平**:只假定读者了解基本语法,不假定其能读懂复杂代码或熟悉引擎内部。让子代理按 `docs/advanced/index.md` 的推荐顺序通读七篇(导览、声明式 vs 命令式、插件系统、可存档内容、录像一致性、data-common 的 Store、钩子深入),然后回答:「读完后你有哪些问题?哪些地方你照做会卡住、会做错,或者会把系统边界理解错?」子代理**只以读者身份提问**、不修改文件、不代入引擎作者视角。把原始提问与执行者的归类写进 `.planning/phases/10-docs-restructure/10-19-READER-REVIEW.md`:开头逐字记录高级 I 人格提示词与审阅范围,并单独写一行「未复用中级人格」标记;每条问题附文件与章节定位;按**阻断性**与**非阻断**分组。记录中可以引用中级人格名称来说明区别,但不得把该名称当作本次人格或提示词,也不得据此设置全文禁语。阻断性口径:读者据此无法完成操作,或会对概念/系统边界产生实质误解。**本轮不改文档**。Commit:`docs(10-19): 记录高级 I 读者问题清单`。 - $ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-19-READER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); foreach($needle in @('有一定编程基础','读完本样板中级教程','深度定制','不熟悉引擎内部架构','阻断','非阻断','docs/advanced/index.md')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; if($raw -match '不懂代码的游戏作者'){ Write-Error "REUSED-INTERMEDIATE-PERSONA" }; Write-Output 'REVIEW-OK' - non-zero exit, or output contains "MISSING", "MISSING-CONTENT", or "REUSED-INTERMEDIATE-PERSONA"; or output lacks "REVIEW-OK" + $ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-19-READER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); foreach($needle in @('对代码有一定了解','了解基本语法','代码能力一般','不熟悉引擎内部架构','已读完中级教程','未复用中级人格','阻断','非阻断','docs/advanced/index.md')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; $flat=$raw -replace '\s',''; $persona='假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程I,想判断自己能不能照着文档完成插件等扩展。'; if(-not $flat.Contains($persona)){ Write-Error "MISSING-PERSONA-PROMPT" }; Write-Output 'REVIEW-OK' + non-zero exit, or output contains "MISSING", or "MISSING-CONTENT"; or output lacks "REVIEW-OK" 审阅记录存在;逐字含高级 I 人格提示词与七篇范围;问题按阻断/非阻断归类并定位到文件章节;未复用中级人格。 @@ -108,7 +108,7 @@ Output: `10-19-READER-REVIEW.md`(人格、问题、迭代、复审)与针对 Task 2: 按清单迭代修正阻断问题(上限 3 轮) docs/advanced/*.md(仅存在阻断性问题的篇目) - 逐个消除 `10-19-READER-REVIEW.md` 中的**阻断性问题**:对每个阻断问题,修改对应 `docs/advanced/*.md` 的相应段落,使一个「能读懂代码但不熟悉引擎内部架构」的读者也能照做——补「这段代码放哪」「和哪个系统对接」「为什么照做没效果」「存档/录像/钩子之间怎么互相影响」;必要时补最短可行示例或调整章节顺序。只改确有阻断问题的篇目;非阻断问题不修、仅保留在清单中供用户判断(D-14)。每轮修正后:(a) 跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,须 green、`build complete`、dead link = 0;(b) 在 `10-19-READER-REVIEW.md` 追加该轮记录(本轮修了哪些问题、依据、构建结论)。迭代**最多 3 轮**:3 轮后仍有阻断问题时,停下把余项列给用户,不继续循环。守住 D-53..D-57 与 D-48..D-52,不因读者提问删掉要求覆盖的内容;不改 `config.ts` 与生产代码。每轮 Commit:`docs(10-19): 迭代修正高级 I 阻断问题(第N轮)`。 + 逐个消除 `10-19-READER-REVIEW.md` 中的**阻断性问题**:对每个阻断问题,修改对应 `docs/advanced/*.md` 的相应段落,使一个「了解基本语法但代码能力一般、不熟悉引擎内部架构」的读者也能照做——补「这段代码放哪」「和哪个系统对接」「为什么照做没效果」「存档/录像/钩子之间怎么互相影响」;必要时补最短可行示例或调整章节顺序。只改确有阻断问题的篇目;非阻断问题不修、仅保留在清单中供用户判断(D-14)。每轮修正后:(a) 跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,须 green、`build complete`、dead link = 0;(b) 在 `10-19-READER-REVIEW.md` 追加该轮记录(本轮修了哪些问题、依据、构建结论)。迭代**最多 3 轮**:3 轮后仍有阻断问题时,停下把余项列给用户,不继续循环。守住 D-53..D-57 与 D-48..D-52,不因读者提问删掉要求覆盖的内容;不改 `config.ts` 与生产代码。每轮 Commit:`docs(10-19): 迭代修正高级 I 阻断问题(第N轮)`。 $ErrorActionPreference='Stop'; $names=@('index','declarative-vs-imperative','plugin-system','saveable-content','replay-consistency','data-stores','hooks-in-depth'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(?&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'ITERATE-OK' non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "NO-ROUND-LOG", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "ITERATE-OK" @@ -119,12 +119,12 @@ Output: `10-19-READER-REVIEW.md`(人格、问题、迭代、复审)与针对 Task 3: 复跑同人格审阅确认阻断清零 .planning/phases/10-docs-restructure/10-19-READER-REVIEW.md - 再次派发一个**独立子代理**(人格提示词逐字同 Task 1,不得换回中级教程人格),让它重新通读七篇并回答「现在还有哪些看不懂、照做会卡住、或会把系统边界理解错的地方?」。把复审结果追加进 `10-19-READER-REVIEW.md`:对照首轮清单,逐条标注「已消除」或「仍存在」;若仍有**阻断性**问题,回到 Task 2 再修(受 3 轮上限约束),否则记「阻断性问题 = 0,审阅通过」。最后跑一次构建门禁确认 green。本任务不引入新功能,只收敛理解性问题。Commit:`docs(10-19): 复审高级 I 读者视角(阻断问题清零)`。 + 再次派发一个**独立子代理**(人格提示词逐字同 Task 1,不得换回中级教程人格),让它重新通读七篇并回答「现在还有哪些看不懂、照做会卡住、或会把系统边界理解错的地方?」。把复审结果追加进 `10-19-READER-REVIEW.md`:对照首轮清单,逐条标注「已消除」或「仍存在」;若仍有**阻断性**问题,回到 Task 2 再修(受 3 轮上限约束)。收敛时二选一写结构化结束标记:阻断问题清零记「阻断性问题 = 0,审阅通过」;3 轮上限后仍有阻断问题记「阻断性问题余项:已交用户」并列出余项与用户处置。复审记录同样保留「未复用中级人格」标记。最后跑一次构建门禁确认 green。本任务不引入新功能,只收敛理解性问题。Commit:`docs(10-19): 复审高级 I 读者视角(收敛)`。 - $ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-19-READER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); foreach($needle in @('已消除','仍存在','阻断性问题 = 0')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; if($raw -match '不懂代码的游戏作者'){ Write-Error "REUSED-INTERMEDIATE-PERSONA" }; $ErrorActionPreference='Continue'; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'RECHECK-OK' - non-zero exit, or output contains "MISSING", "MISSING-CONTENT", "REUSED-INTERMEDIATE-PERSONA", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "RECHECK-OK" + $ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-19-READER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); foreach($needle in @('对代码有一定了解','了解基本语法','代码能力一般','不熟悉引擎内部架构','已读完中级教程','已消除','仍存在','未复用中级人格')){ if($raw -notmatch [regex]::Escape($needle)){ Write-Error "MISSING-CONTENT $needle" } }; $flat=$raw -replace '\s',''; $persona='假设你是一位对代码有一定了解、了解基本语法(变量、函数、类、import等),但代码能力一般、不熟悉引擎内部架构的游戏作者。你已经读完中级教程,正在阅读高级教程I,想判断自己能不能照着文档完成插件等扩展。'; if(-not $flat.Contains($persona)){ Write-Error "MISSING-PERSONA-PROMPT" }; if($raw -notmatch '阻断性问题 = 0' -and $raw -notmatch '阻断性问题余项:已交用户'){ Write-Error "NO-TERMINAL-MARKER" }; $ErrorActionPreference='Continue'; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'RECHECK-OK' + non-zero exit, or output contains "MISSING", "MISSING-CONTENT", "NO-TERMINAL-MARKER", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "RECHECK-OK" - 复审结果记录进 `10-19-READER-REVIEW.md`(逐条已消除/仍存在);阻断性问题 = 0(或余项已交用户);构建 green、`build complete`、dead link = 0。 + 复审结果记录进 `10-19-READER-REVIEW.md`(逐条已消除/仍存在);结束标记为「阻断性问题 = 0」或「阻断性问题余项:已交用户」(后者含余项与用户处置);构建 green、`build complete`、dead link = 0。 @@ -149,9 +149,9 @@ Output: `10-19-READER-REVIEW.md`(人格、问题、迭代、复审)与针对 -- 机制门禁:`10-19-READER-REVIEW.md` 含高级 I 人格提示词、七篇范围、首轮问题清单、每轮迭代记录、复审对照结果。 -- 人格门禁:记录中不得出现中级教程的「不懂代码的游戏作者」人格;提示词含「有一定编程基础」「读完中级教程」「深度定制」「不熟悉引擎内部架构」。 -- 迭代门禁:上限 3 轮;结束状态为阻断性问题 = 0(或余项已交用户)。 +- 机制门禁:`10-19-READER-REVIEW.md` 含高级 I 人格提示词(按空白归一化后逐字包含完整提示词)、七篇范围、首轮问题清单、每轮迭代记录、复审对照结果。 +- 人格门禁:记录含高级 I 人格提示词(「对代码有一定了解」「了解基本语法」「代码能力一般」「不熟悉引擎内部架构」「已读完中级教程」)与独立的「未复用中级人格」标记;该人格不预设高代码水平;允许引用中级人格名称来说明差异,不要求全文禁出现该短语,也不设全局禁语门禁。 +- 迭代门禁:上限 3 轮;结束标记为「阻断性问题 = 0」或「阻断性问题余项:已交用户」(后者须列出余项与用户处置)。 - 构建门禁:每轮及收尾均 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过(green / `build complete` / dead link = 0)。 - 结构门禁:七篇仍 kebab-case、CRLF、单 H1。 - 越界门禁:`git status` 仅含 `docs/advanced/*.md` 的修改与新增的 `.planning` 审阅记录。 diff --git a/.planning/phases/10-docs-restructure/10-20-PLAN.md b/.planning/phases/10-docs-restructure/10-20-PLAN.md index cf7bfc1..fedbafa 100644 --- a/.planning/phases/10-docs-restructure/10-20-PLAN.md +++ b/.planning/phases/10-docs-restructure/10-20-PLAN.md @@ -24,7 +24,7 @@ estimate: must_haves: truths: - "用户主导的修订循环被真正执行:用户以本领域视角逐条提出问题 → 派子代理修改 → 回报 → 用户继续提,直到用户明确确认满意" - - "`10-20-USER-REVIEW.md` 记录每一轮用户意见、落点、处置与构建结论;用户最终确认(通过 / 满意)被明确记录" + - "`10-20-USER-REVIEW.md` 记录每一轮用户意见、落点、处置与构建结论;最终确认以独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意` 记录" - "收尾由用户确认触发,不由 AI 自行收尾;用户未确认前不得写 SUMMARY 或宣称完成" - "最终七篇全部 kebab-case、CRLF、单 H1;prettier 检查通过;构建 green、`build complete`、dead link = 0" - "不改 `config.ts` 与生产代码;越界问题只记录、不实施(D-14)" @@ -65,6 +65,7 @@ Output: `10-20-USER-REVIEW.md`(用户意见与处置)、最终文档修订 **流程约定(D-46 第 2 阶段 / D-57):** - 用户主导:用户提问题,AI 不替用户判断「这不算问题」;用户说改就改,用户说不用改就不改。 - 每轮:记录用户意见 → 派子代理逐条修改 → 回报 → 等用户继续提或确认。 +- 条目状态固定为 `状态:待处理` / `状态:已处理` / `状态:越界-不实施`(可带列表符号);最终确认单独写一行 `用户最终确认:通过` 或 `用户最终确认:满意`。收尾只检查以状态标记开头的条目行与这行最终标记,不把历史轮次里的字样当作未完成项。 - **必须获用户明确确认(「通过」或「满意」)后才可收尾**;AI 不得自行收尾。 - 用户指出的越界内容(超出高级 I 七篇范围)只记录、不实施(D-14)。 - 修订不得删除 D-53..D-57 要求覆盖的内容;高级 II / III 仍只用代码 span 或 HTML 注释。 @@ -79,7 +80,7 @@ Output: `10-20-USER-REVIEW.md`(用户意见与处置)、最终文档修订 Task 0: 向用户汇报用户修订循环计划并等待「可以执行」 - 向用户汇报:**要做什么**(执行高级 I 的用户主导修订循环:用户逐条提问题 → AI 派子代理修改 → 回报 → 用户继续提,直到用户确认满意;确认后做最终格式与构建收口)、**为什么**(D-46 第 2 阶段 / D-57 要求必须经用户循环且获用户确认才可收尾,不得由 AI 自行收尾)、**大致怎么做**(Task 1 交付构建产物并收集用户意见;Task 2 逐条修改并记录;Task 3 回报并等待用户继续提或确认;用户确认后 Task 4 做最终 prettier / 构建 / SUMMARY)、**影响范围**(可能修改 `docs/advanced/*.md` + 新增 `.planning` 下的用户审阅记录与 SUMMARY;不改 `config.ts` 与生产代码)。停下等待用户明确回复「可以执行」四个字;未收到前不得交付审阅、不得派发修改子代理、不得写任何文件。 + 向用户汇报:**要做什么**(执行高级 I 的用户主导修订循环:用户逐条提问题 → AI 派子代理修改 → 回报 → 用户继续提,直到用户确认满意;确认后做最终格式与构建收口)、**为什么**(D-46 第 2 阶段 / D-57 要求必须经用户循环且获用户确认才可收尾,不得由 AI 自行收尾)、**大致怎么做**(Task 1 交付构建产物并收集用户意见;Task 2 逐条修改并记录;Task 3 回报并等待用户继续提或确认;用户确认后 Task 4 做最终 prettier / 构建 / SUMMARY)、**影响范围**(可能修改 `docs/advanced/*.md` + 新增 `.planning` 下的用户审阅记录与 SUMMARY;不改 `config.ts` 与生产代码)。汇报中同时声明:本计划的修改方式为**派发子代理执行**,范围严格限于 `docs/advanced/*.md` 与 `.planning/.../10-20-USER-REVIEW.md`、`10-20-SUMMARY.md`,执行者不内联修改文档。停下等待用户明确回复「可以执行」四个字;未收到前不得交付审阅、不得派发修改子代理、不得写任何文件。 本计划内容:高级 I 用户主导修订循环 + 用户确认后的收尾。 阅读上面的四段说明,确认「用户确认后才收尾」的流程;如对交付方式(预览命令 / 审阅范围)有要求请一并说明。 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 @@ -91,7 +92,7 @@ Output: `10-20-USER-REVIEW.md`(用户意见与处置)、最终文档修订 Task 1: 交付高级 I 构建产物,收集用户意见 - 先跑 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 确认构建 green、`build complete`、dead link = 0,然后向用户交付:七篇的路径清单、`index.md` 的阅读顺序、本地预览方式 `cmd /c "pnpm docs:preview"`,以及 10-19 的读者审阅结论摘要(阻断问题已清零、非阻断残项列表)。请用户以本领域视角逐条提出:内容是否正确、是否有讲错或讲漏、照着做会不会卡住、系统边界(数据端 only、插件优先、存档/录像/钩子关系)是否讲清、有没有死链或排版问题。**不要替用户判断某条算不算问题**;用户提出的每一条都记录到 `.planning/phases/10-docs-restructure/10-20-USER-REVIEW.md`(意见、定位、状态=待处理)。若用户直接回复「通过」或「满意」,记录该结论并跳到 Task 3 的确认分支;否则本任务结束时带着用户意见清单进入 Task 2。Commit:`docs(10-20): 记录用户修订意见(第1轮)`。 + 先跑 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 确认构建 green、`build complete`、dead link = 0,然后向用户交付:七篇的路径清单、`index.md` 的阅读顺序、本地预览方式 `cmd /c "pnpm docs:preview"`,以及 10-19 的读者审阅结论摘要(阻断问题已清零、非阻断残项列表)。请用户以本领域视角逐条提出:内容是否正确、是否有讲错或讲漏、照着做会不会卡住、系统边界(数据端 only、插件优先、存档/录像/钩子关系)是否讲清、有没有死链或排版问题。**不要替用户判断某条算不算问题**;用户提出的每一条都记录到 `.planning/phases/10-docs-restructure/10-20-USER-REVIEW.md`(意见、定位、`状态:待处理`)。若用户直接回复「通过」或「满意」,就在记录中写独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`,并跳到 Task 3 的确认分支;否则本任务结束时带着用户意见清单进入 Task 2。Commit:`docs(10-20): 记录用户修订意见(第1轮)`。 构建后的高级 I 七篇与预览方式;10-19 的读者审阅结论摘要。 本地 `cmd /c "pnpm docs:preview"` 预览,或直接阅读 `docs/advanced/*.md`;按「内容正确 / 可照做 / 边界清楚 / 链接与排版」四类逐条提问。 请逐条列出问题(可带文件名与章节);若已满意,请直接回复「通过」或「满意」。 @@ -104,9 +105,9 @@ Output: `10-20-USER-REVIEW.md`(用户意见与处置)、最终文档修订 Task 2: 按用户意见逐条派子代理修改并回报 docs/advanced/*.md(按用户意见定位), .planning/phases/10-docs-restructure/10-20-USER-REVIEW.md - 读取 `10-20-USER-REVIEW.md` 中状态为「待处理」的用户意见,逐条派子代理修改对应 `docs/advanced/*.md`:每条意见都要落到具体文件与段落;用户说改哪里就改哪里,不擅自扩大范围;用户指出但属于高级 II/III 或渲染端的内容只记录、不实施(D-14)。每轮修改后:(a) 跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,须 green、`build complete`、dead link = 0;(b) 在 `10-20-USER-REVIEW.md` 把该条状态改为「已处理」并写明处置与改动文件;(c) 向用户回报本轮改了哪些、怎么改的、构建结论。若用户又提出新意见,追加到记录并继续处理——这个循环由 Task 2 / Task 3 反复执行,直到用户确认。守住 D-53..D-57 与 D-48..D-52;不删除要求覆盖的内容;不把高级 II/III 占位改成死链;不改 `config.ts` 与生产代码。每轮 Commit:`docs(10-20): 按用户意见修订高级 I(第N轮)`。 + 读取 `10-20-USER-REVIEW.md` 中 `状态:待处理` 的用户意见,逐条派子代理修改对应 `docs/advanced/*.md`:每条意见都要落到具体文件与段落;用户说改哪里就改哪里,不擅自扩大范围;用户指出但属于高级 II/III 或渲染端的内容只记录、不实施(D-14),状态行写 `状态:越界-不实施`。每轮修改后:(a) 跑构建门禁 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,须 green、`build complete`、dead link = 0;(b) 在 `10-20-USER-REVIEW.md` 把该条状态行改为 `状态:已处理` 并写明处置与改动文件;(c) 向用户回报本轮改了哪些、怎么改的、构建结论。若用户又提出新意见,追加到记录并继续处理——这个循环由 Task 2 / Task 3 反复执行,直到用户确认。守住 D-53..D-57 与 D-48..D-52;不删除要求覆盖的内容;不把高级 II/III 占位改成死链;不改 `config.ts` 与生产代码。每轮 Commit:`docs(10-20): 按用户意见修订高级 I(第N轮)`。 - $ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-20-USER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); if($raw -notmatch '已处理|通过|满意'){ Write-Error "NO-DISPOSITION" }; if($raw -notmatch 'docs/advanced/'){ Write-Error "NO-TARGET" }; $names=@('index','declarative-vs-imperative','plugin-system','saveable-content','replay-consistency','data-stores','hooks-in-depth'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $body=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($body -match "(?&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'FIX-OK' + $ErrorActionPreference='Stop'; $f='.planning/phases/10-docs-restructure/10-20-USER-REVIEW.md'; if(-not(Test-Path -LiteralPath $f)){ Write-Error "MISSING $f" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $f)); if($raw -notmatch '状态:已处理' -and $raw -notmatch '状态:越界-不实施' -and $raw -notmatch '用户最终确认:通过' -and $raw -notmatch '用户最终确认:满意'){ Write-Error "NO-DISPOSITION" }; if($raw -notmatch 'docs/advanced/'){ Write-Error "NO-TARGET" }; $names=@('index','declarative-vs-imperative','plugin-system','saveable-content','replay-consistency','data-stores','hooks-in-depth'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $body=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($body -match "(?&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'FIX-OK' non-zero exit, or output contains "MISSING", "NO-DISPOSITION", "NO-TARGET", "LF-ONLY", "H1-COUNT", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "FIX-OK" 本轮用户意见逐条落到具体段落;记录中状态与改动文件清楚;构建 green、`build complete`、dead link = 0。 @@ -114,12 +115,12 @@ Output: `10-20-USER-REVIEW.md`(用户意见与处置)、最终文档修订 Task 3: 回报修改结果,等待用户继续提或确认满意 - 向用户回报本轮处置:逐条列出用户意见 → 改了哪个文件/段落 → 怎么改的 → 构建结论;附上更新后的预览方式。然后请用户继续审阅:如果还有问题,请继续逐条提出(执行者回到 Task 2 继续改,循环不限轮次,直到用户满意);如果已经满意,请明确回复「通过」或「满意」。**只有用户明确回复「通过」或「满意」才可进入 Task 4 收尾**;用户沉默、只回复「可以」、或回复其它内容都不算确认,不得自行收尾。把用户的确认原文记录到 `10-20-USER-REVIEW.md`。Commit:`docs(10-20): 记录用户确认结论`(仅在用户确认后提交)。 + 向用户回报本轮处置:逐条列出用户意见 → 改了哪个文件/段落 → 怎么改的 → 构建结论;附上更新后的预览方式。然后请用户继续审阅:如果还有问题,请继续逐条提出(执行者回到 Task 2 继续改,循环不限轮次,直到用户满意);如果已经满意,请明确回复「通过」或「满意」。**只有用户明确回复「通过」或「满意」才可进入 Task 4 收尾**;用户沉默、只回复「可以」、或回复其它内容(包括「不满意」「未通过」)都不算确认,不得自行收尾。确认后在 `10-20-USER-REVIEW.md` 写独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`,并附用户原文。Commit:`docs(10-20): 记录用户确认结论`(仅在用户确认后提交)。 按用户意见修订后的高级 I 七篇与逐条处置说明。 按上一轮的预览方式重新查看改动处;确认每条意见都已处理,且没有引入新的错误或死链。 若仍有问题,请逐条列出;若已满意,请回复「通过」或「满意」。 - 用户已明确回复「通过」或「满意」,或提出了新的具体意见。 + 用户已明确回复「通过」或「满意」(不含「不满意」「未通过」),或提出了新的具体意见。 用户确认满意(记录原文),或用户提出了新的具体意见(回到 Task 2)。 @@ -127,9 +128,9 @@ Output: `10-20-USER-REVIEW.md`(用户意见与处置)、最终文档修订 Task 4: 用户确认后的最终格式、构建与 SUMMARY .planning/phases/10-docs-restructure/10-20-USER-REVIEW.md, .planning/phases/10-docs-restructure/10-20-SUMMARY.md, docs/advanced/*.md - **前置:用户已在 Task 3 明确回复「通过」或「满意」;未确认则不得执行本任务。** (1) 最终格式:`node node_modules/prettier/bin/prettier.cjs --write "docs/advanced/*.md"`,再 `--check` 确认通过。(2) 最终构建:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。(3) 最终结构:七篇 kebab-case、CRLF、单 H1;`config.ts` 的 `/advanced/` 侧边栏仍为 7 个目标;无渲染端内容;高级 II/III 仍无真实链接。(4) 在 `10-20-USER-REVIEW.md` 记录最终结论:用户确认原文、最终构建结论、非阻断残项(只记录)。(5) 写 `10-20-SUMMARY.md`,含:七篇清单、用户循环轮次与处置摘要、10-19 读者审阅结论、最终构建 / prettier / 链接结论、未处理项(仅越界或非阻断)、以及「用户已确认收尾」的明确记录。Commit:`docs(10-20): 高级 I 用户修订循环收尾`。 + **前置:`10-20-USER-REVIEW.md` 已有独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`;未确认则不得执行本任务。** (1) 最终格式:`node node_modules/prettier/bin/prettier.cjs --write "docs/advanced/*.md"`,再 `--check` 确认通过。(2) 最终构建:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"`,确认 green、`build complete`、dead link = 0。(3) 最终结构:七篇 kebab-case、CRLF、单 H1;`config.ts` 的 `/advanced/` 侧边栏仍为 7 个目标;无渲染端内容;高级 II/III 仍无真实链接。(4) 在 `10-20-USER-REVIEW.md` 记录最终结论:`用户最终确认:通过/满意` 标记与用户原文、最终构建结论、非阻断残项(只记录,标注 `状态:越界-不实施` 或保留为非阻断说明,不写 `状态:待处理`)。(5) 写 `10-20-SUMMARY.md`,含:七篇清单、用户循环轮次与处置摘要、10-19 读者审阅结论、最终构建 / prettier / 链接结论、未处理项(仅越界或非阻断)、以及「用户已确认收尾」的明确记录。Commit:`docs(10-20): 高级 I 用户修订循环收尾`。 - $ErrorActionPreference='Stop'; $rev='.planning/phases/10-docs-restructure/10-20-USER-REVIEW.md'; $sum='.planning/phases/10-docs-restructure/10-20-SUMMARY.md'; if(-not(Test-Path -LiteralPath $rev)){ Write-Error "MISSING $rev" }; if(-not(Test-Path -LiteralPath $sum)){ Write-Error "MISSING $sum" }; $r=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $rev)); if($r -notmatch '通过|满意'){ Write-Error "NO-USER-CONFIRMATION" }; if($r -match '待处理'){ Write-Error "PENDING-USER-ITEMS" }; $s=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $sum)); foreach($needle in @('用户','确认','构建','七篇')){ if($s -notmatch [regex]::Escape($needle)){ Write-Error "SUMMARY-MISSING $needle" } }; $names=@('index','declarative-vs-imperative','plugin-system','saveable-content','replay-consistency','data-stores','hooks-in-depth'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $body=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($body -match "(?&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'CLOSEOUT-OK' + $ErrorActionPreference='Stop'; $rev='.planning/phases/10-docs-restructure/10-20-USER-REVIEW.md'; $sum='.planning/phases/10-docs-restructure/10-20-SUMMARY.md'; if(-not(Test-Path -LiteralPath $rev)){ Write-Error "MISSING $rev" }; if(-not(Test-Path -LiteralPath $sum)){ Write-Error "MISSING $sum" }; $r=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $rev)); if($r -notmatch '(?m)^\s*(?:[-*]\s*)?用户最终确认:(通过|满意)\s*$'){ Write-Error "NO-USER-CONFIRMATION" }; if($r -match '(?m)^\s*(?:[-*]\s*)?状态:待处理\s*$'){ Write-Error "PENDING-USER-ITEMS" }; $s=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $sum)); foreach($needle in @('用户','确认','构建','七篇')){ if($s -notmatch [regex]::Escape($needle)){ Write-Error "SUMMARY-MISSING $needle" } }; $names=@('index','declarative-vs-imperative','plugin-system','saveable-content','replay-consistency','data-stores','hooks-in-depth'); foreach($n in $names){ $p="docs/advanced/$n.md"; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $body=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($body -match "(?&1; $pfe=$LASTEXITCODE; $out = cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build" 2>&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($pfe -ne 0){ $pf | Write-Output; Write-Error "PRETTIER-FAIL" }; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'CLOSEOUT-OK' non-zero exit, or output contains "MISSING", "NO-USER-CONFIRMATION", "PENDING-USER-ITEMS", "SUMMARY-MISSING", "LF-ONLY", "H1-COUNT", "RENDERER-CONTENT", "ADVANCED-LINKS", "PRETTIER-FAIL", "BUILD-FAIL", "NO-BUILD-COMPLETE", or "DEAD-LINK"; or output lacks "CLOSEOUT-OK" 用户确认已记录且无待处理项;七篇结构正确、无渲染端内容;prettier 检查通过;构建 green、`build complete`、dead link = 0;SUMMARY 写明用户确认收尾。 @@ -159,7 +160,7 @@ Output: `10-20-USER-REVIEW.md`(用户意见与处置)、最终文档修订 - 机制门禁:`10-20-USER-REVIEW.md` 含每轮用户意见、定位、处置、构建结论与最终确认原文。 -- 确认门禁:用户明确回复「通过」或「满意」;记录中无「待处理」项。 +- 确认门禁:记录含独占一行的 `用户最终确认:通过` 或 `用户最终确认:满意`;条目级 `状态:待处理` 为 0(越界项记 `状态:越界-不实施`)。历史轮次文本中的「待处理」字样不计。 - 构建门禁:每轮及收尾均 `cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` 通过(green / `build complete` / dead link = 0)。 - 格式门禁:prettier `--check` 对七篇通过。 - 结构门禁:七篇 kebab-case、CRLF、单 H1;侧边栏 7 个目标正确。 diff --git a/.planning/phases/10-docs-restructure/10-CONTEXT.md b/.planning/phases/10-docs-restructure/10-CONTEXT.md index 00b0a01..b192266 100644 --- a/.planning/phases/10-docs-restructure/10-CONTEXT.md +++ b/.planning/phases/10-docs-restructure/10-CONTEXT.md @@ -112,13 +112,13 @@ ### 文档写作流程(长期规范,适用于后续所有文档写作,不止本批) -- **D-45(prettier 格式化):** 文档写完后**必须**跑 prettier 格式化——prettier 也管 markdown;不格式化虽不报 eslint 错,但用户日后手动修改会产生大量格式变动。推荐命令:`node node_modules/prettier/bin/prettier.cjs --write "docs/intermediate/*.md"`(或等价的 `pnpm exec prettier --write`)。若格式化会阻断某条命令执行,**先跳过并在对话中提出**,由用户自行格式化。 -- **D-46(两阶段修订循环):** 修订必须依次经过两阶段,缺一不可: +- **D-45:** prettier 格式化。文档写完后**必须**跑 prettier 格式化——prettier 也管 markdown;不格式化虽不报 eslint 错,但用户日后手动修改会产生大量格式变动。推荐命令:`node node_modules/prettier/bin/prettier.cjs --write "docs/intermediate/*.md"`(或等价的 `pnpm exec prettier --write`)。若格式化会阻断某条命令执行,**先跳过并在对话中提出**,由用户自行格式化。 +- **D-46:** 两阶段修订循环。修订必须依次经过两阶段,缺一不可: 1. **子代理自审循环**:如 plan-checker,以及**按文档实际情况选择合适视角**的子代理反向审阅(面向新手的文档可用「不懂代码的读者」人格;面向有基础作者或特定领域的文档,应选更贴近该受众/领域的视角)→ 问题清单 → 迭代修正。**审阅视角不固定为「不懂代码的读者」,须因文档而异。** 2. **用户主导的修订循环**:用户以更贴近本领域的视角提出问题 → AI 派子代理逐条修改文档 → 回报 → 用户继续提,直到用户满意并确认。 **必须经过用户循环且获用户确认后才可收尾**,不得由 AI 自行收尾。适用于后续所有文档写作。 -- **D-47(高级教程预留,修订 D-16):** 凡「留到高级教程细讲」的内容,必须**显式说明**并**预留链接标记**。由于 `docs/advanced/` 尚未建立,**不得**写指向它的真实 markdown 链接(会造成死链、构建失败);改用非断链占位(如代码 span `高级教程 · ` 或 ``),待高级教程存在后再替换为真链接。此条在「高级教程引用」范围内取代 D-16 的「禁元叙述」。 -- **D-48(实操写法,长期规范):** 系统/原理讲解保持现状(可以讲、且现在这样就好);需要重做的是**「实操/示例」部分**。每处实操统一写成可分步照抄的形式: +- **D-47:** 高级教程预留,修订 D-16。凡「留到高级教程细讲」的内容,必须**显式说明**并**预留链接标记**。由于 `docs/advanced/` 尚未建立,**不得**写指向它的真实 markdown 链接(会造成死链、构建失败);改用非断链占位(如代码 span `高级教程 · ` 或 ``),待高级教程存在后再替换为真链接。此条在「高级教程引用」范围内取代 D-16 的「禁元叙述」。 +- **D-48:** 实操写法,长期规范。系统/原理讲解保持现状(可以讲、且现在这样就好);需要重做的是**「实操/示例」部分**。每处实操统一写成可分步照抄的形式: 1. **目标**:先说要做出什么效果; 2. **改哪里**:哪个文件、文件内哪个位置; 3. **复制什么**:只给要新增的那段,**不含 `import`**;写清「顶部通常已有这些 import,不要再粘;若报缺少 X,再在顶部补 `import ...`」; @@ -126,31 +126,31 @@ 5. **怎么验证**:改完看什么现象; 6. **注意**:常见错误、别碰什么。 另外:示例取**最短可行**(如「下次战斗伤害翻倍」直接用 `onAfterCombat`,不额外写战后脚本);**不写 `dev.md` 的引擎开发约定**(如 import 必须置顶、注释位置等);**不写发布前/数量类无关信息**(如「发布前会有约 100 个内置事件」)。适用于后续所有文档写作。 -- **D-49(示例与「改内置优先」):** +- **D-49:** 示例与「改内置优先」。 1. 示例代码必须**贴合引擎现状**:定义 `class` 再 `new`,**不要**写 `const obj = { ... }` 这类 plain object(引擎代码即如此)。例外:引擎本身就以对象字面量声明的内容(如 `src/content/item.ts` 的 `ItemEffect`),可沿用其现有写法。 2. 文档主体应主要讲**如何改内置类**(如 `src/data/enemy/*`、`src/data/hook/*` 中已有的类);在**末尾**再简述「何时需要自己新写类、怎么写」。 3. 必须明确写明:**如果你不怎么懂代码,建议直接改内置,而不是自己写新的类。** -- **D-50(通用模板 vs 示例):** 对每类可扩展机制,文档要提供的是**机制本身的通用模板**,而不是某个具体效果的模板/示例: +- **D-50:** 通用模板 vs 示例。对每类可扩展机制,文档要提供的是**机制本身的通用模板**,而不是某个具体效果的模板/示例: 1. 单独一节(如「模板:复制什么、改什么」),给出一段可复制的**骨架**(类 / 转换器 / 视图 / 效果等),并用 `[需改]` 标出作者需按自己需求修改的部分; 2. 模板与示例**分开**,不要把某个特定效果(如某个具体光环)当作模板; 3. 示例仅用于辅助说明,尽量短。 示例:光环应给「光环转换器 + 光环视图」的通用骨架 + 需改点,而不是给「减少金币经验的光环」当模板。 -- **D-51(特殊属性实现的落点与讲解方式):** +- **D-51:** 特殊属性实现的落点与讲解方式。 1. **不要建议新建文件**:已有实现文件(如光环的 `src/data/enemy/aura.ts`)就全部写在其中,不要建议「新增一个自己的文件」。样板集中放置是为了方便管理与后续编辑器自动识别;只有**查询属性**需要单独新建 `query.ts`。 2. 对 `aura.ts` / `query.ts` 这类独立的特殊属性实现,建议用 `#region` 包裹,结构更清晰、后续编辑器也可能据此识别。暂定识别约定:`//#region {code}-{name}` … `//#endregion`。 3. 必须用**通俗语言解释「副作用」是什么**(刚接触代码的作者不懂这个概念)。 4. 说明**地图伤害是按「计算后怪物」计算**的:因此若光环给怪物新增了「领域」这类属性,该怪物确实会有领域效果;旧样板无法动态给怪物加特殊属性,这一点值得单独说明。若某种属性确实既要依赖外部环境、又要修改外部环境,应拆成「查询效果 + 光环效果」两个,二者通过新增一个怪物属性桥接(指向高级教程)。 5. `getCriticalLimit` 一般用不到,提一句即可,并说明高级教程会详细讲。 6. **接口讲解方式**:不要上来就搬接口列表;先说「为了实现 X,我们需要修改 Y 接口」,再讲这个接口的参数,这样更自然。 -- **D-52(加粗边界,长期规范):** `**加粗**` 的内容**不要以标点开头或结尾**(CommonMark emphasis 边界规则会导致不渲染)。若确需加粗含标点的短语,应调整结构,使 `**` 相邻处为标点/空白,或改用 HTML ``。提交前用 flanking 规则自检所有 markdown。适用于后续所有文档写作。 -- **D-53(高级教程分层):** 高级教程本身按难度/依赖分为 **I / II / III** 三层(避免与顶层「初级/中级/高级教程」撞名): - - **I**:核心为**插件系统**,后续内容都是基于插件系统的拓展; - - **II**:系统级实现(如战斗上下文/光环/查询/优先级、伤害与地图伤害、渲染层与布局、加载与插件生命周期、自定义录像行为等); - - **III**:原理与架构(双端分离约束、数据端 L0–L3、编辑器识别协议、录像深层原理、性能与调试等)。 - 由于渲染端尚未完工,**当前只规划/编写数据端内容**。 -- **D-54(高级教程定位):** 文档面向**使用者**(不是引擎编写者):在适度解析的同时,必须告诉读者**怎么用、怎么改、怎么自定义**;仍沿用 D-48(实操六步)、D-49(改内置优先/类示例)、D-50(通用模板单独成节)、D-51(落点/副作用/接口讲解方式)、D-52(加粗边界)等规范。 -- **D-55(优先插件):** 明确建议:**新增系统优先通过插件系统实现**;只有不得不修改内置系统时才去改内部。理由:版本迁移时 `src` 基本不会改,但内置包(`packages` / `packages-user`)有可能会改,改内置会增加升级时的维护成本。 -- **D-56(高级 I 内容,7 篇):** +- **D-52:** 加粗边界,长期规范。`**加粗**` 的内容**不要以标点开头或结尾**(CommonMark emphasis 边界规则会导致不渲染)。若确需加粗含标点的短语,应调整结构,使 `**` 相邻处为标点/空白,或改用 HTML ``。提交前用 flanking 规则自检所有 markdown。适用于后续所有文档写作。 +- **D-53:** 高级教程分层。高级教程本身按**难度/深度**(而非领域)分为 **I / II / III** 三层(避免与顶层「初级/中级/高级教程」撞名): + - **I(基础扩展)**:较低门槛,核心为插件系统与基本扩展机制; + - **II(深入定制)**:中等门槛,需要理解并修改引擎的特定系统(主题不固定,可能落数据端也可能落渲染端); + - **III(原理与架构)**:最高门槛,系统性讲解设计原理与架构。 + 由于渲染端尚未完工,**当前只规划/编写数据端内容**。分层是**难度标签,不是领域分类**;具体主题可能在层间调整。 +- **D-54:** 高级教程定位。文档面向**使用者**(不是引擎编写者):在适度解析的同时,必须告诉读者**怎么用、怎么改、怎么自定义**;仍沿用 D-48(实操六步)、D-49(改内置优先/类示例)、D-50(通用模板单独成节)、D-51(落点/副作用/接口讲解方式)、D-52(加粗边界)等规范。 +- **D-55:** 优先插件。明确建议:**新增系统优先通过插件系统实现**;只有不得不修改内置系统时才去改内部。理由:版本迁移时 `src` 基本不会改,但内置包(`packages` / `packages-user`)有可能会改,改内置会增加升级时的维护成本。 +- **D-56:** 高级 I 内容,7 篇。 1. **高级 I 导览**:I/II/III 分层、阅读路径与前置、D-55 原则; 2. **声明式 vs 命令式接口**:旧样板命令式(写一行即生效)vs 新样板声明式(告诉系统要做什么,系统在合适时机执行);必须讲透,作为后续基础; 3. **插件系统**:自定义新插件、插件间调用、`dependencies` 依赖与排序、生命周期进阶、插件 id 稳定性与版本迁移; @@ -159,7 +159,36 @@ 6. **data-common 的 Store**:讲清各 Store 存了什么,明确是**内容层原始数据**、运行时一般**只读**,修改很可能绕过存档/录像/一致性而引发问题; 7. **钩子深入**:多对象场景(地图与图层)、如何判断「触发者是不是我关心的 map/layer」(身份校验)、同一钩子被多个对象复用、注册/移除与异步钩子。 每篇仍保留「怎么验证」。 -- **D-57(高级 I 读者修订循环):** 高级 I 完成后,**必须**再走用户主导的修订循环(D-46 第 2 阶段);且这次的读者人格**不能复用中级教程的「不懂代码的游戏作者」**——应面向**有一定代码基础、已读完中级教程、想做深度定制/理解扩展机制**的作者(具体人格在计划中明确,并经用户确认)。 +- **D-57:** 高级 I 读者修订循环。高级 I 完成后,**必须**再走用户主导的修订循环(D-46 第 2 阶段);且这次的读者人格**不能复用中级教程的「不懂代码的游戏作者」**——应面向**对代码有一定了解、了解基本语法(变量/函数/类/import 等),但代码能力一般、不熟悉引擎内部架构**的作者(既不是完全不懂代码,也不预设过高的代码水平;代码能力一般的作者同样需要高级定制内容)。**高级 I 用较低标准,高级 II / III 可适当提高标准。**具体人格在计划中明确,并经用户确认。 +- **D-58:** **D-49/D-50 的「改内置还是自己新增」取舍与「必须提供通用模板章节」只适用于中级教程。** 高级教程**不强制**提供模板章节:是否提供视文档内容而定(有些可以加,有些不用加)。高级教程的取舍原则仍是 D-55(优先插件、必要时才改内置);不要求逐字写「不懂代码就改内置」这类中级提示。 +- **D-59:** **高级教程写作风格(修订 D-48 在高级教程中的适用):** 高级教程按**一般库文档**的方式写(但读者门槛略低于一般库文档,需要多解释概念),**不再使用中级教程的「复制什么 / 改什么」六步实操**,也不要把读者当成什么都不懂。 + - 提供**示例代码 + 注释解释**即可:先说明要做什么,再给出完整示例(含解释性注释),最后说明如何在需要的地方加载/接入(注释标明写在哪里)。 + - 保留必要的概念解释与验证,但用叙述方式,不要步骤化说教。 + - 不写「如果你不怎么懂代码」这类提示(与 D-58 一致)。 + - 适用于高级 I / II / III。 +- **D-60(简洁优先,长期规范):** **文档不是讲得越多越好。** 所有文档的核心目的是让读者知道「怎么用接口」;理解原理也只是为了更好地用。判断标准: + - 能删的就删,避免面面俱到; + - 不重复其他教程(如中级已讲过的内容)已经讲清的内容; + - 对「几乎不可能需要自定义」的内容(如 Store),只讲内置接口怎么用,不展开「自己写」与验证; + - 高级教程尤其要克制:按库文档方式,只保留读者真正需要的说明与示例。 + 适用于后续所有文档写作。 +- **D-61(主干与边界分离,长期规范):** 文档的**主干只讲最核心的内容**;**边界情况、特殊情况不要混入主干**,应在文末**单独开一节**(如「边界与注意」)集中说明。适用于后续所有文档写作。 +- **D-62(代码块结构完整,长期规范):** 文档中的代码块必须是**完整、结构正确的片段**(完整的类 / 函数 / 文件级片段),能让语法高亮正常解析;**不要单独写某个类成员或脱离上下文的片段**。必要时用注释省略无关部分,但仍需保留结构完整。适用于后续所有文档写作。 +- **D-63(模板的组织顺序,长期规范):** 模板**不要放在文档最开头**。正确顺序是:先讲**理念/概念**(要解决什么问题、可以做哪些扩展)→ 再给引导语(「如果想……,可参考下述模板」)→ 模板代码 → 解释模板做了什么、声明了什么类、实现了什么接口、需要自己改什么。适用于后续所有文档写作。 +- **D-64(模板 vs 纯接口,长期规范):** 只有**需要读者自己实现接口或注册内容**时,才提供完整模板;**纯接口使用**(如 Store)只给示例,不给模板。适用于后续所有文档写作。 +- **D-65(示例注释,长期规范):** 示例代码**必须加解释性注释**;注释**越多越好**,以降低读者的理解难度。适用于后续所有文档写作。 +- **D-66(杂类功能的示例分开写,长期规范):** 对内容较杂的功能(如多个 Store 并列),**示例必须按功能分开写**,一个功能一段示例,**不要合并成一大块**;示例应与它所讲的功能**直接对应**。适用于后续所有教程文档的编写。 +- **D-67(高级 II 内容,暂定):** 高级 II 定位为「**深入定制**」(难度层,非领域分类)。**本规划为暂定**,后续可能调整(例如发现高级 I 仍有遗漏内容时),当前先完成高级 II。高级 II 也需要一篇**导览**。拟含 8 个主题 + 导览: + 1. **高级 II 导览**:本层难度定位、前置(高级 I + 中级相关篇目)、阅读路径; + 2. **自定义范围对象**:`IRange` / 范围参数 / 绑定宿主;被光环、地图伤害等复用; + 3. **静态图块与动态图块**:两者区别与转换;**专门讲点事件与图块事件**; + 4. **勇士的装备系统**:装备实例仓、修饰器、排序器、`compareEquip`、装备事件; + 5. **自定义录像指令**:指令码、`IReplayCommand`、主动/被动、注册与沙盒播放; + 6. **自动寻路**:只讲流程(构建图 → Dijkstra 求路径 → 交给移动器),不讲算法细节; + 7. **新增勇士属性**:修改 `IHeroAttr`;示例用**攻速**(每回合造成 `atkSpeed%` 伤害)与**护甲**(战斗百分比减伤);接入修饰器/伤害计算器;编辑器新增项、状态栏显示等按 D-47 **留空**; + 8. **新增怪物属性**:修改 `IEnemyAttr`;同样用攻速/护甲举例;接入战斗/光环/查询;编辑器新增项、怪物手册(图鉴)修改按 D-47 **留空**; + 9. **怪物上下文与战斗深入**:buildup 管线、优先级、缓存/脏标记、伤害系统与光环/查询/最终的交互。 + 推荐顺序:导览 → 范围对象 → 图块(含点事件/图块事件)→ 装备 → 录像指令 → 寻路 → 勇士属性 → 怪物属性 → 怪物上下文与战斗。仍以数据端为主;渲染端与编辑器内容按 D-47 占位。 diff --git a/.planning/state.json b/.planning/state.json index 264be63..be8e2f3 100644 --- a/.planning/state.json +++ b/.planning/state.json @@ -47,12 +47,17 @@ "number": "9", "name": "最小浏览器可运行版本", "status": "in_progress" + }, + { + "number": "10", + "name": "文档重构", + "status": "in_progress" } ], "next": { "command": "/gsd:progress --next", "label": "Advance to the next step", - "reason": "Phase 9 of 9 · executing" + "reason": "Phase 10 of 10 · in progress(中级 + 高级 I 已收尾)" }, - "updated_at": "2026-10-14T06:06:22.109Z" + "updated_at": "2026-10-20T00:00:00.000Z" }