dsh-notes-board 0.0.0-stage → 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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +21 -0
  3. package/README.md +163 -2
  4. package/client.js +1253 -0
  5. package/cordis.patch.yml +6 -0
  6. package/icon.svg +16 -0
  7. package/index.js +28 -0
  8. package/locale/en.json +6 -0
  9. package/locale/zh.json +6 -0
  10. package/package.json +79 -4
  11. package/scripts/build-client.mjs +175 -0
  12. package/scripts/test-board.mjs +202 -0
  13. package/src/core/notes.js +486 -0
  14. package/src/core/tools.js +221 -0
  15. package/src/host/board.js +184 -0
  16. package/src/host/notes.js +250 -0
  17. package/src/host/skills.js +48 -0
  18. package/src/panel.js +294 -0
  19. package/vendor/board.html +1779 -0
  20. package/vendor/write-notes-like-deepseek/README.md +323 -0
  21. package/vendor/write-notes-like-deepseek/package.json +21 -0
  22. package/vendor/write-notes-like-deepseek/scripts/export-assets.sh +40 -0
  23. package/vendor/write-notes-like-deepseek/scripts/import-dsh-notes.ts +125 -0
  24. package/vendor/write-notes-like-deepseek/scripts/test-skill-install.mjs +63 -0
  25. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/SKILL.md +195 -0
  26. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/assets/agent-notes-board.html +1779 -0
  27. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/archiving.md +109 -0
  28. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/classification.md +33 -0
  29. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/note-format.md +69 -0
  30. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/prose-checklist.md +51 -0
  31. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/quality-gate.md +58 -0
  32. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/simplification-checklist.md +26 -0
  33. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/verification.md +34 -0
  34. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/references/when-to-write.md +83 -0
  35. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/agent-note-tree.ts +75 -0
  36. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/archive-agent-note.ts +167 -0
  37. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/build-board.ts +235 -0
  38. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/check-note-anchors.ts +103 -0
  39. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/verify-agent-note-format.ts +158 -0
  40. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/verify-agent-note-tree.ts +56 -0
  41. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts +127 -0
  42. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/implemented.md +32 -0
  43. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/proposed.md +38 -0
  44. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/rejected.md +27 -0
  45. package/vendor/write-notes-like-deepseek/skills/write-notes-like-deepseek/templates/verify-notes.yml +38 -0
@@ -0,0 +1,323 @@
1
+ # write-notes-like-deepseek
2
+
3
+ > **像 DeepSeek 团队一样维护项目。** 把他们在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 里用的那套方法,装进你的仓库。
4
+
5
+ [![Agent Skills](https://img.shields.io/badge/Agent%20Skills-Standard-blue)](https://agentskills.io)
6
+ [![Live Demo](https://img.shields.io/badge/Live%20Demo-GitHub%20Pages-success)](https://czm15053.github.io/write-notes-like-deepseek-demo/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
8
+
9
+ AI 每天都能帮你交十几个 PR,但每个新会话都是一张白纸,看不见仓库里已经立过的规矩。DeepSeek 团队用写在仓库里的笔记解决这件事;本项目把这套方法做成 Skill,装上就能按同样的方式维护你的项目。
10
+
11
+ ```bash
12
+ npx skills add czm15053/write-notes-like-deepseek
13
+ ```
14
+
15
+ 📺 先看效果:[在线演示看板](https://czm15053.github.io/write-notes-like-deepseek-demo/)(内置 1,267 篇来自 DeepSeek Harness 的真实决策笔记,可脱机浏览)
16
+
17
+ ---
18
+
19
+ ## 当 AI 每天帮你交十几个 PR,代码库会怎样失控
20
+
21
+ <p align="center">
22
+ <img src="assets/01-decay.png" alt="三个失控现象:新 AI 看不见当初为什么这样定;为赶进度打穿模块边界;被否过的老路被一遍遍重提" width="100%" />
23
+ </p>
24
+
25
+ 代码越写越快,结构烂得也越来越快——这是 AI 密集编码时代的新问题:
26
+
27
+ 1. **新来的 AI 看不见当初为什么这样定。** 每个新会话都是一张白纸,只看得见眼前的代码。一段写得很别扭的代码,往往是当年为了避免死锁、为了兼容某个约束故意为之;AI 不知道,就会自作聪明地「优化」掉它。
28
+ 2. **为赶一个局部需求,打穿全局结构。** AI 极其擅长单点突破,但没有全局视野:跨层直接调用、绕过老协议、引入互相冲突的依赖,一天一个坑。
29
+ 3. **被否过的老路被一遍遍重新提出。** 三个月前已经证明会内存溢出的方案,新会话又兴致勃勃地提了一遍——因为没人把「这条路试过了,不行」写下来。
30
+
31
+ 根源只有一句话:**代码只能表达「系统现在怎么跑」,表达不了「为什么必须这样跑、以及放弃了什么」。**
32
+
33
+ 靠提示词提醒 AI「请注意架构」是没有用的。DeepSeek Harness 团队在自己的代码库里验证过:**coding agent 遵守「被强制的门」的可靠性,远高于遵守散文式约定**——而且干活的劳动力已经是 AI,「做门禁太麻烦」这个理由本身就不成立。
34
+
35
+ 所以规矩必须写成 AI 绕不开的形式:和代码**同仓库**(必然读到)、**同一次改动**(必然同步)、**机械校验**(必然遵守)、旧决定**封存带封印**(篡改了会报警)。
36
+
37
+ ### 装上它之后:AI 从「代码推土机」变回「懂规矩的搭档」
38
+
39
+ <p align="center">
40
+ <img src="assets/hero.png" alt="左边:AI 每天十几个 PR 冲刷下代码库失控;右边:同样的代码库配上决策笔记后井然有序" width="100%" />
41
+ <br>
42
+ <em>左边没有笔记:每天十几个 PR 把仓库冲乱。右边有笔记:同样的代码库按规矩改。</em>
43
+ </p>
44
+
45
+ **没有它时:**
46
+
47
+ > **你**:「给插件加个实时进度通知。」
48
+ > **AI**:「已完成:在宿主内核新增 `getProgress()` 方法,所有插件可直接调用 ✅」
49
+ >
50
+ > 三个月后:四个插件绕开消息通道直连内核,微内核成了乱炖——而当初那个「多此一举」的消息通道约定,已经没人记得为什么。
51
+
52
+ **装上它后:**
53
+
54
+ > **你**:「给插件加个实时进度通知。」
55
+ > **AI**:「这涉及跨插件通信。仓库笔记里立着规矩:所有跨插件通信必须走消息通道,哪怕多一层序列化开销。我已在 `proposed/` 按这个约束起草了方案,对比了两条备选,请你过目后再施工。」
56
+
57
+ 一句台词的差别:动手之前,先看见当初为什么这样定。
58
+
59
+ ---
60
+
61
+ ## 它是怎么转起来的:三步闭环
62
+
63
+ <p align="center">
64
+ <img src="assets/02-loop.png" alt="三步闭环:动手前写方案稿;代码和笔记一起交;老方案被取代就标明被谁取代并归档封存" width="100%" />
65
+ </p>
66
+
67
+ 1. **动手前,先写方案稿**(放进 `proposed/`):要解决什么问题、考虑过哪几条路——每条被放弃的路,先写它**最强的理由**,再解释为什么不用。想清楚后施工(有评审就走评审,一个人写就自己拍板)。
68
+ 2. **代码和笔记一起交**:落地后方案稿转为 `implemented/`,只许用现在时写「已经发生的事」(门禁只拒提案标题)。
69
+ 3. **老方案被取代时,干净归档**:新笔记接管并承继旧理由;能删则删,否则物理移入 `archived/` 并只插一行 `Archived:`——是源码级的归档,不是改个状态字段。互链写在新笔记里。
70
+
71
+ 封存是机械的,不靠自觉:
72
+
73
+ - 每篇归档笔记记入 `manifest.json` 的 SHA-256 封印,此后**只增不改**——谁动了归档里的一个字,校验当场报警;
74
+ - **死链不过夜**:归档那一刻,脚本列出所有还链着旧笔记的引用清单,逐条修完才算完;
75
+ - 旧笔记从此不参与日常校验,但也永远不会丢——新会话再想走回头路,会先撞见归档快照和新笔记里的互链。
76
+
77
+ ---
78
+
79
+ ## 什么样的决定值得记
80
+
81
+ <p align="center">
82
+ <img src="assets/03-scenarios.png" alt="判定只有一条:非平凡改动必须留笔记。命中行为、架构、跨文件契约、流程工具链、测试策略、落盘网络配置格式任一项就写;写的时候想清楚守住哪个方向" width="100%" />
83
+ </p>
84
+
85
+ **判定对齐 DSH:非平凡改动必须留笔记。** 改了**行为**、**架构**、**跨文件契约**、**流程与工具链**、**测试策略**,或**落盘 / 网络 / 配置格式**——命中任何一项就写;其他维护者日后可能重访的决定,也一样。纯机械性的局部改动(改样式、格式化、打标、不改行为的依赖补丁、常规 CRUD)直接交代码,不用记。
86
+
87
+ **写的时候,想清楚这笔决定守住哪个方向:**
88
+
89
+ - **往前看:给系统立新规。** 新的跨模块通信契约、状态流转规则、访问边界、运行时不变量——比如「所有跨插件通信必须走消息通道」「会话日志一旦写入就不可变」。不写下来,后来的 AI 各写一套、随意击穿模块。事故复盘后补的锁粒度、连接池规矩也属于这类,是最硬的新规。
90
+ - **往回看:为看不见的约束做过的妥协。** 为了零依赖开箱即用,坚决不引入外部常驻进程;为了崩溃可恢复,宁可放弃内存缓存。当年放弃的往往是更主流、更直觉的解法——不写下来,后来的人只看见「慢」和「土」,把被否掉的路重走一遍。
91
+ - **做减法:收窄暴露面、废弃旧东西。** 删代码、砍 API、下线旧流程——退出条件和迁移边界光看代码看不出来。不写下来,没人敢删第二刀;或者删过了头,把还在用的东西一起砍掉。
92
+
93
+ **不用记的**:改样式、格式化、打个版本号、不改行为的依赖补丁和常规 CRUD——直接提交代码,别给自己加戏。过度留痕和完全不记,是同一个错误的两种样子。
94
+
95
+ <p align="center">
96
+ <img src="assets/05-when.png" alt="拿不准是不是非平凡时的补刀问句:光看代码和单测,后来的人推导得出为什么这样定吗?推导得出多半是平凡改动别记,推导不出就是非平凡" width="100%" />
97
+ </p>
98
+
99
+ ### 规矩不能只靠自觉
100
+
101
+ > 对 AI 来说,写在散文里的规矩,等于没有规矩。
102
+
103
+ DeepSeek Harness 团队在自家代码库里立过这条元规矩:**agent 遵守被强制的门,远胜于遵守散文式约定**。所以这套系统里,几乎每条纪律都有机械牙齿:
104
+
105
+ - 笔记必须有备选方案、implemented 不许留提案标题 → 校验脚本非零退出,红给你看;
106
+ - 目录和类别不许自造 → 树校验直接拦下「第七种分类」;
107
+ - 老决定封存 → SHA-256 封印只增不改,篡改当场报警。
108
+
109
+ Prompt 只负责提醒,脚本负责咬合。你不需要相信 AI 的自觉,只需要相信非零退出码。
110
+
111
+ ---
112
+
113
+ ## 一篇笔记长什么样
114
+
115
+ 摘自 DeepSeek Harness 现行笔记(有删节):`.agents/notes/implemented/process/2026-07-26-dependencies-over-hand-rolling.md`
116
+
117
+ ```markdown
118
+ # Agent Note: 优先选用持续维护的依赖,而非手写实现
119
+
120
+ Status: implemented
121
+
122
+ ## Problem
123
+
124
+ 仓库没写依赖政策,agent 从「外部依赖很少」推断出「不要加依赖」,比任何人实际决定过的都严。手写的 SSE 解析器、协议分帧器、重试循环,每一份都要自己测、自己审,却吃不到生态已经修过的边界情况。
125
+
126
+ ## Decision
127
+
128
+ 引入维护良好的外部依赖(或引擎下限已提供的 Node 内置)来替换手写实现,是正当的简化。门槛:净删除我们维护的代码;包要健康;语义要契合;不重开已定案的 seam。
129
+
130
+ ## Alternatives considered
131
+
132
+ - **维持隐性的「不加新依赖」文化** — 最省事,但它从来不是一项有记录的决策;代价是手写协议和解析代码重复实现久经实战的库,评审还得重推一遍生态已修过的边界。
133
+ - **一份获批包的硬性白名单** — 看起来可控。但仓库还在预发布、依赖集合很小;按 PR 设证据门槛再加评审,不必再养一份白名单。
134
+ - **每个新依赖都像 Cordis 一样以源码收录** — 能打补丁、能锁死上游。但 vendor 只适用于必须打补丁或锁定的包;推广到所有依赖,等于把本要卸下的维护负担再背回来。
135
+
136
+ ## Consequences
137
+
138
+ - **收益**:巡查简化时,「用包 Y 替换手写的 X」算正规产出。
139
+ - **代价**:依赖清单会增长,供应链接触面随之扩大;扫描和更新节奏另有提案管。
140
+ ```
141
+
142
+ 三个要点:**被放弃的方案先写最强理由再否决**(防止后人翻案);**收益和代价都写**(没有代价的决定是挑选过的);**只写已经发生的事**——`## Decision` 用现在时;门禁只拒提案标题,不扫正文用词。
143
+
144
+ <p align="center">
145
+ <img src="assets/04-anatomy.png" alt="DSH 现行笔记解剖:先写对方最强理由再否决,收益代价并列" width="100%" />
146
+ </p>
147
+
148
+ ---
149
+
150
+ ## 目录就是状态,没有总索引
151
+
152
+ 路径格式严格遵循:`{走到哪一步}/{哪一类}/yyyy-mm-dd-主题.md`
153
+
154
+ ```
155
+ .agents/notes/
156
+ ├── proposed/ # 动手前:方案稿,写清背景、备选与验收标准
157
+ ├── implemented/ # 已落地:只写现在时事实,随代码一起改
158
+ ├── rejected/ # 被否决:写明原因防重犯,没价值就删
159
+ └── archived/ # 已封存:完成使命的旧决定,永久只读,改了会报警
160
+ ```
161
+
162
+ 笔记分六种,不许自造类别(校验脚本会拦):
163
+
164
+ <p align="center">
165
+ <img src="assets/06-classes.png" alt="六种笔记类型:新能力、修缺陷、只删不增的简化、结构决策、流程工具、测试策略" width="100%" />
166
+ </p>
167
+
168
+ - `feature`:用户看得见的新能力和产品选择。
169
+ - `bug-fix`:缺陷修复,或事故复盘补上的架构缺口。
170
+ - `simplification`:**只删不增**——清理废弃逻辑、收敛暴露面;行为不变的普通重构归这里。
171
+ - `architecture`:源码怎么组织、模块边界、包依赖。
172
+ - `process`:围着代码转的工具链、校验、发布流程。
173
+ - `testing`:测试基建、分层与验收策略。
174
+
175
+ <p align="center">
176
+ <img src="assets/07-no-index.png" alt="为什么不要总索引:多分支并行时全局 INDEX.md 每改必冲突;文件夹位置本身就是状态" width="100%" />
177
+ </p>
178
+
179
+ **为什么没有一个总的 INDEX.md?** 因为多分支、多人同时开发时,总索引是最抢手的冲突源——每篇笔记的改动都要碰它。文件夹位置本身就是状态:想看待审方案看 `proposed/`,想看踩坑记录看 `rejected/`,配合全文搜索足够。(一个人写代码、不开分支?这条无所谓,放着就行。)
180
+
181
+ ### 个人写、团队写,差别只在加多少流程
182
+
183
+ <p align="center">
184
+ <img src="assets/08-spectrum.png" alt="落地光谱:笔记目录结构人人相同;一个人直接开写,加 git 就多一条提交纪律,团队再加评审和 CI 校验" width="100%" />
185
+ </p>
186
+
187
+ **所有人的笔记目录长一个样**:`proposed / implemented / rejected / archived × 六种分类`,与 DSH 对齐的硬结构,不分个人还是团队。差别只在往上叠加多少流程:
188
+
189
+ | 你的处境 | 在相同底座上加什么 |
190
+ |---|---|
191
+ | **一个人写** | 不加。目录结构照标准建,装上 Skill 就开写;不用 git 也照常跑。 |
192
+ | **一个人 + git** | 加一条纪律:代码和笔记**同一次提交**,不让笔记掉队。 |
193
+ | **团队开发** | 加评审、PR 模板提一句「重要改动必带一篇笔记」、CI 接上 `verify-notes` 三条校验(见下节)。 |
194
+
195
+ ---
196
+
197
+ ## 本地校验:零依赖,`npx` 直接跑
198
+
199
+ > 校验脚本通过 Node.js 和 `npx tsx` 运行。以下命令在宿主项目根目录执行,使用项目级安装位置 `.agents/skills/write-notes-like-deepseek/`;若安装在 `.claude/skills/` 或全局目录,请替换为实际 Skill 路径。不要切换到 Skill 目录运行,默认检查的是当前目录下的 `.agents/notes/`。
200
+
201
+ ```bash
202
+ # 1. 目录、类别、文件名、笔记之间的相对链接
203
+ npx tsx .agents/skills/write-notes-like-deepseek/scripts/verify-agent-note-tree.ts
204
+
205
+ # 2. 头部与骨架:状态行、必备小节、备选方案必填、implemented 禁用提案标题
206
+ npx tsx .agents/skills/write-notes-like-deepseek/scripts/verify-agent-note-format.ts
207
+
208
+ # 3. 封存区体检:归档笔记的头部布局、封印哈希、只增不改(没有 git 自动降级)
209
+ npx tsx .agents/skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts
210
+
211
+ # 4. 老方案被取代,一键归档:只插 Archived: 一行 + 封印 + 列出谁还链着它
212
+ # --superseded-by 在新笔记里补互链,不写进归档篇
213
+ npx tsx .agents/skills/write-notes-like-deepseek/scripts/archive-agent-note.ts .agents/notes/implemented/<类别>/<文件名>.md \
214
+ --superseded-by .agents/notes/implemented/<类别>/<新笔记>.md
215
+
216
+ # 5. 可选体检(只提醒不报错,不进 CI):代码里若有 // Note: 锚点,是否指着不存在的笔记
217
+ npx tsx .agents/skills/write-notes-like-deepseek/scripts/check-note-anchors.ts
218
+ ```
219
+
220
+ 配进 `package.json`:
221
+
222
+ ```json
223
+ {
224
+ "scripts": {
225
+ "verify-notes": "npx tsx .agents/skills/write-notes-like-deepseek/scripts/verify-agent-note-tree.ts && npx tsx .agents/skills/write-notes-like-deepseek/scripts/verify-agent-note-format.ts && npx tsx .agents/skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts",
226
+ "archive-note": "npx tsx .agents/skills/write-notes-like-deepseek/scripts/archive-agent-note.ts"
227
+ }
228
+ }
229
+ ```
230
+
231
+ 团队场景可将安装目录里的 `templates/verify-notes.yml`([查看模板](skills/write-notes-like-deepseek/templates/verify-notes.yml))复制到宿主仓库的 `.github/workflows/verify-notes.yml`,核对安装路径并提交 Skill 文件后启用。安装 Skill 本身不会自动启用 CI。
232
+
233
+ ### 装上 Skill 之后
234
+
235
+ ```bash
236
+ npx skills add czm15053/write-notes-like-deepseek
237
+ ```
238
+
239
+ 把以下规则加入项目的 `AGENTS.md` 或 `CLAUDE.md`,AI 就会自动遵守:
240
+
241
+ ```markdown
242
+ ## 重要改动必须留笔记
243
+
244
+ 1. 非平凡改动(改了行为、架构、跨文件契约、流程与工具链、测试策略、落盘/网络/配置格式)前,遵循 .agents/skills/write-notes-like-deepseek/SKILL.md 写或更新笔记;机械性小改(样式、格式化、打标、不改行为的补丁)直接提交。
245
+ 2. 写之前先检索 .agents/notes/ 里的同主题旧笔记:有归属就地更新;新想法先放 proposed/,落地随同代码改动转 implemented/;新方案彻底取代旧决策时,同批归档旧篇并标明被谁取代。
246
+ 3. 被放弃的方案先写它最强的理由,再解释为什么不用。
247
+ 4. 提交前跑 npm run verify-notes,红了先修再交。
248
+ ```
249
+
250
+ **日常使用就一句话**——像平时一样提需求,改动大的时候点名让它先立笔记:
251
+
252
+ ```text
253
+ 把鉴权模块从 Session 重构成 JWT,改动比较大,
254
+ 动手前先按 write-notes-like-deepseek 立一篇 Note。
255
+ ```
256
+
257
+ AI 会自动在 `proposed/` 输出结构化提案(背景、备选及各自的最强理由、验收标准),等你确认后施工;代码落地时,笔记随同转为 `implemented/`。
258
+
259
+ ---
260
+
261
+ ## 辅助工具:决策看板
262
+
263
+ 不是必需品,只是个顺手的观察窗:一条命令生成单文件 `board.html`,双击就能看——**被引用最多的那几篇笔记**(就是这套系统里最怕碰的决定)、所有被否决方案的避坑清单、按月份的演进时间线。日常开发中它直读本地笔记目录,改了笔记切回浏览器就自动刷新;也可以打包成单文件发到网上([在线演示](https://czm15053.github.io/write-notes-like-deepseek-demo/)就是这么来的)。
264
+
265
+ ```bash
266
+ npx tsx .agents/skills/write-notes-like-deepseek/scripts/build-board.ts --init board.html "项目决策看板" # 本地直读,热更新
267
+ npx tsx .agents/skills/write-notes-like-deepseek/scripts/build-board.ts --bundle .agents/notes demo.html "项目决策看板" # 打包分发
268
+ ```
269
+
270
+ 真实界面(来自内嵌 DeepSeek Harness 1,267 篇真实笔记的[在线演示](https://czm15053.github.io/write-notes-like-deepseek-demo/)):
271
+
272
+ <p align="center">
273
+ <img src="assets/board-baseline.png" alt="看板真实界面:四组 KPI 总览与「系统承重墙」——按交叉引用权重萃取的最关键决策" width="100%" />
274
+ </p>
275
+
276
+ 点开任意一篇笔记,阅读原文、被放弃方案的最强理由与血缘链路:
277
+
278
+ <p align="center">
279
+ <img src="assets/board-note.png" alt="笔记阅读视图:反向锚点注释一键复制、编号小节、被引用次数与血缘依赖" width="100%" />
280
+ </p>
281
+
282
+ 「避坑智库」汇总了全库被放弃的方案——每一条都先写它最强的理由,再写为什么不用:
283
+
284
+ <p align="center">
285
+ <img src="assets/board-pitfalls.png" alt="避坑智库:每条被放弃的方案都带权衡依据,底部标注最终被采纳的决策" width="100%" />
286
+ </p>
287
+
288
+ 按月份与分类切片,回看全部笔记铺开的演进轨迹:
289
+
290
+ <p align="center">
291
+ <img src="assets/board-timeline.png" alt="演进时间线:月份与分类双维切片,2026-06 至 2026-09 共 1,196 条记录" width="100%" />
292
+ </p>
293
+
294
+ ---
295
+
296
+ ## 仓库导览
297
+
298
+ - [`SKILL.md`](skills/write-notes-like-deepseek/SKILL.md):装给 AI 的主契约——先判「要不要写」,再谈怎么写。
299
+ - [`templates/`](skills/write-notes-like-deepseek/templates/):`proposed` / `implemented` / `rejected` 三份填空模板。
300
+ - [`references/when-to-write.md`](skills/write-notes-like-deepseek/references/when-to-write.md):什么时候写、什么时候原地改、什么时候归档。
301
+ - [`references/archiving.md`](skills/write-notes-like-deepseek/references/archiving.md):封存规矩——被取代的老决定怎么干净归档。
302
+ - [`references/quality-gate.md`](skills/write-notes-like-deepseek/references/quality-gate.md):写完笔记后的语义自检清单。
303
+ - [`references/verification.md`](skills/write-notes-like-deepseek/references/verification.md):每个校验脚本在查什么、为什么。
304
+
305
+
306
+
307
+ ## 友情链接
308
+
309
+ - [LinuxDo](https://linux.do) — 真诚、友善、团结、专业,你的品质开源与技术社区
310
+
311
+ ## 许可证
312
+
313
+ [MIT](LICENSE)
314
+
315
+ ## 仓库维护与安装内容
316
+
317
+ 可安装内容集中在 `skills/write-notes-like-deepseek/`,包含 `SKILL.md`、`references/`、`templates/`、`scripts/` 和看板模板 `assets/agent-notes-board.html`。根目录的 README 配图、CI、导入示例笔记和配图导出脚本用于维护本仓库。
318
+
319
+ 原安装命令 `npx skills add czm15053/write-notes-like-deepseek` 保持不变,无需指定 `--skill`。安装器负责发现子目录中的 Skill 并放入所选 Agent 的安装位置。
320
+
321
+ 维护本仓库时,在仓库根目录执行 `npm run verify-notes`、`npm run init-board` 或 `npm run bundle-board`;`board.html` 和 `demo.html` 均为生成产物。下游项目需自行配置上文的 npm scripts。
322
+
323
+ 运行 `npm run test-skill-install` 可在临时宿主项目中验证安装边界、Codex / Claude Code 安装路径、笔记校验、归档和看板生成。该检查使用固定版本 `skills@1.7.1`,覆盖默认链接和 `--copy` 两种安装方式,且不指定 `--skill`;需要联网获取 CLI 与 tsx,CI 使用 Node.js 24。
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "write-notes-like-deepseek",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "像 DeepSeek 团队一样维护项目:把他们在 DeepSeek Harness 里用的那套方法,装进你的仓库",
7
+ "scripts": {
8
+ "verify-agent-note-tree": "npx tsx skills/write-notes-like-deepseek/scripts/verify-agent-note-tree.ts",
9
+ "verify-agent-note-format": "npx tsx skills/write-notes-like-deepseek/scripts/verify-agent-note-format.ts",
10
+ "verify-archived": "npx tsx skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts",
11
+ "verify-notes": "npx tsx skills/write-notes-like-deepseek/scripts/verify-agent-note-tree.ts && npx tsx skills/write-notes-like-deepseek/scripts/verify-agent-note-format.ts && npx tsx skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts",
12
+ "archive-agent-note": "npx tsx skills/write-notes-like-deepseek/scripts/archive-agent-note.ts",
13
+ "check-anchors": "npx tsx skills/write-notes-like-deepseek/scripts/check-note-anchors.ts",
14
+ "init-board": "npx tsx skills/write-notes-like-deepseek/scripts/build-board.ts --init board.html '工程决策看板'",
15
+ "bundle-board": "npx tsx skills/write-notes-like-deepseek/scripts/build-board.ts --bundle .agents/notes demo.html '工程决策看板'",
16
+ "build-board": "npx tsx skills/write-notes-like-deepseek/scripts/build-board.ts --init board.html '工程决策看板'",
17
+ "import-dsh-notes": "npx tsx scripts/import-dsh-notes.ts",
18
+ "export-assets": "bash scripts/export-assets.sh",
19
+ "test-skill-install": "node scripts/test-skill-install.mjs"
20
+ }
21
+ }
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env bash
2
+ # Export every assets/*.svg to a @2x PNG next to it (SVG is the source of truth).
3
+ # Usage: bash scripts/export-assets.sh # all SVGs
4
+ # bash scripts/export-assets.sh hero # just hero.svg
5
+ set -euo pipefail
6
+
7
+ cd "$(dirname "$0")/.."
8
+
9
+ EXPORTER=""
10
+ if command -v rsvg-convert >/dev/null 2>&1; then
11
+ EXPORTER="rsvg-convert"
12
+ elif command -v inkscape >/dev/null 2>&1; then
13
+ EXPORTER="inkscape"
14
+ else
15
+ echo "error: need rsvg-convert (brew install librsvg) or inkscape to export PNGs" >&2
16
+ exit 1
17
+ fi
18
+
19
+ filter="${1:-}"
20
+ failed=0
21
+ for svg in assets/*.svg; do
22
+ base="$(basename "$svg" .svg)"
23
+ if [ -n "$filter" ] && [ "$base" != "$filter" ]; then
24
+ continue
25
+ fi
26
+ png="assets/${base}.png"
27
+ case "$EXPORTER" in
28
+ rsvg-convert)
29
+ rsvg-convert -w 2800 -o "$png" "$svg" ;;
30
+ inkscape)
31
+ inkscape "$svg" -w 2800 -o "$png" >/dev/null ;;
32
+ esac
33
+ if [ -s "$png" ]; then
34
+ echo "ok: $svg -> $png"
35
+ else
36
+ echo "FAILED: $svg" >&2
37
+ failed=1
38
+ fi
39
+ done
40
+ exit "$failed"
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from 'node:child_process';
4
+ import { readdirSync, readFileSync, writeFileSync, mkdirSync, existsSync, rmSync, rmdirSync } from 'node:fs';
5
+ import { join, resolve, relative, dirname } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+
11
+ const args = process.argv.slice(2);
12
+ const dshNotesDir = args[0] ? resolve(args[0]) : resolve(process.cwd(), '../deepseek-harness/.agents/notes');
13
+ const targetNotesDir = args[1] ? resolve(args[1]) : resolve(__dirname, '../.agents/notes');
14
+
15
+ const LIFECYCLES = ['implemented', 'proposed', 'rejected', 'archived'];
16
+
17
+ if (!existsSync(dshNotesDir)) {
18
+ console.error(`❌ Source dsh notes not found at: ${dshNotesDir}`);
19
+ process.exit(1);
20
+ }
21
+
22
+ console.log(`📦 正在从 ${dshNotesDir} 提取并标准化中文 Note...`);
23
+
24
+ // 扫描所有文件并配对:优先取 .zh.md
25
+ const noteMap = new Map<string, string>(); // cleanRelPath -> sourceFilePath
26
+
27
+ function scan(currentDir: string) {
28
+ const entries = readdirSync(currentDir, { withFileTypes: true });
29
+ for (const entry of entries) {
30
+ if (entry.name.startsWith('.')) continue;
31
+ const fullPath = join(currentDir, entry.name);
32
+
33
+ if (entry.isDirectory()) {
34
+ scan(fullPath);
35
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
36
+ const rel = relative(dshNotesDir, fullPath).replace(/\\/g, '/');
37
+ const isZh = entry.name.endsWith('.zh.md');
38
+ const cleanRel = isZh ? rel.replace(/\.zh\.md$/, '.md') : rel;
39
+ const parts = cleanRel.split('/');
40
+
41
+ if (parts.length >= 3 && LIFECYCLES.includes(parts[0])) {
42
+ if (!noteMap.has(cleanRel) || isZh) {
43
+ noteMap.set(cleanRel, fullPath);
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ scan(dshNotesDir);
51
+ console.log(`🔍 扫描完毕,发现 ${noteMap.size} 篇唯一 Note 待迁移。`);
52
+
53
+ let copied = 0;
54
+ for (const [cleanRel, sourcePath] of noteMap.entries()) {
55
+ const destPath = join(targetNotesDir, cleanRel);
56
+ mkdirSync(dirname(destPath), { recursive: true });
57
+
58
+ let content = readFileSync(sourcePath, 'utf8');
59
+
60
+ // 1. 去除多余的双语切换条目,例如 `[English](xxx.md) | 中文` 或 `English | [中文](xxx.zh.md)`
61
+ content = content.replace(/^\[English\]\([^)]+\)\s*\|\s*中文\s*\n+/m, '');
62
+ content = content.replace(/^English\s*\|\s*\[中文\]\([^)]+\)\s*\n+/m, '');
63
+ content = content.replace(/^\[English\]\([^)]+\)\s*\n+/m, '');
64
+
65
+ // 2. 将文内所有的 `.zh.md` 相对链接归一化为标准的 `.md`(包括带有 #anchor 的链接)
66
+ content = content.replace(/\]\(([^)#]+)\.zh\.md([#)])/g, ']($1.md$2');
67
+
68
+ writeFileSync(destPath, content, 'utf8');
69
+ copied++;
70
+ }
71
+
72
+ // 拷贝 README.md 和 AGENTS.md 到 .agents/notes 根目录供相对跳转
73
+ for (const topDoc of ['README.zh.md', 'README.md', 'AGENTS.md']) {
74
+ const p = join(dshNotesDir, topDoc);
75
+ if (existsSync(p)) {
76
+ let topContent = readFileSync(p, 'utf8').replace(/\]\(([^)#]+)\.zh\.md([#)])/g, ']($1.md$2');
77
+ writeFileSync(join(targetNotesDir, topDoc === 'README.zh.md' ? 'README.md' : topDoc), topContent, 'utf8');
78
+ }
79
+ }
80
+
81
+ // 清理已在源端被移除或移动的旧 Note
82
+ function cleanTarget(currentDir: string) {
83
+ if (!existsSync(currentDir)) return;
84
+ const entries = readdirSync(currentDir, { withFileTypes: true });
85
+ for (const entry of entries) {
86
+ if (entry.name.startsWith('.')) continue;
87
+ const fullPath = join(currentDir, entry.name);
88
+ if (entry.isDirectory()) {
89
+ cleanTarget(fullPath);
90
+ try {
91
+ if (readdirSync(fullPath).length === 0) {
92
+ rmdirSync(fullPath);
93
+ }
94
+ } catch {}
95
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
96
+ const rel = relative(targetNotesDir, fullPath).replace(/\\/g, '/');
97
+ if (rel === 'README.md' || rel === 'AGENTS.md' || rel === 'archived/AGENTS.md') continue;
98
+ if (!noteMap.has(rel)) {
99
+ rmSync(fullPath);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ cleanTarget(targetNotesDir);
105
+
106
+ // 拷贝 archived/AGENTS.md
107
+ const archivedAgents = join(dshNotesDir, 'archived', 'AGENTS.md');
108
+ if (existsSync(archivedAgents)) {
109
+ mkdirSync(join(targetNotesDir, 'archived'), { recursive: true });
110
+ writeFileSync(join(targetNotesDir, 'archived', 'AGENTS.md'), readFileSync(archivedAgents, 'utf8'), 'utf8');
111
+ }
112
+
113
+ // 重建归档 Note 密封清单:本地笔记经过标准化,与上游原文不同,seal 必须基于本地文件重算
114
+ const localManifest = join(targetNotesDir, 'archived', 'manifest.json');
115
+ if (existsSync(localManifest)) {
116
+ try {
117
+ rmSync(localManifest);
118
+ } catch {}
119
+ }
120
+
121
+ try {
122
+ execSync('npx tsx skills/write-notes-like-deepseek/scripts/verify-archived-agent-notes.ts --write', { stdio: 'ignore' });
123
+ } catch {}
124
+
125
+ console.log(`✅ 成功将 ${copied} 篇中文 Note 标准化写入到: ${targetNotesDir}`);
@@ -0,0 +1,63 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { existsSync, mkdtempSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { dirname, join, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const repo = resolve(dirname(fileURLToPath(import.meta.url)), '..');
9
+ const scratch = realpathSync(mkdtempSync(join(tmpdir(), 'notes-skill-install-')));
10
+ const env = { ...process.env, DISABLE_TELEMETRY: '1' };
11
+ delete env.AGENT_NOTE_ROOT;
12
+ delete env.AGENT_NOTE_ARCHIVE_BASE_REF;
13
+
14
+ function run(cwd, args, success = true) {
15
+ const result = spawnSync('npx', ['--yes', ...args], { cwd, env, encoding: 'utf8' });
16
+ if (result.error) throw result.error;
17
+ assert.equal(result.status === 0, success, `${args.join(' ')}\n${result.stdout}\n${result.stderr}`);
18
+ return result.stdout;
19
+ }
20
+
21
+ try {
22
+ for (const mode of ['symlink', 'copy']) {
23
+ const host = join(scratch, mode);
24
+ mkdirSync(host);
25
+ // Deliberately omit --skill: discover the single skill from the repository root.
26
+ const output = run(host, ['skills@1.7.1', 'add', repo, '--agent', 'codex', 'claude-code', '-y',
27
+ ...(mode === 'copy' ? ['--copy'] : [])]);
28
+ assert.match(output, /write-notes-like-deepseek/);
29
+
30
+ const canonical = join(host, '.agents/skills/write-notes-like-deepseek');
31
+ const claude = join(host, '.claude/skills/write-notes-like-deepseek');
32
+ for (const installed of [canonical, claude]) {
33
+ assert.deepEqual(readdirSync(installed).sort(), ['SKILL.md', 'assets', 'references', 'scripts', 'templates']);
34
+ assert.deepEqual(readdirSync(join(installed, 'assets')), ['agent-notes-board.html']);
35
+ assert.ok(existsSync(join(installed, 'templates/verify-notes.yml')));
36
+ assert.equal(readFileSync(join(installed, 'SKILL.md'), 'utf8'),
37
+ readFileSync(join(repo, 'skills/write-notes-like-deepseek/SKILL.md'), 'utf8'));
38
+ }
39
+
40
+ const noteDir = join(host, '.agents/notes/implemented/process');
41
+ mkdirSync(noteDir, { recursive: true });
42
+ const note = join(noteDir, '2026-10-07-install-check.md');
43
+ writeFileSync(note, '# Agent Note: Install check\n\nStatus: implemented\n\n## Problem\nValidate installed paths.\n\n## Decision\nRun from the host project.\n\n## Alternatives considered\nRunning from the skill directory targets the wrong notes.\n\n## Consequences\nHost notes are checked.\n');
44
+ const script = (name) => join(canonical, 'scripts', `${name}.ts`);
45
+ for (const name of ['verify-agent-note-tree', 'verify-agent-note-format', 'verify-archived-agent-notes']) {
46
+ run(host, ['tsx', script(name)]);
47
+ }
48
+ // A broken host note must fail even though the installed skill has no notes.
49
+ writeFileSync(note, readFileSync(note, 'utf8').replace('Status: implemented', 'Status: proposed'));
50
+ run(host, ['tsx', join(claude, 'scripts/verify-agent-note-format.ts')], false);
51
+ writeFileSync(note, readFileSync(note, 'utf8').replace('Status: proposed', 'Status: implemented'));
52
+ run(host, ['tsx', script('build-board'), '--init', 'board.html', 'Install check']);
53
+ assert.match(readFileSync(join(host, 'board.html'), 'utf8'), /Install check/);
54
+ run(host, ['tsx', script('build-board'), '--bundle', '.agents/notes', 'demo.html', 'Install check']);
55
+ assert.match(readFileSync(join(host, 'demo.html'), 'utf8'), /Host notes are checked/);
56
+ run(host, ['tsx', script('archive-agent-note'), note]);
57
+ run(host, ['tsx', script('verify-archived-agent-notes')]);
58
+ assert.ok(existsSync(join(host, '.agents/notes/archived/process/2026-10-07-install-check.md')));
59
+ console.log(`ok: ${mode} installation, Codex/Claude paths, host validation, boards, archive`);
60
+ }
61
+ } finally {
62
+ rmSync(scratch, { recursive: true, force: true });
63
+ }