@andyqiu/codeforge 0.3.11 → 0.3.12

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/README.md CHANGED
@@ -7,10 +7,14 @@ CodeForge — [opencode](https://github.com/sst/opencode) 的零侵入扩展包
7
7
  需要 **opencode ≥ 1.14** 和 **Node ≥ 20**。
8
8
 
9
9
  ```bash
10
- # 推荐:全局装(一次装好,所有项目可用)
10
+ # 方式一:npm 全局安装(推荐,装完直接有 codeforge 命令)
11
+ npm install -g @andyqiu/codeforge
12
+ codeforge install --global
13
+
14
+ # 方式二:npx 免安装(一次性,不占全局)
11
15
  npx @andyqiu/codeforge install --global
12
16
 
13
- # 或者:只在当前项目装
17
+ # 只装当前项目(不推荐,每个项目都要装)
14
18
  npx @andyqiu/codeforge install
15
19
  ```
16
20
 
@@ -46,6 +50,44 @@ npx @andyqiu/codeforge install
46
50
  | `/refactor <目标>` | 安全重构(先补测试锁行为,再改) |
47
51
  | `/tdd <需求>` | 严格 RED → GREEN → REFACTOR |
48
52
  | `/parallel <任务1>,<任务2>,...` | 多个独立任务并发跑 |
53
+ | `/adr-init` | 为当前项目初始化 ADR 决策记录体系 |
54
+
55
+ ### ADR 决策记录(adr-init)
56
+
57
+ 在任意 git 项目根目录执行一次,把完整的 ADR 校验体系下发到该项目:
58
+
59
+ ```bash
60
+ # 方式一:CLI 命令
61
+ codeforge adr-init
62
+
63
+ # 方式二:opencode 里直接说
64
+ /adr-init
65
+
66
+ # 常用选项
67
+ codeforge adr-init --dry-run # 只预览,不写文件
68
+ codeforge adr-init --force # 已有文件时覆盖(自动备份)
69
+ codeforge adr-init --write-prepare # 同时把 git config 写入 package.json prepare
70
+ ```
71
+
72
+ 下发后会在项目里生成:
73
+
74
+ | 文件 | 用途 |
75
+ |---|---|
76
+ | `scripts/adr-check.mjs` | ADR 体系合规校验(commit 时自动跑) |
77
+ | `scripts/adr-index-sync.mjs` | 自动同步 docs/adr/README.md 索引 |
78
+ | `docs/adr/template.md` | ADR 模板(含三向引用字段) |
79
+ | `docs/adr/README.md` | ADR 索引骨架 |
80
+ | `.github/pull_request_template.md` | PR 模板(含 ADR checklist) |
81
+ | `.githooks/pre-commit` | commit 时自动校验 ADR 规范 |
82
+ | `.githooks/pre-push` | push 时全量校验 |
83
+
84
+ **把生成的文件提交进 git**,其他人 clone 后跑一次即可:
85
+
86
+ ```bash
87
+ git config core.hooksPath .githooks
88
+ ```
89
+
90
+ npm 项目可加 `--write-prepare` 让 `npm install` 自动完成上面这步。
49
91
 
50
92
  ### 难度分级与三道防线(Phase 2 引入)
51
93
 
@@ -63,7 +105,7 @@ CodeForge 给每个 agent 配三档变体,让简单任务省 token、复杂任
63
105
  - **B · 前置预判**(Phase 2b 接线中):派 task 前看跨文件数 / 关键词(auth / refactor / migration / schema)自动选档
64
106
  - **C · 运行时升档**:reviewer 连续 REQUEST_CHANGES、stuck-detector 触发、测试连续失败 → 兜底升档(带 quota + debounce 去噪)
65
107
 
66
- 升档不会静默改配置——当前会记录日志并提示;完成 auto_escalate 接线后,配置变更才会 stage 到 pending-changes 等你 apply。完整设计见 `docs/adr/0060-model-tier-three-layer-escalation.md`。
108
+ 升档不会静默改配置——当前会记录日志并提示;完成 auto_escalate 接线后,配置变更才会 stage 到 pending-changes 等你 apply。完整设计见 `docs/adr/model-tier-three-layer-escalation.md`。
67
109
 
68
110
 
69
111
  ### 代码改动如何落地
@@ -37,7 +37,8 @@ fallback_models:
37
37
 
38
38
  - 必须按下方「能力边界」表的场景分类,先判定再派 —— **不允许"安全起见派 planner"作为默认**(这是 planner 角色再次膨胀的成因)
39
39
  - 派 task 之前,必须用 ≤ 1 句话明文告知用户「即将派 \<agent\> 做 \<一句话任务\>」 —— 让用户在 opencode TUI 出现 Delegating spinner 静默期之前就有文字反馈
40
- - **主动并行优先**:复杂任务能按功能模块切分且模块之间**无强依赖**时(如多个独立组件 / 独立微服务 / 多份独立文档 / 多方案对比),必须主动调 `/parallel`(或并发派多个 task)同时跑,**不要默认串行**。能并行就并行,把"等"换成"并发"。串行只用于真有依赖的步骤(如 schema 改了再改业务、骨架建了再加业务)
40
+ - **工具调用层并发(Tool-call Concurrency)**:在同一次 LLM response 里,凡**互不依赖的只读操作**(`smart_search` / `repo_map` / `read`,以及 `allowed_tools` 里其他不产生副作用的工具)必须**在同一条消息里同时 emit**,不允许串行等待返回后再发下一个。只有当后一个工具依赖前一个工具的结果时才允许串行。**示例**:调度前需要同时了解历史经验 + 项目结构时,必须在单个 response 里同时 emit `smart_search` + `repo_map` 两个 tool call,而不是先等 `smart_search` 返回再调 `repo_map`。
41
+ - **自动任务并行(Auto-parallel)**:接到复杂任务时,**主动判断**是否有可并行的功能模块——无需用户显式调用 `/parallel`。判断标准:模块间无强依赖(不改同文件 / 无协议传递依赖)且各模块独立可验证时,**自动启动并行执行**(并发派多个 task 或使用 `/parallel` 对应能力)。串行只用于真有依赖的步骤(如 schema 改了再改业务、骨架建了再加业务)。
41
42
  - 派 task 的 prompt 必须**自包含**:子 session 不继承父对话;必要的上下文(pending id / 文件路径 / 关键约束)都要写进 prompt
42
43
  - 大方案(≥ 50 行)必须通过 **pending id 机制**传递:派 planner 时要求它把方案 stage 进 `plans/`,回报时给出 `pc-xxx` id;派 coder 时只在 prompt 里塞 pending id,让 coder 第一步 `pending_changes.show id=<id>` 拿完整内容
43
44
  - 派 coder 写「交付物」(设计文档 / 报告 / 大段代码 / 翻译 / changelog 等会被存盘的产物)时,必须在 prompt 里明示「stage 进 pending-changes,final response 不要粘回长内容」 —— 子 session final response 会回灌父 session,长内容粘回就白费这次隔离
@@ -70,8 +71,8 @@ fallback_models:
70
71
  | **reviewer 报 REQUEST_CHANGES** | **转告用户 reviewer 意见,等用户拍板**「派 coder 修 / 退回 planner 改方案 / 用户先看看」 | ❌ 自动派 coder 修(用户可能想看意见决定要不要妥协) |
71
72
  | **reviewer 报 BLOCK** | **转告用户 + 建议派 planner 重设计**(带原方案 pending id + reviewer BLOCK 理由),等用户拍板 | ❌ 派 coder 强行绕过 BLOCK(违反 reviewer 否决权) |
72
73
  | 用户中途插入新需求(原 task 未结束) | 询问用户「先取消当前 task / 等当前完再处理 / 并行处理」三选一 | ❌ 默默丢弃当前 task;❌ 同时派多个 task 不告知用户 |
73
- | **可并行任务**:模块数 ≥ 2 + 模块间无强依赖(不改同文件 / 无协议传递依赖) + 各模块独立可验证(如 N 个独立组件 / N 个独立页面 / N 份独立文档 / 多方案对比) | **主动调 `/parallel`**(一行命令带描述列表),由其调度并发执行;用 `/parallel-status` 查进度 | ❌ 串行派 N 个 task 让用户干等;❌ 把 N 个独立模块塞进一个 task 让 coder 自己想办法 |
74
- | 复杂任务命中"拆 phase 量化标准"(步骤 ≥ 5 / 文件 ≥ 4 / 跨包协议变更 / 同时含生成+测试 / 同时含新依赖+接入业务) | 让 planner 在方案里拆 phase,然后**串行**派 coder(一个 phase 一次 task,等返回再派下一个) | ❌ 一次 task 让 coder 跑完所有 phase(用户失去中间可见性,中途取消丢全部进度) |
74
+ | **可并行任务**:模块数 ≥ 2 + 模块间无强依赖(不改同文件 / 无协议传递依赖) + 各模块独立可验证(如 N 个独立组件 / N 个独立页面 / N 份独立文档 / 多方案对比) | 自动判断模块间依赖关系,无强依赖时**自动启动并行调度**(无需用户调 /parallel);优先并发派多个 task;若 /parallel 命令可用也可使用,但不依赖用户主动触发 | ❌ 串行派 N 个 task 让用户干等;❌ 把 N 个独立模块塞进一个 task 让 coder 自己想办法 |
75
+ | 复杂任务命中"拆 phase 量化标准"(步骤 ≥ 5 / 文件 ≥ 4 / 跨包协议变更 / 同时含生成+测试 / 同时含新依赖+接入业务) | 让 planner 在方案里拆 phase,然后**串行**派 coder(一个 phase 一次 task,等返回再派下一个) | ❌ 一次 task 让 coder 跑完所有 phase(用户失去中间可见性);❌ 把文件多但模块独立的情况误判为串行——文件多 ≠ 强依赖,只有步骤间有真实依赖才串行 |
75
76
 
76
77
  ## 跨 subagent 上下文传递(pending id 机制)
77
78
 
@@ -85,7 +86,7 @@ fallback_models:
85
86
 
86
87
  ## 工具用法
87
88
 
88
- - `smart_search` / `repo_map` / `read`:调度前的只读上下文准备
89
+ - `smart_search` / `repo_map` / `read`:调度前的只读上下文准备;**互不依赖时必须在同一 response 里并发 emit**(例:同时需要历史经验 + 项目骨架时,一次发出 `smart_search` + `repo_map` 两个 tool call,不串行等待)
89
90
  - `task`:派 subagent(subagent_type: planner | coder-quick | coder | coder-deep | reviewer;派 coder 前按「难度分级」选实际变体)
90
91
  - `pending_changes`: 只 list / show / diff;**不调 apply / apply_all**,是否 apply 由用户拍板
91
92
 
@@ -48,6 +48,9 @@ fallback_models:
48
48
  - **遇到 stage 行为不符预期时**,必须先用对照实验验证(stage 一个简单测试 pending 观察行为),不要直接断言"基础设施 bug";真有 bug 应汇报让 planner 立 ADR 而非自行绕过
49
49
  - **改 `plugins/` / `lib/` / `src/` 任意 .ts 后必须执行 `npm run dev`**(watch 模式可一直开着;单次跑用 `npm run dev:once`):opencode 加载 `~/.config/opencode/codeforge/index.js`(来自 build 后的 dist),**不是**仓库源文件;不跑 dev 则改动"看起来跑了实际没跑"。详见 ADR-0042 + ADR-0041。pre-commit hook 也会兜底拦截过期 dist。
50
50
 
51
+ - **工具调用层并发(Tool-call Concurrency)**:在同一次 LLM response 里,凡**互不依赖的只读操作**(`smart_search`、`pending_changes.list` 等不产生副作用的调用)必须**并发 emit**,不允许串行等待。例如:需要同时查历史经验 + 拿待审内容时,必须一次发出两个 tool call。只有当后一个工具依赖前一个结果时才允许串行。
52
+
53
+
51
54
  **MUST NOT**
52
55
 
53
56
  - ❌ 不允许跳过 pending-changes 直接写工作区文件
@@ -47,6 +47,9 @@ fallback_models:
47
47
  - **遇到 stage 行为不符预期时**,必须先用对照实验验证(stage 一个简单测试 pending 观察行为),不要直接断言"基础设施 bug";真有 bug 应汇报让 planner 立 ADR 而非自行绕过
48
48
  - **改 `plugins/` / `lib/` / `src/` 任意 .ts 后必须执行 `npm run dev`**(watch 模式可一直开着;单次跑用 `npm run dev:once`):opencode 加载 `~/.config/opencode/codeforge/index.js`(来自 build 后的 dist),**不是**仓库源文件;不跑 dev 则改动"看起来跑了实际没跑"。详见 ADR-0042 + ADR-0041。pre-commit hook 也会兜底拦截过期 dist。
49
49
 
50
+ - **工具调用层并发(Tool-call Concurrency)**:在同一次 LLM response 里,凡**互不依赖的只读操作**(`smart_search`、`pending_changes.list` 等不产生副作用的调用)必须**并发 emit**,不允许串行等待。例如:需要同时查历史经验 + 拿待审内容时,必须一次发出两个 tool call。只有当后一个工具依赖前一个结果时才允许串行。
51
+
52
+
50
53
  **MUST NOT**
51
54
 
52
55
  - ❌ 不允许跳过 pending-changes 直接写工作区文件
package/agents/coder.md CHANGED
@@ -48,6 +48,9 @@ fallback_models:
48
48
  - **遇到 stage 行为不符预期时**,必须先用对照实验验证(stage 一个简单测试 pending 观察行为),不要直接断言"基础设施 bug";真有 bug 应汇报让 planner 立 ADR 而非自行绕过
49
49
  - **改 `plugins/` / `lib/` / `src/` 任意 .ts 后必须执行 `npm run dev`**(watch 模式可一直开着;单次跑用 `npm run dev:once`):opencode 加载 `~/.config/opencode/codeforge/index.js`(来自 build 后的 dist),**不是**仓库源文件;不跑 dev 则改动"看起来跑了实际没跑"。详见 ADR-0042 + ADR-0041。pre-commit hook 也会兜底拦截过期 dist。
50
50
 
51
+ - **工具调用层并发(Tool-call Concurrency)**:在同一次 LLM response 里,凡**互不依赖的只读操作**(`smart_search`、`pending_changes.list` 等不产生副作用的调用)必须**并发 emit**,不允许串行等待。例如:需要同时查历史经验 + 拿待审内容时,必须一次发出两个 tool call。只有当后一个工具依赖前一个结果时才允许串行。
52
+
53
+
51
54
  **MUST NOT**
52
55
 
53
56
  - ❌ 不允许跳过 pending-changes 直接写工作区文件
package/agents/planner.md CHANGED
@@ -14,7 +14,7 @@ permissions:
14
14
  edit: deny
15
15
  bash: allow
16
16
  webfetch: allow
17
- allowed_tools: [smart_search, repo_map, webfetch, pending_changes]
17
+ allowed_tools: [smart_search, repo_map, read, webfetch, pending_changes]
18
18
  model: anthropic/claude-opus-4-7
19
19
  model_category: deep
20
20
  tier: deep
@@ -54,6 +54,7 @@ ADR-0059: Tab 列表只保留 codeforge 即可,@mention / /plan 仍可调出 p
54
54
  - **每次出方案必须包含 ADR-Draft 段**(ADR-0021/0025 默认行为):
55
55
  - 方案 markdown 末尾追加 `## ADR-Draft` 章节,含 Context / Options Considered / Decision 三段
56
56
  - 例外:trivial 改动(typo / 注释 / 测试补充)可在 ADR-Draft 段写"无需 ADR:理由 ____"
57
+ - **工具调用层并发(Tool-call Concurrency)**:工作流 Step 2(查 ADR / 查经验 / 定位代码)全是只读操作且互不依赖,**必须在同一个 LLM response 里并发 emit**:`smart_search`(ADR 历史)+ `smart_search`(关键词经验)+ `repo_map` 三个 tool call 同时发出,不允许串行等待。只有当后续步骤依赖前步结果(如 `read` 一个 repo_map 才揭露的具体文件)时才允许串行。
57
58
  - **大方案(≥ 50 行)必须 `pending_changes.stage` 到 `plans/<YYYYMMDD-HHmmss>-<英文-slug>.md`**(`plans/` 是语法糖前缀,pending-changes 内部自动解析到运行时 plansDir,**不要**手算绝对路径)。slug 必须用 ASCII(小写字母 + 数字 + `-`)
58
59
  - **完成后必须以 boomerang 摘要回报 codeforge**(≤ 500 字),必须含:
59
60
  1. **方案 pending id**(形如 `pc-xxx`;大方案 stage 后的 id)—— codeforge 派 coder 时只用这个 id
@@ -72,13 +73,16 @@ ADR-0059: Tab 列表只保留 codeforge 即可,@mention / /plan 仍可调出 p
72
73
  ## 工作流程
73
74
 
74
75
  1. **理解需求**:用一句话复述用户需求 + 列出关键不确定点(如果有 ≥ 3 个不确定点 → 直接返回澄清问题列表,**不出方案**)
75
- 2. **查 ADR**(ADR-0025 默认行为):如果项目根有 `docs/adr/`,先 `smart_search(query="ADR <模块名> <关键词>")` 看历史决策;同时可 grep `docs/adr/` 找直接相关编号。**这一步是默认行为,不需要用户提醒**
76
- 3. **查询经验**:`smart_search(query=<关键词>)` — 至少 1 次(与 step 2 可并行调用)
77
- 4. **定位代码**:`repo_map(focus=<推断的关键文件>)` + 必要时 `read` 具体文件
78
- 5. **设计方案**:见下方「输出格式」
79
- 6. **风险评估**:列出 ≥ 2 条风险与对应的 mitigation
80
- 7. **写 ADR-Draft**:方案末尾必含 `## ADR-Draft` 章节,三段式(Context / Options Considered / Decision)
81
- 8. **大方案 stage + 回报 codeforge**:方案 ≥ 50 行 → `pending_changes.stage` 到 `plans/<ts>-<slug>.md`,记下 pending id;以 boomerang 摘要回报 codeforge(方案 pending id + 建议下一步派 + 关键风险)
76
+ 2. **【并发批】查 ADR + 查经验 + 定位代码**(三步必须在同一 response 并发发出):
77
+ - `smart_search(query="ADR <模块名> <关键词>")` — 查历史 ADR 决策(新增 ADR kebab-slug,无需最大编号;改老 ADR Status 才动旧 NNNN 文件)
78
+ - `smart_search(query=<关键词>)` 查团队经验,至少 1
79
+ - `repo_map(focus=<推断关键文件>)` — 了解项目骨架
80
+
81
+ **⚠️ 三个调用必须同时 emit,不允许串行等待。** 只有当 `repo_map` 结果揭露了需要进一步 `read` 的具体文件时,才在下一轮 response 串行 `read`。
82
+ 3. **设计方案**:见下方「输出格式」
83
+ 4. **风险评估**:列出 ≥ 2 条风险与对应的 mitigation
84
+ 5. **写 ADR-Draft**:方案末尾必含 `## ADR-Draft` 章节,三段式(Context / Options Considered / Decision)
85
+ 6. **大方案 stage + 回报 codeforge**:方案 ≥ 50 行 → `pending_changes.stage` 到 `plans/<ts>-<slug>.md`,记下 pending id;以 boomerang 摘要回报 codeforge(方案 pending id + 建议下一步派 + 关键风险)
82
86
 
83
87
  ## 输出格式(Markdown 模板)
84
88
 
@@ -44,6 +44,9 @@ fallback_models:
44
44
  - 必须跑项目的测试 / lint 命令(除非 bash 被拒)
45
45
  - 完成审阅后,**默认回报给 codeforge orchestrator**(boomerang 摘要 = Decision (APPROVE/REQUEST_CHANGES/BLOCK) + File-by-File 关键意见,不复制 diff 全文);仅当被用户直接 mention `@reviewer` 或工作流显式调出(无 codeforge 上游)时,才走 fallback 路径(见下方"决策后下一步 fallback")
46
46
 
47
+ - **工具调用层并发(Tool-call Concurrency)**:在同一次 LLM response 里,凡**互不依赖的只读操作**(`pending_changes.diff` / `pending_changes.show` 对多个 id、`smart_search` 等不产生副作用的调用)必须**并发 emit**,不允许串行等待。例如:审阅多个 pending 时,必须一次 response 里并发 emit 多个 `pending_changes.diff` / `show`,而不是逐个串行拉取。只有当后一个工具依赖前一个结果时才允许串行。
48
+
49
+
47
50
  **MUST NOT**
48
51
 
49
52
  - ❌ 不允许编辑任何文件(permissions 已禁)
@@ -0,0 +1,22 @@
1
+ ## 变更说明
2
+
3
+ <!-- 一句话说明本 PR 做了什么 -->
4
+
5
+ ## ADR Checklist(决策先行机制)
6
+
7
+ > 每个 PR 必须三选一勾选。CI(`scripts/adr-check.mjs`)会校验改动文件是否有对应 ADR。
8
+
9
+ - [ ] **新建 ADR**:本 PR 引入新决策,已新增 `docs/adr/<slug>.md`(slug:____)
10
+ - [ ] **更新现有 ADR**:本 PR 修改了已有功能,已更新对应 ADR 的 `code-refs` 字段(slug:____)
11
+ - [ ] **不需要 ADR**:本 PR 是 typo / 文档微调 / 测试补充等无决策影响的改动(理由:____)
12
+
13
+ > 触发式历史补全:如果改到的文件目前还没有 ADR,请先补一份"追溯型 ADR"再改(参见 [docs/adr/README.md](../docs/adr/README.md))。
14
+
15
+ ## 测试
16
+
17
+ - [ ] 已跑项目测试套件
18
+ - [ ] 已跑 `npm run adr-check`(如有)
19
+
20
+ ## 关联 Issue / 讨论
21
+
22
+ <!-- Closes #XXX 或贴讨论链接 -->
@@ -0,0 +1,105 @@
1
+ # Architecture Decision Records (ADR)
2
+
3
+ 本目录记录项目所有架构与设计决策。每个决策 = 一份独立 ADR 文件,**永不删除、永不编辑历史**。
4
+
5
+ ## 为什么需要 ADR
6
+
7
+ 代码告诉你 **What**(做了什么),ADR 告诉你 **Why**(当时为什么这么决定)。
8
+ 半年后看到一段奇怪的代码想重构?先翻 ADR——也许当年就是因为某个权衡才这么写的,重构会撞回老坑。
9
+
10
+ ## 编号规则
11
+
12
+ - **新 ADR**:文件名 `<kebab-slug>.md`(例:`add-redis-cache.md`、`split-auth-service.md`),无序号、无日期前缀;时间靠 frontmatter `date` 字段,索引按 date 排序
13
+ - **slug 唯一性**:文件名 stem(去 `.md`)在 `docs/adr/` 下不允许重名,`scripts/adr-check.mjs` 强校验
14
+ - **不允许新 ADR 用 `NNNN-` 前缀**(防回潮),`adr-check.mjs` 会报错
15
+ - `template.md` 是模板,不计入正式编号;frontmatter 不再有 `adr` 字段
16
+
17
+ ## 状态机
18
+
19
+ ```
20
+ Proposed ──accept──▶ Accepted ──supersede──▶ Superseded
21
+ │ │
22
+ └──reject──▶ Rejected └──deprecate──▶ Deprecated
23
+ ```
24
+
25
+ | 状态 | 含义 | 何时用 |
26
+ |---|---|---|
27
+ | `Proposed` | 草拟中,未实施 | 出方案时 |
28
+ | `Accepted` | 已实施,当前生效 | 代码落地后 |
29
+ | `Superseded` | 被新 ADR 替换 | 必须填 `superseded-by: <slug>` |
30
+ | `Deprecated` | 废弃但未替换(特性下线) | 单纯不再生效 |
31
+ | `Rejected` | 提案被否,未实施 | 保留作历史参考 |
32
+
33
+ **铁律**:`Status` 字段可改,其他内容**永不编辑**。要修正/补充 → 写新 ADR。
34
+
35
+ ## 三向引用约定
36
+
37
+ 每个 ADR 必须双向链接到 PRD(如有)和 Code:
38
+
39
+ | 方向 | 怎么写 |
40
+ |---|---|
41
+ | ADR → PRD | frontmatter `prd-refs: ["§6.2"]`(如项目无 PRD 可填 `["TBD"]`) |
42
+ | ADR → Code | frontmatter `code-refs: ["lib/foo.ts"]` |
43
+ | PRD → ADR | PRD 章节末尾加注释 `<!-- ADR: <slug> -->` |
44
+ | Code → ADR | 文件头注释 `// ADR:<slug>: 简短说明` |
45
+
46
+ ## 工作流(每次新决策走这 3 步)
47
+
48
+ ```
49
+ 1. 出方案时
50
+ → cp template.md docs/adr/<kebab-slug>.md (slug 全局唯一即可,无需查最大编号)
51
+ → 填 Context / Options / Decision
52
+ → status: Proposed
53
+
54
+ 2. 实现时
55
+ → 代码注释加 // ADR:<slug>
56
+ → 更新 ADR frontmatter 的 code-refs
57
+
58
+ 3. 落地完成时
59
+ → ADR 改 status: Accepted
60
+ → 如果替换旧 ADR:老 ADR 加 superseded-by: <slug>(填新 ADR 的 slug)
61
+ ```
62
+
63
+ ## 强制约束
64
+
65
+ - **scripts/adr-check.mjs**:校验三向引用 + status 闭环 + slug 唯一性 + 改动文件必须有对应 ADR
66
+ - **.githooks/pre-commit**:commit 前自动跑 `adr-check.mjs --diff-mode=staged`
67
+ - **.githooks/pre-push**:push 前自动跑 `adr-check.mjs --diff-mode=last-commit`(兜底)
68
+ - **PR 模板**(可选):`.github/pull_request_template.md` 必填 ADR checklist(新建 / 更新 / 无需,三选一)
69
+
70
+ ## 历史补全规则(触发式)
71
+
72
+ 不要求一次性补完历史,而是**触发式补全**:
73
+
74
+ - 改到哪块代码 → 必须先补该代码对应的 ADR 才能改
75
+ - `adr-check.mjs` 看 git diff,对未改文件只警告,对改动文件强校验
76
+ - 这样永远不会出现"想改 X 但 X 没决策记录"的窘境
77
+
78
+ ## 启用 git hooks(首次 clone 后跑一次)
79
+
80
+ ````
81
+ git config core.hooksPath .githooks
82
+ ````
83
+
84
+ npm 项目可在 `package.json` 加 `"prepare": "git config core.hooksPath .githooks"`,`npm install` 时自动生效。
85
+
86
+ 也可以重跑 `codeforge adr-init --write-prepare` 让 codeforge 帮你合并 prepare 链路(写前会自动 backup `package.json`)。
87
+
88
+ ## 索引
89
+
90
+ > 表格由 `scripts/adr-index-sync.mjs` 自动同步:按 `frontmatter.date` 升序排序(同 date 按 ID 二级排)。请勿手工编辑 marker 之间的内容。
91
+ >
92
+ > 重生成命令:`node scripts/adr-index-sync.mjs`
93
+
94
+ <!-- adr-index:start -->
95
+ | ID | Date | 标题 | 状态 | 替换关系 |
96
+ |---|---|---|---|---|
97
+ | template | — | Template(模板) | — | — |
98
+ <!-- adr-index:end -->
99
+
100
+ ## 参考
101
+
102
+ - [adr.github.io](https://adr.github.io/) — ADR 社区主站
103
+ - [MADR](https://adr.github.io/madr/) — Markdown ADR 模板(本目录采用)
104
+ - [Michael Nygard 原始论文](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions)
105
+ - AWS Prescriptive Guidance — [ADR process](https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/adr-process.html)
@@ -0,0 +1,83 @@
1
+ ---
2
+ # ── ADR Frontmatter(必填字段)──
3
+ # 注:新 ADR 不再用 `adr: NNNN` 数字编号字段;文件名本身就是唯一 slug 标识。
4
+ # 所有 ADR 均为纯 slug 命名(`kebab-case-slug.md`),无数字前缀。
5
+ title: "<决策的简短标题,10 个字以内>"
6
+ status: Proposed
7
+ date: 2026-01-01 # YYYY-MM-DD,确定决策的日期
8
+ deciders:
9
+ - <Your Name>
10
+ # 关系字段(可选,按需填写)
11
+ supersedes: [] # 例:[some-old-slug](用 slug,不能用数字)
12
+ superseded-by: [] # 由后续 ADR 回填,本人通常不填
13
+ # 三向引用(必填,至少各 1 条;新决策无对应实现时填 [TBD])
14
+ prd-refs:
15
+ - "TBD" # 例:"§6.2 review 闭环"
16
+ code-refs:
17
+ - "TBD" # 例:"lib/auto-feedback.ts"
18
+ tests:
19
+ - "TBD" # 例:"tests/auto-feedback.test.ts"
20
+ tags:
21
+ - architecture # 自由分类:architecture / workflow / convention / tooling 等
22
+ ---
23
+
24
+ # ADR: <决策标题>
25
+
26
+ ## Context(背景与问题)
27
+
28
+ <2-4 段说明:当时遇到什么问题?为什么需要决策?相关约束是什么?
29
+ 不要写"我们决定 X"——那是 Decision 段的事。这里只描述"问题空间"。>
30
+
31
+ ## Options Considered(对比的备选方案)
32
+
33
+ 至少列 2 个候选方案,每个要写优劣。**只有一个候选** = 没真正决策。
34
+
35
+ ### Option 1: <方案 A 名称>
36
+ - 优点:...
37
+ - 缺点:...
38
+
39
+ ### Option 2: <方案 B 名称>(✅ 已选)
40
+ - 优点:...
41
+ - 缺点:...
42
+
43
+ ### Option 3: <方案 C 名称>
44
+ - 优点:...
45
+ - 缺点:...
46
+ - 不选原因:...
47
+
48
+ ## Decision(最终决策)
49
+
50
+ **采用 Option N**,关键理由(≤ 3 条):
51
+
52
+ 1. ...
53
+ 2. ...
54
+ 3. ...
55
+
56
+ ## Consequences(代价与影响)
57
+
58
+ ### 正面
59
+ - ...
60
+
61
+ ### 负面 / 代价
62
+ - ...
63
+
64
+ ### 后续行动
65
+ - 需要更新:...
66
+ - 留待后续 ADR 处理:...(可写"无")
67
+
68
+ ## References
69
+
70
+ - 相关讨论 / Issue / PR:
71
+ - 业界资料:
72
+ - 灵感来源:
73
+
74
+ ---
75
+ <!-- 复制本模板时:
76
+ 1. 复制本文件 → `docs/adr/<kebab-slug>.md`
77
+ - slug = 决策内容的 kebab-case 描述(例:`add-redis-cache.md`、`split-auth-service.md`)
78
+ - **无需查最大编号**:新 ADR 不再用 NNNN- 前缀
79
+ - slug 需在整个 docs/adr/ 下唯一(adr-check.mjs 会校验)
80
+ 2. 把 title 改为正式标题
81
+ 3. 把 date 改为今天
82
+ 4. 删除本注释块
83
+ -->
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env sh
2
+ # Generated by codeforge adr-init — 提交前 ADR 体系合规校验
3
+ #
4
+ # 安装方式:
5
+ # git config core.hooksPath .githooks
6
+ # 或 npm 项目可在 package.json scripts.prepare 加 "git config core.hooksPath .githooks"
7
+ #
8
+ # 紧急绕过(不推荐):
9
+ # git commit --no-verify
10
+
11
+ ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
12
+ cd "$ROOT" || exit 0
13
+
14
+ if ! command -v node >/dev/null 2>&1; then
15
+ echo "⚠️ 未找到 node,跳过 ADR 校验(请安装 Node.js >= 20)"
16
+ exit 0
17
+ fi
18
+
19
+ # 1. ADR 文件改动 → 同步 README 索引
20
+ STAGED_ADR=$(git diff --cached --name-only --diff-filter=ACMR \
21
+ | grep -E '^docs/adr/.*\.md$' \
22
+ | grep -v '^docs/adr/README\.md$' || true)
23
+
24
+ if [ -n "$STAGED_ADR" ] && [ -f "$ROOT/scripts/adr-index-sync.mjs" ]; then
25
+ echo "📚 检测到 ADR 改动,自动同步 README 索引..."
26
+ if node "$ROOT/scripts/adr-index-sync.mjs"; then
27
+ if ! git diff --quiet docs/adr/README.md; then
28
+ git add docs/adr/README.md
29
+ echo " ✓ docs/adr/README.md 已自动同步并加入 commit"
30
+ else
31
+ echo " ✓ README 索引已是最新(无需改动)"
32
+ fi
33
+ else
34
+ echo "❌ adr-index-sync 失败,请手动跑 node scripts/adr-index-sync.mjs 后重试"
35
+ exit 1
36
+ fi
37
+ fi
38
+
39
+ # 2. ADR 合规校验(staged 模式)
40
+ if [ -f "$ROOT/scripts/adr-check.mjs" ]; then
41
+ echo "🔍 ADR 合规校验中..."
42
+ ADR_STRICT=1 ADR_DIFF_MODE=staged node "$ROOT/scripts/adr-check.mjs" || {
43
+ echo "❌ ADR 校验失败 — commit 已阻断;紧急绕过 git commit --no-verify(不推荐)"
44
+ exit 1
45
+ }
46
+ fi
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env sh
2
+ # Generated by codeforge adr-init — push 前 ADR 体系合规校验(last-commit 模式)
3
+ #
4
+ # 兜底 pre-commit 漏网(如有人 --no-verify commit);扫最后一个 commit 的改动。
5
+ #
6
+ # 紧急绕过(不推荐):
7
+ # git push --no-verify
8
+
9
+ ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
10
+ cd "$ROOT" || exit 0
11
+
12
+ if ! command -v node >/dev/null 2>&1; then
13
+ echo "⚠️ 未找到 node,跳过 ADR 校验(请安装 Node.js >= 20)"
14
+ exit 0
15
+ fi
16
+
17
+ if [ -f scripts/adr-check.mjs ]; then
18
+ echo "🔍 ADR 合规校验中(push 前 last-commit 模式)..."
19
+ ADR_STRICT=1 ADR_DIFF_MODE=last-commit node scripts/adr-check.mjs || {
20
+ echo "❌ ADR 校验失败 — push 已阻断;紧急绕过 git push --no-verify(不推荐)"
21
+ exit 1
22
+ }
23
+ fi