add-coder 0.2.8 → 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 (58) hide show
  1. package/README.md +66 -27
  2. package/dist/index.js +158 -11
  3. package/package.json +9 -12
  4. package/templates/.add-coder-src-hash.json +256 -0
  5. package/templates/adapters/claude/hooks/doc-format-guard.sh +17 -0
  6. package/templates/adapters/claude/hooks/lib/notify.sh +34 -0
  7. package/templates/adapters/claude/hooks/pre-tool-use.sh +26 -7
  8. package/templates/adapters/claude/hooks/prompt-submit.sh +16 -0
  9. package/templates/adapters/codex/hooks/doc-format-guard.sh +17 -0
  10. package/templates/adapters/codex/hooks/lib/notify.sh +34 -0
  11. package/templates/adapters/codex/hooks/pre-tool-use.sh +48 -18
  12. package/templates/adapters/codex/hooks/prompt-submit.sh +16 -0
  13. package/templates/adapters/qoder/hooks/doc-format-guard.sh +17 -0
  14. package/templates/adapters/qoder/hooks/lib/notify.sh +34 -0
  15. package/templates/adapters/qoder/hooks/pre-tool-use.sh +28 -9
  16. package/templates/adapters/qoder/hooks/prompt-submit.sh +18 -1
  17. package/templates/adapters/trae/hooks/doc-format-guard.sh +17 -0
  18. package/templates/adapters/trae/hooks/lib/notify.sh +34 -0
  19. package/templates/adapters/trae/hooks/pre-tool-use.sh +48 -18
  20. package/templates/adapters/trae/hooks/prompt-submit.sh +16 -0
  21. package/templates/adapters/vscode/hooks/doc-format-guard.sh +16 -0
  22. package/templates/adapters/vscode/hooks/lib/notify.sh +34 -0
  23. package/templates/adapters/vscode/hooks/pre-tool-use.sh +26 -7
  24. package/templates/adapters/vscode/hooks/prompt-submit.sh +16 -0
  25. package/templates/core/hooks/doc-format-guard.sh +17 -0
  26. package/templates/core/hooks/lib/notify.sh +34 -0
  27. package/templates/core/hooks/pre-tool-use.sh +48 -18
  28. package/templates/core/hooks/prompt-submit.sh +16 -0
  29. package/templates/core/reviews/.gitkeep +0 -0
  30. package/templates/core/scripts/mcp-server/elicitation/confirm.ts +30 -0
  31. package/templates/core/scripts/mcp-server/elicitation/index.ts +1 -0
  32. package/templates/core/scripts/mcp-server/index.ts +15 -0
  33. package/templates/core/scripts/mcp-server/notifications/hitl.ts +49 -0
  34. package/templates/core/scripts/mcp-server/notifications/hook.ts +268 -0
  35. package/templates/core/scripts/mcp-server/notifications/index.ts +8 -0
  36. package/templates/core/scripts/mcp-server/resources/add-coder-version.ts +25 -0
  37. package/templates/core/scripts/mcp-server/resources/add-state.ts +44 -0
  38. package/templates/core/scripts/mcp-server/resources/hook-events-report.ts +104 -0
  39. package/templates/core/scripts/mcp-server/resources/index.ts +12 -0
  40. package/templates/core/scripts/mcp-server/resources/round-task.ts +22 -0
  41. package/templates/core/scripts/mcp-server/sampling/index.ts +1 -0
  42. package/templates/core/scripts/mcp-server/sampling/review.ts +47 -0
  43. package/templates/core/scripts/mcp-server/shared/env.ts +26 -0
  44. package/templates/core/scripts/mcp-server/shared/fs.ts +40 -0
  45. package/templates/core/scripts/mcp-server/shared/prisma.ts +35 -0
  46. package/templates/core/scripts/mcp-server/shared/response.ts +9 -0
  47. package/templates/core/scripts/mcp-server/tasks/index.ts +2 -0
  48. package/templates/core/scripts/mcp-server/tasks/runner.ts +20 -0
  49. package/templates/core/scripts/mcp-server/tasks/store.ts +20 -0
  50. package/templates/core/scripts/mcp-server/tools/audit.ts +73 -0
  51. package/templates/core/scripts/mcp-server/tools/context.ts +337 -0
  52. package/templates/core/scripts/mcp-server/tools/docs.ts +42 -0
  53. package/templates/core/scripts/mcp-server/tools/gateway.ts +135 -0
  54. package/templates/core/scripts/mcp-server/tools/hook-event-report.ts +92 -0
  55. package/templates/core/scripts/mcp-server/tools/index.ts +17 -0
  56. package/templates/core/scripts/mcp-server/tools/quality.ts +93 -0
  57. package/templates/core/scripts/mcp-server/types.ts +7 -0
  58. package/templates/core/scripts/mcp-server.ts +8 -3455
package/README.md CHANGED
@@ -1,11 +1,15 @@
1
1
  # add-coder
2
2
 
3
+ Make 0.75 into one.
4
+
3
5
  > 🀄中文 | 🔤[English](#-english-readme)
4
6
 
5
7
  **AI 代码治理的落地方案** — [codein2027](https://github.com/xiaomingming92/codein2027) 快速构建 ADD 编程范式的完整脚手架。以「审计即基础设施」为核心,彻底打破编程过程黑盒与跨轮失忆,让编程范式进化为可审计、可追溯、可收敛的新时代。 [NPM](https://www.npmjs.com/package/add-coder) · [GitHub](https://github.com/xiaomingming92/add-coder)
6
8
 
7
9
 
8
10
  > 🧭 **从零上手实操?** 请参见 [GUIDE.md](https://github.com/xiaomingming92/add-coder/blob/main/GUIDE.md) — 包含触发词速查、需求转 Plan、完整链路演练。
11
+ >
12
+ > 🔄 **add-coder 升级后更新模板?** `npx add-coder sync --adapter=qoder --patch` — 实操看 [GUIDE.md §版本升级](#) | 原理看 [DEVELOPMENT.md](https://github.com/xiaomingming92/add-coder/blob/main/DEVELOPMENT.md)
9
13
 
10
14
  ```bash
11
15
  npx add-coder init
@@ -27,7 +31,22 @@ npx add-coder init
27
31
  | 审计靠开发者自觉记录 | **MCP 审计工具链** 自动记录每次操作,系统闸门强制检查 |
28
32
  | 无关联性 | 审计事件天然关联 Plan → Spec → Task → Step → Tool Call,形成完整证据链 |
29
33
 
30
- ### ② Prompt Cache 原生友好 — 月费 ¥218,节省 98%
34
+ ### ② Caijuehub 规则引擎:业务规则直驱代码
35
+
36
+ Caijuehub 是 add-coder 历史上第一个实现 **TOML 规则声明 → 自动生成策略 → 业务代码消费** 的裁决引擎。以 sync --patch 为例:
37
+
38
+ ```toml
39
+ # sync-rules.toml — 改这里,不改代码
40
+ [patch]
41
+ on_conflict = "interactive" # 内容冲突时:交互勾选
42
+ on_missing = "write" # 文件缺失时:静默写入
43
+ [version]
44
+ on_upgrade = "baseline" # 版本升级时:自动覆盖
45
+ ```
46
+
47
+ `npm run generate` 后,策略直驱 sync.ts 行为。**人类从"追踪散落的 if"升级为"读一张决策表"**——认知负担从 O(N×M) 降为 O(1)。产品经理、市场人员改 TOML 即可把控软件能力,决策权集中、单一入口绕不过去。更进一步:当业务规则以声明式集中管理,**AI Agent 可大规模索引、检索、修改规则**——人机协作不再局限于对话生成代码,而是共同操作同一张决策表。这是 [codein2027 集中裁决层理论](https://github.com/xiaomingming92/codein2027) 的第一个工程落地。详见 [docs/caijuehub.md](./docs/caijuehub.md)。
48
+
49
+ ### ③ Prompt Cache 原生友好 — 月费 ¥218,节省 98%
31
50
 
32
51
  ADD 范式不仅是方法论——它的结构化 Step 流程天然适配 DeepSeek Prompt Cache 的前缀匹配机制,带来极致的 Token 成本效率。**实测数据验证**:
33
52
 
@@ -46,7 +65,7 @@ ADD 范式 + Qoder: cache 命中率 99.31%, 每次请求 MISS 仅 2,426 toke
46
65
 
47
66
  > 📊 [完整分析报告](./docs/ADD范式缓存命中分析报告.md) — 含 4 张 Mermaid 图表、17 天逐日数据、跨 IDE 对比与成本建模。
48
67
 
49
- ### 门禁驱动,而非自由对话
68
+ ### 门禁驱动,而非自由对话
50
69
 
51
70
  传统 AI coding 是「你说我做」,质量完全依赖 LLM 当天状态。add-coder 在架构中嵌入了 **双质量闸门**:
52
71
 
@@ -57,7 +76,7 @@ RAHS (Runtime Architecture Health Score) — 运行时架构健康度,< 90% BL
57
76
 
58
77
  这不是「建议」,是**架构阻断** — 不通过闸门的 Step 无法推进到下一步。
59
78
 
60
- ### 跨轮记忆,而非每轮失忆
79
+ ### 跨轮记忆,而非每轮失忆
61
80
 
62
81
  AI 对话的致命缺陷:上次讨论的架构决策、已修复的 Bug、达成的约定,下轮对话全部遗忘。add-coder 在架构层面解决:
63
82
 
@@ -65,7 +84,7 @@ AI 对话的致命缺陷:上次讨论的架构决策、已修复的 Bug、达
65
84
  - **Plan 索引** — 所有 Plan 通过 `index.md` 集中索引,支持模糊匹配快速定位
66
85
  - **DevLog 时序记录** — 每一步操作写入 `{YYYY-MM}/{DD}/` 时间轴,可回溯任意历史状态
67
86
 
68
- ### Policy-Update-Loop:治理自我进化(脚手架不包含此架构能力,接下来会给到DEMO仓库让大家更好理解Policy-Update-Loop和Report体系)
87
+ ### Policy-Update-Loop:治理自我进化(脚手架不包含此架构能力,接下来会给到DEMO仓库让大家更好理解Policy-Update-Loop和Report体系)
69
88
 
70
89
  不是静态模板,而是**闭环自适应系统**:
71
90
 
@@ -75,7 +94,7 @@ AI 对话的致命缺陷:上次讨论的架构决策、已修复的 Bug、达
75
94
 
76
95
  运行时产生的 Report 会反过来更新 governance rules,实现治理策略的持续进化。
77
96
 
78
- ### 多 IDE 的 Hook 即治理层
97
+ ### 多 IDE 的 Hook 即治理层
79
98
 
80
99
  hook 不是「通知推送」,而是 **ADD 范式在 IDE agent 生命周期中的 17 个确定性治理卡位**。每个 IDE(Claude Code / Qoder CN / VS Code Copilot / Trae / Codex)有各自的 hook 机制,但治理逻辑统一——架构一致,适配层不同。
81
100
 
@@ -89,6 +108,8 @@ hook 不是「通知推送」,而是 **ADD 范式在 IDE agent 生命周期中
89
108
 
90
109
  > 实施 Plan: [add-coder-hook-full-alignment-plan-v1](./.qoder/plans/2026-07/17/add-coder-hook-full-alignment-plan-v1.md) | 触发源: [GitHub Issue #6](https://github.com/xiaomingming92/add-coder/issues/6)
91
110
 
111
+
112
+
92
113
  ---
93
114
 
94
115
  ## 快速开始
@@ -158,16 +179,16 @@ npx add-coder init
158
179
  ```
159
180
  MCP 能力 方向 当前状态 说明
160
181
  ─────────────────────────────────────────────────────────────
161
- Tools Client→Server ✅ 已实现 17 个审计与治理工具(pull 模式)
162
- Resources+Sub Client←Server 🔜 本轮 Plan/Review/Route/Task 状态实时推送
163
- Notifications Server→Client 🔜 本轮 HITL 就绪通知 / Hook 结果推送
164
- Sampling Server→Client 🔜 本轮 服务端回调 AI 生成 Review
182
+ Tools Client→Server ✅ 已实现 18 个审计与治理工具(pull 模式)
183
+ Resources+Sub Client←Server 已实现 8 个端点 Plan/Review/Route/Task/Hook 状态推送
184
+ Notifications Server→Client 已实现 HITL 就绪 + Hook 拦截事件推送
185
+ Sampling Server→Client 已实现 服务端回调 AI 生成 Review (HITL 两步法)
165
186
  ── 横切 ──
166
- Elicitation Server→Client 🔜 本轮 向用户请求 HITL 确认/风险输入
167
- Tasks (实验性) 双向 🔜 本轮 长任务持久化 + 状态追踪
187
+ Elicitation Server→Client 已实现 向用户请求 HITL 确认/风险输入
188
+ Tasks (实验性) 双向 已实现 长任务持久化 + 状态追踪
168
189
  ```
169
190
 
170
- **当前已实现的 17 个 Tools**:
191
+ **当前已实现的 18 个 Tools**:
171
192
 
172
193
  | 工具 | 用途 | 触发场景 |
173
194
  |------|------|---------|
@@ -180,6 +201,7 @@ Tasks (实验性) 双向 🔜 本轮 长任务持久化 +
180
201
  | `check_add_route_status` | add-route 文件存在性校验 | Step 3 前 |
181
202
  | `check_spec_sync` | Spec 文档勾选状态与代码一致性 | Spec 执行后 |
182
203
  | `find_related_docs` | 检索相关架构/规范文档 | 语境理解 |
204
+ | `get_hook_events` | 查询 Hook 拦截事件(planKeyword/hook/时间过滤+分组) | 治理审计、阈值告警 |
183
205
 
184
206
  > 完整六能力架构设计见 [MCP 重构 Plan](.qoder/plans/2026-07/23/add-coder-mcp-restructure-plan-v1.md)。
185
207
 
@@ -246,11 +268,12 @@ Tasks (实验性) 双向 🔜 本轮 长任务持久化 +
246
268
 
247
269
  ## 🎬 预告
248
270
 
249
- | 计划 | 说明 |
250
- |------|------|
251
- | Demo 仓库演示 | 提供完整示例仓库,展示 Policy-Update-Loop 与 Report 体系的端到端闭环实践 |
252
- | MCP 能力重构 | MCP 工具链架构升级,提升审计与门禁工具的可扩展性和独立部署能力 |
253
- | 对话记忆增强 | 长期项目知识记忆和plan级别的稀疏记忆 |
271
+ | 计划 | 说明 |备注|
272
+ |------|------|------|
273
+ | Demo 仓库演示 | 提供完整示例仓库,展示 Policy-Update-Loop 与 Report 体系的端到端闭环实践 |--|
274
+ | MCP 能力重构 | ✅ v0.2.9 MCP 工具链架构升级,提升审计与门禁工具的可扩展性和独立部署能力 | 2026-07/23/add-coder-mcp-restructure-plan-v1.md |
275
+ | Hook 通知升级 | ✅ v0.2.9 Hook 拦截事件 jsonl → fs.watch → record_dev_operation 落库 + Notification + 治理信号 | 2026-07/24/add-coder-hook-notify-upgrade-plan-v1.md |
276
+ | 对话记忆增强 | 长期项目知识记忆和plan级别的稀疏记忆 |--|
254
277
 
255
278
 
256
279
 
@@ -282,7 +305,22 @@ Traditional AI development: Chat → Generate code → Dig through chat history
282
305
  | Auditing relies on developer discipline | The **MCP audit toolchain** automatically records every operation; system gateways enforce checks |
283
306
  | No traceability | Audit events are naturally linked: Plan → Spec → Task → Step → Tool Call, forming a complete evidence chain |
284
307
 
285
- ### ② Prompt Cache Native ¥218/mo, 98% Savings
308
+ ### ② Caijuehub Rule Engine: Business Rules Drive Code
309
+
310
+ Caijuehub is add-coder's first implementation of **TOML declaration → auto-generated strategy → business code consumption**. Using sync --patch as an example:
311
+
312
+ ```toml
313
+ # sync-rules.toml — edit here, not code
314
+ [patch]
315
+ on_conflict = "interactive" # content conflict → interactive checkbox
316
+ on_missing = "write" # file missing → silent write
317
+ [version]
318
+ on_upgrade = "baseline" # version upgrade → auto overwrite
319
+ ```
320
+
321
+ After `npm run generate`, the strategy directly drives sync.ts behavior. **Humans upgrade from "hunting scattered if-statements" to "reading a decision table"** — cognitive load drops from O(N×M) to O(1). Product managers and marketers edit TOML to control software capabilities, with decisions centralized at a single entry point that cannot be bypassed. Furthermore: when business rules are declaratively centralized, **AI Agents can index, search, and modify rules at scale** — human-AI collaboration extends beyond conversation-driven code generation to jointly operating the same decision table. This is the first engineering implementation of [codein2027's Centralized Decision Layer theory](https://github.com/xiaomingming92/codein2027). Details: [docs/caijuehub.md](./docs/caijuehub.md).
322
+
323
+ ### ③ Prompt Cache Native — ¥218/mo, 98% Savings
286
324
 
287
325
  The ADD paradigm isn't just methodology — its structured Step workflow naturally aligns with DeepSeek's Prompt Cache prefix-matching mechanism, delivering extreme token cost efficiency. **Real-world billing validation**:
288
326
 
@@ -301,7 +339,7 @@ ADD paradigm + Qoder: cache hit rate 99.31%, only 2,426 MISS tokens/req
301
339
 
302
340
  > 📊 [Full analysis report](./docs/ADD范式缓存命中分析报告.md) — 4 Mermaid diagrams, 17-day daily data, cross-IDE comparison, and cost modeling.
303
341
 
304
- ### Gateway-Driven, Not Free-Form Conversation
342
+ ### Gateway-Driven, Not Free-Form Conversation
305
343
 
306
344
  Traditional AI coding is "you say, I do" — quality depends entirely on the LLM's state that day. add-coder embeds **dual quality gateways** into the architecture:
307
345
 
@@ -312,7 +350,7 @@ RAHS (Runtime Architecture Health Score) — Runtime architecture health, < 90%
312
350
 
313
351
  These are not "suggestions" — they are **architectural blocks**. A Step cannot advance without passing its gateway.
314
352
 
315
- ### Cross-Session Memory, Not Per-Session Amnesia
353
+ ### Cross-Session Memory, Not Per-Session Amnesia
316
354
 
317
355
  The fatal flaw of AI conversations: architectural decisions from last session, bugs fixed, agreements reached — all forgotten in the next conversation. add-coder solves this at the architecture level:
318
356
 
@@ -320,7 +358,7 @@ The fatal flaw of AI conversations: architectural decisions from last session, b
320
358
  - **Plan Index** — All Plans are centrally indexed via `index.md`, supporting fuzzy-match quick lookup
321
359
  - **DevLog Timeline** — Every operation is written to the `{YYYY-MM}/{DD}/` timeline, enabling full historical state traceability
322
360
 
323
- ### Policy-Update-Loop: Self-Evolving Governance (the scaffold itself does not include this architectural capability; a DEMO repo will be provided next to better illustrate the Policy-Update-Loop and Report system)
361
+ ### Policy-Update-Loop: Self-Evolving Governance (the scaffold itself does not include this architectural capability; a DEMO repo will be provided next to better illustrate the Policy-Update-Loop and Report system)
324
362
 
325
363
  Not a static template, but a **closed-loop adaptive system**:
326
364
 
@@ -330,7 +368,7 @@ Execute → Audit → Boundary Report → Rule Adjustment → Next Execution
330
368
 
331
369
  Runtime-generated Reports feed back into governance rules, enabling continuous evolution of governance strategies.
332
370
 
333
- ### Multi-IDE Hooks as the Governance Layer
371
+ ### Multi-IDE Hooks as the Governance Layer
334
372
 
335
373
  Hooks are not "notification push" — they are the **IDE runtime interception layer**:
336
374
 
@@ -497,10 +535,11 @@ npx add-coder init
497
535
 
498
536
  ## 🎬 Coming Soon
499
537
 
500
- | Plan | Description |
501
- |------|-------------|
502
- | Demo Repo | A full example repository showcasing end-to-end closed-loop practice of Policy-Update-Loop and the Report system |
503
- | MCP Restructure | MCP toolchain architecture upgrade, improving audit and gateway tool extensibility and standalone deployment capability |
504
- | Memory Enhancement | Long-term project knowledge memory and plan-level sparse memory |
538
+ | Plan | Description | remark |
539
+ |------|-------------|:---:|
540
+ | Demo Repo | Full example repository showcasing Policy-Update-Loop with Report system end-to-end | 📋 |
541
+ | ~~MCP Restructure~~ | v0.2.9 3,467-line monolith 27 modules covering all six MCP primitives | 2026-07/23/... |
542
+ | ~~Hook Notification Upgrade~~ | v0.2.9 ~36 files: hook intercept jsonl → fs.watch → record_dev_operation | 2026-07/24/... |
543
+ | Memory Enhancement | Long-term project knowledge memory and plan-level sparse memory | 📋 |
505
544
 
506
545
  ---
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/index.ts
4
- import { readFileSync as readFileSync6 } from "fs";
4
+ import { readFileSync as readFileSync7 } from "fs";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // src/caijuehub/strategies/detect.strategy.ts
@@ -155,7 +155,7 @@ function renderList(items, selected, startIdx, height) {
155
155
  `;
156
156
  }
157
157
  out += `
158
- \u547D\u4EE4: [a]\u5168\u9009 [n]\u53D6\u6D88\u5168\u9009 [1-${items.length}]\u5207\u6362 [\u2191\u2193]\u6EDA\u52A8 [Enter]\u786E\u8BA4 [q]\u9000\u51FA
158
+ \u547D\u4EE4: [a]\u5168\u90E8\u8DF3\u8FC7 [A]\u5168\u90E8\u8986\u76D6 [1-${items.length}]\u5207\u6362 [Enter]\u786E\u8BA4 [q]\u9000\u51FA
159
159
  `;
160
160
  return out;
161
161
  }
@@ -197,12 +197,12 @@ async function selectFiles(projectRoot, files) {
197
197
  draw();
198
198
  });
199
199
  rl.on("line", (input2) => {
200
- const trimmed = input2.trim().toLowerCase();
201
- if (trimmed === "q" || trimmed === "quit") {
200
+ const trimmed = input2.trim();
201
+ if (trimmed === "q" || trimmed.toLowerCase() === "quit") {
202
202
  rl.close();
203
- } else if (trimmed === "a") {
203
+ } else if (trimmed === "A") {
204
204
  items.forEach((_, i) => selected.add(i));
205
- } else if (trimmed === "n") {
205
+ } else if (trimmed === "a") {
206
206
  selected.clear();
207
207
  } else {
208
208
  const num = parseInt(trimmed, 10);
@@ -444,7 +444,7 @@ var PRISMA_CONFIG = {
444
444
  autoGenerate: true,
445
445
  migrationName: "add_workflow_init",
446
446
  schemaArg: "--schema=prisma/",
447
- requiresUserModel: false
447
+ requiresUserModel: true
448
448
  };
449
449
  function ensurePrismaConfig(projectRoot) {
450
450
  const configPath = resolve3(projectRoot, "prisma.config.ts");
@@ -629,6 +629,7 @@ async function injectPrisma2(projectRoot, options = {}) {
629
629
 
630
630
  // src/cli/commands/init.ts
631
631
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync3, copyFileSync as copyFileSync2, readdirSync as readdirSync2 } from "fs";
632
+ import { createHash } from "crypto";
632
633
  import { resolve as resolve5 } from "path";
633
634
  import { spawnSync as spawnSync2 } from "child_process";
634
635
  import { createConnection } from "net";
@@ -893,6 +894,33 @@ async function renderAndWrite(ctx) {
893
894
  for (const [p, c] of claudeFiles) allFiles.set(p, c);
894
895
  console.log(`claude adapter (via Agent Host): ${claudeFiles.size} \u6587\u4EF6`);
895
896
  }
897
+ for (const d of [".add", magicDir]) {
898
+ const reviewsDir = resolve5(projectRoot, d, "reviews");
899
+ if (!existsSync6(reviewsDir)) {
900
+ if (dry) {
901
+ console.log(`[dry-run] \u5C06\u521B\u5EFA ${reviewsDir}/`);
902
+ } else {
903
+ mkdirSync3(reviewsDir, { recursive: true });
904
+ }
905
+ }
906
+ }
907
+ if (!dry) {
908
+ const hashMap = {};
909
+ let npmVer = "";
910
+ try {
911
+ npmVer = JSON.parse(readFileSync5(resolve5(projectRoot, "node_modules", "add-coder", "templates", ".add-coder-src-hash.json"), "utf-8"))._version ?? "";
912
+ } catch {
913
+ }
914
+ for (const [rp, c] of allFiles) {
915
+ hashMap[rp] = createHash("sha256").update(c).digest("hex").slice(0, 8);
916
+ }
917
+ const hashOut = resolve5(projectRoot, magicDir, ".add-coder-hash.json");
918
+ writeFileSync3(hashOut, JSON.stringify(hashMap, null, 2) + "\n", "utf-8");
919
+ if (npmVer) {
920
+ writeFileSync3(resolve5(projectRoot, magicDir, ".add-coder-version"), npmVer + "\n", "utf-8");
921
+ }
922
+ console.log(`hash: ${Object.keys(hashMap).length} entries \u2192 ${magicDir}/.add-coder-hash.json`);
923
+ }
896
924
  return await writeFiles2(projectRoot, allFiles, { force: options.force, dryRun: options.dryRun });
897
925
  }
898
926
  async function deployDatabase(ctx) {
@@ -986,8 +1014,30 @@ function finalize(ctx, result) {
986
1014
  }
987
1015
 
988
1016
  // src/cli/commands/sync.ts
989
- import { existsSync as existsSync7 } from "fs";
1017
+ import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
990
1018
  import { resolve as resolve6 } from "path";
1019
+ import { createHash as createHash2 } from "crypto";
1020
+
1021
+ // src/caijuehub/strategies/sync.strategy.ts
1022
+ var SYNC_CONFIG = {
1023
+ PATCH_GUARD: [/[/]plans[/]/, /[/]specs[/]/, /[/]reviews[/]/],
1024
+ HASH_OUTPUT_FILE: ".add-coder-hash.json",
1025
+ HASH_SRC_FILE: "templates/.add-coder-src-hash.json",
1026
+ HASH_HEX_LENGTH: 8,
1027
+ PATCH_ON_MISSING: "write",
1028
+ PATCH_ON_CONFLICT: "interactive",
1029
+ PATCH_ON_SAME: "skip",
1030
+ VERSION_ON_FIRST: "baseline",
1031
+ VERSION_ON_UPGRADE: "baseline",
1032
+ VERSION_ON_HASH_LOST: "conflict",
1033
+ VERSION_SENTINEL: ".add-coder-version",
1034
+ DEFAULT_ON_MISSING: "write",
1035
+ DEFAULT_ON_EXISTING: "skip",
1036
+ PROMPT_FULL: "\u6240\u6709 ADD \u6A21\u677F\u6587\u4EF6\u5DF2\u5C31\u4F4D\u3002\u4F7F\u7528 --patch \u66F4\u65B0\u5DF2\u6709\u6587\u4EF6\u3002",
1037
+ PROMPT_PATCH_DONE: "\u6240\u6709 ADD \u6A21\u677F\u6587\u4EF6\u5DF2\u662F\u6700\u65B0\u3002"
1038
+ };
1039
+
1040
+ // src/cli/commands/sync.ts
991
1041
  var ADAPTER_RENDERERS2 = {
992
1042
  claude: renderAdapter,
993
1043
  qoder: renderAdapter2,
@@ -1010,6 +1060,34 @@ function resolveAdapter2(projectRoot, specified) {
1010
1060
  console.log("\u672A\u68C0\u6D4B\u5230 IDE \u73AF\u5883\uFF0C\u9ED8\u8BA4 qoder");
1011
1061
  return "qoder";
1012
1062
  }
1063
+ function isUserData(p) {
1064
+ return SYNC_CONFIG.PATCH_GUARD.some((r) => r.test(p));
1065
+ }
1066
+ function hash8(c) {
1067
+ return createHash2("sha256").update(c).digest("hex").slice(0, SYNC_CONFIG.HASH_HEX_LENGTH);
1068
+ }
1069
+ function loadHashFile(root, magic) {
1070
+ try {
1071
+ return JSON.parse(readFileSync6(resolve6(root, magic, SYNC_CONFIG.HASH_OUTPUT_FILE), "utf-8"));
1072
+ } catch {
1073
+ return {};
1074
+ }
1075
+ }
1076
+ function loadVersionFile(root, magic) {
1077
+ try {
1078
+ return readFileSync6(resolve6(root, magic, SYNC_CONFIG.VERSION_SENTINEL), "utf-8").trim();
1079
+ } catch {
1080
+ return "";
1081
+ }
1082
+ }
1083
+ function saveVersionFile(root, magic, version2) {
1084
+ writeFileSync4(resolve6(root, magic, SYNC_CONFIG.VERSION_SENTINEL), version2 + "\n", "utf-8");
1085
+ }
1086
+ function saveHashFile(root, magic, files) {
1087
+ const m = {};
1088
+ for (const [p, c] of files) m[p] = hash8(c);
1089
+ writeFileSync4(resolve6(root, magic, SYNC_CONFIG.HASH_OUTPUT_FILE), JSON.stringify(m, null, 2) + "\n", "utf-8");
1090
+ }
1013
1091
  async function syncCommand(options = {}) {
1014
1092
  const projectRoot = process.cwd();
1015
1093
  const target = resolveAdapter2(projectRoot, options.adapter);
@@ -1040,6 +1118,75 @@ async function syncCommand(options = {}) {
1040
1118
  for (const [p, c] of claudeFiles) allFiles.set(p, c);
1041
1119
  console.log(`claude adapter (via Agent Host): ${claudeFiles.size} \u6587\u4EF6`);
1042
1120
  }
1121
+ if (options.patch) {
1122
+ const candidates = /* @__PURE__ */ new Map();
1123
+ let skipped = 0;
1124
+ for (const [p, c] of allFiles) {
1125
+ if (isUserData(p)) {
1126
+ skipped++;
1127
+ continue;
1128
+ }
1129
+ candidates.set(p, c);
1130
+ }
1131
+ const outHash = loadHashFile(projectRoot, magicDir);
1132
+ const srcHashPath = resolve6(projectRoot, "node_modules", "add-coder", "templates", ".add-coder-src-hash.json");
1133
+ let npmVersion = "";
1134
+ try {
1135
+ npmVersion = JSON.parse(readFileSync6(srcHashPath, "utf-8"))._version ?? "";
1136
+ } catch {
1137
+ }
1138
+ const installedVersion = loadVersionFile(projectRoot, magicDir);
1139
+ const isFirstPatch = !installedVersion;
1140
+ const isUpgrade = installedVersion && npmVersion && installedVersion !== npmVersion;
1141
+ const hashLost = installedVersion && !isUpgrade && Object.keys(outHash).length === 0;
1142
+ const establishBaseline = isFirstPatch || isUpgrade;
1143
+ if (isFirstPatch) {
1144
+ console.log(`\u{1F3AF} \u9996\u6B21 patch\uFF0C\u5EFA\u7ACB\u57FA\u7EBF v${npmVersion}`);
1145
+ } else if (isUpgrade) {
1146
+ console.log(`\u{1F3AF} \u7248\u672C\u5347\u7EA7: ${installedVersion} \u2192 ${npmVersion}\uFF0C\u5EFA\u7ACB\u65B0\u57FA\u7EBF`);
1147
+ } else if (hashLost) {
1148
+ console.log(`\u26A0\uFE0F hash \u4E22\u5931\uFF08\u7248\u672C ${installedVersion} \u672A\u53D8\uFF09\uFF0C\u5168\u90E8\u8FDB\u4EA4\u4E92\u786E\u8BA4`);
1149
+ }
1150
+ const missingFiles = /* @__PURE__ */ new Map();
1151
+ const conflictFiles = /* @__PURE__ */ new Map();
1152
+ let sameCount = 0;
1153
+ for (const [relPath, content] of candidates) {
1154
+ const absPath = resolve6(projectRoot, relPath);
1155
+ if (!existsSync7(absPath)) {
1156
+ missingFiles.set(relPath, content);
1157
+ } else if (establishBaseline) {
1158
+ missingFiles.set(relPath, content);
1159
+ } else {
1160
+ const curH = hash8(readFileSync6(absPath, "utf-8"));
1161
+ const storedH = outHash[relPath];
1162
+ if (storedH && curH === storedH) {
1163
+ sameCount++;
1164
+ } else {
1165
+ conflictFiles.set(relPath, content);
1166
+ }
1167
+ }
1168
+ }
1169
+ console.log(`patch: ${allFiles.size} \u2192 skip user ${skipped} | missing ${missingFiles.size} | conflict ${conflictFiles.size} | same ${sameCount}`);
1170
+ if (missingFiles.size > 0) {
1171
+ const r = await writeFiles2(projectRoot, missingFiles, { force: true, yes: true });
1172
+ console.log(` missing: \u65B0\u5EFA ${r.created}`);
1173
+ }
1174
+ if (conflictFiles.size > 0) {
1175
+ const sel = await selectFiles(projectRoot, conflictFiles);
1176
+ if (sel.size > 0) {
1177
+ const r = await writeFiles2(projectRoot, sel, { force: true, yes: true });
1178
+ console.log(` conflict: \u8986\u76D6 ${r.overwritten}, \u8DF3\u8FC7 ${conflictFiles.size - sel.size}`);
1179
+ } else {
1180
+ console.log(` conflict: \u7528\u6237\u53D6\u6D88\uFF0C${conflictFiles.size} \u4E2A\u6587\u4EF6\u672A\u5199\u5165`);
1181
+ }
1182
+ }
1183
+ if (missingFiles.size === 0 && conflictFiles.size === 0) {
1184
+ console.log(SYNC_CONFIG.PROMPT_PATCH_DONE);
1185
+ }
1186
+ saveHashFile(projectRoot, magicDir, new Map([...missingFiles, ...conflictFiles]));
1187
+ saveVersionFile(projectRoot, magicDir, npmVersion);
1188
+ return;
1189
+ }
1043
1190
  const missing = /* @__PURE__ */ new Map();
1044
1191
  for (const [relPath, content] of allFiles) {
1045
1192
  if (!existsSync7(resolve6(projectRoot, relPath))) {
@@ -1047,7 +1194,7 @@ async function syncCommand(options = {}) {
1047
1194
  }
1048
1195
  }
1049
1196
  if (missing.size === 0) {
1050
- console.log("\u6240\u6709 ADD \u6A21\u677F\u6587\u4EF6\u5DF2\u5C31\u4F4D\u3002");
1197
+ console.log(SYNC_CONFIG.PROMPT_FULL);
1051
1198
  return;
1052
1199
  }
1053
1200
  let filesToWrite = missing;
@@ -1091,11 +1238,11 @@ async function statusCommand() {
1091
1238
 
1092
1239
  // src/cli/index.ts
1093
1240
  var { version } = JSON.parse(
1094
- readFileSync6(new URL("../package.json", import.meta.url), "utf-8")
1241
+ readFileSync7(new URL("../package.json", import.meta.url), "utf-8")
1095
1242
  );
1096
1243
  var program = new Command();
1097
1244
  program.name("add-coder").description("\u521D\u59CB\u5316 ADD \u8303\u5F0F\u5DE5\u4F5C\u6D41\u6A21\u677F").version(version);
1098
1245
  program.command("init").description("\u521D\u59CB\u5316 ADD \u6A21\u677F\u5230\u5F53\u524D\u9879\u76EE").option("--adapter <type>", "\u76EE\u6807 IDE: claude | qoder | vscode").option("--config <path>", "\u6307\u5B9A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--force", "\u8986\u76D6\u5DF2\u6709\u6587\u4EF6\uFF0C\u4E0D\u4EA4\u4E92").option("--dry-run", "\u9884\u89C8\u6A21\u5F0F\uFF0C\u4E0D\u5B9E\u9645\u5199\u5165").action(initCommand);
1099
- program.command("sync").description("\u589E\u91CF\u540C\u6B65\u7F3A\u5931\u6587\u4EF6").option("--adapter <type>", "\u76EE\u6807 IDE: claude | qoder | vscode").option("-i, --interactive", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u8981\u540C\u6B65\u7684\u6587\u4EF6").action(syncCommand);
1246
+ program.command("sync").description("\u589E\u91CF\u540C\u6B65\u7F3A\u5931\u6587\u4EF6\uFF08--patch \u8986\u76D6\u5DF2\u6709\u6A21\u677F\uFF09").option("--adapter <type>", "\u76EE\u6807 IDE: claude | qoder | vscode").option("--patch", "\u8986\u76D6\u5DF2\u6709\u6A21\u677F\u6587\u4EF6\uFF08\u4E0D\u78B0 plans/specs/reviews\uFF09").option("-i, --interactive", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u8981\u540C\u6B65\u7684\u6587\u4EF6").action(syncCommand);
1100
1247
  program.command("status").description("\u68C0\u67E5 ADD \u6A21\u677F\u5B8C\u6574\u6027").action(statusCommand);
1101
1248
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "add-coder",
3
- "version": "0.2.8",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "description": "[codein2027](https://github.com/xiaomingming92/codein2027) - A complete scaffolding for building the ADD programming paradigm, the implementation layer for AI code governance. Core principle: Audit as Infrastructure. Breaks the black-box programming process and cross-session amnesia, evolving programming paradigms into an auditable, traceable, and convergent new era. npx-ready.\n\n[codein2027](https://github.com/xiaomingming92/codein2027) 快速构建 ADD 编程范式的完整脚手架——AI 代码治理的落地方案。以「审计即基础设施」为核心,彻底打破编程过程黑盒与跨轮失忆,让编程范式进化为可审计、可追溯、可收敛的新时代。npx 即用,人人可体验。",
6
6
  "repository": {
@@ -32,25 +32,26 @@
32
32
  "vscode",
33
33
  "mcp",
34
34
  "workflow",
35
- "codein2027"
35
+ "codein2027",
36
+ "裁决层",
37
+ "caijuehub"
36
38
  ],
37
39
  "author": "xiaomingming",
38
40
  "email": "wujixmm@gmail.com",
39
41
  "license": "AGPL-3.0-only",
40
42
  "dependencies": {
43
+ "@modelcontextprotocol/server": "2.0.0-beta.5",
41
44
  "commander": "^13.1.0",
42
45
  "smol-toml": "^1.7.0",
43
- "zod": "^3.24.0"
46
+ "zod": "^4.4.3"
44
47
  },
45
48
  "peerDependencies": {
46
- "@modelcontextprotocol/sdk": "^1.0.0",
47
49
  "@prisma/adapter-libsql": "^7.0.0",
48
50
  "@prisma/adapter-pg": "^7.0.0",
49
51
  "@prisma/client": "^7.0.0",
50
52
  "dotenv": "*",
51
53
  "prisma": "^7.0.0",
52
- "tsx": "*",
53
- "zod": "^3.24.0"
54
+ "tsx": ">=4"
54
55
  },
55
56
  "peerDependenciesMeta": {
56
57
  "@prisma/client": {
@@ -59,12 +60,6 @@
59
60
  "prisma": {
60
61
  "optional": false
61
62
  },
62
- "@modelcontextprotocol/sdk": {
63
- "optional": false
64
- },
65
- "zod": {
66
- "optional": false
67
- },
68
63
  "dotenv": {
69
64
  "optional": false
70
65
  },
@@ -96,6 +91,8 @@
96
91
  "lint": "eslint src/",
97
92
  "lint:fix": "eslint src/ --fix",
98
93
  "generate": "tsx src/caijuehub/transcribe.ts",
94
+ "podman-add-coder-up": "podman-compose --env-file .env.development -f podman-compose.add.yml up -d",
95
+ "podman-add-coder-down": "podman-compose --env-file .env.development -f podman-compose.add.yml down",
99
96
  "test": "vitest run"
100
97
  }
101
98
  }