diff --git a/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs b/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs index 97d19625f..e170b07c6 100644 --- a/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs +++ b/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs @@ -143,7 +143,12 @@ export const usage = `用法: --plan 走「做方案」立项策划入口,不做游戏,不做产物验收和试玩 --timeout-minutes <分钟> 设置本次执行期限;自动任务默认 50 分钟,--plan 默认 6 分钟,手工模式默认不限时 --dry-run 只检查目录发现和项目准备,不启动 LLM - -h, --help 显示帮助`; + -h, --help 显示帮助 + +环境变量: + AGC_PLAN_GDD_DECISION 审批卡自动应答动作,默认 approve;revise/reject 必须 + 同时用 AGC_PLAN_GDD_COMMENT 给出真实修改意见 + AGC_PLAN_GDD_COMMENT revise/reject 的意见原文`; function readOptionValue(args, index, option) { const value = args[index + 1]?.trim(); @@ -911,12 +916,15 @@ export function parseSettledSwarmTurnReport(output) { async function runCapturedCargo( cliArguments, setActiveChild, - { timeoutMs = null, label = 'Cargo 子命令' } = {}, + { timeoutMs = null, label = 'Cargo 子命令', stdin = null } = {}, ) { const child = spawnChild(cargoCommand, buildCargoCliArguments(cliArguments), { - stdio: ['ignore', 'pipe', 'pipe'], + stdio: [stdin === null ? 'ignore' : 'pipe', 'pipe', 'pipe'], }); setActiveChild(child); + if (stdin !== null) { + child.stdin.end(stdin); + } let stdout = ''; let stderr = ''; child.stdout.setEncoding('utf8'); @@ -1007,7 +1015,9 @@ async function runTaskCargo( let planGddApprovalPromise = null; const startPlanGddApproval = () => { planGddApprovalStarted = true; - console.log('[自动审批] 检测到 Fast GDD 审批位,正在提交 approve'); + console.log( + `[自动审批] 检测到 Fast GDD 审批位,正在提交 ${resolvePlanGddAutoDecision().action}`, + ); planGddApprovalPromise = onPlanGddApprovalWait() .then((value) => { planGddApproval = value; @@ -1842,13 +1852,30 @@ export function parsePlanGddDecisionOutput(output) { ); } -// 审批卡是这条链路唯一的人类判据,所以自动应答只投 approve,且只在投影确实有一张 -// 待决定审批时出手。revise/reject 需要一段真实的修改意见,让机器编一段等于把判据 -// 换成噪声;要跑那两条分支就手工调 --plan-gdd-decide。 +// 审批卡是这条链路唯一的人类判据,所以自动应答默认只投 approve,且只在投影确实有 +// 一张待决定审批时出手。revise/reject 需要一段真实的修改意见,让机器编一段等于把 +// 判据换成噪声——所以那两条分支只在跑的人自己用 AGC_PLAN_GDD_COMMENT 给出意见时 +// 才走。手工调 --plan-gdd-decide 也能达到同样效果,但那要求 plan 根 run 仍然活着, +// 而它恰好是本进程持有的 CLI 子进程。 export function planGddAutoApprovalIsPending(state) { return Boolean(state?.pendingApproval); } +export function resolvePlanGddAutoDecision(env = process.env) { + const action = (env.AGC_PLAN_GDD_DECISION ?? 'approve').trim(); + if (!['approve', 'revise', 'reject'].includes(action)) { + throw new Error('AGC_PLAN_GDD_DECISION 只能是 approve / revise / reject'); + } + const comment = (env.AGC_PLAN_GDD_COMMENT ?? '').trim(); + if (action === 'approve') return { action, comment: null }; + if (!comment) { + throw new Error( + `${action} 必须同时设 AGC_PLAN_GDD_COMMENT 提供真实修改意见`, + ); + } + return { action, comment }; +} + async function settlePlanGddApproval( projectPath, runtimeConfigPath, @@ -1875,18 +1902,21 @@ async function settlePlanGddApproval( if (!planGddAutoApprovalIsPending(before)) { return { decided: false, state: before }; } + const { action, comment } = resolvePlanGddAutoDecision(); const decision = await runCapturedCargo( [ '--config-dir', runtimeConfigPath, '--plan-gdd-decide', projectPath, - 'approve', + action, + ...(comment === null ? [] : ['--stdin']), ], setActiveChild, { timeoutMs: planGddApprovalTimeoutMs, label: 'Fast GDD 审批决定', + stdin: comment, }, ); if (decision.code !== 0 || decision.signal) { @@ -1926,7 +1956,7 @@ async function reportPlanGddApproval(approval) { return; } console.log( - ` [已批准] outcome=${approval.receipt.outcome} v${approval.receipt.decisionRef.version} 投影状态=${state.state}`, + ` [已决定 ${approval.receipt.decisionRef.action}] outcome=${approval.receipt.outcome} v${approval.receipt.decisionRef.version} 投影状态=${state.state}`, ); if (approval.recovered) { console.log(