# Action: Plan Solutions 为选中的 issues 生成执行方案。 ## Purpose 使用 subagent 分析 issues 并生成解决方案,支持多解决方案选择和自动绑定。 ## Preconditions - [ ] `state.status === "running"` - [ ] `issues with status === "planning"` exist ## Execution ```javascript async function execute(state) { const workDir = state.work_dir; const issues = state.issues || {}; // 1. 识别需要规划的 issues const planningIssues = Object.values(issues).filter(i => i.status === "planning"); if (planningIssues.length === 0) { console.log("No issues to plan"); return { stateUpdates: { issues } }; } console.log(`\n=== Planning ${planningIssues.length} Issues ===`); // 2. 为每个 issue 生成规划 subagent const planningAgents = planningIssues.map(issue => ({ issue_id: issue.id, issue_title: issue.title, prompt: ` ## TASK ASSIGNMENT ### MANDATORY FIRST STEPS (Agent Execute) 1. **Read role definition**: ~/.codex/agents/issue-plan-agent.md (MUST read first) 2. Read: .workflow/project-tech.json 3. Read: .workflow/project-guidelines.json 4. Read schema: ~/.claude/workflows/cli-templates/schemas/solution-schema.json --- Goal: Plan solution for issue "${issue.id}: ${issue.title}" Scope: - CAN DO: Explore codebase, design solutions, create tasks - CANNOT DO: Execute solutions, modify production code - Directory: ${process.cwd()} Task Description: ${issue.title} Deliverables: - Create ONE primary solution - Write to: ${workDir}/solutions/${issue.id}-plan.json - Format: JSON following solution-schema.json Quality bar: - Tasks have quantified acceptance.criteria - Each task includes test.commands - Solution follows schema exactly Return: JSON with solution_id, task_count, status ` })); // 3. 执行规划(串行执行避免竞争) for (const agent of planningAgents) { console.log(`\n→ Planning: ${agent.issue_id}`); try { // 对于 Codex,这里应该使用 spawn_agent // 对于 Claude Code Task,使用 Task() // 模拟 Task 调用 (实际应该是 spawn_agent 对于 Codex) const result = await Task({ subagent_type: "universal-executor", run_in_background: false, description: `Plan solution for ${agent.issue_id}`, prompt: agent.prompt }); // 解析结果 let planResult; try { planResult = typeof result === "string" ? JSON.parse(result) : result; } catch { planResult = { status: "executed", solution_id: `SOL-${agent.issue_id}-1` }; } // 更新 issue 状态 issues[agent.issue_id].status = "planned"; issues[agent.issue_id].solution_id = planResult.solution_id || `SOL-${agent.issue_id}-1`; issues[agent.issue_id].planned_at = new Date().toISOString(); console.log(`✓ ${agent.issue_id} → ${issues[agent.issue_id].solution_id}`); // 绑定解决方案 try { Bash(`ccw issue bind ${agent.issue_id} ${issues[agent.issue_id].solution_id}`); } catch (error) { console.log(`Note: Could not bind solution (${error.message})`); } } catch (error) { console.error(`✗ Planning failed for ${agent.issue_id}: ${error.message}`); issues[agent.issue_id].status = "registered"; // 回退 issues[agent.issue_id].error = error.message; } } // 4. 更新 issue 状态到 ccw try { Bash(`ccw issue update --from-planning`); } catch { console.log("Note: Could not update issue status"); } return { stateUpdates: { issues: issues, completed_actions: [...state.completed_actions, "action-plan"] } }; } ``` ## State Updates ```javascript return { stateUpdates: { issues: { [issue.id]: { ...issue, status: "planned", solution_id: solutionId, planned_at: timestamp } }, queue: [ ...state.queue, { item_id: `S-${index}`, issue_id: issue.id, solution_id: solutionId, status: "pending" } ] } }; ``` ## Error Handling | Error Type | Recovery | |------------|----------| | Subagent 超时 | 标记为失败,继续下一个 | | 无效解决方案 | 回退到 registered 状态 | | 绑定失败 | 记录警告,但继续 | | 文件写入失败 | 重试 3 次 | ## Next Actions (Hints) - 所有 issues 规划完成:执行 action-execute - 部分失败:用户选择是否继续或重试 - 全部失败:返回 action-list 重新选择