add-coder 0.1.5 → 0.1.8
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/LICENSE +700 -0
- package/README.md +117 -11
- package/dist/index.js +38 -30
- package/package.json +18 -13
- package/templates/adapters/qoder/hooks/doc-format-guard.sh +0 -0
- package/templates/adapters/qoder/hooks/lib/context-inject.sh +0 -0
- package/templates/adapters/qoder/hooks/lib/state-detect.sh +0 -0
- package/templates/adapters/qoder/hooks/lib/vocabulary.sh +0 -0
- package/templates/adapters/qoder/hooks/notification.sh +0 -0
- package/templates/adapters/qoder/hooks/permission-gate.sh +0 -0
- package/templates/adapters/qoder/hooks/post-tool-failure.sh +0 -0
- package/templates/adapters/qoder/hooks/post-tool-use.sh +0 -0
- package/templates/adapters/qoder/hooks/pre-compact.sh +0 -0
- package/templates/adapters/qoder/hooks/pre-tool-use.sh +0 -0
- package/templates/adapters/qoder/hooks/prompt-submit.sh +0 -0
- package/templates/adapters/qoder/hooks/review-checklist.sh +0 -0
- package/templates/adapters/qoder/hooks/session-start.sh +0 -0
- package/templates/adapters/qoder/hooks/stop-check.sh +0 -0
- package/templates/adapters/qoder/hooks/subagent-guard.sh +0 -0
- package/templates/core/plans/2026-07/08/farm-agent-add-coder-npm-package-add-route-v1.md +10 -2
- package/templates/core/plans/2026-07/08/farm-agent-add-coder-npm-package-handoff-v1.md +8 -0
- package/templates/core/plans/2026-07/08/farm-agent-add-coder-npm-package-plan-v1.md +111 -1
- package/templates/core/scripts/mcp-server.ts +59 -17
- package/templates/core/specs/farm-agent-add-coder-npm-package/spec.md +19 -3
package/README.md
CHANGED
|
@@ -1,10 +1,70 @@
|
|
|
1
1
|
# add-coder
|
|
2
2
|
|
|
3
|
-
[codein2027](https://github.com/xiaomingming92/codein2027)
|
|
3
|
+
**AI 代码治理的落地方案** — [codein2027](https://github.com/xiaomingming92/codein2027) 快速构建 ADD 编程范式的完整脚手架。以「审计即基础设施」为核心,彻底打破编程过程黑盒与跨轮失忆,让编程范式进化为可审计、可追溯、可收敛的新时代。[本项目NPM包地址](https://www.npmjs.com/package/add-coder)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
```bash
|
|
6
|
+
npx add-coder init
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 这不是模板工具,这是架构差异
|
|
12
|
+
|
|
13
|
+
市面上已有大量 AI 编程模板、hook 适配器、MCP 脚手架。add-coder 与它们的根本区别不在「生成什么文件」,而在 **架构层面的范式转换**:
|
|
14
|
+
|
|
15
|
+
### ① 审计是基础设施,而非事后日志
|
|
16
|
+
|
|
17
|
+
传统 AI 开发:对话 → 生成代码 → 事后翻聊天记录找「谁改了什么」
|
|
18
|
+
|
|
19
|
+
| 传统模式 | add-coder |
|
|
20
|
+
|---------|----------|
|
|
21
|
+
| 日志是 append-only 文本文件 | 审计是 **结构化数据表**(DevOperation + AuditLog),支持按 plan/step/agent/tool 多维查询 |
|
|
22
|
+
| 审计靠开发者自觉记录 | **MCP 审计工具链** 自动记录每次操作,系统闸门强制检查 |
|
|
23
|
+
| 无关联性 | 审计事件天然关联 Plan → Spec → Task → Step → Tool Call,形成完整证据链 |
|
|
24
|
+
|
|
25
|
+
### ② 门禁驱动,而非自由对话
|
|
26
|
+
|
|
27
|
+
传统 AI coding 是「你说我做」,质量完全依赖 LLM 当天状态。add-coder 在架构中嵌入了 **双质量闸门**:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
DPS (Design-Process Symmetry) — 设计/实现/文档/审计 四维各 25%,< 85% BLOCKED
|
|
31
|
+
RAHS (Runtime Architecture Health Score) — 运行时架构健康度,< 90% BLOCKED
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
这不是「建议」,是**架构阻断** — 不通过闸门的 Step 无法推进到下一步。
|
|
35
|
+
|
|
36
|
+
### ③ 跨轮记忆,而非每轮失忆
|
|
37
|
+
|
|
38
|
+
AI 对话的致命缺陷:上次讨论的架构决策、已修复的 Bug、达成的约定,下轮对话全部遗忘。add-coder 在架构层面解决:
|
|
39
|
+
|
|
40
|
+
- **Handoff 文档** — 每轮 Session 结束时自动生成结构化交接文档,下轮会话自动加载
|
|
41
|
+
- **Plan 索引** — 所有 Plan 通过 `index.md` 集中索引,支持模糊匹配快速定位
|
|
42
|
+
- **DevLog 时序记录** — 每一步操作写入 `{YYYY-MM}/{DD}/` 时间轴,可回溯任意历史状态
|
|
6
43
|
|
|
7
|
-
|
|
44
|
+
### ④ Policy-Update-Loop:治理自我进化
|
|
45
|
+
|
|
46
|
+
不是静态模板,而是**闭环自适应系统**:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
执行 → 审计 → 边界报告 → 规则调整 → 下一轮执行
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
运行时产生的 Report 会反过来更新 governance rules,实现治理策略的持续进化。
|
|
53
|
+
|
|
54
|
+
### ⑤ 多 IDE 的 Hook 即治理层
|
|
55
|
+
|
|
56
|
+
hook 不是「通知推送」,而是 **IDE 运行时拦截层**:
|
|
57
|
+
|
|
58
|
+
| Hook 类型 | 作用 |
|
|
59
|
+
|----------|------|
|
|
60
|
+
| PreToolUse | 工具调用前校验白名单、注入上下文、DPS 条件检查 |
|
|
61
|
+
| PostToolUse | 自动审计记录、Plan 同步检测、格式守卫 |
|
|
62
|
+
| PreCompact | 跨轮上下文压缩时强制保留关键文档路径 |
|
|
63
|
+
| PromptSubmit | 注入 ADD 词汇表触发词,确保 LLM 对「验收」「门禁」等命令零延迟响应 |
|
|
64
|
+
|
|
65
|
+
每个 IDE(Claude/Qoder/VS Code)有各自的 hook 实现,但**治理逻辑统一** — 架构一致,适配层不同。
|
|
66
|
+
|
|
67
|
+
---
|
|
8
68
|
|
|
9
69
|
## 快速开始
|
|
10
70
|
|
|
@@ -47,8 +107,6 @@ npx add-coder init --yes
|
|
|
47
107
|
|
|
48
108
|
### init 内部流程
|
|
49
109
|
|
|
50
|
-
`npx add-coder init` 按以下步骤执行:
|
|
51
|
-
|
|
52
110
|
| 步骤 | 动作 | 说明 |
|
|
53
111
|
|------|------|------|
|
|
54
112
|
| ① | 检测 IDE | 扫描 `.qoder/` `.claude/` `.vscode/` 存在性,或通过 `--adapter` 指定 |
|
|
@@ -59,8 +117,6 @@ npx add-coder init --yes
|
|
|
59
117
|
| ⑥ | 写入文件 | 交互/yes/force/dry-run 四种模式,`.sh` 脚本自动 `chmod` |
|
|
60
118
|
| ⑦ | 输出摘要 | 新建/跳过/覆盖统计 + 下一步提示 |
|
|
61
119
|
|
|
62
|
-
> **Prisma 注入说明**:ADD-7 审计需要 `DevOperation` + `AuditLog` 两张表。首次 `init` 自动引导 `prisma init` 并注入 `User` 模型,第二次 `init` 执行 `prisma migrate dev` 完成建表。
|
|
63
|
-
|
|
64
120
|
### init 选项
|
|
65
121
|
|
|
66
122
|
| 选项 | 说明 |
|
|
@@ -80,11 +136,61 @@ npx add-coder init --yes
|
|
|
80
136
|
| `.qoder/` | Qoder 适配(hooks、settings.json、mcp.json) |
|
|
81
137
|
| `.vscode/` | VS Code 适配(settings.json、tasks.json) |
|
|
82
138
|
|
|
83
|
-
##
|
|
139
|
+
## MCP 审计工具链
|
|
140
|
+
|
|
141
|
+
`init` 自动部署 MCP 服务器 (`mcp-server.ts`) 到项目中,IDE 通过 `mcp.json` 加载。提供以下审计与治理工具:
|
|
84
142
|
|
|
85
|
-
|
|
143
|
+
| 工具 | 用途 | 触发场景 |
|
|
144
|
+
|------|------|---------|
|
|
145
|
+
| `record_dev_operation` | 记录开发操作审计(before/after/reason) | 每次文件变更、配置修改 |
|
|
146
|
+
| `query_audit_logs` | 按 planKeyword / targetId 查询审计记录 | 跨会话恢复上下文、验证迭代证据 |
|
|
147
|
+
| `get_project_context` | 获取 ADD 工作流状态快照 | 空白对话开局 |
|
|
148
|
+
| `get_db_schema` | 获取 Prisma schema 信息 | 数据库相关操作 |
|
|
149
|
+
| `check_dps` | DPS 闸门(设计/实现/文档/审计 四维各 25%) | Step 0 末尾 |
|
|
150
|
+
| `check_rahs` | RAHS 闸门(运行时架构健康度) | Step 4/8 |
|
|
151
|
+
| `check_add_route_status` | add-route 文件存在性校验 | Step 3 前 |
|
|
152
|
+
| `check_spec_sync` | Spec 文档勾选状态与代码一致性 | Spec 执行后 |
|
|
153
|
+
| `find_related_docs` | 检索相关架构/规范文档 | 语境理解 |
|
|
86
154
|
|
|
87
|
-
>
|
|
155
|
+
> 完整工具列表见 [MCP 工具链规范](https://github.com/xiaomingming92/codein2027/blob/main/docs/大田精准耕播智能决策系统/knowledge/02-规范/%E3%80%8A%E5%BC%80%E5%8F%91%E6%93%8D%E4%BD%9C%E5%AE%A1%E8%AE%A1%E5%AD%98%E6%A1%A3%E8%A7%84%E8%8C%83%E3%80%8B.md)。
|
|
156
|
+
|
|
157
|
+
## 架构全景
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
┌─────────────┐
|
|
161
|
+
│ ADD 范式 │
|
|
162
|
+
│ Step 0-9 │
|
|
163
|
+
└──────┬──────┘
|
|
164
|
+
│ 门禁驱动
|
|
165
|
+
┌────────────┼────────────┐
|
|
166
|
+
▼ ▼ ▼
|
|
167
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
168
|
+
│ DPS 闸门 │ │ RAHS 闸门│ │合规检查 │
|
|
169
|
+
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
|
170
|
+
│ │ │
|
|
171
|
+
▼ ▼ ▼
|
|
172
|
+
┌─────────────────────────────────────┐
|
|
173
|
+
│ 审计基础设施层 │
|
|
174
|
+
│ DevOperation / AuditLog 表 │
|
|
175
|
+
│ MCP 审计工具链 │
|
|
176
|
+
│ Handoff / DevLog 时序文档 │
|
|
177
|
+
└─────────────────────────────────────┘
|
|
178
|
+
│
|
|
179
|
+
┌────────────┼────────────┐
|
|
180
|
+
▼ ▼ ▼
|
|
181
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
182
|
+
│ Claude │ │ Qoder │ │ VS Code │
|
|
183
|
+
│ Hooks │ │ Hooks │ │ Config │
|
|
184
|
+
└──────────┘ └──────────┘ └──────────┘
|
|
185
|
+
│
|
|
186
|
+
┌────────────┘
|
|
187
|
+
▼
|
|
188
|
+
┌─────────────────────────────────────┐
|
|
189
|
+
│ Caijuehub 规则引擎 │
|
|
190
|
+
│ TOML 驱动的策略体系 │
|
|
191
|
+
│ 检测/适配/Prisma/写入 全可配置 │
|
|
192
|
+
└─────────────────────────────────────┘
|
|
193
|
+
```
|
|
88
194
|
|
|
89
195
|
## 前置条件
|
|
90
196
|
|
|
@@ -102,4 +208,4 @@ npm 包提供模板和 MCP 工具链骨架。Report 体系(gateway.md 边界
|
|
|
102
208
|
> POSTGRES_USER: admin
|
|
103
209
|
> POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
104
210
|
> ```
|
|
105
|
-
> 数据卷建议挂载到 `~/data/your_project/postgres/`,避免容器销毁丢失数据。
|
|
211
|
+
> 数据卷建议挂载到 `~/data/your_project/postgres/`,避免容器销毁丢失数据。
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
4
5
|
import { Command } from "commander";
|
|
5
6
|
|
|
6
7
|
// src/caijuehub/strategies/detect.strategy.ts
|
|
@@ -83,7 +84,7 @@ var defaults = {
|
|
|
83
84
|
};
|
|
84
85
|
|
|
85
86
|
// src/cli/config-loader.ts
|
|
86
|
-
async function loadConfig(projectRoot, configPath,
|
|
87
|
+
async function loadConfig(projectRoot, configPath, _options) {
|
|
87
88
|
let config = { ...defaults };
|
|
88
89
|
const pkgPath = join2(projectRoot, "package.json");
|
|
89
90
|
if (existsSync2(pkgPath)) {
|
|
@@ -114,12 +115,9 @@ ${errors}`);
|
|
|
114
115
|
// src/caijuehub/strategies/writer.strategy.ts
|
|
115
116
|
import { existsSync as existsSync3, mkdirSync, writeFileSync, chmodSync } from "fs";
|
|
116
117
|
import { join as join3, dirname } from "path";
|
|
118
|
+
|
|
119
|
+
// src/lib/utils.ts
|
|
117
120
|
import { createInterface } from "readline";
|
|
118
|
-
var WRITER_CONFIG = {
|
|
119
|
-
onExisting: "ask",
|
|
120
|
-
jsonMerge: "deep",
|
|
121
|
-
shellChmod: true
|
|
122
|
-
};
|
|
123
121
|
function ask(q) {
|
|
124
122
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
125
123
|
return new Promise((r) => {
|
|
@@ -129,6 +127,13 @@ function ask(q) {
|
|
|
129
127
|
});
|
|
130
128
|
});
|
|
131
129
|
}
|
|
130
|
+
|
|
131
|
+
// src/caijuehub/strategies/writer.strategy.ts
|
|
132
|
+
var WRITER_CONFIG = {
|
|
133
|
+
onExisting: "ask",
|
|
134
|
+
jsonMerge: "deep",
|
|
135
|
+
shellChmod: true
|
|
136
|
+
};
|
|
132
137
|
async function writeFiles(projectRoot, files, options = {}) {
|
|
133
138
|
const C = WRITER_CONFIG;
|
|
134
139
|
let created = 0, skipped = 0, overwritten = 0;
|
|
@@ -186,6 +191,7 @@ var PLACEHOLDERS = {
|
|
|
186
191
|
"{{docsDir}}": "docsDir",
|
|
187
192
|
"{{logDir}}": "logDir",
|
|
188
193
|
"{{envFilePath}}": "envFilePath",
|
|
194
|
+
"{{magicDir}}": "magicDir",
|
|
189
195
|
"{{auditLoggerPath}}": "auditLoggerPath",
|
|
190
196
|
"{{mcpServerCommand}}": "mcpServerCommand",
|
|
191
197
|
"{{agentAuditImport}}": "agentAuditImport"
|
|
@@ -320,10 +326,9 @@ import { resolve as resolve2, dirname as dirname6 } from "path";
|
|
|
320
326
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
321
327
|
|
|
322
328
|
// src/caijuehub/strategies/prisma.strategy.ts
|
|
323
|
-
import {
|
|
329
|
+
import { spawnSync } from "child_process";
|
|
324
330
|
import { copyFileSync, existsSync as existsSync4, readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
325
331
|
import { resolve } from "path";
|
|
326
|
-
import { createInterface as createInterface2 } from "readline";
|
|
327
332
|
var PRISMA_CONFIG = {
|
|
328
333
|
onMissing: "ask",
|
|
329
334
|
onExistingAddPrisma: "ask",
|
|
@@ -333,15 +338,6 @@ var PRISMA_CONFIG = {
|
|
|
333
338
|
schemaArg: "--schema=prisma/",
|
|
334
339
|
requiresUserModel: true
|
|
335
340
|
};
|
|
336
|
-
function ask2(q) {
|
|
337
|
-
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
338
|
-
return new Promise((r) => {
|
|
339
|
-
rl.question(q, (a) => {
|
|
340
|
-
rl.close();
|
|
341
|
-
r(a.trim().toLowerCase());
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
341
|
async function injectPrisma(projectRoot, addPrismaTemplate, options = {}) {
|
|
346
342
|
const C = PRISMA_CONFIG;
|
|
347
343
|
const prismaDir = resolve(projectRoot, "prisma");
|
|
@@ -353,10 +349,10 @@ async function injectPrisma(projectRoot, addPrismaTemplate, options = {}) {
|
|
|
353
349
|
return true;
|
|
354
350
|
}
|
|
355
351
|
if (C.onMissing === "ask" && !options.force && !options.yes) {
|
|
356
|
-
const a = await
|
|
352
|
+
const a = await ask("\u9879\u76EE\u7F3A\u5C11 Prisma\uFF0C\u662F\u5426\u6267\u884C prisma init\uFF1F[Y/n] ");
|
|
357
353
|
if (a !== "n" && a !== "no") {
|
|
358
354
|
console.log("\u6267\u884C npx prisma init ...");
|
|
359
|
-
|
|
355
|
+
spawnSync("npx", ["prisma", "init", "--datasource-provider", "postgresql"], { cwd: projectRoot, stdio: "inherit", shell: false });
|
|
360
356
|
const envPath = resolve(projectRoot, ".env");
|
|
361
357
|
const devEnvPath = resolve(projectRoot, ".env.development");
|
|
362
358
|
if (existsSync4(envPath)) {
|
|
@@ -368,7 +364,7 @@ async function injectPrisma(projectRoot, addPrismaTemplate, options = {}) {
|
|
|
368
364
|
writeFileSync2(devEnvPath, `${existing}${existing ? "\n" : ""}${dbUrl[0]}
|
|
369
365
|
`, "utf-8");
|
|
370
366
|
}
|
|
371
|
-
|
|
367
|
+
if (existsSync4(envPath)) unlinkSync(envPath);
|
|
372
368
|
console.log("\u5DF2\u5C06 DATABASE_URL \u8FC1\u79FB\u5230 .env.development");
|
|
373
369
|
}
|
|
374
370
|
}
|
|
@@ -393,7 +389,7 @@ async function injectPrisma(projectRoot, addPrismaTemplate, options = {}) {
|
|
|
393
389
|
writeFileSync2(schemaPath, userModel + "\n" + schema, "utf-8");
|
|
394
390
|
console.log("\u5DF2\u6CE8\u5165 User \u6A21\u578B\u5230 schema.prisma");
|
|
395
391
|
} else {
|
|
396
|
-
const a = await
|
|
392
|
+
const a = await ask("schema.prisma \u7F3A\u5C11 User \u6A21\u578B\uFF0C\u662F\u5426\u81EA\u52A8\u6CE8\u5165\uFF1F[Y/n] ");
|
|
397
393
|
if (a !== "n" && a !== "no") {
|
|
398
394
|
const schema = readFileSync6(schemaPath, "utf-8");
|
|
399
395
|
writeFileSync2(schemaPath, userModel + "\n" + schema, "utf-8");
|
|
@@ -415,14 +411,14 @@ async function injectPrisma(projectRoot, addPrismaTemplate, options = {}) {
|
|
|
415
411
|
console.log("\u8DF3\u8FC7");
|
|
416
412
|
return true;
|
|
417
413
|
} else {
|
|
418
|
-
const choice = await
|
|
414
|
+
const choice = await ask("\u5DF2\u6709 prisma/add.prisma\uFF1A[s]\u8DF3\u8FC7 / [o]\u8986\u76D6 / [d]diff\uFF08\u9ED8\u8BA4 s\uFF09: ");
|
|
419
415
|
if (choice === "o") {
|
|
420
416
|
console.log("\u8986\u76D6");
|
|
421
417
|
} else if (choice === "d") {
|
|
422
418
|
copyFileSync(destPath, destPath + ".bak");
|
|
423
419
|
console.log("=== \u5F53\u524D\uFF08\u5DF2\u5907\u4EFD\uFF09===\n" + readFileSync6(destPath, "utf-8"));
|
|
424
420
|
console.log("=== \u6A21\u677F ===\n" + readFileSync6(addPrismaTemplate, "utf-8"));
|
|
425
|
-
if (await
|
|
421
|
+
if (await ask("\u786E\u8BA4\u8986\u76D6\uFF1F[y/N] ") !== "y") {
|
|
426
422
|
console.log("\u5DF2\u8DF3\u8FC7");
|
|
427
423
|
return true;
|
|
428
424
|
}
|
|
@@ -439,21 +435,26 @@ async function injectPrisma(projectRoot, addPrismaTemplate, options = {}) {
|
|
|
439
435
|
copyFileSync(addPrismaTemplate, destPath);
|
|
440
436
|
console.log("\u5DF2\u590D\u5236 add.prisma");
|
|
441
437
|
try {
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
438
|
+
const args = ["prisma", "migrate", "dev", "--name", C.migrationName];
|
|
439
|
+
if (C.schemaArg) args.push(C.schemaArg);
|
|
440
|
+
console.log(`\u6267\u884C npx ${args.join(" ")} ...`);
|
|
441
|
+
const r = spawnSync("npx", args, { cwd: projectRoot, stdio: "inherit", shell: false });
|
|
442
|
+
if (r.status !== 0) throw new Error(`prisma migrate dev \u9000\u51FA\u7801: ${r.status}`);
|
|
445
443
|
} catch (err) {
|
|
446
444
|
if (C.onMigrateFail === "keep") {
|
|
447
445
|
console.log("\u8FC1\u79FB\u5931\u8D25\uFF0C\u4FDD\u7559\u6587\u4EF6");
|
|
448
446
|
return true;
|
|
449
447
|
}
|
|
450
|
-
|
|
448
|
+
try {
|
|
449
|
+
unlinkSync(destPath);
|
|
450
|
+
} catch {
|
|
451
|
+
}
|
|
451
452
|
console.log("\u5DF2\u56DE\u6EDA");
|
|
452
453
|
throw new Error(`\u8FC1\u79FB\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`);
|
|
453
454
|
}
|
|
454
455
|
if (C.autoGenerate) {
|
|
455
456
|
console.log("\u6267\u884C prisma generate ...");
|
|
456
|
-
|
|
457
|
+
spawnSync("npx", ["prisma", "generate"], { cwd: projectRoot, stdio: "inherit", shell: false });
|
|
457
458
|
}
|
|
458
459
|
console.log("ADD \u6CBB\u7406\u6A21\u578B\u5DF2\u5C31\u7EEA");
|
|
459
460
|
return true;
|
|
@@ -480,10 +481,14 @@ async function initCommand(options) {
|
|
|
480
481
|
console.log(`\u68C0\u6D4B\u5230 IDE: ${target}${specified ? " (--adapter)" : " (\u81EA\u52A8)"}`);
|
|
481
482
|
const config = await loadConfig(projectRoot, options.config, { yes: options.yes, force: options.force });
|
|
482
483
|
config.projectRoot = projectRoot;
|
|
484
|
+
const MAGIC_DIR_MAP = { claude: ".claude", qoder: ".qoder", vscode: ".vscode" };
|
|
485
|
+
const magicDir = MAGIC_DIR_MAP[target] || ".qoder";
|
|
486
|
+
console.log(`magicDir: ${magicDir}`);
|
|
487
|
+
const renderConfig = { ...config, magicDir };
|
|
483
488
|
if (!options.dryRun) {
|
|
484
489
|
await injectPrisma2(projectRoot, { yes: options.yes, force: options.force, dryRun: options.dryRun });
|
|
485
490
|
}
|
|
486
|
-
const coreFiles = renderCore(
|
|
491
|
+
const coreFiles = renderCore(renderConfig, !!options.dryRun);
|
|
487
492
|
console.log(`Core \u6A21\u677F: ${coreFiles.size} \u6587\u4EF6`);
|
|
488
493
|
const CORE_TARGETS = [".add", ".qoder", ".claude"];
|
|
489
494
|
const allFiles = /* @__PURE__ */ new Map();
|
|
@@ -568,8 +573,11 @@ async function statusCommand() {
|
|
|
568
573
|
}
|
|
569
574
|
|
|
570
575
|
// src/cli/index.ts
|
|
576
|
+
var { version } = JSON.parse(
|
|
577
|
+
readFileSync7(new URL("../package.json", import.meta.url), "utf-8")
|
|
578
|
+
);
|
|
571
579
|
var program = new Command();
|
|
572
|
-
program.name("add-coder").description("\u521D\u59CB\u5316 ADD \u8303\u5F0F\u5DE5\u4F5C\u6D41\u6A21\u677F").version(
|
|
580
|
+
program.name("add-coder").description("\u521D\u59CB\u5316 ADD \u8303\u5F0F\u5DE5\u4F5C\u6D41\u6A21\u677F").version(version);
|
|
573
581
|
program.command("init").description("\u521D\u59CB\u5316 ADD \u6A21\u677F\u5230\u5F53\u524D\u9879\u76EE").option("--adapter <type>", "\u76EE\u6807 IDE: claude | qoder | vscode | auto", "auto").option("--config <path>", "\u6307\u5B9A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--yes", "\u8DF3\u8FC7\u4EA4\u4E92\uFF0C\u53EA\u521B\u5EFA\u65B0\u6587\u4EF6").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);
|
|
574
582
|
program.command("sync").description("\u589E\u91CF\u540C\u6B65\u7F3A\u5931\u6587\u4EF6").action(syncCommand);
|
|
575
583
|
program.command("status").description("\u68C0\u67E5 ADD \u6A21\u677F\u5B8C\u6574\u6027").action(statusCommand);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "add-coder",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "[codein2027](https://github.com/xiaomingming92/codein2027) 快速构建 ADD 编程范式的完整脚手架——AI 代码治理的落地方案。以「审计即基础设施」为核心,彻底打破编程过程黑盒与跨轮失忆,让编程范式进化为可审计、可追溯、可收敛的新时代。npx 即用,人人可体验。",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"add-coder": "bin/add-coder.js"
|
|
@@ -15,19 +15,11 @@
|
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=20"
|
|
17
17
|
},
|
|
18
|
-
"packageManager": "pnpm@11.9.0",
|
|
19
18
|
"files": [
|
|
20
19
|
"bin",
|
|
21
20
|
"dist",
|
|
22
21
|
"templates"
|
|
23
22
|
],
|
|
24
|
-
"scripts": {
|
|
25
|
-
"build": "tsup",
|
|
26
|
-
"prepare": "tsup",
|
|
27
|
-
"dev": "tsup --watch",
|
|
28
|
-
"generate": "tsx src/caijuehub/transcribe.ts",
|
|
29
|
-
"test": "node bin/add-coder.js --help"
|
|
30
|
-
},
|
|
31
23
|
"keywords": [
|
|
32
24
|
"add",
|
|
33
25
|
"add-paradigm",
|
|
@@ -35,11 +27,12 @@
|
|
|
35
27
|
"qoder",
|
|
36
28
|
"vscode",
|
|
37
29
|
"mcp",
|
|
38
|
-
"workflow"
|
|
30
|
+
"workflow",
|
|
31
|
+
"codein2027"
|
|
39
32
|
],
|
|
40
33
|
"author": "xiaomingming",
|
|
41
34
|
"email": "wujixmm@gmail.com",
|
|
42
|
-
"license": "AGPL-3.0
|
|
35
|
+
"license": "AGPL-3.0-only",
|
|
43
36
|
"dependencies": {
|
|
44
37
|
"commander": "^13.1.0",
|
|
45
38
|
"smol-toml": "^1.7.0",
|
|
@@ -58,7 +51,19 @@
|
|
|
58
51
|
}
|
|
59
52
|
},
|
|
60
53
|
"devDependencies": {
|
|
54
|
+
"@eslint/js": "^9.39.4",
|
|
55
|
+
"@types/node": "^22.20.1",
|
|
56
|
+
"eslint": "^9.39.4",
|
|
61
57
|
"tsup": "^8.4.0",
|
|
62
|
-
"typescript": "^
|
|
58
|
+
"typescript": "^6.0.3",
|
|
59
|
+
"typescript-eslint": "^8.62.1"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsup",
|
|
63
|
+
"dev": "tsup --watch",
|
|
64
|
+
"lint": "eslint src/",
|
|
65
|
+
"lint:fix": "eslint src/ --fix",
|
|
66
|
+
"generate": "tsx src/caijuehub/transcribe.ts",
|
|
67
|
+
"test": "node bin/add-coder.js --help"
|
|
63
68
|
}
|
|
64
69
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
**输入**:
|
|
16
16
|
- 上游 Review:`.qoder/reviews/farm-agent-add-coder-npm-package-review-v1.md` ✅
|
|
17
|
+
- 上游 Review v2:`.qoder/reviews/farm-agent-add-coder-npm-package-review-v2.md` ✅ — 代码实现评审
|
|
17
18
|
- Plan 文档:`.qoder/plans/2026-07/08/farm-agent-add-coder-npm-package-plan-v1.md` ✅
|
|
18
19
|
|
|
19
20
|
**动作**:
|
|
@@ -107,11 +108,12 @@
|
|
|
107
108
|
| 4 | 3 | Claude 适配器实现 | `templates/adapters/claude/`、`src/adapters/claude/renderer.ts` | `record_dev_operation` (CREATE) | — | 第2轮 Task 0 | ⬜ |
|
|
108
109
|
| 5 | 3 | Qoder 适配器实现 | `templates/adapters/qoder/`、`src/adapters/qoder/renderer.ts` | `record_dev_operation` (CREATE/MODIFY) | — | 第3轮 Task 0 | ⬜ |
|
|
109
110
|
| 6 | 3 | VS Code 适配器实现 | `templates/adapters/vscode/`、`src/adapters/vscode/renderer.ts` | `record_dev_operation` (CREATE/MODIFY) | — | 第3轮 Task 1 | ⬜ |
|
|
111
|
+
| 6b | 3 | 三目录部署(core→.add/.qoder/.claude) | `src/core/renderer.ts`、`src/cli/commands/init.ts`、adapter renderers | `record_dev_operation` (MODIFY) | — | 第3轮 Task 2 | ⬜ |
|
|
110
112
|
| 7 | 4 | 配置系统(Zod schema) | `src/config/schema.ts`、`src/config/defaults.ts` | `record_dev_operation` (CREATE) | — | 无 | ⬜ |
|
|
111
113
|
| 8 | 4 | CLI 重写 | `src/cli/`、`bin/add-coder.js`、`tsup.config.ts` | `record_dev_operation` (CREATE/MODIFY) | — | 第1轮 Task 0 + 第4轮 Task 0 | ⬜ |
|
|
112
114
|
| 9 | 5 | 集成测试 + 文档 + devlog | 测试文件、`README.md`、`package.json` | `record_dev_operation` (CREATE/MODIFY) | — | 全部前序 Task | ⬜ |
|
|
113
|
-
| 10 | 6 | CaijueHub 核心 | `src/caijuehub/caijue.toml`、`src/caijuehub/caijue.ts` | `record_dev_operation` (CREATE) | — | 第4轮 Task 1 | ⬜ |
|
|
114
|
-
| 11 | 6 |
|
|
115
|
+
| 10 | 6 | CaijueHub 核心 | `src/caijuehub/caijue.toml`、`src/caijuehub/caijue.ts`、`src/caijuehub/transcribe.ts`、`src/caijuehub/*-rules.toml` (4) | `record_dev_operation` (CREATE) | — | 第4轮 Task 1 | ⬜ |
|
|
116
|
+
| 11 | 6 | 策略文件 + cli 重构 | `src/caijuehub/strategies/*.strategy.ts` (4)、`src/cli/detect.ts`、`src/cli/prisma-injector.ts`、`src/cli/writer.ts` | `record_dev_operation` (CREATE/MODIFY) | — | 第6轮 Task 0 | ⬜ |
|
|
115
117
|
|
|
116
118
|
### 依赖拓扑
|
|
117
119
|
|
|
@@ -127,6 +129,9 @@
|
|
|
127
129
|
▼
|
|
128
130
|
第3轮: 适配器实现
|
|
129
131
|
Task 0: Claude → Task 1: Qoder → Task 2: VS Code(串行)
|
|
132
|
+
│
|
|
133
|
+
▼ 增量:core 内容三目录部署
|
|
134
|
+
Task 3.3: renderCore() 改造 → adapter renderers 不再重复部署 core
|
|
130
135
|
│
|
|
131
136
|
▼
|
|
132
137
|
第4轮: 配置 + CLI
|
|
@@ -320,4 +325,7 @@
|
|
|
320
325
|
| `packages/add-coder/templates/docs/` (grounding 文档) | CREATE | 1/1 | DOC | ⬜ |
|
|
321
326
|
| `packages/add-coder/src/caijuehub/caijue.toml` | CREATE | 6/0 | CAIJUE_CONFIG | ⬜ |
|
|
322
327
|
| `packages/add-coder/src/caijuehub/caijue.ts` | CREATE | 6/0 | CAIJUE_CONFIG | ⬜ |
|
|
328
|
+
| `packages/add-coder/src/caijuehub/transcribe.ts` | CREATE | 6/0 | CAIJUE_CONFIG | ⬜ |
|
|
329
|
+
| `packages/add-coder/src/caijuehub/*-rules.toml` (4) | CREATE | 6/0 | CAIJUE_CONFIG | ⬜ |
|
|
330
|
+
| `packages/add-coder/src/caijuehub/strategies/*.strategy.ts` (4) | CREATE | 6/1 | STRATEGY | ⬜ |
|
|
323
331
|
| `packages/add-coder/README.md` | MODIFY | 5/0 | DOC | ⬜ |
|
|
@@ -610,6 +610,11 @@ npm run generate → transcribe.ts → GENERATED 区块 │ injectPrisma
|
|
|
610
610
|
| caijue.toml | 无 | 索引注册 4 个策略 | 新增 |
|
|
611
611
|
| transcribe.ts | 无 | GENERATED 区块产出引擎 | 新增 |
|
|
612
612
|
| 策略文件 | 无 | GENERATED+USER CODE 双区块模式 | 新增 |
|
|
613
|
+
| 模板部署策略 | 仅 `.add/` | `.qoder/` `.claude/` 同时部署 core 内容 | IDE 只认自身 magic path,需三者各自完整 |
|
|
614
|
+
| `templates/core/prisma/` | add.prisma 模板 | 删除,由 injectPrisma 直接处理 | Prisma 文件不应在 `.add/` 下 |
|
|
615
|
+
| plans/specs 示例 | 无 | `templates/core/plans/` `specs/` 含 add-coder 示例 | 用户首次 init 即可看到完整 ADD 文档样例 |
|
|
616
|
+
| 三目录部署 | 仅 `.add/` | Plan 已设计,`renderCore()` 改造待执行 | 见 Plan §3.2 改造待执行清单 |
|
|
617
|
+
| Review v2 回流 | 无 | `.qoder/reviews/farm-agent-add-coder-npm-package-review-v2.md` | 代码实现评审:2 条 P0(spawnSync catch 失能、ask 重复定义)在 Plan §4.8 回流,P0-1 已补充至 Task 1.0 验收项 |
|
|
613
618
|
|
|
614
619
|
## §8 验证结果
|
|
615
620
|
|
|
@@ -630,6 +635,9 @@ npm run generate → transcribe.ts → GENERATED 区块 │ injectPrisma
|
|
|
630
635
|
- [x] `grep -r "farm.agent\|大田\|/home/xmm" templates/` 返回空
|
|
631
636
|
- [ ] `npm pack` → `npm install` 端到端(待运行时验证)
|
|
632
637
|
- [x] ADD-7 `query_audit_logs` 回查确认 — 共 20 条记录,覆盖 6 轮全部关键文件
|
|
638
|
+
- [x] Review v2 P0-1(spawnSync catch 失能)已记录至 Plan 并补充验收项
|
|
639
|
+
- [ ] Review v2 P0-2(ask 重复定义)待第6轮 CaijueHub 重构时提取到 utils
|
|
640
|
+
- [ ] Review v2 P1-1(unlinkSync 缺口)、P1-2/3(gitignore)待 CI 基建清单补充
|
|
633
641
|
|
|
634
642
|
---
|
|
635
643
|
|