@andyqiu/codeforge 0.5.29 → 0.6.1
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/agents/codeforge.md +1 -1
- package/agents/coder-deep.md +1 -1
- package/agents/coder-quick.md +1 -1
- package/agents/coder.md +1 -1
- package/agents/discover-challenger.md +0 -1
- package/agents/discover.md +0 -1
- package/agents/planner.md +1 -1
- package/agents/reviewer-lite.md +1 -1
- package/agents/reviewer.md +1 -1
- package/bin/codeforge.mjs +22 -48
- package/dist/index.js +604 -2074
- package/install.mjs +754 -0
- package/package.json +5 -7
- package/context-templates/kh-instructions.md +0 -109
- package/install.ps1 +0 -559
- package/install.sh +0 -726
- package/scripts/merge-agents-md.mjs +0 -228
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* scripts/merge-agents-md.mjs — install.sh / install.ps1 共用的 AGENTS.md 智能合并 CLI
|
|
4
|
-
*
|
|
5
|
-
* 阶段 C.4 抽取:
|
|
6
|
-
* - 取代 install.sh / install.ps1 各自内嵌的 inline node script
|
|
7
|
-
* - 算法语义与 lib/agents-merge.ts 严格一致(单一来源)
|
|
8
|
-
* - 自带实现而不是 import lib/agents-merge.ts,因为 install 时 lib/ 可能不可访问
|
|
9
|
-
* (npm install / 全局安装场景),CLI 必须自包含
|
|
10
|
-
*
|
|
11
|
-
* 用法:
|
|
12
|
-
* node scripts/merge-agents-md.mjs --target <path/to/AGENTS.md> --template <path/to/kh-instructions.md>
|
|
13
|
-
*
|
|
14
|
-
* 选项:
|
|
15
|
-
* --target <path> 目标 AGENTS.md 路径(必填)
|
|
16
|
-
* --template <path> KH instructions 模板路径(必填)
|
|
17
|
-
* --dry-run 仅打印将要做什么,不实际写文件
|
|
18
|
-
* --no-backup 跳过 .bak 备份(默认会备份)
|
|
19
|
-
* --quiet 静默模式(仅错误输出)
|
|
20
|
-
* -h / --help 帮助
|
|
21
|
-
*
|
|
22
|
-
* 退出码:
|
|
23
|
-
* 0 = 成功(或 dry-run)
|
|
24
|
-
* 1 = 参数错误
|
|
25
|
-
* 2 = 模板文件不存在
|
|
26
|
-
* 3 = 写文件失败
|
|
27
|
-
*
|
|
28
|
-
* 任何失败都不应影响 install 主流程:调用方应检查返回码并自行决定是否容忍。
|
|
29
|
-
*
|
|
30
|
-
* 算法:见 lib/agents-merge.ts 的 JSDoc。三个分支:
|
|
31
|
-
* 1. 已存在 marker 块 → 替换块内(marker 自身保留)
|
|
32
|
-
* 2. 不存在 marker 块 → 顶部插入新块(原内容下移)
|
|
33
|
-
* 3. 文件不存在 → 生成短版骨架
|
|
34
|
-
*
|
|
35
|
-
* 单一来源声明:
|
|
36
|
-
* 本脚本是 sh / ps1 共用入口(C.4)。如需修改算法,
|
|
37
|
-
* 也要同步 lib/agents-merge.ts(TypeScript 端,给 plugin 内部用)。
|
|
38
|
-
* install.sh / install.ps1 不再持有算法实现,调用本 CLI。
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
import { readFileSync, writeFileSync, copyFileSync, existsSync } from "node:fs"
|
|
42
|
-
import { basename } from "node:path"
|
|
43
|
-
import process from "node:process"
|
|
44
|
-
|
|
45
|
-
const KH_MARKER_START = "<!-- knowledge-hub:start -->"
|
|
46
|
-
const KH_MARKER_END = "<!-- knowledge-hub:end -->"
|
|
47
|
-
const START_PREFIX = "<!-- knowledge-hub:start"
|
|
48
|
-
const END_PREFIX = "<!-- knowledge-hub:end"
|
|
49
|
-
|
|
50
|
-
// ────────────────────────────────────────────────────────────────────
|
|
51
|
-
// 算法:与 lib/agents-merge.ts 一致
|
|
52
|
-
// ────────────────────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
function findMarkerLine(text, prefix, fromLine = 0) {
|
|
55
|
-
const lines = text.split("\n")
|
|
56
|
-
for (let i = fromLine; i < lines.length; i++) {
|
|
57
|
-
if (lines[i].trimStart().startsWith(prefix)) return i
|
|
58
|
-
}
|
|
59
|
-
return -1
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function normalizeTemplate(tpl) {
|
|
63
|
-
return tpl.replace(/\n+$/g, "")
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function backupSuffix(now = new Date()) {
|
|
67
|
-
const pad = (n) => String(n).padStart(2, "0")
|
|
68
|
-
return (
|
|
69
|
-
`${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}` +
|
|
70
|
-
`${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function backupPath(originalPath, now = new Date()) {
|
|
75
|
-
return `${originalPath}.bak.${backupSuffix(now)}`
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function createDefault(template) {
|
|
79
|
-
const tpl = normalizeTemplate(template)
|
|
80
|
-
return [
|
|
81
|
-
"# 项目 AGENTS.md",
|
|
82
|
-
"",
|
|
83
|
-
KH_MARKER_START,
|
|
84
|
-
"",
|
|
85
|
-
tpl,
|
|
86
|
-
"",
|
|
87
|
-
KH_MARKER_END,
|
|
88
|
-
"",
|
|
89
|
-
"## 项目专属约定",
|
|
90
|
-
"",
|
|
91
|
-
"(在此添加本项目特有的开发约定)",
|
|
92
|
-
"",
|
|
93
|
-
].join("\n")
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 智能合并主入口。返回 { content, mode }。
|
|
98
|
-
*
|
|
99
|
-
* mode 可能值:
|
|
100
|
-
* - "replaced" 已存在 marker 块,替换块内
|
|
101
|
-
* - "inserted" 顶部插入新块
|
|
102
|
-
* - "created" 文件不存在,生成短版
|
|
103
|
-
*/
|
|
104
|
-
function mergeAgentsMd({ template, existing }) {
|
|
105
|
-
const tpl = normalizeTemplate(template)
|
|
106
|
-
|
|
107
|
-
if (existing == null || existing.length === 0) {
|
|
108
|
-
return { content: createDefault(tpl), mode: "created" }
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const startIdx = findMarkerLine(existing, START_PREFIX)
|
|
112
|
-
const endIdx = startIdx === -1 ? -1 : findMarkerLine(existing, END_PREFIX, startIdx + 1)
|
|
113
|
-
|
|
114
|
-
if (startIdx !== -1 && endIdx !== -1) {
|
|
115
|
-
const lines = existing.split("\n")
|
|
116
|
-
const before = lines.slice(0, startIdx + 1)
|
|
117
|
-
const after = lines.slice(endIdx)
|
|
118
|
-
const middle = ["", tpl, ""]
|
|
119
|
-
return {
|
|
120
|
-
content: [...before, ...middle, ...after].join("\n"),
|
|
121
|
-
mode: "replaced",
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const block = `${KH_MARKER_START}\n\n${tpl}\n\n${KH_MARKER_END}\n\n`
|
|
126
|
-
return {
|
|
127
|
-
content: block + existing,
|
|
128
|
-
mode: "inserted",
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ────────────────────────────────────────────────────────────────────
|
|
133
|
-
// CLI
|
|
134
|
-
// ────────────────────────────────────────────────────────────────────
|
|
135
|
-
|
|
136
|
-
const HELP = `
|
|
137
|
-
scripts/merge-agents-md.mjs — AGENTS.md 智能合并 CLI
|
|
138
|
-
|
|
139
|
-
用法:
|
|
140
|
-
node scripts/merge-agents-md.mjs --target <path> --template <path> [选项]
|
|
141
|
-
|
|
142
|
-
选项:
|
|
143
|
-
--target <path> 目标 AGENTS.md 路径(必填)
|
|
144
|
-
--template <path> KH instructions 模板路径(必填)
|
|
145
|
-
--dry-run 仅打印将要做什么
|
|
146
|
-
--no-backup 跳过 .bak 备份(默认会备份)
|
|
147
|
-
--quiet 静默模式
|
|
148
|
-
-h / --help 本帮助
|
|
149
|
-
|
|
150
|
-
退出码:
|
|
151
|
-
0 成功 1 参数错误 2 模板缺失 3 写文件失败
|
|
152
|
-
`
|
|
153
|
-
|
|
154
|
-
function parseArgs(argv) {
|
|
155
|
-
const args = { target: null, template: null, dryRun: false, backup: true, quiet: false }
|
|
156
|
-
for (let i = 0; i < argv.length; i++) {
|
|
157
|
-
const a = argv[i]
|
|
158
|
-
if (a === "-h" || a === "--help") {
|
|
159
|
-
process.stdout.write(HELP)
|
|
160
|
-
process.exit(0)
|
|
161
|
-
} else if (a === "--target") args.target = argv[++i]
|
|
162
|
-
else if (a === "--template") args.template = argv[++i]
|
|
163
|
-
else if (a === "--dry-run") args.dryRun = true
|
|
164
|
-
else if (a === "--no-backup") args.backup = false
|
|
165
|
-
else if (a === "--quiet") args.quiet = true
|
|
166
|
-
else {
|
|
167
|
-
process.stderr.write(`未知参数: ${a}\n${HELP}`)
|
|
168
|
-
process.exit(1)
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return args
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function main() {
|
|
175
|
-
const args = parseArgs(process.argv.slice(2))
|
|
176
|
-
if (!args.target || !args.template) {
|
|
177
|
-
process.stderr.write("错误:--target 和 --template 都必须指定\n" + HELP)
|
|
178
|
-
process.exit(1)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const log = args.quiet ? () => {} : (msg) => process.stdout.write(msg + "\n")
|
|
182
|
-
|
|
183
|
-
// 读模板
|
|
184
|
-
if (!existsSync(args.template)) {
|
|
185
|
-
process.stderr.write(`模板文件不存在: ${args.template}\n`)
|
|
186
|
-
process.exit(2)
|
|
187
|
-
}
|
|
188
|
-
const template = readFileSync(args.template, "utf8")
|
|
189
|
-
|
|
190
|
-
// 读现有 AGENTS.md(可能不存在)
|
|
191
|
-
const existing = existsSync(args.target) ? readFileSync(args.target, "utf8") : null
|
|
192
|
-
|
|
193
|
-
// 合并
|
|
194
|
-
const result = mergeAgentsMd({ template, existing })
|
|
195
|
-
|
|
196
|
-
if (args.dryRun) {
|
|
197
|
-
log(`[dry-run] mode=${result.mode} target=${args.target}`)
|
|
198
|
-
log(`[dry-run] 将写入 ${result.content.length} 字节`)
|
|
199
|
-
if (existing && args.backup) {
|
|
200
|
-
log(`[dry-run] 将备份到 ${backupPath(args.target)}`)
|
|
201
|
-
}
|
|
202
|
-
process.exit(0)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// 备份
|
|
206
|
-
if (existing && args.backup) {
|
|
207
|
-
const bak = backupPath(args.target)
|
|
208
|
-
try {
|
|
209
|
-
copyFileSync(args.target, bak)
|
|
210
|
-
log(` ✓ 已备份原 AGENTS.md → ${basename(bak)}`)
|
|
211
|
-
} catch (err) {
|
|
212
|
-
process.stderr.write(`备份失败: ${err.message}\n`)
|
|
213
|
-
process.exit(3)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// 写入
|
|
218
|
-
try {
|
|
219
|
-
writeFileSync(args.target, result.content, "utf8")
|
|
220
|
-
log(` ✓ AGENTS.md ${result.mode}: ${args.target}`)
|
|
221
|
-
process.exit(0)
|
|
222
|
-
} catch (err) {
|
|
223
|
-
process.stderr.write(`写入失败: ${err.message}\n`)
|
|
224
|
-
process.exit(3)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
main()
|