199 lines
8.0 KiB
Markdown
199 lines
8.0 KiB
Markdown
# Cursor Init Reference
|
||
|
||
本文件说明多类型初始化的数据契约和验收规则。机器真相源是 `.cursor/bootstrap/*.json`;
|
||
流程入口是 [SKILL.md](SKILL.md)。不得在本文件重新维护固定 Rule/Skill 数量。
|
||
|
||
## 1. 目录边界
|
||
|
||
```text
|
||
.cursor/
|
||
├─ bootstrap/ # tracked、惰性、自包含可信源
|
||
│ ├─ catalog.json # 支持类型与状态
|
||
│ ├─ common.manifest.json # common canonical、重置与公共策略
|
||
│ ├─ skills.json # 全部 Skill 与 Registry 元数据
|
||
│ ├─ fragments/ # common Git managed block 片段
|
||
│ ├─ templates/ # 状态与空 changelog 模板
|
||
│ ├─ tools/cursor_init.py # dry-run/apply/check 引擎
|
||
│ ├─ tests/test_cursor_init.py
|
||
│ └─ types/<type>/
|
||
│ ├─ manifest.json
|
||
│ ├─ fragments/
|
||
│ └─ payload/ # 未选时不会进入 Cursor 活动目录
|
||
├─ rules/common/ # 始终活动
|
||
├─ rules/project/ # 只含所选类型;general 时仅 .gitkeep
|
||
├─ skills/ # common + 所选类型 Skill
|
||
├─ hooks/changelog-scan.json # 按类型生成的活动扫描策略
|
||
├─ .init-state.json # managed payload 文件 hash
|
||
└─ .init-done # 全部验证通过后的提交标记
|
||
```
|
||
|
||
### 保护边界
|
||
|
||
- `.cursor/bootstrap/**` 永不被 cleanup、类型切换或 reset 修改。
|
||
- common 只在活动层保存一份;缺失时阻塞,不从不明来源生成空文件。
|
||
- payload 中的 `.mdc` / `SKILL.md` 不位于 Cursor 活动路径,未选类型不得物化。
|
||
- `source/` 和业务目录不属于初始化管理范围。
|
||
|
||
## 2. Catalog
|
||
|
||
`.cursor/bootstrap/catalog.json` 字段:
|
||
|
||
- `schema_version`:当前为 `1`;
|
||
- `skill_version`:sentinel 使用的初始化契约版本;
|
||
- `common_manifest`、`skills_catalog`:相对 bootstrap 的安全路径;
|
||
- `types[]`:`id`、用户标签 `label`、`status` 与 manifest 路径。
|
||
|
||
合法状态只有:
|
||
|
||
- `ready`:payload 和片段完整且可通过校验;会出现在 `--list-types`;
|
||
- `draft`:允许保留设计占位,但不会暴露给用户,也不能 dry-run/apply。
|
||
|
||
Agent 只能展示脚本返回的 ready 类型,不从文档、MCP 或目录名猜测支持范围。
|
||
|
||
## 3. Common Manifest
|
||
|
||
`.cursor/bootstrap/common.manifest.json` 是跨类型契约:
|
||
|
||
- `canonical_files`:必须存在的活动 common 文件;
|
||
- `skills`:始终活动的 Skill ID;
|
||
- `local_env_fields`:所有类型都声明的本机字段;是否由初始化采集由字段元数据决定;
|
||
- `scan`:Hook 公共扫描策略;
|
||
- `gitignore_fragments` / `gitattributes_fragments`:公共 Git 片段;
|
||
- `reset_files`:初始化时恢复为空模板的状态文件;
|
||
- `cleanup_globs`:确认后删除的历史 fragment、缓存、备份和运行标记。
|
||
|
||
所有路径必须是项目根或 manifest 根内的相对路径;`..` 与绝对路径非法。
|
||
|
||
## 4. Type Manifest
|
||
|
||
每个 `.cursor/bootstrap/types/<type>/manifest.json` 声明:
|
||
|
||
- `id`、`version`;
|
||
- `readiness`:是否允许空 payload,以及 ready 时是否强制要求 scan / gitignore;
|
||
- `files[]`:单文件 source → 活动 target;
|
||
- `trees[]`:完整目录 source → 活动 target,适合项目专属 Skill;
|
||
- `skills[]`:该类型激活的 Skill ID;
|
||
- `local_env_fields`:仅选择该类型时生成;是否由初始化采集由字段元数据决定;
|
||
- `scan`:与 common 合并的 Hook 文件名、扩展名和排除目录;
|
||
- Git managed block 片段。
|
||
|
||
`general` 表示 common-only,不物化 project Rule/Skill。类型切换时,只删除已知 managed
|
||
且 hash 未被用户修改的旧 bundle 文件;用户改动过的文件必须成为阻塞项。
|
||
|
||
## 5. Skill Registry
|
||
|
||
`.cursor/bootstrap/skills.json` 保存每个 Skill 的:
|
||
|
||
- `id`、`scope`、活动 `target`;
|
||
- Registry 的类型、能力、触发场景和输出。
|
||
|
||
common manifest 和 type manifest 只引用 Skill ID。初始化脚本按活动 ID 生成
|
||
`.cursor/skills/epee-orchestrator/registry.md`,并验证对应目录存在 `SKILL.md`。
|
||
创建、删除、重命名或实质修改 Skill 时,先更新 `skills.json` 与所属 manifest,再重新生成 Registry。
|
||
|
||
## 6. Dry-run 与所有权
|
||
|
||
dry-run 至少包含:
|
||
|
||
```text
|
||
创建 / 更新 / 删除
|
||
Foreign
|
||
阻塞
|
||
PLAN_DIGEST
|
||
```
|
||
|
||
阻塞条件包括:
|
||
|
||
- common canonical、ready payload 或片段缺失;
|
||
- 活动目录存在 manifest 未登记的 Rule/Skill;
|
||
- managed 文件内容既不等于 payload,也不等于 `.init-state.json` 记录的安装 hash;
|
||
- 本机必填字段缺失;
|
||
- Git managed block 标记缺失一端、重复或损坏;
|
||
- 路径越界或 schema 无效。
|
||
|
||
Apply 必须重算同一份计划并比对 digest。只有无阻塞计划才可执行。
|
||
|
||
## 7. 生成文件
|
||
|
||
### `local-env.example.json` / `local-env.json`
|
||
|
||
common 与所选类型的 `local_env_fields` 按顺序合并。每个字段可使用:
|
||
|
||
- `required`:初始化完成前是否必须提供;
|
||
- `sensitive`:值是否属于密钥等敏感信息;
|
||
- `collect_at_init`:初始化问卷和 `--set` 是否允许采集。
|
||
|
||
example 可提交且只能包含占位值;local-env 保留未知键和已有用户值,并由 `.gitignore`
|
||
忽略。只有非 sensitive 且 `collect_at_init` 未设为 `false` 的字段才允许通过
|
||
`--set KEY=VALUE` 提供。敏感字段不阻塞初始化,也不参与状态漂移,真实值必须由用户
|
||
手工写入 `.cursor/local-env.json`;不得保存密码、Cookie 或会话令牌。
|
||
|
||
### `changelog-scan.json`
|
||
|
||
common + type 的 `included_names`、`included_extensions`、`excluded_directories` 去重合并。
|
||
PowerShell/Bash Hook 只读取此文件;会话标记、Git 内容状态与 mtime 的守卫逻辑留在脚本中。
|
||
|
||
### Git managed blocks
|
||
|
||
脚本只维护以下标记之间的内容:
|
||
|
||
```text
|
||
# >>> cursor-init managed >>>
|
||
...
|
||
# <<< cursor-init managed <<<
|
||
```
|
||
|
||
标记外用户内容不得覆盖。选择 `--skip-git-files` 时不改 `.gitignore` / `.gitattributes`,
|
||
sentinel 写 `gitignore_generated: false`。
|
||
|
||
### `.init-state.json`
|
||
|
||
记录当前项目类型、bundle 版本、manifest digest 与已物化 payload 文件 hash,用于区分
|
||
bundle 升级和用户修改。它需要提交,不能包含本机绝对路径或秘密。
|
||
|
||
## 8. Sentinel
|
||
|
||
`.cursor/.init-done` 仅在 apply 后活动闭包再次验证通过时写入:
|
||
|
||
```yaml
|
||
initialized_by: cursor-init
|
||
initialized_at: <ISO_DATETIME>
|
||
schema_version: 1
|
||
skill_version: <catalog.skill_version>
|
||
project_type: <single-ready-type>
|
||
bundle_version: <type-manifest.version>
|
||
manifest_digest: <sha256>
|
||
gitignore_generated: true|false
|
||
```
|
||
|
||
sentinel 和 `.init-state.json` 字段必须与当前 manifest 一致。取消、摘要变化、部分写入或验证失败
|
||
都不得创建/更新 sentinel。
|
||
|
||
## 9. Hook 契约
|
||
|
||
`check-changelog.ps1` 与 `.sh` 必须保持相同行为:
|
||
|
||
1. 非 Agent mode、缺 changelog、缺 scan config、缺 `.session-start` 时返回 `{}`;
|
||
2. Git 不可用、状态失败或工作区无内容差异时返回 `{}`;
|
||
3. 只扫描活动配置命中的文件,并要求 mtime 晚于 session/changelog;
|
||
4. 候选路径还必须被 `git status --porcelain` 判定为未提交改动;
|
||
5. 任意解析或运行错误 fail-open,不阻断用户。
|
||
|
||
回归测试入口:
|
||
|
||
```bash
|
||
python .cursor/hooks/tests/test_check_changelog.py
|
||
```
|
||
|
||
## 10. 验收
|
||
|
||
初始化或重置完成后:
|
||
|
||
- `python .cursor/bootstrap/tools/cursor_init.py --check` 通过;
|
||
- 活动 project Rules/Skills 与单选类型闭包完全一致,未选 payload 仍惰性保留;
|
||
- Registry、scan config、local-env example、Git managed blocks 与 manifest 一致;
|
||
- cleanup 后 changelog entries 仅有 `.gitkeep`,状态文件等于模板;
|
||
- `python .cursor/changelog/tools/changelog_build.py --check` 通过;
|
||
- Hook 双实现测试、初始化引擎测试、`git diff --check` 通过;
|
||
- 本轮写入文本为 UTF-8 无 BOM、LF。
|