dsh-notes-board 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +7 -0
- package/README.md +115 -13
- package/index.js +21 -178
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +31 -8
- package/scripts/test-board.mjs +15 -1
- package/src/core/notes.js +486 -0
- package/src/core/tools.js +221 -0
- package/src/host/board.js +184 -0
- package/src/host/notes.js +250 -0
- package/src/host/skills.js +48 -0
- package/vendor/write-notes-like-deepseek/README.md +323 -0
- package/vendor/write-notes-like-deepseek/package.json +21 -0
- package/vendor/write-notes-like-deepseek/scripts/export-assets.sh +40 -0
- package/vendor/write-notes-like-deepseek/scripts/import-dsh-notes.ts +125 -0
- package/vendor/write-notes-like-deepseek/scripts/test-skill-install.mjs +63 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/SKILL.md +195 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/assets/agent-notes-board.html +1779 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/archiving.md +109 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/classification.md +33 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/note-format.md +69 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/prose-checklist.md +51 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/quality-gate.md +58 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/simplification-checklist.md +26 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/verification.md +34 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/when-to-write.md +83 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/agent-note-tree.ts +75 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/archive-agent-note.ts +167 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/build-board.ts +235 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/check-note-anchors.ts +103 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/verify-agent-note-format.ts +158 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/verify-agent-note-tree.ts +56 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts +127 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/implemented.md +32 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/proposed.md +38 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/rejected.md +27 -0
- package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/verify-notes.yml +38 -0
package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/archiving.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# 按需阅读:归档、生命周期治理与冻结机制
|
|
2
|
+
|
|
3
|
+
> 提炼自 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的 notes 治理实践。收尾、复盘或大版本跃迁时对照;日常改动零负担,仅顺手就近替代。
|
|
4
|
+
|
|
5
|
+
**目录**:§0 执行频次(日常顺手 vs 大扫除)|§1 过时判定与保留红线(1.1 免检保留 / 1.2 归档标准 / 1.3 垃圾清理 / 1.4 校准示例)|§2 归档的标准操作流(CLI)|§3 永久冻结契约
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 0. 执行频次:日常顺手 vs 里程碑大扫除
|
|
10
|
+
|
|
11
|
+
无需每次修改代码都全量扫描,根据场景分级执行:
|
|
12
|
+
|
|
13
|
+
1. **日常提交(90% 场景:零全量心智负担)**:
|
|
14
|
+
- **就地修改(80%)**:改了某模块,顺手更新持有该决定的现成 Note 事实。
|
|
15
|
+
- **当场审计(10%)**:新增 Note 时,按模块名/关键词搜活跃笔记,当场分类(无关 / 部分重叠互链 / 完全吸收后删或归档 / 过时提案 reject 或删)。禁止把已知匹配推迟到大扫除。
|
|
16
|
+
2. **里程碑大扫除(10% 场景:按需治理)**:
|
|
17
|
+
- 仅处理当时搜不到的漏网:季度复盘、大版本发布、或活跃 Note 累积过多影响检索时,集中扫一次。
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. 过时判定与保留红线
|
|
22
|
+
|
|
23
|
+
判断是否过时**不看字数多少,也不看存续时间长短**,严格依据「未来防撞护栏价值」:
|
|
24
|
+
|
|
25
|
+
### 1.1 活跃区免检保留红线(即使年代久远也必须保留在 `implemented/`)
|
|
26
|
+
只要符合以下任一特征,绝对不过时,严禁归档:
|
|
27
|
+
- **所有权边界**:明确界定了模块调用权限与架构职责划分(如"UI 层严禁直接直连 DB")。
|
|
28
|
+
- **否定性保证(Negative Guarantees)**:明确承诺"绝不提供某项能力"或"永不向后兼容某旧协议"。
|
|
29
|
+
- **安全与合规底线**:防止注入、鉴权绕过或数据泄露的刚性约束。
|
|
30
|
+
- **易复踩的被否决方案(Alternatives considered)**:记录了极具诱惑力但在实践中已被证明会导致死锁/崩溃的错误路线。
|
|
31
|
+
|
|
32
|
+
### 1.2 归档标准(移入 `archived/`)
|
|
33
|
+
仅对 `implemented/` 中满足以下条件的记录执行归档:
|
|
34
|
+
- **被新架构完全取代但仍有独立杠杆**:后续 Note 已吸收核心逻辑,旧篇还留着否定性保证 / 所有权边界 / 重新引入条件——归档,互链写在新笔记。能删则删,见 `references/when-to-write.md` §4。
|
|
35
|
+
- **一次性设计与窄细节**:一次性 UI 边距调整、已废弃平台的狭窄单点适配器、已彻底闭环的简单 bug 修补。
|
|
36
|
+
|
|
37
|
+
### 1.3 垃圾清理规则(不进归档树)
|
|
38
|
+
- **`proposed/` 绝不归档**:前提消失(如依赖升级自带该能力)或不再推进的提案,直接转为 `Status: rejected — <一句话原因>`;已在其他方案中吸收的直接关闭。
|
|
39
|
+
- **无价值 `rejected/` 物理删除**:若被否决方案所依赖的旧技术/API 已被彻底移除,未来 Agent 绝无可能再提出该错误路线,直接将文件物理删除,不留冗余。
|
|
40
|
+
|
|
41
|
+
### 1.4 校准示例(立标用;词数证明篇幅不是标准)
|
|
42
|
+
|
|
43
|
+
移植自 DeepSeek Harness 的归档 skill。判断时对标示例的**理由结构**,别对标词数。
|
|
44
|
+
|
|
45
|
+
**该归档的 implemented(决定已完成、理由 unlikely 再指导未来工作):**
|
|
46
|
+
|
|
47
|
+
- 折叠侧边栏控制栏(~530 词)——已闭环的次要 UI 行为;
|
|
48
|
+
- 某 CLI 参数适配器(~1,500 词)——实现细节很重,但对未来设计几乎没有杠杆;
|
|
49
|
+
- 文档生成管线(~920 词)——机器已完成使命,现行生成器本身就是权威。
|
|
50
|
+
|
|
51
|
+
**该保留的 implemented(理由仍 owning 或 constraining 什么):**
|
|
52
|
+
|
|
53
|
+
- 事件溯源会话存储(~250 词)——基础性权威与持久化边界;
|
|
54
|
+
- 跨产品所有权解析规则(~600 词)——一条所有权边界立法;
|
|
55
|
+
- 项目会话目录策略(~630 词)—— durable 存储与身份策略;
|
|
56
|
+
- 并行 pre-push 门禁(~400 词)——边界案例,但仍指导门禁排程;
|
|
57
|
+
- 已下线的图片内容块(~330 词)——保留,直到多模态落地:它写着协调好的重引入条件。
|
|
58
|
+
|
|
59
|
+
**rejected 的存与删:**
|
|
60
|
+
|
|
61
|
+
- 保留「合并压缩包拆分」(~430 词)——合并的诱惑仍在,防重犯价值还在;
|
|
62
|
+
- 删除「经工具调用推送流式进度」(~970 词)——其 ACP/UI 前提已过时;
|
|
63
|
+
- 删除「去掉 ACP 终端元数据」(~360 词)——后来的自动化决策已经回答了这个问题。
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 2. 归档的标准操作流
|
|
68
|
+
|
|
69
|
+
推荐直接用 CLI(物理移动 + 封印 + 入站死链报告一次完成,**不依赖 git**):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx tsx .agents/skills/write-notes-like-deepseek/scripts/archive-agent-note.ts \
|
|
73
|
+
.agents/notes/implemented/<class>/<filename>.md \
|
|
74
|
+
[--superseded-by .agents/notes/implemented/<class>/<新笔记>.md]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
CLI 依次完成:
|
|
78
|
+
|
|
79
|
+
1. **写头部标记**:`Archived: YYYY-MM-DD` **紧邻** `Status: implemented` 插入(L3/L4 之间不留空行——这是与 DSH 原版对齐的硬契约,封印校验器逐行核对):
|
|
80
|
+
```markdown
|
|
81
|
+
# Agent Note: xxx
|
|
82
|
+
|
|
83
|
+
Status: implemented
|
|
84
|
+
Archived: 2026-08-31
|
|
85
|
+
|
|
86
|
+
## Problem
|
|
87
|
+
...
|
|
88
|
+
```
|
|
89
|
+
2. **物理移动**:`implemented/<class>/...` → `archived/<class>/...`(git 场景建议用 `git mv` 保留历史,CLI 用文件移动实现,无 git 同样工作)。
|
|
90
|
+
3. **封印入 `archived/manifest.json`**:记录该文件的 SHA-256。封印后任何对归档内容的篡改都会被 `verify-archived` 报警。
|
|
91
|
+
4. **入站死链报告**:扫描活跃笔记里指向该笔记的 Markdown 相对链接(精确链接解析,非文本子串),列出需人工修复的清单。
|
|
92
|
+
5. **可选 `--superseded-by`**:校验新笔记存在,并在**新笔记**末尾补一条指向归档路径的相对链接。不改归档篇。
|
|
93
|
+
|
|
94
|
+
除头部 `Archived:` 一行外,**禁止修改归档正文的任何其他字符**。
|
|
95
|
+
|
|
96
|
+
> 历史包袱补齐:若 `archived/` 已有笔记但还没有 manifest(例如从 DSH 导入的语料),运行
|
|
97
|
+
> `npx tsx .agents/skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts --write` 一次性补封印——它会先校验既有封印未被改动,再追加缺失条目,绝不重写历史。
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 3. 永久冻结契约(Frozen Immutable Contract)
|
|
102
|
+
|
|
103
|
+
一旦进入 `archived/`:
|
|
104
|
+
- **永久只读**:严禁编辑、翻译、重排版、更新、移动或删除。
|
|
105
|
+
- **机械强制**:`verify-archived` 校验头部布局、manifest 哈希、以及封印的 append-only(有 git 时与基线 ref 对比,`AGENT_NOTE_ARCHIVE_BASE_REF` 可指定基线,默认 HEAD;无 git 自动降级为哈希自校验并提示)。封印只增不改,已封印条目被改动或删除即报错。
|
|
106
|
+
- **免除日常扫描**:`verify-agent-note-tree` 和 `verify-agent-note-format` 默认跳过 `archived/` 目录,归档文件的出站链接失效不会阻塞日常构建。
|
|
107
|
+
- **不可作为当前行为依据**:代码冲突或架构评审时,以 `implemented/` 为准,`archived/` 仅作为历史考据参考;取代关系以新笔记互链和入站改写为准。
|
|
108
|
+
|
|
109
|
+
上述命令从宿主项目根目录执行;若 Skill 安装在其他位置,请替换 `.agents/skills/write-notes-like-deepseek` 为实际路径。
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 按需阅读:Class 分类
|
|
2
|
+
|
|
3
|
+
> SKILL §1 的展开。新建 Note 选 class 时对照。
|
|
4
|
+
|
|
5
|
+
## 封闭集(6 个,再加要改检查脚本)
|
|
6
|
+
|
|
7
|
+
| Class | 覆盖范围 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `feature` | 新增面向用户或模型的能力 |
|
|
10
|
+
| `bug-fix` | 修缺陷或补 postmortem 暴露的缺口 |
|
|
11
|
+
| `simplification` | 不新增能力的前提下删代码/行为/表面 |
|
|
12
|
+
| `architecture` | 已发布源码的结构性决定——包如何关联、运行时词汇是什么 |
|
|
13
|
+
| `process` | 代码之外的工具/策略/流程——门禁、包管理、vendoring 等 |
|
|
14
|
+
| `testing` | 测试 infra 与策略 |
|
|
15
|
+
|
|
16
|
+
判定技巧:
|
|
17
|
+
|
|
18
|
+
- `architecture` vs `process`:前者是"发出去的源码长什么样",后者是"围绕源码的工具链与工作流"。
|
|
19
|
+
- `refactor` 不单列——用 `simplification` 的判据"可观察行为变了吗"区分;行为不变即 simplification,行为变了归对应 feature/bug-fix/architecture。
|
|
20
|
+
- `feature` 不只在"新增能力"时用——**用户/模型可见、不显然的行为或产品选择,changes 够不上架构,也归 `feature`**。判据是"行为是否可被用户或下游观察",而不是"改动了多少代码"。只有局部实现细节、普通重构、行为不变的依赖补丁才不写任何 Note。
|
|
21
|
+
- 拿不准时看这条 Note 以后会被谁检索:找能力演进看 `feature`,找结构决策看 `architecture`,找门禁/发布看 `process`。
|
|
22
|
+
|
|
23
|
+
每条 Note 必带的语义要求(检查脚本管不了的):
|
|
24
|
+
|
|
25
|
+
- **Alternatives 只记录真实考虑过的对手方案**:先写它最强的论据再否——只写弱处的拒绝是稻草人。「不做/复用」仅当当时真的权衡过才写,不要编。
|
|
26
|
+
- **简化必写代价上限**:`simplification` 的 `## Consequences` 要写明"这个取舍的已知上限是什么、什么信号发生时该重访"。没有升级触发条件的简化会悄悄变永久。
|
|
27
|
+
- **验证要可确认**:写"改对了"时落到可被检查的表面(记"哪条路径、什么量级、跑什么命令确认"),没有基线就不要用相对量词——"提升了/更快了"在没有对比基线时是未验证断言,比不写更糟。
|
|
28
|
+
|
|
29
|
+
## 检查脚本
|
|
30
|
+
|
|
31
|
+
`scripts/agent-note-tree.ts` 定义 `AGENT_NOTE_CLASSES` 常量;未知 class 文件夹、lifecycle 根下的散落 `.md` 都会报错。新增 class 必须同时改常量和本文档,否则检查直接红。
|
|
32
|
+
|
|
33
|
+
分类封闭集与判据对齐 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的 notes 分类实践。
|
package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/note-format.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# 按需阅读:Note 文件格式
|
|
2
|
+
|
|
3
|
+
> SKILL §2 的展开。写/改 Note 时对照;只改代码不动 Note 时跳过。
|
|
4
|
+
|
|
5
|
+
## 头块(前三行,检查脚本会核对)
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
# Agent Note: <标题>
|
|
9
|
+
|
|
10
|
+
Status: <状态>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- `proposed` → `Status: proposed`
|
|
14
|
+
- `implemented` → `Status: implemented`
|
|
15
|
+
- `rejected` → `Status: rejected — <一句话原因>`
|
|
16
|
+
|
|
17
|
+
标题前必须带 `Agent Note: ` 前缀;状态不含日期与括号;必须与所在 lifecycle 文件夹一致(脚本会交叉核对)。文件名日期是首次提出日,git 承载其余时间信息。
|
|
18
|
+
|
|
19
|
+
## Body 骨架
|
|
20
|
+
|
|
21
|
+
每篇 Note 都以 `## Problem` 开头——动机要能脱离方案独立成立。之后按 lifecycle区分:
|
|
22
|
+
|
|
23
|
+
**`proposed/`**
|
|
24
|
+
|
|
25
|
+
```markdown
|
|
26
|
+
## Problem
|
|
27
|
+
## Proposal
|
|
28
|
+
…自由节…
|
|
29
|
+
## Alternatives considered
|
|
30
|
+
## Acceptance criteria
|
|
31
|
+
## Risks
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`Proposal` 可用将来时;`Acceptance criteria` 说清什么可观察状态算完成;`Risks` 同时写风险与已知取舍。
|
|
35
|
+
|
|
36
|
+
**`implemented/`**
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
## Problem
|
|
40
|
+
## Decision
|
|
41
|
+
…自由节…
|
|
42
|
+
## Alternatives considered
|
|
43
|
+
## Consequences
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`Decision` 用现在时描述已落地事实;门禁只拒提案标题(`## Proposal` / `## Plan` / `## Migration plan` / `## Acceptance criteria` 及其中文别名);用 `## Consequences` 同时记录代价与收益;可按需加 `## Testing` / `## Verification` 等现在时事实节。现在时靠人写,不靠词法扫描。
|
|
47
|
+
|
|
48
|
+
**`rejected/`**
|
|
49
|
+
|
|
50
|
+
冻结的 proposal 形态,verdict 在 `Status:` 行;保留提案时的 `Alternatives` 等节,不改写为对立面。
|
|
51
|
+
|
|
52
|
+
## Alternatives considered(必写)
|
|
53
|
+
|
|
54
|
+
每篇 Note 必含 `## Alternatives considered`:每个**真考虑过**的备选为何没选,一段一备选(可用 `### Why not <X>?` 子节)。没有过的选项不要编。「不做 / 复用现状」仅当当时真的权衡过才写。脚本只检查这一节在不在。
|
|
55
|
+
|
|
56
|
+
## 时态与禁止改写
|
|
57
|
+
|
|
58
|
+
- `proposed` 可用将来时;`implemented` 一律现在时,描述已落地事实。
|
|
59
|
+
- 一条 Note 永远不被改写成另一个决定;被取代用新 Note 接管,旧 Note 按归档/合并规则处理。
|
|
60
|
+
|
|
61
|
+
头块标题兼容全角冒号(`# Agent Note:标题`,中文输入法常打出全角);新笔记建议半角。
|
|
62
|
+
|
|
63
|
+
## 自由节与文风
|
|
64
|
+
|
|
65
|
+
- 自由节(package 拓扑、wire 契约、schema 等)放在 `Decision` 与 `Alternatives` 之间。
|
|
66
|
+
- 保留可检索的机制名与 `must`/`may`/`never` 时序强调;一个事实只在一处讲透,其余链过去。
|
|
67
|
+
- 跨 Note 引用用相对 Markdown 链接 `[topic](../../implemented/architecture/2026-…-….md)`,不要裸数字。
|
|
68
|
+
|
|
69
|
+
格式与别名表对齐 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的 notes 规范;本项目为中文单语,头块 `Agent Note:` 与 `Status:` 保持英文原文以便脚本核对,正文用中文。
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# 按需阅读:Notes 行文与去泄露自检
|
|
2
|
+
|
|
3
|
+
> 提炼自 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 仓库内 `dsh-prose-standard` 与 `dsh-trim-cot-leakage` 两个 skill 的可搬运部分。写/改 Note 时对照此清单;只改代码不动 Note 时跳过。
|
|
4
|
+
|
|
5
|
+
## 原则
|
|
6
|
+
|
|
7
|
+
- 只写代码说不清的:行为、失败、时序、所有权、后果与取舍。别复述代码或推导过程。
|
|
8
|
+
- 不变量能编进类型、可见性或 API 报错的,别只写在笔记里。
|
|
9
|
+
- 说人话,点名谁做了什么、在什么条件下、会怎样;少用“契约/边界/形态”等抽象词,除非指的就是该技术主体。
|
|
10
|
+
- 一个事实只在一处讲透,其余链过去;别把同一规则抄得到处都是。
|
|
11
|
+
- 写完自问:这段话不看实现能独立成立吗?不看当时聊天,现在的读者能验证吗?
|
|
12
|
+
|
|
13
|
+
## 写前自检(来自 prose-standard)
|
|
14
|
+
|
|
15
|
+
- 每段保留完整命题:主体/动作、条件/时序、must/may/never、否定保证与例外、所有权/副作用/失败与后果——缺一不可。
|
|
16
|
+
- `implemented` 用现在时,描述已落地事实;去掉计划口吻与 checklist。
|
|
17
|
+
- 保留可检索的机制名与关键 must/may/never、时序与否定强调;装饰性加粗和感叹少用。
|
|
18
|
+
- 一个改动内批量套用刚学到的规则到相似段落,别只改一处。
|
|
19
|
+
|
|
20
|
+
## 按位置查
|
|
21
|
+
|
|
22
|
+
- **Decision/Consequences**:区分、抛错/拒绝、副作用、所有权、时序、取消、持久化是否说清。
|
|
23
|
+
- **自由节**(拓扑/契约/schema):讲清职责、依赖与非显而易见的选择及指向。
|
|
24
|
+
- **Alternatives/Consequences**:同时写代价与收益,点名放弃的能力与重引入条件。
|
|
25
|
+
- **Testing/Verification**:只解释“为何这样验证”(fixture/断言/真实入口的必要性),不写走读。
|
|
26
|
+
|
|
27
|
+
## 去泄露自检(来自 trim-cot-leakage)
|
|
28
|
+
|
|
29
|
+
对每段可疑文字问:**只有当时的会话/PR/草稿可见吗?HEAD 的读者能独立验证吗?** 不能则重述为仓库视角,删去会话痕迹。能解析也≠安全——可验证只代表过了去泄露这一关,README/文档等当前状态面上,可解析的变更叙事仍是变更叙事,按第 3 类路由。
|
|
30
|
+
|
|
31
|
+
常见泄露(命中即改):
|
|
32
|
+
|
|
33
|
+
1. 死引用:`(decision 7)`/`(audit C2)`/`§N`/`plan §1.4` — 改为对已提交 Note/文档的具名路径引用,无主则删引用、重述事实。
|
|
34
|
+
2. 栈/PR 视角:`后续 PR`/`本 PR 新增`/`上一 commit` — 改为已落地的机制或扩展点;未做事项用 `TODO` 或 issue 引用,或收进 `## Deferred` 小节。
|
|
35
|
+
3. 变更叙事:`used to`/`不再`/`旧 X`/`this cut`/`now` — 改为现在时;回归用现在时反事实“若无 X 则 Y”。
|
|
36
|
+
4. 评审编排:`评审时否掉`/`reviewer 确认`/`v5` — 只留决定与理由,删谁说的、何时说的。
|
|
37
|
+
5. 自证正确:`这样转是安全的,因为…` — 改为使之安全的 invariant,或直接删(代码已自明)。
|
|
38
|
+
6. 过程复述:`先 X 再 Y`/`测试走读` — 删,只留非显然契约。
|
|
39
|
+
7. 含糊与占位:`应该够了`/`probably fine` — 升为 `TODO/FIXME` 或明确边界。
|
|
40
|
+
8. 语言串台:中英混杂的工作语言片段 — 翻译或删除。
|
|
41
|
+
|
|
42
|
+
**不算泄露(保留):** issue 引用 `#1470`/`TODO(name):`(裸 `TODO` 注意正文扫描,见上条豁免)、Agent Note 与 postmortem 内的已合并 PR 引用、suppression 理由、现在时反事实、带实测值的边界、运行时 old/new 状态、已提交文档的 `§` 编号。
|
|
43
|
+
|
|
44
|
+
## 删过头警示(overcorrection traps,来自 trim-cot-leakage)
|
|
45
|
+
|
|
46
|
+
删之前先把段落里的命题列全,再对照四个"删过头"的坑:
|
|
47
|
+
|
|
48
|
+
- 把必须/禁止的义务删成"可以这样"的背书——约束变可选。
|
|
49
|
+
- 把"计划中/考虑过"的假设删成已落地事实——proposed 当 implemented。
|
|
50
|
+
- 删掉一句真事实,只因为它读起来像过程叙述。
|
|
51
|
+
- 丢掉承重溯源:`实测:512 嵌套 ≈ 0.15s` 里的 `实测`、来源标注与编号删掉,结论就没根了。
|
package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/quality-gate.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# 按需阅读:语义自检(写完笔记后过一遍)
|
|
2
|
+
|
|
3
|
+
> 脚本管结构,这张清单管意思。写完后自检,只向用户报缺口和写得好的地方,不逐条背诵。
|
|
4
|
+
> 定位:这是给 Agent 的自检,不是给脚本的规则——下列检查点全部是语义判断,永不进 verify 脚本。
|
|
5
|
+
|
|
6
|
+
## 动手前:先自己查,再问用户
|
|
7
|
+
|
|
8
|
+
- [ ] 这个"问题"真的是决策吗?——能用 §3 检索四法(入口注释若有 / 分类树 / rg / 模块文档)自己查到的事实,不要抛给用户。Finding facts is your job; 只有取舍和拍板才占用用户时间。
|
|
9
|
+
|
|
10
|
+
## Problem
|
|
11
|
+
|
|
12
|
+
- [ ] 动机脱离方案也能独立成立——删掉 Decision 再读一遍,还是同一个问题吗?
|
|
13
|
+
- [ ] 触发清楚:什么破了、什么要变、不做会怎样。
|
|
14
|
+
|
|
15
|
+
## Decision / Proposal
|
|
16
|
+
|
|
17
|
+
- [ ] 具体到能行动,不是"用更好的数据库"而是"为会话存储用 SQLite"。
|
|
18
|
+
- [ ] 理由是被"vs"逼出来的——写"决定用 X"就补一句"X vs Y 为何选 X"。
|
|
19
|
+
|
|
20
|
+
## Alternatives considered
|
|
21
|
+
|
|
22
|
+
- [ ] ≥2 个真备选;不要编没权衡过的选项。「不做/复用」仅当当时真的考虑过才算一档,不是必填档。
|
|
23
|
+
- [ ] 每个被否项先写它最强的论据,再写为何否——只写弱处的拒绝是稻草人。
|
|
24
|
+
- [ ] 否掉的理由落到具体驱动条件,不是"经验上不行"。
|
|
25
|
+
|
|
26
|
+
## Consequences
|
|
27
|
+
|
|
28
|
+
- [ ] 代价和收益都写。自问"什么变难了?维护成本是什么?"——只有收益的后果是挑选过的。
|
|
29
|
+
- [ ] 简化注明已知上限与何时该重访。没有升级触发条件的简化会悄悄变永久。
|
|
30
|
+
- [ ] 没有基线就不写相对量词——"提升了/更快了"说不清基线时,降级为事实陈述。
|
|
31
|
+
|
|
32
|
+
## Verification / Testing(implemented)
|
|
33
|
+
|
|
34
|
+
- [ ] 落到可确认表面:哪条路径、什么量级、跑什么命令。
|
|
35
|
+
- [ ] 不写"看起来能用"——验收标准要么可勾选,要么明确留给后续。
|
|
36
|
+
|
|
37
|
+
## 汇报形态
|
|
38
|
+
|
|
39
|
+
写完自检后,这样汇报(一行一缺口,没缺口就收口):
|
|
40
|
+
|
|
41
|
+
```markdown
|
|
42
|
+
**语义自检:<filename>**
|
|
43
|
+
✅ 稳定:动机独立成立 / 有 2 个真备选 / 后果代价收益兼备
|
|
44
|
+
⚠️ 缺口:
|
|
45
|
+
- Alternatives — 有"做了 vs 不做"稻草人,补一个与现行方案平行的真实选项
|
|
46
|
+
- Consequences — "性能提升"要落到哪条路径、什么量级
|
|
47
|
+
建议:修以上 2 处后落盘 / 可接受缺口,直接放行
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
用户接受缺口即放行;不接受就修再落盘。意思上的判断不是脚本,别把它撑成另一道检查。
|
|
51
|
+
|
|
52
|
+
## 这套自检生效了吗(观测判据)
|
|
53
|
+
|
|
54
|
+
每隔一段时间回看,以下信号说明自检在起作用;信号消失说明它在空转:
|
|
55
|
+
|
|
56
|
+
- 你向用户提的问题里,**不再出现**翻一下笔记树或 rg 一下就能答的事实性问题。
|
|
57
|
+
- 汇报里的每条缺口都带着**具体修法**(改哪节、补什么),而不是"建议再完善"。
|
|
58
|
+
- `rejected/` 和 Alternatives 里被否掉的路线,**不再被新会话重新提出**——这正是整套系统存在的理由。
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# 按需阅读:简化机会自检
|
|
2
|
+
|
|
3
|
+
> 提炼自 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的 `dsh-find-simplifications` skill。收尾或重构时扫一遍;别在功能改动里硬塞无关简化。
|
|
4
|
+
|
|
5
|
+
## 值得删/合/降级的信号
|
|
6
|
+
|
|
7
|
+
- 公开方法、事件、配置项、包、持久化事件或测试产物没有生产消费方(测试/文档是唯一消费方且行为非关键)。
|
|
8
|
+
- 两处表示同一事实(尤其是持久化事件与瞬态事件各存一份)。
|
|
9
|
+
- 某个能力的所有实现都必须实现某方法,但没有消费方在用它。
|
|
10
|
+
- 包只为测试/demo/支撑而存在,增加发布与依赖成本。
|
|
11
|
+
- 为“以后可能要”做的通用性:多会话、后台任务台账、年中转向、工具自带 UI 等,无当前归属。
|
|
12
|
+
- 为不存在的 API 准备的不变式、回滚、快照或特判。
|
|
13
|
+
- 手写了业界已有包或同版本 Node 已提供的能力,换掉能净删除实现与对应测试。
|
|
14
|
+
|
|
15
|
+
## 怎么证实
|
|
16
|
+
|
|
17
|
+
- 用 `rg` 搜符号/事件/配置键/包名,看生产代码(`packages/*/src`、`examples` 运行时、`loader/config` 路径)是否真在用。
|
|
18
|
+
- 区分生产/非生产/模糊语料——测试与文档里的出现不算生产证据;`knip` 可辅助但不能替代读调用点。
|
|
19
|
+
- 小而确定的清理用 `TODO/FIXME/XXX` 记下,别为此开一条 Note;只有 durable 的取舍才值得一条 proposed Note。
|
|
20
|
+
- Hand-rolled vs 依赖:看净删除(实现+测试+文档)、健康度、边界贴合度;能真删才换,包一层同样复杂度不算赢。
|
|
21
|
+
|
|
22
|
+
## 与 Notes 的衔接
|
|
23
|
+
|
|
24
|
+
- 符合信号且这个取舍需要留下来 → 写 `proposed/simplification` Note(Problem/Proposal/Alternatives/Acceptance/Risks)。
|
|
25
|
+
- 已落地的 simplification → `implemented/simplification`,Consequences 同时写删掉的成本与省下的负担。
|
|
26
|
+
- 触发 Note 树膨胀时,用 `archiving.md` 的“未来参考价值”判定是否归档,而非字数/年龄。
|
package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/verification.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 按需阅读:校验脚本
|
|
2
|
+
|
|
3
|
+
> SKILL §6 的展开。接入 CI 时对照;本地轻量使用时跳过。
|
|
4
|
+
|
|
5
|
+
## 检查脚本(均为 tsx,零新增依赖,均可 `npx tsx` 独立运行)
|
|
6
|
+
|
|
7
|
+
1. **`verify-agent-note-tree`**(`scripts/agent-note-tree.ts` + `scripts/verify-agent-note-tree.ts`)
|
|
8
|
+
- 校验 lifecycle 封闭集 `proposed/implemented/rejected` + `archived`、class 封闭集 6 个、路径深度 `{lifecycle}/{class}/file.md`、文件名 `yyyy-mm-dd-topic.md`、禁止 `INDEX.md`、活跃笔记内部相对 Markdown 链接有效性。
|
|
9
|
+
|
|
10
|
+
2. **`verify-agent-note-format`**(`scripts/verify-agent-note-format.ts`)
|
|
11
|
+
- 头部:第 1 行 `# Agent Note:` 标题(半角/全角冒号都收,中文输入法常打出全角)、第 2/4 行空行、第 3 行 `Status:` 与 lifecycle 一致且全篇唯一。
|
|
12
|
+
- 骨架:首节必须 `## Problem`/`## 问题`;per-lifecycle 必需节匹配中英别名(`## Decision`/`## 决策`、`## Consequences`/`## 后果` 等;`## Decision(说明)` 这类括号后缀会先剥掉再匹配);`implemented` 禁用提案式标题(`## Proposal`/`## Plan`/`## Migration plan`/`## Acceptance criteria` 及其中文别名)。现在时是散文纪律,不扫正文。
|
|
13
|
+
- 备选方案:`## Alternatives considered` / `## 备选方案` / `## 已考虑的替代方案` 等别名必写。脚本不检查「不做/复用」档,也不接受占位注释豁免。
|
|
14
|
+
- 兼容:CRLF/BOM 自动归一。
|
|
15
|
+
|
|
16
|
+
3. **`verify-archived`**(`scripts/verify-archived-agent-notes.ts`,标配)
|
|
17
|
+
- 每篇归档:头部布局逐行校验(L3 `Status: implemented` / L4 `Archived: YYYY-MM-DD` 紧邻 / L5 空行)。不承认 `Superseded-by:` 字段。
|
|
18
|
+
- `archived/manifest.json`:每个文件有封印条目、每条目有对应文件、sha256 与磁盘内容一致(冻结 = 不可篡改的机械含义)。
|
|
19
|
+
- append-only:有 git 时与基线 ref 的 manifest 逐条对比(env `AGENT_NOTE_ARCHIVE_BASE_REF`,本地默认 HEAD)。CI 必须指向变更前的 commit(本仓库 workflow:PR 用 `pull_request.base.sha`,push 用 `github.event.before`),用 HEAD 等于没查。已封印条目被改/删即报错;**无 git 自动降级**为哈希自校验并打印提示——不用 git 一样能跑,只是少了版本基线对照。
|
|
20
|
+
- `--write`:先证明既有封印未变,再为未封印文件追加封印(历史语料补齐用这个)。
|
|
21
|
+
|
|
22
|
+
4. **`check-note-anchors`**(`scripts/check-note-anchors.ts`,软报告,退出码恒 0,**不进 CI**)
|
|
23
|
+
- 扫描源码(env `AGENT_NOTE_CODE_ROOT` 指定根,默认 cwd;自动跳过 node_modules/.git/dist 等)里的 `// Note:` / `# Note:` 物理锚点:报告悬空锚点、没有锚点指向的 implemented 笔记、缺路径的锚点行。宿主没用锚点就不必跑。
|
|
24
|
+
|
|
25
|
+
## 接入建议
|
|
26
|
+
|
|
27
|
+
- 轻量(个人/无 git):前两个脚本即可,归档封印在第一次归档后自然生效。
|
|
28
|
+
- 完整(团队):`npm run verify-notes` 三线串进 CI,失败即红(本 Skill 的 `templates/verify-notes.yml` 可作模板,复制到宿主根目录 `.github/workflows/` 并核对脚本路径后启用)。
|
|
29
|
+
|
|
30
|
+
三个校验脚本方法上来自 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness),按通用中文单语宿主裁过:无双语三件套、无 DSH 迁仓豁免。锚点体检是可选软报告,不是 DSH 门禁。
|
|
31
|
+
|
|
32
|
+
## 脚本路径
|
|
33
|
+
|
|
34
|
+
本文的 `scripts/` 相对于 Skill 安装目录。运行命令时保持当前目录为宿主项目根目录,并使用实际 Skill 路径调用脚本;安装本身不会创建宿主 npm scripts。
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# 按需阅读:何时写、何时改与决策流转
|
|
2
|
+
|
|
3
|
+
> SKILL §4 的深度展开。每个重要改动或评审时对照一次。
|
|
4
|
+
|
|
5
|
+
## 核心心智:更新既有归属,严禁重复新建(Update the owning note)
|
|
6
|
+
|
|
7
|
+
DeepSeek 的公开演进历史(deepseek-ai/deepseek-harness 的 git 记录)里能看到同样的形态:Note 的新增很少,现有 Note 的**就地事实修正**占了绝大多数。
|
|
8
|
+
**不要把 Note 当做一次性发表的博客或流水账。它是与代码共存亡的「现行法律」。**
|
|
9
|
+
|
|
10
|
+
一篇 Note 永远不被改写成另一个决定:事实(路径、符号、默认值)就地改;决定或理由翻转 → 新开一篇并互链。禁止把 `## Decision` 改写成反面,禁止只靠 git 当旧理由的唯一副本。
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. 场景判定矩阵
|
|
15
|
+
|
|
16
|
+
| 场景 | 操作动作 | 典型范式 |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| **代码重构、改名、移包、改默认参数** | **原地更新现有 Note 事实** | Decision 核心理由不变;直接改路径、类名、默认值(不追加变更流水账)。理由变了就走新建,不走原地 |
|
|
19
|
+
| **写新 Note 之前** | **当场审计活跃笔记** | 按模块名/关键词搜 proposed + implemented + rejected;每篇命中当场分类(无关 / 部分重叠 / 完全吸收 / 过时提案),和这篇新 Note 一起落盘。禁止推迟到大扫除 |
|
|
20
|
+
| **提出全新的架构尝试或技术选型** | **新建 `proposed/`** | 动手编码前写清动机、真实考虑过的备选与验收指标 |
|
|
21
|
+
| **完成开发并准备合入主干** | **转为 `implemented/`** | 见 §3 改写清单;与代码同批落盘(git 场景即同一 commit/PR) |
|
|
22
|
+
| **方案被新决策部分取代** | **两篇都留、互链** | 只更新仍成立的事实。禁止归档 |
|
|
23
|
+
| **方案在评审中被否决** | **移入 `rejected/` 或删除** | 仅当其理由能避免未来重蹈覆辙时保留并写清原因;否则彻底删除 |
|
|
24
|
+
| **新架构完全取代了旧架构** | **先吸收,能删则删,否则归档** | 见 §4。指针写在新笔记里,不写进归档篇 |
|
|
25
|
+
| **版本封版打标、依赖小补丁、排版** | **免除(Not Applicable)** | 直接提交代码,无需任何 Note |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. 原地同步法则(In-place Fact Sync)
|
|
30
|
+
|
|
31
|
+
当现有 Note 所守护的模块发生演进,但核心决策并未被推翻时:
|
|
32
|
+
|
|
33
|
+
1. **直接修改,不记流水账**:
|
|
34
|
+
- ❌ 错误:在文末追加 `### 2026-09-02 更新:类名重命名为 X`
|
|
35
|
+
- ✅ 正确:直接在正文中将旧类名替换为新类名,保证任何时候打开这篇 Note,它反映的都是 HEAD 分支的绝对事实。
|
|
36
|
+
2. **时态永保现在时**:
|
|
37
|
+
- 始终使用现在时(`系统使用 SQLite 作为持久化引擎`),严禁使用变更叙事(`系统不再使用 JSONL,现在使用 SQLite`)。门禁只拒提案标题,现在时靠这条纪律,不靠词法扫描。
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 3. proposed → implemented 改写清单
|
|
42
|
+
|
|
43
|
+
同一次改动里做完:
|
|
44
|
+
|
|
45
|
+
1. 移到 `implemented/<class>/`,文件名日期不动(首次提出日)
|
|
46
|
+
2. `Status: proposed` → `Status: implemented`
|
|
47
|
+
3. `## Proposal` → `## Decision`,改成现在时(已落地的事实)
|
|
48
|
+
4. `## Acceptance criteria` / `## Risks` 折进 `## Consequences`(或现在时 `## Testing` / `## Verification`)
|
|
49
|
+
5. 删计划段(`## Plan` / 迁移步骤 / 开放问题)
|
|
50
|
+
|
|
51
|
+
门禁靠骨架变化卡住:implemented 里残留 `## Proposal` 会失败。
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 4. 取代:部分重叠 vs 完全吸收
|
|
56
|
+
|
|
57
|
+
**部分重叠**:新方案只覆盖旧方案一部分 → 两篇都留,双方加相对链接;只更新仍成立的事实。禁止归档、禁止推迟。
|
|
58
|
+
|
|
59
|
+
**完全吸收**(旧方案被彻底淘汰):
|
|
60
|
+
|
|
61
|
+
1. **审计旧 Note 资产**:独有的安全边界、否定性保证、失败场景、重新引入条件、验证缺口。
|
|
62
|
+
2. **搬迁与吸收**:写入新 Note 的 `## Decision` / `## Alternatives considered` / `## Consequences`。
|
|
63
|
+
3. **旧 Note 二选一**:
|
|
64
|
+
- **删除**:新篇已写入旧篇全部独特内容,且入站链接已改完 → 物理删除,不进 `archived/`。
|
|
65
|
+
- **归档**:旧篇还有独立杠杆(否定性保证、所有权边界、重新引入条件)→ `archive-agent-note.ts`。只插 `Archived:` 一行;互链写在新笔记。
|
|
66
|
+
4. **修复入站链接**:把仍指向旧路径的相对链接改到新 Note(引历史快照时才指向 `archived/`)。
|
|
67
|
+
|
|
68
|
+
`--superseded-by` 只校验新笔记存在,并在新笔记末尾补一条指向归档路径的相对链接。
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 5. 可选:源码入口反向注释
|
|
73
|
+
|
|
74
|
+
宿主若已有此惯例,可在核心入口留一行:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Note: 会话持久化采用文件句柄管理,避免并发写冲突 — 见 .agents/notes/implemented/architecture/2026-08-27-handle-based-session-persistence.md
|
|
78
|
+
export class SessionFileHandlePool {
|
|
79
|
+
// ...
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
不是门禁。`check-note-anchors` 只做软报告,不进 CI。
|
package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/agent-note-tree.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared structural source of truth for the Agent Note tree.
|
|
3
|
+
* Portable: resolves .agents/notes from cwd (or AGENT_NOTE_ROOT env).
|
|
4
|
+
*/
|
|
5
|
+
import { readdirSync, existsSync } from 'node:fs'
|
|
6
|
+
import { resolve } from 'node:path'
|
|
7
|
+
|
|
8
|
+
/** Recurse `dir` and return posix-relative `.md` paths prefixed with `prefix`. Node 18 compatible (no fs.globSync). */
|
|
9
|
+
function listMd(dir: string, prefix: string): string[] {
|
|
10
|
+
if (!existsSync(dir)) return []
|
|
11
|
+
const out: string[] = []
|
|
12
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
13
|
+
if (entry.name.startsWith('.')) continue
|
|
14
|
+
const rel = prefix ? `${prefix}/${entry.name}` : entry.name
|
|
15
|
+
if (entry.isDirectory()) out.push(...listMd(resolve(dir, entry.name), rel))
|
|
16
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) out.push(rel)
|
|
17
|
+
}
|
|
18
|
+
return out
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveAgentNoteRoot(): string {
|
|
22
|
+
if (process.env.AGENT_NOTE_ROOT) return resolve(process.env.AGENT_NOTE_ROOT)
|
|
23
|
+
return resolve(process.cwd(), '.agents/notes')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const agentNoteRoot = resolveAgentNoteRoot()
|
|
27
|
+
|
|
28
|
+
const AGENT_NOTE_LIFECYCLES = ['proposed', 'implemented', 'rejected'] as const
|
|
29
|
+
export const AGENT_NOTE_CLASSES = ['feature', 'bug-fix', 'simplification', 'architecture', 'process', 'testing'] as const
|
|
30
|
+
const AGENT_NOTE_ARCHIVE = 'archived'
|
|
31
|
+
const ROOT_ALLOWLIST = new Set(['AGENTS.md', 'CLAUDE.md'])
|
|
32
|
+
|
|
33
|
+
export interface AgentNote {
|
|
34
|
+
lifecycle: string
|
|
35
|
+
rel: string
|
|
36
|
+
date: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function walkAgentNoteTree(): { notes: AgentNote[]; errors: string[] } {
|
|
40
|
+
const notes: AgentNote[] = []
|
|
41
|
+
const errors: string[] = []
|
|
42
|
+
if (!existsSync(agentNoteRoot)) return { notes, errors }
|
|
43
|
+
for (const entry of readdirSync(agentNoteRoot, { withFileTypes: true })) {
|
|
44
|
+
if (entry.name === 'INDEX.md') {
|
|
45
|
+
errors.push('structure: INDEX.md — centralized Agent Note indexes are forbidden; browse the lifecycle/class tree or search the repository')
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
if (entry.isDirectory() && entry.name !== AGENT_NOTE_ARCHIVE && !(AGENT_NOTE_LIFECYCLES as readonly string[]).includes(entry.name)) {
|
|
49
|
+
errors.push(`structure: ${entry.name}/ — unknown lifecycle folder (allowed: ${AGENT_NOTE_LIFECYCLES.join(', ')}, plus ${AGENT_NOTE_ARCHIVE}/)`)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const lifecycle of AGENT_NOTE_LIFECYCLES) {
|
|
53
|
+
for (const match of listMd(resolve(agentNoteRoot, lifecycle), lifecycle).sort()) {
|
|
54
|
+
const segs = match.split('/')
|
|
55
|
+
if (segs.length === 2 && ROOT_ALLOWLIST.has(segs[1] ?? '')) continue
|
|
56
|
+
if (match.endsWith('.zh.md')) continue
|
|
57
|
+
const cls = segs[1]
|
|
58
|
+
const base = segs[2]
|
|
59
|
+
if (segs.length !== 3 || cls === undefined || base === undefined) {
|
|
60
|
+
errors.push(`structure: ${match} — expected {lifecycle}/{class}/file.md (got depth ${segs.length})`)
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
if (!(AGENT_NOTE_CLASSES as readonly string[]).includes(cls)) {
|
|
64
|
+
errors.push(`structure: ${match} — unknown class folder "${cls}" (allowed: ${AGENT_NOTE_CLASSES.join(', ')})`)
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
if (!/^\d{4}-\d{2}-\d{2}-.+\.md$/.test(base)) {
|
|
68
|
+
errors.push(`structure: ${match} — filename must be yyyy-mm-dd-topic.md`)
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
notes.push({ lifecycle, rel: match, date: base.slice(0, 10) })
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { notes, errors }
|
|
75
|
+
}
|