mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 15:03:57 +08:00
feat: Add explorer and synthesizer roles with commands for codebase exploration and synthesis
- Implemented `explorer` role for parallel codebase exploration using `cli-explore-agent`. - Created `explore.md` command documentation detailing exploration strategy and execution steps. - Established `synthesizer` role for integrating insights from explorations, analyses, and discussions. - Developed `synthesize.md` command documentation outlining synthesis strategy and output format. - Configured team settings in `team-config.json` to support new roles and pipeline modes. - Added regression test for CodexLens bootstrap fallback to ensure robustness in error handling.
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
# Command: deepen
|
||||
|
||||
> 深入探索与补充分析。根据讨论类型执行针对性的代码探索或 CLI 分析。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of Discussant
|
||||
- 用户反馈已收集,需要深入处理
|
||||
- 每个 DISCUSS-* 任务触发一次
|
||||
|
||||
**Trigger conditions**:
|
||||
- initial: 首轮讨论,汇总分析结果
|
||||
- deepen: 继续深入当前方向
|
||||
- direction-adjusted: 方向调整后重新分析
|
||||
- specific-questions: 回答用户具体问题
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: Mixed(简单汇总内联,深入探索用 subagent/CLI)
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
function selectDeepenStrategy(discussType, complexity) {
|
||||
const strategies = {
|
||||
'initial': {
|
||||
mode: 'inline',
|
||||
description: 'Summarize all analysis results into discussion format'
|
||||
},
|
||||
'deepen': {
|
||||
mode: complexity === 'High' ? 'cli' : 'subagent',
|
||||
description: 'Further exploration in current direction'
|
||||
},
|
||||
'direction-adjusted': {
|
||||
mode: 'cli',
|
||||
description: 'Re-analyze from new perspective'
|
||||
},
|
||||
'specific-questions': {
|
||||
mode: 'subagent',
|
||||
description: 'Targeted exploration to answer questions'
|
||||
}
|
||||
}
|
||||
return strategies[discussType] || strategies['initial']
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Strategy Selection
|
||||
|
||||
```javascript
|
||||
const strategy = selectDeepenStrategy(discussType, assessComplexity(userFeedback))
|
||||
```
|
||||
|
||||
### Step 2: Execute by Type
|
||||
|
||||
#### Initial Discussion
|
||||
|
||||
```javascript
|
||||
function processInitialDiscussion() {
|
||||
// 汇总所有分析结果
|
||||
const summary = {
|
||||
perspectives_analyzed: allAnalyses.map(a => a.perspective),
|
||||
total_insights: currentInsights.length,
|
||||
total_findings: currentFindings.length,
|
||||
convergent_themes: identifyConvergentThemes(allAnalyses),
|
||||
conflicting_views: identifyConflicts(allAnalyses),
|
||||
top_discussion_points: discussionPoints.slice(0, 5),
|
||||
open_questions: openQuestions.slice(0, 5)
|
||||
}
|
||||
|
||||
roundContent.updated_understanding.new_insights = summary.convergent_themes
|
||||
roundContent.new_findings = currentFindings.slice(0, 10)
|
||||
roundContent.new_questions = openQuestions.slice(0, 5)
|
||||
}
|
||||
|
||||
function identifyConvergentThemes(analyses) {
|
||||
// 跨视角找共同主题
|
||||
const allInsights = analyses.flatMap(a =>
|
||||
(a.key_insights || []).map(i => typeof i === 'string' ? i : i.insight)
|
||||
)
|
||||
// 简单去重 + 聚合
|
||||
return [...new Set(allInsights)].slice(0, 5)
|
||||
}
|
||||
|
||||
function identifyConflicts(analyses) {
|
||||
// 识别视角间的矛盾
|
||||
return [] // 由实际分析结果决定
|
||||
}
|
||||
```
|
||||
|
||||
#### Deepen Discussion
|
||||
|
||||
```javascript
|
||||
function processDeepenDiscussion() {
|
||||
// 在当前方向上进一步探索
|
||||
Task({
|
||||
subagent_type: "cli-explore-agent",
|
||||
run_in_background: false,
|
||||
description: `Deepen exploration: ${topic} (round ${round})`,
|
||||
prompt: `
|
||||
## Context
|
||||
Topic: ${topic}
|
||||
Round: ${round}
|
||||
Previous findings: ${currentFindings.slice(0, 5).join('; ')}
|
||||
Open questions: ${openQuestions.slice(0, 3).join('; ')}
|
||||
|
||||
## MANDATORY FIRST STEPS
|
||||
1. Focus on open questions from previous analysis
|
||||
2. Search for specific patterns mentioned in findings
|
||||
3. Look for edge cases and exceptions
|
||||
|
||||
## Exploration Focus
|
||||
- Deepen understanding of confirmed patterns
|
||||
- Investigate open questions
|
||||
- Find additional evidence for uncertain insights
|
||||
|
||||
## Output
|
||||
Write to: ${sessionFolder}/discussions/deepen-${discussNum}.json
|
||||
Schema: {new_findings, answered_questions, remaining_questions, evidence}
|
||||
`
|
||||
})
|
||||
|
||||
// 读取深入探索结果
|
||||
let deepenResult = {}
|
||||
try {
|
||||
deepenResult = JSON.parse(Read(`${sessionFolder}/discussions/deepen-${discussNum}.json`))
|
||||
} catch {}
|
||||
|
||||
roundContent.updated_understanding.new_insights = deepenResult.new_findings || []
|
||||
roundContent.new_findings = deepenResult.new_findings || []
|
||||
roundContent.new_questions = deepenResult.remaining_questions || []
|
||||
}
|
||||
```
|
||||
|
||||
#### Direction Adjusted
|
||||
|
||||
```javascript
|
||||
function processDirectionAdjusted() {
|
||||
// 方向调整后,通过 CLI 重新分析
|
||||
Bash({
|
||||
command: `ccw cli -p "PURPOSE: Re-analyze '${topic}' with adjusted focus on '${userFeedback}'
|
||||
Success: New insights from adjusted direction
|
||||
|
||||
PREVIOUS ANALYSIS CONTEXT:
|
||||
- Previous insights: ${currentInsights.slice(0, 5).map(i => typeof i === 'string' ? i : i.insight).join('; ')}
|
||||
- Direction change reason: User requested focus on '${userFeedback}'
|
||||
|
||||
TASK:
|
||||
• Re-evaluate findings from new perspective
|
||||
• Identify what changes with adjusted focus
|
||||
• Find new patterns relevant to adjusted direction
|
||||
• Note what previous findings remain valid
|
||||
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Topic: ${topic}
|
||||
EXPECTED: Updated analysis with: validated findings, new insights, invalidated assumptions
|
||||
CONSTRAINTS: Focus on ${userFeedback}
|
||||
" --tool gemini --mode analysis`,
|
||||
run_in_background: true
|
||||
})
|
||||
|
||||
// ⚠️ STOP: Wait for CLI callback
|
||||
|
||||
roundContent.updated_understanding.corrected = ['Direction adjusted per user request']
|
||||
roundContent.updated_understanding.new_insights = [] // From CLI result
|
||||
}
|
||||
```
|
||||
|
||||
#### Specific Questions
|
||||
|
||||
```javascript
|
||||
function processSpecificQuestions() {
|
||||
// 针对用户问题进行探索
|
||||
Task({
|
||||
subagent_type: "cli-explore-agent",
|
||||
run_in_background: false,
|
||||
description: `Answer questions: ${topic}`,
|
||||
prompt: `
|
||||
## Context
|
||||
Topic: ${topic}
|
||||
User questions: ${userFeedback}
|
||||
Known findings: ${currentFindings.slice(0, 5).join('; ')}
|
||||
|
||||
## MANDATORY FIRST STEPS
|
||||
1. Search for code related to user's questions
|
||||
2. Trace execution paths relevant to questions
|
||||
3. Check configuration and environment factors
|
||||
|
||||
## Output
|
||||
Write to: ${sessionFolder}/discussions/questions-${discussNum}.json
|
||||
Schema: {answers: [{question, answer, evidence, confidence}], follow_up_questions}
|
||||
`
|
||||
})
|
||||
|
||||
let questionResult = {}
|
||||
try {
|
||||
questionResult = JSON.parse(Read(`${sessionFolder}/discussions/questions-${discussNum}.json`))
|
||||
} catch {}
|
||||
|
||||
roundContent.updated_understanding.new_insights =
|
||||
(questionResult.answers || []).map(a => `Q: ${a.question} → A: ${a.answer}`)
|
||||
roundContent.new_questions = questionResult.follow_up_questions || []
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
// 结果已写入 roundContent,由 role.md Phase 4 处理
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| cli-explore-agent fails | Use existing analysis results, note limitation |
|
||||
| CLI timeout | Report partial results |
|
||||
| No previous analyses | Process as initial with empty context |
|
||||
| User feedback unparseable | Treat as 'deepen' type |
|
||||
273
.claude/skills/team-ultra-analyze/roles/discussant/role.md
Normal file
273
.claude/skills/team-ultra-analyze/roles/discussant/role.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# Role: discussant
|
||||
|
||||
讨论处理者。根据 coordinator 传递的用户反馈,执行方向调整、深入探索或补充分析,更新讨论时间线。
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `discussant`
|
||||
- **Task Prefix**: `DISCUSS-*`
|
||||
- **Responsibility**: Analysis + Exploration(讨论处理)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[discussant]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `DISCUSS-*` 前缀的任务
|
||||
- 所有输出必须带 `[discussant]` 标识
|
||||
- 仅通过 SendMessage 与 coordinator 通信
|
||||
- 基于用户反馈和已有分析结果执行深入探索
|
||||
- 将讨论结果写入 shared-memory.json 的 `discussions` 字段
|
||||
- 更新 discussion.md 的讨论时间线
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- ❌ 直接与用户交互(AskUserQuestion 由 coordinator 驱动)
|
||||
- ❌ 生成最终结论(属于 synthesizer)
|
||||
- ❌ 为其他角色创建任务
|
||||
- ❌ 直接与其他 worker 通信
|
||||
- ❌ 修改源代码
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `discussion_processed` | discussant → coordinator | 讨论处理完成 | 包含更新的理解和新发现 |
|
||||
| `error` | discussant → coordinator | 处理失败 | 阻塞性错误 |
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `deepen` | [commands/deepen.md](commands/deepen.md) | Phase 3 | 深入探索与补充分析 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `cli-explore-agent` | deepen.md | 针对性代码库探索 |
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | deepen.md | 深入分析 |
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('DISCUSS-') &&
|
||||
t.owner === 'discussant' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
|
||||
if (myTasks.length === 0) return // idle
|
||||
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
|
||||
### Phase 2: Context Loading
|
||||
|
||||
```javascript
|
||||
// 从任务描述中提取上下文
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim()
|
||||
const topic = task.description.match(/topic:\s*(.+)/)?.[1]?.trim()
|
||||
const round = parseInt(task.description.match(/round:\s*(\d+)/)?.[1] || '1')
|
||||
const discussType = task.description.match(/type:\s*(.+)/)?.[1]?.trim() || 'initial'
|
||||
const userFeedback = task.description.match(/user_feedback:\s*(.+)/)?.[1]?.trim() || ''
|
||||
|
||||
// 读取 shared memory
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
|
||||
// 读取已有分析结果
|
||||
const analysisFiles = Glob({ pattern: `${sessionFolder}/analyses/*.json` })
|
||||
const allAnalyses = analysisFiles.map(f => {
|
||||
try { return JSON.parse(Read(f)) } catch { return null }
|
||||
}).filter(Boolean)
|
||||
|
||||
// 读取已有探索结果
|
||||
const explorationFiles = Glob({ pattern: `${sessionFolder}/explorations/*.json` })
|
||||
const allExplorations = explorationFiles.map(f => {
|
||||
try { return JSON.parse(Read(f)) } catch { return null }
|
||||
}).filter(Boolean)
|
||||
|
||||
// 聚合当前理解
|
||||
const currentFindings = allAnalyses.flatMap(a => a.key_findings || [])
|
||||
const currentInsights = allAnalyses.flatMap(a => a.key_insights || [])
|
||||
const openQuestions = allAnalyses.flatMap(a => a.open_questions || [])
|
||||
const discussionPoints = allAnalyses.flatMap(a => a.discussion_points || [])
|
||||
```
|
||||
|
||||
### Phase 3: Discussion Processing
|
||||
|
||||
```javascript
|
||||
// Read commands/deepen.md for full implementation
|
||||
Read("commands/deepen.md")
|
||||
```
|
||||
|
||||
**根据 discussType 选择处理策略**:
|
||||
|
||||
```javascript
|
||||
const discussNum = task.subject.match(/DISCUSS-(\d+)/)?.[1] || '001'
|
||||
const outputPath = `${sessionFolder}/discussions/discussion-round-${discussNum}.json`
|
||||
|
||||
switch (discussType) {
|
||||
case 'initial':
|
||||
// 首轮讨论:汇总所有分析结果,生成讨论摘要
|
||||
processInitialDiscussion()
|
||||
break
|
||||
|
||||
case 'deepen':
|
||||
// 继续深入:在当前方向上进一步探索
|
||||
processDeepenDiscussion()
|
||||
break
|
||||
|
||||
case 'direction-adjusted':
|
||||
// 方向调整:基于新方向重新组织发现
|
||||
processDirectionAdjusted()
|
||||
break
|
||||
|
||||
case 'specific-questions':
|
||||
// 具体问题:针对用户问题进行分析
|
||||
processSpecificQuestions()
|
||||
break
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Update Discussion Timeline
|
||||
|
||||
```javascript
|
||||
// 构建讨论轮次内容
|
||||
const roundContent = {
|
||||
round,
|
||||
type: discussType,
|
||||
user_feedback: userFeedback,
|
||||
updated_understanding: {
|
||||
confirmed: [], // 确认的假设
|
||||
corrected: [], // 纠正的假设
|
||||
new_insights: [] // 新发现
|
||||
},
|
||||
new_findings: [],
|
||||
new_questions: [],
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
|
||||
Write(outputPath, JSON.stringify(roundContent, null, 2))
|
||||
|
||||
// 更新 discussion.md
|
||||
const discussionMdContent = `
|
||||
### Round ${round + 1} - Discussion (${new Date().toISOString()})
|
||||
|
||||
#### Type
|
||||
${discussType}
|
||||
|
||||
#### User Input
|
||||
${userFeedback || '(Initial discussion round)'}
|
||||
|
||||
#### Updated Understanding
|
||||
${roundContent.updated_understanding.confirmed.length > 0
|
||||
? `**Confirmed**: ${roundContent.updated_understanding.confirmed.map(c => `\n- ✅ ${c}`).join('')}` : ''}
|
||||
${roundContent.updated_understanding.corrected.length > 0
|
||||
? `**Corrected**: ${roundContent.updated_understanding.corrected.map(c => `\n- 🔄 ${c}`).join('')}` : ''}
|
||||
${roundContent.updated_understanding.new_insights.length > 0
|
||||
? `**New Insights**: ${roundContent.updated_understanding.new_insights.map(i => `\n- 💡 ${i}`).join('')}` : ''}
|
||||
|
||||
#### New Findings
|
||||
${(roundContent.new_findings || []).map(f => `- ${f}`).join('\n') || '(None)'}
|
||||
|
||||
#### Open Questions
|
||||
${(roundContent.new_questions || []).map(q => `- ${q}`).join('\n') || '(None)'}
|
||||
`
|
||||
|
||||
const currentDiscussion = Read(`${sessionFolder}/discussion.md`)
|
||||
Write(`${sessionFolder}/discussion.md`, currentDiscussion + discussionMdContent)
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
// 更新 shared memory
|
||||
sharedMemory.discussions = sharedMemory.discussions || []
|
||||
sharedMemory.discussions.push({
|
||||
id: `discussion-round-${discussNum}`,
|
||||
round,
|
||||
type: discussType,
|
||||
new_insight_count: roundContent.updated_understanding.new_insights?.length || 0,
|
||||
corrected_count: roundContent.updated_understanding.corrected?.length || 0,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
|
||||
// 更新 current_understanding
|
||||
sharedMemory.current_understanding = sharedMemory.current_understanding || { established: [], clarified: [], key_insights: [] }
|
||||
sharedMemory.current_understanding.established.push(...(roundContent.updated_understanding.confirmed || []))
|
||||
sharedMemory.current_understanding.clarified.push(...(roundContent.updated_understanding.corrected || []))
|
||||
sharedMemory.current_understanding.key_insights.push(...(roundContent.updated_understanding.new_insights || []))
|
||||
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
|
||||
const resultSummary = `Round ${round}: ${roundContent.updated_understanding.new_insights?.length || 0} 新洞察, ${roundContent.updated_understanding.corrected?.length || 0} 纠正`
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "discussant",
|
||||
to: "coordinator",
|
||||
type: "discussion_processed",
|
||||
summary: `[discussant] ${resultSummary}`,
|
||||
ref: outputPath
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [discussant] Discussion Round ${round} Results
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Type**: ${discussType}
|
||||
|
||||
### Summary
|
||||
${resultSummary}
|
||||
|
||||
### Key Updates
|
||||
${roundContent.updated_understanding.new_insights?.slice(0, 3).map(i => `- 💡 ${i}`).join('\n') || '(No new insights)'}
|
||||
${roundContent.updated_understanding.corrected?.slice(0, 3).map(c => `- 🔄 ${c}`).join('\n') || ''}
|
||||
|
||||
### Output
|
||||
${outputPath}`,
|
||||
summary: `[discussant] DISCUSS complete: ${resultSummary}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
// Check for next task
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('DISCUSS-') &&
|
||||
t.owner === 'discussant' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
|
||||
if (nextTasks.length > 0) {
|
||||
// Continue with next task → back to Phase 1
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No DISCUSS-* tasks available | Idle, wait for coordinator assignment |
|
||||
| No analysis results found | Report empty discussion, notify coordinator |
|
||||
| CLI tool unavailable | Use existing analysis results for discussion |
|
||||
| User feedback unclear | Process as 'deepen' type, note ambiguity |
|
||||
| Session folder missing | Error to coordinator |
|
||||
Reference in New Issue
Block a user