cursor Init 完善多人协同changelog,以及godot相关基础skill和代码规范

This commit is contained in:
Nostars Developer
2026-07-15 14:38:08 +08:00
parent fc8557f2a9
commit 6446261c69
56 changed files with 3523 additions and 1584 deletions

View File

@@ -1,830 +1,199 @@
---
name: cursor-init
description: >-
初始化项目的 .cursor 结构。两种触发方式:
1首次自动触发 —— 当 `.cursor/.init-done` sentinel 不存在时,`cursor-init-recall.mdc`
会在会话首次响应前引导 Agent 主动执行本 Skill
2关键词手动触发 —— "初始化cursor"、"cursor init"、"重置 cursor"、"补 gitignore" 等
流程:识别并迁移目标项目原有的 rules/skills清理模板残留的项目专用数据
changelog/deferred/pitfalls/profile/distillery/local-env/项目级 rules 与 skills
可选生成 .gitignore 模板,最后写入 `.cursor/.init-done` 标记完成。
已 init 仓库不会再自动触发,除非用户主动通过关键词请求。
初始化或重置项目的 .cursor 基础设施:保留 canonical Rules、Skills、Hooks 与
Godot baseline清除模板历史数据采集本机环境生成 .gitignore并在验证成功后
写入 .init-done。首次缺少 sentinel 时自动使用;也用于“初始化 cursor”、
重置 cursor”、“补 gitignore”等请求
---
# Cursor Init Skill
# Cursor Init
从其它项目复制过来(或通过 git clone 模板仓库获得)的 `.cursor/` 目录重置为当前新项目的干净起点
模板仓库或复制来的 `.cursor/` 变成可安全使用、可重复执行的 Godot 项目基线
## 使用场景
详细白名单、清理模式、状态模板、sentinel 和 `.gitignore` 片段统一见
[reference.md](reference.md)。执行全流程或仅补 `.gitignore` 前都必须直接读取该文件,
不得凭记忆重建清单。
### 场景 A克隆模板仓库后的首次会话
```
1. 用户把本模板作为 git 仓库发布
2. 其他人 `git clone <模板仓库>` 得到新项目骨架
3. 用户打开 Cursor在该仓库发出任意第一条消息
4. `cursor-init-recall.mdc`alwaysApply检测 .cursor/.init-done 不存在
→ 引导 Agent 暂停用户原始请求,先执行本 Skill
5. Agent 按阶段 0 → 7 跑完,写入 .init-done
6. 后续会话 sentinel 已存在,不再自动触发
```
## 入口
### 场景 B从已有项目直接复制 .cursor 目录
### 首次自动初始化
```
1. 用户在 "源项目 A" 中使用本 .cursor 模板开发
2. 用户开 "新项目 B",把 A 的 .cursor/ 整体拷贝到 B
3. B 原先可能也有自己零散的 rules/SKILL 文件(未必标准)
4. 用户在 B 中说"初始化cursor"(或首次会话被 recall 触发)
5. 本 Skill 把 B 原有的 rules/skills 按 baserule 归位,清空 A 遗留的项目数据,
重建 registry生成 .gitignore写入 sentinel
```
每次会话首次响应前由 `.cursor/rules/common/cursor-init-recall.mdc` 检查
`.cursor/.init-done`。若 sentinel 不存在:
### 场景 C只补 .gitignore
1. 暂存用户原请求,说明需要先初始化。
2. 获得用户同意后执行本 Skill 的阶段 07。
3. 仅在阶段 6 全部通过后写 sentinel。
4. 初始化成功后继续原请求。
```
init 后用户说"补一下 gitignore"或"生成 gitignore" → 只跑阶段 5.5
```
## 触发条件
本 Skill 由 `cursor-init-recall.mdc` 触发,两类入口:
若用户暂时拒绝,尊重选择;不要写 sentinel下次会话仍会提醒。
### A. 全流程(阶段 0 → 7
- `.cursor/.init-done` 不存在 → 会话首次响应前由 recall 规则自动引导
- 用户关键词:`初始化cursor` / `cursor init` / `重置 cursor` / `reset cursor`
- 口头描述"把复制过来的 .cursor 清理一下"、"按 baserule 归位一下"
### 手动全流程
### B. 仅补 .gitignore只跑阶段 5.5
触发词包括:`初始化 cursor``cursor init``重置 cursor``reset cursor`
“清理复制来的 .cursor”、“按基线归位”。
- 用户关键词:`补 gitignore` / `生成 gitignore` / `gitignore 模板`
- 跳过阶段 1-5 和阶段 7 的除"更新 gitignore_generated 字段"外的其他操作
sentinel 已存在时必须先展示其元数据并再次确认;不得把手动触发当作无提示重置。
## 执行原则(不可协商)
1. **稳定准确 > token 成本**:每一步可以多读、多确认、让用户点头,不要图快
2. **破坏性操作必须 dry-run**:删除、重置必须先列清单给用户确认
3. **不可逆操作前提醒 git**:开始前先提示用户确认工作区已 commit/stash
4. **模糊就问**:分类不清的文件一律问用户,不要猜
5. **幂等**:反复运行应当无害(第二次在已干净状态下不会做破坏)
6. **中断可恢复**:任何阶段异常 abort **不写入** `.init-done`,下次会话仍会被 recall 触发从头继续
### 仅补 `.gitignore`
## 核心流程
触发词包括:`补 gitignore``生成 .gitignore``gitignore 模板`
只执行阶段 5不得改动 `.cursor/` 的其他内容。若 sentinel 存在,只更新
`gitignore_generated`;若不存在,询问是否改跑完整初始化,不得只为补
`.gitignore` 创建 sentinel。
### 阶段 0前置确认 + 幂等判断
## 不可协商的安全契约
```
1. 检查当前工作目录下存在 .cursor/
- 不存在 → 直接结束,提示用户先复制模板
2. 读取 .cursor/.init-done
- 不存在 → 继续,按"首次 init"路径执行
- 已存在 → 展示其元数据initialized_at、project_type 等),提示:
"检测到本仓库已于 {initialized_at} 完成初始化project_type: {type})。
继续执行会清空 deferred / pitfalls / distillery 等数据文件。确认要继续吗?"
等用户明确回复"继续"再往下
3. 运行 `git status`
- 不是 git 仓库 → 警告但不阻塞,建议手动备份
- 有未提交改动 → 提醒"建议先 commit 或 stash便于回滚",等用户明确回复"继续"
4. 向用户声明本次操作范围(见"分组规则"),请求口头确认启动
```
1. **先 dry-run后确认才写入**:删除、重置、移动、覆盖、追加都进入同一份预览清单。
2. **canonical 永不删除**:尤其不得清空 `.cursor/rules/project/`;六个 Godot baseline
project rules 必须保留。
3. **精确白名单**`.cursor/skills/` 最终只能有 reference 中列出的 8 个目录。
4. **不触碰来源树**:只处理目标项目;不得删除或修改 `source/`
5. **幂等**:同一输入重复执行,第二次应只产生空或等价 dry-run。
6. **失败不写 sentinel**:取消、异常、验证失败或未决冲突都不得创建/更新
`.cursor/.init-done`
7. **运行态不冒充 canonical**`.cursor/local-env.json``.cursor/changelog/.changelog-ack`
`.cursor/changelog/.session-start` 都是 gitignored 本机文件,不是 tracked 白名单项。
8. **文本规范**:新写文本使用 UTF-8 无 BOM、LF。
### 阶段 1递归扫描 `.cursor/`
## 阶段 0前置检查
```
1. 用 shell 列出 .cursor 下所有文件(含子目录)
2. 把每个文件对照"规范清单"和"清理清单"分成三组:
- A 组canonical在规范清单中原样保留
- B 组template-data在清理清单中需要删除或重置
- C 组foreign两张清单都没覆盖到的视作目标项目原有文件或未知项
3. 把分组结果用表格汇报给用户:
| 组 | 路径 | 处理动作 |
```
1. 确认项目根存在 `.cursor/`;不存在则停止并说明缺失。
2. 读取 `.cursor/.init-done`
- 不存在:进入首次初始化。
- 存在:展示 `initialized_at``project_type``skill_version`,等待用户明确继续。
3. 执行 `git status`。有未提交改动时建议先 commit/stash并等待明确继续非 Git
仓库则建议备份,但可继续。
4. 读取 [reference.md](reference.md),声明本轮会保留、删除、重置、生成的范围。
5. 未获得明确确认前不得进入写入阶段。
### 阶段 2处理 C 组(目标项目原有文件归位)
## 阶段 1一次性采集本机配置
对 C 组中的每个文件,按 baserule.mdc 的归属约定分类,逐条询问用户(可一次性列清单批量确认)
在**一轮提问**中采集
| 文件特征 | 建议归属 | 目标路径 |
|----------|----------|----------|
| `.mdc` 且内容是跨项目通用规则 | 通用 Rule | `.cursor/rules/common/<name>.mdc` |
| `.mdc` 且内容是当前新项目专属规则 | 项目 Rule | `.cursor/rules/project/<name>.mdc` |
| 包含 `SKILL.md` 的目录 | Skill无论通用/项目专属) | `.cursor/skills/<skill-name>/` |
| 看不出归属 | 询问用户 | — |
| 明显是临时/垃圾文件(`*.log``*.tmp`、缓存等) | 删除(需用户确认) | — |
1. `changelog-author`:稳定、适合文件名的作者 handle。
2. `shell``powershell``bash``zsh`;可把当前探测值作为默认。
3. `godot4_path`Godot 4 executable 的绝对路径;允许留空。
执行要点:
同一轮可附带询问 `.gitignore` 的写入方式(新建 / 追加 / 替换 / 跳过)和自定义忽略项,
不要把三个环境字段拆成多轮追问。仅收集值,此阶段不写文件。
- **先列清单一次性确认**,然后批量执行移动/删除,避免交互过于频繁
- **重名冲突**C 组文件若与 A 组规范文件重名,**保留 A 组版本**,把 C 组备份到 `.cursor/_init-backup/` 下让用户自行 diff不直接覆盖
- **Skill 归属提示**:通用 Skill 建议用户之后手动同步到 `~/.cursor/skills/`(跨项目便利副本,可选)
- **迁移后核查**:移动完成后重新扫描,确认 C 组已清空
### 阶段 3处理 B 组(源项目项目专用数据清理/重置)
按"清理清单"执行:
**A. 直接删除**
- `.cursor/rules/project/*.mdc`(全部)—— 源项目的项目级 rules新项目不适用
- `.cursor/skills/<非规范 skill 目录>/` —— 源项目的项目级 Skills不在白名单的所有 skill 目录)
- `.cursor/plans/` 下所有文件(目录保留,内容清空)
- `.cursor/debug-*.log``.cursor/*.log` —— 调试日志
- `.cursor/local-env.json` —— 设备绑定,需新设备重新生成(`local-env-check.mdc` 自动探测)
**B. 重置为空模板**(保留文件,仅清内容)
| 文件 | 模板(见"模板内容"节) |
|------|------------------------|
| `.cursor/changelog/changelog-full.md` | L1 模板 |
| `.cursor/changelog/changelog-recent.md` | L2 模板 |
| `.cursor/changelog/changelog-headlines.md` | L3 模板 |
| `.cursor/changelog/.changelog-ack` | 空文件touch |
| `.cursor/deferred/registry.md` | deferred 模板 |
| `.cursor/pitfalls/pitfalls.md` | pitfalls 模板 |
| `.cursor/distillery/problems.md` | problems 模板 |
| `.cursor/distillery/insights.md` | insights 模板 |
| `.cursor/distillery/golden-rules.md` | golden-rules 模板 |
| `.cursor/profile/project-profile.md` | project-profile 模板 |
| `.cursor/profile/project-profile-log.md` | project-profile-log 模板 |
执行要点:
- 每个重置前**先 Read 现有内容预览前 10 行**给用户,避免误删有价值数据(特别是 deferred/pitfalls 用户可能想保留)
- 如用户对某个数据文件明确说"保留"(例如 golden-rules 想带过去),跳过该文件的重置
### 阶段 4重建 registry
打开 `.cursor/skills/epee-orchestrator/registry.md`
1. 解析现有条目(每条 `### <skill-name>` 块)
2. 删除所有 `类型: 项目级` 的条目
3. 遍历 `.cursor/skills/` 目录,对照 registry
- registry 有条目但 skill 目录不存在 → 删除条目
- skill 目录存在但 registry 无条目 → 读取该 skill 的 SKILL.md frontmatter新增条目
4. **确保 `cursor-init` 条目本身存在**(类型: 基础设施)
5. 写回 registry.md
### 阶段 5同步 `hooks.json`(跨平台保守处理)
- 读取 `.cursor/hooks.json`
-`command` 字段硬编码为 `powershell ...`,且目标新项目声明/探测到的 shell 不是 powershell参考 `local-env-check.mdc`**提醒用户**需要按 `hooks/README.md` 手动改为 `bash .cursor/hooks/xxx.sh`
- 本阶段不自动改 hooks.json避免误判
### 阶段 5.5`.gitignore` 交互式生成
#### 5.5.1 前置检测
```
检测项目根 .gitignore
不存在 → 进入 5.5.2 问卷
已存在且非空 → Read 前 30 行展示给用户,询问:
[覆盖 / 追加到文件末尾 / 跳过本阶段]
用户选"跳过" → 本阶段结束,.init-done 里标记 gitignore_generated: false
```
#### 5.5.2 问卷(一次性批量 AskQuestion 收集)
必问 3 项 + 可选 1 项:
| 编号 | 问题 | 类型 | 选项 |
|------|------|------|------|
| Q1 | 项目主要技术栈 | 多选 | Unity / Node.js / Python / Rust / Go / C# 非 Unity / Web 静态站点 / 其他 / **不确定(跳过语言段)** |
| Q2 | IDE 偏好 | 多选 | Cursor预勾/ VSCode / JetBrains 全家桶 / Visual Studio / Vim+Emacs |
| Q3 | 操作系统 | 多选 | Windows / macOS / Linux按探测到的当前 OS 预勾) |
| Q4可选| 其他要忽略的路径 | 自由文本 | 用户可跳过 |
#### 5.5.3 片段组装
## 阶段 2扫描、分类与 dry-run
按问卷选择拼装,片段内容见下方"模板内容 · .gitignore 片段库"。拼装顺序固定
递归扫描 `.cursor/`,按 reference 分为
```
# === Cursor固定所有项目都包含 ===
# === OS ===
# === IDE ===
# === Language / Framework ===
# === Custom ===
```
若 Q1 选"不确定" → 跳过 Language 段,其他段正常拼装(极简版仍可用)。
#### 5.5.4 预览与确认
1. 把组装结果写到 `.cursor/_gitignore-preview`(临时文件)
2. 给用户完整展示(超过 60 行则折叠中段)
3. AskQuestion`[写入 .gitignore / 让我调整再确认 / 放弃本阶段]`
4. "写入"→ move 到项目根 `.gitignore`(已存在时按 5.5.1 的选择做覆盖或追加),删除预览文件
5. "调整"→ 根据用户描述修改后重复步骤 2-3
6. "放弃"→ 删除预览文件,`.init-done` 标记 `gitignore_generated: false`
- **A / canonical**:精确白名单,保留;缺失项记为阻塞错误。
- **B / cleanup**:历史 fragment、备份、缓存、设备配置、ack、临时文件和状态数据。
- **C / foreign**:不属于 A/B 的文件。
### 阶段 6验证与报告
处理 C 组:
```
1. 重新递归扫描 .cursor/,再次分组
2. 期望状态:
- A 组:全部保留,文件内容未被动过
- B 组:数据文件仅含模板内容;项目级 rules/skills/日志 已删除
- C 组:为空(或仅剩用户明确要求保留的文件)
- 项目根 .gitignore按用户选择存在或被放弃状态记到报告里
3. 给用户一份结构化报告,至少包含:
- 移动的文件from → to
- 删除的文件
- 重置的文件
- 新注册/移除的 registry 条目
- .gitignore 的处理结果(新建/追加/覆盖/放弃)
- 未处理的文件(如果有,逐条说明原因)
```
- 非白名单 Skill 必须从 `.cursor/skills/` 移除;如用户要保留,先迁出该目录再删原件。
- 非 baseline project rule 视为模板项目遗留;逐项预览,确认后删除或迁出。
- 通用 `.mdc` 可建议迁到 `.cursor/rules/common/`,但只有九个 common rule 属于本基线;
最终仍需用户明确决定。
- 重名冲突永远保留 canonical 版本;冲突副本只能在用户确认后临时放入
`.cursor/_init-backup/`,并须在阶段 6 前移出或删除。
### 阶段 7写入 `.init-done` sentinel
输出一份合并 dry-run至少列出
**仅在阶段 6 验证全部通过后执行**。任何前序阶段异常中断都不写入此文件,确保下次会话 recall 能再次触发。
- 保留及缺失的 canonical 项;
- 删除的文件/目录;
- 重置的状态文件;
- C 组迁移/删除动作;
- `local-env.json` 生成计划;
- registry 重写计划;
- `.gitignore` 新建/追加/替换计划。
```
1. 按"模板内容 · .init-done"格式,填充实际值写入 .cursor/.init-done
2. 向用户输出收尾提示:
> 初始化完成。建议现在执行:
> git add .cursor/ .gitignore
> git diff --cached -- .cursor/
> git commit -m "chore(cursor): initialize .cursor from template"
>
> ⚠️ .cursor/.init-done 必须 commit否则团队其他成员 clone 后会被再次触发 init。
```
等待用户对整份计划明确确认。分类不清就问,不得猜。
**仅跑阶段 5.5 时**(用户说"补 gitignore"
-`.init-done` 存在 → 更新其中的 `gitignore_generated: true` 字段,保留其他字段
-`.init-done` 不存在 → 提示用户"仓库尚未完整 init只补 gitignore 不会写 sentinel。是否改为跑完整 init"
## 阶段 3执行 cleanup
---
严格按已确认 dry-run 和 reference 的 cleanup 表执行:
## 规范清单canonical
1. 删除全部历史 changelog fragments只保留 `entries/.gitkeep`
2. 删除全部 backup、cache、编译缓存、ack、session marker、日志和 init 临时文件。
3. 删除旧 `.cursor/local-env.json`;后续从 example 重新生成。
4. 删除非白名单 Skill最终目录名必须恰好为 8 个。
5. 保留六个 Godot baseline project rules绝不执行“清空 rules/project”。
6. 重置 deferred、pitfalls、distillery、profile 状态文件。
7. 在 entries 为空后运行 `changelog_build.py`,确定性重建四个 changelog 视图。
下列文件构成本 `.cursor` 模板的"主干",初始化后必须都在、内容不被删改(数据文件除外):
某一步失败立即停止;不要继续“尽量完成”,也不要写 sentinel。
### 顶层
## 阶段 4重建本机配置与 Registry
- `.cursor/hooks.json`
- `.cursor/local-env.example.json`
- `.cursor/.init-done` —— **阶段 7 写入**;模板仓库自身不应包含此文件
### `local-env.json`
### Rules通用
1. 读取 `.cursor/local-env.example.json`
2. 深拷贝其 JSON 结构到 `.cursor/local-env.json`,保留 example 中不认识的键。
3. 用阶段 1 的值设置 `changelog-author``shell``godot4_path`
4. `godot4_path` 留空时写空字符串,不伪造路径。
5. 验证 JSON 可解析,且 `.gitignore` 忽略该文件。
- `.cursor/rules/common/baserule.mdc`
- `.cursor/rules/common/changelog-recall.mdc`
- `.cursor/rules/common/deferred-recall.mdc`
- `.cursor/rules/common/distillery-recall.mdc`
- `.cursor/rules/common/epee-orchestrator.mdc`
- `.cursor/rules/common/pitfall-recall.mdc`
- `.cursor/rules/common/profile-recall.mdc`
- `.cursor/rules/common/cursor-init-recall.mdc`
不要引用或等待额外的环境检查 Rule本阶段就是唯一初始化入口。
### Rules项目专属目录
### Skill Registry
- `.cursor/rules/project/`(保留**空目录**;源项目的 `.mdc` 内容一律删除)
`.cursor/skills/epee-orchestrator/registry.md` 校准为磁盘上的 8 个真实 Skill
### Skills规范 Skill 目录白名单)
`cursor-init``deferred-decisions``dev-changelog``epee-orchestrator`
`pitfall-journal``problem-distillery``profile-memory``html-doc`
- `.cursor/skills/cursor-init/`
- `.cursor/skills/deferred-decisions/`
- `.cursor/skills/dev-changelog/`
- `.cursor/skills/epee-orchestrator/`(含 `registry.md`,见阶段 4
- `.cursor/skills/pitfall-journal/`
- `.cursor/skills/problem-distillery/`
- `.cursor/skills/profile-memory/`
不得保留这 8 项之外的条目或任何磁盘上不存在的 Skill。
每条的路径、类型、能力、触发场景、输出必须与对应 `SKILL.md` 一致。
> **任何不在此白名单中的 skill 目录**,在阶段 3 中一律删除(视为源项目的项目级 Skill
## 阶段 5生成或补齐 `.gitignore`
### Hooks
使用 [reference.md](reference.md) 的片段,不得临时拼写:
- `.cursor/hooks/README.md`
- `.cursor/hooks/run-hook.ps1`
- `.cursor/hooks/session-init.ps1`
- `.cursor/hooks/session-init.sh`
- `.cursor/hooks/check-changelog.ps1`
- `.cursor/hooks/check-changelog.sh`
1. 固定加入 Cursor 运行态片段。
2. 固定加入 Godot 片段:忽略 `.godot/`,但提交 `*.uid` 和资源 `*.import` sidecar。
3. 按用户 shell/OS 与自定义项补充其他片段。
4. 已有 `.gitignore` 时按阶段 1 的新建/追加/替换/跳过选择处理。
5. 写入前展示最终预览;用户调整后重新预览。
6. 清除与 `*.uid``*.import` 提交要求冲突的旧忽略规则;不要忽略
`.cursor/.init-done`
### 数据占位目录(保留目录,文件重置为模板内容)
用户跳过时记录 `gitignore_generated: false`;这不等于流程失败,但报告中必须明确。
- `.cursor/changelog/{changelog-full.md, changelog-recent.md, changelog-headlines.md, .changelog-ack}`
- `.cursor/deferred/registry.md`
- `.cursor/pitfalls/pitfalls.md`
- `.cursor/distillery/{problems.md, insights.md, golden-rules.md}`
- `.cursor/profile/{project-profile.md, project-profile-log.md}`
- `.cursor/plans/`(空目录)
## 阶段 6验证
---
逐项验证,任何失败都回到修复或停止状态:
## 清理清单cleanup list
1. reference 中全部 canonical 文件存在。
2. 九个 common rules 和六个 Godot baseline project rules 全部存在。
3. `.cursor/skills/` 的一级目录集合与 8 项白名单**完全相等**。
4. 所有历史 fragments、backup、cache、旧 ack、session marker 和临时文件均不存在。
5. `entries/.gitkeep` 存在entries 下无其他文件。
6. 四个 changelog 视图与空 entries 经生成器重建的结果一致。
7. 状态文件等于 reference 模板。
8. `local-env.json` 可解析、字段与用户输入一致且被 Git 忽略。
9. registry 恰有 8 项,路径均存在,无三个排除项或旧项目名。
10. 所有 Skill frontmatter `name` 与目录一致description 同时说明 what + when。
11. Skill 内相对引用均存在;不存在环境检查 Rule 的悬空引用。
12. `.gitignore` 忽略 `.godot/``local-env.json`、ack、session marker同时不忽略 `*.uid`
资源 `*.import`
13. 本次写入的文本为 UTF-8 无 BOM、LF。
### 强制删除
报告移动、删除、重置、生成、跳过和未解决项。未解决项不为空时不得进入阶段 7。
| 路径 | 原因 |
|------|------|
| `.cursor/rules/project/*.mdc` | 源项目的项目级 Rules |
| `.cursor/skills/<非白名单>/` | 源项目的项目级 Skills |
| `.cursor/plans/*`(内容) | 源项目规划文档 |
| `.cursor/*.log``.cursor/debug-*.log` | 调试日志遗留 |
| `.cursor/local-env.json` | 设备绑定配置,需由新设备重新生成 |
| `.cursor/_init-backup/`(如果是上一轮残留) | 仅阶段 2 冲突备份用,运行前应不存在 |
| `.cursor/_gitignore-preview`(如果是上一轮残留) | 阶段 5.5 临时文件 |
## 阶段 7写 sentinel
### 重置为模板
仅在阶段 6 全部通过后,按 reference 模板写 `.cursor/.init-done`。写入后再次读取并验证
字段。`project_type` 固定为 `godot``gitignore_generated` 反映阶段 5 实际结果。
见"模板内容"节
最后提醒用户检查 `git status` 和 diff并提交 `.cursor/.init-done`;不要代替用户提交
---
## 验收结果
## 模板内容
完整初始化后:
重置数据文件时使用以下内容。带 `{{DATE}}` 的占位符替换为当天日期(`YYYY-MM-DD`)。
### changelog-full.md
```markdown
# Dev Changelog — Full
完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。
## 记录
```
### changelog-recent.md
```markdown
# Dev Changelog — Recent
最近 ~10 次改动的摘要记录,按时间倒序排列。
当 Agent 检测到当前任务与近期改动相关时自动读取。
```
### changelog-headlines.md
```markdown
# Dev Changelog — Headlines
最近 ~50 次改动的一句话概要,按时间倒序排列。每次会话自动注入上下文。
```
### .changelog-ack
空文件0 字节),只用于更新 mtime 阻止 hook 重复提醒。
### deferred/registry.md
```markdown
# Deferred Decisions Registry
## Active Items
(暂无延期方案)
---
## Completed / Cancelled Items
(暂无已完成或已废弃的方案)
```
### pitfalls/pitfalls.md
```markdown
# Pitfall Journal
开发过程中踩过的坑,按时间倒序排列。
Agent 进入 Debug mode 或遇到运行时错误时自动检索匹配。
---
```
### distillery/problems.md
```markdown
# Problem Distillery — Problems
反复出现的顽固问题追踪记录,按时间倒序排列。
<!-- 新条目追加在此行下方 -->
```
### distillery/insights.md
```markdown
# Problem Distillery — Insights
从已解决的顽固问题中蒸馏出的精炼方法论。
<!-- 新条目追加在此行下方 -->
---
last_distill_date: {{DATE}}
```
### distillery/golden-rules.md
```markdown
# Golden Rules
经过实践验证(权重 >= 5的精炼认知每次新会话自动注入。
<!-- 当条目达到权重阈值后由 Agent 自动写入 -->
```
### profile/project-profile.md
```markdown
# Project Profile
## 项目定位
## 技术栈与架构
## 设计约定
## 产品方向
```
### profile/project-profile-log.md
```markdown
# Project Profile Log
详细记录每次项目画像更新的完整上下文,按时间正序追加。
## 记录
```
### .init-done
阶段 7 写入的 sentinelYAML 格式,字段固定:
```yaml
# .cursor/.init-done — cursor-init Skill 写入的初始化标记文件
# 本文件的存在表示本仓库已完成 .cursor 模板初始化
# 请务必 git commit 此文件,避免团队成员 clone 后被再次触发 init
initialized_at: {{ISO_DATETIME}} # 如 2026-04-21T16:30:00+08:00
initialized_by: cursor-init
skill_version: 2
project_type: {{PROJECT_TYPE}} # 阶段 5.5 问卷 Q1 结果;多选逗号分隔;"不确定"写 unknown
gitignore_generated: {{BOOL}} # true / false
```
**写入时机**
- 全流程跑完(阶段 6 验证通过)时由阶段 7 写入
- "补 gitignore" 单独跑阶段 5.5 时,若已存在则只更新 `gitignore_generated` 字段
---
## 模板内容 · .gitignore 片段库
阶段 5.5 按用户问卷选择拼接以下片段。每段前后各空一行,保证可读性。
### 固定段Cursor
```gitignore
# === Cursor ===
# 设备绑定配置,不同机器需独立生成
.cursor/local-env.json
# Hook 运行态标记(仅影响本地会话)
.cursor/changelog/.changelog-ack
# cursor-init 临时产物
.cursor/_init-backup/
.cursor/_gitignore-preview
```
### OS 段(按问卷 Q3 多选拼接)
**Windows**
```gitignore
# === OS: Windows ===
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
Desktop.ini
$RECYCLE.BIN/
*.stackdump
*.lnk
```
**macOS**
```gitignore
# === OS: macOS ===
.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
```
**Linux**
```gitignore
# === OS: Linux ===
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*
```
### IDE 段(按问卷 Q2 多选拼接)
**VSCode**
```gitignore
# === IDE: VSCode ===
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
.history/
*.vsix
```
**JetBrains**
```gitignore
# === IDE: JetBrains ===
.idea/
*.iml
*.ipr
*.iws
.idea_modules/
atlassian-ide-plugin.xml
```
**Visual Studio**
```gitignore
# === IDE: Visual Studio ===
.vs/
*.user
*.suo
*.userprefs
bin/
obj/
[Dd]ebug/
[Rr]elease/
x64/
x86/
```
**Vim/Emacs**
```gitignore
# === IDE: Vim / Emacs ===
*.swp
*.swo
*.swn
Session.vim
.netrwhist
*~
\#*\#
.\#*
```
**Cursor**:固定段已覆盖,无需额外片段。
### Language / Framework 段(按问卷 Q1 多选拼接)
**Unity**
```gitignore
# === Language: Unity ===
[Ll]ibrary/
[Tt]emp/
[Oo]bj/
[Bb]uild/
[Bb]uilds/
[Ll]ogs/
[Uu]ser[Ss]ettings/
[Mm]emoryCaptures/
[Rr]ecordings/
sysinfo.txt
*.apk
*.aab
*.unitypackage
*.app
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
```
**Node.js**
```gitignore
# === Language: Node.js ===
node_modules/
.npm/
.yarn/
.pnp.*
dist/
build/
out/
.next/
.nuxt/
.cache/
.parcel-cache/
coverage/
.env
.env.local
.env.*.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.turbo/
```
**Python**
```gitignore
# === Language: Python ===
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
dist/
*.egg-info/
*.egg
.venv/
venv/
env/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.coverage
.coverage.*
htmlcov/
.tox/
.nox/
.hypothesis/
.ipynb_checkpoints/
```
**Rust**
```gitignore
# === Language: Rust ===
target/
**/*.rs.bk
*.pdb
# Cargo.locklib crate 建议忽略bin crate 建议提交,默认不忽略
# Cargo.lock
```
**Go**
```gitignore
# === Language: Go ===
bin/
vendor/
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
go.work
```
**C# 非 Unity**
```gitignore
# === Language: C# (non-Unity) ===
bin/
obj/
*.user
*.suo
*.pdb
*.cache
[Dd]ebug/
[Rr]elease/
x64/
x86/
[Bb]uild/
*.dll
*.pdb
```
**Web 静态站点**
```gitignore
# === Language: Web Static ===
node_modules/
dist/
build/
public/build/
.cache/
.tmp/
.sass-cache/
.parcel-cache/
```
**其他**:不拼接语言段,用户在 `# === Custom ===` 段自行补充。
### Custom 段(固定尾部)
```gitignore
# === Custom ===
# 在此段追加项目专属需要忽略的路径
```
若用户在问卷 Q4 填了自由文本,按行拆分后追加到 Custom 段下方。
---
## 冲突与边界情况处理
| 场景 | 处理 |
|------|------|
| C 组某文件与 A 组重名 | 保留 A 组C 组移到 `.cursor/_init-backup/`,告知用户自行 diff |
| C 组有 `SKILL.md` 且 skill 名与 A 组白名单同名 | 保留 A 组 skillC 组整个 skill 目录移到 `_init-backup/` |
| 数据文件(如 `pitfalls.md`)用户明确说"保留" | 跳过该文件重置 |
| `local-env.json` 存在且用户说"我就在这台机器上开 B保留它" | 跳过删除,但提醒其已在 `.gitignore` |
| `.cursor/rules/project/` 为空目录 | 保留空目录(便于未来放项目级 rules |
| 扫描到 `.cursor/_init-backup/`(上轮残留) | 警告用户并询问:删除 / 保留 / 重命名 |
| `git status` 不能执行(不是 git 仓库) | 警告但不阻塞,改为建议用户手动备份 |
| `.cursor/.init-done` 已存在且用户触发了全流程 | 阶段 0 展示其元数据并要求二次确认 |
| 阶段 5.5 项目根已有 `.gitignore` 且用户选"追加" | 把拼装结果追加到现有文件末尾(用 `\n\n# --- 以下由 cursor-init 追加 ---\n` 分隔) |
| 阶段 5.5 中途异常或用户放弃 | 不写入 `.gitignore``.init-done``gitignore_generated` 记 false |
| 阶段 7 写 `.init-done` 前前序阶段已 abort | 不写入 sentinel下次会话 recall 会重新触发 |
| 用户说"补 gitignore" 但 `.init-done` 不存在 | 提醒"仓库尚未完整 init",询问是否改为跑全流程 |
---
## 与其他系统的协作
| 系统 | 关系 | 说明 |
|------|------|------|
| `baserule.mdc` | 分类权威 | 阶段 2 归位目录严格按 baserule 约定 |
| `cursor-init-recall.mdc` | 触发器 | 负责首次自动触发alwaysApply + sentinel 检查)和关键词触发 |
| `epee-orchestrator` Skill | 双向 | 本 Skill 被 Orchestrator 在 registry 里注册;同时本 Skill 负责清理 registry |
| `dev-changelog` / `pitfall-journal` / `deferred-decisions` / `problem-distillery` / `profile-memory` | 下游数据主人 | 本 Skill 只在阶段 3 重置其数据文件,不改动 SKILL.md |
| `local-env-check.mdc` | 后继 | 本 Skill 删除 `local-env.json`,后续新会话由 `local-env-check` 自动重新探测并生成 |
---
## 一次运行的最终状态(验收标准)
全流程(阶段 0 → 7完成后 `.cursor/` 应当满足:
1. 规范清单中列出的所有文件/目录都存在
2. 所有数据文件changelog/deferred/pitfalls/distillery/profile仅含模板内容
3. `.cursor/rules/project/` 为空目录
4. `.cursor/skills/` 下仅有白名单中的 skill 目录
5. `.cursor/skills/epee-orchestrator/registry.md` 中只有:基础设施 + 个人级 skill 条目,且包含 `cursor-init` 条目
6. 不存在 `*.log``local-env.json``_init-backup/``_gitignore-preview`
7. `.cursor/.init-done` 已写入,字段完整且值有效
8. 项目根 `.gitignore` 状态明确(存在且有内容 / 被用户显式放弃)
9. `git status .cursor/ .gitignore` 能让用户清楚看到所有改动
仅跑阶段 5.5"补 gitignore")完成后:
1. 项目根 `.gitignore` 存在或被显式放弃
2.`.init-done` 已存在,其 `gitignore_generated` 字段被更新
3. 其他 `.cursor/` 内容**零改动**
---
## 自迭代日志
本节记录使用本 Skill 过程中发现的必要检查项。
### 已知必要检查
1. **阶段 2 的 C 组归位前必须先做 dry-run 展示** —— 批量移动 .mdc / SKILL 文件是高破坏性操作,只要有一条分类错误就会污染 canonical 结构,必须让用户在列表上逐条过一遍再执行。
2. **重名冲突不许直接覆盖** —— C 组与 A 组重名时A 组(模板版本)永远是 source of truth冲突文件只能进 `_init-backup/`,让用户自行决定是否把差异合并回 common rule。
3. **registry 重建时先读后写** —— 阶段 4 不要直接用硬编码模板覆盖 registry.md必须先解析现有条目只移除项目级条目、补齐缺失条目避免丢失用户自己添加的个人级 Skill 条目。
4. **`.init-done` 是完成度契约** —— 只有阶段 6 验证通过后才能写入此文件。中途 abort 必须让 sentinel 缺失,这是保证下次会话能恢复触发的关键设计。
5. **`.gitignore` 用户主导** —— 阶段 5.5 对语言栈/IDE/OS 的判断完全来自用户问卷,不要根据文件探测"智能推断",因为新项目此时通常还是空白,推断不准反而会填错条目。
- baseline 结构完整,六个 Godot project rules 仍在;
- `.cursor/skills/` 只有指定 8 个目录;
- 历史数据、backup、cache、ack 与临时文件已清;
- 状态模板与四视图已重置;
- `local-env.json` 已由 example 生成且 gitignored
- `.gitignore` 正确区分 Godot 缓存和需提交的 sidecar
- `.init-done` 只在所有验证通过后存在。

View File

@@ -0,0 +1,552 @@
# Cursor Init Reference
本文件是 `cursor-init` 的精确数据契约。`SKILL.md` 负责流程,本文件负责 canonical、
cleanup、状态模板、sentinel 与 `.gitignore` 片段。路径均相对项目根。
## 1. Canonical 白名单
canonical 是初始化期间必须保留的 tracked 基线。缺失项应报错并从可信模板恢复,
不得用空文件伪造。除这里列出的 8 个 Skill 目录外,`.cursor/skills/` 不允许有其他
一级目录。
### 1.1 顶层配置与生成标记
```text
.cursor/hooks.json
.cursor/local-env.example.json
.cursor/.init-done
```
说明:
- `.cursor/.init-done` 是阶段 7 生成后需要提交的文件;模板源在首次 init 前可以没有。
- `.cursor/local-env.json` 是由 example 生成的 gitignored 运行态,不是 canonical。
- `.cursor/changelog/.changelog-ack` 是 gitignored hook 运行态,不是 canonical。
- `.cursor/changelog/.session-start` 是 sessionStart hook 刷新的 gitignored 运行态,不是 canonical。
### 1.2 Common Rules恰好 9 个基线项)
```text
.cursor/rules/common/baserule.mdc
.cursor/rules/common/changelog-recall.mdc
.cursor/rules/common/cursor-init-recall.mdc
.cursor/rules/common/deferred-recall.mdc
.cursor/rules/common/distillery-recall.mdc
.cursor/rules/common/epee-orchestrator.mdc
.cursor/rules/common/pitfall-recall.mdc
.cursor/rules/common/profile-recall.mdc
.cursor/rules/common/dependency-governance.mdc
```
### 1.3 Godot baseline Project Rules首次 init 必须保留)
```text
.cursor/rules/project/godot-architecture.mdc
.cursor/rules/project/godot-assets.mdc
.cursor/rules/project/godot-data-systems.mdc
.cursor/rules/project/godot-gdscript-style.mdc
.cursor/rules/project/godot-scene-conventions.mdc
.cursor/rules/project/godot-testing.mdc
```
禁止用 `.cursor/rules/project/*.mdc` 之类的通配删除覆盖这些文件。
### 1.4 Skills最终恰好 8 个目录)
```text
.cursor/skills/cursor-init/
.cursor/skills/deferred-decisions/
.cursor/skills/dev-changelog/
.cursor/skills/epee-orchestrator/
.cursor/skills/pitfall-journal/
.cursor/skills/problem-distillery/
.cursor/skills/profile-memory/
.cursor/skills/html-doc/
```
目录内 canonical 文件:
```text
.cursor/skills/cursor-init/SKILL.md
.cursor/skills/cursor-init/reference.md
.cursor/skills/deferred-decisions/SKILL.md
.cursor/skills/dev-changelog/SKILL.md
.cursor/skills/epee-orchestrator/SKILL.md
.cursor/skills/epee-orchestrator/registry.md
.cursor/skills/pitfall-journal/SKILL.md
.cursor/skills/problem-distillery/SKILL.md
.cursor/skills/profile-memory/SKILL.md
.cursor/skills/html-doc/SKILL.md
.cursor/skills/html-doc/assets/theme.css
.cursor/skills/html-doc/assets/annotate.js
.cursor/skills/html-doc/templates/skeleton.html
```
### 1.5 Hooks 全套
```text
.cursor/hooks.json
.cursor/hooks/README.md
.cursor/hooks/run-hook.ps1
.cursor/hooks/session-init.ps1
.cursor/hooks/session-init.sh
.cursor/hooks/check-changelog.ps1
.cursor/hooks/check-changelog.sh
```
### 1.6 Changelog tools 全套
```text
.cursor/changelog/tools/changelog_build.py
.cursor/changelog/tools/migrate_changelog.py
.cursor/changelog/tools/install-git-hooks.ps1
.cursor/changelog/tools/install-git-hooks.sh
.cursor/changelog/tools/merge-import.ps1
.cursor/changelog/tools/merge-import.sh
.cursor/changelog/tools/git-hooks/pre-commit
.cursor/changelog/tools/git-hooks/post-merge
```
`tools/__pycache__/``*.pyc` 永远不是 canonical。
### 1.7 Changelog 四视图与 entries 占位
```text
.cursor/changelog/changelog-full.md
.cursor/changelog/changelog-recent.md
.cursor/changelog/changelog-headlines.md
.cursor/changelog/changelog-by-author.md
.cursor/changelog/entries/.gitkeep
```
四视图由 `changelog_build.py` 生成,不手改。初始化时先清空 entries保留
`.gitkeep`),再运行生成器得到空视图。
### 1.8 状态模板文件
```text
.cursor/deferred/registry.md
.cursor/pitfalls/pitfalls.md
.cursor/distillery/problems.md
.cursor/distillery/insights.md
.cursor/distillery/golden-rules.md
.cursor/profile/project-profile.md
.cursor/profile/project-profile-log.md
```
## 2. Cleanup 清单
### 2.1 强制删除
下面内容必须进入 dry-run确认后删除
```text
# 全部历史 changelog fragment唯一例外是 entries/.gitkeep
.cursor/changelog/entries/**
!.cursor/changelog/entries/.gitkeep
# 历史备份
.cursor/changelog/_backup/**
.cursor/_init-backup/**
.cursor/**/_backup/**
.cursor/**/*.bak
.cursor/**/*.backup
# 缓存和编译产物
.cursor/**/__pycache__/**
.cursor/**/*.pyc
.cursor/**/*.pyo
.cursor/**/*.cache
.cursor/**/.cache/**
# 设备绑定与 hook 运行态
.cursor/local-env.json
.cursor/changelog/.changelog-ack
.cursor/changelog/.session-start
# init / 调试临时产物
.cursor/_gitignore-preview
.cursor/**/*.tmp
.cursor/**/*.temp
.cursor/**/*.log
.cursor/debug-*.log
```
模式中的 `!` 只是“例外”说明,不表示可把这段直接交给任意删除命令。实现时必须先枚举
实际文件并逐项比对白名单,防止通配误删。
此外:
- 删除 `.cursor/skills/` 下所有非 8 项白名单目录。
- 删除或迁出非 baseline project rules但必须逐项确认六个 baseline 永不删除。
- 删除任何非 8 项白名单 Skill。
- 不删除 `source/`,不修改项目根 Git 文件(`.gitignore` 仅在用户明确选择时例外)。
### 2.2 重置而非删除
以下文件保留路径并重置为第 3 节模板:
```text
.cursor/deferred/registry.md
.cursor/pitfalls/pitfalls.md
.cursor/distillery/problems.md
.cursor/distillery/insights.md
.cursor/distillery/golden-rules.md
.cursor/profile/project-profile.md
.cursor/profile/project-profile-log.md
```
四个 changelog 视图不使用手写模板覆盖:删除 fragments 后运行生成器重建。
### 2.3 环境配置入口
本机环境只由 `cursor-init` 阶段 1 和阶段 4 一次性采集、生成,不依赖额外环境检查 Rule。
## 3. 状态模板
写入时替换 `{{DATE}}` 为本地日期 `YYYY-MM-DD`
### 3.1 `.cursor/deferred/registry.md`
```markdown
# Deferred Decisions Registry
## Active Items
(暂无延期方案)
---
## Completed / Cancelled Items
(暂无已完成或已废弃的方案)
```
### 3.2 `.cursor/pitfalls/pitfalls.md`
```markdown
# Pitfall Journal
开发过程中踩过的坑,按时间倒序排列。
Agent 进入 Debug mode 或遇到运行时错误时自动检索匹配。
---
```
### 3.3 `.cursor/distillery/problems.md`
```markdown
# Problem Distillery — Problems
反复出现的顽固问题追踪记录,按时间倒序排列。
<!-- 新条目追加在此行下方 -->
```
### 3.4 `.cursor/distillery/insights.md`
```markdown
# Problem Distillery — Insights
从已解决的顽固问题中蒸馏出的精炼方法论。
<!-- 新条目追加在此行下方 -->
---
last_distill_date: {{DATE}}
```
### 3.5 `.cursor/distillery/golden-rules.md`
```markdown
# Golden Rules
经过实践验证(权重 >= 5的精炼认知每次新会话自动注入。
<!-- 当条目达到权重阈值后由 Agent 自动写入 -->
```
### 3.6 `.cursor/profile/project-profile.md`
```markdown
# Project Profile
## 项目定位
## 技术栈与架构
## 设计约定
## 产品方向
```
### 3.7 `.cursor/profile/project-profile-log.md`
```markdown
# Project Profile Log
详细记录每次项目画像更新的完整上下文,按时间正序追加。
## 记录
```
## 4. 空 Changelog 四视图
`.cursor/changelog/tools/changelog_build.py` 的输出为准。entries 仅有 `.gitkeep` 时,
生成结果应具备以下固定头部且无条目:
### 4.1 `changelog-headlines.md`
```markdown
# Dev Changelog — Headlines
最近 ~50 次改动的一句话概要,按时间倒序排列。每次会话自动注入上下文。
> 本文件由 `tools/changelog_build.py` 从 `entries/` 自动生成,请勿手改。
```
### 4.2 `changelog-recent.md`
```markdown
# Dev Changelog — Recent
最近 ~20 次改动的摘要记录,按时间倒序排列。
当 Agent 检测到当前任务与近期改动相关时自动读取。
> 本文件由 `tools/changelog_build.py` 从 `entries/` 自动生成,请勿手改。
```
### 4.3 `changelog-full.md`
```markdown
# Dev Changelog — Full
完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。
> 本文件由 `tools/changelog_build.py` 从 `entries/` 自动生成,请勿手改;新增/修改请编辑 `entries/<author>/<id>.md` 后重跑生成器。
## 记录
```
### 4.4 `changelog-by-author.md`
```markdown
# Dev Changelog — By Author
按作者聚合的贡献概览,便于多人协作时区分提交来源。
> 本文件由 `tools/changelog_build.py` 自动生成,请勿手改。
```
生成器统一以单个 LF 结尾,不保留多余空白行;验证应比较生成器实际输出,不自行 trim 后回写。
## 5. `local-env.json` 生成契约
必须读取 `.cursor/local-env.example.json`,复制完整 JSON 结构,再覆盖三个键:
```json
{
"shell": "{{SHELL}}",
"changelog-author": "{{CHANGELOG_AUTHOR}}",
"godot4_path": "{{GODOT4_EXECUTABLE_OR_EMPTY}}"
}
```
规则:
- example 中其他键原样保留,不以这段最小示例覆盖整个文件。
- `godot4_path` 可为空字符串。
- 不写用户未确认的自动猜测值。
- 文件必须能被 JSON parser 读取,并由 `.gitignore` 忽略。
- 不提交 `local-env.json`
## 6. `.init-done` 模板
仅在全部验证通过后写入:
```yaml
# .cursor/.init-done — cursor-init 写入的初始化标记
# 必须提交此文件,避免 clone 后重复触发初始化
initialized_at: {{ISO_DATETIME}}
initialized_by: cursor-init
skill_version: 3
project_type: godot
gitignore_generated: {{BOOL}}
```
`{{BOOL}}` 只能是 `true``false`。流程失败、取消或存在未解决项时不得写入。
## 7. `.gitignore` 片段
拼装顺序:
1. Cursor runtime
2. Godot
3. OS / IDE / Language如用户需要
4. Custom
追加到已有文件时,用以下分隔:
```gitignore
# --- 以下由 cursor-init 追加 ---
```
### 7.1 Cursor runtime固定
```gitignore
# === Cursor runtime ===
.cursor/local-env.json
.cursor/changelog/.changelog-ack
.cursor/changelog/.session-start
.cursor/_init-backup/
.cursor/_gitignore-preview
# .cursor/.init-done 是需提交的完成标记,不得忽略
```
### 7.2 Godot固定
```gitignore
# === Godot ===
# 编辑器导入缓存可重建,不提交
.godot/
# Godot 4 UID sidecar 与资源导入配置是项目元数据,必须提交
!*.uid
!**/*.uid
!*.import
!**/*.import
```
写入前检查并移除或修正已有的冲突规则,例如 `*.uid``*.import``**/*.uid`
`**/*.import`。不要把 `.godot/` 内的生成缓存误认为资源旁的 `*.import` sidecar。
### 7.3 Windows
```gitignore
# === OS: Windows ===
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
Desktop.ini
$RECYCLE.BIN/
*.stackdump
*.lnk
```
### 7.4 macOS
```gitignore
# === OS: macOS ===
.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
```
### 7.5 Linux
```gitignore
# === OS: Linux ===
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*
```
### 7.6 VS Code
```gitignore
# === IDE: VS Code ===
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
.history/
*.vsix
```
### 7.7 JetBrains
```gitignore
# === IDE: JetBrains ===
.idea/
*.iml
*.ipr
*.iws
.idea_modules/
```
### 7.8 Visual Studio
```gitignore
# === IDE: Visual Studio ===
.vs/
*.user
*.suo
*.userprefs
bin/
obj/
[Dd]ebug/
[Rr]elease/
x64/
x86/
```
### 7.9 Vim / Emacs
```gitignore
# === IDE: Vim / Emacs ===
*.swp
*.swo
*.swn
Session.vim
.netrwhist
*~
\#*\#
.\#*
```
### 7.10 Custom
```gitignore
# === Custom ===
# 在此追加项目专属忽略项
```
## 8. Dry-run 输出格式
```markdown
## cursor-init dry-run
### 保留
- path — canonical
### 缺失(阻塞)
- path — 需要从可信模板恢复
### 删除
- path — cleanup 原因
### 重置
- path — 使用的模板
### 迁移 / 冲突
- from → to — 原因与是否需要用户选择
### 生成
- .cursor/local-env.json — 输入字段摘要(不要泄露不必要的本机信息)
- .cursor/skills/epee-orchestrator/registry.md — 8 项
- .gitignore — 新建 / 追加 / 替换 / 跳过
- .cursor/.init-done — 仅验证成功后
```
确认必须覆盖整份 dry-run。dry-run 后扫描结果变化时应重新生成清单并再次确认。

View File

@@ -1,259 +1,222 @@
---
name: dev-changelog
description: >-
三层开发进程记录系统。在 Agent 完成代码改动后自动记录,提供从一句话概要到完整日志的
多级上下文,帮助 Agent 在跨会话场景下保持对项目开发进展的感知。
三层开发进程记录系统fragment 源 + 自动生成视图。Agent 完成代码改动后,
写入一条独立的 fragment 文件并重建视图,提供从一句话概要到完整日志的多级上下文,
帮助 Agent 跨会话保持对项目进展的感知,并支持多人协作下的低冲突合并与作者区分。
当用户提到"开发日志"、"changelog"、"最近改了什么"、"回顾改动"等时触发。
---
# Dev Changelog
三层开发进程记录系统,解决 Agent 跨会话的上下文断裂问题。
跨会话开发进程记录系统。**数据源是一条一文件的 fragment三层视图由脚本自动生成。**
这套设计同时解决了三个老问题:体量失控、三层手动同步漂移、以及多人协作时 git merge 冲突。
## 三层架构
## 架构总览
| 层级 | 文件 | 信息密度 | 条目数量 | 注入方式 |
|------|------|---------|---------|---------|
| L1 完整版 | `changelog-full.md` | 高5-15 行/条) | 无上限,只追加 | 用户手动唤醒 |
| L2 中期版 | `changelog-recent.md` | 中3-5 行/条) | 滚动窗口 ~20 条 | 检测到关联时自动读取 |
| L3 概要版 | `changelog-headlines.md` | 低1 行/条) | 滚动窗口 ~50 条 | 每次会话自动注入 |
```
.cursor/changelog/
├─ entries/<author>/<id>.md ← 唯一数据源(一条改动 = 一个文件,提交进 git
├─ changelog-full.md ← 视图L1 完整,全部条目) \
├─ changelog-recent.md ← 视图L2 摘要,最近 ~20 条) | 全部由
├─ changelog-headlines.md ← 视图L3 一句话,最近 ~50 条) | 生成器产出
├─ changelog-by-author.md ← 视图(按作者聚合) /
└─ tools/
├─ changelog_build.py ← 生成器entries/ → 4 个视图确定性、stdlib-only
├─ migrate_changelog.py ← 一次性迁移脚本(已执行,留作参考)
├─ install-git-hooks.ps1/.sh ← 安装 pre-commit / post-merge git hook
└─ git-hooks/{pre-commit,post-merge}
```
所有数据文件存放在 `.cursor/changelog/` 目录下。
| 层级 | 视图文件 | 信息密度 | 窗口 | 注入方式 |
|------|---------|---------|------|---------|
| L1 完整版 | `changelog-full.md` | 高(完整正文) | 全部 | 用户手动唤醒 |
| L2 中期版 | `changelog-recent.md` | 中3-5 行摘要) | ~20 条 | 检测到关联时自动读取 |
| L3 概要版 | `changelog-headlines.md` | 低1 行) | ~50 条 | 每次会话自动注入 |
| 作者视图 | `changelog-by-author.md` | 索引 | 全部 | 按需 |
> **重要**:视图文件顶部都标了"由 changelog_build.py 自动生成,请勿手改"。
> 一切修改都改 fragment再跑生成器。视图改了不算数下次生成会被覆盖
## 锚点 ID 机制
每条记录在写入时生成一个**锚点 ID**格式 `CL-YYYYMMDD-HHMM`(如 `CL-20260412-1430`)。
同一分钟内有多条时追加字母后缀`CL-20260412-1430a``CL-20260412-1430b`)。
格式 `CL-YYYYMMDD-HHMM-<author>`(如 `CL-20260715-1521-alice`)。同一分钟多条时在 `HHMM`
追加字母(`CL-...-1521a-sq`)。历史迁移条目无作者后缀(`author: legacy`),保持原 ID 不变
以维持 pitfalls / deferred / source_chat 等处的交叉引用有效。
锚点 ID 在三层文件中保持一致,用于跨层精准定位:
- L3 一句话条目以 `[CL-xxx]` 开头
- L2 摘要条目的 H3 标题包含 `[CL-xxx]`
- L1 完整条目的 H3 标题包含 `[CL-xxx]`
锚点 ID 在 fragment 与三层视图中一致,用于逐级 Grep 精准定位L3 → L2 → L1
这使得从 L3 → L2 → L1 的逐级查找可以通过 Grep 精准定位,无需全文读取。
## 作者标识(多人协作核心)
## 逐级上溯机制
每条 fragment 记录作者,体现在三处:① 目录 `entries/<author>/`、② 文件名 / ID 后缀、
③ frontmatter `author` 字段。视图层 L3 行前缀 `@<author>`、L2/L1 有 `author` 字段、
另有按作者聚合的 `changelog-by-author.md`
当 Agent 在使用 L3 概要作为上下文时,如果某条记录的一句话描述**语义模糊**
(如无法判断改动的具体范围、与当前任务的关系不明确),执行以下逐级查找:
**作者 handle 的确定顺序**(写入时):
1.`.cursor/local-env.json``changelog-author` 字段设备绑定、gitignored每位开发者各自配一次最稳
2. 缺失则取 `git config user.name`,转小写、取首个英文单词或姓名缩写作为 handle
3. 仍无法确定则用 `unknown`
```
1. 从 L3 条目中提取锚点 ID如 CL-20260412-1430
2. 在 changelog-recent.mdL2中 Grep 该 ID
- 找到 → 读取该条目的 3-5 行摘要,通常足以消除歧义
- 未找到(已滚出 L2 窗口)→ 进入步骤 3
3. 在 changelog-full.mdL1中 Grep 该 ID
- 找到 → 用 Read 工具读取该 ID 所在行号 ±20 行范围(精准读取,不读全文)
- 未找到 → 放弃上溯,该条目上下文不可用
> 建议每位协作者在本机 `.cursor/local-env.json` 里加 `"changelog-author": "<你的handle>"`
> 保证 handle 稳定(不随 git user.name 大小写/格式变化而漂移)。
## fragment 文件格式
```markdown
---
id: CL-20260715-1521-alice
date: 2026-07-15 15:21
author: alice
author_name: Alice
type: fix
merge_source: HEAD
status: active
superseded_by:
title: 一句话标题(用于视图的 H3 标题)
source_chat: [对话简述](chat-uuid)
tags:
- tag1
- tag2
affected_files:
- scripts/player/player_controller.gd
- scenes/player/player.tscn
---
<!-- L3 -->
一句话描述改动内容≤80 字,进 headlines
<!-- L2 -->
做了什么 + 为什么3-5 行摘要,进 recent当本条进入最近 20 时被展示)
<!-- L1 -->
- **what**: ...
- **why**: ...
- **decisions**: ...
- **notes**: ...
symptom / root-cause / fix / tests / followups / relation 等按需,正文原样进 full
```
### 上溯原则
- **按需触发**:只有在 L3 信息不足以支撑当前任务判断时才上溯,不预防性地批量读取
- **精准读取**:对 L1 的访问必须通过 Grep 定位行号 + Read 局部读取,禁止全文读取
- **最小化**:一次上溯通常只涉及 1-3 条记录,不批量上溯
字段说明:
- `type``feat` / `fix` / `refactor` / `docs` / `chore` / `infra`(机读,便于统计)
- `merge_source`:本条记录时所在分支(`HEAD` / `master` / 分支名),留空则视图不显示
- `status``active`(默认)/ `reverted` / `superseded`;后两者配 `superseded_by: CL-xxx`
- `affected_files`**必须全路径**(视图 L2 的硬匹配靠它,缩写路径会失效)
- `tags` / `affected_files` 为块列表其余为标量。frontmatter 之外的三段用 `<!-- L1/L2/L3 -->` 分隔
## 操作 A记录写入核心流程
### 触发条件
Agent 完成了一个涉及**代码或配置文件实质性改动**的任务后自动触发。
Agent 完成涉及**代码或配置文件实质性改动**的任务后自动触发。
以下情况**不触发**
- 纯对话讨论、方案设计、问题解答(无文件改动)
- 只读操作(查看文件、搜索代码)
- 只改动了 `.cursor/` 目录下的基础设施文件如画像、延期方案、changelog 自身)
**不触发**:纯对话/方案/答疑(无文件改动)、只读操作、只改 `.cursor/` 下基础设施文件
画像、延期、changelog 自身、hooks、tools 等)。
### 写入流程
```
1. 生成锚点 IDCL-YYYYMMDD-HHMM检查是否与已有 ID 冲突,冲突则追加字母后缀
1. 确定作者 handle见上「作者标识」三步顺序
2. 从刚完成的任务中提取以下信息:
- 做了什么what一句话概括
- 为什么这样做why动机和背景
- 改了哪里where受影响的文件/模块列表
- 关键决策decisions如果有方案选择记录选了什么、放弃了什么
- 注意事项notes后续可能受影响的地方、已知限制等
2. 生成锚点 IDCL-YYYYMMDD-HHMM-<author>
- 检查 entries/ 下是否已存在同 ID含其他作者目录冲突则 HHMM 后加字母后缀
3. 生成三层内容(共享同一个锚点 ID
- L1 完整条目(包含以上全部信息)
- L2 摘要条目what + why + where3-5 行)
- L3 一句话what不超过 80 字)
3. 从刚完成的任务提取what / why / where(affected_files, 全路径) / decisions / notes
并判定 type、merge_source当前分支、tags
4. 写入三个文件(按以下顺序)
a. 读取 changelog-full.md在 "## 记录" 下方追加 L1 条目
b. 读取 changelog-recent.md在顶部插入 L2 条目,如超过 20 条则移除最旧的与下方「L2 窗口」一致)
c. 读取 changelog-headlines.md在顶部插入 L3 条目,如超过 50 条则移除最旧的
4. 用 Write 工具创建单个 fragment 文件
.cursor/changelog/entries/<author>/<id>.md
- 按上面的格式填好 frontmatter + L3/L2/L1 三段
- L3 ≤80 字一句话L2 3-5 行L1 完整正文
5. 在回复末尾附一行提示:"[已记录到开发日志]"
5. 跑生成器重建视图:
python .cursor/changelog/tools/changelog_build.py
Windows 控制台先 set PYTHONIOENCODING=utf-8
6. 在回复末尾附 "[已记录到开发日志]"
```
### 与旧流程的关键区别
- **不再用 StrReplace 往三个文件顶部插入**——只新建一个 fragment 文件,零冲突、零半损坏风险
(旧的 StrReplace 顶部插入曾导致条目半损坏fragment 模型下该风险彻底消失)。
- **不再手动维护滚动窗口**——recent/headlines 的 ~20/~50 截断由生成器自动算。
- **不再手动保持三层同步**——三层都是同一 fragment 的不同密度渲染,天然一致。
### 静默写入原则
- **不需要用户确认**——Agent 自己的改动,对"做了什么"的认知是一手的
- 用户如果觉得记录不准确,可通过操作 D 修改或删除
- 回滚操作也要记录("回退了 XX 改动"),真实反映开发过程
- 不需要用户确认Agent 自己的改动是一手认知)。
- 回滚也要记录(新建一条 `type: chore` / 在被回滚条目里置 `status: reverted` + `superseded_by`)。
## 操作 BL2 自动触发读取
### 触发条件
`changelog-recall.mdc` Rule 调度。当 Agent 开始处理一个新任务时,判断该任务是否
与近期改动相关
### 匹配策略(文件 + 标签双匹配)
```
1. 从当前任务中提取:
- 涉及的文件路径
- 语义关键词(模块名、功能领域等)
2. 读取 changelog-recent.md逐条检查
- 硬匹配:当前任务涉及的文件出现在条目的 affected_files 中
- 软匹配:当前任务的语义关键词与条目的 tags 有交集
3. 任一匹配命中 → 将匹配到的 L2 条目作为上下文纳入考量
4. 在回复中自然融入,不显式提及"根据开发日志"
```
`changelog-recall.mdc` 调度,读取 `changelog-recent.md`
- 硬匹配:当前任务涉及的文件出现在条目 `affected_files`(现为全路径)
- 软匹配:当前任务语义关键词与条目 `tags` 有交集
任一命中即纳入上下文。读取的是**视图**,无需读 fragment
## 操作 CL1 手动检索
### 触发条件
用户要求回顾完整记录时,读取 `changelog-full.md` 并按时间 / 模块 / tags 过滤展示。
用户主动要求回顾完整改动记录时触发。典型话语:
- "回顾一下最近的改动"
- "XX 模块之前改过什么"
- "查看开发日志"
- "changelog"
### 流程
## 逐级上溯机制
L3 信息不足时(语义模糊),按 ID 逐级 Grep
```
1. 读取 changelog-full.md
2. 根据用户需求过滤:
- 按时间范围
- 按模块/文件
- 按 tags
3. 展示匹配的条目摘要表,用户可以进一步查看某条的完整内容
1. 从 L3 提取锚点 ID
2. Grep changelog-recent.mdL2→ 命中读该条
3. 仍不足 → Grep changelog-full.mdL1拿行号Read 该行 ±20 行
(也可直接 Read 对应 fragmententries/*/<id>.md
```
原则:按需触发、精准读取、一次 1-3 条、不全文读 L1。
## 操作 D记录管理
用户可以对已有记录进行管理:
- **修改**:编辑对应 `entries/*/<id>.md` 后跑生成器(不要直接改视图)。
- **删除**:删除对应 fragment 文件后跑生成器。
- **标记取代/回滚**:在 fragment 里置 `status: superseded`/`reverted` + `superseded_by`
| 操作 | 说明 |
## 滚动窗口(自动)
生成器按 ID 时间倒序排序后headlines 取前 50、recent 取前 20、full 全量、by-author 全量。
**无需任何手动修剪**,被移出窗口的条目仍完整保留在 fragment 与 full 视图中。
## git 协作与冲突
- **fragment 几乎不冲突**:不同人写不同文件、不同作者写不同子目录。
- **视图冲突自动吸收**`.gitattributes` 给 4 个视图设 `merge=union`merge 不中断),
pre-commit / post-merge git hook 跑生成器从 fragment **确定性重建**视图,所有人收敛到一致。
- 新克隆需跑一次 `tools/install-git-hooks.ps1`(或 `.sh`)装 hook。
- CI 可加 `changelog_build.py --check` 校验"视图 == 重建(fragment)"防止有人没装 hook 就提交。
- **合并尚未 fragment 化的旧分支**(如重构前的 master`git merge --no-commit --no-ff <分支>`
union 让视图不冲突、`--no-commit` 防止 hook 过早重建),再跑 `tools/merge-import.ps1 [-Ref <分支>]`
(或 `.sh`)把对方旧格式条目收割成 fragment只补缺失 ID、不覆盖已有自动重建并校验无丢失最后 `git add -A; git commit`
- **两条改动撞了同一个 fragment ID**(生成器遇重复 ID 会直接报错):给其中一条改 ID`HHMM` 后加字母,如 `1521``1521a`
文件名与 frontmatter `id` 同步改,再跑生成器。两条都保留、不丢内容。
## 与其他系统协作
| 系统 | 关系 |
|------|------|
| 删除 | 从三层文件中同步移除对应条目 |
| 修改 | 修改某条记录的描述(三层同步更新) |
| 清理 | 手动触发 L1 的归档(如按月分文件,暂不实现,作为演进方向) |
## 条目格式
### L1 完整条目
```markdown
### [CL-20260412-1430] YYYY-MM-DD HH:MM — 一句话标题
- **tags**: tag1, tag2, tag3
- **affected_files**:
- path/to/file1
- path/to/file2
- **what**: 做了什么的简要描述
- **why**: 动机和背景
- **decisions**: 选择了 A 方案(放弃了 B 因为 xxx
- **notes**: 后续注意事项
- **source_chat**: [对话简述](chat-uuid)
```
### L2 摘要条目
```markdown
### [CL-20260412-1430] YYYY-MM-DD — 一句话标题
- **tags**: tag1, tag2, tag3
- **affected_files**: file1, file2
- **summary**: 做了什么 + 为什么3-5 行)
```
### L3 一句话条目
```markdown
- [CL-20260412-1430] 一句话描述改动内容(不超过 80 字)
```
## 滚动窗口维护
### L2 窗口(~20 条)
```
写入新条目后,检查总条目数:
- <= 20 条:不做处理
- > 20 条:移除文件底部(最旧的)条目,直到恰好 20 条
```
### L3 窗口(~50 条)
```
写入新条目后,检查总行数(排除文件头部的标题和说明):
- <= 50 条:不做处理
- > 50 条:移除文件底部(最旧的)条目,直到恰好 50 条
```
被移除的条目不需要额外归档——L1 完整版保留了所有历史。
## 数据文件模板
首次写入时,如对应文件不存在,按以下模板创建。
### changelog-full.md
```markdown
# Dev Changelog — Full
完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。
## 记录
```
### changelog-recent.md
```markdown
# Dev Changelog — Recent
最近 ~10 次改动的摘要记录,按时间倒序排列。
当 Agent 检测到当前任务与近期改动相关时自动读取。
```
### changelog-headlines.md
```markdown
# Dev Changelog — Headlines
最近 ~50 次改动的一句话概要,按时间倒序排列。每次会话自动注入上下文。
```
## 与其他系统的协作
| 系统 | 关系 | 说明 |
|------|------|------|
| `changelog-recall` Rule | 下游消费者 | 每次会话注入 L3自动触发 L2 读取 |
| `deferred-decisions` Skill | 互补 | deferred 记"没做什么"changelog 记"做了什么" |
| `profile-memory` Skill | 结构对称 | profile 是"是什么"changelog 是"做了什么" |
| `epee-orchestrator` | 注册 | 在 registry.md 中注册本 Skill |
| `changelog-recall` Rule | 下游消费者:注入 L3、按需读 L2、上溯 L1 |
| `deferred-decisions` | 互补:记"没做什么" |
| `profile-memory` | 结构对称:记"是什么" |
| `epee-orchestrator` | 在 registry.md 注册本 Skill |
## 自迭代日志
本节记录使用本 Skill 过程中发现的必要检查项。
### 已知必要检查
1. **大任务收尾遗漏风险**单次任务涉及 5+ 文件改动时,Agent 容易在输出总结回复后遗漏被动写入流程。应在生成最终回复前,先执行 `changelog-recall.mdc` 中的"任务完成 Checklist",确认三层日志已写入后再输出回复。绝不能"先回复再补写"。
1. **大任务收尾不要遗漏写入** — 单次 5+ 文件改动时,先按 `changelog-recall.mdc`
"任务完成 Checklist" 写完 fragment + 跑生成器,再输出回复;绝不"先回复再补写"。
2. **L3/L2 滚动窗口必须落地** — 操作 A 第 4 步不是「插入即结束」写入后必须数清条目L3 为以 `- [` 开头的列表行L2 为 `### [CL-` 标题行。L3 超过 50 条、L2 超过 20 条时,必须从**文件底部(最旧)**整段删除条目直至恰好满足上限;禁止长期只追加不修剪。若发现 `changelog-headlines.md` 列表行多于 50说明上次写入未执行本项本次补修剪并自检。
2. **affected_files 必须全路径** — 视图 L2 的硬匹配依赖全路径;缩写路径(如只写文件名)
会让 recall 的硬匹配失效。迁移前的旧 L2 缩写路径问题已由本次重构(从 frontmatter 全路径渲染)解决。
3. **顶部插入 StrReplace 范式L1/L2** — L1 和 L2 的每个条目都是多行结构(标题 + 多条 `- **字段**:`)。使用 StrReplace 在顶部插入新条目时anchor`old_string`)有且仅有两种合法选择:
(a) 只包含新条目之前的"稳定前缀"(如 L1 的 `## 记录\n\n` 或 L2 的整段文件头说明),**不触及任何已有条目的任何一行**`new_string` = 稳定前缀 + 新条目完整内容 + 空行
(b) 把旧首条目的**完整多行内容**(标题行 + 全部字段行)都纳入 `old_string``new_string` = 新条目完整内容 + 空行 + 旧首条目完整内容。
3. **写完务必跑生成器** — 只建 fragment 不跑 `changelog_build.py`视图就不会更新recall 读的是视图)。
pre-commit hook 会兜底重建,但当前会话内的 recall 注入读的是已落盘视图,故应即时生成
**绝对禁止**:只把旧首条目的标题行(或前 1-2 字段)当 anchor 而不带上剩余字段行——StrReplace 会吞掉这些 anchor 行但不动剩余字段,造成"旧标题丢失、字段游离"的半损坏状态2026-04-20 在 `pitfall-journal` 的写入中已实际踩过此坑)。
4. **作者 handle 要稳定** — 优先用 `.cursor/local-env.json``changelog-author`,避免每次从
`git config user.name` 推导导致 handle 漂移(同一人出现多个目录)。
**写入后自检**Read 文件头部 30 行,确认看到新条目完整 + 旧首条目标题行仍存在且字段完整跟随。L3 的一行条目不受本条约束(它就是单行,天然无此风险)。
5. **Windows 控制台编码** — 跑脚本前 `set PYTHONIOENCODING=utf-8`(或 PowerShell `$env:PYTHONIOENCODING="utf-8"`
否则中文输出在 GBK 控制台显示乱码(不影响 UTF-8 文件写入,仅影响 stdout 观感)。

View File

@@ -93,7 +93,8 @@ description: >-
### 条目格式
参见 [registry.md](registry.md) 中的条目结构。
参见 [registry.md](registry.md) 中的条目结构。Registry 条目必须对应磁盘上真实存在的
Skill删除 Skill 时同步移除条目。
## Skill 创建价值判断标准
@@ -114,9 +115,8 @@ description: >-
|------|------|------|
| `create-skill` Skill | 下游委托 | 操作 B 创建流程的执行者 |
| `deferred-decisions` Skill | 下游工具 | 操作 B 延期记录的执行者 |
| `skill-self-iteration` Rule | 并行 | 它负责单个 Skill 的经验积累Orchestrator 负责 Skill 间的调度 |
| `deferred-recall` Rule | 协同 | Orchestrator 延期的建议通过 deferred-recall 在未来自动提醒 |
| `forskill-convention` Rule | 兼容 | 新 Skill 如需 Editor 脚本,仍遵循 ForSkill 约定 |
| `deferred-recall` Rule | 协同 | 延期建议通过 deferred-recall 在未来自动提醒 |
| `cursor-init` Skill | 校准 | 初始化时把 Registry 校准为实际 8 个 Skill |
## 自迭代日志
@@ -124,4 +124,6 @@ description: >-
### 已知必要检查
1. **收尾动作级联遗漏** — 当 Agent 遗漏了一个收尾动作(如 changelog 写入)后,后续的收尾动作自迭代、Registry 同步)也会被一并遗漏,因为它们都在同一个"收尾阶段"。`changelog-recall.mdc` 中的 Checklist 化设计可以打断这种级联——每项独立检查,不依赖前一项的执行记忆。
1. **收尾动作级联遗漏** — 当 Agent 遗漏了一个收尾动作(如 changelog 写入)后,
后续的 Registry 同步也容易遗漏。每次创建、删除或实质修改 Skill 后都应把
Registry 同步作为独立检查项。

View File

@@ -1,17 +1,15 @@
# EPEE Skill Registry
> 本文件由 EPEE Skill Orchestrator 维护,记录所有已实现 Skill 的摘要信息
> 每次创建/修改 Skill 后必须同步更新(参见 `epee-orchestrator.mdc` Rule
> 本文件由 EPEE Skill Orchestrator 维护,只登记磁盘上真实存在的 Skill
> 创建、删除或实质修改 Skill 后必须同步更新。
## 条目格式说明
## 条目格式
每个条目包含以下字段:
- **类型**项目级 / 个人级 / 基础设施
- **能力**1 句话核心能力描述
- **触发场景**:逗号分隔的关键词/短语,用于与任务特征匹配
- **输出**该 Skill 的产出物
- **路径**SKILL.md 的相对路径
- **备注**(可选):特殊说明
- **类型**:基础设施 / 个人级
- **能力**该 Skill 做什么
- **触发场景**:何时使用
- **输出**:实际产出
- **路径**存在的 `SKILL.md` 相对路径
---
@@ -19,52 +17,56 @@
### cursor-init
- **类型**: 基础设施
- **能力**: 把从模板 clone 或复制过来的 .cursor/ 重置为新项目的干净起点——按 baserule 归位原有 rules/skills清理源项目的项目专用数据重建 registry交互式生成 .gitignore最后写入 `.cursor/.init-done` sentinel
- **触发场景**: 首次会话自动触发(.cursor/.init-done 缺失时由 cursor-init-recall 规则引导);关键词:"初始化cursor"、"cursor init"、"重置 cursor"、"reset cursor"、"按 baserule 归位"、"补 gitignore"、"生成 gitignore"、"gitignore 模板"
- **输出**: 清理后`.cursor/` 结构规范清单完整、项目级内容已清、数据文件为模板、registry 仅含通用条目)、项目根 `.gitignore`(可选)`.cursor/.init-done` sentinel
- **能力**: 以精确 canonical 白名单初始化或重置 `.cursor/`,保留 Godot baseline清理历史运行数据生成本机配置与 `.gitignore`,并在验证成功后写 sentinel
- **触发场景**: 首次缺少 `.cursor/.init-done`"初始化 cursor"、"cursor init"、"重置 cursor"、"补 gitignore"
- **输出**: 干净且通过验证`.cursor/` 基线、gitignored `local-env.json`、可选 `.gitignore``.cursor/.init-done`
- **路径**: .cursor/skills/cursor-init/SKILL.md
- **备注**: 首次通过 sentinel 自动触发一次,之后仅关键词手动触发;破坏性操作必须 dry-run设计为幂等重复运行无害阶段 7 失败时不写 sentinel 保证可恢复
### deferred-decisions
- **类型**: 基础设施
- **能力**: 记录和追踪延期的技术方案/决策,在关联任务出现时主动提醒
- **能力**: 记录和追踪延期的技术方案决策,在关联任务出现时提醒
- **触发场景**: "以后再做"、"先不做"、"defer"、延期方案管理、延期回顾
- **输出**: .cursor/deferred/registry.md 条目
- **输出**: `.cursor/deferred/registry.md` 条目及状态更新
- **路径**: .cursor/skills/deferred-decisions/SKILL.md
- **备注**: 不参与任务分流匹配,仅作为 Orchestrator 的下游工具
### dev-changelog
- **类型**: 基础设施
- **能力**: 三层开发进程记录系统Agent 完成代码改动后自动记录,提供一句话概要到完整日志的多级上下文
- **触发场景**: "开发日志"、"changelog"、"最近改了什么"、"回顾改动"、"查看开发记录"、代码改动后自动写入
- **输出**: .cursor/changelog/ 下的 changelog-full.md、changelog-recent.md、changelog-headlines.md
- **能力**: 以一条一文件的 fragment 记录开发改动,并确定性重建完整、近期、概要和作者四个视图
- **触发场景**: 实质代码或配置改动完成后、"开发日志"、"changelog"、"最近改了什么"、"回顾改动"
- **输出**: `.cursor/changelog/entries/<author>/<id>.md` 与四个生成视图
- **路径**: .cursor/skills/dev-changelog/SKILL.md
### epee-orchestrator
- **类型**: 基础设施
- **能力**: 匹配已有 Skill、发现可复用工作流缺口并维护与磁盘一致的 Skill Registry
- **触发场景**: 手动配置密集、重复模式明确、步骤繁多、Skill 缺口发现、Registry 同步
- **输出**: Skill 分流或创建建议,以及 `.cursor/skills/epee-orchestrator/registry.md` 更新
- **路径**: .cursor/skills/epee-orchestrator/SKILL.md
### pitfall-journal
- **类型**: 基础设施
- **能力**: 记录开发中踩过的坑(非显而易见问题),在遇到同类问题时自动检索匹配已有经验
- **触发场景**: debug 完成、"踩坑"、"之前遇到过"、"坑"、进入 Debug mode、同类错误反复出现
- **输出**: .cursor/pitfalls/pitfalls.md 条目
- **能力**: 记录非显而易见问题的症状、根因、解法和防御措施,并在同类问题出现时检索
- **触发场景**: debug 完成、问题反复出现、"踩坑"、"之前遇到过"、进入 Debug mode
- **输出**: `.cursor/pitfalls/pitfalls.md` 条目或匹配到的既有经验
- **路径**: .cursor/skills/pitfall-journal/SKILL.md
### problem-distillery
- **类型**: 基础设施
- **能力**: 追踪反复出现的顽固问题,记录解决过程和弯路,定期蒸馏精炼方法论,经实践验证后自动升级为新会话常规注入
- **触发场景**: "还有问题"、"没解决"、"还是一样"、"又出现了"、"试了好多次"、"反复出现"、Agent 意识到同一问题尝试 2 次以上未解决、"蒸馏"、"总结经验"
- **输出**: .cursor/distillery/ 下的 problems.mdinsights.mdgolden-rules.md
- **能力**: 追踪反复未解决的问题,蒸馏方法论,并把经验证的 insight 升级为 Golden Rule
- **触发场景**: "还有问题"、"没解决"、"还是一样"、同一问题尝试两次以上、"蒸馏"、"总结经验"
- **输出**: `.cursor/distillery/problems.md``insights.md``golden-rules.md`
- **路径**: .cursor/skills/problem-distillery/SKILL.md
### profile-memory
- **类型**: 个人级
- **能力**: 在对话中被动检测用户个人特质和项目信息,经确认持久化为精简画像和详细日志
- **触发场景**: "画像"、"profile"、"我的偏好"、"查看画像"、"项目信息"、"查看项目画像"、用户主动管理画像
- **输出**: ~/.cursor/profile/user-profile.md、.cursor/profile/project-profile.md 及对应 log 文件
- **能力**: 检测并经确认持久化用户偏好与项目画像,支持查看、修改、删除和溯源
- **触发场景**: 持久偏好或项目决策出现、"画像"、"profile"、"我的偏好"、"查看项目画像"
- **输出**: 用户与项目的精简 Profile 及详细 Log
- **路径**: .cursor/skills/profile-memory/SKILL.md
### epee-orchestrator
- **类型**: 基础设施
- **能力**: 元层调度系统,检测任务是否可由已有 Skill 处理并分流,或发现 Skill 缺口并引导创建新 Skill同时负责 Skill Registry 维护
- **触发场景**: 手动配置密集、重复模式明确、手工指引过长的任务、Skill 缺口发现、Registry 同步维护
- **输出**: 分流决策(调用已有 Skill / 创建新 Skill、.cursor/skills/epee-orchestrator/registry.md 维护
- **路径**: .cursor/skills/epee-orchestrator/SKILL.md
- **备注**: 元层 Skill自身注册以便其他 Agent 了解调度能力的可用性
### html-doc
- **类型**: 个人级
- **能力**: 生成统一深色主题的单文件 HTML 文档,并可选提供本地暂存和回传批注功能
- **触发场景**: HTML 参考手册、说明页、报告、清单、统一 HTML 样式、可批注文档
- **输出**: 内联 CSS/JS 的自包含 `.html` 文档
- **路径**: .cursor/skills/html-doc/SKILL.md

View File

@@ -0,0 +1,88 @@
---
name: html-doc
description: >-
生成人类可读的单文件 HTML 文档(参考手册、报告、字段说明、清单等),统一深色主题
与版式(侧边目录 + 表格 + callout + 徽标 + 代码块),并可选挂载标准化的「批注模块」——
让读者逐字段/逐区块填备注、自动暂存、一键导出带备注的 HTML 副本回传,作者打开即见全部批注。
当用户要「做一份给人看的 HTML 文档/参考手册/说明页/报告」,或提到「统一 HTML 样式」、
「让别人写批注/注释」、「可批注文档」时使用。
---
# html-doc
把「给人阅读的 HTML 文档」标准化:统一主题 + 统一版式 + 可选批注模块。**产出单文件自包含 HTML**CSS/JS 全内联,一个 `.html` 直接发人)。
## 资产
| 文件 | 作用 | 生成时怎么用 |
|------|------|------|
| `assets/theme.css` | 通用深色主题tokens + 版式 + 表格/callout/徽标/目录/代码块) | 内联进 `<head><style>` |
| `assets/annotate.js` | 标准化批注模块(表格列 / 区块框、localStorage 暂存、导出嵌 JSON、复制 Markdown | 需批注时内联进末尾 `<script>` |
| `templates/skeleton.html` | 文档骨架(侧栏目录 + 正文 + 占位符) | 复制后填内容 |
> 三者是唯一真相源;改主题/批注逻辑只改 assets再重新生成文档。
## 生成工作流
```
1. 明确文档类型与章节结构(参考手册 / 报告 / 清单…)
2. 复制 templates/skeleton.html替换占位符
{{TITLE}} {{SUBTITLE}} {{DOC_ID}}(批注命名空间,用短横线英文,如 csv-data-reference
{{TOC_LINKS}} {{CONTENT}} {{FOOTER}}
3. 把 assets/theme.css 全部内容内联到 <head> 的 <style> 里(单文件自包含)
4. 按「组件速查」填正文;每章一个 <section id="...">,与目录 <a href="#..."> 对应
5. 若需批注 → 见「批注模块」:给目标加 data 属性 + 内联 annotate.js
6. 用 Read/ReadLints 自查;中文内容务必用文件工具写(勿用 PowerShell 重定向,见 baserule
```
## 组件速查
章节标题:`<h2 class="section">`(自带顶部分隔线);子标题 `<h3>`
目录项:`<a href="#id">主名<span class="cn">副名</span></a>`;分隔 `<div class="sep"></div>`
表格:标准 `<table><thead><tr><th>…</thead><tbody>…`。类型列用 `<td class="type">`
徽标(语义色,放 `<span class="badge X">``accent` / `ok` / `warn` / `danger` / `muted`
提示框:
```html
<div class="callout warn"><div class="t">标题</div><p>正文</p></div>
```
变体:默认(蓝)/ `warn` / `danger` / `ok`
其他:`.tag`(等宽 pill`.legend`(图例行)、`ul.tight`(紧凑列表)、`.muted`(弱化文字)、`<footer>`
配色改动只动 `theme.css``:root` design tokens。文档专属徽标追加在内联 theme 之后。
## 批注模块(可选)
目的:读者填备注 → 导出带备注的 HTML 发回 → 作者打开即见。纯前端、零依赖、幂等。
**接入三步**
1. `<body data-note-ns="文档唯一标识">`(骨架已留 `{{DOC_ID}}`;隔离不同文档的本地暂存)
2. 标记批注目标(二选一或混用):
- 表格模式:`<table data-annotate="唯一名">` → 每行自动追加一列「备注」
- 区块模式:任意元素加 `data-note-id="唯一名"` → 其后插入一个备注框
- 防行序漂移:可给某 `<tr>``data-note-id="稳定key"` 覆盖自动 key
3.`assets/annotate.js` 全部内容内联进末尾 `<script>`
**运行行为**:页头下方出现工具栏(导出带备注副本 / 复制 Markdown / 清空 / 已填计数);输入自动存 localStorage导出时克隆文档、剔除注入 UI、仅把备注以 `<script id="embedded-notes" type="application/json">` 嵌入 → 对方打开由脚本幂等重建并回填。
**恢复优先级**:嵌入 JSON > localStorage保证收到的回传文件一定显示对方批注
## 反模式
- 别用外链 CSS/JS破坏「一个文件发人」——一律内联。
- 别硬编码猜测批注目标(如靠表头文字)——用 `data-annotate` / `data-note-id` 显式 opt-in。
- 别手改 `embedded-notes` JSON —— 由模块导出维护。
- 中文文本别用 PowerShell `Set-Content`/`echo >` 落盘GBK 会损坏),用文件工具写。
## 自迭代日志
本节记录使用本 Skill 过程中发现的必要检查项。
### 已知必要检查
1. **单文件自包含** — 生成后确认 `theme.css`(及批注时的 `annotate.js`)已真正内联,页面无 `<link>`/外链 `<script src>`,否则发给别人会样式/功能丢失。
2. **批注命名空间唯一**`data-note-ns` 必须每份文档不同,否则不同文档的 localStorage 暂存互相污染。

View File

@@ -0,0 +1,232 @@
/* ============================================================
html-doc · 批注模块annotate.js
让读者在文档里逐字段/逐区块填备注,自动暂存到 localStorage
一键导出「把备注嵌进 JSON 的 HTML 副本」发回,对方打开即可看到全部批注。
用法(生成单文件文档时,把本文件全部内联进 <script>
1) 表格模式:给 <table> 加 data-annotate="唯一名",会为每行追加一列「备注」。
- 可选:给某个 <tr> 加 data-note-id="稳定key" 覆盖自动 key防行序漂移
2) 区块模式:给任意元素加 data-note-id="稳定key",其后会插入一个备注框。
3) 命名空间:给 <body> 加 data-note-ns="文档唯一标识",隔离不同文档的暂存。
纯前端、零依赖、幂等(重复打开导出的副本不会重复注入)。
============================================================ */
(function () {
"use strict";
var NS = (document.body && document.body.dataset.noteNs) || document.title || "html-doc";
var STORAGE_PREFIX = "htmldoc-note::" + NS + "::";
var NOTE_COL_LABEL = "备注 / 批注";
// 1. 读取上一份文件嵌入的备注(对方发回来的文件里带着)
var embedded = {};
var embEl = document.getElementById("embedded-notes");
if (embEl) {
try { embedded = JSON.parse(embEl.textContent || "{}"); } catch (e) { embedded = {}; }
}
// 2. 注入自带样式
var style = document.createElement("style");
style.id = "hd-note-style";
style.textContent = [
".hd-note-toolbar{position:sticky;top:0;z-index:30;display:flex;align-items:center;gap:10px;flex-wrap:wrap;",
"background:var(--panel,#171a21);border:1px solid var(--border,#2a2f3a);border-radius:10px;padding:12px 16px;",
"margin:0 0 24px;box-shadow:0 6px 18px rgba(0,0,0,.35)}",
".hd-note-toolbar .nt-title{font-weight:600;font-size:14px}",
".hd-note-toolbar .nt-count{color:var(--accent-2,#7ee0a2);font-size:12.5px}",
".hd-note-toolbar .nt-hint{color:var(--text-dim,#9aa1ad);font-size:12.5px;flex-basis:100%;margin-top:2px}",
".hd-note-btn{background:var(--panel-2,#1e222b);color:var(--text,#d7dbe2);border:1px solid var(--border,#2a2f3a);",
"border-radius:7px;padding:6px 12px;font-size:13px;cursor:pointer;font-family:inherit}",
".hd-note-btn:hover{border-color:var(--accent,#5aa9ff);color:var(--accent,#5aa9ff)}",
".hd-note-btn.primary{background:rgba(90,169,255,.14);border-color:rgba(90,169,255,.5);color:var(--accent,#5aa9ff)}",
".hd-note-btn.danger:hover{border-color:var(--danger,#ff6b6b);color:var(--danger,#ff6b6b)}",
"th.hd-note-col,td.hd-note-cell{min-width:200px}",
"textarea.hd-note{width:100%;background:var(--code-bg,#11141a);color:var(--text,#d7dbe2);",
"border:1px solid var(--border,#2a2f3a);border-radius:6px;padding:6px 8px;font-family:inherit;font-size:13px;",
"line-height:1.5;resize:vertical;min-height:38px}",
"textarea.hd-note:focus{outline:none;border-color:var(--accent,#5aa9ff)}",
"textarea.hd-note.filled{border-color:rgba(126,224,162,.5);background:rgba(126,224,162,.06)}",
".hd-note-block{margin:8px 0 18px}",
".hd-note-block .lbl{font-size:12px;color:var(--text-dim,#9aa1ad);margin-bottom:4px}"
].join("");
document.head.appendChild(style);
var entries = []; // {key, label, group, ta}
function restore(key) {
if (Object.prototype.hasOwnProperty.call(embedded, key)) return embedded[key]; // 收到的文件优先显示对方批注
var ls = localStorage.getItem(STORAGE_PREFIX + key);
return ls !== null ? ls : "";
}
function makeTextarea(key, label, group) {
var ta = document.createElement("textarea");
ta.className = "hd-note";
ta.rows = 2;
ta.placeholder = "在此填写备注…";
ta.dataset.key = key;
var val = restore(key);
ta.value = val;
if (val.trim()) ta.classList.add("filled");
ta.addEventListener("input", function () {
localStorage.setItem(STORAGE_PREFIX + key, ta.value);
ta.classList.toggle("filled", ta.value.trim() !== "");
updateCount();
});
entries.push({ key: key, label: label, group: group, ta: ta });
return ta;
}
// 3a. 表格模式table[data-annotate]
var annTables = document.querySelectorAll("table[data-annotate]");
Array.prototype.forEach.call(annTables, function (table, ti) {
var tableKey = table.getAttribute("data-annotate") || ("table" + ti);
var section = table.closest("section");
var h2 = section ? section.querySelector("h2.section, h2, h3") : null;
var group = h2 ? h2.textContent.trim() : tableKey;
var headRow = table.querySelector("thead tr");
if (headRow) {
var th = document.createElement("th");
th.className = "hd-note-col";
th.textContent = NOTE_COL_LABEL;
headRow.appendChild(th);
}
var rows = table.querySelectorAll("tbody tr");
Array.prototype.forEach.call(rows, function (tr, idx) {
var firstCell = tr.querySelector("td");
var label = firstCell ? firstCell.textContent.trim() : ("行" + idx);
var key = tr.getAttribute("data-note-id") || (tableKey + "::" + idx + "::" + label);
var td = document.createElement("td");
td.className = "hd-note-cell";
td.appendChild(makeTextarea(key, label, group));
tr.appendChild(td);
});
});
// 3b. 区块模式:任意 [data-note-id](表格行已在上面处理,这里排除)
var blocks = document.querySelectorAll("[data-note-id]");
Array.prototype.forEach.call(blocks, function (el) {
if (el.tagName === "TR" || el.closest("table[data-annotate]")) return;
var key = el.getAttribute("data-note-id");
var section = el.closest("section");
var h2 = section ? section.querySelector("h2.section, h2, h3") : null;
var group = h2 ? h2.textContent.trim() : "区块批注";
var label = (el.textContent || "").trim().slice(0, 40) || key;
var wrap = document.createElement("div");
wrap.className = "hd-note-block";
var lbl = document.createElement("div");
lbl.className = "lbl";
lbl.textContent = NOTE_COL_LABEL;
wrap.appendChild(lbl);
wrap.appendChild(makeTextarea(key, label, group));
if (el.nextSibling) el.parentNode.insertBefore(wrap, el.nextSibling);
else el.parentNode.appendChild(wrap);
});
if (!entries.length) return; // 没有任何批注目标就不加工具栏
// 4. 工具栏
var bar = document.createElement("div");
bar.className = "hd-note-toolbar";
bar.innerHTML =
'<span class="nt-title">批注模式</span>' +
'<span class="nt-count" id="hdNoteCount">已填 0 条</span>' +
'<button class="hd-note-btn primary" id="hdBtnExport">导出带备注的副本 (.html)</button>' +
'<button class="hd-note-btn" id="hdBtnMd">复制备注为 Markdown</button>' +
'<button class="hd-note-btn danger" id="hdBtnClear">清空本地备注</button>' +
'<span class="nt-hint">填写会自动暂存到本机浏览器;填完点「导出带备注的副本」下载一份 HTML 发回即可,对方打开就能看到所有批注。</span>';
var main = document.querySelector("main") || document.body;
var head = main.querySelector("header.page-head");
if (head && head.nextSibling) main.insertBefore(bar, head.nextSibling);
else main.insertBefore(bar, main.firstChild);
function collect() {
var out = {};
entries.forEach(function (e) { if (e.ta.value.trim() !== "") out[e.key] = e.ta.value; });
return out;
}
function updateCount() {
var n = entries.filter(function (e) { return e.ta.value.trim() !== ""; }).length;
var el = document.getElementById("hdNoteCount");
if (el) el.textContent = "已填 " + n + " 条";
}
updateCount();
function pad(n) { return (n < 10 ? "0" : "") + n; }
function stamp() {
var d = new Date();
return "" + d.getFullYear() + pad(d.getMonth() + 1) + pad(d.getDate()) + "-" + pad(d.getHours()) + pad(d.getMinutes());
}
function flash(btn, msg) {
if (!btn) return;
var old = btn.textContent;
btn.textContent = msg;
setTimeout(function () { btn.textContent = old; }, 1500);
}
// 5. 导出:克隆文档 → 剔除注入的 UI → 仅嵌入备注 JSON再次打开由本脚本幂等重建
function exportHtml() {
var data = collect();
var clone = document.documentElement.cloneNode(true);
clone.querySelectorAll(".hd-note-col,.hd-note-cell,.hd-note-block,.hd-note-toolbar,#hd-note-style,#embedded-notes")
.forEach(function (el) { el.parentNode.removeChild(el); });
var s = document.createElement("script");
s.type = "application/json";
s.id = "embedded-notes";
s.textContent = JSON.stringify(data, null, 2);
clone.querySelector("body").appendChild(s);
var html = "<!DOCTYPE html>\n" + clone.outerHTML;
var blob = new Blob([html], { type: "text/html;charset=utf-8" });
var a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "notes-" + NS.replace(/[^a-zA-Z0-9_-]+/g, "_") + "-" + stamp() + ".html";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(a.href);
}
// 6. 复制为 Markdown按 group 分组)
function toMarkdown() {
var byGroup = {}, order = [];
entries.forEach(function (e) {
if (e.ta.value.trim() === "") return;
if (!byGroup[e.group]) { byGroup[e.group] = []; order.push(e.group); }
byGroup[e.group].push("- **" + e.label + "**: " + e.ta.value.replace(/\n+/g, " "));
});
if (!order.length) return "(暂无备注)";
var lines = ["# " + NS + " · 批注", ""];
order.forEach(function (g) { lines.push("## " + g); lines.push.apply(lines, byGroup[g]); lines.push(""); });
return lines.join("\n");
}
function copyMd() {
var md = toMarkdown();
var done = function () { flash(document.getElementById("hdBtnMd"), "已复制 Markdown"); };
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(md).then(done, function () { fallbackCopy(md, done); });
} else { fallbackCopy(md, done); }
}
function fallbackCopy(text, cb) {
var t = document.createElement("textarea");
t.value = text; t.style.position = "fixed"; t.style.opacity = "0";
document.body.appendChild(t); t.select();
try { document.execCommand("copy"); } catch (e) {}
document.body.removeChild(t); if (cb) cb();
}
function clearAll() {
if (!window.confirm("确定清空本机暂存的所有备注?(不影响已导出的文件)")) return;
entries.forEach(function (e) {
localStorage.removeItem(STORAGE_PREFIX + e.key);
e.ta.value = ""; e.ta.classList.remove("filled");
});
updateCount();
}
var be = document.getElementById("hdBtnExport");
var bm = document.getElementById("hdBtnMd");
var bc = document.getElementById("hdBtnClear");
if (be) be.addEventListener("click", exportHtml);
if (bm) bm.addEventListener("click", copyMd);
if (bc) bc.addEventListener("click", clearAll);
})();

View File

@@ -0,0 +1,195 @@
/* ============================================================
html-doc · 通用深色主题
人类可读 HTML 文档的统一表现层。生成单文件文档时,把本文件
全部内容内联进 <style>。design tokens 集中在 :root改配色只动这里。
============================================================ */
:root {
--bg: #0f1115;
--panel: #171a21;
--panel-2: #1e222b;
--border: #2a2f3a;
--text: #d7dbe2;
--text-dim: #9aa1ad;
--accent: #5aa9ff;
--accent-2: #7ee0a2;
--warn: #ffb454;
--danger: #ff6b6b;
--code-bg: #11141a;
--mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
--sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: var(--sans);
line-height: 1.6;
font-size: 15px;
}
/* ---------- 布局:侧边目录 + 正文 ---------- */
.layout { display: flex; align-items: flex-start; }
nav.toc {
position: sticky;
top: 0;
align-self: flex-start;
width: 260px;
height: 100vh;
overflow-y: auto;
background: var(--panel);
border-right: 1px solid var(--border);
padding: 20px 16px;
flex-shrink: 0;
}
nav.toc h2 {
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-dim);
margin: 0 0 12px;
}
nav.toc a {
display: block;
color: var(--text);
text-decoration: none;
padding: 6px 10px;
border-radius: 6px;
font-size: 14px;
margin-bottom: 2px;
}
nav.toc a:hover { background: var(--panel-2); color: var(--accent); }
nav.toc a .cn { color: var(--text-dim); font-size: 12px; margin-left: 6px; }
nav.toc .sep { height: 1px; background: var(--border); margin: 12px 4px; }
main {
flex: 1;
max-width: 1080px;
margin: 0 auto;
padding: 40px 48px 120px;
min-width: 0;
}
/* ---------- 标题与正文 ---------- */
header.page-head { margin-bottom: 32px; }
header.page-head h1 { font-size: 30px; margin: 0 0 8px; }
header.page-head p.sub { color: var(--text-dim); margin: 0; }
h2.section {
font-size: 24px;
margin: 48px 0 6px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
h2.section:first-of-type { border-top: none; }
h3 { font-size: 19px; margin: 32px 0 10px; }
.file-title { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.file-title code { font-size: 18px; }
.cnname { color: var(--text-dim); font-size: 15px; }
p { margin: 10px 0; }
a.link { color: var(--accent); }
.muted { color: var(--text-dim); }
/* ---------- 代码 ---------- */
code {
font-family: var(--mono);
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 4px;
padding: 1px 5px;
font-size: 13px;
color: #e6c07b;
}
pre {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 8px;
padding: 14px 16px;
overflow-x: auto;
font-family: var(--mono);
font-size: 13px;
line-height: 1.55;
}
pre code { background: none; border: none; padding: 0; color: var(--text); }
/* ---------- 表格 ---------- */
table {
width: 100%;
border-collapse: collapse;
margin: 14px 0 6px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
font-size: 14px;
}
thead th {
text-align: left;
background: var(--panel-2);
color: var(--text-dim);
font-weight: 600;
padding: 10px 12px;
border-bottom: 1px solid var(--border);
white-space: nowrap;
}
tbody td { padding: 9px 12px; border-bottom: 1px solid var(--border); vertical-align: top; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--panel-2); }
td.type { color: var(--warn); font-family: var(--mono); font-size: 12.5px; white-space: nowrap; }
/* ---------- 徽标(语义色)---------- */
.badge {
display: inline-block;
font-size: 11px;
padding: 1px 7px;
border-radius: 999px;
border: 1px solid var(--border);
white-space: nowrap;
line-height: 1.5;
}
.badge.accent { background: rgba(90,169,255,0.14); color: var(--accent); border-color: rgba(90,169,255,0.4); }
.badge.ok { background: rgba(126,224,162,0.12); color: var(--accent-2); border-color: rgba(126,224,162,0.35); }
.badge.warn { background: rgba(255,180,84,0.10); color: var(--warn); border-color: rgba(255,180,84,0.3); }
.badge.danger { background: rgba(255,107,107,0.12); color: var(--danger); border-color: rgba(255,107,107,0.4); }
.badge.muted { background: rgba(154,161,173,0.10); color: var(--text-dim); }
/* ---------- 提示框 ---------- */
.callout {
border-left: 3px solid var(--accent);
background: var(--panel);
border-radius: 0 8px 8px 0;
padding: 12px 16px;
margin: 16px 0;
}
.callout.warn { border-left-color: var(--warn); }
.callout.danger { border-left-color: var(--danger); }
.callout.ok { border-left-color: var(--accent-2); }
.callout .t { font-weight: 600; margin-bottom: 4px; }
/* ---------- 通用 pill / 标签 ---------- */
.tag {
display: inline-block;
background: var(--panel-2);
border: 1px solid var(--border);
border-radius: 6px;
padding: 3px 9px;
font-family: var(--mono);
font-size: 12.5px;
color: var(--accent);
margin: 4px 6px 4px 0;
}
/* ---------- 图例 / 列表 ---------- */
.legend { display: flex; gap: 14px; flex-wrap: wrap; margin: 10px 0 0; font-size: 13px; color: var(--text-dim); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
ul.tight { margin: 8px 0; padding-left: 22px; }
ul.tight li { margin: 3px 0; }
footer { margin-top: 60px; padding-top: 20px; border-top: 1px solid var(--border); color: var(--text-dim); font-size: 13px; }
@media (max-width: 860px) {
nav.toc { display: none; }
main { padding: 24px 18px 80px; }
}

View File

@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{TITLE}}</title>
<style>
/* [html-doc] 生成时:把 assets/theme.css 的全部内容内联到这里(保证单文件自包含)。
如需文档专属徽标/样式,追加在 theme.css 内容之后即可。 */
</style>
</head>
<body data-note-ns="{{DOC_ID}}">
<div class="layout">
<nav class="toc">
<h2>目录</h2>
<!-- {{TOC_LINKS}} 例:<a href="#sec1">章节一<span class="cn">副标题</span></a>
分隔线用 <div class="sep"></div> -->
</nav>
<main>
<header class="page-head">
<h1>{{TITLE}}</h1>
<p class="sub">{{SUBTITLE}}</p>
</header>
<!-- {{CONTENT}}
每个章节: <section id="sec1"><h2 class="section">标题</h2> ... </section>
组件速查见 SKILL.md「组件速查」。 -->
<footer>{{FOOTER}}</footer>
</main>
</div>
<!-- [html-doc] 需要批注功能时:
1) 给要批注的 <table> 加 data-annotate="唯一名";或给任意区块加 data-note-id="唯一名"
2) 把 assets/annotate.js 的全部内容内联到下面的 <script> 中并取消注释 -->
<!-- <script>/* INLINE assets/annotate.js */</script> -->
</body>
</html>