@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 +45 -3
- package/agents/codeforge.md +5 -4
- package/agents/coder-deep.md +3 -0
- package/agents/coder-quick.md +3 -0
- package/agents/coder.md +3 -0
- package/agents/planner.md +12 -8
- package/agents/reviewer.md +3 -0
- package/assets/adr-init/.github/pull_request_template.md +22 -0
- package/assets/adr-init/docs/adr/README.md +105 -0
- package/assets/adr-init/docs/adr/template.md +83 -0
- package/assets/adr-init/githooks/pre-commit.sh +46 -0
- package/assets/adr-init/githooks/pre-push.sh +23 -0
- package/assets/adr-init/scripts/adr-check.mjs +428 -0
- package/assets/adr-init/scripts/adr-index-sync.mjs +151 -0
- package/bin/codeforge.mjs +96 -3
- package/commands/adr-init.md +67 -0
- package/dist/adr-init.js +207 -0
- package/dist/index.js +1691 -580
- package/package.json +16 -5
- package/scripts/sync-agent-models.mjs +1 -1
- package/workflows/bugfix.yaml +3 -3
- package/workflows/feature-dev.yaml +3 -3
- package/workflows/parallel-explore.yaml +1 -1
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/
|
|
108
|
+
升档不会静默改配置——当前会记录日志并提示;完成 auto_escalate 接线后,配置变更才会 stage 到 pending-changes 等你 apply。完整设计见 `docs/adr/model-tier-three-layer-escalation.md`。
|
|
67
109
|
|
|
68
110
|
|
|
69
111
|
### 代码改动如何落地
|
package/agents/codeforge.md
CHANGED
|
@@ -37,7 +37,8 @@ fallback_models:
|
|
|
37
37
|
|
|
38
38
|
- 必须按下方「能力边界」表的场景分类,先判定再派 —— **不允许"安全起见派 planner"作为默认**(这是 planner 角色再次膨胀的成因)
|
|
39
39
|
- 派 task 之前,必须用 ≤ 1 句话明文告知用户「即将派 \<agent\> 做 \<一句话任务\>」 —— 让用户在 opencode TUI 出现 Delegating spinner 静默期之前就有文字反馈
|
|
40
|
-
-
|
|
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 份独立文档 / 多方案对比) |
|
|
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
|
|
package/agents/coder-deep.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/coder-quick.md
CHANGED
|
@@ -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.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
|
package/agents/reviewer.md
CHANGED
|
@@ -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
|