From 1239fb46516bfdc2dc2f6d5f6c995ac4112b1f46 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:13:22 +0800 Subject: [PATCH] =?UTF-8?q?refactor(skills):=20=E7=BB=9F=E4=B8=80=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E5=88=B7=E6=96=B0=E6=8A=80=E8=83=BD=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 gframework-doc-refresh 统一技能入口,并补齐模块扫描、证据顺序、模板与校验脚本 - 更新共享文档规范与模块映射,收口源码模块到 README、docs 和 ai-libs 的固定关联 - 删除旧 vitepress-* 公开技能定义,避免继续以文档类型拆分入口 - 同步 documentation-governance-and-refresh 的恢复点、风险和下一步 --- .agents/skills/README.md | 52 ++ .../skills/_shared/DOCUMENTATION_STANDARDS.md | 108 ++++ .agents/skills/_shared/module-config.sh | 256 ++++++++++ .agents/skills/_shared/module-map.json | 434 ++++++++++++++++ .../_shared/scripts/generate-examples.sh | 0 .../_shared/scripts/parse-csharp-xml.sh | 0 .../_shared/scripts/update-vitepress-nav.sh | 0 .../skills/gframework-boot/SKILL.md | 0 .../skills/gframework-boot/agents/openai.yaml | 0 .../references/startup-artifacts.md | 0 .../skills/gframework-doc-refresh/SKILL.md | 205 ++++++++ .../gframework-doc-refresh/agents/openai.yaml | 4 + .../references/evidence-and-ai-libs.md | 35 ++ .../references/module-selection.md | 29 ++ .../references/output-strategy.md | 38 ++ .../scripts/scan_module_evidence.py | 226 +++++++++ .../scripts/validate-all.sh | 67 +++ .../scripts/validate-code-blocks.sh | 56 +++ .../scripts/validate-frontmatter.sh | 40 ++ .../scripts/validate-links.sh | 42 +- .../templates/api-reference.md | 27 + .../templates/module-landing.md | 30 ++ .../templates/topic-refresh.md | 26 + .../templates/tutorial.md | 30 ++ .../skills/gframework-pr-review/SKILL.md | 0 .../gframework-pr-review/agents/openai.yaml | 0 .../scripts/fetch_current_pr_review.py | 0 .claude/skills/README.md | 469 ------------------ .../skills/_shared/DOCUMENTATION_STANDARDS.md | 205 -------- .claude/skills/_shared/module-config.sh | 84 ---- .claude/skills/vitepress-api-doc/SKILL.md | 210 -------- .../examples/class-example.md | 252 ---------- .../examples/enum-example.md | 193 ------- .../examples/interface-example.md | 290 ----------- .claude/skills/vitepress-api-doc/template.md | 37 -- .claude/skills/vitepress-batch-api/SKILL.md | 364 -------------- .../scripts/batch-generate.sh | 81 --- .../skills/vitepress-doc-generator/SKILL.md | 52 -- .../vitepress-doc-generator/template.md | 0 .claude/skills/vitepress-guide/SKILL.md | 256 ---------- .../vitepress-guide/examples/guide-example.md | 283 ----------- .claude/skills/vitepress-guide/template.md | 34 -- .claude/skills/vitepress-tutorial/SKILL.md | 253 ---------- .../examples/tutorial-example.md | 347 ------------- .claude/skills/vitepress-tutorial/template.md | 42 -- .claude/skills/vitepress-validate/SKILL.md | 297 ----------- .../scripts/validate-all.sh | 109 ---- .../scripts/validate-code-blocks.sh | 64 --- .../scripts/validate-frontmatter.sh | 57 --- ...ntation-governance-and-refresh-tracking.md | 32 +- ...umentation-governance-and-refresh-trace.md | 54 ++ 51 files changed, 1751 insertions(+), 4019 deletions(-) create mode 100644 .agents/skills/README.md create mode 100644 .agents/skills/_shared/DOCUMENTATION_STANDARDS.md create mode 100644 .agents/skills/_shared/module-config.sh create mode 100644 .agents/skills/_shared/module-map.json rename {.claude => .agents}/skills/_shared/scripts/generate-examples.sh (100%) rename {.claude => .agents}/skills/_shared/scripts/parse-csharp-xml.sh (100%) rename {.claude => .agents}/skills/_shared/scripts/update-vitepress-nav.sh (100%) rename {.codex => .agents}/skills/gframework-boot/SKILL.md (100%) rename {.codex => .agents}/skills/gframework-boot/agents/openai.yaml (100%) rename {.codex => .agents}/skills/gframework-boot/references/startup-artifacts.md (100%) create mode 100644 .agents/skills/gframework-doc-refresh/SKILL.md create mode 100644 .agents/skills/gframework-doc-refresh/agents/openai.yaml create mode 100644 .agents/skills/gframework-doc-refresh/references/evidence-and-ai-libs.md create mode 100644 .agents/skills/gframework-doc-refresh/references/module-selection.md create mode 100644 .agents/skills/gframework-doc-refresh/references/output-strategy.md create mode 100644 .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py create mode 100644 .agents/skills/gframework-doc-refresh/scripts/validate-all.sh create mode 100644 .agents/skills/gframework-doc-refresh/scripts/validate-code-blocks.sh create mode 100644 .agents/skills/gframework-doc-refresh/scripts/validate-frontmatter.sh rename {.claude/skills/vitepress-validate => .agents/skills/gframework-doc-refresh}/scripts/validate-links.sh (55%) create mode 100644 .agents/skills/gframework-doc-refresh/templates/api-reference.md create mode 100644 .agents/skills/gframework-doc-refresh/templates/module-landing.md create mode 100644 .agents/skills/gframework-doc-refresh/templates/topic-refresh.md create mode 100644 .agents/skills/gframework-doc-refresh/templates/tutorial.md rename {.codex => .agents}/skills/gframework-pr-review/SKILL.md (100%) rename {.codex => .agents}/skills/gframework-pr-review/agents/openai.yaml (100%) rename {.codex => .agents}/skills/gframework-pr-review/scripts/fetch_current_pr_review.py (100%) delete mode 100644 .claude/skills/README.md delete mode 100644 .claude/skills/_shared/DOCUMENTATION_STANDARDS.md delete mode 100644 .claude/skills/_shared/module-config.sh delete mode 100644 .claude/skills/vitepress-api-doc/SKILL.md delete mode 100644 .claude/skills/vitepress-api-doc/examples/class-example.md delete mode 100644 .claude/skills/vitepress-api-doc/examples/enum-example.md delete mode 100644 .claude/skills/vitepress-api-doc/examples/interface-example.md delete mode 100644 .claude/skills/vitepress-api-doc/template.md delete mode 100644 .claude/skills/vitepress-batch-api/SKILL.md delete mode 100644 .claude/skills/vitepress-batch-api/scripts/batch-generate.sh delete mode 100644 .claude/skills/vitepress-doc-generator/SKILL.md delete mode 100644 .claude/skills/vitepress-doc-generator/template.md delete mode 100644 .claude/skills/vitepress-guide/SKILL.md delete mode 100644 .claude/skills/vitepress-guide/examples/guide-example.md delete mode 100644 .claude/skills/vitepress-guide/template.md delete mode 100644 .claude/skills/vitepress-tutorial/SKILL.md delete mode 100644 .claude/skills/vitepress-tutorial/examples/tutorial-example.md delete mode 100644 .claude/skills/vitepress-tutorial/template.md delete mode 100644 .claude/skills/vitepress-validate/SKILL.md delete mode 100644 .claude/skills/vitepress-validate/scripts/validate-all.sh delete mode 100644 .claude/skills/vitepress-validate/scripts/validate-code-blocks.sh delete mode 100644 .claude/skills/vitepress-validate/scripts/validate-frontmatter.sh diff --git a/.agents/skills/README.md b/.agents/skills/README.md new file mode 100644 index 00000000..b5913ec3 --- /dev/null +++ b/.agents/skills/README.md @@ -0,0 +1,52 @@ +# GFramework Skills + +文档工作流的公开入口已统一为 `gframework-doc-refresh`。 + +## 公开入口 + +### `gframework-doc-refresh` + +按源码模块驱动文档刷新,而不是按 `guide`、`tutorial`、`api` 等类型拆入口。 + +适用场景: + +- 刷新某个模块的 landing page +- 复核专题页是否与源码、测试、README 一致 +- 评估是否需要补 API reference 或教程 +- 在 adoption path 不清晰时引入 `ai-libs/` 消费者接法作为补充证据 + +推荐调用: + +```bash +/gframework-doc-refresh +``` + +示例: + +```bash +/gframework-doc-refresh Core +/gframework-doc-refresh Godot.SourceGenerators +/gframework-doc-refresh Cqrs +``` + +## 共享资源 + +- `_shared/DOCUMENTATION_STANDARDS.md` + - 统一的文档规则、证据顺序与验证要求 +- `_shared/module-map.json` + - 机器可读的模块映射表 +- `_shared/module-config.sh` + - 轻量 shell 辅助函数 + +## 内部资源 + +`gframework-doc-refresh/` 下包含: + +- `references/` + - 模块选择、证据顺序、输出策略 +- `templates/` + - landing page、专题页、API reference、教程模板 +- `scripts/` + - 模块扫描与文档验证脚本 + +旧 `vitepress-*` skills 不再作为并列公开入口保留。 diff --git a/.agents/skills/_shared/DOCUMENTATION_STANDARDS.md b/.agents/skills/_shared/DOCUMENTATION_STANDARDS.md new file mode 100644 index 00000000..70678847 --- /dev/null +++ b/.agents/skills/_shared/DOCUMENTATION_STANDARDS.md @@ -0,0 +1,108 @@ +# GFramework 文档编写规范 + +本文件只保留跨模块稳定生效的写作与校验规则,不再维护容易失真的固定页面清单。 + +模块到源码、测试、README、`docs/zh-CN` 栏目以及 `ai-libs/` 参考入口的映射,统一以 +`.agents/skills/_shared/module-map.json` 为准。 + +## 证据顺序 + +统一按以下顺序判断文档应写什么、删什么、保留什么: + +1. 源码、公开 XML docs、`*.csproj` +2. 对应测试和 snapshot +3. 模块 `README.md` +4. 当前 `docs/zh-CN` 页面 +5. `ai-libs/` 下已验证的消费者项目 +6. 归档文档,仅在前述证据无法解释当前行为时回看 + +不要把旧文档互相抄写当成“更新”。 + +## 模块驱动规则 + +- 先按源码模块归一化输入,再决定落到 landing page、专题页、API reference、教程还是仅做校验。 +- 如果用户给的是栏目名而不是源码模块名,先映射回模块;若仍有歧义,只给归一化建议,不直接生成文档。 +- 文档栏目是派生输出,不是主输入源。 + +## `ai-libs/` 使用边界 + +`ai-libs/` 只用于补消费者视角证据: + +- 验证真实接入目录结构 +- 查最小 wiring、扩展点装配方式 +- 给 adoption path 提供端到端例子 + +不要用 `ai-libs/` 覆盖以下事实: + +- 公共 API 契约 +- 当前版本支持范围 +- Source Generator 诊断与生成语义 + +如果 `ai-libs/` 与当前源码或测试冲突,以当前仓库实现为准,并在文档里写明迁移或兼容边界。 + +## Markdown 规则 + +### 泛型与 HTML 转义 + +代码块外出现泛型或 XML 标签时必须转义: + +- `List<T>` +- `Result<TValue, TError>` +- `<summary>` +- `<param>` + +### Frontmatter + +每个文档都必须包含合法 frontmatter: + +```yaml +--- +title: 文档标题 +description: 1-2 句话描述当前页面解决什么问题 +--- +``` + +### 代码块 + +- 始终标注语言,如 `csharp`、`bash`、`json` +- 示例只保留当前实现可追溯的最小路径 +- 必要时写中文注释解释接入原因或边界,不要堆砌与代码同步无关的注释 + +### 链接 + +- 只链接到当前仓库真实存在的页面 +- 站内链接优先使用 `/zh-CN/...` 形式 +- 如果文档站不允许跳出 `docs/` 根目录,就不要把仓库 README 写成站内链接 + +## 输出优先级 + +统一按以下顺序决定产出: + +1. 先修模块 README、landing page 与 adoption path +2. 再修失真的专题页 +3. 再补 API reference +4. 最后才补教程 + +## 验证清单 + +- [ ] frontmatter 正确 +- [ ] 代码块语言标记齐全 +- [ ] 泛型和 XML 标签已转义 +- [ ] 站内链接存在 +- [ ] 示例与当前实现一致 +- [ ] `ai-libs/` 只作为消费者接入参考,没有覆盖源码契约 + +## 验证工具 + +统一复用 `gframework-doc-refresh/scripts/` 下的校验脚本: + +- `validate-frontmatter.sh` +- `validate-links.sh` +- `validate-code-blocks.sh` +- `validate-all.sh` + +需要站点级验证时,执行: + +```bash +cd docs && bun run build +``` diff --git a/.agents/skills/_shared/module-config.sh b/.agents/skills/_shared/module-config.sh new file mode 100644 index 00000000..85f43deb --- /dev/null +++ b/.agents/skills/_shared/module-config.sh @@ -0,0 +1,256 @@ +#!/bin/bash +# 共享的模块配置 +# 机器可读映射以 .agents/skills/_shared/module-map.json 为准。 + +normalize_module() { + local INPUT + INPUT="$(echo "$1" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr '_' '-')" + + case "$INPUT" in + core|core-runtime|runtime-core|core-module) + echo "Core" + ;; + core.abstractions|core-abstractions) + echo "Core.Abstractions" + ;; + core.sourcegenerators|core-source-generators|core-sourcegenerators) + echo "Core.SourceGenerators" + ;; + core.sourcegenerators.abstractions|core-source-generators-abstractions) + echo "Core.SourceGenerators.Abstractions" + ;; + game|game-runtime|runtime-game|game-module) + echo "Game" + ;; + game.abstractions|game-abstractions) + echo "Game.Abstractions" + ;; + game.sourcegenerators|game-source-generators) + echo "Game.SourceGenerators" + ;; + godot|godot-runtime|runtime-godot|godot-module) + echo "Godot" + ;; + godot.sourcegenerators|godot-source-generators|godot-generators) + echo "Godot.SourceGenerators" + ;; + godot.sourcegenerators.abstractions|godot-source-generators-abstractions) + echo "Godot.SourceGenerators.Abstractions" + ;; + cqrs|mediator|cqrs-module) + echo "Cqrs" + ;; + cqrs.abstractions|cqrs-abstractions) + echo "Cqrs.Abstractions" + ;; + cqrs.sourcegenerators|cqrs-source-generators) + echo "Cqrs.SourceGenerators" + ;; + ecs|ecs.arch|ecs-arch) + echo "Ecs.Arch" + ;; + ecs.arch.abstractions|ecs-arch-abstractions) + echo "Ecs.Arch.Abstractions" + ;; + sourcegenerators.common|source-generators-common) + echo "SourceGenerators.Common" + ;; + *) + return 1 + ;; + esac +} + +get_all_modules() { + cat <<'EOF' +Core +Core.Abstractions +Core.SourceGenerators +Core.SourceGenerators.Abstractions +Game +Game.Abstractions +Game.SourceGenerators +Godot +Godot.SourceGenerators +Godot.SourceGenerators.Abstractions +Cqrs +Cqrs.Abstractions +Cqrs.SourceGenerators +Ecs.Arch +Ecs.Arch.Abstractions +SourceGenerators.Common +EOF +} + +is_valid_module() { + normalize_module "$1" >/dev/null 2>&1 +} + +get_source_dirs() { + local MODULE + MODULE="$(normalize_module "$1")" || return 1 + + case "$MODULE" in + Core) + echo "GFramework.Core" + ;; + Core.Abstractions) + echo "GFramework.Core.Abstractions" + ;; + Core.SourceGenerators) + echo "GFramework.Core.SourceGenerators" + ;; + Core.SourceGenerators.Abstractions) + echo "GFramework.Core.SourceGenerators.Abstractions" + ;; + Game) + echo "GFramework.Game" + ;; + Game.Abstractions) + echo "GFramework.Game.Abstractions" + ;; + Game.SourceGenerators) + echo "GFramework.Game.SourceGenerators" + ;; + Godot) + echo "GFramework.Godot" + ;; + Godot.SourceGenerators) + echo "GFramework.Godot.SourceGenerators" + ;; + Godot.SourceGenerators.Abstractions) + echo "GFramework.Godot.SourceGenerators.Abstractions" + ;; + Cqrs) + echo "GFramework.Cqrs" + ;; + Cqrs.Abstractions) + echo "GFramework.Cqrs.Abstractions" + ;; + Cqrs.SourceGenerators) + echo "GFramework.Cqrs.SourceGenerators" + ;; + Ecs.Arch) + echo "GFramework.Ecs.Arch" + ;; + Ecs.Arch.Abstractions) + echo "GFramework.Ecs.Arch.Abstractions" + ;; + SourceGenerators.Common) + echo "GFramework.SourceGenerators.Common" + ;; + esac +} + +get_test_projects() { + local MODULE + MODULE="$(normalize_module "$1")" || return 1 + + case "$MODULE" in + Core|Core.Abstractions) + echo "GFramework.Core.Tests/GFramework.Core.Tests.csproj" + ;; + Core.SourceGenerators|Core.SourceGenerators.Abstractions|Game.SourceGenerators|Cqrs.SourceGenerators|SourceGenerators.Common) + echo "GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj" + ;; + Game|Game.Abstractions) + echo "GFramework.Game.Tests/GFramework.Game.Tests.csproj" + ;; + Godot) + echo "GFramework.Godot.Tests/GFramework.Godot.Tests.csproj" + ;; + Godot.SourceGenerators|Godot.SourceGenerators.Abstractions) + echo "GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj" + ;; + Cqrs|Cqrs.Abstractions) + echo "GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj" + ;; + Ecs.Arch|Ecs.Arch.Abstractions) + echo "GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj" + ;; + esac +} + +get_readme_paths() { + local MODULE + MODULE="$(normalize_module "$1")" || return 1 + + case "$MODULE" in + Core) + echo "GFramework.Core/README.md" + ;; + Core.Abstractions) + echo "GFramework.Core.Abstractions/README.md" + ;; + Core.SourceGenerators) + echo "GFramework.Core.SourceGenerators/README.md" + ;; + Game) + echo "GFramework.Game/README.md" + ;; + Game.Abstractions) + echo "GFramework.Game.Abstractions/README.md" + ;; + Game.SourceGenerators) + echo "GFramework.Game.SourceGenerators/README.md" + ;; + Godot) + echo "GFramework.Godot/README.md" + ;; + Godot.SourceGenerators) + echo "GFramework.Godot.SourceGenerators/README.md" + ;; + Cqrs) + echo "GFramework.Cqrs/README.md" + ;; + Cqrs.Abstractions) + echo "GFramework.Cqrs.Abstractions/README.md" + ;; + Cqrs.SourceGenerators) + echo "GFramework.Cqrs.SourceGenerators/README.md" + ;; + Ecs.Arch) + echo "GFramework.Ecs.Arch/README.md" + ;; + esac +} + +infer_module_from_namespace() { + local NAMESPACE="$1" + + if [[ "$NAMESPACE" == GFramework.Core.SourceGenerators.Abstractions* ]]; then + echo "Core.SourceGenerators.Abstractions" + elif [[ "$NAMESPACE" == GFramework.Core.SourceGenerators* ]]; then + echo "Core.SourceGenerators" + elif [[ "$NAMESPACE" == GFramework.Core.Abstractions* ]]; then + echo "Core.Abstractions" + elif [[ "$NAMESPACE" == GFramework.Core* ]]; then + echo "Core" + elif [[ "$NAMESPACE" == GFramework.Game.SourceGenerators* ]]; then + echo "Game.SourceGenerators" + elif [[ "$NAMESPACE" == GFramework.Game.Abstractions* ]]; then + echo "Game.Abstractions" + elif [[ "$NAMESPACE" == GFramework.Game* ]]; then + echo "Game" + elif [[ "$NAMESPACE" == GFramework.Godot.SourceGenerators.Abstractions* ]]; then + echo "Godot.SourceGenerators.Abstractions" + elif [[ "$NAMESPACE" == GFramework.Godot.SourceGenerators* ]]; then + echo "Godot.SourceGenerators" + elif [[ "$NAMESPACE" == GFramework.Godot* ]]; then + echo "Godot" + elif [[ "$NAMESPACE" == GFramework.Cqrs.SourceGenerators* ]]; then + echo "Cqrs.SourceGenerators" + elif [[ "$NAMESPACE" == GFramework.Cqrs.Abstractions* ]]; then + echo "Cqrs.Abstractions" + elif [[ "$NAMESPACE" == GFramework.Cqrs* ]]; then + echo "Cqrs" + elif [[ "$NAMESPACE" == GFramework.Ecs.Arch.Abstractions* ]]; then + echo "Ecs.Arch.Abstractions" + elif [[ "$NAMESPACE" == GFramework.Ecs.Arch* ]]; then + echo "Ecs.Arch" + elif [[ "$NAMESPACE" == GFramework.SourceGenerators.Common* ]]; then + echo "SourceGenerators.Common" + else + return 1 + fi +} diff --git a/.agents/skills/_shared/module-map.json b/.agents/skills/_shared/module-map.json new file mode 100644 index 00000000..33341c14 --- /dev/null +++ b/.agents/skills/_shared/module-map.json @@ -0,0 +1,434 @@ +{ + "version": 1, + "description": "Canonical documentation refresh module map for GFramework skills.", + "modules": { + "Core": { + "aliases": ["core", "core-runtime", "runtime-core", "core module"], + "source_paths": ["GFramework.Core"], + "project_file": "GFramework.Core/GFramework.Core.csproj", + "test_projects": ["GFramework.Core.Tests/GFramework.Core.Tests.csproj"], + "readme_paths": ["GFramework.Core/README.md"], + "docs": { + "landing": ["docs/zh-CN/core/index.md"], + "topics": [ + "docs/zh-CN/core/architecture.md", + "docs/zh-CN/core/context.md", + "docs/zh-CN/core/lifecycle.md", + "docs/zh-CN/core/events.md", + "docs/zh-CN/core/property.md", + "docs/zh-CN/core/logging.md", + "docs/zh-CN/core/state-management.md", + "docs/zh-CN/core/coroutine.md" + ], + "fallback": [ + "docs/zh-CN/getting-started/quick-start.md", + "docs/zh-CN/api-reference/index.md" + ] + }, + "ai_libs": { + "paths": [ + "ai-libs/CoreGrid/CoreGrid.csproj", + "ai-libs/CoreGrid/global", + "ai-libs/CoreGrid/docs" + ], + "search_hints": [ + "rg -n \"Architecture|RegisterModel|RegisterSystem|BindableProperty|EventBus\" ai-libs/CoreGrid" + ] + } + }, + "Core.Abstractions": { + "aliases": ["core.abstractions", "core-abstractions", "core abstractions"], + "source_paths": ["GFramework.Core.Abstractions"], + "project_file": "GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj", + "test_projects": ["GFramework.Core.Tests/GFramework.Core.Tests.csproj"], + "readme_paths": ["GFramework.Core.Abstractions/README.md"], + "docs": { + "landing": ["docs/zh-CN/abstractions/core-abstractions.md"], + "topics": [ + "docs/zh-CN/core/index.md", + "docs/zh-CN/core/architecture.md", + "docs/zh-CN/core/context.md" + ], + "fallback": ["docs/zh-CN/api-reference/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/CoreGrid.csproj"], + "search_hints": [ + "rg -n \"GFramework\\.Core\\.Abstractions|IArchitecture|IModel|ISystem\" ai-libs/CoreGrid" + ] + } + }, + "Core.SourceGenerators": { + "aliases": [ + "core.sourcegenerators", + "core-sourcegenerators", + "core-source-generators", + "core source generators" + ], + "source_paths": ["GFramework.Core.SourceGenerators"], + "project_file": "GFramework.Core.SourceGenerators/GFramework.Core.SourceGenerators.csproj", + "test_projects": ["GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj"], + "readme_paths": ["GFramework.Core.SourceGenerators/README.md"], + "docs": { + "landing": ["docs/zh-CN/source-generators/index.md"], + "topics": [ + "docs/zh-CN/source-generators/context-aware-generator.md", + "docs/zh-CN/source-generators/context-get-generator.md", + "docs/zh-CN/source-generators/priority-generator.md", + "docs/zh-CN/source-generators/logging-generator.md" + ], + "fallback": ["docs/zh-CN/api-reference/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/global", "ai-libs/CoreGrid/scripts"], + "search_hints": [ + "rg -n \"ContextAware|ContextGet|Priority|GeneratedLogger|Log\" ai-libs/CoreGrid" + ] + } + }, + "Core.SourceGenerators.Abstractions": { + "aliases": [ + "core.sourcegenerators.abstractions", + "core-source-generators-abstractions", + "core source generators abstractions" + ], + "source_paths": ["GFramework.Core.SourceGenerators.Abstractions"], + "project_file": "GFramework.Core.SourceGenerators.Abstractions/GFramework.Core.SourceGenerators.Abstractions.csproj", + "test_projects": ["GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj"], + "readme_paths": [], + "docs": { + "landing": ["docs/zh-CN/source-generators/index.md"], + "topics": [ + "docs/zh-CN/source-generators/context-aware-generator.md", + "docs/zh-CN/source-generators/context-get-generator.md", + "docs/zh-CN/source-generators/priority-generator.md" + ], + "fallback": ["docs/zh-CN/api-reference/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/global"], + "search_hints": [ + "rg -n \"GFramework\\.Core\\.SourceGenerators\\.Abstractions|\\[ContextAware\\]|\\[Priority\\]\" ai-libs/CoreGrid" + ] + } + }, + "Game": { + "aliases": ["game", "game-runtime", "runtime-game", "game module"], + "source_paths": ["GFramework.Game"], + "project_file": "GFramework.Game/GFramework.Game.csproj", + "test_projects": ["GFramework.Game.Tests/GFramework.Game.Tests.csproj"], + "readme_paths": ["GFramework.Game/README.md"], + "docs": { + "landing": ["docs/zh-CN/game/index.md"], + "topics": [ + "docs/zh-CN/game/scene.md", + "docs/zh-CN/game/ui.md", + "docs/zh-CN/game/data.md", + "docs/zh-CN/game/storage.md", + "docs/zh-CN/game/serialization.md", + "docs/zh-CN/game/setting.md", + "docs/zh-CN/game/config-system.md" + ], + "fallback": [ + "docs/zh-CN/getting-started/quick-start.md", + "docs/zh-CN/api-reference/index.md" + ] + }, + "ai_libs": { + "paths": [ + "ai-libs/CoreGrid/global", + "ai-libs/CoreGrid/scenes", + "ai-libs/CoreGrid/addons" + ], + "search_hints": [ + "rg -n \"SceneRouter|UiRouter|Setting|Storage|Serialization|Config\" ai-libs/CoreGrid" + ] + } + }, + "Game.Abstractions": { + "aliases": ["game.abstractions", "game-abstractions", "game abstractions"], + "source_paths": ["GFramework.Game.Abstractions"], + "project_file": "GFramework.Game.Abstractions/GFramework.Game.Abstractions.csproj", + "test_projects": ["GFramework.Game.Tests/GFramework.Game.Tests.csproj"], + "readme_paths": ["GFramework.Game.Abstractions/README.md"], + "docs": { + "landing": ["docs/zh-CN/abstractions/game-abstractions.md"], + "topics": [ + "docs/zh-CN/game/index.md", + "docs/zh-CN/game/scene.md", + "docs/zh-CN/game/ui.md" + ], + "fallback": ["docs/zh-CN/api-reference/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/global", "ai-libs/CoreGrid/scenes"], + "search_hints": [ + "rg -n \"ISceneFactory|ISceneRoot|UiInteractionProfile|IUiRoot\" ai-libs/CoreGrid" + ] + } + }, + "Game.SourceGenerators": { + "aliases": [ + "game.sourcegenerators", + "game-source-generators", + "game source generators" + ], + "source_paths": ["GFramework.Game.SourceGenerators"], + "project_file": "GFramework.Game.SourceGenerators/GFramework.Game.SourceGenerators.csproj", + "test_projects": ["GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj"], + "readme_paths": ["GFramework.Game.SourceGenerators/README.md"], + "docs": { + "landing": ["docs/zh-CN/source-generators/index.md"], + "topics": [ + "docs/zh-CN/source-generators/auto-scene-generator.md", + "docs/zh-CN/source-generators/auto-ui-page-generator.md" + ], + "fallback": ["docs/zh-CN/game/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/scenes", "ai-libs/CoreGrid/addons"], + "search_hints": [ + "rg -n \"AutoScene|AutoUiPage|SceneRouter|UiRouter\" ai-libs/CoreGrid" + ] + } + }, + "Godot": { + "aliases": ["godot", "godot-runtime", "runtime-godot", "godot module"], + "source_paths": ["GFramework.Godot"], + "project_file": "GFramework.Godot/GFramework.Godot.csproj", + "test_projects": ["GFramework.Godot.Tests/GFramework.Godot.Tests.csproj"], + "readme_paths": ["GFramework.Godot/README.md"], + "docs": { + "landing": ["docs/zh-CN/godot/index.md"], + "topics": [ + "docs/zh-CN/godot/architecture.md", + "docs/zh-CN/godot/scene.md", + "docs/zh-CN/godot/ui.md", + "docs/zh-CN/godot/storage.md", + "docs/zh-CN/godot/setting.md", + "docs/zh-CN/godot/signal.md" + ], + "fallback": [ + "docs/zh-CN/source-generators/index.md", + "docs/zh-CN/api-reference/index.md" + ] + }, + "ai_libs": { + "paths": [ + "ai-libs/CoreGrid/project.godot", + "ai-libs/CoreGrid/global", + "ai-libs/CoreGrid/scenes" + ], + "search_hints": [ + "rg -n \"AutoLoad|InputActions|Node|Signal|PackedScene|Godot\" ai-libs/CoreGrid" + ] + } + }, + "Godot.SourceGenerators": { + "aliases": [ + "godot.sourcegenerators", + "godot-source-generators", + "godot source generators", + "godot generators" + ], + "source_paths": ["GFramework.Godot.SourceGenerators"], + "project_file": "GFramework.Godot.SourceGenerators/GFramework.Godot.SourceGenerators.csproj", + "test_projects": ["GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj"], + "readme_paths": ["GFramework.Godot.SourceGenerators/README.md"], + "docs": { + "landing": ["docs/zh-CN/source-generators/index.md"], + "topics": [ + "docs/zh-CN/source-generators/godot-project-generator.md", + "docs/zh-CN/source-generators/get-node-generator.md", + "docs/zh-CN/source-generators/bind-node-signal-generator.md", + "docs/zh-CN/source-generators/auto-register-exported-collections-generator.md" + ], + "fallback": ["docs/zh-CN/godot/index.md"] + }, + "ai_libs": { + "paths": [ + "ai-libs/CoreGrid/project.godot", + "ai-libs/CoreGrid/global", + "ai-libs/CoreGrid/scenes" + ], + "search_hints": [ + "rg -n \"GetNode|BindNodeSignal|AutoRegisterExported|project\\.godot|AutoLoad\" ai-libs/CoreGrid" + ] + } + }, + "Godot.SourceGenerators.Abstractions": { + "aliases": [ + "godot.sourcegenerators.abstractions", + "godot-source-generators-abstractions", + "godot source generators abstractions" + ], + "source_paths": ["GFramework.Godot.SourceGenerators.Abstractions"], + "project_file": "GFramework.Godot.SourceGenerators.Abstractions/GFramework.Godot.SourceGenerators.Abstractions.csproj", + "test_projects": ["GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj"], + "readme_paths": [], + "docs": { + "landing": ["docs/zh-CN/source-generators/index.md"], + "topics": [ + "docs/zh-CN/source-generators/godot-project-generator.md", + "docs/zh-CN/source-generators/get-node-generator.md", + "docs/zh-CN/source-generators/bind-node-signal-generator.md" + ], + "fallback": ["docs/zh-CN/godot/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/project.godot", "ai-libs/CoreGrid/global"], + "search_hints": [ + "rg -n \"GFramework\\.Godot\\.SourceGenerators\\.Abstractions|GetNode|BindNodeSignal\" ai-libs/CoreGrid" + ] + } + }, + "Cqrs": { + "aliases": ["cqrs", "mediator", "cqrs module"], + "source_paths": ["GFramework.Cqrs"], + "project_file": "GFramework.Cqrs/GFramework.Cqrs.csproj", + "test_projects": ["GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj"], + "readme_paths": ["GFramework.Cqrs/README.md"], + "docs": { + "landing": ["docs/zh-CN/core/cqrs.md"], + "topics": [ + "docs/zh-CN/core/command.md", + "docs/zh-CN/core/query.md", + "docs/zh-CN/core/cqrs.md" + ], + "fallback": [ + "docs/zh-CN/core/index.md", + "docs/zh-CN/api-reference/index.md" + ] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/global", "ai-libs/CoreGrid/scripts"], + "search_hints": [ + "rg -n \"CommandHandler|QueryHandler|RegisterCqrs|PipelineBehavior\" ai-libs/CoreGrid" + ] + } + }, + "Cqrs.Abstractions": { + "aliases": ["cqrs.abstractions", "cqrs-abstractions", "cqrs abstractions"], + "source_paths": ["GFramework.Cqrs.Abstractions"], + "project_file": "GFramework.Cqrs.Abstractions/GFramework.Cqrs.Abstractions.csproj", + "test_projects": ["GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj"], + "readme_paths": ["GFramework.Cqrs.Abstractions/README.md"], + "docs": { + "landing": ["docs/zh-CN/core/cqrs.md"], + "topics": [ + "docs/zh-CN/core/command.md", + "docs/zh-CN/core/query.md" + ], + "fallback": ["docs/zh-CN/api-reference/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/global"], + "search_hints": [ + "rg -n \"GFramework\\.Cqrs\\.Abstractions|ICommand|IQuery|IRequest\" ai-libs/CoreGrid" + ] + } + }, + "Cqrs.SourceGenerators": { + "aliases": [ + "cqrs.sourcegenerators", + "cqrs-source-generators", + "cqrs source generators" + ], + "source_paths": ["GFramework.Cqrs.SourceGenerators"], + "project_file": "GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj", + "test_projects": ["GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj"], + "readme_paths": ["GFramework.Cqrs.SourceGenerators/README.md"], + "docs": { + "landing": ["docs/zh-CN/source-generators/index.md"], + "topics": [], + "fallback": [ + "docs/zh-CN/core/cqrs.md", + "docs/zh-CN/api-reference/index.md" + ] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/global"], + "search_hints": [ + "rg -n \"GFramework\\.Cqrs\\.SourceGenerators|RequestHandler|PipelineBehavior\" ai-libs/CoreGrid" + ] + } + }, + "Ecs.Arch": { + "aliases": ["ecs.arch", "ecs-arch", "ecs arch", "ecs"], + "source_paths": ["GFramework.Ecs.Arch"], + "project_file": "GFramework.Ecs.Arch/GFramework.Ecs.Arch.csproj", + "test_projects": ["GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj"], + "readme_paths": ["GFramework.Ecs.Arch/README.md"], + "docs": { + "landing": ["docs/zh-CN/ecs/index.md"], + "topics": ["docs/zh-CN/ecs/arch.md"], + "fallback": [ + "docs/zh-CN/core/index.md", + "docs/zh-CN/api-reference/index.md" + ] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/scripts", "ai-libs/CoreGrid/global"], + "search_hints": [ + "rg -n \"Arch\\.Core|World|SystemGroup|QueryDescription\" ai-libs/CoreGrid" + ] + } + }, + "Ecs.Arch.Abstractions": { + "aliases": [ + "ecs.arch.abstractions", + "ecs-arch-abstractions", + "ecs arch abstractions" + ], + "source_paths": ["GFramework.Ecs.Arch.Abstractions"], + "project_file": "GFramework.Ecs.Arch.Abstractions/GFramework.Ecs.Arch.Abstractions.csproj", + "test_projects": ["GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj"], + "readme_paths": [], + "docs": { + "landing": ["docs/zh-CN/ecs/index.md"], + "topics": ["docs/zh-CN/ecs/arch.md"], + "fallback": ["docs/zh-CN/api-reference/index.md"] + }, + "ai_libs": { + "paths": ["ai-libs/CoreGrid/scripts"], + "search_hints": [ + "rg -n \"GFramework\\.Ecs\\.Arch\\.Abstractions|IArchSystem|IArchModel\" ai-libs/CoreGrid" + ] + } + }, + "SourceGenerators.Common": { + "aliases": [ + "sourcegenerators.common", + "source-generators-common", + "source generators common" + ], + "source_paths": ["GFramework.SourceGenerators.Common"], + "project_file": "GFramework.SourceGenerators.Common/GFramework.SourceGenerators.Common.csproj", + "test_projects": ["GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj"], + "readme_paths": [], + "docs": { + "landing": ["docs/zh-CN/source-generators/index.md"], + "topics": [], + "fallback": ["docs/zh-CN/api-reference/index.md"] + }, + "ai_libs": { + "paths": [], + "search_hints": [] + } + } + }, + "docs_section_aliases": { + "core": ["Core"], + "abstractions": ["Core.Abstractions", "Game.Abstractions", "Ecs.Arch.Abstractions"], + "game": ["Game"], + "godot": ["Godot"], + "cqrs": ["Cqrs"], + "ecs": ["Ecs.Arch"], + "source-generators": [ + "Core.SourceGenerators", + "Game.SourceGenerators", + "Cqrs.SourceGenerators", + "Godot.SourceGenerators" + ] + } +} diff --git a/.claude/skills/_shared/scripts/generate-examples.sh b/.agents/skills/_shared/scripts/generate-examples.sh similarity index 100% rename from .claude/skills/_shared/scripts/generate-examples.sh rename to .agents/skills/_shared/scripts/generate-examples.sh diff --git a/.claude/skills/_shared/scripts/parse-csharp-xml.sh b/.agents/skills/_shared/scripts/parse-csharp-xml.sh similarity index 100% rename from .claude/skills/_shared/scripts/parse-csharp-xml.sh rename to .agents/skills/_shared/scripts/parse-csharp-xml.sh diff --git a/.claude/skills/_shared/scripts/update-vitepress-nav.sh b/.agents/skills/_shared/scripts/update-vitepress-nav.sh similarity index 100% rename from .claude/skills/_shared/scripts/update-vitepress-nav.sh rename to .agents/skills/_shared/scripts/update-vitepress-nav.sh diff --git a/.codex/skills/gframework-boot/SKILL.md b/.agents/skills/gframework-boot/SKILL.md similarity index 100% rename from .codex/skills/gframework-boot/SKILL.md rename to .agents/skills/gframework-boot/SKILL.md diff --git a/.codex/skills/gframework-boot/agents/openai.yaml b/.agents/skills/gframework-boot/agents/openai.yaml similarity index 100% rename from .codex/skills/gframework-boot/agents/openai.yaml rename to .agents/skills/gframework-boot/agents/openai.yaml diff --git a/.codex/skills/gframework-boot/references/startup-artifacts.md b/.agents/skills/gframework-boot/references/startup-artifacts.md similarity index 100% rename from .codex/skills/gframework-boot/references/startup-artifacts.md rename to .agents/skills/gframework-boot/references/startup-artifacts.md diff --git a/.agents/skills/gframework-doc-refresh/SKILL.md b/.agents/skills/gframework-doc-refresh/SKILL.md new file mode 100644 index 00000000..5fc44195 --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/SKILL.md @@ -0,0 +1,205 @@ +--- +name: gframework-doc-refresh +description: Refresh or reassess GFramework documentation for a source module such as Core, Game, Godot, Cqrs, Ecs.Arch, or their generator/abstraction packages. Use this when the user asks to update module docs, re-evaluate landing pages, fix outdated topic pages, refresh API reference coverage, verify adoption paths against source/tests/README, or compare current docs with ai-libs consumer wiring. Recommended command: /gframework-doc-refresh . +--- + +# Purpose + +Use this skill to refresh GFramework documentation from source-first evidence. + +The public entry is module-driven, not doc-type-driven: + +- Input: a source module or a resolvable docs section alias +- Output: the minimal documentation update set needed for that module +- Evidence: code, tests, README, current docs, then `ai-libs/` + +Do not start by deciding “this is an API doc task” or “this is a tutorial task”. +Decide that only after the module scan. + +# Triggers + +Use this skill when the user asks things like: + +- `refresh docs for Core` +- `update Game module docs` +- `根据 Godot 模块源码刷新文档` +- `重新评估 Cqrs 模块文档并更新` +- `核对 Godot.SourceGenerators 的文档状态` +- `看看 source-generators 栏目哪些页面已经失真` + +Recommended command form: + +```bash +/gframework-doc-refresh +``` + +# Supported Modules + +Canonical module names: + +- `Core` +- `Core.Abstractions` +- `Core.SourceGenerators` +- `Core.SourceGenerators.Abstractions` +- `Game` +- `Game.Abstractions` +- `Game.SourceGenerators` +- `Godot` +- `Godot.SourceGenerators` +- `Godot.SourceGenerators.Abstractions` +- `Cqrs` +- `Cqrs.Abstractions` +- `Cqrs.SourceGenerators` +- `Ecs.Arch` +- `Ecs.Arch.Abstractions` +- `SourceGenerators.Common` + +The canonical mapping lives in `.agents/skills/_shared/module-map.json`. + +If the user supplies a docs section name: + +- resolve it back to a source module first +- if it maps to multiple modules, stop at normalization guidance and do not draft docs yet + +# Workflow + +## 1. Normalize the input + +Run: + +```bash +python3 .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py +``` + +The script normalizes aliases, reports ambiguity, and prints the module's evidence surface. + +If the result is ambiguous: + +- return the candidate modules +- ask the user to pick the intended source module +- do not continue into document generation + +## 2. Scan the evidence surface + +For the resolved module, inspect: + +- source directories +- `*.csproj` +- relevant test projects +- sibling `README.md` +- mapped `docs/zh-CN` landing pages and topic pages +- optional `ai-libs/` consumer evidence when needed + +Always confirm the actual files in the repository. +Do not assume the mapping is enough on its own. + +## 3. Decide whether `ai-libs/` is needed + +Use `ai-libs/` when: + +- adoption path is unclear from source and README alone +- extension points need a real consumer wiring example +- current docs have concepts but lack an end-to-end integration path + +Do not rely on `ai-libs/` for: + +- public API contract definitions +- generator diagnostics or semantic guarantees +- claims about what the current version officially supports + +If `ai-libs/` conflicts with current source or tests, keep source/tests as the contract and document the migration boundary. + +## 4. Judge the documentation state + +Classify the module into one or more of these states: + +- missing landing page +- stale landing page +- stale topic page +- missing or stale API reference coverage +- stale tutorial/example +- validation-only + +Base this on evidence, not on the previous docs shape. + +## 5. Choose the output set + +Always prioritize: + +1. README / landing page / adoption path +2. topic pages +3. API reference +4. tutorials + +If the module only needs validation or relinking, do not generate extra pages. + +## 6. Draft or update docs + +Load only the template that matches the output you selected: + +- `templates/module-landing.md` +- `templates/topic-refresh.md` +- `templates/api-reference.md` +- `templates/tutorial.md` + +Keep examples minimal, current, and traceable to source or tests. + +## 7. Validate + +Run the internal validators as needed: + +```bash +bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh +``` + +For site-level confirmation after doc edits: + +```bash +cd docs && bun run build +``` + +# Evidence Order + +Use this exact priority: + +1. source code, XML docs, `*.csproj` +2. tests and snapshots +3. module `README.md` +4. current `docs/zh-CN` pages +5. verified `ai-libs/` consumers +6. archived docs only as fallback context + +# Output Rules + +- Prefer correcting the adoption path over expanding page count. +- Do not copy wording from outdated docs just to keep page volume. +- Escape generics outside code blocks. +- Keep internal links real and current. +- Mark code blocks with explicit languages. +- Use the smallest example that demonstrates the current contract. +- Consumer examples may align with `ai-libs/`, but must not exceed the current module contract. + +# Validation + +Use the shared standards in `.agents/skills/_shared/DOCUMENTATION_STANDARDS.md`. + +When this skill changes public docs, prefer: + +1. focused validator on touched pages +2. `cd docs && bun run build` + +When this skill changes the skill system itself: + +1. validate `SKILL.md` frontmatter exists +2. run the module scan script for representative modules +3. confirm obsolete `vitepress-*` public entries are gone + +# References + +Read these only when needed: + +- `.agents/skills/_shared/DOCUMENTATION_STANDARDS.md` +- `.agents/skills/_shared/module-map.json` +- `references/module-selection.md` +- `references/evidence-and-ai-libs.md` +- `references/output-strategy.md` diff --git a/.agents/skills/gframework-doc-refresh/agents/openai.yaml b/.agents/skills/gframework-doc-refresh/agents/openai.yaml new file mode 100644 index 00000000..73303bce --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "GFramework Doc Refresh" + short_description: "Refresh module docs from code-first evidence" + default_prompt: "Use $gframework-doc-refresh to refresh a GFramework module's docs from source, tests, README, current docs, and ai-libs evidence." diff --git a/.agents/skills/gframework-doc-refresh/references/evidence-and-ai-libs.md b/.agents/skills/gframework-doc-refresh/references/evidence-and-ai-libs.md new file mode 100644 index 00000000..8bd1fffb --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/references/evidence-and-ai-libs.md @@ -0,0 +1,35 @@ +# Evidence And `ai-libs` + +The evidence order is fixed: + +1. source code, XML docs, `*.csproj` +2. tests and snapshots +3. module README +4. current `docs/zh-CN` +5. `ai-libs/` +6. archived docs + +## When To Use `ai-libs` + +Use `ai-libs/` to answer questions like: + +- How is this extension point wired in a real project? +- What does the minimal project layout look like? +- Which project-side files need to exist for this module to work end to end? + +## When Not To Use `ai-libs` + +Do not use `ai-libs/` as the primary source for: + +- public API semantics +- exact generator output guarantees +- supported package matrix +- diagnostics behavior + +## Conflict Rule + +If `ai-libs/` drifts from the current repo: + +- trust source and tests +- mention the drift as a compatibility or migration note +- do not document old consumer behavior as if it were still the contract diff --git a/.agents/skills/gframework-doc-refresh/references/module-selection.md b/.agents/skills/gframework-doc-refresh/references/module-selection.md new file mode 100644 index 00000000..b3eadcac --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/references/module-selection.md @@ -0,0 +1,29 @@ +# Module Selection + +Use `.agents/skills/_shared/module-map.json` as the canonical source for: + +- supported modules +- aliases +- source paths +- test projects +- README paths +- docs landing/topic/fallback pages +- `ai-libs/` reference roots + +Selection rules: + +1. Prefer explicit canonical module names. +2. Resolve docs section aliases back to source modules before scanning docs. +3. If an alias maps to multiple modules, stop and return the candidate list. +4. If a module has no dedicated docs section, fall back to the nearest existing landing page or API index instead of inventing a fake section. + +Representative ambiguous inputs: + +- `source-generators` -> likely one of `Core.SourceGenerators`, `Game.SourceGenerators`, `Cqrs.SourceGenerators`, `Godot.SourceGenerators` +- `abstractions` -> likely one of `Core.Abstractions`, `Game.Abstractions`, `Ecs.Arch.Abstractions` + +Representative resolvable aliases: + +- `core-abstractions` -> `Core.Abstractions` +- `godot generators` -> `Godot.SourceGenerators` +- `ecs` -> `Ecs.Arch` diff --git a/.agents/skills/gframework-doc-refresh/references/output-strategy.md b/.agents/skills/gframework-doc-refresh/references/output-strategy.md new file mode 100644 index 00000000..c199f425 --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/references/output-strategy.md @@ -0,0 +1,38 @@ +# Output Strategy + +The module scan determines the document type. + +Use this priority: + +1. fix README / landing page / adoption path +2. fix stale topic pages +3. add or refresh API reference coverage +4. add or refresh tutorials + +## Landing Page Checklist + +- module purpose +- package relationship +- minimum adoption path +- real entry points +- next-reading links + +## Topic Page Checklist + +- current role +- public entry points +- minimum example +- compatibility or migration boundary +- related pages + +## API Reference Checklist + +- only for types or members that materially help consumers +- grounded in XML docs and source +- no speculative examples + +## Tutorial Checklist + +- only after the landing path is accurate +- keep the scenario traceable to source/tests or `ai-libs/` +- explain why each step exists, not just the code shape diff --git a/.agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py b/.agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py new file mode 100644 index 00000000..c46a5859 --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +"""Normalize a GFramework docs module input and report its evidence surface.""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path +from typing import Any + + +SCRIPT_DIR = Path(__file__).resolve().parent +REPO_ROOT = SCRIPT_DIR.parents[3] +MODULE_MAP_PATH = REPO_ROOT / ".agents/skills/_shared/module-map.json" + + +def load_module_map() -> dict[str, Any]: + return json.loads(MODULE_MAP_PATH.read_text(encoding="utf-8")) + + +def normalize_key(value: str) -> str: + return value.strip().lower().replace("_", "-").replace(" ", "-") + + +def resolve_module(raw_input: str, module_map: dict[str, Any]) -> dict[str, Any]: + modules = module_map["modules"] + docs_section_aliases = module_map.get("docs_section_aliases", {}) + normalized = normalize_key(raw_input) + + for canonical_name in modules: + if normalize_key(canonical_name) == normalized: + return {"status": "ok", "module": canonical_name, "reason": "canonical"} + + for canonical_name, config in modules.items(): + aliases = config.get("aliases", []) + if normalized in {normalize_key(alias) for alias in aliases}: + return {"status": "ok", "module": canonical_name, "reason": "alias"} + + if normalized in docs_section_aliases: + candidates = docs_section_aliases[normalized] + if len(candidates) == 1: + return {"status": "ok", "module": candidates[0], "reason": "docs_section"} + return { + "status": "ambiguous", + "reason": "docs_section", + "input": raw_input, + "candidates": candidates, + } + + fuzzy = [ + canonical_name + for canonical_name in modules + if normalized in normalize_key(canonical_name) or normalize_key(canonical_name) in normalized + ] + if fuzzy: + return {"status": "unknown", "reason": "closest_match", "input": raw_input, "candidates": fuzzy} + + return {"status": "unknown", "reason": "no_match", "input": raw_input, "candidates": []} + + +def collect_path_state(paths: list[str]) -> list[dict[str, Any]]: + states: list[dict[str, Any]] = [] + for relative_path in paths: + absolute_path = REPO_ROOT / relative_path + states.append( + { + "path": relative_path, + "exists": absolute_path.exists(), + "kind": "dir" if absolute_path.is_dir() else "file", + } + ) + return states + + +def assess_docs(module_config: dict[str, Any]) -> list[str]: + docs_config = module_config["docs"] + landing = collect_path_state(docs_config.get("landing", [])) + topics = collect_path_state(docs_config.get("topics", [])) + assessment: list[str] = [] + + if landing and not any(item["exists"] for item in landing): + assessment.append("landing_missing") + elif landing: + assessment.append("landing_present") + + if not topics: + assessment.append("topic_docs_not_mapped") + else: + existing_topics = sum(1 for item in topics if item["exists"]) + if existing_topics == 0: + assessment.append("topic_docs_missing") + elif existing_topics < len(topics): + assessment.append("topic_docs_partial") + else: + assessment.append("topic_docs_present") + + return assessment + + +def build_report(module_name: str, module_config: dict[str, Any]) -> dict[str, Any]: + source_paths = collect_path_state(module_config.get("source_paths", [])) + test_projects = collect_path_state(module_config.get("test_projects", [])) + readmes = collect_path_state(module_config.get("readme_paths", [])) + docs_config = module_config["docs"] + ai_libs = module_config.get("ai_libs", {}) + + report = { + "status": "ok", + "module": module_name, + "source_paths": source_paths, + "project_file": collect_path_state([module_config["project_file"]])[0], + "test_projects": test_projects, + "readme_paths": readmes, + "docs": { + "landing": collect_path_state(docs_config.get("landing", [])), + "topics": collect_path_state(docs_config.get("topics", [])), + "fallback": collect_path_state(docs_config.get("fallback", [])) + }, + "ai_libs": { + "paths": collect_path_state(ai_libs.get("paths", [])), + "search_hints": ai_libs.get("search_hints", []), + }, + "assessment": assess_docs(module_config), + } + + if readmes and not any(item["exists"] for item in readmes): + report["assessment"].append("readme_missing") + + if test_projects and not any(item["exists"] for item in test_projects): + report["assessment"].append("tests_missing") + + if not ai_libs.get("paths"): + report["assessment"].append("ai_libs_optional") + + if not docs_config.get("topics"): + report["assessment"].append("fallback_docs_only") + + return report + + +def print_text_report(report: dict[str, Any]) -> None: + if report["status"] != "ok": + print(json.dumps(report, ensure_ascii=False, indent=2)) + return + + print(f"module: {report['module']}") + print("assessment:") + for item in report["assessment"]: + print(f" - {item}") + + print("source:") + for item in report["source_paths"]: + print(f" - {'OK' if item['exists'] else 'MISS'} {item['path']}") + + project_file = report["project_file"] + print(f"project: {'OK' if project_file['exists'] else 'MISS'} {project_file['path']}") + + print("tests:") + for item in report["test_projects"]: + print(f" - {'OK' if item['exists'] else 'MISS'} {item['path']}") + + print("readme:") + if report["readme_paths"]: + for item in report["readme_paths"]: + print(f" - {'OK' if item['exists'] else 'MISS'} {item['path']}") + else: + print(" - none mapped") + + print("docs landing:") + for item in report["docs"]["landing"]: + print(f" - {'OK' if item['exists'] else 'MISS'} {item['path']}") + + print("docs topics:") + if report["docs"]["topics"]: + for item in report["docs"]["topics"]: + print(f" - {'OK' if item['exists'] else 'MISS'} {item['path']}") + else: + print(" - none mapped") + + print("docs fallback:") + for item in report["docs"]["fallback"]: + print(f" - {'OK' if item['exists'] else 'MISS'} {item['path']}") + + print("ai-libs:") + if report["ai_libs"]["paths"]: + for item in report["ai_libs"]["paths"]: + print(f" - {'OK' if item['exists'] else 'MISS'} {item['path']}") + else: + print(" - none mapped") + + if report["ai_libs"]["search_hints"]: + print("ai-libs search hints:") + for item in report["ai_libs"]["search_hints"]: + print(f" - {item}") + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("module", help="Canonical module name, alias, or docs section name.") + parser.add_argument("--json", action="store_true", help="Emit JSON instead of text.") + args = parser.parse_args() + + module_map = load_module_map() + resolution = resolve_module(args.module, module_map) + + if resolution["status"] != "ok": + if args.json: + print(json.dumps(resolution, ensure_ascii=False, indent=2)) + else: + print(json.dumps(resolution, ensure_ascii=False, indent=2)) + return 1 + + report = build_report(resolution["module"], module_map["modules"][resolution["module"]]) + report["resolution"] = resolution + + if args.json: + print(json.dumps(report, ensure_ascii=False, indent=2)) + else: + print_text_report(report) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.agents/skills/gframework-doc-refresh/scripts/validate-all.sh b/.agents/skills/gframework-doc-refresh/scripts/validate-all.sh new file mode 100644 index 00000000..b236cdfd --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/scripts/validate-all.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# 运行统一文档校验脚本集合。 + +set -e + +TARGET="$1" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ -z "$TARGET" ]; then + echo "用法: $0 <文件或目录路径>" + exit 1 +fi + +if [ ! -e "$TARGET" ]; then + echo "错误: 路径不存在: $TARGET" + exit 1 +fi + +if [ -f "$TARGET" ]; then + FILES=("$TARGET") +else + mapfile -t FILES < <(find "$TARGET" -type f -name "*.md" | sort) +fi + +if [ ${#FILES[@]} -eq 0 ]; then + echo "未找到 Markdown 文件" + exit 0 +fi + +TOTAL_ERRORS=0 +FAILED_FILES=0 + +for FILE in "${FILES[@]}"; do + FILE_ERRORS=0 + + echo "验证: $FILE" + + if ! bash "$SCRIPT_DIR/validate-frontmatter.sh" "$FILE"; then + FILE_ERRORS=$((FILE_ERRORS + 1)) + fi + + if ! bash "$SCRIPT_DIR/validate-links.sh" "$FILE"; then + FILE_ERRORS=$((FILE_ERRORS + 1)) + fi + + if ! bash "$SCRIPT_DIR/validate-code-blocks.sh" "$FILE"; then + FILE_ERRORS=$((FILE_ERRORS + 1)) + fi + + if [ $FILE_ERRORS -eq 0 ]; then + echo "✓ $FILE" + else + echo "✗ $FILE" + FAILED_FILES=$((FAILED_FILES + 1)) + fi + + TOTAL_ERRORS=$((TOTAL_ERRORS + FILE_ERRORS)) + echo "" +done + +if [ $TOTAL_ERRORS -eq 0 ]; then + echo "✓ 所有验证通过" + exit 0 +fi + +echo "✗ 验证失败:$FAILED_FILES 个文件存在问题" +exit 1 diff --git a/.agents/skills/gframework-doc-refresh/scripts/validate-code-blocks.sh b/.agents/skills/gframework-doc-refresh/scripts/validate-code-blocks.sh new file mode 100644 index 00000000..338fb36d --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/scripts/validate-code-blocks.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# 验证 Markdown 代码块是否闭合并带有语言标记。 + +set -e + +FILE="$1" + +if [ -z "$FILE" ]; then + echo "用法: $0 <文件路径>" + exit 1 +fi + +if [ ! -f "$FILE" ]; then + echo "错误: 文件不存在: $FILE" + exit 1 +fi + +ERROR_COUNT=0 +WARNING_COUNT=0 +CODE_FENCE_COUNT=$(grep -c '^```' "$FILE" || true) + +if [ $((CODE_FENCE_COUNT % 2)) -ne 0 ]; then + echo "✗ 错误: 存在未闭合的代码块" + ERROR_COUNT=$((ERROR_COUNT + 1)) +fi + +LINE_NUMBER=0 +while IFS= read -r LINE; do + LINE_NUMBER=$((LINE_NUMBER + 1)) + + if echo "$LINE" | grep -qE '^```(cs|c#|C#)$'; then + echo "⚠ 警告: 第 $LINE_NUMBER 行使用了非标准 C# 标记,建议改为 csharp" + WARNING_COUNT=$((WARNING_COUNT + 1)) + fi + + if echo "$LINE" | grep -qE '^```$'; then + NEXT_LINE=$(sed -n "$((LINE_NUMBER + 1))p" "$FILE") + if [ -n "$NEXT_LINE" ] && ! echo "$NEXT_LINE" | grep -qE '^```'; then + echo "⚠ 警告: 第 $LINE_NUMBER 行的代码块缺少语言标记" + WARNING_COUNT=$((WARNING_COUNT + 1)) + fi + fi +done < "$FILE" + +if [ $ERROR_COUNT -eq 0 ] && [ $WARNING_COUNT -eq 0 ]; then + echo "✓ 代码块验证通过" + exit 0 +fi + +if [ $ERROR_COUNT -eq 0 ]; then + echo "⚠ 代码块验证通过,但有 $WARNING_COUNT 个警告" + exit 0 +fi + +echo "✗ 代码块验证失败($ERROR_COUNT 个错误,$WARNING_COUNT 个警告)" +exit 1 diff --git a/.agents/skills/gframework-doc-refresh/scripts/validate-frontmatter.sh b/.agents/skills/gframework-doc-refresh/scripts/validate-frontmatter.sh new file mode 100644 index 00000000..e775a6cd --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/scripts/validate-frontmatter.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# 验证 Markdown frontmatter。 + +set -e + +FILE="$1" + +if [ -z "$FILE" ]; then + echo "用法: $0 <文件路径>" + exit 1 +fi + +if [ ! -f "$FILE" ]; then + echo "错误: 文件不存在: $FILE" + exit 1 +fi + +if ! head -n 5 "$FILE" | grep -q "^---$"; then + echo "✗ 错误: 文件缺少 frontmatter" + exit 1 +fi + +FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$FILE" | sed '1d;$d') + +if [ -z "$FRONTMATTER" ]; then + echo "✗ 错误: frontmatter 为空" + exit 1 +fi + +if ! echo "$FRONTMATTER" | grep -q "^title:"; then + echo "✗ 错误: 缺少必需字段: title" + exit 1 +fi + +if ! echo "$FRONTMATTER" | grep -q "^description:"; then + echo "✗ 错误: 缺少必需字段: description" + exit 1 +fi + +echo "✓ Frontmatter 验证通过" diff --git a/.claude/skills/vitepress-validate/scripts/validate-links.sh b/.agents/skills/gframework-doc-refresh/scripts/validate-links.sh similarity index 55% rename from .claude/skills/vitepress-validate/scripts/validate-links.sh rename to .agents/skills/gframework-doc-refresh/scripts/validate-links.sh index 7f42ab73..6b13bae0 100644 --- a/.claude/skills/vitepress-validate/scripts/validate-links.sh +++ b/.agents/skills/gframework-doc-refresh/scripts/validate-links.sh @@ -1,11 +1,9 @@ #!/bin/bash -# 验证内部链接有效性 -# 用法: validate-links.sh <文件路径> +# 验证 Markdown 内部链接是否指向当前仓库中的真实页面。 set -e FILE="$1" -BASE_DIR="docs/zh-CN" if [ -z "$FILE" ]; then echo "用法: $0 <文件路径>" @@ -17,58 +15,40 @@ if [ ! -f "$FILE" ]; then exit 1 fi -echo "验证内部链接: $FILE" - -# 获取文件所在目录 FILE_DIR=$(dirname "$FILE") - -# 提取所有 Markdown 链接 LINKS=$(grep -oP '\[([^\]]+)\]\(([^)]+)\)' "$FILE" | grep -oP '\(([^)]+)\)' | sed 's/[()]//g' || true) if [ -z "$LINKS" ]; then - echo "✓ 未找到链接" + echo "✓ 未找到需要验证的链接" exit 0 fi ERROR_COUNT=0 while IFS= read -r LINK; do - # 跳过外部链接 - if [[ "$LINK" =~ ^https?:// ]]; then + if [[ "$LINK" =~ ^https?:// ]] || [[ "$LINK" =~ ^mailto: ]] || [[ "$LINK" =~ ^# ]]; then continue fi - # 跳过锚点链接(仅 #开头) - if [[ "$LINK" =~ ^# ]]; then - continue - fi - - # 移除锚点部分 LINK_PATH=$(echo "$LINK" | sed 's/#.*//') - # 跳过空路径 if [ -z "$LINK_PATH" ]; then continue fi - # 处理相对路径 - if [[ "$LINK_PATH" =~ ^\. ]]; then - TARGET="$FILE_DIR/$LINK_PATH" - # 处理绝对路径 - elif [[ "$LINK_PATH" =~ ^/ ]]; then + if [[ "$LINK_PATH" =~ ^/ ]]; then TARGET="docs$LINK_PATH" - # 如果没有扩展名,尝试添加 .md - if [[ ! "$TARGET" =~ \. ]]; then + if [[ ! "$TARGET" =~ \.[A-Za-z0-9]+$ ]]; then TARGET="$TARGET.md" fi + elif [[ "$LINK_PATH" =~ ^\. ]]; then + TARGET="$FILE_DIR/$LINK_PATH" else TARGET="$FILE_DIR/$LINK_PATH" fi - # 规范化路径 TARGET=$(realpath -m "$TARGET" 2>/dev/null || echo "$TARGET") - # 检查文件是否存在 if [ ! -f "$TARGET" ] && [ ! -d "$TARGET" ]; then echo "✗ 损坏的链接: $LINK" echo " 目标不存在: $TARGET" @@ -77,9 +57,9 @@ while IFS= read -r LINK; do done <<< "$LINKS" if [ $ERROR_COUNT -eq 0 ]; then - echo "✓ 内部链接验证通过" + echo "✓ 链接验证通过" exit 0 -else - echo "✗ 发现 $ERROR_COUNT 个损坏的链接" - exit 1 fi + +echo "✗ 共发现 $ERROR_COUNT 个损坏链接" +exit 1 diff --git a/.agents/skills/gframework-doc-refresh/templates/api-reference.md b/.agents/skills/gframework-doc-refresh/templates/api-reference.md new file mode 100644 index 00000000..c0b8bd95 --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/templates/api-reference.md @@ -0,0 +1,27 @@ +--- +title: {{API_TITLE}} +description: {{API_DESCRIPTION}} +outline: deep +--- + +# {{API_TITLE}} + +## 概述 + +{{API_OVERVIEW}} + +## 适用范围 + +{{API_SCOPE}} + +## 关键成员 + +{{KEY_MEMBERS}} + +## 最小示例 + +{{MINIMUM_EXAMPLE}} + +## 相关类型 + +{{RELATED_TYPES}} diff --git a/.agents/skills/gframework-doc-refresh/templates/module-landing.md b/.agents/skills/gframework-doc-refresh/templates/module-landing.md new file mode 100644 index 00000000..5b28aefe --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/templates/module-landing.md @@ -0,0 +1,30 @@ +--- +title: {{MODULE_TITLE}} +description: {{MODULE_DESCRIPTION}} +--- + +# {{MODULE_TITLE}} + +## 模块定位 + +{{MODULE_POSITIONING}} + +## 包关系 + +{{PACKAGE_RELATIONSHIP}} + +## 最小接入路径 + +{{MINIMUM_ADOPTION_PATH}} + +## 关键入口 + +{{KEY_ENTRY_POINTS}} + +## 当前边界 + +{{CURRENT_BOUNDARIES}} + +## 继续阅读 + +{{NEXT_READING}} diff --git a/.agents/skills/gframework-doc-refresh/templates/topic-refresh.md b/.agents/skills/gframework-doc-refresh/templates/topic-refresh.md new file mode 100644 index 00000000..192512c4 --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/templates/topic-refresh.md @@ -0,0 +1,26 @@ +--- +title: {{TOPIC_TITLE}} +description: {{TOPIC_DESCRIPTION}} +--- + +# {{TOPIC_TITLE}} + +## 当前角色 + +{{CURRENT_ROLE}} + +## 公开入口 + +{{PUBLIC_ENTRY_POINTS}} + +## 最小示例 + +{{MINIMUM_EXAMPLE}} + +## 兼容与迁移边界 + +{{COMPATIBILITY_BOUNDARY}} + +## 相关页面 + +{{RELATED_PAGES}} diff --git a/.agents/skills/gframework-doc-refresh/templates/tutorial.md b/.agents/skills/gframework-doc-refresh/templates/tutorial.md new file mode 100644 index 00000000..64b877d6 --- /dev/null +++ b/.agents/skills/gframework-doc-refresh/templates/tutorial.md @@ -0,0 +1,30 @@ +--- +title: {{TUTORIAL_TITLE}} +description: {{TUTORIAL_DESCRIPTION}} +--- + +# {{TUTORIAL_TITLE}} + +## 学习目标 + +{{LEARNING_OBJECTIVES}} + +## 前置条件 + +{{PREREQUISITES}} + +## 步骤 + +{{STEP_SEQUENCE}} + +## 完整代码 + +{{FULL_CODE}} + +## 验证结果 + +{{EXPECTED_RESULT}} + +## 继续阅读 + +{{NEXT_READING}} diff --git a/.codex/skills/gframework-pr-review/SKILL.md b/.agents/skills/gframework-pr-review/SKILL.md similarity index 100% rename from .codex/skills/gframework-pr-review/SKILL.md rename to .agents/skills/gframework-pr-review/SKILL.md diff --git a/.codex/skills/gframework-pr-review/agents/openai.yaml b/.agents/skills/gframework-pr-review/agents/openai.yaml similarity index 100% rename from .codex/skills/gframework-pr-review/agents/openai.yaml rename to .agents/skills/gframework-pr-review/agents/openai.yaml diff --git a/.codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py b/.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py similarity index 100% rename from .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py rename to .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py diff --git a/.claude/skills/README.md b/.claude/skills/README.md deleted file mode 100644 index c76819be..00000000 --- a/.claude/skills/README.md +++ /dev/null @@ -1,469 +0,0 @@ -# VitePress 文档生成 Skills 系统 - -为 GFramework 项目提供自动化的 VitePress 文档生成能力。 - -## 概述 - -这是一套专门为 GFramework 项目设计的文档生成 skills,能够根据 C# 源代码自动生成高质量的 VitePress 文档。系统采用模块化设计,每个 skill 专注于特定的文档生成任务。 - -## 可用 Skills - -### 1. vitepress-api-doc - API 文档生成 - -为单个 C# 文件生成 API 参考文档。 - -**用途**: -- 类、接口、枚举的 API 文档 -- 方法、属性、事件的详细说明 -- 基于 XML 注释生成文档 - -**调用方式**: -```bash -/vitepress-api-doc -``` - -**示例**: -```bash -/vitepress-api-doc GFramework.Core/architecture/Architecture.cs -``` - -**输出位置**:`docs/zh-CN/api-reference/<模块>/<文件名>.md` - -[详细文档](./vitepress-api-doc/SKILL.md) - ---- - -### 2. vitepress-guide - 功能指南生成 - -生成功能模块的使用指南文档。 - -**用途**: -- 核心功能模块的使用说明 -- 设计模式和架构概念 -- 最佳实践和常见问题 - -**调用方式**: -```bash -/vitepress-guide <主题> <目标模块> -``` - -**示例**: -```bash -/vitepress-guide "事件系统" Core -/vitepress-guide "IoC 容器" Core -``` - -**输出位置**:`docs/zh-CN/<模块>/<主题>.md` - -[详细文档](./vitepress-guide/SKILL.md) - ---- - -### 3. vitepress-tutorial - 分步教程生成 - -生成分步教程文档,适合初学者学习。 - -**用途**: -- 框架入门教程 -- 功能实现教程 -- 问题解决方案 - -**调用方式**: -```bash -/vitepress-tutorial <教程主题> -``` - -**示例**: -```bash -/vitepress-tutorial "创建第一个 System" -/vitepress-tutorial "使用事件系统" -``` - -**输出位置**:`docs/zh-CN/tutorials/<主题>.md` - -[详细文档](./vitepress-tutorial/SKILL.md) - ---- - -### 4. vitepress-batch-api - 批量 API 文档生成 - -为整个模块批量生成 API 文档。 - -**用途**: -- 初始化模块文档 -- 更新整个模块的文档 -- 快速生成大量文档 - -**调用方式**: -```bash -/vitepress-batch-api <模块名> -``` - -**示例**: -```bash -/vitepress-batch-api Core -/vitepress-batch-api Godot -``` - -**输出位置**:`docs/zh-CN/api-reference/<模块>/` - -[详细文档](./vitepress-batch-api/SKILL.md) - ---- - -### 5. vitepress-validate - 文档验证 - -验证文档的质量和规范性。 - -**用途**: -- Frontmatter 格式验证 -- 内部链接有效性检查 -- 代码块语法验证 -- 标点符号规范检查 - -**调用方式**: -```bash -/vitepress-validate <文件或目录路径> -``` - -**示例**: -```bash -/vitepress-validate docs/zh-CN/api-reference/core/architecture.md -/vitepress-validate docs/zh-CN/ -``` - -[详细文档](./vitepress-validate/SKILL.md) - ---- - -## 快速开始 - -### 1. 生成单个 API 文档 - -```bash -# 为 Architecture 类生成文档 -/vitepress-api-doc GFramework.Core/architecture/Architecture.cs -``` - -### 2. 批量生成模块文档 - -```bash -# 为整个 Core 模块生成文档 -/vitepress-batch-api Core -``` - -### 3. 生成功能指南 - -```bash -# 生成事件系统使用指南 -/vitepress-guide "事件系统" Core -``` - -### 4. 生成教程 - -```bash -# 生成创建 Model 的教程 -/vitepress-tutorial "创建第一个 Model" -``` - -### 5. 验证文档 - -```bash -# 验证生成的文档 -/vitepress-validate docs/zh-CN/api-reference/core/ -``` - -## 工作流程 - -### 典型工作流程 - -```mermaid -graph TD - A[开始] --> B{文档类型?} - B -->|API 文档| C[/vitepress-api-doc] - B -->|功能指南| D[/vitepress-guide] - B -->|教程| E[/vitepress-tutorial] - C --> F[/vitepress-validate] - D --> F - E --> F - F --> G{验证通过?} - G -->|是| H[完成] - G -->|否| I[修复问题] - I --> F -``` - -### 推荐流程 - -1. **初始化模块文档** - ```bash - /vitepress-batch-api Core - ``` - -2. **生成功能指南** - ```bash - /vitepress-guide "IoC 容器" Core - /vitepress-guide "事件系统" Core - ``` - -3. **生成教程** - ```bash - /vitepress-tutorial "创建第一个 Model" - /vitepress-tutorial "使用命令系统" - ``` - -4. **验证所有文档** - ```bash - /vitepress-validate docs/zh-CN/ - ``` - -## 目录结构 - -``` -.claude/skills/ -├── README.md # 本文件 -├── _shared/ # 共享资源 -│ └── scripts/ # 共享脚本 -│ ├── update-vitepress-nav.sh # 更新导航配置 -│ ├── parse-csharp-xml.sh # 解析 XML 注释 -│ └── generate-examples.sh # 生成代码示例 -│ -├── vitepress-api-doc/ # API 文档生成 -│ ├── SKILL.md # Skill 说明 -│ ├── template.md # 文档模板 -│ └── examples/ # 示例文档 -│ ├── class-example.md -│ ├── interface-example.md -│ └── enum-example.md -│ -├── vitepress-guide/ # 功能指南生成 -│ ├── SKILL.md -│ ├── template.md -│ └── examples/ -│ └── guide-example.md -│ -├── vitepress-tutorial/ # 教程生成 -│ ├── SKILL.md -│ ├── template.md -│ └── examples/ -│ └── tutorial-example.md -│ -├── vitepress-batch-api/ # 批量 API 文档生成 -│ ├── SKILL.md -│ └── scripts/ -│ └── batch-generate.sh -│ -└── vitepress-validate/ # 文档验证 - ├── SKILL.md - └── scripts/ - ├── validate-frontmatter.sh - ├── validate-links.sh - ├── validate-code-blocks.sh - └── validate-all.sh -``` - -## 设计原则 - -### 1. 单一职责 - -每个 skill 专注于一个特定任务: -- `vitepress-api-doc` - 单文件 API 文档 -- `vitepress-guide` - 功能指南 -- `vitepress-tutorial` - 分步教程 -- `vitepress-batch-api` - 批量生成 -- `vitepress-validate` - 质量验证 - -### 2. 模块化设计 - -- 共享脚本放在 `_shared/scripts/` -- 每个 skill 独立维护 -- 可以单独使用或组合使用 - -### 3. 基于源代码 - -- 仅使用 XML 注释,不添加 AI 补充 -- 保持文档与代码同步 -- 代码示例由 AI 自动生成 - -### 4. 质量保证 - -- 所有生成的文档都应通过验证 -- 遵循 VitePress 规范 -- 保持一致的文档风格 - -## 文档规范 - -### Frontmatter 格式 - -```yaml ---- -title: 文档标题 -description: 简短描述(1-2 句话) -outline: deep # 可选 ---- -``` - -### 代码块标记 - -- C# 代码使用 `csharp` -- Bash 脚本使用 `bash` -- JSON 使用 `json` -- YAML 使用 `yaml` - -### 泛型符号转义 - -在正文中使用 HTML 实体: -- `List` → `List<T>` -- 代码块内保持原样 - -### 中文标点符号 - -- 中文句子使用全角标点:,。!? -- 英文句子使用半角标点:,.!? -- 代码周围使用半角符号 - -## 共享脚本 - -### update-vitepress-nav.sh - -更新 VitePress 侧边栏导航配置。 - -**用法**: -```bash -.claude/skills/_shared/scripts/update-vitepress-nav.sh <文件路径> <标题> -``` - -### parse-csharp-xml.sh - -解析 C# XML 文档注释。 - -**用法**: -```bash -.claude/skills/_shared/scripts/parse-csharp-xml.sh -``` - -### generate-examples.sh - -生成代码示例。 - -**用法**: -```bash -.claude/skills/_shared/scripts/generate-examples.sh <类型名> <命名空间> -``` - -## 最佳实践 - -### 1. 文档生成顺序 - -1. 先生成 API 文档(基础) -2. 再生成功能指南(概念) -3. 最后生成教程(实践) - -### 2. 保持文档同步 - -- 修改代码后及时更新文档 -- 使用单文件生成更新特定文档 -- 定期批量验证所有文档 - -### 3. 质量控制 - -- 生成后立即验证 -- 修复所有错误和警告 -- 确保链接有效 - -### 4. 版本控制 - -- 将生成的文档提交到 Git -- 在 PR 中包含文档更新 -- 保持文档与代码版本一致 - -## 故障排除 - -### 问题:生成的文档缺少内容 - -**原因**:源代码缺少 XML 注释 - -**解决方案**: -1. 在源代码中添加 XML 注释 -2. 重新生成文档 - -### 问题:验证失败 - -**原因**:文档格式不符合规范 - -**解决方案**: -1. 查看验证错误信息 -2. 根据提示修复问题 -3. 重新验证 - -### 问题:链接损坏 - -**原因**:文件路径错误或文件不存在 - -**解决方案**: -1. 检查链接的目标文件是否存在 -2. 修正文件路径 -3. 重新验证 - -### 问题:批量生成速度慢 - -**原因**:文件数量多 - -**解决方案**: -1. 使用 `--parallel` 选项(如果支持) -2. 分批生成 -3. 仅生成修改的文件 - -## 扩展开发 - -### 添加新 Skill - -1. 在 `.claude/skills/` 下创建新目录 -2. 创建 `SKILL.md` 说明文档 -3. 创建必要的模板和脚本 -4. 在本 README 中添加说明 - -### 修改现有 Skill - -1. 更新 `SKILL.md` 文档 -2. 修改模板或脚本 -3. 更新示例文档 -4. 测试修改后的功能 - -## 贡献指南 - -### 报告问题 - -在 GitHub Issues 中报告问题,包含: -- 使用的 skill 名称 -- 输入参数 -- 预期结果 -- 实际结果 -- 错误信息 - -### 提交改进 - -1. Fork 项目 -2. 创建功能分支 -3. 提交修改 -4. 创建 Pull Request - -## 版本历史 - -- v1.0.0 (2025-01-XX) - 初始版本 - - 5 个核心 skills - - 3 个共享脚本 - - 完整的文档和示例 - -## 许可证 - -与 GFramework 项目保持一致。 - -## 联系方式 - -如有问题或建议,请通过以下方式联系: -- GitHub Issues -- 项目讨论区 - ---- - -**注意**:本 skills 系统专为 GFramework 项目设计,使用前请确保了解项目结构和文档规范。 diff --git a/.claude/skills/_shared/DOCUMENTATION_STANDARDS.md b/.claude/skills/_shared/DOCUMENTATION_STANDARDS.md deleted file mode 100644 index d4eb815c..00000000 --- a/.claude/skills/_shared/DOCUMENTATION_STANDARDS.md +++ /dev/null @@ -1,205 +0,0 @@ -# GFramework 文档编写规范 - -## Markdown 语法规范 - -### 1. 泛型标记转义 - -在 Markdown 文档中,所有泛型标记必须转义,否则会被 VitePress 误认为 HTML 标签。 - -**错误示例**: -```markdown -`Option` 是一个泛型类型 -`Result` 表示结果 -public class Repository { } -``` - -**正确示例**: -```markdown -`Option<T>` 是一个泛型类型 -`Result<TValue, TError>` 表示结果 -public class Repository<TData> { } -``` - -**常见泛型标记**: -- `` → `<T>` -- `` → `<TResult>` -- `` → `<TValue>` -- `` → `<TError>` -- `` → `<TSaveData>` -- `` → `<TData>` -- `` → `<TNode>` - -### 2. HTML 标签转义 - -如果需要在文档中显示 HTML 标签,必须转义: -- `` → `<summary>` -- `` → `<param>` -- `` → `<returns>` - -### 3. 链接验证 - -**内部链接规则**: -- 使用相对路径: `/zh-CN/core/events` -- 确保目标文件存在 -- 不要链接到尚未创建的页面 - -**已存在的文档路径**: - -**Core 模块**: -- `/zh-CN/core/architecture` - 架构系统 -- `/zh-CN/core/ioc` - IoC 容器 -- `/zh-CN/core/events` - 事件系统 -- `/zh-CN/core/command` - 命令系统 -- `/zh-CN/core/query` - 查询系统 -- `/zh-CN/core/model` - Model 系统 -- `/zh-CN/core/system` - System 系统 -- `/zh-CN/core/utility` - Utility 系统 -- `/zh-CN/core/controller` - Controller 系统 -- `/zh-CN/core/logging` - 日志系统 -- `/zh-CN/core/pool` - 对象池 -- `/zh-CN/core/property` - 可绑定属性 -- `/zh-CN/core/lifecycle` - 生命周期管理 -- `/zh-CN/core/coroutine` - 协程系统 -- `/zh-CN/core/resource` - 资源管理 -- `/zh-CN/core/state-machine` - 状态机 -- `/zh-CN/core/cqrs` - CQRS 与 Mediator -- `/zh-CN/core/functional` - 函数式编程 -- `/zh-CN/core/pause` - 暂停管理 -- `/zh-CN/core/configuration` - 配置管理 -- `/zh-CN/core/ecs` - ECS 系统集成 -- `/zh-CN/core/extensions` - 扩展方法 -- `/zh-CN/core/rule` - 规则系统 -- `/zh-CN/core/environment` - 环境系统 -- `/zh-CN/core/context` - 上下文系统 -- `/zh-CN/core/async-initialization` - 异步初始化 - -**Game 模块**: -- `/zh-CN/game/scene` - 场景系统 -- `/zh-CN/game/ui` - UI 系统 -- `/zh-CN/game/data` - 数据与存档 -- `/zh-CN/game/storage` - 存储系统 -- `/zh-CN/game/serialization` - 序列化系统 -- `/zh-CN/game/setting` - 设置系统 - -**Godot 模块**: -- `/zh-CN/godot/architecture` - Godot 架构集成 -- `/zh-CN/godot/scene` - Godot 场景系统 -- `/zh-CN/godot/ui` - Godot UI 系统 -- `/zh-CN/godot/pool` - Godot 节点池 -- `/zh-CN/godot/resource` - Godot 资源仓储 -- `/zh-CN/godot/logging` - Godot 日志系统 -- `/zh-CN/godot/pause` - Godot 暂停处理 -- `/zh-CN/godot/extensions` - Godot 扩展 -- `/zh-CN/godot/coroutine` - Godot 协程 -- `/zh-CN/godot/signal` - Godot 信号 -- `/zh-CN/godot/storage` - Godot 存储 - -**教程**: -- `/zh-CN/tutorials/coroutine-tutorial` - 协程系统教程 -- `/zh-CN/tutorials/state-machine-tutorial` - 状态机教程 -- `/zh-CN/tutorials/resource-management` - 资源管理教程 -- `/zh-CN/tutorials/save-system` - 存档系统教程 -- `/zh-CN/tutorials/godot-complete-project` - Godot 完整项目 -- `/zh-CN/tutorials/functional-programming` - 函数式编程实践 -- `/zh-CN/tutorials/pause-system` - 暂停系统实现 -- `/zh-CN/tutorials/data-migration` - 数据迁移实践 -- `/zh-CN/tutorials/godot-integration` - Godot 集成 -- `/zh-CN/tutorials/advanced-patterns` - 高级模式 - -**其他**: -- `/zh-CN/getting-started/quick-start` - 快速开始 -- `/zh-CN/getting-started/installation` - 安装指南 -- `/zh-CN/best-practices/architecture-patterns` - 架构模式 - -**不存在的路径** (不要链接): -- `/zh-CN/best-practices/performance` - 尚未创建 -- `/zh-CN/core/serializer` - 错误路径,应使用 `/zh-CN/game/serialization` - -## 代码块规范 - -### 1. 代码块语言标识 - -始终指定代码块的语言: - -```markdown -\`\`\`csharp -public class Example { } -\`\`\` - -\`\`\`bash -npm install -\`\`\` -``` - -### 2. 代码注释 - -代码示例应包含中文注释: - -```csharp -// 创建玩家实体 -var player = new Player -{ - Name = "玩家1", // 玩家名称 - Level = 1 // 初始等级 -}; -``` - -## Frontmatter 规范 - -每个文档必须包含正确的 frontmatter: - -```yaml ---- -title: 文档标题 -description: 简短描述(1-2 句话) ---- -``` - -## 文档结构规范 - -### 指南文档结构 - -1. 概述 -2. 核心概念 -3. 基本用法 -4. 高级用法 -5. 最佳实践 -6. 常见问题 -7. 相关文档 - -### 教程文档结构 - -1. 学习目标 -2. 前置条件 -3. 步骤 1-N (3-7 步) -4. 完整代码 -5. 运行结果 -6. 下一步 -7. 相关文档 - -## 验证清单 - -生成文档后,必须检查: - -- [ ] 所有泛型标记已转义 (`` → `<T>`) -- [ ] 所有内部链接指向存在的页面 -- [ ] Frontmatter 格式正确 -- [ ] 代码块指定了语言 -- [ ] 代码包含中文注释 -- [ ] 文档结构完整 -- [ ] 没有 HTML 标签错误 - -## 自动修复脚本 - -如果文档已生成,可以使用以下脚本修复常见问题: - -```bash -# 修复泛型标记 -sed -i 's//\<T\>/g' file.md -sed -i 's//\<TResult\>/g' file.md -sed -i 's//\<TValue\>/g' file.md -sed -i 's//\<TError\>/g' file.md - -# 验证构建 -cd docs && bun run build -``` diff --git a/.claude/skills/_shared/module-config.sh b/.claude/skills/_shared/module-config.sh deleted file mode 100644 index 1c645c34..00000000 --- a/.claude/skills/_shared/module-config.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -# 共享的模块配置 -# 用于统一管理 GFramework 项目的模块映射关系 - -# 根据模块名获取源代码目录 -get_source_dir() { - local MODULE="$1" - case "$MODULE" in - Core) - echo "GFramework.Core" - ;; - Game) - echo "GFramework.Game" - ;; - Godot) - echo "GFramework.Godot" - ;; - SourceGenerators) - echo "GFramework.SourceGenerators" - ;; - *) - echo "" - return 1 - ;; - esac -} - -# 根据模块名获取文档输出目录 -get_docs_dir() { - local MODULE="$1" - case "$MODULE" in - Core) - echo "docs/zh-CN/api-reference/core" - ;; - Game) - echo "docs/zh-CN/api-reference/game" - ;; - Godot) - echo "docs/zh-CN/api-reference/godot" - ;; - SourceGenerators) - echo "docs/zh-CN/api-reference/source-generators" - ;; - *) - echo "" - return 1 - ;; - esac -} - -# 根据命名空间推断模块名 -infer_module_from_namespace() { - local NAMESPACE="$1" - if [[ "$NAMESPACE" == GFramework.Core* ]]; then - echo "Core" - elif [[ "$NAMESPACE" == GFramework.Game* ]]; then - echo "Game" - elif [[ "$NAMESPACE" == GFramework.Godot* ]]; then - echo "Godot" - elif [[ "$NAMESPACE" == GFramework.SourceGenerators* ]]; then - echo "SourceGenerators" - else - echo "" - return 1 - fi -} - -# 获取所有可用模块列表 -get_all_modules() { - echo "Core Game Godot SourceGenerators" -} - -# 验证模块名是否有效 -is_valid_module() { - local MODULE="$1" - case "$MODULE" in - Core|Game|Godot|SourceGenerators) - return 0 - ;; - *) - return 1 - ;; - esac -} diff --git a/.claude/skills/vitepress-api-doc/SKILL.md b/.claude/skills/vitepress-api-doc/SKILL.md deleted file mode 100644 index f7bc7b61..00000000 --- a/.claude/skills/vitepress-api-doc/SKILL.md +++ /dev/null @@ -1,210 +0,0 @@ -# VitePress API 文档生成 - -为单个 C# 类、接口或枚举生成符合 VitePress 标准的 API 参考文档。 - -## 用途 - -此 skill 用于从 C# 源代码文件自动生成结构化的 API 文档,包括: -- 类型概述和命名空间信息 -- 构造函数、方法、属性的详细说明 -- 基于 XML 文档注释的描述 -- 自动生成的使用示例 -- 相关类型的交叉引用 - -## 调用方式 - -```bash -/vitepress-api-doc -``` - -**示例**: -```bash -/vitepress-api-doc GFramework.Core/architecture/Architecture.cs -``` - -## 工作流程 - -1. **读取源代码文件** - - 验证文件存在且为 C# 文件 - - 读取完整的源代码内容 - -2. **解析代码结构** - - 提取命名空间、类名、访问修饰符 - - 识别类型(class/interface/enum/struct) - - 解析继承关系和实现的接口 - - 提取所有公共成员(构造函数、方法、属性、事件、字段) - -3. **提取 XML 文档注释** - - 解析 `/// ` 标签(类型和成员描述) - - 解析 `/// ` 标签(参数说明) - - 解析 `/// ` 标签(返回值说明) - - 解析 `/// ` 标签(异常说明) - - 解析 `/// ` 标签(示例代码) - - 解析 `/// ` 标签(交叉引用) - -4. **生成 Markdown 文档** - - 根据 `template.md` 填充内容 - - 转义泛型符号(`` → `<T>`) - - 生成使用示例(基于 API 签名) - - 添加相关文档链接 - -5. **确定输出路径** - - 根据命名空间确定模块(Core/Game/Godot/SourceGenerators) - - 输出到 `docs/zh-CN/api-reference/<模块>/<类名>.md` - -6. **更新 VitePress 配置** - - 调用共享脚本 `update-vitepress-nav.sh` - - 在侧边栏配置中添加新文档条目 - -7. **验证文档质量** - - 检查 Frontmatter 格式 - - 验证内部链接 - - 确保代码块语法正确 - -## 输出规范 - -### Frontmatter 格式 - -```yaml ---- -title: 类名 -description: 从 XML 提取的简短描述 -outline: deep ---- -``` - -### 文档结构 - -1. **标题**:使用类名作为一级标题 -2. **概述**:XML summary 内容 -3. **命名空间和程序集信息** -4. **继承链**(如果适用) -5. **构造函数**(如果有) -6. **公共方法**(按字母顺序) -7. **公共属性**(按字母顺序) -8. **公共事件**(如果有) -9. **使用示例**(自动生成) -10. **另请参阅**(相关类型链接) - -### 代码块格式 - -所有 C# 代码块必须使用: -```markdown -\`\`\`csharp -// 代码内容 -\`\`\` -``` - -### 泛型符号转义 - -- `List` → `List<T>` -- `Dictionary` → `Dictionary<K, V>` -- `IEnumerable` → `IEnumerable<T>` - -### 内部链接格式 - -- 相对路径:`[Architecture](./architecture.md)` -- 绝对路径:`[Core 架构](/zh-CN/core/architecture)` -- 锚点链接:`[构造函数](#构造函数)` - -## 前置条件 - -1. 项目必须有 VitePress 配置文件(`docs/.vitepress/config.mts`) -2. 目标 C# 文件必须存在且可读 -3. C# 文件必须包含 XML 文档注释(`///`) -4. 文件必须包含至少一个公共类型 - -## 配置选项 - -### 自动检测模块 - -根据命名空间自动确定模块: -- `GFramework.Core.*` → `core` -- `GFramework.Game.*` → `game` -- `GFramework.Godot.*` → `godot` -- `GFramework.SourceGenerators.*` → `source-generators` - -### 示例生成策略 - -- **基本用法**:最简单的 API 调用 -- **常见场景**:实际应用案例 -- **高级用法**:复杂配置(如果适用) - -## 示例输出 - -参考 `examples/` 目录中的示例文档: -- `class-example.md` - 类文档示例 -- `interface-example.md` - 接口文档示例 -- `enum-example.md` - 枚举文档示例 - -## 注意事项 - -1. **仅使用 XML 注释**:不对缺失的注释进行 AI 补充 -2. **仅提取公共成员**:忽略 `internal`、`private`、`protected` 成员 -3. **保持文档同步**:文档内容直接来源于代码,确保准确性 -4. **遵循项目风格**:参考现有文档的格式和术语 - -## 相关 Skills - -- `/vitepress-validate` - 验证生成的文档质量 -- `/vitepress-batch-api` - 批量生成整个模块的 API 文档 - -## 技术细节 - -### XML 注释标签映射 - -| XML 标签 | Markdown 输出 | -|---------|--------------| -| `` | 概述章节 | -| `` | 参数列表 | -| `` | 返回值说明 | -| `` | 异常列表 | -| `` | 示例代码块 | -| `` | 内部链接 | -| `` | 备注章节 | - -### 成员签名格式 - -**方法**: -```markdown -### MethodName - -描述内容 - -**签名**: -\`\`\`csharp -public ReturnType MethodName(ParamType param) -\`\`\` - -**参数**: -- `param` (ParamType): 参数说明 - -**返回值**: -- (ReturnType): 返回值说明 -``` - -**属性**: -```markdown -### PropertyName - -描述内容 - -**类型**:`PropertyType` - -**访问**:get / set -``` - -## 故障排除 - -### 问题:找不到 XML 注释 -**解决方案**:确保 C# 文件包含 `///` 注释,而不是 `//` 或 `/* */` - -### 问题:泛型符号显示错误 -**解决方案**:VitePress 配置中已包含 `safeGenericEscapePlugin`,确保正确转义 - -### 问题:侧边栏未更新 -**解决方案**:检查 `update-vitepress-nav.sh` 脚本是否正确执行 - -## 版本历史 - -- v1.0.0 - 初始版本,支持类、接口、枚举的文档生成 diff --git a/.claude/skills/vitepress-api-doc/examples/class-example.md b/.claude/skills/vitepress-api-doc/examples/class-example.md deleted file mode 100644 index c536120e..00000000 --- a/.claude/skills/vitepress-api-doc/examples/class-example.md +++ /dev/null @@ -1,252 +0,0 @@ ---- -title: Architecture -description: 架构基类,提供系统、模型、工具等组件的注册与管理功能。专注于生命周期管理、初始化流程控制和架构阶段转换。 -outline: deep ---- - -# Architecture - -## 概述 - -架构基类,提供系统、模型、工具等组件的注册与管理功能。专注于生命周期管理、初始化流程控制和架构阶段转换。 - -**命名空间**:`GFramework.Core.architecture` -**程序集**:`GFramework.Core` -**继承**:`Object` → `Architecture` -**实现**:`IArchitecture` - -## 构造函数 - -### Architecture - -创建架构实例。 - -**签名**: -```csharp -public Architecture( - IArchitectureConfiguration? configuration = null, - IEnvironment? environment = null, - IArchitectureServices? services = null, - IArchitectureContext? context = null -) -``` - -**参数**: -- `configuration` (IArchitectureConfiguration?): 架构配置对象,为 null 时使用默认配置 -- `environment` (IEnvironment?): 环境配置对象,为 null 时使用默认环境 -- `services` (IArchitectureServices?): 架构服务对象,为 null 时创建新实例 -- `context` (IArchitectureContext?): 架构上下文对象,为 null 时创建新实例 - -## 公共方法 - -### Initialize - -同步初始化架构,阻塞当前线程直到初始化完成。 - -**签名**: -```csharp -public void Initialize() -``` - -**特点**: -- 阻塞式初始化 -- 适用于简单场景或控制台应用 -- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段 - -### InitializeAsync - -异步初始化架构,返回 Task 以便调用者可以等待初始化完成。 - -**签名**: -```csharp -public async Task InitializeAsync() -``` - -**返回值**: -- (Task): 表示异步初始化操作的任务 - -**特点**: -- 非阻塞式初始化 -- 支持异步组件初始化 -- 适用于需要异步加载资源的场景 - -### InstallModule - -安装架构模块,用于扩展架构功能。 - -**签名**: -```csharp -public IArchitectureModule InstallModule(IArchitectureModule module) -``` - -**参数**: -- `module` (IArchitectureModule): 要安装的模块实例 - -**返回值**: -- (IArchitectureModule): 返回安装的模块实例 - -### RegisterSystem - -注册系统组件到架构中。 - -**签名**: -```csharp -public void RegisterSystem(TSystem system) where TSystem : ISystem -``` - -**类型参数**: -- `TSystem`: 系统类型,必须实现 ISystem 接口 - -**参数**: -- `system` (TSystem): 要注册的系统实例 - -### RegisterModel - -注册模型组件到架构中。 - -**签名**: -```csharp -public void RegisterModel(TModel model) where TModel : IModel -``` - -**类型参数**: -- `TModel`: 模型类型,必须实现 IModel 接口 - -**参数**: -- `model` (TModel): 要注册的模型实例 - -### RegisterUtility - -注册工具组件到架构中。 - -**签名**: -```csharp -public void RegisterUtility(TUtility utility) where TUtility : IUtility -``` - -**类型参数**: -- `TUtility`: 工具类型,必须实现 IUtility 接口 - -**参数**: -- `utility` (TUtility): 要注册的工具实例 - -### SendCommand - -发送并执行命令。 - -**签名**: -```csharp -public void SendCommand(ICommand command) -``` - -**参数**: -- `command` (ICommand): 要执行的命令实例 - -### SendCommand<TResult> - -发送并执行带返回值的命令。 - -**签名**: -```csharp -public TResult SendCommand(ICommand command) -``` - -**类型参数**: -- `TResult`: 命令返回值类型 - -**参数**: -- `command` (ICommand<TResult>): 要执行的命令实例 - -**返回值**: -- (TResult): 命令执行结果 - -## 公共属性 - -### CurrentPhase - -获取当前架构的阶段。 - -**类型**:`ArchitecturePhase` -**访问**:get - -### Context - -获取架构上下文,提供对架构服务的访问。 - -**类型**:`IArchitectureContext` -**访问**:get - -### IsReady - -获取一个布尔值,指示当前架构是否处于就绪状态。 - -**类型**:`bool` -**访问**:get - -## 使用示例 - -### 基本用法 - -```csharp -// 1. 定义你的架构(继承 Architecture 基类) -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 注册 Model - RegisterModel(new PlayerModel()); - RegisterModel(new InventoryModel()); - - // 注册 System - RegisterSystem(new GameplaySystem()); - RegisterSystem(new SaveSystem()); - - // 注册 Utility - RegisterUtility(new StorageUtility()); - RegisterUtility(new TimeUtility()); - } -} - -// 2. 创建并初始化架构 -var architecture = new GameArchitecture(); -architecture.Initialize(); - -// 3. 等待架构就绪 -await architecture.WaitUntilReadyAsync(); -``` - -### 异步初始化 - -```csharp -var architecture = new GameArchitecture(); -await architecture.InitializeAsync(); // 异步等待初始化完成 - -// 检查架构是否已就绪 -if (architecture.IsReady) -{ - Console.WriteLine("架构已就绪,可以开始游戏"); -} -``` - -### 使用自定义配置 - -```csharp -var config = new ArchitectureConfiguration -{ - ArchitectureProperties = new ArchitectureProperties - { - StrictPhaseValidation = true, // 启用严格阶段验证 - AllowLateRegistration = false // 禁止就绪后注册组件 - } -}; - -var architecture = new GameArchitecture(configuration: config); -architecture.Initialize(); -``` - -## 另请参阅 - -- [IArchitecture](./iarchitecture.md) - 架构接口 -- [ArchitecturePhase](./architecture-phase.md) - 架构阶段枚举 -- [IArchitectureModule](./iarchitecture-module.md) - 架构模块接口 -- [架构组件](/zh-CN/core/architecture) - 架构使用指南 diff --git a/.claude/skills/vitepress-api-doc/examples/enum-example.md b/.claude/skills/vitepress-api-doc/examples/enum-example.md deleted file mode 100644 index dac3a06b..00000000 --- a/.claude/skills/vitepress-api-doc/examples/enum-example.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -title: ArchitecturePhase -description: 架构阶段枚举,定义了架构生命周期的各个阶段。 -outline: deep ---- - -# ArchitecturePhase - -## 概述 - -架构阶段枚举,定义了架构生命周期的各个阶段。 - -**命名空间**:`GFramework.Core.Abstractions.enums` -**程序集**:`GFramework.Core.Abstractions` -**基础类型**:`Enum` - -## 枚举值 - -### None - -初始阶段,架构尚未开始初始化。 - -**值**:`0` - -### BeforeUtilityInit - -工具初始化前阶段。 - -**值**:`1` - -### AfterUtilityInit - -工具初始化后阶段。 - -**值**:`2` - -### BeforeModelInit - -模型初始化前阶段。 - -**值**:`3` - -### AfterModelInit - -模型初始化后阶段。 - -**值**:`4` - -### BeforeSystemInit - -系统初始化前阶段。 - -**值**:`5` - -### AfterSystemInit - -系统初始化后阶段。 - -**值**:`6` - -### Ready - -就绪状态,架构已完全初始化并可以使用。 - -**值**:`7` - -### FailedInitialization - -初始化失败状态。 - -**值**:`8` - -### Destroying - -正在销毁阶段。 - -**值**:`9` - -### Destroyed - -已销毁阶段。 - -**值**:`10` - -## 使用示例 - -### 检查架构阶段 - -```csharp -var architecture = new GameArchitecture(); -architecture.Initialize(); - -// 检查架构是否已就绪 -if (architecture.CurrentPhase == ArchitecturePhase.Ready) -{ - Console.WriteLine("架构已就绪,可以开始游戏"); -} -``` - -### 监听阶段变化 - -```csharp -public class PhaseMonitor : IArchitectureLifecycle -{ - public void OnPhase(ArchitecturePhase phase, IArchitecture architecture) - { - switch (phase) - { - case ArchitecturePhase.BeforeUtilityInit: - Console.WriteLine("开始初始化工具"); - break; - case ArchitecturePhase.AfterUtilityInit: - Console.WriteLine("工具初始化完成"); - break; - case ArchitecturePhase.BeforeModelInit: - Console.WriteLine("开始初始化模型"); - break; - case ArchitecturePhase.AfterModelInit: - Console.WriteLine("模型初始化完成"); - break; - case ArchitecturePhase.BeforeSystemInit: - Console.WriteLine("开始初始化系统"); - break; - case ArchitecturePhase.AfterSystemInit: - Console.WriteLine("系统初始化完成"); - break; - case ArchitecturePhase.Ready: - Console.WriteLine("架构就绪"); - break; - case ArchitecturePhase.FailedInitialization: - Console.WriteLine("架构初始化失败"); - break; - case ArchitecturePhase.Destroying: - Console.WriteLine("架构正在销毁"); - break; - case ArchitecturePhase.Destroyed: - Console.WriteLine("架构已销毁"); - break; - } - } -} - -// 注册监听器 -var architecture = new GameArchitecture(); -architecture.RegisterLifecycleHook(new PhaseMonitor()); -architecture.Initialize(); -``` - -### 等待特定阶段 - -```csharp -public async Task WaitForReady(IArchitecture architecture) -{ - while (architecture.CurrentPhase != ArchitecturePhase.Ready) - { - if (architecture.CurrentPhase == ArchitecturePhase.FailedInitialization) - { - throw new Exception("架构初始化失败"); - } - - await Task.Delay(100); - } - - Console.WriteLine("架构已就绪"); -} -``` - -## 阶段转换顺序 - -正常初始化流程的阶段转换顺序: - -1. `None` → `BeforeUtilityInit` -2. `BeforeUtilityInit` → `AfterUtilityInit` -3. `AfterUtilityInit` → `BeforeModelInit` -4. `BeforeModelInit` → `AfterModelInit` -5. `AfterModelInit` → `BeforeSystemInit` -6. `BeforeSystemInit` → `AfterSystemInit` -7. `AfterSystemInit` → `Ready` - -销毁流程的阶段转换顺序: - -1. `Ready` → `Destroying` -2. `Destroying` → `Destroyed` - -异常流程: - -- 任何阶段 → `FailedInitialization`(初始化过程中发生异常) - -## 另请参阅 - -- [Architecture](./architecture.md) - 架构基类 -- [IArchitectureLifecycle](./iarchitecture-lifecycle.md) - 生命周期钩子接口 -- [架构组件](/zh-CN/core/architecture) - 架构使用指南 diff --git a/.claude/skills/vitepress-api-doc/examples/interface-example.md b/.claude/skills/vitepress-api-doc/examples/interface-example.md deleted file mode 100644 index 80e3efc2..00000000 --- a/.claude/skills/vitepress-api-doc/examples/interface-example.md +++ /dev/null @@ -1,290 +0,0 @@ ---- -title: IArchitecture -description: 架构接口,定义了框架的核心功能契约。 -outline: deep ---- - -# IArchitecture - -## 概述 - -架构接口,定义了框架的核心功能契约。 - -**命名空间**:`GFramework.Core.Abstractions.architecture` -**程序集**:`GFramework.Core.Abstractions` -**实现类**:[Architecture](./architecture.md) - -## 公共方法 - -### RegisterSystem<TSystem> - -注册系统组件到架构中。 - -**签名**: -```csharp -void RegisterSystem(TSystem system) where TSystem : ISystem -``` - -**类型参数**: -- `TSystem`: 系统类型,必须实现 ISystem 接口 - -**参数**: -- `system` (TSystem): 要注册的系统实例 - -### RegisterModel<TModel> - -注册模型组件到架构中。 - -**签名**: -```csharp -void RegisterModel(TModel model) where TModel : IModel -``` - -**类型参数**: -- `TModel`: 模型类型,必须实现 IModel 接口 - -**参数**: -- `model` (TModel): 要注册的模型实例 - -### RegisterUtility<TUtility> - -注册工具组件到架构中。 - -**签名**: -```csharp -void RegisterUtility(TUtility utility) where TUtility : IUtility -``` - -**类型参数**: -- `TUtility`: 工具类型,必须实现 IUtility 接口 - -**参数**: -- `utility` (TUtility): 要注册的工具实例 - -### GetModel<T> - -从容器中获取已注册的模型。 - -**签名**: -```csharp -T GetModel() where T : class, IModel -``` - -**类型参数**: -- `T`: 模型类型 - -**返回值**: -- (T): 模型实例 - -### GetSystem<T> - -从容器中获取已注册的系统。 - -**签名**: -```csharp -T GetSystem() where T : class, ISystem -``` - -**类型参数**: -- `T`: 系统类型 - -**返回值**: -- (T): 系统实例 - -### GetUtility<T> - -从容器中获取已注册的工具。 - -**签名**: -```csharp -T GetUtility() where T : class, IUtility -``` - -**类型参数**: -- `T`: 工具类型 - -**返回值**: -- (T): 工具实例 - -### SendCommand - -发送并执行命令。 - -**签名**: -```csharp -void SendCommand(ICommand command) -``` - -**参数**: -- `command` (ICommand): 要执行的命令实例 - -### SendCommand<TResult> - -发送并执行带返回值的命令。 - -**签名**: -```csharp -TResult SendCommand(ICommand command) -``` - -**类型参数**: -- `TResult`: 命令返回值类型 - -**参数**: -- `command` (ICommand<TResult>): 要执行的命令实例 - -**返回值**: -- (TResult): 命令执行结果 - -### SendQuery<TResult> - -发送并执行查询。 - -**签名**: -```csharp -TResult SendQuery(IQuery query) -``` - -**类型参数**: -- `TResult`: 查询返回值类型 - -**参数**: -- `query` (IQuery<TResult>): 要执行的查询实例 - -**返回值**: -- (TResult): 查询结果 - -### SendEvent<T> - -发送事件(无参数)。 - -**签名**: -```csharp -void SendEvent() where T : new() -``` - -**类型参数**: -- `T`: 事件类型,必须有无参构造函数 - -### SendEvent<T> - -发送事件(带参数)。 - -**签名**: -```csharp -void SendEvent(T e) -``` - -**类型参数**: -- `T`: 事件类型 - -**参数**: -- `e` (T): 事件实例 - -### RegisterEvent<T> - -注册事件监听器。 - -**签名**: -```csharp -IUnRegister RegisterEvent(Action onEvent) -``` - -**类型参数**: -- `T`: 事件类型 - -**参数**: -- `onEvent` (Action<T>): 事件处理回调 - -**返回值**: -- (IUnRegister): 用于注销事件的对象 - -### UnRegisterEvent<T> - -注销事件监听器。 - -**签名**: -```csharp -void UnRegisterEvent(Action onEvent) -``` - -**类型参数**: -- `T`: 事件类型 - -**参数**: -- `onEvent` (Action<T>): 要注销的事件处理回调 - -## 公共属性 - -### CurrentPhase - -获取当前架构的阶段。 - -**类型**:`ArchitecturePhase` -**访问**:get - -### Context - -获取架构上下文。 - -**类型**:`IArchitectureContext` -**访问**:get - -## 使用示例 - -### 在 Controller 中使用 - -```csharp -public class GameController : IController -{ - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public void Start() - { - // 获取 Model - var playerModel = this.GetModel(); - - // 发送命令 - this.SendCommand(new StartGameCommand()); - - // 发送查询 - var score = this.SendQuery(new GetScoreQuery()); - - // 注册事件 - this.RegisterEvent(OnPlayerDied); - } - - private void OnPlayerDied(PlayerDiedEvent e) - { - // 处理玩家死亡事件 - } -} -``` - -### 实现自定义架构 - -```csharp -public class GameArchitecture : Architecture -{ - // 单例访问 - public static IArchitecture Interface { get; private set; } - - protected override void Init() - { - Interface = this; - - // 注册组件 - RegisterModel(new PlayerModel()); - RegisterSystem(new GameplaySystem()); - RegisterUtility(new StorageUtility()); - } -} -``` - -## 另请参阅 - -- [Architecture](./architecture.md) - 架构基类实现 -- [IModel](./imodel.md) - 模型接口 -- [ISystem](./isystem.md) - 系统接口 -- [IUtility](./iutility.md) - 工具接口 -- [架构组件](/zh-CN/core/architecture) - 架构使用指南 diff --git a/.claude/skills/vitepress-api-doc/template.md b/.claude/skills/vitepress-api-doc/template.md deleted file mode 100644 index 2df3a4c3..00000000 --- a/.claude/skills/vitepress-api-doc/template.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: {{CLASS_NAME}} -description: {{XML_SUMMARY}} -outline: deep ---- - -# {{CLASS_NAME}} - -## 概述 - -{{XML_SUMMARY}} - -**命名空间**:`{{NAMESPACE}}` -**程序集**:`{{ASSEMBLY}}` -{{INHERITANCE_CHAIN}} - -## 构造函数 - -{{CONSTRUCTORS}} - -## 公共方法 - -{{PUBLIC_METHODS}} - -## 公共属性 - -{{PUBLIC_PROPERTIES}} - -{{PUBLIC_EVENTS}} - -## 使用示例 - -{{AUTO_GENERATED_EXAMPLES}} - -## 另请参阅 - -{{RELATED_TYPES}} diff --git a/.claude/skills/vitepress-batch-api/SKILL.md b/.claude/skills/vitepress-batch-api/SKILL.md deleted file mode 100644 index 98ecb5cc..00000000 --- a/.claude/skills/vitepress-batch-api/SKILL.md +++ /dev/null @@ -1,364 +0,0 @@ -# VitePress 批量 API 文档生成 - -为整个模块批量生成 API 参考文档,提高文档生成效率。 - -## 用途 - -此 skill 用于批量生成模块的 API 文档,适用于: -- 初始化模块文档 -- 更新整个模块的文档 -- 为新模块快速生成文档 -- 重新生成所有 API 文档 - -## 调用方式 - -```bash -/vitepress-batch-api <模块名> -``` - -**示例**: -```bash -/vitepress-batch-api Core -/vitepress-batch-api Game -/vitepress-batch-api Godot -/vitepress-batch-api SourceGenerators -``` - -## 工作流程 - -1. **扫描模块目录** - - 根据模块名确定源代码目录 - - 递归扫描所有 C# 文件 - -2. **过滤目标文件** - - 仅包含公共类型(public class/interface/enum/struct) - - 排除内部类型(internal) - - 排除生成的代码(*.g.cs、*.Designer.cs) - - 排除测试文件(*.Tests.cs) - -3. **批量生成文档** - - 为每个类型调用 `/vitepress-api-doc` - - 显示进度信息 - - 收集生成结果 - -4. **生成模块索引页** - - 创建 `index.md` 列出所有 API - - 按类别分组(类、接口、枚举) - - 添加简短描述 - -5. **批量更新导航** - - 在 VitePress 配置中添加所有新文档 - - 保持字母顺序 - - 更新模块索引 - -6. **生成摘要报告** - - 统计生成的文档数量 - - 列出成功和失败的文件 - - 提供验证建议 - -## 输出规范 - -### 模块索引页格式 - -```markdown ---- -title: Core API 参考 -description: GFramework.Core 模块的 API 参考文档 ---- - -# Core API 参考 - -## 概述 - -GFramework.Core 是框架的核心模块,提供架构基础、依赖注入、事件系统等核心功能。 - -## 类 - -- [Architecture](./architecture.md) - 架构基类 -- [ArchitectureConfiguration](./architecture-configuration.md) - 架构配置 -- [IocContainer](./ioc-container.md) - IoC 容器 - -## 接口 - -- [IArchitecture](./iarchitecture.md) - 架构接口 -- [IModel](./imodel.md) - 模型接口 -- [ISystem](./isystem.md) - 系统接口 - -## 枚举 - -- [ArchitecturePhase](./architecture-phase.md) - 架构阶段 -``` - -### 目录结构 - -``` -docs/zh-CN/api-reference/ -├── core/ -│ ├── index.md # 模块索引 -│ ├── architecture.md -│ ├── iarchitecture.md -│ └── ... -├── game/ -│ ├── index.md -│ └── ... -└── godot/ - ├── index.md - └── ... -``` - -## 模块映射 - -### 源代码目录映射 - -| 模块名 | 源代码目录 | 输出目录 | -|--------|-----------|---------| -| Core | `GFramework.Core/` | `docs/zh-CN/api-reference/core/` | -| Game | `GFramework.Game/` | `docs/zh-CN/api-reference/game/` | -| Godot | `GFramework.Godot/` | `docs/zh-CN/api-reference/godot/` | -| SourceGenerators | `GFramework.SourceGenerators/` | `docs/zh-CN/api-reference/source-generators/` | - -### 命名空间映射 - -- `GFramework.Core.*` → Core 模块 -- `GFramework.Game.*` → Game 模块 -- `GFramework.Godot.*` → Godot 模块 -- `GFramework.SourceGenerators.*` → SourceGenerators 模块 - -## 过滤规则 - -### 包含的文件 - -- 公共类(public class) -- 公共接口(public interface) -- 公共枚举(public enum) -- 公共结构体(public struct) - -### 排除的文件 - -- 内部类型(internal) -- 生成的代码(`*.g.cs`、`*.Designer.cs`) -- 测试文件(`*.Tests.cs`、`*Test.cs`) -- 临时文件(`*.tmp.cs`) -- 编译器生成的文件(`AssemblyInfo.cs`) - -### 排除的类型 - -- 编译器生成的类型(`<>c__DisplayClass`) -- 匿名类型 -- 嵌套的私有类型 - -## 批量处理脚本 - -### batch-generate.sh - -```bash -#!/bin/bash -# 批量生成 API 文档 -# 用法: batch-generate.sh <模块名> - -set -e - -MODULE="$1" - -if [ -z "$MODULE" ]; then - echo "用法: $0 <模块名>" - echo "可用模块: Core, Game, Godot, SourceGenerators" - exit 1 -fi - -# 确定源代码目录 -case "$MODULE" in - Core) - SOURCE_DIR="GFramework.Core" - ;; - Game) - SOURCE_DIR="GFramework.Game" - ;; - Godot) - SOURCE_DIR="GFramework.Godot" - ;; - SourceGenerators) - SOURCE_DIR="GFramework.SourceGenerators" - ;; - *) - echo "错误: 未知的模块: $MODULE" - exit 1 - ;; -esac - -if [ ! -d "$SOURCE_DIR" ]; then - echo "错误: 源代码目录不存在: $SOURCE_DIR" - exit 1 -fi - -echo "==========================================" -echo "批量生成 $MODULE 模块的 API 文档" -echo "==========================================" -echo "" - -# 查找所有 C# 文件 -FILES=$(find "$SOURCE_DIR" -name "*.cs" -type f \ - ! -name "*.g.cs" \ - ! -name "*.Designer.cs" \ - ! -name "*Test.cs" \ - ! -name "*.Tests.cs" \ - ! -name "AssemblyInfo.cs") - -FILE_COUNT=$(echo "$FILES" | wc -l) -echo "找到 $FILE_COUNT 个文件" -echo "" - -GENERATED=0 -SKIPPED=0 -FAILED=0 - -for FILE in $FILES; do - echo "处理: $FILE" - - # 检查是否包含公共类型 - if ! grep -q "public \(class\|interface\|enum\|struct\)" "$FILE"; then - echo " ⊘ 跳过(无公共类型)" - SKIPPED=$((SKIPPED + 1)) - continue - fi - - # 调用 vitepress-api-doc(由 AI 执行) - # /vitepress-api-doc "$FILE" - - if [ $? -eq 0 ]; then - echo " ✓ 生成成功" - GENERATED=$((GENERATED + 1)) - else - echo " ✗ 生成失败" - FAILED=$((FAILED + 1)) - fi - - echo "" -done - -echo "==========================================" -echo "批量生成完成" -echo "==========================================" -echo "总文件数: $FILE_COUNT" -echo "生成成功: $GENERATED" -echo "跳过: $SKIPPED" -echo "失败: $FAILED" -echo "" - -if [ $FAILED -eq 0 ]; then - echo "✓ 所有文档生成成功" - exit 0 -else - echo "✗ 部分文档生成失败" - exit 1 -fi -``` - -## 配置选项 - -### 过滤选项 - -```bash -# 包含内部类型 -/vitepress-batch-api Core --include-internal - -# 包含生成的代码 -/vitepress-batch-api Core --include-generated - -# 自定义过滤规则 -/vitepress-batch-api Core --exclude "*.Tests.cs" --exclude "*.g.cs" -``` - -### 输出选项 - -```bash -# 指定输出目录 -/vitepress-batch-api Core --output docs/zh-CN/api-reference/core/ - -# 覆盖现有文档 -/vitepress-batch-api Core --force - -# 仅生成索引页 -/vitepress-batch-api Core --index-only -``` - -### 并行处理 - -```bash -# 并行生成(加快速度) -/vitepress-batch-api Core --parallel 4 -``` - -## 进度显示 - -### 实时进度 - -``` -======================================== -批量生成 Core 模块的 API 文档 -======================================== - -找到 45 个文件 - -[1/45] 处理: GFramework.Core/architecture/Architecture.cs - ✓ 生成成功 - -[2/45] 处理: GFramework.Core/architecture/IArchitecture.cs - ✓ 生成成功 - -[3/45] 处理: GFramework.Core/command/Command.cs - ⊘ 跳过(无公共类型) - -... - -[45/45] 处理: GFramework.Core/utility/Utility.cs - ✓ 生成成功 - -======================================== -批量生成完成 -======================================== -总文件数: 45 -生成成功: 38 -跳过: 5 -失败: 2 - -✗ 部分文档生成失败 - -失败的文件: -- GFramework.Core/internal/InternalClass.cs (缺少 XML 注释) -- GFramework.Core/legacy/LegacyClass.cs (解析错误) -``` - -## 前置条件 - -1. 模块源代码目录存在 -2. 源代码文件包含 XML 文档注释 -3. 有足够的磁盘空间存储生成的文档 - -## 相关 Skills - -- `/vitepress-api-doc` - 单文件 API 文档生成 -- `/vitepress-validate` - 验证生成的文档 -- `/vitepress-guide` - 生成功能指南 - -## 最佳实践 - -1. **首次生成**:使用批量生成快速创建所有文档 -2. **增量更新**:修改代码后使用单文件生成更新对应文档 -3. **定期验证**:批量生成后运行验证确保质量 -4. **版本控制**:将生成的文档提交到版本控制系统 - -## 故障排除 - -### 问题:部分文件生成失败 -**解决方案**:检查失败文件的 XML 注释是否完整,手动修复后重新生成 - -### 问题:生成速度慢 -**解决方案**:使用 `--parallel` 选项启用并行处理 - -### 问题:生成的文档过多 -**解决方案**:使用过滤选项排除不需要的文件 - -## 版本历史 - -- v1.0.0 - 初始版本,支持批量 API 文档生成 diff --git a/.claude/skills/vitepress-batch-api/scripts/batch-generate.sh b/.claude/skills/vitepress-batch-api/scripts/batch-generate.sh deleted file mode 100644 index 949cdaf7..00000000 --- a/.claude/skills/vitepress-batch-api/scripts/batch-generate.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -# 批量生成 API 文档 -# 用法: batch-generate.sh <模块名> - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=../../_shared/module-config.sh -source "$SCRIPT_DIR/../../_shared/module-config.sh" - -MODULE="$1" - -if [ -z "$MODULE" ]; then - echo "用法: $0 <模块名>" - echo "可用模块: $(get_all_modules)" - exit 1 -fi - -# 验证模块名 -if ! is_valid_module "$MODULE"; then - echo "错误: 未知的模块: $MODULE" - echo "可用模块: $(get_all_modules)" - exit 1 -fi - -# 获取源代码目录 -SOURCE_DIR=$(get_source_dir "$MODULE") - -if [ ! -d "$SOURCE_DIR" ]; then - echo "错误: 源代码目录不存在: $SOURCE_DIR" - exit 1 -fi - -echo "==========================================" -echo "批量生成 $MODULE 模块的 API 文档" -echo "==========================================" -echo "" - -# 查找所有 C# 文件 -mapfile -t FILES < <(find "$SOURCE_DIR" -name "*.cs" -type f \ - ! -name "*.g.cs" \ - ! -name "*.Designer.cs" \ - ! -name "*Test.cs" \ - ! -name "*.Tests.cs" \ - ! -name "AssemblyInfo.cs") - -FILE_COUNT=${#FILES[@]} -echo "找到 $FILE_COUNT 个文件" -echo "" - -GENERATED=0 -SKIPPED=0 -FAILED=0 - -for FILE in "${FILES[@]}"; do - echo "处理: $FILE" - - # 检查是否包含公共类型 - if ! grep -q "public \(class\|interface\|enum\|struct\)" "$FILE"; then - echo " ⊘ 跳过(无公共类型)" - SKIPPED=$((SKIPPED + 1)) - continue - fi - - # 注意: 实际的文档生成由 AI 调用 /vitepress-api-doc 完成 - # 此脚本仅用于扫描和过滤文件 - - echo " → 待生成" - GENERATED=$((GENERATED + 1)) - echo "" -done - -echo "==========================================" -echo "扫描完成" -echo "==========================================" -echo "总文件数: $FILE_COUNT" -echo "待生成: $GENERATED" -echo "跳过: $SKIPPED" -echo "" - -exit 0 diff --git a/.claude/skills/vitepress-doc-generator/SKILL.md b/.claude/skills/vitepress-doc-generator/SKILL.md deleted file mode 100644 index 1cd35e7e..00000000 --- a/.claude/skills/vitepress-doc-generator/SKILL.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: vitepress-doc-generator -description: Generate standardized VitePress documentation from source code. -disable-model-invocation: true ---- - -# Role - -You are a technical documentation generator specialized in VitePress. - -# Objective - -Analyze the provided code context and generate a structured VitePress-compatible Markdown document. - -# Output Requirements - -1. Output MUST be valid Markdown only. -2. Include frontmatter: - ---- -title: -outline: deep ---- - -3. No explanations. -4. No conversational text. -5. No emoji. -6. Use Chinese. -7. Use structured headings. - -# Required Structure - -# 模块概述 -- 模块职责 -- 设计目标 - -# 核心类说明 -## 类名 -### 职责 -### 主要方法 -### 依赖关系 - -# 设计模式分析 -# 可扩展性说明 -# 使用示例(如适用) - -# Self-Validation - -Before returning output, verify: -- Frontmatter exists -- All required sections exist -- No extra commentary text \ No newline at end of file diff --git a/.claude/skills/vitepress-doc-generator/template.md b/.claude/skills/vitepress-doc-generator/template.md deleted file mode 100644 index e69de29b..00000000 diff --git a/.claude/skills/vitepress-guide/SKILL.md b/.claude/skills/vitepress-guide/SKILL.md deleted file mode 100644 index b2539ef2..00000000 --- a/.claude/skills/vitepress-guide/SKILL.md +++ /dev/null @@ -1,256 +0,0 @@ -# VitePress 功能指南生成 - -生成功能模块的使用指南文档,包括概念说明、用法示例和最佳实践。 - -## 用途 - -此 skill 用于生成结构化的功能指南文档,适用于: -- 核心功能模块的使用说明 -- 设计模式和架构概念 -- 系统功能的详细介绍 -- 最佳实践和常见问题 - -## 调用方式 - -```bash -/vitepress-guide <主题> <目标模块> -``` - -**示例**: -```bash -/vitepress-guide "事件系统" Core -/vitepress-guide "IoC 容器" Core -/vitepress-guide "Godot 节点扩展" Godot -``` - -## 工作流程 - -1. **收集需求** - - 询问用户指南主题 - - 确定目标受众(初学者/进阶/专家) - - 了解重点内容(概念/用法/最佳实践) - -2. **搜索相关资源** - - 搜索相关代码文件 - - 查找现有文档 - - 识别相关类型和接口 - -3. **生成指南结构** - - 根据 `template.md` 创建文档框架 - - 填充概述和核心概念 - - 添加基本用法和高级用法 - - 补充最佳实践和常见问题 - -4. **生成代码示例** - - 基本用法示例(最简单的场景) - - 常见场景示例(实际应用) - - 高级用法示例(复杂配置) - -5. **确定输出路径** - - 保存到 `docs/zh-CN/<模块>/` - - 文件名使用小写加连字符(如 `event-system.md`) - -6. **更新导航配置** - - 在 VitePress 侧边栏中添加新指南 - -## 输出规范 - -### Frontmatter 格式 - -```yaml ---- -title: 指南标题 -description: 简短描述(1-2 句话) ---- -``` - -### 文档结构 - -1. **概述**:功能的简介和用途 -2. **核心概念**:关键概念和术语解释 -3. **基本用法**:最简单的使用方式 -4. **高级用法**:复杂场景和配置 -5. **最佳实践**:推荐的使用方式 -6. **常见问题**:FAQ 和故障排除 - -### 章节示例 - -**概述**: -```markdown -## 概述 - -事件系统提供了一种松耦合的组件间通信机制。通过事件,不同的组件可以在不直接引用彼此的情况下进行交互。 - -**主要特性**: -- 类型安全的事件 -- 自动内存管理 -- 支持事件优先级 -- 线程安全 -``` - -**核心概念**: -```markdown -## 核心概念 - -### 事件类型 - -事件是一个普通的 C# 类,用于携带事件数据: - -\`\`\`csharp -public class PlayerDiedEvent -{ - public int PlayerId { get; set; } - public string Reason { get; set; } -} -\`\`\` - -### 事件发送 - -通过架构发送事件: - -\`\`\`csharp -this.SendEvent(new PlayerDiedEvent -{ - PlayerId = 1, - Reason = "Fall damage" -}); -\`\`\` - -### 事件监听 - -注册事件监听器: - -\`\`\`csharp -this.RegisterEvent(OnPlayerDied); -\`\`\` -``` - -## 模板变量 - -- `{{GUIDE_TITLE}}` - 指南标题 -- `{{GUIDE_DESCRIPTION}}` - 简短描述 -- `{{OVERVIEW}}` - 概述内容 -- `{{CORE_CONCEPTS}}` - 核心概念 -- `{{BASIC_USAGE}}` - 基本用法 -- `{{ADVANCED_USAGE}}` - 高级用法 -- `{{BEST_PRACTICES}}` - 最佳实践 -- `{{FAQ}}` - 常见问题 - -## 示例输出 - -参考 `examples/guide-example.md`,该示例基于现有的 IoC 容器文档创建。 - -## 内容要求 - -### 概述部分 -- 1-2 段简介 -- 列出主要特性(3-5 个) -- 说明适用场景 - -### 核心概念部分 -- 使用三级标题(###)分隔不同概念 -- 每个概念包含简短说明和代码示例 -- 解释关键术语 - -### 基本用法部分 -- 提供完整的可运行示例 -- 从最简单的场景开始 -- 逐步增加复杂度 -- 包含必要的 using 语句 - -### 高级用法部分 -- 展示复杂场景 -- 说明配置选项 -- 提供性能优化建议 - -### 最佳实践部分 -- 使用编号列表 -- 每条实践包含简短说明 -- 提供正反示例(✓ 推荐 / ✗ 不推荐) - -### 常见问题部分 -- 使用问答格式 -- 提供具体的解决方案 -- 包含相关链接 - -## 写作风格 - -### 语气 -- 友好、专业 -- 使用第二人称("你") -- 避免过于技术化的术语 - -### 代码示例 -- 完整且可运行 -- 包含注释说明关键步骤 -- 使用有意义的变量名 -- 遵循项目代码风格 - -### 格式 -- 使用 Markdown 标准格式 -- 代码块使用语法高亮 -- 重要内容使用粗体或引用块 -- 适当使用列表和表格 - -## 配置选项 - -### 目标受众 - -```bash -# 初学者(更多解释,简单示例) -/vitepress-guide "事件系统" Core --audience beginner - -# 进阶(平衡解释和示例) -/vitepress-guide "事件系统" Core --audience intermediate - -# 专家(简洁说明,复杂示例) -/vitepress-guide "事件系统" Core --audience expert -``` - -### 重点内容 - -```bash -# 侧重概念 -/vitepress-guide "事件系统" Core --focus concepts - -# 侧重用法 -/vitepress-guide "事件系统" Core --focus usage - -# 侧重最佳实践 -/vitepress-guide "事件系统" Core --focus best-practices -``` - -## 前置条件 - -1. 了解指南主题的基本概念 -2. 能够访问相关代码文件 -3. 了解项目的代码风格和术语 - -## 相关 Skills - -- `/vitepress-api-doc` - 生成 API 参考文档 -- `/vitepress-tutorial` - 生成分步教程 -- `/vitepress-validate` - 验证生成的文档 - -## 最佳实践 - -1. **先搜索后编写**:查看现有文档和代码,保持一致性 -2. **使用真实示例**:基于项目实际代码创建示例 -3. **保持简洁**:每个章节聚焦一个主题 -4. **提供完整代码**:确保示例可以直接运行 -5. **添加交叉引用**:链接到相关的 API 文档和其他指南 - -## 故障排除 - -### 问题:不确定指南应该包含哪些内容 -**解决方案**:参考 `examples/guide-example.md` 和现有的指南文档 - -### 问题:代码示例过于复杂 -**解决方案**:将复杂示例拆分为多个简单示例,逐步增加复杂度 - -### 问题:概念解释不清晰 -**解决方案**:使用类比、图表或分步说明来辅助解释 - -## 版本历史 - -- v1.0.0 - 初始版本,支持功能指南生成 diff --git a/.claude/skills/vitepress-guide/examples/guide-example.md b/.claude/skills/vitepress-guide/examples/guide-example.md deleted file mode 100644 index d76d01d3..00000000 --- a/.claude/skills/vitepress-guide/examples/guide-example.md +++ /dev/null @@ -1,283 +0,0 @@ ---- -title: IoC 容器使用指南 -description: IoC(控制反转)容器提供了轻量级的依赖注入功能,用于管理框架中各种组件的注册和获取。 ---- - -# IoC 容器使用指南 - -## 概述 - -IoC(Inversion of Control,控制反转)包提供了一个轻量级的依赖注入容器,用于管理框架中各种组件的注册和获取。通过 IoC 容器,可以实现组件间的解耦,便于测试和维护。 - -IoC 容器是 GFramework 架构的核心组件之一,为整个框架提供依赖管理和组件解析服务。 - -**主要特性**: -- 类型安全的依赖管理 -- 支持单例和多实例注册 -- 线程安全操作 -- 容器冻结保护 -- 自动接口注册 - -## 核心概念 - -### 依赖注入 - -依赖注入是一种设计模式,通过容器管理对象的创建和依赖关系,而不是在代码中直接创建对象。 - -```csharp -// 不使用依赖注入 -public class GameController -{ - private PlayerModel model = new PlayerModel(); // 硬编码依赖 -} - -// 使用依赖注入 -public class GameController : IController -{ - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public void Start() - { - var model = this.GetModel(); // 从容器获取 - } -} -``` - -### 容器注册 - -在架构初始化时,将组件注册到容器中: - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 注册 Model - RegisterModel(new PlayerModel()); - - // 注册 System - RegisterSystem(new GameplaySystem()); - - // 注册 Utility - RegisterUtility(new StorageUtility()); - } -} -``` - -### 容器解析 - -通过扩展方法从容器中获取已注册的组件: - -```csharp -// 在 Controller 中 -var playerModel = this.GetModel(); -var gameplaySystem = this.GetSystem(); -var storageUtility = this.GetUtility(); -``` - -## 基本用法 - -### 注册组件 - -```csharp -var container = new IocContainer(); - -// 注册单例(一个类型只能有一个实例) -container.RegisterSingleton(new PlayerModel()); - -// 注册多实例(一个类型可以有多个实例) -container.RegisterPlurality(new Goblin()); -container.RegisterPlurality(new Orc()); -container.RegisterPlurality(new Dragon()); -``` - -### 获取组件 - -```csharp -// 获取单例 -var playerModel = container.Get(); - -// 获取多实例集合 -var enemies = container.GetAll(); // 返回 List -``` - -### 在架构中使用 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 注册组件 - RegisterModel(new PlayerModel()); - RegisterModel(new InventoryModel()); - RegisterSystem(new GameplaySystem()); - } -} - -// 在 Controller 中使用 -public class GameController : IController -{ - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public void Start() - { - // 通过扩展方法获取组件 - var playerModel = this.GetModel(); - var inventoryModel = this.GetModel(); - var gameplaySystem = this.GetSystem(); - } -} -``` - -## 高级用法 - -### 容器冻结 - -容器在架构初始化完成后会被冻结,防止运行时修改: - -```csharp -var container = new IocContainer(); -container.Register(new PlayerModel()); - -// 冻结容器 -container.Freeze(); - -// 以下操作会抛出 InvalidOperationException -// container.Register(new GameSystem()); -``` - -### 多实例管理 - -```csharp -// 注册多个同类型实例 -container.RegisterPlurality(new Sword()); -container.RegisterPlurality(new Bow()); -container.RegisterPlurality(new Staff()); - -// 获取所有实例 -var allWeapons = container.GetAll(); -foreach (var weapon in allWeapons) -{ - weapon.Attack(); -} -``` - -### 接口自动注册 - -注册实例时,容器会自动将其注册到所有实现的接口: - -```csharp -public class PlayerModel : IModel, IPlayerModel, IDisposable -{ - // ... -} - -// 注册实例 -container.Register(new PlayerModel()); - -// 可以通过任何接口获取 -var model1 = container.Get(); -var model2 = container.Get(); -var model3 = container.Get(); -// 以上三个变量指向同一个实例 -``` - -### 线程安全操作 - -容器的所有操作都是线程安全的: - -```csharp -// 多线程环境下安全使用 -Parallel.For(0, 100, i => -{ - var model = container.Get(); - model.DoSomething(); -}); -``` - -## 最佳实践 - -1. **使用接口注册**:优先使用接口类型注册,而不是具体类型 - ```csharp - ✓ container.Register(new PlayerModel()); - ✗ container.Register(new PlayerModel()); - ``` - -2. **单例 vs 多实例**:根据需求选择合适的注册方式 - - 单例:全局唯一的服务(如配置、管理器) - - 多实例:可以有多个实例的对象(如敌人、道具) - -3. **避免循环依赖**:组件之间不应该相互依赖 - ```csharp - ✗ System A 依赖 System B,System B 又依赖 System A - ✓ 使用事件系统进行通信,避免直接依赖 - ``` - -4. **在 Init 中注册**:所有组件应该在架构的 `Init()` 方法中注册 - ```csharp - protected override void Init() - { - // 在这里注册所有组件 - RegisterModel(new PlayerModel()); - RegisterSystem(new GameplaySystem()); - } - ``` - -5. **使用扩展方法**:通过扩展方法获取组件,代码更简洁 - ```csharp - ✓ var model = this.GetModel(); - ✗ var model = this.GetArchitecture().GetModel(); - ``` - -6. **不要在运行时注册**:容器冻结后不应该再注册新组件 - ```csharp - ✗ 在游戏运行时动态注册组件 - ✓ 在架构初始化时注册所有需要的组件 - ``` - -## 常见问题 - -### 问题:如何判断使用单例还是多实例? - -**解答**: -- 使用单例(`RegisterSingleton`):全局唯一的服务,如 PlayerModel、GameConfiguration -- 使用多实例(`RegisterPlurality`):可以有多个实例的对象,如 Enemy、Weapon - -### 问题:容器冻结后如何添加新组件? - -**解答**: -容器冻结是为了保护架构稳定性。如果需要动态添加组件,应该: -1. 在架构初始化时预先注册所有可能需要的组件 -2. 使用对象池模式管理动态对象 -3. 考虑使用工厂模式创建临时对象 - -### 问题:如何处理组件的生命周期? - -**解答**: -- 实现 `IDisposable` 接口的组件会在架构销毁时自动释放 -- 架构会按注册的逆序销毁组件 -- 不需要手动管理组件的生命周期 - -### 问题:可以在容器中注册值类型吗? - -**解答**: -可以,但会发生装箱。建议将值类型包装在类中: -```csharp -// 不推荐 -container.Register(42); - -// 推荐 -public class GameConfig -{ - public int MaxPlayers { get; set; } = 42; -} -container.Register(new GameConfig()); -``` - -## 相关文档 - -- [架构组件](/zh-CN/core/architecture) - 架构基础 -- [Model 层](/zh-CN/core/model) - 数据模型 -- [System 层](/zh-CN/core/system) - 业务系统 -- [Utility 工具类](/zh-CN/core/utility) - 工具类 diff --git a/.claude/skills/vitepress-guide/template.md b/.claude/skills/vitepress-guide/template.md deleted file mode 100644 index 3f7fbd70..00000000 --- a/.claude/skills/vitepress-guide/template.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: {{GUIDE_TITLE}} -description: {{GUIDE_DESCRIPTION}} ---- - -# {{GUIDE_TITLE}} - -## 概述 - -{{OVERVIEW}} - -## 核心概念 - -{{CORE_CONCEPTS}} - -## 基本用法 - -{{BASIC_USAGE}} - -## 高级用法 - -{{ADVANCED_USAGE}} - -## 最佳实践 - -{{BEST_PRACTICES}} - -## 常见问题 - -{{FAQ}} - -## 相关文档 - -{{RELATED_DOCS}} diff --git a/.claude/skills/vitepress-tutorial/SKILL.md b/.claude/skills/vitepress-tutorial/SKILL.md deleted file mode 100644 index 99e9b9df..00000000 --- a/.claude/skills/vitepress-tutorial/SKILL.md +++ /dev/null @@ -1,253 +0,0 @@ -# VitePress 教程生成 - -生成分步教程文档,适合初学者学习框架功能。 - -## 用途 - -此 skill 用于生成结构化的分步教程,适用于: -- 框架入门教程 -- 功能实现教程 -- 最佳实践演示 -- 问题解决方案 - -## 调用方式 - -```bash -/vitepress-tutorial <教程主题> -``` - -**示例**: -```bash -/vitepress-tutorial "创建第一个 System" -/vitepress-tutorial "实现自定义命令" -/vitepress-tutorial "使用事件系统" -``` - -## 工作流程 - -1. **收集需求** - - 询问用户教程主题 - - 确定学习目标 - - 了解前置知识要求 - -2. **设计教程步骤** - - 将任务分解为 3-7 个步骤 - - 每步聚焦一个具体任务 - - 确保步骤之间逻辑连贯 - -3. **生成教程内容** - - 根据 `template.md` 创建文档框架 - - 为每步编写详细说明和代码 - - 添加完整的可运行代码 - - 说明预期结果 - -4. **确定输出路径** - - 保存到 `docs/zh-CN/tutorials/` - - 文件名使用小写加连字符 - -5. **更新导航配置** - - 在 VitePress 侧边栏中添加新教程 - -## 输出规范 - -### Frontmatter 格式 - -```yaml ---- -title: 教程标题 -description: 简短描述(1 句话说明学习内容) ---- -``` - -### 文档结构 - -1. **学习目标**:完成教程后能够掌握的技能 -2. **前置条件**:需要的前置知识和环境 -3. **步骤 1-N**:分步说明(3-7 步) -4. **完整代码**:汇总所有代码 -5. **运行结果**:预期输出和效果 -6. **下一步**:后续学习建议 - -### 步骤格式 - -每个步骤应包含: -- 步骤标题(简短、动词开头) -- 步骤说明(为什么要这样做) -- 代码示例(完整且可运行) -- 代码解释(关键部分的说明) - -**示例**: -```markdown -## 步骤 1:创建 Model 类 - -首先,我们需要创建一个 Model 来存储玩家数据。Model 负责管理应用的数据和状态。 - -\`\`\`csharp -using GFramework.Core.Abstractions.model; -using GFramework.Core.Abstractions.property; - -public class PlayerModel : IModel -{ - // 玩家名称(可绑定属性) - public BindableProperty Name { get; } = new("Player"); - - // 玩家生命值 - public BindableProperty Health { get; } = new(100); - - // 玩家金币 - public BindableProperty Gold { get; } = new(0); - - public void Init() { } -} -\`\`\` - -**代码说明**: -- `BindableProperty` 是可绑定属性,值变化时会自动通知监听者 -- `Init()` 方法在 Model 注册到架构时被调用 -- 使用属性初始化器设置默认值 -``` - -## 模板变量 - -- `{{TUTORIAL_TITLE}}` - 教程标题 -- `{{TUTORIAL_DESCRIPTION}}` - 简短描述 -- `{{LEARNING_OBJECTIVES}}` - 学习目标 -- `{{PREREQUISITES}}` - 前置条件 -- `{{STEP_N_TITLE}}` - 步骤标题 -- `{{STEP_N_CONTENT}}` - 步骤内容 -- `{{FULL_CODE}}` - 完整代码 -- `{{EXPECTED_OUTPUT}}` - 预期输出 -- `{{NEXT_STEPS}}` - 下一步建议 - -## 示例输出 - -参考 `examples/tutorial-example.md`,该示例基于现有的教程文档创建。 - -## 内容要求 - -### 学习目标 -- 使用列表格式 -- 3-5 个具体的学习目标 -- 使用"能够..."句式 - -**示例**: -```markdown -## 学习目标 - -完成本教程后,你将能够: -- 创建自定义的 Model 类 -- 在架构中注册 Model -- 从 Controller 中访问 Model -- 使用可绑定属性管理数据 -``` - -### 前置条件 -- 列出必需的知识 -- 说明环境要求 -- 提供相关文档链接 - -**示例**: -```markdown -## 前置条件 - -- 已安装 GFramework.Core NuGet 包 -- 了解 C# 基础语法 -- 阅读过[架构概览](/zh-CN/getting-started) -``` - -### 步骤内容 -- 每步 100-300 字说明 -- 包含完整的代码示例 -- 解释关键代码的作用 -- 使用注释标注重要部分 - -### 完整代码 -- 汇总所有步骤的代码 -- 确保可以直接复制运行 -- 包含必要的 using 语句 -- 添加文件结构说明 - -### 运行结果 -- 描述预期的输出 -- 如果有界面,提供截图或描述 -- 说明如何验证结果正确 - -### 下一步 -- 推荐 2-3 个后续教程 -- 提供相关文档链接 -- 建议进阶学习方向 - -## 写作风格 - -### 语气 -- 友好、鼓励性 -- 使用第二人称("你") -- 避免假设读者已有高级知识 - -### 步骤说明 -- 使用主动语态 -- 步骤标题使用动词开头 -- 说明"为什么"而不仅是"怎么做" - -### 代码示例 -- 完整且可运行 -- 包含详细注释 -- 使用有意义的变量名 -- 遵循项目代码风格 - -## 配置选项 - -### 教程难度 - -```bash -# 初学者(更多解释,简单示例) -/vitepress-tutorial "创建第一个 System" --level beginner - -# 中级(平衡解释和复杂度) -/vitepress-tutorial "实现自定义命令" --level intermediate - -# 高级(简洁说明,复杂示例) -/vitepress-tutorial "架构模块开发" --level advanced -``` - -### 步骤数量 - -```bash -# 指定步骤数量(3-7 步) -/vitepress-tutorial "使用事件系统" --steps 5 -``` - -## 前置条件 - -1. 了解教程主题的基本概念 -2. 能够访问相关代码文件 -3. 了解目标受众的知识水平 - -## 相关 Skills - -- `/vitepress-api-doc` - 生成 API 参考文档 -- `/vitepress-guide` - 生成功能指南 -- `/vitepress-validate` - 验证生成的文档 - -## 最佳实践 - -1. **从简单开始**:第一步应该是最简单的操作 -2. **逐步增加复杂度**:每步在前一步基础上增加新内容 -3. **提供完整代码**:确保每步的代码都可以运行 -4. **解释关键概念**:不要假设读者已经了解所有术语 -5. **测试教程**:确保按照步骤操作能够得到预期结果 - -## 故障排除 - -### 问题:步骤过多,教程太长 -**解决方案**:将教程拆分为多个小教程,或合并相似的步骤 - -### 问题:代码示例不完整 -**解决方案**:在"完整代码"章节提供所有文件的完整代码 - -### 问题:读者反馈步骤不清晰 -**解决方案**:增加更多说明,使用截图或图表辅助 - -## 版本历史 - -- v1.0.0 - 初始版本,支持分步教程生成 diff --git a/.claude/skills/vitepress-tutorial/examples/tutorial-example.md b/.claude/skills/vitepress-tutorial/examples/tutorial-example.md deleted file mode 100644 index ef628b38..00000000 --- a/.claude/skills/vitepress-tutorial/examples/tutorial-example.md +++ /dev/null @@ -1,347 +0,0 @@ ---- -title: 创建第一个 Model -description: 学习如何创建和使用 Model 来管理应用数据 ---- - -# 创建第一个 Model - -## 学习目标 - -完成本教程后,你将能够: -- 理解 Model 在架构中的作用 -- 创建自定义的 Model 类 -- 在架构中注册 Model -- 从 Controller 中访问 Model -- 使用可绑定属性管理数据 - -## 前置条件 - -- 已安装 GFramework.Core NuGet 包 -- 了解 C# 基础语法 -- 阅读过[架构概览](/zh-CN/getting-started) - -## 步骤 1:创建 Model 类 - -首先,我们需要创建一个 Model 来存储玩家数据。Model 负责管理应用的数据和状态。 - -```csharp -using GFramework.Core.Abstractions.model; -using GFramework.Core.Abstractions.property; - -namespace MyGame.Models -{ - /// - /// 玩家数据模型 - /// - public class PlayerModel : IModel - { - // 玩家名称(可绑定属性) - public BindableProperty Name { get; } = new("Player"); - - // 玩家生命值 - public BindableProperty Health { get; } = new(100); - - // 玩家金币 - public BindableProperty Gold { get; } = new(0); - - // 玩家等级 - public BindableProperty Level { get; } = new(1); - - /// - /// Model 初始化方法 - /// - public void Init() - { - // 在这里可以进行初始化操作 - // 例如:从配置文件加载默认值 - } - } -} -``` - -**代码说明**: -- `IModel` 接口标识这是一个数据模型 -- `BindableProperty` 是可绑定属性,值变化时会自动通知监听者 -- `Init()` 方法在 Model 注册到架构时被调用 -- 使用属性初始化器设置默认值 - -## 步骤 2:在架构中注册 Model - -创建架构类并注册 Model: - -```csharp -using GFramework.Core.architecture; -using MyGame.Models; - -namespace MyGame -{ - /// - /// 游戏架构 - /// - public class GameArchitecture : Architecture - { - // 单例访问点 - public static IArchitecture Interface { get; private set; } - - /// - /// 初始化架构 - /// - protected override void Init() - { - Interface = this; - - // 注册 Model - RegisterModel(new PlayerModel()); - } - } -} -``` - -**代码说明**: -- 继承 `Architecture` 基类 -- 在 `Init()` 方法中注册 Model -- 提供静态属性 `Interface` 用于全局访问架构 - -## 步骤 3:创建 Controller 访问 Model - -创建 Controller 来使用 Model: - -```csharp -using GFramework.Core.Abstractions.architecture; -using GFramework.Core.Abstractions.controller; -using GFramework.Core.extensions; -using MyGame.Models; - -namespace MyGame.Controllers -{ - /// - /// 游戏控制器 - /// - public class GameController : IController - { - /// - /// 获取架构实例 - /// - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - /// - /// 初始化玩家数据 - /// - public void InitializePlayer() - { - // 获取 PlayerModel - var playerModel = this.GetModel(); - - // 设置玩家数据 - playerModel.Name.Value = "勇者"; - playerModel.Health.Value = 100; - playerModel.Gold.Value = 50; - playerModel.Level.Value = 1; - - // 监听属性变化 - playerModel.Health.RegisterOnValueChanged(health => - { - Console.WriteLine($"玩家生命值变化: {health}"); - - if (health <= 0) - { - Console.WriteLine("玩家死亡!"); - } - }); - } - - /// - /// 玩家受到伤害 - /// - public void TakeDamage(int damage) - { - var playerModel = this.GetModel(); - playerModel.Health.Value -= damage; - } - - /// - /// 玩家获得金币 - /// - public void AddGold(int amount) - { - var playerModel = this.GetModel(); - playerModel.Gold.Value += amount; - } - } -} -``` - -**代码说明**: -- 实现 `IController` 接口 -- 通过 `this.GetModel()` 扩展方法获取 Model -- 使用 `.Value` 访问和修改属性值 -- 使用 `RegisterOnValueChanged` 监听属性变化 - -## 步骤 4:初始化并使用架构 - -在程序入口点初始化架构: - -```csharp -using MyGame; -using MyGame.Controllers; - -// 1. 创建并初始化架构 -var architecture = new GameArchitecture(); -architecture.Initialize(); - -// 2. 等待架构就绪 -await architecture.WaitUntilReadyAsync(); - -// 3. 创建 Controller 并使用 -var gameController = new GameController(); - -// 初始化玩家 -gameController.InitializePlayer(); - -// 玩家受到伤害 -gameController.TakeDamage(20); -// 输出: 玩家生命值变化: 80 - -// 玩家获得金币 -gameController.AddGold(100); -``` - -**代码说明**: -- 创建架构实例并调用 `Initialize()` -- 使用 `WaitUntilReadyAsync()` 等待架构就绪 -- 创建 Controller 实例并调用方法 - -## 完整代码 - -### PlayerModel.cs - -```csharp -using GFramework.Core.Abstractions.model; -using GFramework.Core.Abstractions.property; - -namespace MyGame.Models -{ - public class PlayerModel : IModel - { - public BindableProperty Name { get; } = new("Player"); - public BindableProperty Health { get; } = new(100); - public BindableProperty Gold { get; } = new(0); - public BindableProperty Level { get; } = new(1); - - public void Init() { } - } -} -``` - -### GameArchitecture.cs - -```csharp -using GFramework.Core.architecture; -using MyGame.Models; - -namespace MyGame -{ - public class GameArchitecture : Architecture - { - public static IArchitecture Interface { get; private set; } - - protected override void Init() - { - Interface = this; - RegisterModel(new PlayerModel()); - } - } -} -``` - -### GameController.cs - -```csharp -using GFramework.Core.Abstractions.architecture; -using GFramework.Core.Abstractions.controller; -using GFramework.Core.extensions; -using MyGame.Models; - -namespace MyGame.Controllers -{ - public class GameController : IController - { - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public void InitializePlayer() - { - var playerModel = this.GetModel(); - playerModel.Name.Value = "勇者"; - playerModel.Health.Value = 100; - playerModel.Gold.Value = 50; - playerModel.Level.Value = 1; - - playerModel.Health.RegisterOnValueChanged(health => - { - Console.WriteLine($"玩家生命值变化: {health}"); - if (health <= 0) - { - Console.WriteLine("玩家死亡!"); - } - }); - } - - public void TakeDamage(int damage) - { - var playerModel = this.GetModel(); - playerModel.Health.Value -= damage; - } - - public void AddGold(int amount) - { - var playerModel = this.GetModel(); - playerModel.Gold.Value += amount; - } - } -} -``` - -### Program.cs - -```csharp -using MyGame; -using MyGame.Controllers; - -var architecture = new GameArchitecture(); -architecture.Initialize(); -await architecture.WaitUntilReadyAsync(); - -var gameController = new GameController(); -gameController.InitializePlayer(); -gameController.TakeDamage(20); -gameController.AddGold(100); -``` - -## 运行结果 - -运行程序后,你将看到以下输出: - -``` -玩家生命值变化: 100 -玩家生命值变化: 80 -``` - -**验证步骤**: -1. 程序成功启动,没有异常 -2. 控制台输出生命值变化信息 -3. 玩家数据正确更新 - -## 下一步 - -恭喜!你已经学会了如何创建和使用 Model。接下来可以学习: - -- [创建第一个 System](/zh-CN/tutorials/create-first-system) - 学习如何创建业务逻辑层 -- [使用命令系统](/zh-CN/tutorials/use-command-system) - 学习如何封装操作 -- [使用事件系统](/zh-CN/tutorials/use-event-system) - 学习组件间通信 - -## 相关文档 - -- [Model 层](/zh-CN/core/model) - Model 详细说明 -- [属性系统](/zh-CN/core/property) - 可绑定属性详解 -- [架构组件](/zh-CN/core/architecture) - 架构基础 -- [Controller 层](/zh-CN/core/controller) - Controller 详细说明 diff --git a/.claude/skills/vitepress-tutorial/template.md b/.claude/skills/vitepress-tutorial/template.md deleted file mode 100644 index f29ab937..00000000 --- a/.claude/skills/vitepress-tutorial/template.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: {{TUTORIAL_TITLE}} -description: {{TUTORIAL_DESCRIPTION}} ---- - -# {{TUTORIAL_TITLE}} - -## 学习目标 - -{{LEARNING_OBJECTIVES}} - -## 前置条件 - -{{PREREQUISITES}} - -## 步骤 1:{{STEP_1_TITLE}} - -{{STEP_1_CONTENT}} - -## 步骤 2:{{STEP_2_TITLE}} - -{{STEP_2_CONTENT}} - -## 步骤 3:{{STEP_3_TITLE}} - -{{STEP_3_CONTENT}} - -## 完整代码 - -{{FULL_CODE}} - -## 运行结果 - -{{EXPECTED_OUTPUT}} - -## 下一步 - -{{NEXT_STEPS}} - -## 相关文档 - -{{RELATED_DOCS}} diff --git a/.claude/skills/vitepress-validate/SKILL.md b/.claude/skills/vitepress-validate/SKILL.md deleted file mode 100644 index 2596c39a..00000000 --- a/.claude/skills/vitepress-validate/SKILL.md +++ /dev/null @@ -1,297 +0,0 @@ -# VitePress 文档验证 - -验证 VitePress 文档的质量和规范性,确保文档符合项目标准。 - -## 用途 - -此 skill 用于验证 Markdown 文档的格式和内容,包括: -- Frontmatter 格式正确性 -- 内部链接有效性 -- 代码块语法标记 -- 标题层级结构 -- 中文标点符号规范 -- 泛型符号转义 - -## 调用方式 - -```bash -# 验证单个文件 -/vitepress-validate <文件路径> - -# 验证整个目录 -/vitepress-validate <目录路径> - -# 验证所有文档 -/vitepress-validate docs/zh-CN/ -``` - -**示例**: -```bash -/vitepress-validate docs/zh-CN/api-reference/core/architecture.md -/vitepress-validate docs/zh-CN/core/ -``` - -## 验证项 - -### 1. Frontmatter 验证 - -**检查项**: -- YAML 语法正确性 -- 必需字段存在(`title`、`description`) -- 字段值类型正确 -- `outline` 字段值有效(`deep`、`[2,3]` 等) - -**示例**: -```yaml ---- -title: Architecture # 必需 -description: 架构基类说明 # 必需 -outline: deep # 可选,但值必须有效 ---- -``` - -### 2. 内部链接验证 - -**检查项**: -- 相对路径链接指向的文件存在 -- 绝对路径链接格式正确 -- 锚点链接对应的标题存在 -- 没有损坏的链接 - -**有效链接格式**: -- `[文本](./file.md)` - 相对路径 -- `[文本](/zh-CN/core/architecture)` - 绝对路径 -- `[文本](#标题)` - 锚点链接 -- `[文本](./file.md#标题)` - 组合链接 - -### 3. 代码块验证 - -**检查项**: -- 代码块有语法标记(```csharp、```bash 等) -- C# 代码块使用 `csharp` 标记(不是 `cs` 或 `c#`) -- 代码块正确闭合 -- 没有未闭合的反引号 - -**正确格式**: -```markdown -\`\`\`csharp -public class Example { } -\`\`\` -``` - -**错误格式**: -```markdown -\`\`\`cs // 应该使用 csharp -public class Example { } -\`\`\` -``` - -### 4. 标题层级验证 - -**检查项**: -- 标题层级不跳级(不能从 `#` 直接跳到 `###`) -- 每个文档只有一个一级标题(`#`) -- 标题层级递增合理 - -**正确示例**: -```markdown -# 一级标题 -## 二级标题 -### 三级标题 -## 另一个二级标题 -``` - -**错误示例**: -```markdown -# 一级标题 -### 三级标题 ❌ 跳过了二级标题 -``` - -### 5. 中文标点符号验证 - -**检查项**: -- 中文句子使用全角标点(,。!?) -- 英文句子使用半角标点(,.!?) -- 代码和技术术语周围使用半角符号 -- 括号使用规范 - -**规范示例**: -- "这是一个示例。" ✓(中文全角句号) -- "This is an example." ✓(英文半角句号) -- "`Architecture` 类提供了..." ✓(代码周围半角) - -### 6. 泛型符号验证 - -**检查项**: -- 泛型符号正确转义(`` → `<T>`) -- 仅在代码块外转义 -- 代码块内保持原样 - -**正确示例**: -```markdown -`List<T>` 是一个泛型类。 - -\`\`\`csharp -List items = new List(); // 代码块内不转义 -\`\`\` -``` - -## 验证脚本 - -### validate-frontmatter.sh - -验证 Frontmatter 格式。 - -**用法**: -```bash -.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh <文件路径> -``` - -### validate-links.sh - -验证内部链接有效性。 - -**用法**: -```bash -.claude/skills/vitepress-validate/scripts/validate-links.sh <文件路径> -``` - -### validate-code-blocks.sh - -验证代码块语法。 - -**用法**: -```bash -.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh <文件路径> -``` - -### validate-all.sh - -执行所有验证。 - -**用法**: -```bash -.claude/skills/vitepress-validate/scripts/validate-all.sh <文件或目录路径> -``` - -## 输出格式 - -### 验证通过 - -``` -✓ docs/zh-CN/core/architecture.md - - Frontmatter: 通过 - - 内部链接: 通过 - - 代码块: 通过 - - 标题层级: 通过 - - 标点符号: 通过 - - 泛型符号: 通过 -``` - -### 验证失败 - -``` -✗ docs/zh-CN/core/architecture.md - - Frontmatter: 失败 - × 缺少必需字段: description - - 内部链接: 失败 - × 损坏的链接: ./missing-file.md (第 45 行) - - 代码块: 警告 - ⚠ 使用了 'cs' 标记,建议使用 'csharp' (第 78 行) - - 标题层级: 通过 - - 标点符号: 警告 - ⚠ 中文句子使用了半角句号 (第 102 行) - - 泛型符号: 失败 - × 未转义的泛型符号: List (第 120 行) -``` - -## 修复建议 - -验证失败时,skill 会提供具体的修复建议: - -**示例**: -``` -修复建议: -1. 在 Frontmatter 中添加 description 字段 -2. 修复或删除损坏的链接: ./missing-file.md -3. 将代码块标记从 'cs' 改为 'csharp' -4. 将第 102 行的半角句号改为全角句号 -5. 将第 120 行的 List 改为 List<T> -``` - -## 配置选项 - -### 严格模式 - -启用严格模式时,警告也会导致验证失败。 - -```bash -/vitepress-validate --strict docs/zh-CN/ -``` - -### 忽略特定检查 - -```bash -# 忽略标点符号检查 -/vitepress-validate --ignore-punctuation docs/zh-CN/ - -# 忽略多个检查 -/vitepress-validate --ignore-punctuation --ignore-generics docs/zh-CN/ -``` - -## 集成到工作流 - -### 生成后自动验证 - -```bash -# 1. 生成 API 文档 -/vitepress-api-doc GFramework.Core/architecture/Architecture.cs - -# 2. 自动验证生成的文档 -/vitepress-validate docs/zh-CN/api-reference/core/architecture.md -``` - -### 批量验证 - -```bash -# 验证所有 API 文档 -/vitepress-validate docs/zh-CN/api-reference/ - -# 验证所有文档 -/vitepress-validate docs/zh-CN/ -``` - -## 退出代码 - -- `0` - 所有验证通过 -- `1` - 存在错误 -- `2` - 仅存在警告(非严格模式下仍返回 0) - -## 相关 Skills - -- `/vitepress-api-doc` - 生成 API 文档后自动验证 -- `/vitepress-guide` - 生成指南文档后自动验证 -- `/vitepress-tutorial` - 生成教程文档后自动验证 - -## 最佳实践 - -1. **生成后立即验证**:每次生成文档后立即运行验证 -2. **定期批量验证**:定期验证所有文档,确保一致性 -3. **修复所有错误**:不要忽略验证错误,及时修复 -4. **关注警告**:警告虽不致命,但应该重视并修复 -5. **使用严格模式**:在 CI/CD 中使用严格模式确保质量 - -## 故障排除 - -### 问题:误报泛型符号错误 -**解决方案**:确保泛型符号在代码块外正确转义,代码块内保持原样 - -### 问题:中文标点符号检查过于严格 -**解决方案**:使用 `--ignore-punctuation` 选项,或手动调整规则 - -### 问题:链接验证失败但文件确实存在 -**解决方案**:检查文件路径大小写,确保路径完全匹配 - -## 版本历史 - -- v1.0.0 - 初始版本,支持 6 项基本验证 diff --git a/.claude/skills/vitepress-validate/scripts/validate-all.sh b/.claude/skills/vitepress-validate/scripts/validate-all.sh deleted file mode 100644 index da97e247..00000000 --- a/.claude/skills/vitepress-validate/scripts/validate-all.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/bash -# 执行所有验证 -# 用法: validate-all.sh <文件或目录路径> - -set -e - -TARGET="$1" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -if [ -z "$TARGET" ]; then - echo "用法: $0 <文件或目录路径>" - exit 1 -fi - -if [ ! -e "$TARGET" ]; then - echo "错误: 路径不存在: $TARGET" - exit 1 -fi - -echo "==========================================" -echo "VitePress 文档验证" -echo "==========================================" -echo "" - -# 收集所有 Markdown 文件 -if [ -f "$TARGET" ]; then - FILES=("$TARGET") -elif [ -d "$TARGET" ]; then - mapfile -t FILES < <(find "$TARGET" -name "*.md" -type f) -else - echo "错误: 无效的路径: $TARGET" - exit 1 -fi - -if [ ${#FILES[@]} -eq 0 ]; then - echo "未找到 Markdown 文件" - exit 0 -fi - -echo "找到 ${#FILES[@]} 个文件" -echo "" - -TOTAL_ERRORS=0 -TOTAL_WARNINGS=0 -PASSED_FILES=0 -FAILED_FILES=0 - -for FILE in "${FILES[@]}"; do - echo "验证: $FILE" - echo "----------------------------------------" - - FILE_ERRORS=0 - FILE_WARNINGS=0 - - # 1. Frontmatter 验证 - if bash "$SCRIPT_DIR/validate-frontmatter.sh" "$FILE" 2>&1 | grep -q "✗"; then - FILE_ERRORS=$((FILE_ERRORS + 1)) - fi - - # 2. 链接验证 - if bash "$SCRIPT_DIR/validate-links.sh" "$FILE" 2>&1 | grep -q "✗"; then - FILE_ERRORS=$((FILE_ERRORS + 1)) - fi - - # 3. 代码块验证 - OUTPUT=$(bash "$SCRIPT_DIR/validate-code-blocks.sh" "$FILE" 2>&1 || true) - if echo "$OUTPUT" | grep -q "✗"; then - FILE_ERRORS=$((FILE_ERRORS + 1)) - fi - if echo "$OUTPUT" | grep -q "⚠"; then - FILE_WARNINGS=$((FILE_WARNINGS + 1)) - fi - - # 统计结果 - if [ $FILE_ERRORS -eq 0 ]; then - echo "✓ 验证通过" - PASSED_FILES=$((PASSED_FILES + 1)) - else - echo "✗ 验证失败($FILE_ERRORS 个错误)" - FAILED_FILES=$((FAILED_FILES + 1)) - fi - - if [ $FILE_WARNINGS -gt 0 ]; then - echo "⚠ $FILE_WARNINGS 个警告" - fi - - TOTAL_ERRORS=$((TOTAL_ERRORS + FILE_ERRORS)) - TOTAL_WARNINGS=$((TOTAL_WARNINGS + FILE_WARNINGS)) - - echo "" -done - -echo "==========================================" -echo "验证摘要" -echo "==========================================" -echo "总文件数: ${#FILES[@]}" -echo "通过: $PASSED_FILES" -echo "失败: $FAILED_FILES" -echo "总错误数: $TOTAL_ERRORS" -echo "总警告数: $TOTAL_WARNINGS" -echo "" - -if [ $TOTAL_ERRORS -eq 0 ]; then - echo "✓ 所有验证通过" - exit 0 -else - echo "✗ 验证失败" - exit 1 -fi diff --git a/.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh b/.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh deleted file mode 100644 index 938753ca..00000000 --- a/.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -# 验证代码块语法 -# 用法: validate-code-blocks.sh <文件路径> - -set -e - -FILE="$1" - -if [ -z "$FILE" ]; then - echo "用法: $0 <文件路径>" - exit 1 -fi - -if [ ! -f "$FILE" ]; then - echo "错误: 文件不存在: $FILE" - exit 1 -fi - -echo "验证代码块语法: $FILE" - -ERROR_COUNT=0 -WARNING_COUNT=0 - -# 检查未闭合的代码块 -OPEN_COUNT=$(grep -c '^```' "$FILE" || true) -if [ $((OPEN_COUNT % 2)) -ne 0 ]; then - echo "✗ 错误: 存在未闭合的代码块" - ERROR_COUNT=$((ERROR_COUNT + 1)) -fi - -# 检查 C# 代码块标记 -LINE_NUM=0 -while IFS= read -r LINE; do - LINE_NUM=$((LINE_NUM + 1)) - - # 检查是否使用了错误的 C# 标记 - if echo "$LINE" | grep -qE '^```(cs|c#|C#)$'; then - echo "⚠ 警告: 第 $LINE_NUM 行使用了非标准标记,建议使用 'csharp'" - echo " 当前: $LINE" - WARNING_COUNT=$((WARNING_COUNT + 1)) - fi - - # 检查代码块是否有语言标记 - if echo "$LINE" | grep -qE '^```$'; then - # 检查下一行是否是代码(简单启发式:不是空行且不是 ```) - NEXT_LINE=$(sed -n "$((LINE_NUM + 1))p" "$FILE") - if [ -n "$NEXT_LINE" ] && ! echo "$NEXT_LINE" | grep -qE '^```'; then - echo "⚠ 警告: 第 $LINE_NUM 行的代码块缺少语言标记" - WARNING_COUNT=$((WARNING_COUNT + 1)) - fi - fi -done < "$FILE" - -# 输出结果 -if [ $ERROR_COUNT -eq 0 ] && [ $WARNING_COUNT -eq 0 ]; then - echo "✓ 代码块验证通过" - exit 0 -elif [ $ERROR_COUNT -eq 0 ]; then - echo "⚠ 代码块验证通过(有 $WARNING_COUNT 个警告)" - exit 0 -else - echo "✗ 代码块验证失败($ERROR_COUNT 个错误,$WARNING_COUNT 个警告)" - exit 1 -fi diff --git a/.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh b/.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh deleted file mode 100644 index 96694515..00000000 --- a/.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# 验证 Frontmatter 格式 -# 用法: validate-frontmatter.sh <文件路径> - -set -e - -FILE="$1" - -if [ -z "$FILE" ]; then - echo "用法: $0 <文件路径>" - exit 1 -fi - -if [ ! -f "$FILE" ]; then - echo "错误: 文件不存在: $FILE" - exit 1 -fi - -echo "验证 Frontmatter: $FILE" - -# 检查是否有 Frontmatter(限制在前几行,避免匹配正文中的 '---') -if ! head -n 5 "$FILE" | grep -q "^---$"; then - echo "✗ 错误: 文件缺少 Frontmatter" - exit 1 -fi - -# 提取 Frontmatter 内容(第一个 --- 到第二个 --- 之间) -FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$FILE" | sed '1d;$d') - -if [ -z "$FRONTMATTER" ]; then - echo "✗ 错误: Frontmatter 为空" - exit 1 -fi - -# 检查必需字段: title -if ! echo "$FRONTMATTER" | grep -q "^title:"; then - echo "✗ 错误: 缺少必需字段: title" - exit 1 -fi - -# 检查必需字段: description -if ! echo "$FRONTMATTER" | grep -q "^description:"; then - echo "✗ 错误: 缺少必需字段: description" - exit 1 -fi - -# 检查 outline 字段值(如果存在) -if echo "$FRONTMATTER" | grep -q "^outline:"; then - OUTLINE_VALUE=$(echo "$FRONTMATTER" | grep "^outline:" | sed 's/outline:\s*//') - if [ "$OUTLINE_VALUE" != "deep" ] && [ "$OUTLINE_VALUE" != "false" ] && ! echo "$OUTLINE_VALUE" | grep -qE '^\[.*\]$'; then - echo "⚠ 警告: outline 字段值可能无效: $OUTLINE_VALUE" - echo " 有效值: deep, false, [2,3]" - fi -fi - -echo "✓ Frontmatter 验证通过" -exit 0 diff --git a/ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md b/ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md index eaeba424..3c8c600f 100644 --- a/ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md +++ b/ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md @@ -7,21 +7,19 @@ ## 当前恢复点 -- 恢复点编号:`DOCUMENTATION-GOVERNANCE-REFRESH-RP-007` +- 恢复点编号:`DOCUMENTATION-GOVERNANCE-REFRESH-RP-008` - 当前阶段:`Phase 3` - 当前焦点: - - 已完成 `docs/zh-CN/core/events.md`、`property.md` 与 `logging.md` 的专题页重写 - - 已按源码与测试复核 `docs/zh-CN/core/state-management.md`、`coroutine.md`,当前内容与实现基本一致,无需再做 - 机械改写 - - 已完成 `docs/zh-CN/game/scene.md` 与 `ui.md` 的专题页重写,当前内容已回到“项目自接 factory/root + router 基类”的真实边界 - - 已完成 `docs/zh-CN/source-generators/context-aware-generator.md` 与 `priority-generator.md` 的专题页重写,当前内容已回到“真实生成成员、推荐 API 与兼容边界”的结构 - - 下一轮需要把重心转到 Godot 相关生成器页面核对 + - 已建立统一公开 skill:`.agents/skills/gframework-doc-refresh/` + - 文档重构入口已从“按 guide/tutorial/api 类型拆 skill”收口为“按源码模块驱动文档刷新” + - 旧 `vitepress-*` skill 的模板、规范与校验逻辑已迁入新 skill 或 `_shared/` + - 下一轮需要用统一 skill 推进 Godot 相关生成器页面核对 ## 当前状态摘要 - 文档治理规则已收口到仓库规范,README、站点入口与采用链路不再依赖旧文档自证 - 高优先级模块入口与 `core` 关键专题页已回到可作为默认导航入口的状态,本轮计划中的 `core` 剩余高风险页面已完成收口 -- 当前主题仍是 active topic,因为 `source-generators` 栏目下的 Godot 相关页面仍可能包含与实现漂移的旧内容 +- 当前主题仍是 active topic,因为 `source-generators` 栏目下的 Godot 相关页面仍可能包含与实现漂移的旧内容,且统一 skill 还需要在该场景上继续落地使用 ## 当前活跃事实 @@ -51,6 +49,11 @@ - `docs/zh-CN/source-generators/priority-generator.md` 已改成“生成 `IPrioritized`、priority-aware 检索 API、动态优先级边界与诊断”的结构, 不再把 `GetAllByPriority()` / `system.Init()` 当作所有场景的默认示例 - 本轮重写后再次执行 `cd docs && bun run build` 通过,当前 `source-generators` 栏目改动没有破坏站点构建 +- `.agents/skills/gframework-doc-refresh/SKILL.md` 已改成标准 YAML frontmatter skill,并明确支持模块输入、证据顺序、输出优先级与验证步骤 +- `.agents/skills/_shared/module-map.json` 已收口为源码模块映射表,覆盖源码目录、测试项目、README、`docs/zh-CN` 栏目与 `ai-libs/` 参考入口 +- 旧 `vitepress-api-doc`、`vitepress-batch-api`、`vitepress-doc-generator`、`vitepress-guide`、`vitepress-tutorial`、`vitepress-validate` + 已不再保留为可用公开 skill 定义文件 +- `ai-libs/` 已纳入统一 skill 的标准证据链,只作为消费者接入参考,不再替代源码与测试契约 ## 当前风险 @@ -59,6 +62,14 @@ 继续按源码、测试、`*.csproj` 与 `ai-libs/` 下已验证参考实现核对剩余 Godot 相关页面,不把旧文档当事实来源 - 采用路径误导风险:根聚合包与模块边界若再次被写错,会继续误导消费者的包选择 - 缓解措施:保持“源码与包关系优先”的证据顺序,改动采用说明时同步核对包依赖与生成器 wiring +- 模块映射不全风险:统一 skill 若遗漏模块别名、测试项目或 docs 栏目映射,会让后续扫描阶段直接失焦 + - 缓解措施:以当前 `*.csproj` 族为 canonical module list,统一维护 `.agents/skills/_shared/module-map.json` +- `ai-libs/` 漂移风险:参考项目若滞后于当前实现,可能把过时 wiring 重新带回文档 + - 缓解措施:在 skill 中固定“源码/测试优先,`ai-libs/` 只补 adoption path”的证据顺序 +- 旧模板迁移失真风险:旧 `vitepress-*` skill 的模板和规范若原样沿用,可能继续输出过时结构 + - 缓解措施:只迁移可复用骨架,把输出优先级和证据规则重写进统一 skill +- 统一入口过宽风险:若 `gframework-doc-refresh` 的触发描述过宽,可能在模块不明确时误进入文档生成 + - 缓解措施:要求先做模块归一化;遇到栏目别名歧义时只返回建议,不直接生成文档 - Active 入口回膨胀风险:后续若把栏目级重写过程直接追加到 active 文档,会再次拖慢恢复 - 缓解措施:阶段完成并验证后,继续把细节迁入本 topic 的 `archive/` - review 跟进遗漏风险:如果 PR review 抓取继续优先选中空 review body,会漏掉 CodeRabbit 的 Nitpick 和 @@ -76,10 +87,13 @@ - active 跟踪文件已按 `ai-plan` 治理规则精简为当前恢复入口 - `cd docs && bun run build` - `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json` +- `python3 .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py Core` +- `python3 .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py Godot.SourceGenerators` +- `python3 .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py Cqrs` ## 下一步 1. 继续核对 Godot 相关生成器页面,优先处理 `godot-project-generator.md`、`get-node-generator.md` 与 - `bind-node-signal-generator.md` + `bind-node-signal-generator.md`,优先用 `gframework-doc-refresh` 的模块扫描结果驱动判断 2. 重点确认 `project.godot`、`AutoLoad` / `InputActions`、`GetNode` / `BindNodeSignal` 示例仍与当前包关系和生成器入口一致 3. 若 active trace 再积累新的已完成阶段,按恢复点粒度迁入 `archive/traces/`,避免默认启动入口再次膨胀 diff --git a/ai-plan/public/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md b/ai-plan/public/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md index 1fb0d47d..2efbb4ec 100644 --- a/ai-plan/public/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md +++ b/ai-plan/public/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md @@ -181,3 +181,57 @@ `bind-node-signal-generator.md` 2. 重点确认 `project.godot`、`AutoLoad` / `InputActions`、`GetNode` / `BindNodeSignal` 示例仍与当前包关系和生成器入口一致 3. 若 Godot 页面也出现连续收口结果,再按恢复点粒度整理 active trace,避免默认入口继续膨胀 + +## 2026-04-22 + +### 阶段:统一文档编排 skill 收口(RP-008) + +- 依据当前主题“文档治理 + 持续刷新”的目标,复核 `.agents/skills/` 后确认:现有 `vitepress-api-doc`、 + `vitepress-batch-api`、`vitepress-doc-generator`、`vitepress-guide`、`vitepress-tutorial` 与 + `vitepress-validate` 仍保留旧的并列入口模型,其中多数 `SKILL.md` 没有标准 YAML frontmatter,已经不适合作为当前 + Codex skill 继续公开暴露 +- 结合当前 `*.csproj`、`docs/zh-CN` 栏目、模块 README 与 `ai-libs/CoreGrid` 参考入口,建立 + `.agents/skills/_shared/module-map.json`,把文档刷新主输入固定为真实源码模块,而不是 `guide/tutorial/api` + 之类的文档类型 +- 重写 `.agents/skills/_shared/DOCUMENTATION_STANDARDS.md`,去掉已经失真的固定页面清单,明确固定证据顺序: + 1. 源码 / XML docs / `*.csproj` + 2. 测试与 snapshot + 3. README + 4. 当前 `docs/zh-CN` + 5. `ai-libs/` + 6. 归档文档 +- 新增 `.agents/skills/gframework-doc-refresh/`,补齐: + - 标准 frontmatter 的 `SKILL.md` + - `agents/openai.yaml` + - `references/` 下的模块选择、证据顺序与输出策略说明 + - `templates/` 下的 landing/topic/API/tutorial 骨架 + - `scripts/scan_module_evidence.py` + - 迁移后的文档校验脚本 `validate-*.sh` +- `scan_module_evidence.py` 已支持: + - 模块名与别名归一化 + - docs 栏目别名歧义检测 + - 输出源码、测试、README、docs、`ai-libs/` 的存在性扫描结果 + - 对 landing/topic/fallback 状态做基础判断,作为后续页面收口入口 +- `.agents/skills/README.md` 已改成“统一公开入口 + 共享资源”说明,不再把旧 `vitepress-*` skill 当成推荐工作流 +- 旧 `vitepress-*` skill 文件已删除;目录本身在当前 Windows-backed worktree 上因只读元数据仍可能残留为空目录,但由于 + `SKILL.md` 已删除,它们不再构成可发现的 skill 入口 + +### 验证(RP-008) + +- `python3 -B .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py Core` +- `python3 -B .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py Godot.SourceGenerators` +- `python3 -B .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py Cqrs` +- `python3 -B .agents/skills/gframework-doc-refresh/scripts/scan_module_evidence.py source-generators --json` + +### 当前结论(RP-008) + +- 当前文档刷新入口已经从“按文档类型拆 skill”转为“按源码模块驱动文档评估与更新” +- `ai-libs/` 已正式纳入标准证据链,但仅用于 adoption path 和真实 wiring 参考,不覆盖源码契约 +- 旧 skill 中仍有价值的模板与校验逻辑已经迁入统一入口或 `_shared/`,后续不需要再维护多套并列说明 + +### 下一步(RP-008) + +1. 使用 `gframework-doc-refresh` 对 `Godot.SourceGenerators` 做一次真实模块扫描,并据此继续刷新 + `godot-project-generator.md`、`get-node-generator.md` 与 `bind-node-signal-generator.md` +2. 若发现 `module-map.json` 在 Godot 场景下仍缺少别名或 docs 映射,再回补共享映射,而不是在单页文档里硬编码 +3. 若后续 skill 收口过程继续积累细节,再把迁移细节归档到本 topic 的 `archive/`,保持 active trace 可快速恢复