需求规划工作流Skill workflow-req-plan

该技能用于将复杂需求分解为渐进式路线图或任务序列,自动创建问题并生成执行计划,便于团队协作和项目管理。关键词包括需求分解、路线图规划、问题创建、团队协作、项目管理、软件开发、自动化工作流。

需求分析 0 次安装 2 次浏览 更新于 3/16/2026

name: workflow-req-plan description: 需求级渐进式路线图规划与问题创建。将需求分解为收敛层或任务序列,通过 ccw issue create 创建问题,并生成 roadmap.md 供人工审查。问题存储在 .workflow/issues/issues.jsonl(单一事实来源)。 argument-hint: “[-y|–yes] [-c|–continue] [-m|–mode progressive|direct|auto] "需求描述"” allowed-tools: spawn_agent, wait, send_input, close_agent, AskUserQuestion, Read, Write, Edit, Bash, Glob, Grep

工作流 需求规划

使用方式

$workflow-req-plan "实现用户认证系统,支持 OAuth 和 2FA"

# 选择模式
$workflow-req-plan -m progressive "构建实时通知系统"   # 分层 MVP→迭代
$workflow-req-plan -m direct "重构支付模块"                   # 拓扑排序任务序列
$workflow-req-plan -m auto "添加数据导出功能"                     # 自动选择策略

# 继续现有会话
$workflow-req-plan --continue "用户认证系统"

# 自动模式(跳过所有确认)
$workflow-req-plan -y "实现缓存层"

# 标志
-y, --yes                              跳过所有确认(自动模式)
-c, --continue                         继续现有会话
-m, --mode <progressive|direct|auto>   分解策略(默认:auto)

上下文来源:cli-explore-agent(可选)+ 需求分析 输出目录.workflow/.req-plan/{会话-id}/ 核心创新:需求分解 → 通过 ccw issue create 创建问题。问题存储在 .workflow/issues/issues.jsonl(单一事实来源);波次和依赖信息嵌入在问题标签和 extended_context.notes 中。team-planex 直接通过 ID 或标签查询消费问题。

概述

需求级分层路线图规划。将需求分解为 收敛层或任务序列,通过 ccw issue create 创建问题。问题是 .workflow/issues/issues.jsonl 中的单一事实来源;波次和依赖信息嵌入在问题标签和 extended_context.notes 中。

双重模式

  • 渐进式:分层 MVP→迭代,适用于高不确定性需求(先验证,后细化)
  • 直接式:拓扑排序任务序列,适用于低不确定性需求(清晰任务,直接排序)
  • 自动式:基于不确定性级别自动选择

核心工作流:需求理解 → 策略选择 → 上下文收集(可选) → 分解 + 问题创建 → 验证 → team-planex 交接

执行过程

阶段 0:初始化
   ├─ 解析参数(--yes、--continue、--mode)
   ├─ 生成会话 ID(RPLAN-{slug}-{date})
   └─ 创建会话文件夹

阶段 1:需求理解与策略选择
   ├─ 解析需求:目标 / 约束 / 利益方
   ├─ 评估不确定性级别
   │   ├─ 高不确定性 → 推荐渐进式
   │   └─ 低不确定性 → 推荐直接式
   ├─ ASK_USER:确认策略(-m 跳过,-y 自动选择)
   └─ 写入 strategy-assessment.json + roadmap.md 骨架

阶段 2:上下文收集(可选,子代理)
   ├─ 检测代码库:package.json / go.mod / src / ...
   ├─ 有代码库 → spawn_agent cli-explore-agent
   │   ├─ 探索相关模块和模式
   │   ├─ wait 等待完成
   │   └─ close_agent 关闭代理
   └─ 无代码库 → 跳过,纯需求分解

阶段 3:分解与问题创建(内联代理)
   ├─ 步骤 3.1:CLI 辅助分解
   │   ├─ 构建 CLI 提示,包含需求 + 上下文 + 模式
   │   ├─ 执行 Gemini(备用:Qwen → 手动分解)
   │   └─ 解析 CLI 输出为结构化记录
   ├─ 步骤 3.2:记录增强与验证
   │   ├─ 根据模式验证每条记录
   │   ├─ 增强收敛标准质量
   │   ├─ 验证依赖图(无循环)
   │   └─ 渐进式:验证范围;直接式:验证输入/输出
   ├─ 步骤 3.3:问题创建与输出生成
   │   ├─ 内部记录 → 问题数据映射
   │   ├─ 为每个项目创建 ccw issue(获取 ISS-xxx ID)
   │   └─ 生成 roadmap.md 带问题 ID 引用
   └─ 步骤 3.4:分解质量检查(强制)
       ├─ 执行 CLI 质量检查(Gemini,Qwen 备用)
       └─ 决定:通过 / 自动修复 / 需要审查

阶段 4:验证与 team-planex 交接
   ├─ 显示分解结果(表格 + 收敛标准)
   ├─ ASK_USER:反馈循环(最多 5 轮)
   └─ ASK_USER:下一步(team-planex / 波次执行 / 查看 / 完成)

输出

.workflow/.req-plan/RPLAN-{slug}-YYYY-MM-DD/
├── roadmap.md                    # 人类可读路线图,带问题 ID 引用
├── strategy-assessment.json      # 策略评估结果
└── exploration-codebase.json     # 代码库上下文(可选)
文件 阶段 描述
strategy-assessment.json 1 不确定性分析 + 模式推荐 + 提取的目标/约束/利益方
roadmap.md(骨架) 1 初始骨架带占位符,阶段 3 最终化
exploration-codebase.json 2 代码库上下文:相关模块、模式、集成点(仅当代码库存在时)
roadmap.md(最终) 3 人类可读路线图,带问题 ID 引用、收敛详情、team-planex 执行指南

子代理 API 参考

spawn_agent

创建新子代理并分配任务。

const agentId = spawn_agent({
  message: `
## 任务分配

### 强制第一步(代理执行)
1. **读取角色定义**:~/.codex/agents/{agent-type}.md(必须先读)
2. 读取:.workflow/project-tech.json
3. 读取:.workflow/project-guidelines.json

## 任务上下文
${taskContext}

## 可交付物
${deliverables}
`
})

wait

从子代理获取结果(唯一检索结果的方式)。

const result = wait({
  ids: [agentId],
  timeout_ms: 600000  // 10 分钟
})

if (result.timed_out) {
  // 处理超时 - 可以发送输入提示完成
}

close_agent

清理子代理资源(不可逆)。

close_agent({ id: agentId })

实现

阶段 0:初始化

步骤 0:确定项目根目录
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()

// 解析参数
const args = "$ARGUMENTS"
const AUTO_YES = args.includes('--yes') || args.includes('-y')
const continueMode = args.includes('--continue') || args.includes('-c')
const modeMatch = args.match(/(?:--mode|-m)\s+(progressive|direct|auto)/)
const requestedMode = modeMatch ? modeMatch[1] : 'auto'

// 清理需求文本(移除标志)
const requirement = args
  .replace(/--yes|-y|--continue|-c|--mode\s+\w+|-m\s+\w+/g, '')
  .trim()

const slug = requirement.toLowerCase()
  .replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-')
  .substring(0, 40)
const dateStr = getUtc8ISOString().substring(0, 10)
const sessionId = `RPLAN-${slug}-${dateStr}`
const sessionFolder = `${projectRoot}/.workflow/.req-plan/${sessionId}`

bash(`mkdir -p ${sessionFolder}`)

// 实用函数
function fileExists(p) {
  try { return bash(`test -f "${p}" && echo "yes"`).includes('yes') } catch { return false }
}

阶段 1:需求理解与策略选择

目标:解析需求,评估不确定性,选择分解策略。

// 1. 解析需求
// - 提取核心目标(要实现什么)
// - 识别约束(技术栈、时间线、兼容性等)
// - 识别利益方(用户、管理员、开发者等)
// - 识别关键词以确定领域

// 2. 评估不确定性级别
const uncertaintyFactors = {
  scope_clarity: '低|中|高',
  technical_risk: '低|中|高',
  dependency_unknown: '低|中|高',
  domain_familiarity: '低|中|高',
  requirement_stability: '低|中|高'
}
// 高不确定性(>=3 高) → 渐进式
// 低不确定性(>=3 低) → 直接式
// 其他 → 询问用户偏好

// 3. 策略选择
let selectedMode
if (requestedMode !== 'auto') {
  selectedMode = requestedMode
} else if (AUTO_YES) {
  selectedMode = recommendedMode  // 使用默认值
} else {
  const strategyAnswer = ASK_USER([
    {
      id: "strategy", type: "select",
      prompt: `分解策略选择:

不确定性:${uncertaintyLevel}
推荐:${recommendedMode}

选择:`,
      options: [
        { label: recommendedMode === 'progressive' ? "渐进式(推荐)" : "渐进式",
          description: "分层 MVP→迭代,先验证核心" },
        { label: recommendedMode === 'direct' ? "直接式(推荐)" : "直接式",
          description: "拓扑排序任务序列" }
      ]
    }
  ])  // 阻塞(等待用户响应)
  selectedMode = strategyAnswer.strategy.toLowerCase().includes('progressive') ? 'progressive' : 'direct'
}

// 4. 生成 strategy-assessment.json
const strategyAssessment = {
  session_id: sessionId,
  requirement: requirement,
  timestamp: getUtc8ISOString(),
  uncertainty_factors: uncertaintyFactors,
  uncertainty_level: uncertaintyLevel,
  recommended_mode: recommendedMode,
  selected_mode: selectedMode,
  goal: extractedGoal,
  constraints: extractedConstraints,
  stakeholders: extractedStakeholders,
  domain_keywords: extractedKeywords
}
Write(`${sessionFolder}/strategy-assessment.json`, JSON.stringify(strategyAssessment, null, 2))

// 5. 初始化 roadmap.md 骨架
const roadmapMdSkeleton = `# 需求路线图

**会话**:${sessionId}
**需求**:${requirement}
**策略**:${selectedMode}
**状态**:规划中
**创建时间**:${getUtc8ISOString()}

## 策略评估
- 不确定性级别:${uncertaintyLevel}
- 分解模式:${selectedMode}

## 路线图
> 阶段 3 分解后填充

## 收敛标准详情
> 阶段 3 分解后填充

## 风险项
> 阶段 3 分解后填充

## 下一步
> 阶段 4 验证后填充
`
Write(`${sessionFolder}/roadmap.md`, roadmapMdSkeleton)

成功标准

  • 需求目标、约束、利益方已识别
  • 不确定性级别已评估
  • 策略已选择(渐进式或直接式)
  • strategy-assessment.json 已生成
  • roadmap.md 骨架已初始化

阶段 2:上下文收集(可选,子代理)

目标:如果存在代码库,收集相关上下文以增强分解质量。

// 1. 检测代码库
const hasCodebase = bash(`
  test -f package.json && echo "nodejs" ||
  test -f go.mod && echo "golang" ||
  test -f Cargo.toml && echo "rust" ||
  test -f pyproject.toml && echo "python" ||
  test -f pom.xml && echo "java" ||
  test -d src && echo "generic" ||
  echo "none"
`).trim()

// 2. 代码库探索(仅当 hasCodebase !== 'none')
let exploreAgent = null

if (hasCodebase !== 'none') {
  try {
    exploreAgent = spawn_agent({
      message: `
## 任务分配

### 强制第一步(代理执行)
1. **读取角色定义**:~/.codex/agents/cli-explore-agent.md(必须先读)
2. 读取:${projectRoot}/.workflow/project-tech.json(如果存在)
3. 读取:${projectRoot}/.workflow/project-guidelines.json(如果存在)

---

## 任务目标
探索代码库以获取需求分解上下文。

## 探索上下文
需求:${requirement}
策略:${selectedMode}
项目类型:${hasCodebase}
会话:${sessionFolder}

## 强制第一步
1. 运行:ccw tool exec get_modules_by_depth '{}'
2. 基于需求关键词执行相关搜索

## 探索重点
- 识别与需求相关的模块/组件
- 找到应遵循的现有模式
- 定位新功能的集成点
- 评估当前架构约束

## 输出
将发现写入:${sessionFolder}/exploration-codebase.json

模式:{
  project_type: "${hasCodebase}",
  relevant_modules: [{name, path, relevance}],
  existing_patterns: [{pattern, files, description}],
  integration_points: [{location, description, risk}],
  architecture_constraints: [string],
  tech_stack: {languages, frameworks, tools},
  _metadata: {timestamp, exploration_scope}
}
`
    })

    // 等待并处理超时
    let result = wait({ ids: [exploreAgent], timeout_ms: 600000 })

    if (result.timed_out) {
      send_input({ id: exploreAgent, message: '立即完成并写入 exploration-codebase.json。' })
      result = wait({ ids: [exploreAgent], timeout_ms: 300000 })
      if (result.timed_out) throw new Error('代理超时')
    }

  } finally {
    if (exploreAgent) close_agent({ id: exploreAgent })
  }
}
// 无代码库 → 跳过,直接进入阶段 3

阶段 3:分解与问题创建(内联代理)

目标:执行需求分解,创建问题,生成 execution-plan.json + issues.jsonl + roadmap.md

关键:创建问题后,必须执行 分解质量检查(步骤 3.4),使用 CLI 分析,然后才能进入阶段 4。

准备上下文

const strategy = JSON.parse(Read(`${sessionFolder}/strategy-assessment.json`))
let explorationContext = null
if (fileExists(`${sessionFolder}/exploration-codebase.json`)) {
  explorationContext = JSON.parse(Read(`${sessionFolder}/exploration-codebase.json`))
}

内部记录模式(CLI 解析)

这些模式内部用于解析 CLI 分解输出。在步骤 3.3 中转换为问题。

渐进式模式 - 层记录

{
  id: "L{n}",               // L0, L1, L2, L3
  name: string,              // 层名称:MVP / 可用 / 完善 / 优化
  goal: string,              // 层目标(一句话)
  scope: [string],           // 包含的功能
  excludes: [string],        // 明确排除的功能
  convergence: {
    criteria: [string],         // 可测试条件
    verification: string,       // 如何验证
    definition_of_done: string  // 业务语言完成定义
  },
  risks: [{description, probability, impact, mitigation}],
  effort: "small" | "medium" | "large",
  depends_on: ["L{n}"]
}

直接式模式 - 任务记录

{
  id: "T{n}",                // T1, T2, T3, ...
  title: string,
  type: "infrastructure" | "feature" | "enhancement" | "testing",
  scope: string,
  inputs: [string],
  outputs: [string],
  convergence: { criteria, verification, definition_of_done },
  depends_on: ["T{n}"],
  parallel_group: number      // 相同组 = 可并行化
}

收敛质量要求

字段 要求 坏示例 好示例
criteria[] 可测试 "系统工作正常" "API 返回 200 且响应体包含 user_id 字段"
verification 可执行 "检查一下" "jest --testPathPattern=auth && curl -s localhost:3000/health"
definition_of_done 业务语言 "代码通过编译" "新用户可完成注册→登录→执行核心操作的完整流程"

步骤 3.1:CLI 辅助分解

渐进式模式 CLI 模板
ccw cli -p "
目的:将需求分解为渐进式层(MVP→迭代),带收敛标准
成功:2-4 个自包含层,每层有可测试收敛,无范围重叠

需求:
${requirement}

策略上下文:
- 不确定性:${strategy.uncertainty_level}
- 目标:${strategy.goal}
- 约束:${strategy.constraints.join(', ')}
- 利益方:${strategy.stakeholders.join(', ')}

${explorationContext ? `代码库上下文:
- 相关模块:${explorationContext.relevant_modules.map(m => m.name).join(', ')}
- 现有模式:${explorationContext.existing_patterns.map(p => p.pattern).join(', ')}
- 架构约束:${explorationContext.architecture_constraints.join(', ')}
- 技术栈:${JSON.stringify(explorationContext.tech_stack)}` : '无代码库(纯需求分解)'}

任务:
• 定义 2-4 个从 MVP 到完整实现的渐进式层
• L0 (MVP):最小可行闭环 - 核心路径端到端工作
• L1 (可用):关键用户路径,基本错误处理
• L2 (完整):边界情况、性能、安全强化
• L3 (优化):高级功能、可观测性、运营支持
• 每层:明确范围(包含)和排除(不包含)
• 每层:收敛带可测试标准、可执行验证、业务语言 DoD
• 每层风险项

模式:analysis
上下文:@**/*
预期:
每层输出:
## L{n}: {名称}
**目标**:{一句话}
**范围**:{逗号分隔功能}
**排除**:{逗号分隔排除功能}
**收敛**:
- 标准:{可测试条件列表}
- 验证:{可执行命令或步骤}
- 完成定义:{业务语言句子}
**风险项**:{列表}
**工作量**:{small|medium|large}
**依赖**:{层 ID 或无}

约束:
- 每个功能仅属于一层(无重叠)
- 标准必须可测试(可编写断言)
- 验证必须可执行(命令或明确步骤)
- 完成定义必须非技术利益方可理解
- L0 必须是完整闭环(端到端路径工作)
" --tool gemini --mode analysis
直接式模式 CLI 模板
ccw cli -p "
目的:将需求分解为拓扑排序任务序列,带收敛标准
成功:自包含任务,清晰输入/输出,可测试收敛,正确依赖顺序

需求:
${requirement}

策略上下文:
- 目标:${strategy.goal}
- 约束:${strategy.constraints.join(', ')}

${explorationContext ? `代码库上下文:
- 相关模块:${explorationContext.relevant_modules.map(m => m.name).join(', ')}
- 现有模式:${explorationContext.existing_patterns.map(p => p.pattern).join(', ')}
- 技术栈:${JSON.stringify(explorationContext.tech_stack)}` : '无代码库(纯需求分解)'}

任务:
• 分解为垂直切片,边界清晰
• 每任务:类型(基础设施|功能|增强|测试)
• 每任务:明确输入(需要什么)和输出(产生什么)
• 每任务:收敛带可测试标准、可执行验证、业务语言 DoD
• 拓扑排序:尊重依赖顺序
• 分配 parallel_group 数字(相同组 = 可并行运行)

模式:analysis
上下文:@**/*
预期:
每任务输出:
## T{n}: {标题}
**类型**:{infrastructure|feature|enhancement|testing}
**范围**:{描述}
**输入**:{逗号分隔文件/模块或 'none'}
**输出**:{逗号分隔文件/模块}
**收敛**:
- 标准:{可测试条件列表}
- 验证:{可执行命令或步骤}
- 完成定义:{业务语言句子}
**依赖**:{任务 ID 或无}
**并行组**:{数字}

约束:
- 输入必须来自前置任务输出或现有资源
- 无循环依赖
- 标准必须可测试
- 验证必须可执行
- 相同 parallel_group 的任务必须真正独立
" --tool gemini --mode analysis
CLI 备用链
// 备用链:Gemini → Qwen → 手动分解
try {
  cliOutput = executeCLI('gemini', prompt)
} catch (error) {
  try {
    cliOutput = executeCLI('qwen', prompt)
  } catch {
    // 手动备用(见备用分解)
    records = selectedMode === 'progressive'
      ? manualProgressiveDecomposition(requirement, explorationContext)
      : manualDirectDecomposition(requirement, explorationContext)
  }
}
CLI 输出解析
// 解析渐进式层
function parseProgressiveLayers(cliOutput) {
  const layers = []
  const layerBlocks = cliOutput.split(/## L(\d+):/).slice(1)

  for (let i = 0; i < layerBlocks.length; i += 2) {
    const layerId = `L${layerBlocks[i].trim()}`
    const text = layerBlocks[i + 1]

    const nameMatch = /^(.+?)(?=
)/.exec(text)
    const goalMatch = /\*\*Goal\*\*:\s*(.+?)(?=
)/.exec(text)
    const scopeMatch = /\*\*Scope\*\*:\s*(.+?)(?=
)/.exec(text)
    const excludesMatch = /\*\*Excludes\*\*:\s*(.+?)(?=
)/.exec(text)
    const effortMatch = /\*\*Effort\*\*:\s*(.+?)(?=
)/.exec(text)
    const dependsMatch = /\*\*Depends On\*\*:\s*(.+?)(?=
|$)/.exec(text)
    const riskMatch = /\*\*Risk Items\*\*:
((?:- .+?
)*)/.exec(text)

    const convergence = parseConvergence(text)

    layers.push({
      id: layerId,
      name: nameMatch?.[1].trim() || `层 ${layerId}`,
      goal: goalMatch?.[1].trim() || "",
      scope: scopeMatch?.[1].split(/[,,]/).map(s => s.trim()).filter(Boolean) || [],
      excludes: excludesMatch?.[1].split(/[,,]/).map(s => s.trim()).filter(Boolean) || [],
      convergence,
      risks: riskMatch
        ? riskMatch[1].split('
').map(s => s.replace(/^- /, '').trim()).filter(Boolean)
            .map(desc => ({description: desc, probability: "中", impact: "中", mitigation: "N/A"}))
        : [],
      effort: normalizeEffort(effortMatch?.[1].trim()),
      depends_on: parseDependsOn(dependsMatch?.[1], 'L')
    })
  }

  return layers
}

// 解析直接式任务
function parseDirectTasks(cliOutput) {
  const tasks = []
  const taskBlocks = cliOutput.split(/## T(\d+):/).slice(1)

  for (let i = 0; i < taskBlocks.length; i += 2) {
    const taskId = `T${taskBlocks[i].trim()}`
    const text = taskBlocks[i + 1]

    const titleMatch = /^(.+?)(?=
)/.exec(text)
    const typeMatch = /\*\*Type\*\*:\s*(.+?)(?=
)/.exec(text)
    const scopeMatch = /\*\*Scope\*\*:\s*(.+?)(?=
)/.exec(text)
    const inputsMatch = /\*\*Inputs\*\*:\s*(.+?)(?=
)/.exec(text)
    const outputsMatch = /\*\*Outputs\*\*:\s*(.+?)(?=
)/.exec(text)
    const dependsMatch = /\*\*Depends On\*\*:\s*(.+?)(?=
|$)/.exec(text)
    const groupMatch = /\*\*Parallel Group\*\*:\s*(\d+)/.exec(text)

    const convergence = parseConvergence(text)

    tasks.push({
      id: taskId,
      title: titleMatch?.[1].trim() || `任务 ${taskId}`,
      type: normalizeType(typeMatch?.[1].trim()),
      scope: scopeMatch?.[1].trim() || "",
      inputs: parseList(inputsMatch?.[1]),
      outputs: parseList(outputsMatch?.[1]),
      convergence,
      depends_on: parseDependsOn(dependsMatch?.[1], 'T'),
      parallel_group: parseInt(groupMatch?.[1]) || 1
    })
  }

  return tasks
}

// 解析收敛部分
function parseConvergence(text) {
  const criteriaMatch = /- Criteria:\s*((?:.+
?)+?)(?=- Verification:)/.exec(text)
  const verificationMatch = /- Verification:\s*(.+?)(?=
- Definition)/.exec(text)
  const dodMatch = /- Definition of Done:\s*(.+?)(?=
\*\*|$)/.exec(text)

  const criteria = criteriaMatch
    ? criteriaMatch[1].split('
')
        .map(s => s.replace(/^\s*[-•]\s*/, '').trim())
        .filter(s => s && !s.startsWith('Verification') && !s.startsWith('Definition'))
    : []

  return {
    criteria: criteria.length > 0 ? criteria : ["任务成功完成"],
    verification: verificationMatch?.[1].trim() || "手动验证",
    definition_of_done: dodMatch?.[1].trim() || "功能按预期工作"
  }
}

// 辅助函数
function normalizeEffort(effort) {
  if (!effort) return "中"
  const lower = effort.toLowerCase()
  if (lower.includes('small') || lower.includes('low')) return "小"
  if (lower.includes('large') || lower.includes('high')) return "大"
  return "中"
}

function normalizeType(type) {
  if (!type) return "功能"
  const lower = type.toLowerCase()
  if (lower.includes('infra')) return "基础设施"
  if (lower.includes('enhance')) return "增强"
  if (lower.includes('test')) return "测试"
  return "功能"
}

function parseList(text) {
  if (!text || text.toLowerCase() === 'none') return []
  return text.split(/[,,]/).map(s => s.trim()).filter(Boolean)
}

function parseDependsOn(text, prefix) {
  if (!text || text.toLowerCase() === 'none' || text === '[]') return []
  const pattern = new RegExp(`${prefix}\\d+`, 'g')
  return (text.match(pattern) || [])
}
备用分解
// CLI 失败时手动分解
function manualProgressiveDecomposition(requirement, context) {
  return [
    {
      id: "L0", name: "MVP", goal: "最小可用闭环",
      scope: ["核心功能"], excludes: ["高级功能", "优化"],
      convergence: {
        criteria: ["核心路径端到端可跑通"],
        verification: "手动测试核心流程",
        definition_of_done: "用户可完成一次核心操作的完整流程"
      },
      risks: [{description: "技术选型待验证", probability: "中", impact: "中", mitigation: "待评估"}],
      effort: "中", depends_on: []
    },
    {
      id: "L1", name: "可用", goal: "关键用户路径完善",
      scope: ["错误处理", "输入校验"], excludes: ["性能优化", "监控"],
      convergence: {
        criteria: ["所有用户输入有校验", "错误场景有提示"],
        verification: "单元测试 + 手动测试错误场景",
        definition_of_done: "用户遇到问题时有清晰的引导和恢复路径"
      },
      risks: [], effort: "中", depends_on: ["L0"]
    }
  ]
}

function manualDirectDecomposition(requirement, context) {
  return [
    {
      id: "T1", title: "基础设施搭建", type: "基础设施",
      scope: "项目骨架和基础配置",
      inputs: [], outputs: ["project-structure"],
      convergence: {
        criteria: ["项目可构建无报错", "基础配置完成"],
        verification: "npm run build(或对应构建命令)",
        definition_of_done: "项目基础框架就绪,可开始功能开发"
      },
      depends_on: [], parallel_group: 1
    },
    {
      id: "T2", title: "核心功能实现", type: "功能",
      scope: "核心业务逻辑",
      inputs: ["project-structure"], outputs: ["core-module"],
      convergence: {
        criteria: ["核心 API/功能可调用", "返回预期结果"],
        verification: "运行核心功能测试",
        definition_of_done: "核心业务功能可正常使用"
      },
      depends_on: ["T1"], parallel_group: 2
    }
  ]
}

步骤 3.2:记录增强与验证

// 验证渐进式层
function validateProgressiveLayers(layers) {
  const errors = []

  // 检查范围重叠
  const allScopes = new Map()
  layers.forEach(layer => {
    layer.scope.forEach(feature => {
      if (allScopes.has(feature)) {
        errors.push(`范围重叠:"${feature}" 同时存在于 ${allScopes.get(feature)} 和 ${layer.id}`)
      }
      allScopes.set(feature, layer.id)
    })
  })

  // 检查循环依赖
  const cycleErrors = detectCycles(layers, 'L')
  errors.push(...cycleErrors)

  // 检查收敛质量
  layers.forEach(layer => {
    errors.push(...validateConvergence(layer.id, layer.convergence))
  })

  // 检查 L0 自包含(无依赖)
  const l0 = layers.find(l => l.id === 'L0')
  if (l0 && l0.depends_on.length > 0) {
    errors.push("L0 (MVP) 不应有依赖")
  }

  return errors
}

// 验证直接式任务
function validateDirectTasks(tasks) {
  const errors = []

  // 检查输入/输出链
  const availableOutputs = new Set()
  const sortedTasks = topologicalSort(tasks)

  sortedTasks.forEach(task => {
    task.inputs.forEach(input => {
      if (!availableOutputs.has(input)) {
        // 现有文件是有效输入 - 仅警告
      }
    })
    task.outputs.forEach(output => availableOutputs.add(output))
  })

  // 检查循环依赖
  errors.push(...detectCycles(tasks, 'T'))

  // 检查收敛质量
  tasks.forEach(task => {
    errors.push(...validateConvergence(task.id, task.convergence))
  })

  // 检查并行组一致性
  const groups = new Map()
  tasks.forEach(task => {
    if (!groups.has(task.parallel_group)) groups.set(task.parallel_group, [])
    groups.get(task.parallel_group).push(task)
  })
  groups.forEach((groupTasks, groupId) => {
    if (groupTasks.length > 1) {
      const ids = new Set(groupTasks.map(t => t.id))
      groupTasks.forEach(task => {
        task.depends_on.forEach(dep => {
          if (ids.has(dep)) {
            errors.push(`并行组 ${groupId}:${task.id} 依赖 ${dep},但两者在同一组`)
          }
        })
      })
    }
  })

  return errors
}

// 验证收敛质量
function validateConvergence(recordId, convergence) {
  const errors = []

  const vaguePatterns = /正常|正确|好|可以|没问题|works|fine|good|correct/i
  convergence.criteria.forEach((criterion, i) => {
    if (vaguePatterns.test(criterion) && criterion.length < 15) {
      errors.push(`${recordId} criteria[${i}]:太模糊 - "${criterion}"`)
    }
  })

  if (convergence.verification.length < 10) {
    errors.push(`${recordId} verification:太短,需要可执行步骤`)
  }

  const technicalPatterns = /compile|build|lint|npm|npx|jest|tsc|eslint/i
  if (technicalPatterns.test(convergence.definition_of_done)) {
    errors.push(`${recordId} definition_of_done:应为业务语言,非技术命令`)
  }

  return errors
}

// 检测循环依赖
function detectCycles(records, prefix) {
  const errors = []
  const graph = new Map(records.map(r => [r.id, r.depends_on]))
  const visited = new Set()
  const inStack = new Set()

  function dfs(node, path) {
    if (inStack.has(node)) {
      errors.push(`检测到循环依赖:${[...path, node].join(' → ')}`)
      return
    }
    if (visited.has(node)) return

    visited.add(node)
    inStack.add(node)
    ;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node]))
    inStack.delete(node)
  }

  records.forEach(r => {
    if (!visited.has(r.id)) dfs(r.id, [])
  })

  return errors
}

// 拓扑排序
function topologicalSort(tasks) {
  const result = []
  const visited = new Set()
  const taskMap = new Map(tasks.map(t => [t.id, t]))

  function visit(taskId) {
    if (visited.has(taskId)) return
    visited.add(taskId)
    const task = taskMap.get(taskId)
    if (task) {
      task.depends_on.forEach(dep => visit(dep))
      result.push(task)
    }
  }

  tasks.forEach(t => visit(t.id))
  return result
}

步骤 3.3:问题创建与输出生成

3.3a:内部记录 → 问题数据映射
// 渐进式模式:层 → 问题数据(issues-jsonl-schema)
function layerToIssue(layer, sessionId, timestamp) {
  const context = `## 目标
${layer.goal}

` +
    `## 范围
${layer.scope.map(s => `- ${s}`).join('
')}

` +
    `## 排除
${layer.excludes.map(s => `- ${s}`).join('
') || '无'}

` +
    `## 收敛标准
${layer.convergence.criteria.map(c => `- ${c}`).join('
')}

` +
    `## 验证
${layer.convergence.verification}

` +
    `## 完成定义
${layer.convergence.definition_of_done}

` +
    (layer.risks.length ? `## 风险
${layer.risks.map(r => `- ${r.description} (概率:${r.probability} 影响:${r.impact})`).join('
')}` : '')

  const effortToPriority = { small: 4, medium: 3, large: 2 }

  return {
    title: `[${layer.name}] ${layer.goal}`,
    context: context,
    priority: effortToPriority[layer.effort] || 3,
    source: "text",
    tags: ["req-plan", "progressive", layer.name.toLowerCase(), `wave-${getWaveNum(layer)}`],
    affected_components: [],
    extended_context: {
      notes: JSON.stringify({
        session: sessionId,
        strategy: "progressive",
        layer: layer.id,
        wave: getWaveNum(layer),
        effort: layer.effort,
        depends_on_issues: [],    // 所有问题创建后回填
        original_id: layer.id
      })
    },
    lifecycle_requirements: {
      test_strategy: "integration",
      regression_scope: "affected",
      acceptance_type: "automated",
      commit_strategy: "per-task"
    }
  }
}

function getWaveNum(layer) {
  const match = layer.id.match(/L(\d+)/)
  return match ? parseInt(match[1]) + 1 : 1
}

// 直接式模式:任务 → 问题数据(issues-jsonl-schema)
function taskToIssue(task, sessionId, timestamp) {
  const context = `## 范围
${task.scope}

` +
    `## 输入
${task.inputs.length ? task.inputs.map(i => `- ${i}`).join('
') : '无(起始任务)'}

` +
    `## 输出
${task.outputs.map(o => `- ${o}`).join('
')}

` +
    `## 收敛标准
${task.convergence.criteria.map(c => `- ${c}`).join('
')}

` +
    `## 验证
${task.convergence.verification}

` +
    `## 完成定义
${task.convergence.definition_of_done}`

  return {
    title: `[${task.type}] ${task.title}`,
    context: context,
    priority: 3,
    source: "text",
    tags: ["req-plan", "direct", task.type, `wave-${task.parallel_group}`],
    affected_components: task.outputs,
    extended_context: {
      notes: JSON.stringify({
        session: sessionId,
        strategy: "direct",
        task_id: task.id,
        wave: task.parallel_group,
        parallel_group: task.parallel_group,
        depends_on_issues: [],    // 所有问题创建后回填
        original_id: task.id
      })
    },
    lifecycle_requirements: {
      test_strategy: task.type === 'testing' ? 'unit' : 'integration',
      regression_scope: "affected",
      acceptance_type: "automated",
      commit_strategy: "per-task"
    }
  }
}
3.3b:通过 ccw issue create 创建问题
// 顺序创建问题(获取正式 ISS-xxx ID)
const issueIdMap = {}  // originalId → ISS-xxx

for (const record of records) {
  const issueData = selectedMode === 'progressive'
    ? layerToIssue(record, sessionId, getUtc8ISOString())
    : taskToIssue(record, sessionId, getUtc8ISOString())

  // 通过 ccw issue create 创建问题
  try {
    const createResult = bash(`ccw issue create --data '${JSON.stringify(issueData)}' --json`)
    const created = JSON.parse(createResult.trim())
    issueIdMap[record.id] = created.id
  } catch (error) {
    // 重试一次
    try {
      const retryResult = bash(`ccw issue create --data '${JSON.stringify(issueData)}' --json`)
      const created = JSON.parse(retryResult.trim())
      issueIdMap[record.id] = created.id
    } catch {
      // 记录错误,跳过此记录,继续其余
      console.error(`无法为 ${record.id} 创建问题`)
    }
  }
}

// 回填 depends_on_issues 到 extended_context.notes
for (const record of records) {
  const issueId = issueIdMap[record.id]
  if (!issueId) continue
  const deps = record.depends_on.map(d => issueIdMap[d]).filter(Boolean)
  if (deps.length > 0) {
    const currentNotes = JSON.parse(issueData.extended_context.notes)
    currentNotes.depends_on_issues = deps
    bash(`ccw issue update ${issueId} --notes '${JSON.stringify(currentNotes)}'`)
  }
}
3.3c:生成 execution-plan.json
function generateExecutionPlan(records, issueIdMap, sessionId, requirement, selectedMode) {
  const issueIds = records.map(r => issueIdMap[r.id]).filter(Boolean)

  let waves
  if (selectedMode === 'progressive') {
    waves = records.filter(r => issueIdMap[r.id]).map((r, i) => ({
      wave: i + 1,
      label: r.name,
      issue_ids: [issueIdMap[r.id]],
      depends_on_waves: r.depends_on.length > 0
        ? [...new Set(r.depends_on.map(d => records.findIndex(x => x.id === d) + 1))]
        : []
    }))
  } else {
    const groups = new Map()
    records.filter(r => issueIdMap[r.id]).forEach(r => {
      const g = r.parallel_group
      if (!groups.has(g)) groups.set(g, [])
      groups.get(g).push(r)
    })

    waves = [...groups.entries()]
      .sort(([a], [b]) => a - b)
      .map(([groupNum, groupRecords]) => ({
        wave: groupNum,
        label: `组 ${groupNum}`,
        issue_ids: groupRecords.map(r => issueIdMap[r.id]),
        depends_on_waves: groupNum > 1 ? [groupNum - 1] : []
      }))
  }

  const issueDependencies = {}
  records.forEach(r => {
    if (!issueIdMap[r.id]) return
    const deps = r.depends_on.map(d => issueIdMap[d]).filter(Boolean)
    if (deps.length > 0) {
      issueDependencies[issueIdMap[r.id]] = deps
    }
  })

  return {
    session_id: sessionId,
    requirement: requirement,
    strategy: selectedMode,
    created_at: new Date().toISOString(),
    issue_ids: issueIds,
    waves: waves,
    issue_dependencies: issueDependencies
  }
}

const executionPlan = generateExecutionPlan(records, issueIdMap, sessionId, requirement, selectedMode)
Write(`${sessionFolder}/execution-plan.json`, JSON.stringify(executionPlan, null, 2))
3.3d:生成 issues.jsonl 会话副本
const sessionIssues = []
for (const originalId of Object.keys(issueIdMap)) {
  const issueId = issueIdMap[originalId]
  if (!issueId) continue
  const issueJson = bash(`ccw issue status ${issueId} --json`).trim()
  sessionIssues.push(issueJson)
}
Write(`${sessionFolder}/issues.jsonl`, sessionIssues.join('
') + '
')
3.3e:生成 roadmap.md(带问题 ID 引用)
// 渐进式模式路线图
function generateProgressiveRoadmapMd(layers, issueIdMap, input) {
  return `# 需求路线图

**会话**:${input.sessionId}
**需求**:${input.requirement}
**策略**:渐进式
**不确定性**:${input.strategy.uncertainty_level}
**生成时间**:${new Date().toISOString()}

## 策略评估

- 目标:${input.strategy.goal}
- 约束:${input.strategy.constraints.join(', ') || '无'}
- 利益方:${input.strategy.stakeholders.join(', ') || '无'}

## 路线图概览

| 层级 | 名称 | 目标 | 工作量 | 依赖 | 问题 ID |
|------|------|------|--------|------|----------|
${layers.map(l => `| ${l.id} | ${l.name} | ${l.goal} | ${l.effort} | ${l.depends_on.length ? l.depends_on.join(', ') : '-'} | ${issueIdMap[l.id]} |`).join('
')}

## 问题映射

| 波次 | 问题 ID | 标题 | 优先级 |
|------|----------|-------|----------|
${layers.map(l => `| ${getWaveNum(l)} | ${issueIdMap[l.id]} | [${l.name}] ${l.goal} | ${({small: 4, medium: 3, large: 2})[l.effort] || 3} |`).join('
')}

## 各层详情

${layers.map(l => `### ${l.id}: ${l.name} (${issueIdMap[l.id]})

**目标**:${l.goal}

**范围**:${l.scope.join('、')}

**排除**:${l.excludes.join('、') || '无'}

**收敛标准**:
${l.convergence.criteria.map(c => `- ${c}`).join('
')}
- **验证方法**:${l.convergence.verification}
- **完成定义**:${l.convergence.definition_of_done}

**风险项**:${l.risks.length ? l.risks.map(r => `
- ${r.description}(概率:${r.probability},影响:${r.impact},缓解:${r.mitigation})`).join('') : '无'}

**工作量**:${l.effort}
`).join('
---

')}

## 风险汇总

${layers.flatMap(l => l.risks.map(r => `- **${l.id}**(${issueIdMap[l.id]}):${r.description}(概率:${r.probability},影响:${r.impact})`)).join('
') || '无已识别风险'}

## 下一步

### 使用 team-planex 执行全部波次
\`\`\`
$team-planex --plan ${input.sessionFolder}/execution-plan.json
\`\`\`

### 按波次逐步执行
\`\`\`
${layers.map(l => `# 波次 ${getWaveNum(l)}:${l.name}
$team-planex ${issueIdMap[l.id]}`).join('
')}
\`\`\`

路线图文件:\`${input.sessionFolder}/\`
- issues.jsonl(标准问题格式)
- execution-plan.json(波次编排)
`
}

// 直接式模式路线图
function generateDirectRoadmapMd(tasks, issueIdMap, input) {
  const groups = new Map()
  tasks.forEach(t => {
    const g = t.parallel_group
    if (!groups.has(g)) groups.set(g, [])
    groups.get(g).push(t)
  })

  return `# 需求路线图

**会话**:${input.sessionId}
**需求**:${input.requirement}
**策略**:直接式
**生成时间**:${new Date().toISOString()}

## 策略评估

- 目标:${input.strategy.goal}
- 约束:${input.strategy.constraints.join(', ') || '无'}

## 任务序列

| 组 | ID | 标题 | 类型 | 依赖 | 问题 ID |
|----|-----|------|------|------|----------|
${tasks.map(t => `| ${t.parallel_group} | ${t.id} | ${t.title} | ${t.type} | ${t.depends_on.length ? t.depends_on.join(', ') : '-'} | ${issueIdMap[t.id]} |`).join('
')}

## 问题映射

| 波次 | 问题 ID | 标题 | 优先级 |
|------|----------|-------|----------|
${tasks.map(t => `| ${t.parallel_group} | ${issueIdMap[t.id]} | [${t.type}] ${t.title} | 3 |`).join('
')}

## 各任务详情

${tasks.map(t => `### ${t.id}: ${t.title} (${issueIdMap[t.id]})

**类型**:${t.type} | **并行组**:${t.parallel_group}

**范围**:${t.scope}

**输入**:${t.inputs.length ? t.inputs.join(', ') : '无(起始任务)'}
**输出**:${t.outputs.join(', ')}

**收敛标准**:
${t.convergence.criteria.map(c => `- ${c}`).join('
')}
- **验证方法**:${t.convergence.verification}
- **完成定义**:${t.convergence.definition_of_done}
`).join('
---

')}

## 下一步

### 使用 team-planex 执行全部波次
\`\`\`
$team-planex --plan ${input.sessionFolder}/execution-plan.json
\`\`\`

### 按波次逐步执行
\`\`\`
${[...groups.entries()].sort(([a], [b]) => a - b).map(([g, ts]) =>
  `# 波次 ${g}:组 ${g}
$team-planex ${ts.map(t => issueIdMap[t.id]).join(' ')}`
).join('
')}
\`\`\`

路线图文件:\`${input.sessionFolder}/\`
- issues.jsonl(标准问题格式)
- execution-plan.json(波次编排)
`
}

// 写入 roadmap.md
const roadmapInput = {
  sessionId, requirement, sessionFolder,
  strategy: { ...strategy }
}
const roadmapMd = selectedMode === 'progressive'
  ? generateProgressiveRoadmapMd(records, issueIdMap, roadmapInput)
  : generateDirectRoadmapMd(records, issueIdMap, roadmapInput)
Write(`${sessionFolder}/roadmap.md`, roadmapMd)

步骤 3.4:分解质量检查(强制)

创建问题并生成输出文件后,必须在继续之前执行 CLI 质量检查。

质量维度
维度 检查标准 关键?
需求覆盖率 所有原始需求方面都在问题中处理
收敛质量 标准可测试、验证可执行、DoD 业务可读
范围完整性 渐进式:无重叠/间隙;直接式:输入/输出链有效
依赖正确性 无循环依赖、顺序正确、问题依赖匹配
工作量平衡 无单个问题过大
CLI 质量检查
ccw cli -p "
目的:验证路线图分解质量
成功:所有质量维度通过

原始需求:
${requirement}

已创建问题(${selectedMode} 模式):
${issuesJsonlContent}

执行计划:
${JSON.stringify(executionPlan, null, 2)}

任务:
• 需求覆盖率:分解是否处理需求的所有方面?
• 收敛质量:标准可测试吗?验证可执行吗?DoD 业务可读吗?
• 范围完整性:${selectedMode === 'progressive' ? '层间无范围重叠,无功能间隙' : '输入/输出链有效,并行组正确'}
• 依赖正确性:无循环依赖,波次顺序正确
• 工作量平衡:无过大项

模式:analysis
预期:
## 质量检查结果
### 需求覆盖率:通过|失败
[详情]
### 收敛质量:通过|失败
[详情及每记录具体问题]
### 范围完整性:通过|失败
[详情]
### 依赖正确性:通过|失败
[详情]
### 工作量平衡:通过|失败
[详情]

## 推荐:通过|自动修复|需要审查
## 修复(如果自动修复):
[具体修复作为 JSON 补丁]

约束:只读验证,不修改文件
" --tool gemini --mode analysis
自动修复策略
问题类型 自动修复操作
模糊标准 替换为具体、可测试条件
技术 DoD 重写为业务语言
缺失范围项 添加到适当问题上下文
工作量不平衡 建议拆分(报告给用户)

修复后,通过 ccw issue update 更新问题并重新生成 issues.jsonl + roadmap.md


阶段 4:验证与 team-planex 交接

目标:显示分解结果,收集用户反馈,提供 team-planex 执行选项。

// 1. 显示分解结果
const executionPlan = JSON.parse(Read(`${sessionFolder}/execution-plan.json`))
const issueIds = executionPlan.issue_ids
const waves = executionPlan.waves

渐进式模式显示:

## 路线图概览

| 波次 | 问题 ID | 名称 | 目标 | 优先级 |
|------|----------|------|------|----------|
| 1 | ISS-xxx | MVP | ... | 2 |
| 2 | ISS-yyy | 可用 | ... | 3 |

### 收敛标准
**波次 1 - MVP (ISS-xxx)**:
- 标准:[标准列表]
- 验证:[验证]
- 完成定义:[完成定义]

直接式模式显示:

## 任务序列

| 波次 | 问题 ID | 标题 | 类型 | 依赖 |
|------|----------|-------|------|--------------|
| 1 | ISS-xxx | ... | 基础设施 | - |
| 2 | ISS-yyy | ... | 功能 | ISS-xxx |

用户反馈循环(最多 5 轮,AUTO_YES 时跳过)

if (!AUTO_YES) {
  let round = 0
  let continueLoop = true

  while (continueLoop && round < 5) {
    round++
    const feedback = ASK_USER([
      {
        id: "feedback", type: "select",
        prompt: `路线图验证(第 ${round} 轮):
对当前分解有任何反馈吗?`,
        options: [
          { label: "批准", description: "分解合理,进入下一步" },
          { label: "调整范围", description: "某些问题范围需要调整" },
          { label: "修改收敛", description: "收敛标准不够具体或可测试" },
          { label: "重新分解", description: "整体策略或分层方法需要更改" }
        ]
      }
    ])  // 阻塞(等待用户响应)

    if (feedback.feedback === '批准') {
      continueLoop = false
    } else {
      // 基于反馈类型处理调整
      // 调整后,重新显示并返回循环顶部
    }
  }
}

完成选项

if (AUTO_YES) {
  // 自动模式:显示摘要并结束
  console.log(`路线图已生成,${issueIds.length} 个问题已创建。`)
  console.log(`会话:${sessionFolder}`)
} else {
  const nextStep = ASK_USER([
    {
      id: "next", type: "select",
      prompt: `路线图已生成,${issueIds.length} 个问题已创建。下一步:`,
      options: [
        { label: "使用 team-planex 执行",
          description: `启动 team-planex 执行全部 ${issueIds.length} 个问题(${waves.length} 个波次)` },
        { label: "执行第一波",
          description: `仅执行波次 1:${waves[0].label}` },
        { label: "查看问题",
          description: "查看已创建的问题详情" },
        { label: "完成",
          description: "保存路线图,稍后执行" }
      ]
    }
  ])  // 阻塞(等待用户响应)
}
选择 操作
使用 team-planex 执行 $team-planex --plan ${sessionFolder}/execution-plan.json
执行第一波 $team-planex ${waves[0].issue_ids.join(' ')}
查看问题 从 issues.jsonl 显示问题摘要表
完成 显示文件路径,结束

实现草图:编排器内部使用 Skill(skill="team-planex", args="--plan ...") 接口调用, 此为伪代码示意,非命令行语法。


JSONL 模式设计

问题格式(issues.jsonl)

每行遵循标准 issues-jsonl-schema.json(见 .ccw/workflows/cli-templates/schemas/issues-jsonl-schema.json)。

字段 来源 描述
id ccw issue create 正式 ISS-YYYYMMDD-NNN ID
title 层/任务映射 [层名称] 目标[任务类型] 标题
context 收敛字段 Markdown 带目标、范围、收敛标准、验证、DoD
priority 工作量映射 小→4,中→3,大→2
source 固定 "text"
tags 自动生成 ["req-plan", 模式, 名称/类型, "wave-N"]
extended_context.notes 元数据 JSON 会话、策略、original_id、波次、depends_on_issues
lifecycle_requirements 固定 test_strategy、regression_scope、acceptance_type、commit_strategy

执行计划格式(execution-plan.json)

{
  "session_id": "RPLAN-{slug}-{date}",
  "requirement": "原始需求描述",
  "strategy": "progressive|direct",
  "created_at": "ISO 8601",
  "issue_ids": ["ISS-xxx", "ISS-yyy"],
  "waves": [
    {
      "wave": 1,
      "label": "MVP",
      "issue_ids": ["ISS-xxx"],
      "depends_on_waves": []
    },
    {
      "wave": 2,
      "label": "Usable",
      "issue_ids": ["ISS-yyy"],
      "depends_on_waves": [1]
    }
  ],
  "issue_dependencies": {
    "ISS-yyy": ["ISS-xxx"]
  }
}

波次映射

  • 渐进式模式:每层 → 一波(L0→波次 1,L1→波次 2,…)
  • 直接式模式:每并行组 → 一波(组 1→波次 1,组 2→波次 2,…)

会话配置

标志 默认 描述
-y, --yes false 自动确认所有决策
-c, --continue false 继续现有会话
-m, --mode auto 分解策略:渐进式 / 直接式 / 自动式

会话 ID 格式RPLAN-{slug}-{YYYY-MM-DD}

  • slug:小写,字母数字 + CJK 字符,最多 40 字符
  • 日期:YYYY-MM-DD (UTC+8)

错误处理

错误 解决
cli-explore-agent 超时 重试一次,发送输入提示,然后跳过探索
cli-explore-agent 失败 跳过代码探索,继续纯需求分解
无代码库 正常流,跳过阶段 2
CLI 分解失败(Gemini) 备用到 Qwen,然后手动分解
问题创建失败 重试一次,然后跳过并继续其余
检测到循环依赖 提示用户调整依赖,重新分解
用户反馈超时 保存当前状态,显示 --continue 恢复命令
最大反馈轮数达到 使用当前版本生成最终工件
会话文件夹冲突 追加时间戳后缀
质量检查 NEEDS_REVIEW 报告关键问题给用户手动解决

核心规则

  1. 显式生命周期:wait 完成后始终 close_agent 释放资源
  2. 不要停止:连续多阶段工作流。完成每阶段后,立即进入下一阶段
  3. 从不输出模糊收敛:标准必须可测试,验证可执行,DoD 用业务语言
  4. 从不跳过质量检查:步骤 3.4 强制,然后才能进入阶段 4
  5. 始终写入所有三个输出文件:issues.jsonl、execution-plan.json、roadmap.md

最佳实践

  1. 清晰需求描述:详细描述 → 更准确的不确定性评估和分解
  2. 先验证 MVP:渐进式模式中,L0 应是最小可验证闭环
  3. 可测试收敛:标准必须可编写断言或手动步骤;definition_of_done 应非技术利益方可判断
  4. 增量验证:使用 --continue 迭代现有路线图
  5. team-planex 集成:创建的问题遵循标准 issues-jsonl-schema,可直接通过 execution-plan.json 由 $team-planex 消费

使用建议

使用 $workflow-req-plan 时:

  • 需要将大型需求分解为可渐进执行的路线图
  • 不确定从何开始,需要 MVP 策略
  • 需要生成可跟踪任务序列
  • 需求涉及多个阶段或迭代
  • 希望自动问题创建 + team-planex 执行管道

使用 $workflow-lite-plan 时:

  • 有明确的单个任务要执行
  • 需求已经是路线图中的层/任务
  • 不需要分层规划

直接使用 $team-planex 时:

  • 问题已存在(手动或其他工作流创建)
  • 有来自先前 req-plan 会话的 execution-plan.json

现在为执行 req-plan 工作流: $ARGUMENTS