agentflowctl 0.4.0 → 0.6.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.
package/README.md CHANGED
@@ -17,7 +17,7 @@ claude # 完成登入
17
17
  codex # 完成登入
18
18
  ```
19
19
 
20
- 沒有內建的 agent,只會使用 `flow.config.json` 的 `agents` 裡設定的。用 `agent setup` 互動設定:它會偵測本機的 `claude`、`codex`、`gemini`,逐一詢問要不要加入、名稱與 model,再設定輪替順序;確認後才一次寫入,最後自動跑一次 `doctor`:
20
+ 沒有內建的 agent,只會使用 `flow.config.json` 的 `agents` 裡設定的。用 `agent setup` 互動設定:它會偵測本機的 `claude`、`codex`、`gemini`,逐一詢問要不要加入、名稱與 model,再設定參與的 agent;確認後才一次寫入,最後自動跑一次 `doctor`:
21
21
 
22
22
  ```bash
23
23
  npx agentflowctl agent setup
@@ -30,7 +30,7 @@ npx agentflowctl agent add claude --adapter claude
30
30
  npx agentflowctl agent add codex --adapter codex
31
31
  ```
32
32
 
33
- 之後改了設定或換了環境,用 `doctor` 檢查。它會列出設定的 agent 的 CLI 是否已安裝,並印出即將使用的輪替順序。沒有設定 `cycle` 時,依 `agents` 的順序取已安裝的;一個都沒偵測到就無法執行。
33
+ 之後改了設定或換了環境,用 `doctor` 檢查。它會列出設定的 agent 的 CLI 是否已安裝,並印出即將參與的 agent。沒有設定 `cycle` 時,依 `agents` 的順序取已安裝的;一個都沒偵測到就無法執行。
34
34
 
35
35
  ```bash
36
36
  npx agentflowctl doctor
@@ -64,26 +64,28 @@ pnpm run build
64
64
  pnpm link --global
65
65
  ```
66
66
 
67
- ## 輪替怎麼打破同溫層
67
+ ## 角色分配怎麼打破同溫層
68
68
 
69
69
  同一個模型審查自己的程式碼,容易放過自己的寫法;測試和實作出自同一個模型,也容易寫出剛好會過的測試。角色分配只有三條規則,定義在 `src/roles.ts`:
70
70
 
71
71
  | 規則 | 效果 |
72
72
  |---|---|
73
- | 審查者永遠不是最後寫程式的 agent | 每一輪審查都由另一家看 |
73
+ | 審查者永遠不是最後寫程式的 agent,多位審查者彼此不重複 | 每一輪審查都由另一家看 |
74
74
  | 同一個任務的測試與實作由不同 agent 負責(`tddSplit`) | A 寫的測試,B 實作到通過,而且不能改測試 |
75
- | 所有角色沿著同一個輪替順序前進 | 各家輪流當作者、審查者、修正者 |
75
+ | 人選隨機決定,不依 `cycle` 的順序 | 各家輪流當作者、審查者、修正者,不會固定由同一家起頭 |
76
76
 
77
- 兩家時是乒乓。輪替順序 `claude → codex` 會跑成:
77
+ `cycle` 只決定哪些 agent 參與。隨機以 run id 為種子,同一個 run 的同一步驟 `resume` 後仍是同一家。寫測試的人每 N 個任務(N 為參與的家數)洗一次牌,每家各輪一次,換輪時也不會連續兩個任務由同一家寫測試。
78
+
79
+ 兩家時是乒乓,例如:
78
80
 
79
81
  ```
80
- 計畫:claude 撰寫 → codex 審查(要求修改)→ claude 修改 → codex 審查(核准)
82
+ 計畫:codex 撰寫 → claude 審查(要求修改)→ codex 修改 → claude 審查(核准)
81
83
  T-1 測試:claude 實作:codex
82
84
  T-2 測試:codex 實作:claude
83
85
  審查:codex(最後作者是 claude)→ 要求修改 → claude 修正 → codex 審查(核准)
84
86
  ```
85
87
 
86
- 三家時,修正與審查會一直換人。例如 codex 寫、gemini 審、claude 修;仲裁交給沒寫過這份計畫、也沒審過它的那一家。
88
+ 三家時,每一輪的審查者從作者以外隨機挑,修正者從審查者以外隨機挑;仲裁交給沒寫過這份計畫、也沒審過它的那一家(有多家時隨機挑一家)。
87
89
 
88
90
  每個 commit 訊息結尾會標上實際作者,例如 `feat(T-2): 匯出 [gemini]`。
89
91
 
@@ -112,7 +114,7 @@ agentflowctl clean --all # 清掉所有已結束的 run 與中斷留
112
114
  |---|---|
113
115
  | `--req` / `--req-file` | 需求文字,或從檔案讀取 |
114
116
  | `--base` | 基底分支,預設為目前分支 |
115
- | `--cycle` | 這次 run 的輪替順序,例如 `claude,codex,gemini`;建立後就固定,`resume` 沿用 |
117
+ | `--cycle` | 這次 run 參與的 agent,例如 `claude,codex,gemini`;順序不影響分工;建立後就固定,`resume` 沿用 |
116
118
  | `--max-agent-runs` | 這次 run 的 agent 執行次數上限 |
117
119
  | `--manual-plan` | 計畫通過審查後進入 `awaiting_approval`,等 `approve` 才開始實作 |
118
120
  | `-v` / `--verbose` | 執行時印出 agent 的文字、工具呼叫與專案指令;`run`、`resume`、`approve` 都適用,也可設 `AGENTFLOWCTL_VERBOSE=1` |
@@ -226,6 +228,7 @@ stderr:
226
228
  "fixStrategy": "ring",
227
229
  "tddSplit": true,
228
230
  "tieBreak": "proceed",
231
+ "defaultModels": { "claude": "Claude 模型名稱", "codex": "Codex 模型名稱", "gemini": "Gemini 模型名稱" },
229
232
  "agents": {
230
233
  "claude": { "adapter": "claude" },
231
234
  "codex": { "adapter": "codex", "model": "你要用的模型" },
@@ -236,8 +239,9 @@ stderr:
236
239
 
237
240
  | 設定 | 預設 | 說明 |
238
241
  |---|---|---|
239
- | `cycle` | 自動偵測 | 輪替順序。未設定時依 `agents` 的順序取已安裝的 CLI。同一家 CLI 可以登記成不同 agent,例如 `claude-fast` 與 `claude-strong` |
240
- | `fixStrategy` | `ring` | `ring`:審查意見交給審查者的下一位;`author`:交回最後作者 |
242
+ | `cycle` | 自動偵測 | 參與的 agent,順序不影響分工(人選隨機決定)。未設定時依 `agents` 的順序取已安裝的 CLI。同一家 CLI 可以登記成不同 agent,例如 `claude-fast` 與 `claude-strong` |
243
+ | `defaultModels` | `{}` | 依 `claude`、`codex`、`gemini` adapter 指定全域預設 model;agent 的 `model` 優先,兩者都沒設時使用各 CLI 的預設。`command` adapter 不套用 |
244
+ | `fixStrategy` | `ring` | `ring`:審查意見隨機交給審查者以外的一家;`author`:交回最後作者 |
241
245
  | `tddSplit` | `true` | 測試與實作是否分開 |
242
246
  | `reviewQuorum` | `1` | 程式碼需要幾位不同審查者都 `approve` |
243
247
  | `planReviewQuorum` | `1` | 計畫需要幾位不同審查者都 `approve` |
@@ -271,14 +275,14 @@ verify 失敗(型別、lint、建置)一律交回最後作者。審查意見
271
275
  `agents` 與 `cycle` 也可以用 `agent` 指令修改,不必手動編輯 JSON。每次寫入前都會先驗證整份設定:
272
276
 
273
277
  ```bash
274
- agentflowctl agent setup # 互動設定 claude、codex、gemini 與輪替順序
275
- agentflowctl agent list # 設定的 agent、是否已安裝、輪替位置
278
+ agentflowctl agent setup # 互動設定 claude、codex、gemini 與參與的 agent
279
+ agentflowctl agent list # 設定的 agent、是否已安裝、是否參與
276
280
  agentflowctl agent add claude-strong --adapter claude --model opus
277
281
  agentflowctl agent add aider --adapter command -- aider --yes-always --message {prompt}
278
282
  agentflowctl agent set codex --model 你要用的模型 --extra-arg=--search
279
283
  agentflowctl agent set aider --adapter gemini # 換 adapter
280
284
  agentflowctl agent remove aider
281
- agentflowctl agent cycle claude-strong,codex,gemini # 不帶參數時顯示目前的順序
285
+ agentflowctl agent cycle claude-strong,codex,gemini # 不帶參數時顯示目前參與的 agent
282
286
  ```
283
287
 
284
288
  修改會連帶更新相關設定,並在終端機列出:
@@ -286,9 +290,9 @@ agentflowctl agent cycle claude-strong,codex,gemini # 不帶參數時顯
286
290
  - `set --adapter` 換 adapter 時,會清掉舊 adapter 的 `model`、`extraArgs`、`command`,這次有重新指定的除外。
287
291
  - `remove` 會一併從 `cycle` 移除。`cycle` 變空就刪除這個欄位,改回從 `agents` 自動偵測。
288
292
  - `--extra-arg` 可以重複指定,會整個取代原本的 `extraArgs`。參數以 `-` 開頭時,寫成 `--extra-arg=--sandbox`。
289
- - `setup` 遇到已存在的名稱會先問要不要覆寫;不覆寫時保留原設定,但仍放進這次的輪替順序。在非互動式環境(CI、管線)裡請改用 `agent add`。`command` adapter 要自己寫指令,不在 `setup` 裡。
293
+ - `setup` 遇到已存在的名稱會先問要不要覆寫;不覆寫時保留原設定,但仍會參與。在非互動式環境(CI、管線)裡請改用 `agent add`。`command` adapter 要自己寫指令,不在 `setup` 裡。
290
294
 
291
- 已建立的 run 會沿用建立時的輪替順序,不受這些修改影響。
295
+ 已建立的 run 會沿用建立時參與的 agent,不受這些修改影響。
292
296
 
293
297
  ## 計畫怎麼在沒有人的情況下通過
294
298
 
@@ -303,27 +307,29 @@ agentflowctl agent cycle claude-strong,codex,gemini # 不帶參數時顯
303
307
  | 有幾家 | 誰來仲裁 | 結果 |
304
308
  | --- | --- | --- |
305
309
  | 三家以上 | 沒參與這次討論的那一家 | 核准就繼續,否則 run 失敗 |
306
- | 兩家 | 兩家各自在全新 context 裡判斷 | 都核准就繼續;都不核准就停下;分歧依 `tieBreak` |
310
+ | 兩家 | 兩家各自在全新 context 裡判斷 | 都核准就繼續;都不核准就依裁決意見修訂並重新審查;分歧依 `tieBreak` |
307
311
  | 一家 | 同一家 | 由它自己仲裁 |
308
312
 
309
313
  兩家時的仲裁是雙盲的。仲裁者只看計畫,以及一份不含模型名稱的爭議清單(`.flow/dispute.md`)。帶有名稱的審查紀錄移到 worktree 以外。`tieBreak` 預設 `proceed`,因為後面還有測試紅燈、綠燈、verify 與程式碼審查。
310
314
 
311
- 裁決與每位仲裁者的理由附在 `plan.md` 最後的「仲裁紀錄」。原始審查與仲裁紀錄在 `.agentflowctl/runs/<id>/reviews/`。
315
+ 計畫定案或仲裁最終停止時,裁決與每位仲裁者的理由附在 `plan.md` 最後的「仲裁紀錄」。需再修訂時,裁決理由寫進 `.flow/feedback.md`,供修訂者處理;重新審查會從第一輪計數。原始審查與每輪仲裁紀錄在 `.agentflowctl/runs/<id>/reviews/`。兩家都要求修改時不因仲裁輪數而直接失敗;整個 run 仍受 `maxAgentRuns` 限制。
316
+
317
+ 仲裁 JSON 的 `verdict` 應為 `approve` 或 `changes_requested`;若模型寫成 `reject`,程式會當成 `changes_requested` 並保留理由。缺少檔案、JSON 格式錯誤或其他不合法輸出不算反對票,run 會暫停並顯示驗證錯誤;檢查 `agentflowctl logs <id>` 與 `.flow/plan-arbiter.json` 後可用 `resume` 重新執行。
312
318
 
313
319
  ## 階段與通過條件
314
320
 
315
321
  | 階段 | 負責的 agent | 程式認定通過的條件 | 失敗時 |
316
322
  |---|---|---|---|
317
- | spec | 輪替順序第 1 位 | 檔案存在、zod 驗證、id 不重複 | 重試 |
318
- | plan | 輪替順序第 1 位 | zod、相依存在、無循環、每條驗收條件都有任務 | 重試 |
319
- | plan_review | 非計畫作者的下一位(可多位) | 所有審查者都 `approve` | 進入 plan_fix |
323
+ | spec | 隨機一位 | 檔案存在、zod 驗證、id 不重複 | 重試 |
324
+ | plan | 與 spec 同一位 | zod、相依存在、無循環、每條驗收條件都有任務 | 重試 |
325
+ | plan_review | 計畫作者以外隨機挑(可多位,不重複) | 所有審查者都 `approve` | 進入 plan_fix |
320
326
  | plan_fix | 依 `fixStrategy` | 修改後仍通過 plan 的格式與 DAG 檢查 | 還原並重試 |
321
- | 仲裁 | 見上一節 | 一致核准;分歧依 `tieBreak` | 都不核准,或 `tieBreak: stop` 時 run 失敗 |
327
+ | 仲裁 | 見上一節 | 一致核准;分歧依 `tieBreak` | 兩家都不核准時進入 plan_fix 再審查;第三方不核准或 `tieBreak: stop` 時失敗 |
322
328
  | 人工確認 | 你(只有 `--manual-plan`) | `agentflowctl approve` | — |
323
- | implement 紅燈 | 第 i 個任務由第 i 位 | 有測試變更,而且測試執行後失敗 | 還原並重試 |
324
- | implement 綠燈 | 測試作者的下一位 | 測試檔沒有任何修改,而且測試通過 | 還原,或帶著輸出重試 |
329
+ | implement 紅燈 | 洗牌輪流,每家各一次 | 有測試變更,而且測試執行後失敗 | 還原並重試 |
330
+ | implement 綠燈 | 測試作者以外隨機一位 | 測試檔沒有任何修改,而且測試通過 | 還原,或帶著輸出重試 |
325
331
  | verify | — | `install` 與所有 `checks` 通過 | 交回作者修正 |
326
- | review | 非作者的下一位(可多位) | 所有審查者都 `approve` | 依 `fixStrategy` 交給下一位修正 |
332
+ | review | 作者以外隨機挑(可多位,不重複) | 所有審查者都 `approve` | 依 `fixStrategy` 交給他人修正 |
327
333
  | pr | — | push 成功;有 `gh` 就開 PR | — |
328
334
 
329
335
  驗收條件寫在 `.flow/acceptance.json`(`AC-1`…),任務寫在 `.flow/tasks.json`(`T-1`…)。
@@ -345,6 +351,14 @@ Agent 的最後回覆要附上 XML 中繼資料:
345
351
 
346
352
  `blocked` 與 `concerns` 會印在終端機上,完整回覆留在 log,可用 `agentflowctl logs` 查看。這份中繼資料只給人看;缺少或格式錯誤都不影響流程,是否通過仍由上表的程式檢查決定。
347
353
 
354
+ ### Agent 交接紀錄
355
+
356
+ 每次 agent 執行前,程式會把與當前階段有關的未結事項寫入 `.flow/handoff-context.md`。agent 完成時必須寫 `.flow/handoff-response.json`,包含 `newIssues` 和 `dispositions` 兩個陣列;沒有事項也要明確寫成 `{ "newIssues": [], "dispositions": [] }`。缺少檔案或 JSON 格式不合法,會依該步驟的重試規則處理。
357
+
358
+ 程式只在原有關卡通過後接收交接回覆,並將正式紀錄原子儲存於 `.agentflowctl/runs/<id>/handoff.json`。`action` 是需要後續處理的事項;`info` 只供參考。作者只能提出已修正並附證據,審查者才能確認結案或附理由接受。XML `<concerns>` 可以供人閱讀,但重要疑慮必須寫進交接 JSON,才能交給下一位 agent。額度代打與重試不會接收失敗呼叫的交接內容;中斷後可用 `resume` 接續。
359
+
360
+ 計畫審查或程式碼審查若核准,但該階段仍有未結的 `action`,程式會視為互相矛盾的審查結果並重試。計畫定案和開 PR 前也會再檢查一次;`info` 會提供給目標階段閱讀,但不阻擋通關。
361
+
348
362
  ## Adapter
349
363
 
350
364
  | adapter | 執行方式 | 權限 |
@@ -367,7 +381,7 @@ Codex 沙箱預設不能連網,所以建立 worktree 時會先跑 `install`。
367
381
  | 步驟 | 行為 |
368
382
  | --- | --- |
369
383
  | 計畫審查、程式碼審查、仲裁 | 暫停。額度恢復後 `agentflowctl resume`。換人代審會變成作者審自己 |
370
- | 規格、計畫、修改計畫、寫測試、寫實作、修正 | 由輪替順序上下一位還有額度的 agent 代打 |
384
+ | 規格、計畫、修改計畫、寫測試、寫實作、修正 | 隨機由另一家還有額度的 agent 代打 |
371
385
  | 每家都用完 | 暫停 |
372
386
 
373
387
  換人或暫停前,額度用完的 agent 留下的半成品會先清掉。代打寫在 `.agentflowctl/runs/<id>/substitutions.jsonl`,`status` 會列出。commit 結尾標的是實際執行的模型。
@@ -394,7 +408,7 @@ agentflowctl 本身只依賴 Node.js 與 git。專案指令透過系統 shell
394
408
  src/
395
409
  cli.ts 指令列(run、doctor、status……)
396
410
  engine.ts 狀態機與各階段
397
- roles.ts 輪替規則(含計畫修正者與仲裁者)
411
+ roles.ts 角色分配規則(含計畫修正者與仲裁者)
398
412
  runner.ts 執行 agent、正規化結果、執行專案指令
399
413
  logs.ts log 檔名、檔頭檔尾、列表與解析
400
414
  agents/ claude、codex、gemini、command
@@ -59,21 +59,21 @@ export function removeAgent(cfg, name) {
59
59
  const rest = cycle.filter((n) => n !== name);
60
60
  if (rest.length) {
61
61
  next.cycle = rest;
62
- changes.push(`已從輪替順序移除,現在是 ${rest.join(" → ")}`);
62
+ changes.push(`已從參與的 agent 移除,現在是 ${rest.join("、")}`);
63
63
  }
64
64
  else {
65
65
  delete next.cycle;
66
- changes.push("輪替順序因此變空,已刪除 cycle,改回從 agents 自動偵測已安裝的 CLI");
66
+ changes.push("參與的 agent 因此變空,已刪除 cycle,改回從 agents 自動偵測已安裝的 CLI");
67
67
  }
68
68
  }
69
69
  return { cfg: next, changes };
70
70
  }
71
71
  export function setCycle(cfg, names) {
72
72
  if (!names.length)
73
- throw new Error("輪替順序至少要有一個 agent");
73
+ throw new Error("參與的 agent 至少要有一個");
74
74
  const dup = names.find((n, i) => names.indexOf(n) !== i);
75
75
  if (dup)
76
- throw new Error(`輪替順序裡 ${dup} 重複了`);
76
+ throw new Error(`參與的 agent 裡 ${dup} 重複了`);
77
77
  const missing = names.filter((n) => !isDefined(cfg, n));
78
78
  if (missing.length)
79
79
  throw new Error(`未定義的 agent:${missing.join("、")}(先用 agent add 新增)`);
@@ -0,0 +1,12 @@
1
+ /** 兩家仲裁都要求修改時交回計畫修訂;整體執行次數由 maxAgentRuns 限制。 */
2
+ export function arbitrationDecision(verdicts, tieBreak) {
3
+ if (verdicts.includes("abstain"))
4
+ return "invalid";
5
+ const approvals = verdicts.filter((v) => v === "approve").length;
6
+ if (approvals === verdicts.length)
7
+ return "proceed";
8
+ if (approvals > 0)
9
+ return tieBreak;
10
+ return verdicts.length === 2 ? "revise" : "stop";
11
+ }
12
+ //# sourceMappingURL=arbitration.js.map
package/dist/cli.js CHANGED
@@ -36,7 +36,7 @@ function printSummary(run) {
36
36
  console.log(`run ${run.id}`);
37
37
  console.log(`階段 ${run.stage}`);
38
38
  console.log(`用量 agent 執行 ${agentRuns(run.id)} / ${run.maxAgentRuns} 次`);
39
- console.log(`agent ${run.cycle.join(" → ")}${run.lastWriter ? `(最後作者:${run.lastWriter})` : ""}`);
39
+ console.log(`agent ${run.cycle.join("、")}${run.lastWriter ? `(最後作者:${run.lastWriter})` : ""}`);
40
40
  console.log(`分支 ${run.branch}`);
41
41
  console.log(`worktree ${worktreeDir(run.id)}`);
42
42
  if (run.prUrl)
@@ -63,7 +63,7 @@ function printSummary(run) {
63
63
  if (run.stage === "awaiting_approval")
64
64
  console.log(`\n確認計畫後執行 agentflowctl approve ${run.id}`);
65
65
  }
66
- /** 決定輪替順序:指令參數 > flow.config.json > 自動偵測已安裝的 CLI */
66
+ /** 決定參與的 agent:指令參數 > flow.config.json > 自動偵測已安裝的 CLI */
67
67
  async function resolveCycle(flag) {
68
68
  const cfg = loadRepoConfig();
69
69
  const wanted = flag ? flag.split(",").map((s) => s.trim()).filter(Boolean) : cfg.cycle;
@@ -102,7 +102,7 @@ program
102
102
  .option("--base <branch>", "基底分支(預設為目前的分支)")
103
103
  .option("--max-agent-runs <n>", "單一 run 最多執行幾次 agent(預設取 flow.config.json 的 maxAgentRuns)")
104
104
  .option("--manual-plan", "計畫通過 AI 審查後,仍停下來等你確認", false)
105
- .option("--cycle <agents>", "agent 輪替順序,例如 claude,codex,gemini")
105
+ .option("--cycle <agents>", "參與的 agent,例如 claude,codex,gemini(順序不影響分工)")
106
106
  .action(async (opts) => {
107
107
  const requirement = opts.reqFile ? readFileSync(opts.reqFile, "utf8") : opts.req;
108
108
  if (!requirement?.trim())
@@ -116,7 +116,7 @@ program
116
116
  const branch = `flow/${id}`;
117
117
  console.log(`[${id}] 🌿 從 ${base} 建立 worktree(分支 ${branch})`);
118
118
  await addWorktree(root, worktreeDir(id), base, branch);
119
- console.log(`[${id}] 🤝 agent 輪替順序:${cycle.join(" → ")}`);
119
+ console.log(`[${id}] 🤝 參與的 agent:${cycle.join("、")}(角色隨機分配)`);
120
120
  const cfg = loadRepoConfig();
121
121
  const now = new Date().toISOString();
122
122
  // worktree 一建好就寫入紀錄:之後在任何地方中斷,都能用 resume 接續或用 clean 清掉
@@ -241,13 +241,13 @@ function applyEdit(edit, done) {
241
241
  for (const c of changes)
242
242
  console.log(` ↳ ${c}`);
243
243
  if (JSON.stringify(before.cycle) !== JSON.stringify(cfg.cycle)) {
244
- console.log(" 已建立的 run 會沿用建立時的輪替順序,不受影響");
244
+ console.log(" 已建立的 run 會沿用建立時參與的 agent,不受影響");
245
245
  }
246
246
  }
247
247
  const agent = program.command("agent").description("管理 agent 與 adapter 設定(寫入 flow.config.json)");
248
248
  agent
249
249
  .command("list")
250
- .description("列出設定的 agent、是否已安裝、在輪替中的位置")
250
+ .description("列出設定的 agent、是否已安裝、是否參與")
251
251
  .action(async () => {
252
252
  const cfg = loadRepoConfig();
253
253
  const cycle = await resolveCycle().catch(() => cfg.cycle ?? []);
@@ -264,10 +264,10 @@ agent
264
264
  def.extraArgs.length && `extraArgs=${def.extraArgs.join(" ")}`,
265
265
  def.command && `command=${def.command.join(" ")}`,
266
266
  ].filter(Boolean);
267
- console.log(`${ok ? "✅" : "❌"} ${name.padEnd(14)} ${pos >= 0 ? `輪替 #${pos + 1}` : "不在輪替"} ${detail.join(" ")}`);
267
+ console.log(`${ok ? "✅" : "❌"} ${name.padEnd(14)} ${pos >= 0 ? "參與" : "不參與"} ${detail.join(" ")}`);
268
268
  }
269
269
  console.log(`
270
- 輪替順序:${cycle.length ? cycle.join(" → ") : "(沒有可用的 agent)"}${cfg.cycle ? "" : "(自動偵測)"}`);
270
+ 參與的 agent:${cycle.length ? cycle.join("、") : "(沒有可用的 agent)"}${cfg.cycle ? "" : "(自動偵測)"}`);
271
271
  });
272
272
  agent
273
273
  .command("add <name> [command...]")
@@ -276,7 +276,7 @@ agent
276
276
  .option("--model <model>", "模型名稱")
277
277
  .option("--extra-arg <arg>", "額外參數,可重複;以 - 開頭時寫成 --extra-arg=--sandbox", collect)
278
278
  .action((name, command, opts) => {
279
- applyEdit((cfg) => addAgent(cfg, name, { adapter: opts.adapter, model: opts.model, extraArgs: opts.extraArg, command: command.length ? command : undefined }), `已新增 ${name};要加進輪替請用 agent cycle`);
279
+ applyEdit((cfg) => addAgent(cfg, name, { adapter: opts.adapter, model: opts.model, extraArgs: opts.extraArg, command: command.length ? command : undefined }), `已新增 ${name};要讓它參與請用 agent cycle`);
280
280
  });
281
281
  agent
282
282
  .command("set <name> [command...]")
@@ -289,19 +289,19 @@ agent
289
289
  });
290
290
  agent
291
291
  .command("remove <name>")
292
- .description("刪除 agent,一併從輪替移除")
292
+ .description("刪除 agent,一併從參與的 agent 移除")
293
293
  .action((name) => applyEdit((cfg) => removeAgent(cfg, name), `已移除 ${name}`));
294
294
  agent
295
295
  .command("cycle [names]")
296
- .description("顯示輪替順序,或用逗號分隔設定新的順序")
296
+ .description("顯示參與的 agent,或用逗號分隔設定新的名單")
297
297
  .action(async (names) => {
298
298
  if (!names) {
299
299
  const cfg = loadRepoConfig();
300
- console.log(`${(await resolveCycle()).join(" → ")}${cfg.cycle ? "" : "(自動偵測)"}`);
300
+ console.log(`${(await resolveCycle()).join("、")}${cfg.cycle ? "" : "(自動偵測)"}`);
301
301
  return;
302
302
  }
303
303
  const list = names.split(",").map((s) => s.trim()).filter(Boolean);
304
- applyEdit((cfg) => setCycle(cfg, list), `輪替順序設為 ${list.join(" → ")}`);
304
+ applyEdit((cfg) => setCycle(cfg, list), `參與的 agent 設為 ${list.join("、")}`);
305
305
  const cfg = loadRepoConfig();
306
306
  for (const n of list) {
307
307
  if (!(await probeAgent(resolveAgent(cfg, n))))
@@ -310,7 +310,7 @@ agent
310
310
  });
311
311
  agent
312
312
  .command("setup")
313
- .description("互動式設定:偵測已安裝的 claude、codex、gemini,逐一選擇要不要加入並設定輪替順序")
313
+ .description("互動式設定:偵測已安裝的 claude、codex、gemini,逐一選擇要不要加入並設定參與的 agent")
314
314
  .action(async () => {
315
315
  if (!stdin.isTTY)
316
316
  throw new Error("agent setup 需要互動式終端機,請改用 agent add");
@@ -332,7 +332,7 @@ agent
332
332
  console.log("");
333
333
  await doctor();
334
334
  });
335
- /** 檢查設定的 agent 是否已安裝,印出輪替順序與主要設定 */
335
+ /** 檢查設定的 agent 是否已安裝,印出參與的 agent 與主要設定 */
336
336
  async function doctor() {
337
337
  const cfg = loadRepoConfig();
338
338
  const names = Object.keys(cfg.agents);
@@ -344,7 +344,7 @@ async function doctor() {
344
344
  console.log(`${ok ? "✅" : "❌"} ${name.padEnd(10)} adapter=${def.adapter}${def.model ? ` model=${def.model}` : ""}`);
345
345
  }
346
346
  try {
347
- console.log(`\n輪替順序:${(await resolveCycle()).join(" → ")}`);
347
+ console.log(`\n參與的 agent:${(await resolveCycle()).join("、")}`);
348
348
  }
349
349
  catch (e) {
350
350
  console.log(`\n${e.message}`);
@@ -353,7 +353,7 @@ async function doctor() {
353
353
  console.log(`修正策略:${cfg.fixStrategy} 測試與實作分開:${cfg.tddSplit ? "是" : "否"}`);
354
354
  console.log(`程式碼審查人數:${cfg.reviewQuorum} 計畫審查人數:${cfg.planReviewQuorum} 計畫仲裁:${cfg.planArbiter ? "開啟" : "關閉"}`);
355
355
  }
356
- program.command("doctor").description("檢查可用的 agent CLI 與目前的輪替設定").action(doctor);
356
+ program.command("doctor").description("檢查可用的 agent CLI 與目前參與的 agent").action(doctor);
357
357
  program
358
358
  .command("list")
359
359
  .description("列出這個專案的所有 run")
package/dist/config.js CHANGED
@@ -1,6 +1,4 @@
1
1
  export const config = {
2
- /** 指定 Claude Code 使用的模型;未設定則用 Claude Code 預設值 */
3
- model: process.env.AGENTFLOWCTL_MODEL,
4
2
  /** 單一 Agent 執行最多幾輪工具迴圈,避免卡在迴圈裡 */
5
3
  maxTurns: Number(process.env.AGENTFLOWCTL_MAX_TURNS ?? 80),
6
4
  /** 同一個關卡連續失敗幾次後停止 */