@andyqiu/codeforge 0.3.7 → 0.3.9
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 +185 -0
- package/agents/coder.md +7 -3
- package/agents/planner.md +133 -400
- package/agents/reviewer.md +7 -3
- package/commands/parallel-status.md +56 -0
- package/commands/parallel.md +38 -1
- package/dist/index.js +695 -433
- package/install.sh +119 -14
- package/package.json +1 -1
- package/workflows/parallel-explore.yaml +18 -53
package/install.sh
CHANGED
|
@@ -155,6 +155,96 @@ opencode_cfg_path() {
|
|
|
155
155
|
echo "$TARGET_ROOT/opencode.json"
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
# 配置默认 agent → codeforge(ADR-0056 D5 / D2 实施细节)
|
|
159
|
+
#
|
|
160
|
+
# 在 ~/.config/opencode/opencode.json 顶层幂等合并 "default_agent": "codeforge"。
|
|
161
|
+
# 行为规则:
|
|
162
|
+
# - 字段不存在 → 写入 codeforge
|
|
163
|
+
# - 字段已是 codeforge → unchanged
|
|
164
|
+
# - 字段为其他值(用户自配) → 跳过不动 + 打 warn(绝不覆盖用户配置)
|
|
165
|
+
# 仅在 MODE=user/global 调用(项目级配置由用户自己管,不动)。
|
|
166
|
+
# 失败不阻塞 install 主流程(warn + return 0)。
|
|
167
|
+
# 用 node 处理 JSON(避免 sed/awk 处理 JSON 转义边界)。
|
|
168
|
+
configure_default_agent() {
|
|
169
|
+
local opencode_json="${XDG_CONFIG_HOME:-$HOME/.config}/opencode/opencode.json"
|
|
170
|
+
local target_agent="codeforge"
|
|
171
|
+
|
|
172
|
+
if [[ ! -f "$opencode_json" ]]; then
|
|
173
|
+
warn "opencode.json 不存在,跳过 default_agent 配置(首次安装 opencode 后请手动重跑 codeforge install)"
|
|
174
|
+
return 0
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
178
|
+
warn "未找到 node,跳过 default_agent 配置(请安装 Node.js >= 20 后重跑 install)"
|
|
179
|
+
return 0
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
if [[ $DRY_RUN -eq 1 ]]; then
|
|
183
|
+
printf " ${C_BLUE}[dry-run]${C_RESET} configure default_agent=%s in %s\n" "$target_agent" "$opencode_json"
|
|
184
|
+
return 0
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
local result
|
|
188
|
+
result=$(CFG="$opencode_json" TARGET="$target_agent" node -e '
|
|
189
|
+
const fs = require("node:fs");
|
|
190
|
+
const path = process.env.CFG;
|
|
191
|
+
const target = process.env.TARGET;
|
|
192
|
+
let cfg;
|
|
193
|
+
try { cfg = JSON.parse(fs.readFileSync(path, "utf8")); }
|
|
194
|
+
catch (e) { console.log("ERROR: " + e.message); process.exit(0); }
|
|
195
|
+
const current = cfg.default_agent;
|
|
196
|
+
if (current === undefined) {
|
|
197
|
+
cfg.default_agent = target;
|
|
198
|
+
fs.writeFileSync(path, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
199
|
+
console.log("SET default_agent=" + target);
|
|
200
|
+
} else if (current === target) {
|
|
201
|
+
console.log("UNCHANGED (already " + target + ")");
|
|
202
|
+
} else {
|
|
203
|
+
console.log("SKIPPED: user has default_agent=\"" + current + "\", not touching");
|
|
204
|
+
}
|
|
205
|
+
' 2>&1) || {
|
|
206
|
+
warn "default_agent 配置失败(不阻塞 install 主流程)"
|
|
207
|
+
return 0
|
|
208
|
+
}
|
|
209
|
+
ok "default_agent: $result"
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# 卸载时还原 default_agent(仅当当前值是 codeforge 时移除字段)。
|
|
213
|
+
# 用户改成其他值的不动。
|
|
214
|
+
restore_default_agent() {
|
|
215
|
+
local opencode_json="${XDG_CONFIG_HOME:-$HOME/.config}/opencode/opencode.json"
|
|
216
|
+
if [[ ! -f "$opencode_json" ]]; then
|
|
217
|
+
return 0
|
|
218
|
+
fi
|
|
219
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
220
|
+
warn "未找到 node,跳过 default_agent 卸载还原"
|
|
221
|
+
return 0
|
|
222
|
+
fi
|
|
223
|
+
if [[ $DRY_RUN -eq 1 ]]; then
|
|
224
|
+
printf " ${C_BLUE}[dry-run]${C_RESET} restore default_agent in %s (remove if codeforge)\n" "$opencode_json"
|
|
225
|
+
return 0
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
local result
|
|
229
|
+
result=$(CFG="$opencode_json" node -e '
|
|
230
|
+
const fs = require("node:fs");
|
|
231
|
+
const path = process.env.CFG;
|
|
232
|
+
let cfg;
|
|
233
|
+
try { cfg = JSON.parse(fs.readFileSync(path, "utf8")); }
|
|
234
|
+
catch { process.exit(0); }
|
|
235
|
+
if (cfg.default_agent === "codeforge") {
|
|
236
|
+
delete cfg.default_agent;
|
|
237
|
+
fs.writeFileSync(path, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
238
|
+
console.log("REMOVED default_agent (was codeforge)");
|
|
239
|
+
} else if (cfg.default_agent !== undefined) {
|
|
240
|
+
console.log("SKIPPED: default_agent=\"" + cfg.default_agent + "\" not set by codeforge");
|
|
241
|
+
} else {
|
|
242
|
+
console.log("NOOP (no default_agent)");
|
|
243
|
+
}
|
|
244
|
+
' 2>&1) || return 0
|
|
245
|
+
ok "default_agent: $result"
|
|
246
|
+
}
|
|
247
|
+
|
|
158
248
|
# 写 ~/.config/codeforge/kh.json 模板(仅 --global 调用)
|
|
159
249
|
#
|
|
160
250
|
# 硬约束 #2:API key 绝不能落盘,模板里**不写** token / apiKey 字段。
|
|
@@ -293,6 +383,10 @@ remove_plugin_entry() {
|
|
|
293
383
|
uninstall() {
|
|
294
384
|
log "卸载 CodeForge from: $TARGET_ROOT"
|
|
295
385
|
remove_plugin_entry
|
|
386
|
+
# 还原 default_agent(仅 user/global mode;project mode 不动用户级配置)
|
|
387
|
+
if [[ "$MODE" != "project" ]]; then
|
|
388
|
+
restore_default_agent
|
|
389
|
+
fi
|
|
296
390
|
for name in "${LEGACY_DIRS[@]}" "${MANAGED_DIRS[@]}"; do
|
|
297
391
|
local p="$TARGET_ROOT/$name"
|
|
298
392
|
if [[ -e "$p" || -L "$p" ]]; then
|
|
@@ -338,13 +432,13 @@ if [[ "$ACTION" == "uninstall" ]]; then
|
|
|
338
432
|
exit 0
|
|
339
433
|
fi
|
|
340
434
|
|
|
341
|
-
# Step 1/
|
|
342
|
-
log "Step 1/
|
|
435
|
+
# Step 1/8: 环境检测
|
|
436
|
+
log "Step 1/8: 环境检测"
|
|
343
437
|
detect_opencode
|
|
344
438
|
detect_kh_mcp
|
|
345
439
|
|
|
346
|
-
# Step 2/
|
|
347
|
-
log "Step 2/
|
|
440
|
+
# Step 2/8: build dist bundle
|
|
441
|
+
log "Step 2/8: 构建 dist/index.js 单 bundle"
|
|
348
442
|
BUNDLE_SRC="$SOURCE_ROOT/$BUNDLE_SRC_REL"
|
|
349
443
|
if [[ $SKIP_BUILD -eq 1 ]]; then
|
|
350
444
|
warn "已跳过 build(--skip-build),使用现有 dist/index.js"
|
|
@@ -369,8 +463,8 @@ if [[ -f "$BUNDLE_SRC" ]]; then
|
|
|
369
463
|
ok "bundle 已就绪: $BUNDLE_SRC (${size} bytes)"
|
|
370
464
|
fi
|
|
371
465
|
|
|
372
|
-
# Step 3/
|
|
373
|
-
log "Step 3/
|
|
466
|
+
# Step 3/8: 准备目录 + 清理 legacy
|
|
467
|
+
log "Step 3/8: 准备目标目录 + 清理 legacy 注入物"
|
|
374
468
|
ensure_dir "$TARGET_ROOT"
|
|
375
469
|
for legacy in "${LEGACY_DIRS[@]}"; do
|
|
376
470
|
p="$TARGET_ROOT/$legacy"
|
|
@@ -380,8 +474,8 @@ for legacy in "${LEGACY_DIRS[@]}"; do
|
|
|
380
474
|
fi
|
|
381
475
|
done
|
|
382
476
|
|
|
383
|
-
# Step 4/
|
|
384
|
-
log "Step 4/
|
|
477
|
+
# Step 4/8: 装 bundle
|
|
478
|
+
log "Step 4/8: 装入 dist/index.js bundle"
|
|
385
479
|
BUNDLE_DST="$TARGET_ROOT/$BUNDLE_DST_REL"
|
|
386
480
|
ensure_dir "$(dirname "$BUNDLE_DST")"
|
|
387
481
|
run "cp -f '$BUNDLE_SRC' '$BUNDLE_DST'"
|
|
@@ -396,8 +490,8 @@ if [[ $DRY_RUN -eq 0 ]]; then
|
|
|
396
490
|
fi
|
|
397
491
|
ok "VERSION → ${VERSION_FILE} (${CF_VERSION})"
|
|
398
492
|
|
|
399
|
-
# Step 5/
|
|
400
|
-
log "Step 5/
|
|
493
|
+
# Step 5/8: 装 agents / commands / workflows / context-templates
|
|
494
|
+
log "Step 5/8: 装 agents / commands / workflows / context-templates"
|
|
401
495
|
for entry in "${MD_COPY_DIRS[@]}"; do
|
|
402
496
|
src_name="${entry%%:*}"; dst_name="${entry##*:}"
|
|
403
497
|
src_path="$SOURCE_ROOT/$src_name"
|
|
@@ -430,8 +524,8 @@ for entry in "${COPY_DIRS[@]}"; do
|
|
|
430
524
|
ok "$src_name/ → $dst_path (整目录拷贝)"
|
|
431
525
|
done
|
|
432
526
|
|
|
433
|
-
# Step 6/
|
|
434
|
-
log "Step 6/
|
|
527
|
+
# Step 6/8: AGENTS.md 智能合并(仅项目模式)
|
|
528
|
+
log "Step 6/8: AGENTS.md 智能合并"
|
|
435
529
|
if [[ "$MODE" == "project" ]]; then
|
|
436
530
|
agents_target="$(pwd)/AGENTS.md"
|
|
437
531
|
template_path="$SOURCE_ROOT/$KH_TEMPLATE_REL"
|
|
@@ -440,14 +534,25 @@ else
|
|
|
440
534
|
ok "全局模式:跳过项目 AGENTS.md 合并(context-templates 已装到 $TARGET_ROOT/context-templates)"
|
|
441
535
|
fi
|
|
442
536
|
|
|
443
|
-
# Step 7/
|
|
444
|
-
log "Step 7/
|
|
537
|
+
# Step 7/8: KH 全局配置模板(仅 --global)
|
|
538
|
+
log "Step 7/8: KH 全局配置模板"
|
|
445
539
|
if [[ "$MODE" == "global" ]]; then
|
|
446
540
|
write_kh_template
|
|
447
541
|
else
|
|
448
542
|
ok "项目级安装,跳过 KH 全局模板(要装请加 --global)"
|
|
449
543
|
fi
|
|
450
544
|
|
|
545
|
+
# Step 8/8: 配置默认 agent → codeforge(ADR-0056 D5)
|
|
546
|
+
# 仅 user/global mode 配置用户级 ~/.config/opencode/opencode.json
|
|
547
|
+
# project mode 不动用户级配置(项目应由用户自决是否覆盖)
|
|
548
|
+
# Windows 用户暂需手动配置(install.ps1 尚未实现该步骤,留待 ADR-0059)
|
|
549
|
+
log "Step 8/8: 配置默认 agent → codeforge"
|
|
550
|
+
if [[ "$MODE" == "global" ]]; then
|
|
551
|
+
configure_default_agent
|
|
552
|
+
else
|
|
553
|
+
ok "项目级安装,跳过用户级 default_agent 配置(要装请加 --global)"
|
|
554
|
+
fi
|
|
555
|
+
|
|
451
556
|
# 验证清单
|
|
452
557
|
hr
|
|
453
558
|
ok "${C_BOLD}CodeForge v${CF_VERSION} 安装完成${C_RESET}"
|
package/package.json
CHANGED
|
@@ -1,64 +1,29 @@
|
|
|
1
|
-
#
|
|
2
|
-
# parallel-explore.yaml — N 路并行探索工作流(Phase 4 Task NN)
|
|
1
|
+
# DEPRECATED (ADR-0054 hotfix 2)
|
|
3
2
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# 1. planner 根据用户原始需求 + KH 历史,拆出 N 个独立子任务
|
|
7
|
-
# 2. subtasks plugin 并发执行(每条子任务可分配独立 worktree)
|
|
8
|
-
# 3. reviewer 看冲突报告 + 各子任务摘要,给最终建议
|
|
3
|
+
# /parallel 命令已由 plugins/subtasks.ts 直接拦截处理(command.execute.before hook),
|
|
4
|
+
# 提供 4 类文字反馈(派出/启动/完成/总结)+ /parallel-status 查询。
|
|
9
5
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
6
|
+
# 本 workflow 之前作为 fallback 路径存在,dry_run 模式会吐大段 plan JSON 污染父 session;
|
|
7
|
+
# 真跑模式又会和 plugin 路径冲突。当前实现下整个 workflow 已无用。
|
|
8
|
+
#
|
|
9
|
+
# 双保险禁用:
|
|
10
|
+
# 1. trigger 错位为 /parallel-DISABLED-DO-NOT-MATCH — 永远 match 不上 /parallel
|
|
11
|
+
# 2. 唯一 step 是 no-op smart_search,即使误触发也仅查询 KH,不会破坏任何东西
|
|
12
|
+
#
|
|
13
|
+
# schema 要求 steps ≥ 1 + 不识别 disabled 字段,所以无法用纯禁用语法;改用 trigger 错位兜底。
|
|
14
|
+
#
|
|
15
|
+
# 如未来 plugin 链路出问题,可恢复此文件(改回 trigger /parallel + 写真正 steps)。
|
|
13
16
|
|
|
14
17
|
name: parallel-explore
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
把一个含糊需求扔给 planner 拆成 N 路独立子任务,subtasks plugin 并发跑(每路独立
|
|
18
|
-
worktree),reviewer 看冲突 + digest 给最终建议。灵感来自 Cursor Composer 的多路探索。
|
|
19
|
-
|
|
20
|
-
trigger: /parallel
|
|
18
|
+
description: (已弃用 - 见 plugins/subtasks.ts)
|
|
19
|
+
trigger: /parallel-DISABLED-DO-NOT-MATCH
|
|
21
20
|
|
|
22
21
|
steps:
|
|
23
|
-
- name:
|
|
22
|
+
- name: no-op (workflow 已弃用)
|
|
24
23
|
agent: planner
|
|
25
|
-
description: 把 ${user_request} 拆成 2~4 个独立可并发的子任务
|
|
26
|
-
inject_context:
|
|
27
|
-
role_hint: |
|
|
28
|
-
请输出 2~4 条独立子任务(每条独立可跑,互相不冲突)。
|
|
29
|
-
每条用「-」开头,单行描述。
|
|
30
24
|
actions:
|
|
31
25
|
- tool: smart_search
|
|
32
26
|
args:
|
|
33
|
-
query: "
|
|
34
|
-
limit:
|
|
35
|
-
on_error: skip
|
|
36
|
-
on_error: abort
|
|
37
|
-
|
|
38
|
-
- name: 并发
|
|
39
|
-
agent: coder
|
|
40
|
-
description: 用 subtasks plugin 并发跑全部子任务
|
|
41
|
-
requires_human_approval: false
|
|
42
|
-
actions:
|
|
43
|
-
- tool: subtasks-dispatch
|
|
44
|
-
args:
|
|
45
|
-
parentId: "${session_id}"
|
|
46
|
-
# description 由 plugin 从上一步 planner 输出里抽(按行拆)
|
|
47
|
-
description: "${planner_output}"
|
|
48
|
-
maxConcurrency: 4
|
|
49
|
-
on_error: abort
|
|
50
|
-
on_error: abort
|
|
51
|
-
|
|
52
|
-
- name: 汇总
|
|
53
|
-
agent: reviewer
|
|
54
|
-
description: 看冲突 + digest,给最终建议(合并 / 选其一 / 补救)
|
|
55
|
-
actions:
|
|
56
|
-
- tool: save_chat_insight
|
|
57
|
-
args:
|
|
58
|
-
insight: "${session_summary}"
|
|
59
|
-
category: workflow
|
|
60
|
-
tags:
|
|
61
|
-
- "trigger:/parallel"
|
|
62
|
-
- "workflow:parallel-explore"
|
|
27
|
+
query: "deprecated parallel-explore workflow no-op"
|
|
28
|
+
limit: 1
|
|
63
29
|
on_error: skip
|
|
64
|
-
on_error: skip
|