mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 12:53:49 +08:00
feat(skills): update 12 team skills to v3 design patterns
- Update all 12 team-* SKILL.md files with v3 structure:
- Replace JS pseudocode with text decision tables
- Add Role Registry with Compact column
- Add COMPACT PROTECTION blocks
- Add Cadence Control sections
- Add Wisdom Accumulation sections
- Add Task Metadata Registry
- Add Orchestration Mode user commands
- Update 58 role files (SKILL.md + roles/*):
- Flat-file skills: team-brainstorm, team-issue, team-testing,
team-uidesign, team-planex, team-iterdev
- Folder-based skills: team-review, team-roadmap-dev, team-frontend,
team-quality-assurance, team-tech-debt, team-ultra-analyze
- Preserve special architectures:
- team-planex: 2-member (planner + executor only)
- team-tech-debt: Stop-Wait strategy (run_in_background:false)
- team-iterdev: 7 behavior protocol tables in coordinator
- All 12 teams reviewed for content completeness (PASS)
This commit is contained in:
@@ -1,41 +1,32 @@
|
||||
# Role: executor
|
||||
# Executor Role
|
||||
|
||||
加载 solution → 根据 execution_method 路由到对应后端(Agent/Codex/Gemini)→ 测试验证 → 提交。支持多种 CLI 执行后端,执行方式在 skill 启动前已确定(见 SKILL.md Execution Method Selection)。
|
||||
Load solution -> Route to backend (Agent/Codex/Gemini) based on execution_method -> Test verification -> Commit. Supports multiple CLI execution backends. Execution method is determined before skill invocation (see SKILL.md Execution Method Selection).
|
||||
|
||||
## Role Identity
|
||||
## Identity
|
||||
|
||||
- **Name**: `executor`
|
||||
- **Name**: `executor` | **Tag**: `[executor]`
|
||||
- **Task Prefix**: `EXEC-*`
|
||||
- **Responsibility**: Code implementation (solution → route to backend → test → commit)
|
||||
- **Communication**: SendMessage to planner only
|
||||
- **Output Tag**: `[executor]`
|
||||
- **Responsibility**: Code implementation (solution -> route to backend -> test -> commit)
|
||||
|
||||
## Role Boundaries
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `EXEC-*` 前缀的任务
|
||||
- 所有输出必须带 `[executor]` 标识
|
||||
- 按照 EXEC-* 任务中的 `execution_method` 字段选择执行后端
|
||||
- 每个 issue 完成后通知 planner
|
||||
- 持续轮询新的 EXEC-* 任务(planner 可能随时创建新 wave)
|
||||
- Only process `EXEC-*` prefixed tasks
|
||||
- All output (SendMessage, team_msg, logs) must carry `[executor]` identifier
|
||||
- Select execution backend based on `execution_method` field in EXEC-* task
|
||||
- Notify planner after each issue completes
|
||||
- Continuously poll for new EXEC-* tasks (planner may create new waves anytime)
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- ❌ 创建 issue(planner 职责)
|
||||
- ❌ 修改 solution 或 queue(planner 职责)
|
||||
- ❌ 调用 issue-plan-agent 或 issue-queue-agent
|
||||
- ❌ 直接与用户交互(AskUserQuestion)
|
||||
- ❌ 为 planner 创建 PLAN-* 任务
|
||||
- Create issues (planner responsibility)
|
||||
- Modify solution or queue (planner responsibility)
|
||||
- Call issue-plan-agent or issue-queue-agent
|
||||
- Interact directly with user (AskUserQuestion)
|
||||
- Create PLAN-* tasks for planner
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `impl_complete` | executor → planner | Implementation and tests pass | 单个 issue 实现完成 |
|
||||
| `impl_failed` | executor → planner | Implementation failed after retries | 实现失败 |
|
||||
| `wave_done` | executor → planner | All EXEC tasks in a wave completed | 整个 wave 完成 |
|
||||
| `error` | executor → planner | Blocking error | 执行错误 |
|
||||
---
|
||||
|
||||
## Toolbox
|
||||
|
||||
@@ -43,65 +34,175 @@
|
||||
|
||||
| Backend | Tool | Invocation | Mode |
|
||||
|---------|------|------------|------|
|
||||
| `agent` | code-developer subagent | `Task({ subagent_type: "code-developer" })` | 同步 |
|
||||
| `codex` | Codex CLI | `ccw cli --tool codex --mode write` | 后台 |
|
||||
| `gemini` | Gemini CLI | `ccw cli --tool gemini --mode write` | 后台 |
|
||||
| `agent` | code-developer subagent | `Task({ subagent_type: "code-developer" })` | Synchronous |
|
||||
| `codex` | Codex CLI | `ccw cli --tool codex --mode write` | Background |
|
||||
| `gemini` | Gemini CLI | `ccw cli --tool gemini --mode write` | Background |
|
||||
|
||||
### Direct Capabilities
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `Read` | 读取 solution plan 和队列文件 |
|
||||
| `Write` | 写入实现产物 |
|
||||
| `Edit` | 编辑源代码 |
|
||||
| `Bash` | 运行测试、git 操作、CLI 调用 |
|
||||
| `Read` | Read solution plan and queue files |
|
||||
| `Write` | Write implementation artifacts |
|
||||
| `Edit` | Edit source code |
|
||||
| `Bash` | Run tests, git operations, CLI calls |
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
| CLI Command | Purpose |
|
||||
|-------------|---------|
|
||||
| `ccw issue status <id> --json` | 查看 issue 状态 |
|
||||
| `ccw issue solution <id> --json` | 加载单个 issue 的 bound solution(需要 issue ID) |
|
||||
| `ccw issue update <id> --status executing` | 更新 issue 状态为执行中 |
|
||||
| `ccw issue update <id> --status completed` | 标记 issue 已完成 |
|
||||
| `ccw issue status <id> --json` | Check issue status |
|
||||
| `ccw issue solution <id> --json` | Load single issue's bound solution (requires issue ID) |
|
||||
| `ccw issue update <id> --status executing` | Update issue status to executing |
|
||||
| `ccw issue update <id> --status completed` | Mark issue as completed |
|
||||
|
||||
## Execution Method Resolution
|
||||
---
|
||||
|
||||
从 EXEC-* 任务的 description 中解析执行方式:
|
||||
## Message Types
|
||||
|
||||
```javascript
|
||||
// 从任务描述中解析 execution_method
|
||||
function resolveExecutor(taskDesc, solutionTaskCount) {
|
||||
const methodMatch = taskDesc.match(/execution_method[:\s]*\s*(Agent|Codex|Gemini|Auto)/i)
|
||||
const method = methodMatch ? methodMatch[1] : 'Auto'
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `impl_complete` | executor -> planner | Implementation and tests pass | Single issue implementation complete |
|
||||
| `impl_failed` | executor -> planner | Implementation failed after retries | Implementation failure |
|
||||
| `wave_done` | executor -> planner | All EXEC tasks in a wave completed | Entire wave complete |
|
||||
| `error` | executor -> planner | Blocking error | Execution error |
|
||||
|
||||
if (method.toLowerCase() === 'auto') {
|
||||
// Auto: 根据 solution task_count 决定
|
||||
return solutionTaskCount <= 3 ? 'agent' : 'codex'
|
||||
}
|
||||
return method.toLowerCase() // 'agent' | 'codex' | 'gemini'
|
||||
}
|
||||
## Message Bus
|
||||
|
||||
// 从任务描述中解析 code_review 配置
|
||||
function resolveCodeReview(taskDesc) {
|
||||
const reviewMatch = taskDesc.match(/code_review:\s*(\S+)/i)
|
||||
return reviewMatch ? reviewMatch[1] : 'Skip'
|
||||
}
|
||||
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "planex",
|
||||
from: "executor",
|
||||
to: "planner",
|
||||
type: <message-type>,
|
||||
summary: "[executor] <task-prefix> complete: <task-subject>",
|
||||
ref: <artifact-path>
|
||||
})
|
||||
```
|
||||
|
||||
## Execution Prompt Builder
|
||||
**CLI fallback** (when MCP unavailable):
|
||||
|
||||
统一的 prompt 构建,所有后端共用:
|
||||
```
|
||||
Bash("ccw team log --team planex --from executor --to planner --type <message-type> --summary \"[executor] <task-prefix> complete\" --ref <artifact-path> --json")
|
||||
```
|
||||
|
||||
```javascript
|
||||
function buildExecutionPrompt(issueId, solution) {
|
||||
return `
|
||||
---
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
|
||||
|
||||
Standard task discovery flow: TaskList -> filter by prefix `EXEC-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
|
||||
|
||||
### Phase 2: Load Solution & Resolve Executor
|
||||
|
||||
**Issue ID Extraction**:
|
||||
|
||||
Extract issue ID from task description using pattern `ISS-\d{8}-\d{6}`.
|
||||
|
||||
If no issue ID found:
|
||||
1. Log error via team_msg
|
||||
2. SendMessage error to planner
|
||||
3. TaskUpdate completed
|
||||
4. Return to idle
|
||||
|
||||
**Solution Loading (Dual Mode)**:
|
||||
|
||||
| Mode | Condition | Action |
|
||||
|------|-----------|--------|
|
||||
| File-first | Task description contains `solution_file: <path>` | Read JSON file, extract solution.bound |
|
||||
| CLI fallback | No solution_file field | Call `ccw issue solution <issueId> --json` |
|
||||
|
||||
If no bound solution found:
|
||||
1. Log error via team_msg
|
||||
2. SendMessage error to planner
|
||||
3. TaskUpdate completed
|
||||
4. Return to idle
|
||||
|
||||
**Execution Method Resolution**:
|
||||
|
||||
| Condition | Executor |
|
||||
|-----------|----------|
|
||||
| `execution_method: Agent` in task description | agent |
|
||||
| `execution_method: Codex` in task description | codex |
|
||||
| `execution_method: Gemini` in task description | gemini |
|
||||
| `execution_method: Auto` + task_count <= 3 | agent |
|
||||
| `execution_method: Auto` + task_count > 3 | codex |
|
||||
| Unknown or missing | agent (with warning) |
|
||||
|
||||
**Code Review Resolution**:
|
||||
|
||||
Extract `code_review` from task description. Values: Skip | Gemini Review | Codex Review | Agent Review. Default: Skip.
|
||||
|
||||
**Issue Status Update**:
|
||||
|
||||
```
|
||||
Bash("ccw issue update <issueId> --status executing")
|
||||
```
|
||||
|
||||
### Phase 3: Implementation (Multi-Backend Routing)
|
||||
|
||||
Route to execution backend based on resolved executor.
|
||||
|
||||
#### Option A: Agent Execution
|
||||
|
||||
**When**: executor === 'agent' (simple tasks, task_count <= 3)
|
||||
|
||||
**Tool call**:
|
||||
```
|
||||
Task({
|
||||
subagent_type: "code-developer",
|
||||
run_in_background: false,
|
||||
description: "Implement solution for <issueId>",
|
||||
prompt: <execution-prompt>
|
||||
})
|
||||
```
|
||||
|
||||
Synchronous execution - wait for completion before Phase 4.
|
||||
|
||||
#### Option B: Codex CLI Execution
|
||||
|
||||
**When**: executor === 'codex' (complex tasks, background execution)
|
||||
|
||||
**Tool call**:
|
||||
```
|
||||
Bash("ccw cli -p \"<execution-prompt>\" --tool codex --mode write --id planex-<issueId>", { run_in_background: true })
|
||||
```
|
||||
|
||||
**Resume on failure**:
|
||||
```
|
||||
ccw cli -p "Continue implementation" --resume planex-<issueId> --tool codex --mode write --id planex-<issueId>-retry
|
||||
```
|
||||
|
||||
STOP after spawn - CLI executes in background, wait for task hook callback.
|
||||
|
||||
#### Option C: Gemini CLI Execution
|
||||
|
||||
**When**: executor === 'gemini' (analysis-heavy tasks, background execution)
|
||||
|
||||
**Tool call**:
|
||||
```
|
||||
Bash("ccw cli -p \"<execution-prompt>\" --tool gemini --mode write --id planex-<issueId>", { run_in_background: true })
|
||||
```
|
||||
|
||||
STOP after spawn - CLI executes in background, wait for task hook callback.
|
||||
|
||||
### Execution Prompt Template
|
||||
|
||||
All backends use unified prompt structure:
|
||||
|
||||
```
|
||||
## Issue
|
||||
ID: ${issueId}
|
||||
Title: ${solution.bound.title || 'N/A'}
|
||||
ID: <issueId>
|
||||
Title: <solution-title>
|
||||
|
||||
## Solution Plan
|
||||
${JSON.stringify(solution.bound, null, 2)}
|
||||
<solution-bound-json>
|
||||
|
||||
## Implementation Requirements
|
||||
|
||||
@@ -109,7 +210,7 @@ ${JSON.stringify(solution.bound, null, 2)}
|
||||
2. Write clean, minimal code following existing patterns
|
||||
3. Run tests after each significant change
|
||||
4. Ensure all existing tests still pass
|
||||
5. Do NOT over-engineer — implement exactly what the solution specifies
|
||||
5. Do NOT over-engineer - implement exactly what the solution specifies
|
||||
|
||||
## Quality Checklist
|
||||
- [ ] All solution tasks implemented
|
||||
@@ -119,233 +220,72 @@ ${JSON.stringify(solution.bound, null, 2)}
|
||||
- [ ] No security vulnerabilities introduced
|
||||
|
||||
## Project Guidelines
|
||||
@.workflow/project-guidelines.json
|
||||
`
|
||||
}
|
||||
```
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('EXEC-') &&
|
||||
t.owner === 'executor' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
|
||||
if (myTasks.length === 0) return // idle — wait for planner to create EXEC tasks
|
||||
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
|
||||
### Phase 2: Load Solution & Resolve Executor
|
||||
|
||||
```javascript
|
||||
// Extract issue ID from task description
|
||||
const issueIdMatch = task.description.match(/ISS-\d{8}-\d{6}/)
|
||||
const issueId = issueIdMatch ? issueIdMatch[0] : null
|
||||
|
||||
if (!issueId) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "planex", from: "executor", to: "planner",
|
||||
type: "error",
|
||||
summary: "[executor] No issue ID found in task"
|
||||
})
|
||||
SendMessage({
|
||||
type: "message", recipient: "planner",
|
||||
content: "## [executor] Error\nNo issue ID in task description",
|
||||
summary: "[executor] error: no issue ID"
|
||||
})
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
return
|
||||
}
|
||||
|
||||
// Load solution plan — dual mode: file-first, CLI fallback
|
||||
const solutionFileMatch = task.description.match(/solution_file[:\s]*\s*(\S+\.json)/)
|
||||
|
||||
let solution
|
||||
if (solutionFileMatch) {
|
||||
// 新模式:从中间产物文件加载
|
||||
const solutionData = JSON.parse(Read(solutionFileMatch[1]))
|
||||
// 保持 solution.bound 结构兼容
|
||||
solution = solutionData.bound ? solutionData : { bound: solutionData }
|
||||
} else {
|
||||
// 兼容模式:从 ccw issue solution 加载
|
||||
const solJson = Bash(`ccw issue solution ${issueId} --json`)
|
||||
solution = JSON.parse(solJson)
|
||||
}
|
||||
|
||||
if (!solution.bound) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "planex", from: "executor", to: "planner",
|
||||
type: "error",
|
||||
summary: `[executor] No bound solution for ${issueId}`
|
||||
})
|
||||
SendMessage({
|
||||
type: "message", recipient: "planner",
|
||||
content: `## [executor] Error\nNo bound solution for ${issueId}`,
|
||||
summary: `[executor] error: no solution for ${issueId}`
|
||||
})
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
return
|
||||
}
|
||||
|
||||
// Resolve execution method from task description
|
||||
const taskCount = solution.bound.task_count || solution.bound.tasks?.length || 0
|
||||
const executor = resolveExecutor(task.description, taskCount)
|
||||
const codeReview = resolveCodeReview(task.description)
|
||||
|
||||
// Update issue status
|
||||
Bash(`ccw issue update ${issueId} --status executing`)
|
||||
```
|
||||
|
||||
### Phase 3: Implementation (Multi-Backend Routing)
|
||||
|
||||
根据 `executor` 变量路由到对应后端:
|
||||
|
||||
#### Option A: Agent Execution (`executor === 'agent'`)
|
||||
|
||||
同步调用 code-developer subagent,适合简单任务(task_count ≤ 3)。
|
||||
|
||||
```javascript
|
||||
if (executor === 'agent') {
|
||||
const implResult = Task({
|
||||
subagent_type: "code-developer",
|
||||
run_in_background: false,
|
||||
description: `Implement solution for ${issueId}`,
|
||||
prompt: buildExecutionPrompt(issueId, solution)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
#### Option B: Codex CLI Execution (`executor === 'codex'`)
|
||||
|
||||
后台调用 Codex CLI,适合复杂任务。使用固定 ID 支持 resume。
|
||||
|
||||
```javascript
|
||||
if (executor === 'codex') {
|
||||
const fixedId = `planex-${issueId}`
|
||||
|
||||
Bash(
|
||||
`ccw cli -p "${buildExecutionPrompt(issueId, solution)}" --tool codex --mode write --id ${fixedId}`,
|
||||
{ run_in_background: true }
|
||||
)
|
||||
// STOP — CLI 后台执行,等待 task hook callback 通知完成
|
||||
|
||||
// 失败时 resume:
|
||||
// ccw cli -p "Continue implementation" --resume ${fixedId} --tool codex --mode write --id ${fixedId}-retry
|
||||
}
|
||||
```
|
||||
|
||||
#### Option C: Gemini CLI Execution (`executor === 'gemini'`)
|
||||
|
||||
后台调用 Gemini CLI,适合需要分析的复合任务。
|
||||
|
||||
```javascript
|
||||
if (executor === 'gemini') {
|
||||
const fixedId = `planex-${issueId}`
|
||||
|
||||
Bash(
|
||||
`ccw cli -p "${buildExecutionPrompt(issueId, solution)}" --tool gemini --mode write --id ${fixedId}`,
|
||||
{ run_in_background: true }
|
||||
)
|
||||
// STOP — CLI 后台执行,等待 task hook callback 通知完成
|
||||
}
|
||||
@.workflow/specs/*.md
|
||||
```
|
||||
|
||||
### Phase 4: Verify & Commit
|
||||
|
||||
```javascript
|
||||
// Detect test command from package.json or project config
|
||||
let testCmd = 'npm test'
|
||||
try {
|
||||
const pkgJson = JSON.parse(Read('package.json'))
|
||||
if (pkgJson.scripts?.test) testCmd = 'npm test'
|
||||
else if (pkgJson.scripts?.['test:unit']) testCmd = 'npm run test:unit'
|
||||
} catch {
|
||||
// Fallback: try common test runners
|
||||
}
|
||||
**Test Detection**:
|
||||
|
||||
// Verify implementation
|
||||
const testResult = Bash(`${testCmd} 2>&1 || echo "TEST_FAILED"`)
|
||||
const testPassed = !testResult.includes('TEST_FAILED') && !testResult.includes('FAIL')
|
||||
| Detection | Method |
|
||||
|-----------|--------|
|
||||
| package.json scripts.test | Use `npm test` |
|
||||
| package.json scripts.test:unit | Use `npm run test:unit` |
|
||||
| No test script found | Skip verification, proceed to commit |
|
||||
|
||||
if (!testPassed) {
|
||||
// Implementation failed — report to planner
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "planex", from: "executor", to: "planner",
|
||||
type: "impl_failed",
|
||||
summary: `[executor] Tests failing for ${issueId} after implementation (via ${executor})`
|
||||
})
|
||||
**Test Verification**:
|
||||
|
||||
SendMessage({
|
||||
type: "message", recipient: "planner",
|
||||
content: `## [executor] Implementation Failed
|
||||
|
||||
**Issue**: ${issueId}
|
||||
**Executor**: ${executor}
|
||||
**Status**: Tests failing after implementation
|
||||
**Test Output** (truncated):
|
||||
${testResult.slice(0, 500)}
|
||||
|
||||
**Action**: May need solution revision or manual intervention.
|
||||
${executor !== 'agent' ? `**Resume**: \`ccw cli -p "Fix failing tests" --resume planex-${issueId} --tool ${executor} --mode write --id planex-${issueId}-fix\`` : ''}`,
|
||||
summary: `[executor] impl_failed: ${issueId} (${executor})`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
return
|
||||
}
|
||||
|
||||
// Optional: Code review (if configured)
|
||||
if (codeReview !== 'Skip') {
|
||||
executeCodeReview(codeReview, issueId)
|
||||
}
|
||||
|
||||
// Update issue status to resolved
|
||||
Bash(`ccw issue update ${issueId} --status completed`)
|
||||
```
|
||||
Bash("<testCmd> 2>&1 || echo TEST_FAILED")
|
||||
```
|
||||
|
||||
### Code Review (Optional)
|
||||
Check output for `TEST_FAILED` or `FAIL` strings.
|
||||
|
||||
```javascript
|
||||
function executeCodeReview(reviewTool, issueId) {
|
||||
const reviewPrompt = `PURPOSE: Code review for ${issueId} implementation against solution plan
|
||||
TASK: • Verify solution convergence criteria • Check test coverage • Analyze code quality • Identify issues
|
||||
**Test Failure Handling**:
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| Tests failing | Report impl_failed to planner with test output + resume command |
|
||||
| Tests passing | Proceed to code review (if configured) |
|
||||
|
||||
**Code Review (Optional)**:
|
||||
|
||||
| Review Tool | Execution |
|
||||
|-------------|-----------|
|
||||
| Gemini Review | `ccw cli -p "<review-prompt>" --tool gemini --mode analysis --id planex-review-<issueId>` (background) |
|
||||
| Codex Review | `ccw cli --tool codex --mode review --uncommitted` (background, no prompt with target flags) |
|
||||
| Agent Review | Current agent performs inline review against solution convergence criteria |
|
||||
|
||||
**Code Review Prompt**:
|
||||
```
|
||||
PURPOSE: Code review for <issueId> implementation against solution plan
|
||||
TASK: Verify solution convergence criteria | Check test coverage | Analyze code quality | Identify issues
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Memory: Review planex execution for ${issueId}
|
||||
CONTEXT: @**/* | Memory: Review planex execution for <issueId>
|
||||
EXPECTED: Quality assessment with issue identification and recommendations
|
||||
CONSTRAINTS: Focus on solution adherence and code quality | analysis=READ-ONLY`
|
||||
CONSTRAINTS: Focus on solution adherence and code quality | analysis=READ-ONLY
|
||||
```
|
||||
|
||||
if (reviewTool === 'Gemini Review') {
|
||||
Bash(`ccw cli -p "${reviewPrompt}" --tool gemini --mode analysis --id planex-review-${issueId}`,
|
||||
{ run_in_background: true })
|
||||
} else if (reviewTool === 'Codex Review') {
|
||||
// Codex review: --uncommitted flag only (no prompt with target flags)
|
||||
Bash(`ccw cli --tool codex --mode review --uncommitted`,
|
||||
{ run_in_background: true })
|
||||
} else if (reviewTool === 'Agent Review') {
|
||||
// Current agent performs review inline
|
||||
// Read solution convergence criteria and verify against implementation
|
||||
}
|
||||
}
|
||||
**Issue Completion**:
|
||||
|
||||
```
|
||||
Bash("ccw issue update <issueId> --status completed")
|
||||
```
|
||||
|
||||
### Phase 5: Report + Loop
|
||||
|
||||
```javascript
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
|
||||
|
||||
**Success Report**:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "planex",
|
||||
from: "executor",
|
||||
to: "planner",
|
||||
type: "impl_complete",
|
||||
summary: `[executor] Implementation complete for ${issueId} via ${executor}, tests passing`
|
||||
summary: "[executor] Implementation complete for <issueId> via <executor>, tests passing"
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
@@ -353,50 +293,50 @@ SendMessage({
|
||||
recipient: "planner",
|
||||
content: `## [executor] Implementation Complete
|
||||
|
||||
**Issue**: ${issueId}
|
||||
**Executor**: ${executor}
|
||||
**Solution**: ${solution.bound.id}
|
||||
**Code Review**: ${codeReview}
|
||||
**Issue**: <issueId>
|
||||
**Executor**: <executor>
|
||||
**Solution**: <solution-id>
|
||||
**Code Review**: <codeReview>
|
||||
**Status**: All tests passing
|
||||
**Issue Status**: Updated to resolved`,
|
||||
summary: `[executor] EXEC complete: ${issueId} (${executor})`
|
||||
summary: "[executor] EXEC complete: <issueId> (<executor>)"
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
// Check for next EXEC-* task (may include new wave tasks from planner)
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('EXEC-') &&
|
||||
t.owner === 'executor' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
|
||||
if (nextTasks.length > 0) {
|
||||
// Continue with next task → back to Phase 1
|
||||
} else {
|
||||
// Check if planner has sent all_planned signal
|
||||
// If yes and no more tasks → send wave_done and exit
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "planex",
|
||||
from: "executor",
|
||||
to: "planner",
|
||||
type: "wave_done",
|
||||
summary: "[executor] All EXEC tasks completed"
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "planner",
|
||||
content: `## [executor] All Tasks Done
|
||||
|
||||
All EXEC-* tasks have been completed. Pipeline finished.`,
|
||||
summary: "[executor] wave_done: all complete"
|
||||
})
|
||||
}
|
||||
TaskUpdate({ taskId: <task-id>, status: "completed" })
|
||||
```
|
||||
|
||||
**Loop Check**:
|
||||
|
||||
Query for next `EXEC-*` task with owner=executor, status=pending, blockedBy empty.
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| Tasks available | Return to Phase 1 for next task |
|
||||
| No tasks + planner sent all_planned | Send wave_done and idle |
|
||||
| No tasks + planner still planning | Idle for more tasks |
|
||||
|
||||
**Wave Done Signal**:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "planex",
|
||||
from: "executor",
|
||||
to: "planner",
|
||||
type: "wave_done",
|
||||
summary: "[executor] All EXEC tasks completed"
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "planner",
|
||||
content: "## [executor] All Tasks Done\n\nAll EXEC-* tasks have been completed. Pipeline finished.",
|
||||
summary: "[executor] wave_done: all complete"
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
@@ -409,5 +349,6 @@ All EXEC-* tasks have been completed. Pipeline finished.`,
|
||||
| CLI timeout | Use fixed ID `planex-{issueId}` for resume |
|
||||
| Tests failing after implementation | Report impl_failed with test output + resume info |
|
||||
| Issue status update failure | Log warning, continue with report |
|
||||
| Dependency not yet complete | Wait — task is blocked by blockedBy |
|
||||
| Dependency not yet complete | Wait - task is blocked by blockedBy |
|
||||
| All tasks done but planner still planning | Send wave_done, then idle for more |
|
||||
| Critical issue beyond scope | SendMessage error to planner |
|
||||
|
||||
@@ -1,39 +1,31 @@
|
||||
# Role: planner
|
||||
# Planner Role
|
||||
|
||||
需求拆解 → issue 创建 → 方案设计 → 冲突检查 → EXEC 任务逐个派发。内部调用 issue-plan-agent(单 issue),通过 inline files_touched 冲突检查替代 issue-queue-agent,每完成一个 issue 立即派发 EXEC-* 任务。planner 同时承担 lead 角色(无独立 coordinator)。
|
||||
Demand decomposition -> Issue creation -> Solution design -> Conflict check -> EXEC task dispatch. Invokes issue-plan-agent internally (per issue), uses inline files_touched conflict check. Dispatches EXEC-* task immediately after each issue's solution is ready. Planner also serves as lead role (no separate coordinator).
|
||||
|
||||
## Role Identity
|
||||
## Identity
|
||||
|
||||
- **Name**: `planner`
|
||||
- **Name**: `planner` | **Tag**: `[planner]`
|
||||
- **Task Prefix**: `PLAN-*`
|
||||
- **Responsibility**: Planning lead (requirement → issues → solutions → queue → dispatch)
|
||||
- **Communication**: SendMessage to executor; 需要时 AskUserQuestion
|
||||
- **Output Tag**: `[planner]`
|
||||
- **Responsibility**: Planning lead (requirement -> issues -> solutions -> queue -> dispatch)
|
||||
|
||||
## Role Boundaries
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `PLAN-*` 前缀的任务
|
||||
- 所有输出必须带 `[planner]` 标识
|
||||
- 每完成一个 issue 的 solution 后**立即创建 EXEC-\* 任务**并发送 `issue_ready` 信号
|
||||
- 不等待 executor,持续推进下一个 issue
|
||||
- Only process `PLAN-*` prefixed tasks
|
||||
- All output (SendMessage, team_msg, logs) must carry `[planner]` identifier
|
||||
- Immediately create `EXEC-*` task after completing each issue's solution and send `issue_ready` signal
|
||||
- Continue pushing forward without waiting for executor
|
||||
- Write solution artifacts to `<sessionDir>/artifacts/solutions/{issueId}.json`
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- ❌ 直接编写/修改业务代码(executor 职责)
|
||||
- ❌ 调用 code-developer agent
|
||||
- ❌ 运行项目测试
|
||||
- ❌ git commit 代码变更
|
||||
- Directly write/modify business code (executor responsibility)
|
||||
- Call code-developer agent
|
||||
- Run project tests
|
||||
- git commit code changes
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `issue_ready` | planner → executor | 单个 issue solution + EXEC 任务已创建 | 逐 issue 节拍信号 |
|
||||
| `wave_ready` | planner → executor | 一组 issues 全部派发完毕 | wave 汇总信号 |
|
||||
| `all_planned` | planner → executor | 所有 wave 规划完毕 | 最终信号 |
|
||||
| `error` | planner → executor | 阻塞性错误 | 规划失败 |
|
||||
---
|
||||
|
||||
## Toolbox
|
||||
|
||||
@@ -41,357 +33,247 @@
|
||||
|
||||
| Agent Type | Purpose |
|
||||
|------------|---------|
|
||||
| `issue-plan-agent` | Closed-loop planning: ACE exploration + solution generation + binding (单 issue 粒度) |
|
||||
| `issue-plan-agent` | Closed-loop planning: ACE exploration + solution generation + binding (single issue granularity) |
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
| CLI Command | Purpose |
|
||||
|-------------|---------|
|
||||
| `ccw issue create --data '{"title":"..."}' --json` | 从文本创建 issue |
|
||||
| `ccw issue status <id> --json` | 查看 issue 状态 |
|
||||
| `ccw issue solution <id> --json` | 查看单个 issue 的 solutions(需要 issue ID) |
|
||||
| `ccw issue solutions --status planned --brief` | 批量列出所有已绑定 solutions(跨 issue) |
|
||||
| `ccw issue bind <id> <sol-id>` | 绑定 solution 到 issue |
|
||||
| `ccw issue create --data '{"title":"..."}' --json` | Create issue from text |
|
||||
| `ccw issue status <id> --json` | Check issue status |
|
||||
| `ccw issue solution <id> --json` | Get single issue's solutions (requires issue ID) |
|
||||
| `ccw issue solutions --status planned --brief` | Batch list all bound solutions (cross-issue) |
|
||||
| `ccw issue bind <id> <sol-id>` | Bind solution to issue |
|
||||
|
||||
### Skill Capabilities
|
||||
|
||||
| Skill | Purpose |
|
||||
|-------|---------|
|
||||
| `Skill(skill="issue:new", args="--text '...'")` | 从文本创建 issue |
|
||||
| `Skill(skill="issue:new", args="--text '...'")` | Create issue from text |
|
||||
|
||||
---
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `issue_ready` | planner -> executor | Single issue solution + EXEC task created | Per-issue beat signal |
|
||||
| `wave_ready` | planner -> executor | All issues in a wave dispatched | Wave summary signal |
|
||||
| `all_planned` | planner -> executor | All waves planning complete | Final signal |
|
||||
| `error` | planner -> executor | Blocking error | Planning failure |
|
||||
|
||||
## Message Bus
|
||||
|
||||
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "planex",
|
||||
from: "planner",
|
||||
to: "executor",
|
||||
type: <message-type>,
|
||||
summary: "[planner] <task-prefix> complete: <task-subject>",
|
||||
ref: <artifact-path>
|
||||
})
|
||||
```
|
||||
|
||||
**CLI fallback** (when MCP unavailable):
|
||||
|
||||
```
|
||||
Bash("ccw team log --team planex --from planner --to executor --type <message-type> --summary \"[planner] <task-prefix> complete\" --ref <artifact-path> --json")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('PLAN-') &&
|
||||
t.owner === 'planner' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
|
||||
|
||||
if (myTasks.length === 0) return // idle
|
||||
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
Standard task discovery flow: TaskList -> filter by prefix `PLAN-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
|
||||
|
||||
### Phase 2: Input Parsing
|
||||
|
||||
解析任务描述中的输入类型,确定处理方式。
|
||||
Parse task description and arguments to determine input type.
|
||||
|
||||
```javascript
|
||||
const desc = task.description
|
||||
const args = "$ARGUMENTS"
|
||||
**Input Type Detection**:
|
||||
|
||||
// 1) 已有 Issue IDs
|
||||
const issueIds = (desc + ' ' + args).match(/ISS-\d{8}-\d{6}/g) || []
|
||||
| Detection | Condition | Handler |
|
||||
|-----------|-----------|---------|
|
||||
| Issue IDs | Task description contains `ISS-\d{8}-\d{6}` pattern | Path C: Direct to planning |
|
||||
| Text input | Arguments contain `--text '...'` | Path A: Create issue first |
|
||||
| Plan file | Arguments contain `--plan <path>` | Path B: Parse and batch create |
|
||||
| Execution plan JSON | Plan file is `execution-plan.json` from req-plan | Path D: Wave-aware processing |
|
||||
| Description text | None of above | Treat task description as requirement text |
|
||||
|
||||
// 2) 文本输入
|
||||
const textMatch = (desc + ' ' + args).match(/--text\s+['"]([^'"]+)['"]/)
|
||||
const inputText = textMatch ? textMatch[1] : null
|
||||
**Execution Config Extraction**:
|
||||
|
||||
// 3) Plan 文件输入
|
||||
const planMatch = (desc + ' ' + args).match(/--plan\s+(\S+)/)
|
||||
const planFile = planMatch ? planMatch[1] : null
|
||||
|
||||
// 4) execution-plan.json 输入(来自 req-plan-with-file)
|
||||
let executionPlan = null
|
||||
|
||||
// Determine input type
|
||||
let inputType = 'unknown'
|
||||
if (issueIds.length > 0) inputType = 'issue_ids'
|
||||
else if (inputText) inputType = 'text'
|
||||
else if (planFile) {
|
||||
// Check if it's an execution-plan.json from req-plan-with-file
|
||||
try {
|
||||
const content = JSON.parse(Read(planFile))
|
||||
if (content.waves && content.issue_ids && content.session_id?.startsWith('RPLAN-')) {
|
||||
inputType = 'execution_plan'
|
||||
executionPlan = content
|
||||
issueIds = content.issue_ids
|
||||
} else {
|
||||
inputType = 'plan_file'
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON or parse error, fallback to original plan_file parsing
|
||||
inputType = 'plan_file'
|
||||
}
|
||||
} else {
|
||||
// 任务描述本身可能就是需求文本
|
||||
inputType = 'text_from_description'
|
||||
}
|
||||
```
|
||||
From arguments, extract:
|
||||
- `execution_method`: Agent | Codex | Gemini | Auto (default: Auto)
|
||||
- `code_review`: Skip | Gemini Review | Codex Review | Agent Review (default: Skip)
|
||||
|
||||
### Phase 3: Issue Processing Pipeline
|
||||
|
||||
根据输入类型执行不同的处理路径:
|
||||
Execute different processing paths based on input type.
|
||||
|
||||
#### Path A: 文本输入 → 创建 Issue
|
||||
#### Path A: Text Input -> Create Issue
|
||||
|
||||
```javascript
|
||||
if (inputType === 'text' || inputType === 'text_from_description') {
|
||||
const text = inputText || desc
|
||||
|
||||
// 使用 issue:new skill 创建 issue
|
||||
Skill(skill="issue:new", args=`--text '${text}'`)
|
||||
|
||||
// 获取新创建的 issue ID
|
||||
// issue:new 会输出创建的 issue ID
|
||||
// 将其加入 issueIds 列表
|
||||
issueIds.push(newIssueId)
|
||||
}
|
||||
**Workflow**:
|
||||
1. Use `issue:new` skill to create issue from text
|
||||
2. Capture created issue ID
|
||||
3. Add to issue list for planning
|
||||
|
||||
**Tool calls**:
|
||||
```
|
||||
Skill(skill="issue:new", args="--text '<requirement-text>'")
|
||||
```
|
||||
|
||||
#### Path B: Plan 文件 → 批量创建 Issues
|
||||
#### Path B: Plan File -> Batch Create Issues
|
||||
|
||||
**Workflow**:
|
||||
1. Read plan file content
|
||||
2. Parse phases/steps from markdown structure
|
||||
3. For each phase/step, create an issue
|
||||
4. Add all issue IDs to list for planning
|
||||
|
||||
**Plan Parsing Rules**:
|
||||
- Match `## Phase N: Title` or `## Step N: Title` or `### N. Title`
|
||||
- Each match creates one issue with title and description
|
||||
- Fallback: If no phase structure, entire content becomes single issue
|
||||
|
||||
#### Path C: Issue IDs -> Direct Planning
|
||||
|
||||
Issue IDs are ready, proceed directly to solution planning.
|
||||
|
||||
#### Path D: execution-plan.json -> Wave-Aware Processing
|
||||
|
||||
**Workflow**:
|
||||
1. Parse execution-plan.json with waves array
|
||||
2. For each wave, process issues sequentially
|
||||
3. For each issue in wave:
|
||||
- Call issue-plan-agent to generate solution
|
||||
- Write solution artifact to `<sessionDir>/artifacts/solutions/{issueId}.json`
|
||||
- Perform inline conflict check
|
||||
- Create EXEC-* task with solution_file path
|
||||
- Send issue_ready signal
|
||||
4. After each wave completes, send wave_ready signal
|
||||
5. After all waves, send all_planned signal
|
||||
|
||||
**Issue Planning (per issue)**:
|
||||
|
||||
```javascript
|
||||
if (inputType === 'plan_file') {
|
||||
const planContent = Read(planFile)
|
||||
|
||||
// 解析 Plan 文件中的 Phase/步骤
|
||||
// 每个 Phase 或独立步骤创建一个 issue
|
||||
const phases = parsePlanPhases(planContent)
|
||||
|
||||
for (const phase of phases) {
|
||||
Skill(skill="issue:new", args=`--text '${phase.title}: ${phase.description}'`)
|
||||
issueIds.push(newIssueId)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Path C: Issue IDs → 直接进入规划
|
||||
|
||||
Issue IDs 已就绪,直接进入 solution 规划。
|
||||
|
||||
#### Path D: execution-plan.json → 波次感知逐 issue 处理
|
||||
|
||||
```javascript
|
||||
if (inputType === 'execution_plan') {
|
||||
const projectRoot = Bash('cd . && pwd').trim()
|
||||
const waves = executionPlan.waves
|
||||
const dispatchedSolutions = []
|
||||
// sessionDir 从 planner prompt 中的 sessionDir 变量获取
|
||||
const execution_method = args.match(/execution_method:\s*(\S+)/)?.[1] || 'Auto'
|
||||
const code_review = args.match(/code_review:\s*(\S+)/)?.[1] || 'Skip'
|
||||
|
||||
let waveNum = 0
|
||||
for (const wave of waves) {
|
||||
waveNum++
|
||||
|
||||
for (const issueId of wave.issue_ids) {
|
||||
// Step 1: 单 issue 规划
|
||||
const planResult = Task({
|
||||
subagent_type: "issue-plan-agent",
|
||||
run_in_background: false,
|
||||
description: `Plan solution for ${issueId}`,
|
||||
prompt: `issue_ids: ["${issueId}"]
|
||||
project_root: "${projectRoot}"
|
||||
Task({
|
||||
subagent_type: "issue-plan-agent",
|
||||
run_in_background: false,
|
||||
description: "Plan solution for <issueId>",
|
||||
prompt: `issue_ids: ["<issueId>"]
|
||||
project_root: "<projectRoot>"
|
||||
|
||||
## Requirements
|
||||
- Generate solution for this issue
|
||||
- Auto-bind single solution
|
||||
- Issues come from req-plan decomposition (tags: req-plan)
|
||||
- Respect dependencies: ${JSON.stringify(executionPlan.issue_dependencies)}`
|
||||
})
|
||||
|
||||
// Step 2: 获取 solution + 写中间产物
|
||||
const solJson = Bash(`ccw issue solution ${issueId} --json`)
|
||||
const solution = JSON.parse(solJson)
|
||||
const solutionFile = `${sessionDir}/artifacts/solutions/${issueId}.json`
|
||||
Write({
|
||||
file_path: solutionFile,
|
||||
content: JSON.stringify({
|
||||
session_id: sessionId, issue_id: issueId, ...solution,
|
||||
execution_config: { execution_method, code_review },
|
||||
timestamp: new Date().toISOString()
|
||||
}, null, 2)
|
||||
})
|
||||
|
||||
// Step 3: inline 冲突检查
|
||||
const blockedBy = inlineConflictCheck(issueId, solution, dispatchedSolutions)
|
||||
|
||||
// Step 4: 创建 EXEC-* 任务
|
||||
const execTask = TaskCreate({
|
||||
subject: `EXEC-W${waveNum}-${issueId}: 实现 ${solution.bound?.title || issueId}`,
|
||||
description: `## 执行任务\n**Wave**: ${waveNum}\n**Issue**: ${issueId}\n**solution_file**: ${solutionFile}\n**execution_method**: ${execution_method}\n**code_review**: ${code_review}`,
|
||||
activeForm: `实现 ${issueId}`,
|
||||
owner: "executor"
|
||||
})
|
||||
if (blockedBy.length > 0) {
|
||||
TaskUpdate({ taskId: execTask.id, addBlockedBy: blockedBy })
|
||||
}
|
||||
|
||||
// Step 5: 累积 + 节拍信号
|
||||
dispatchedSolutions.push({ issueId, solution, execTaskId: execTask.id })
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "planex", from: "planner", to: "executor",
|
||||
type: "issue_ready",
|
||||
summary: `[planner] issue_ready: ${issueId}`,
|
||||
ref: solutionFile
|
||||
})
|
||||
SendMessage({
|
||||
type: "message", recipient: "executor",
|
||||
content: `## [planner] Issue Ready: ${issueId}\n**solution_file**: ${solutionFile}\n**EXEC task**: ${execTask.subject}`,
|
||||
summary: `[planner] issue_ready: ${issueId}`
|
||||
})
|
||||
}
|
||||
|
||||
// wave 级汇总
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "planex", from: "planner", to: "executor",
|
||||
type: "wave_ready",
|
||||
summary: `[planner] Wave ${waveNum} fully dispatched: ${wave.issue_ids.length} issues`
|
||||
})
|
||||
}
|
||||
// After all waves → Phase 5 (Report + Finalize)
|
||||
}
|
||||
- Respect dependencies: <issue_dependencies>`
|
||||
})
|
||||
```
|
||||
|
||||
**关键差异**: 波次分组来自 `executionPlan.waves`,但每个 issue 独立规划 + 即时派发。Progressive 模式下 L0(Wave 1) → L1(Wave 2),Direct 模式下 parallel_group 映射为 wave。
|
||||
**Solution Artifact**:
|
||||
|
||||
#### Wave 规划(Path A/B/C 汇聚)— 逐 issue 派发
|
||||
|
||||
将 issueIds 逐个规划并即时派发(Path D 使用独立的波次逻辑,不走此路径):
|
||||
|
||||
```javascript
|
||||
if (inputType !== 'execution_plan') {
|
||||
const projectRoot = Bash('cd . && pwd').trim()
|
||||
const dispatchedSolutions = []
|
||||
const execution_method = args.match(/execution_method:\s*(\S+)/)?.[1] || 'Auto'
|
||||
const code_review = args.match(/code_review:\s*(\S+)/)?.[1] || 'Skip'
|
||||
let waveNum = 1 // 简化:不再按 WAVE_SIZE=5 分组,全部视为一个逻辑 wave
|
||||
|
||||
for (const issueId of issueIds) {
|
||||
// Step 1: 单 issue 规划
|
||||
const planResult = Task({
|
||||
subagent_type: "issue-plan-agent",
|
||||
run_in_background: false,
|
||||
description: `Plan solution for ${issueId}`,
|
||||
prompt: `issue_ids: ["${issueId}"]
|
||||
project_root: "${projectRoot}"
|
||||
|
||||
## Requirements
|
||||
- Generate solution for this issue
|
||||
- Auto-bind single solution
|
||||
- For multiple solutions, select the most pragmatic one`
|
||||
})
|
||||
|
||||
// Step 2: 获取 solution + 写中间产物
|
||||
const solJson = Bash(`ccw issue solution ${issueId} --json`)
|
||||
const solution = JSON.parse(solJson)
|
||||
const solutionFile = `${sessionDir}/artifacts/solutions/${issueId}.json`
|
||||
Write({
|
||||
file_path: solutionFile,
|
||||
content: JSON.stringify({
|
||||
session_id: sessionId, issue_id: issueId, ...solution,
|
||||
execution_config: { execution_method, code_review },
|
||||
timestamp: new Date().toISOString()
|
||||
}, null, 2)
|
||||
})
|
||||
|
||||
// Step 3: inline 冲突检查
|
||||
const blockedBy = inlineConflictCheck(issueId, solution, dispatchedSolutions)
|
||||
|
||||
// Step 4: 创建 EXEC-* 任务
|
||||
const execTask = TaskCreate({
|
||||
subject: `EXEC-W${waveNum}-${issueId}: 实现 ${solution.bound?.title || issueId}`,
|
||||
description: `## 执行任务\n**Wave**: ${waveNum}\n**Issue**: ${issueId}\n**solution_file**: ${solutionFile}\n**execution_method**: ${execution_method}\n**code_review**: ${code_review}`,
|
||||
activeForm: `实现 ${issueId}`,
|
||||
owner: "executor"
|
||||
})
|
||||
if (blockedBy.length > 0) {
|
||||
TaskUpdate({ taskId: execTask.id, addBlockedBy: blockedBy })
|
||||
}
|
||||
|
||||
// Step 5: 累积 + 节拍信号
|
||||
dispatchedSolutions.push({ issueId, solution, execTaskId: execTask.id })
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "planex", from: "planner", to: "executor",
|
||||
type: "issue_ready",
|
||||
summary: `[planner] issue_ready: ${issueId}`,
|
||||
ref: solutionFile
|
||||
})
|
||||
SendMessage({
|
||||
type: "message", recipient: "executor",
|
||||
content: `## [planner] Issue Ready: ${issueId}\n**solution_file**: ${solutionFile}\n**EXEC task**: ${execTask.subject}`,
|
||||
summary: `[planner] issue_ready: ${issueId}`
|
||||
})
|
||||
}
|
||||
} // end if (inputType !== 'execution_plan')
|
||||
```
|
||||
Write({
|
||||
file_path: "<sessionDir>/artifacts/solutions/<issueId>.json",
|
||||
content: JSON.stringify({
|
||||
session_id: <sessionId>,
|
||||
issue_id: <issueId>,
|
||||
...solution,
|
||||
execution_config: { execution_method, code_review },
|
||||
timestamp: <ISO-timestamp>
|
||||
}, null, 2)
|
||||
})
|
||||
```
|
||||
|
||||
### Phase 4: Inline Conflict Check + Wave Summary
|
||||
**EXEC Task Creation**:
|
||||
|
||||
EXEC-* 任务创建已在 Phase 3 逐 issue 完成,Phase 4 仅负责 inline 冲突检查函数定义和 wave 汇总。
|
||||
|
||||
#### Inline Conflict Check 函数
|
||||
|
||||
```javascript
|
||||
// Inline conflict check — 替代 issue-queue-agent
|
||||
// 基于 files_touched 重叠检测 + 显式依赖
|
||||
function inlineConflictCheck(issueId, solution, dispatchedSolutions) {
|
||||
const currentFiles = solution.bound?.files_touched
|
||||
|| solution.bound?.affected_files || []
|
||||
const blockedBy = []
|
||||
|
||||
// 1. 文件冲突检测
|
||||
for (const prev of dispatchedSolutions) {
|
||||
const prevFiles = prev.solution.bound?.files_touched
|
||||
|| prev.solution.bound?.affected_files || []
|
||||
const overlap = currentFiles.filter(f => prevFiles.includes(f))
|
||||
if (overlap.length > 0) {
|
||||
blockedBy.push(prev.execTaskId)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 显式依赖
|
||||
const explicitDeps = solution.bound?.dependencies?.on_issues || []
|
||||
for (const depId of explicitDeps) {
|
||||
const depTask = dispatchedSolutions.find(d => d.issueId === depId)
|
||||
if (depTask && !blockedBy.includes(depTask.execTaskId)) {
|
||||
blockedBy.push(depTask.execTaskId)
|
||||
}
|
||||
}
|
||||
|
||||
return blockedBy
|
||||
}
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "EXEC-W<waveNum>-<issueId>: Implement <solution-title>",
|
||||
description: `## Execution Task
|
||||
**Wave**: <waveNum>
|
||||
**Issue**: <issueId>
|
||||
**solution_file**: <solutionFile>
|
||||
**execution_method**: <method>
|
||||
**code_review**: <review>`,
|
||||
activeForm: "Implementing <issueId>",
|
||||
owner: "executor"
|
||||
})
|
||||
```
|
||||
|
||||
#### Wave Summary Signal
|
||||
#### Wave Processing (Path A/B/C Convergence)
|
||||
|
||||
Phase 3 循环完成后发送汇总信号(Path A/B/C 在全部 issue 完成后,Path D 在每个 wave 完成后):
|
||||
For non-execution-plan inputs, process all issues as a single logical wave:
|
||||
|
||||
```javascript
|
||||
// Wave summary — 已在 Phase 3 循环中由每个 wave 末尾发送
|
||||
// Path A/B/C: 全部 issue 完成后发送一次
|
||||
**Workflow**:
|
||||
1. For each issue in list:
|
||||
- Call issue-plan-agent
|
||||
- Write solution artifact
|
||||
- Perform inline conflict check
|
||||
- Create EXEC-* task
|
||||
- Send issue_ready signal
|
||||
2. After all issues complete, send wave_ready signal
|
||||
|
||||
### Phase 4: Inline Conflict Check + Dispatch
|
||||
|
||||
Perform conflict detection using files_touched overlap analysis.
|
||||
|
||||
**Conflict Detection Rules**:
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| File overlap detected | Add blockedBy dependency to previous task |
|
||||
| Explicit dependency in solution.bound.dependencies.on_issues | Add blockedBy to referenced task |
|
||||
| No conflict | No blockedBy, task is immediately executable |
|
||||
|
||||
**Inline Conflict Check Algorithm**:
|
||||
|
||||
1. Get current solution's files_touched (or affected_files)
|
||||
2. For each previously dispatched solution:
|
||||
- Check if any files overlap
|
||||
- If overlap, add previous execTaskId to blockedBy
|
||||
3. Check explicit dependencies from solution.bound.dependencies.on_issues
|
||||
4. Return blockedBy array for TaskUpdate
|
||||
|
||||
**Wave Summary Signal** (after all issues in wave):
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "planex", from: "planner", to: "executor",
|
||||
type: "wave_ready",
|
||||
summary: `[planner] Wave ${waveNum} fully dispatched: ${issueIds.length} issues`
|
||||
summary: "[planner] Wave <waveNum> fully dispatched: <issueCount> issues"
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message", recipient: "executor",
|
||||
content: `## [planner] Wave ${waveNum} Complete\n所有 issues 已逐个派发完毕,共 ${dispatchedSolutions.length} 个 EXEC 任务。`,
|
||||
summary: `[planner] wave_ready: wave ${waveNum}`
|
||||
content: "## [planner] Wave <waveNum> Complete\nAll issues dispatched, <count> EXEC tasks created.",
|
||||
summary: "[planner] wave_ready: wave <waveNum>"
|
||||
})
|
||||
```
|
||||
|
||||
### Phase 5: Report + Finalize
|
||||
|
||||
所有 wave 规划完毕后,发送最终信号。
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
|
||||
|
||||
```javascript
|
||||
// All waves planned
|
||||
**Final Signal** (all waves complete):
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "planex",
|
||||
from: "planner",
|
||||
to: "executor",
|
||||
type: "all_planned",
|
||||
summary: `[planner] All ${waveNum} waves planned, ${issueIds.length} issues total`
|
||||
summary: "[planner] All <waveCount> waves planned, <issueCount> issues total"
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
@@ -399,70 +281,20 @@ SendMessage({
|
||||
recipient: "executor",
|
||||
content: `## [planner] All Waves Planned
|
||||
|
||||
**Total Waves**: ${waveNum}
|
||||
**Total Issues**: ${issueIds.length}
|
||||
**Status**: 所有规划完毕,等待 executor 完成剩余 EXEC-* 任务
|
||||
**Total Waves**: <waveCount>
|
||||
**Total Issues**: <issueCount>
|
||||
**Status**: All planning complete, waiting for executor to finish remaining EXEC-* tasks
|
||||
|
||||
Pipeline 完成后请 executor 发送 wave_done 确认。`,
|
||||
summary: `[planner] all_planned: ${waveNum} waves, ${issueIds.length} issues`
|
||||
Pipeline complete when executor sends wave_done confirmation.`,
|
||||
summary: "[planner] all_planned: <waveCount> waves, <issueCount> issues"
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
// Check for next PLAN-* task (e.g., user added more requirements)
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('PLAN-') &&
|
||||
t.owner === 'planner' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
|
||||
if (nextTasks.length > 0) {
|
||||
// Continue with next task → back to Phase 1
|
||||
}
|
||||
TaskUpdate({ taskId: <task-id>, status: "completed" })
|
||||
```
|
||||
|
||||
## Plan File Parsing
|
||||
**Loop Check**: Query for next `PLAN-*` task with owner=planner, status=pending, blockedBy empty. If found, return to Phase 1.
|
||||
|
||||
解析 Plan 文件为 phases 列表:
|
||||
|
||||
```javascript
|
||||
function parsePlanPhases(planContent) {
|
||||
const phases = []
|
||||
|
||||
// 匹配 ## Phase N: Title 或 ## Step N: Title 或 ### N. Title
|
||||
const phaseRegex = /^#{2,3}\s+(?:Phase|Step|阶段)\s*\d*[:.:]\s*(.+?)$/gm
|
||||
let match
|
||||
let lastIndex = 0
|
||||
let lastTitle = null
|
||||
|
||||
while ((match = phaseRegex.exec(planContent)) !== null) {
|
||||
if (lastTitle !== null) {
|
||||
const description = planContent.slice(lastIndex, match.index).trim()
|
||||
phases.push({ title: lastTitle, description })
|
||||
}
|
||||
lastTitle = match[1].trim()
|
||||
lastIndex = match.index + match[0].length
|
||||
}
|
||||
|
||||
// Last phase
|
||||
if (lastTitle !== null) {
|
||||
const description = planContent.slice(lastIndex).trim()
|
||||
phases.push({ title: lastTitle, description })
|
||||
}
|
||||
|
||||
// Fallback: 如果没有匹配到 Phase 结构,将整个内容作为单个 issue
|
||||
if (phases.length === 0) {
|
||||
const titleMatch = planContent.match(/^#\s+(.+)$/m)
|
||||
phases.push({
|
||||
title: titleMatch ? titleMatch[1] : 'Plan Implementation',
|
||||
description: planContent.slice(0, 500)
|
||||
})
|
||||
}
|
||||
|
||||
return phases
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
@@ -478,3 +310,4 @@ function parsePlanPhases(planContent) {
|
||||
| Empty input (no issues, no text, no plan) | AskUserQuestion for clarification |
|
||||
| Solution artifact write failure | Log warning, create EXEC task without solution_file (executor fallback) |
|
||||
| Wave partially failed | Report partial success, continue with successful issues |
|
||||
| Critical issue beyond scope | SendMessage error to executor |
|
||||
|
||||
Reference in New Issue
Block a user