mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
feat(team-lifecycle-v2): add explorer/architect roles + wisdom accumulation
New roles (on-demand, non-pipeline): - explorer: multi-strategy code search & pattern discovery (EXPLORE-*) - architect: multi-mode architecture assessment (ARCH-*) New files: - roles/explorer/role.md - service role with 5 search strategies - roles/architect/role.md - consulting role with 5 consultation modes - roles/architect/commands/assess.md - mode-specific assessment strategies Updated: - SKILL.md: architecture diagram, role router, message types, session dirs, wisdom protocol - specs/team-config.json: new role definitions + wisdom/explorations/architecture dirs - roles/coordinator/role.md: wisdom directory initialization on session create
This commit is contained in:
@@ -29,6 +29,12 @@ Unified team skill covering specification, implementation, testing, and review.
|
|||||||
│coordinator││analyst││writer││discussant││planner││executor││tester││reviewer│
|
│coordinator││analyst││writer││discussant││planner││executor││tester││reviewer│
|
||||||
│ roles/ ││roles/ ││roles/││ roles/ ││roles/ ││ roles/ ││roles/││ roles/ │
|
│ roles/ ││roles/ ││roles/││ roles/ ││roles/ ││ roles/ ││roles/││ roles/ │
|
||||||
└──────────┘└───────┘└──────┘└──────────┘└───────┘└────────┘└──────┘└────────┘
|
└──────────┘└───────┘└──────┘└──────────┘└───────┘└────────┘└──────┘└────────┘
|
||||||
|
↑ ↑
|
||||||
|
on-demand by coordinator
|
||||||
|
┌──────────┐ ┌─────────┐
|
||||||
|
│ explorer │ │architect│
|
||||||
|
│ (service)│ │(consult)│
|
||||||
|
└──────────┘ └─────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
## Command Architecture
|
## Command Architecture
|
||||||
@@ -65,11 +71,17 @@ roles/
|
|||||||
│ ├── role.md
|
│ ├── role.md
|
||||||
│ └── commands/
|
│ └── commands/
|
||||||
│ └── validate.md # Test-fix cycle
|
│ └── validate.md # Test-fix cycle
|
||||||
└── reviewer/
|
├── reviewer/
|
||||||
├── role.md
|
│ ├── role.md
|
||||||
|
│ └── commands/
|
||||||
|
│ ├── code-review.md # 4-dimension code review
|
||||||
|
│ └── spec-quality.md # 5-dimension spec quality check
|
||||||
|
├── explorer/ # Service role (on-demand)
|
||||||
|
│ └── role.md # Multi-strategy code search & pattern discovery
|
||||||
|
└── architect/ # Consulting role (on-demand)
|
||||||
|
├── role.md # Multi-mode architecture assessment
|
||||||
└── commands/
|
└── commands/
|
||||||
├── code-review.md # 4-dimension code review
|
└── assess.md # Mode-specific assessment strategies
|
||||||
└── spec-quality.md # 5-dimension spec quality check
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Design principle**: role.md keeps Phase 1 (Task Discovery) and Phase 5 (Report) inline. Phases 2-4 either stay inline (simple logic) or delegate to `commands/*.md` via `Read("commands/xxx.md")` when they involve subagent delegation, CLI fan-out, or complex strategies.
|
**Design principle**: role.md keeps Phase 1 (Task Discovery) and Phase 5 (Report) inline. Phases 2-4 either stay inline (simple logic) or delegate to `commands/*.md` via `Read("commands/xxx.md")` when they involve subagent delegation, CLI fan-out, or complex strategies.
|
||||||
@@ -106,7 +118,9 @@ const VALID_ROLES = {
|
|||||||
"planner": { file: "roles/planner/role.md", prefix: "PLAN" },
|
"planner": { file: "roles/planner/role.md", prefix: "PLAN" },
|
||||||
"executor": { file: "roles/executor/role.md", prefix: "IMPL" },
|
"executor": { file: "roles/executor/role.md", prefix: "IMPL" },
|
||||||
"tester": { file: "roles/tester/role.md", prefix: "TEST" },
|
"tester": { file: "roles/tester/role.md", prefix: "TEST" },
|
||||||
"reviewer": { file: "roles/reviewer/role.md", prefix: ["REVIEW", "QUALITY"] }
|
"reviewer": { file: "roles/reviewer/role.md", prefix: ["REVIEW", "QUALITY"] },
|
||||||
|
"explorer": { file: "roles/explorer/role.md", prefix: "EXPLORE", type: "service" },
|
||||||
|
"architect": { file: "roles/architect/role.md", prefix: "ARCH", type: "consulting" }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!VALID_ROLES[role]) {
|
if (!VALID_ROLES[role]) {
|
||||||
@@ -183,6 +197,8 @@ if (!roleMatch) {
|
|||||||
| `executor` | IMPL-* | Code implementation following plans | [roles/executor/role.md](roles/executor/role.md) |
|
| `executor` | IMPL-* | Code implementation following plans | [roles/executor/role.md](roles/executor/role.md) |
|
||||||
| `tester` | TEST-* | Adaptive test-fix cycles, quality gates | [roles/tester/role.md](roles/tester/role.md) |
|
| `tester` | TEST-* | Adaptive test-fix cycles, quality gates | [roles/tester/role.md](roles/tester/role.md) |
|
||||||
| `reviewer` | `REVIEW-*` + `QUALITY-*` | Code review + Spec quality validation (auto-switch by prefix) | [roles/reviewer/role.md](roles/reviewer/role.md) |
|
| `reviewer` | `REVIEW-*` + `QUALITY-*` | Code review + Spec quality validation (auto-switch by prefix) | [roles/reviewer/role.md](roles/reviewer/role.md) |
|
||||||
|
| `explorer` | EXPLORE-* | Code search, pattern discovery, dependency tracing (service role, on-demand) | [roles/explorer/role.md](roles/explorer/role.md) |
|
||||||
|
| `architect` | ARCH-* | Architecture assessment, tech feasibility, design review (consulting role, on-demand) | [roles/architect/role.md](roles/architect/role.md) |
|
||||||
|
|
||||||
## Shared Infrastructure
|
## Shared Infrastructure
|
||||||
|
|
||||||
@@ -254,6 +270,8 @@ mcp__ccw-tools__team_msg({
|
|||||||
| executor | `impl_complete`, `impl_progress`, `error` |
|
| executor | `impl_complete`, `impl_progress`, `error` |
|
||||||
| tester | `test_result`, `impl_progress`, `fix_required`, `error` |
|
| tester | `test_result`, `impl_progress`, `fix_required`, `error` |
|
||||||
| reviewer | `review_result`, `quality_result`, `fix_required`, `error` |
|
| reviewer | `review_result`, `quality_result`, `fix_required`, `error` |
|
||||||
|
| explorer | `explore_ready`, `explore_progress`, `task_failed` |
|
||||||
|
| architect | `arch_ready`, `arch_concern`, `arch_progress`, `error` |
|
||||||
|
|
||||||
### CLI Fallback
|
### CLI Fallback
|
||||||
|
|
||||||
@@ -265,6 +283,59 @@ Bash(`ccw team list --team "${teamName}" --last 10 --json`)
|
|||||||
Bash(`ccw team status --team "${teamName}" --json`)
|
Bash(`ccw team status --team "${teamName}" --json`)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Wisdom Accumulation (All Roles)
|
||||||
|
|
||||||
|
跨任务知识积累机制。Coordinator 在 session 初始化时创建 `wisdom/` 目录,所有 worker 在执行过程中读取和贡献 wisdom。
|
||||||
|
|
||||||
|
**目录结构**:
|
||||||
|
```
|
||||||
|
{sessionFolder}/wisdom/
|
||||||
|
├── learnings.md # 发现的模式和洞察
|
||||||
|
├── decisions.md # 架构和设计决策
|
||||||
|
├── conventions.md # 代码库约定
|
||||||
|
└── issues.md # 已知风险和问题
|
||||||
|
```
|
||||||
|
|
||||||
|
**Phase 2 加载(所有 worker)**:
|
||||||
|
```javascript
|
||||||
|
// Load wisdom context at start of Phase 2
|
||||||
|
const sessionFolder = task.description.match(/Session:\s*([^\n]+)/)?.[1]?.trim()
|
||||||
|
let wisdom = {}
|
||||||
|
if (sessionFolder) {
|
||||||
|
try { wisdom.learnings = Read(`${sessionFolder}/wisdom/learnings.md`) } catch {}
|
||||||
|
try { wisdom.decisions = Read(`${sessionFolder}/wisdom/decisions.md`) } catch {}
|
||||||
|
try { wisdom.conventions = Read(`${sessionFolder}/wisdom/conventions.md`) } catch {}
|
||||||
|
try { wisdom.issues = Read(`${sessionFolder}/wisdom/issues.md`) } catch {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Phase 4/5 贡献(任务完成时)**:
|
||||||
|
```javascript
|
||||||
|
// Contribute wisdom after task completion
|
||||||
|
if (sessionFolder) {
|
||||||
|
const timestamp = new Date().toISOString().substring(0, 10)
|
||||||
|
|
||||||
|
// Role-specific contributions:
|
||||||
|
// analyst → learnings (exploration dimensions, codebase patterns)
|
||||||
|
// writer → conventions (document structure, naming patterns)
|
||||||
|
// planner → decisions (task decomposition rationale)
|
||||||
|
// executor → learnings (implementation patterns), issues (bugs encountered)
|
||||||
|
// tester → issues (test failures, edge cases), learnings (test patterns)
|
||||||
|
// reviewer → conventions (code quality patterns), issues (review findings)
|
||||||
|
// explorer → conventions (codebase patterns), learnings (dependency insights)
|
||||||
|
// architect → decisions (architecture choices), issues (architectural risks)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const targetFile = `${sessionFolder}/wisdom/${wisdomTarget}.md`
|
||||||
|
const existing = Read(targetFile)
|
||||||
|
const entry = `- [${timestamp}] [${role}] ${wisdomEntry}`
|
||||||
|
Write(targetFile, existing + '\n' + entry)
|
||||||
|
} catch {} // wisdom not initialized
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Coordinator 注入**: Coordinator 在 spawn worker 时通过 task description 传递 `Session: {sessionFolder}`,worker 据此定位 wisdom 目录。已有 wisdom 内容为后续 worker 提供上下文,实现跨任务知识传递。
|
||||||
|
|
||||||
### Task Lifecycle (All Worker Roles)
|
### Task Lifecycle (All Worker Roles)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -343,12 +414,21 @@ All session artifacts are stored under a single session folder:
|
|||||||
│ └── spec-summary.md
|
│ └── spec-summary.md
|
||||||
├── discussions/ # Discussion records (discussant output)
|
├── discussions/ # Discussion records (discussant output)
|
||||||
│ └── discuss-001..006.md
|
│ └── discuss-001..006.md
|
||||||
└── plan/ # Plan artifacts (planner output)
|
├── plan/ # Plan artifacts (planner output)
|
||||||
├── exploration-{angle}.json
|
│ ├── exploration-{angle}.json
|
||||||
├── explorations-manifest.json
|
│ ├── explorations-manifest.json
|
||||||
├── plan.json
|
│ ├── plan.json
|
||||||
└── .task/
|
│ └── .task/
|
||||||
└── TASK-*.json
|
│ └── TASK-*.json
|
||||||
|
├── explorations/ # Explorer output (cached for cross-role reuse)
|
||||||
|
│ └── explore-*.json
|
||||||
|
├── architecture/ # Architect output (assessment reports)
|
||||||
|
│ └── arch-*.json
|
||||||
|
└── wisdom/ # Cross-task accumulated knowledge
|
||||||
|
├── learnings.md # Patterns and insights discovered
|
||||||
|
├── decisions.md # Architectural decisions made
|
||||||
|
├── conventions.md # Codebase conventions found
|
||||||
|
└── issues.md # Known issues and risks
|
||||||
```
|
```
|
||||||
|
|
||||||
Messages remain at `.workflow/.team-msg/{team-name}/` (unchanged).
|
Messages remain at `.workflow/.team-msg/{team-name}/` (unchanged).
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
# Assess Command
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Multi-mode architecture assessment with mode-specific analysis strategies. Delegated from architect role.md Phase 3.
|
||||||
|
|
||||||
|
## Input Context
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Provided by role.md Phase 2
|
||||||
|
const { consultMode, sessionFolder, wisdom, explorations, projectTech, task } = context
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mode Strategies
|
||||||
|
|
||||||
|
### spec-review (ARCH-SPEC-*)
|
||||||
|
|
||||||
|
审查架构文档的技术合理性。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const dimensions = [
|
||||||
|
{ name: 'consistency', weight: 0.25 },
|
||||||
|
{ name: 'scalability', weight: 0.25 },
|
||||||
|
{ name: 'security', weight: 0.25 },
|
||||||
|
{ name: 'tech-fitness', weight: 0.25 }
|
||||||
|
]
|
||||||
|
|
||||||
|
// Load architecture documents
|
||||||
|
const archIndex = Read(`${sessionFolder}/spec/architecture/_index.md`)
|
||||||
|
const adrFiles = Glob({ pattern: `${sessionFolder}/spec/architecture/ADR-*.md` })
|
||||||
|
const adrs = adrFiles.map(f => ({ path: f, content: Read(f) }))
|
||||||
|
|
||||||
|
// Check ADR consistency
|
||||||
|
const adrDecisions = adrs.map(adr => {
|
||||||
|
const status = adr.content.match(/status:\s*(\w+)/i)?.[1]
|
||||||
|
const context = adr.content.match(/## Context\n([\s\S]*?)##/)?.[1]?.trim()
|
||||||
|
const decision = adr.content.match(/## Decision\n([\s\S]*?)##/)?.[1]?.trim()
|
||||||
|
return { path: adr.path, status, context, decision }
|
||||||
|
})
|
||||||
|
|
||||||
|
// Cross-reference: ADR decisions vs architecture index
|
||||||
|
// Flag contradictions between ADRs
|
||||||
|
// Check if tech choices align with project-tech.json
|
||||||
|
|
||||||
|
for (const dim of dimensions) {
|
||||||
|
const score = evaluateDimension(dim.name, archIndex, adrs, projectTech)
|
||||||
|
assessment.dimensions.push({ name: dim.name, score, weight: dim.weight })
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### plan-review (ARCH-PLAN-*)
|
||||||
|
|
||||||
|
审查实现计划的架构合理性。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const plan = JSON.parse(Read(`${sessionFolder}/plan/plan.json`))
|
||||||
|
const taskFiles = Glob({ pattern: `${sessionFolder}/plan/.task/TASK-*.json` })
|
||||||
|
const tasks = taskFiles.map(f => JSON.parse(Read(f)))
|
||||||
|
|
||||||
|
// 1. Dependency cycle detection
|
||||||
|
function detectCycles(tasks) {
|
||||||
|
const graph = {}
|
||||||
|
tasks.forEach(t => { graph[t.id] = t.depends_on || [] })
|
||||||
|
const visited = new Set(), inStack = new Set()
|
||||||
|
function dfs(node) {
|
||||||
|
if (inStack.has(node)) return true // cycle
|
||||||
|
if (visited.has(node)) return false
|
||||||
|
visited.add(node); inStack.add(node)
|
||||||
|
for (const dep of (graph[node] || [])) {
|
||||||
|
if (dfs(dep)) return true
|
||||||
|
}
|
||||||
|
inStack.delete(node)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return Object.keys(graph).filter(n => dfs(n))
|
||||||
|
}
|
||||||
|
const cycles = detectCycles(tasks)
|
||||||
|
if (cycles.length > 0) {
|
||||||
|
assessment.concerns.push({
|
||||||
|
severity: 'high',
|
||||||
|
concern: `Circular dependency detected: ${cycles.join(' → ')}`,
|
||||||
|
suggestion: 'Break cycle by extracting shared interface or reordering tasks'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Task granularity check
|
||||||
|
tasks.forEach(t => {
|
||||||
|
const fileCount = (t.files || []).length
|
||||||
|
if (fileCount > 8) {
|
||||||
|
assessment.concerns.push({
|
||||||
|
severity: 'medium',
|
||||||
|
task: t.id,
|
||||||
|
concern: `Task touches ${fileCount} files — may be too coarse`,
|
||||||
|
suggestion: 'Split into smaller tasks with clearer boundaries'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 3. Convention compliance (from wisdom)
|
||||||
|
if (wisdom.conventions) {
|
||||||
|
// Check if plan follows discovered conventions
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Architecture alignment (from wisdom.decisions)
|
||||||
|
if (wisdom.decisions) {
|
||||||
|
// Verify plan doesn't contradict previous architectural decisions
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### code-review (ARCH-CODE-*)
|
||||||
|
|
||||||
|
评估代码变更的架构影响。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const changedFiles = Bash(`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached`)
|
||||||
|
.split('\n').filter(Boolean)
|
||||||
|
|
||||||
|
// 1. Layer violation detection
|
||||||
|
function detectLayerViolation(file, content) {
|
||||||
|
// Check import depth — deeper layers should not import from shallower
|
||||||
|
const imports = (content.match(/from\s+['"]([^'"]+)['"]/g) || [])
|
||||||
|
.map(i => i.match(/['"]([^'"]+)['"]/)?.[1]).filter(Boolean)
|
||||||
|
return imports.filter(imp => isUpwardImport(file, imp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. New dependency analysis
|
||||||
|
const pkgChanges = changedFiles.filter(f => f.includes('package.json'))
|
||||||
|
if (pkgChanges.length > 0) {
|
||||||
|
for (const pkg of pkgChanges) {
|
||||||
|
const diff = Bash(`git diff HEAD~1 -- ${pkg} 2>/dev/null || git diff --cached -- ${pkg}`)
|
||||||
|
const newDeps = (diff.match(/\+\s+"([^"]+)":\s+"[^"]+"/g) || [])
|
||||||
|
.map(d => d.match(/"([^"]+)"/)?.[1]).filter(Boolean)
|
||||||
|
if (newDeps.length > 0) {
|
||||||
|
assessment.recommendations.push({
|
||||||
|
area: 'dependencies',
|
||||||
|
suggestion: `New dependencies added: ${newDeps.join(', ')}. Verify license compatibility and bundle size impact.`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Module boundary changes
|
||||||
|
const indexChanges = changedFiles.filter(f => f.endsWith('index.ts') || f.endsWith('index.js'))
|
||||||
|
if (indexChanges.length > 0) {
|
||||||
|
assessment.concerns.push({
|
||||||
|
severity: 'medium',
|
||||||
|
concern: `Module boundary files modified: ${indexChanges.join(', ')}`,
|
||||||
|
suggestion: 'Verify public API changes are intentional and backward compatible'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Architectural impact scoring
|
||||||
|
assessment.architectural_impact = changedFiles.length > 10 ? 'high'
|
||||||
|
: indexChanges.length > 0 || pkgChanges.length > 0 ? 'medium' : 'low'
|
||||||
|
```
|
||||||
|
|
||||||
|
### consult (ARCH-CONSULT-*)
|
||||||
|
|
||||||
|
回答架构决策咨询。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const question = task.description
|
||||||
|
.replace(/Session:.*\n?/g, '')
|
||||||
|
.replace(/Requester:.*\n?/g, '')
|
||||||
|
.trim()
|
||||||
|
|
||||||
|
const isComplex = question.length > 200 ||
|
||||||
|
/architect|design|pattern|refactor|migrate|scalab/i.test(question)
|
||||||
|
|
||||||
|
if (isComplex) {
|
||||||
|
// Use cli-explore-agent for deep exploration
|
||||||
|
Task({
|
||||||
|
subagent_type: "cli-explore-agent",
|
||||||
|
run_in_background: false,
|
||||||
|
description: `Architecture consultation: ${question.substring(0, 80)}`,
|
||||||
|
prompt: `## Architecture Consultation
|
||||||
|
|
||||||
|
Question: ${question}
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
1. Run: ccw tool exec get_modules_by_depth '{}'
|
||||||
|
2. Search for relevant architectural patterns in codebase
|
||||||
|
3. Read .workflow/project-tech.json (if exists)
|
||||||
|
4. Analyze architectural implications
|
||||||
|
|
||||||
|
## Output
|
||||||
|
Write to: ${sessionFolder}/architecture/consult-exploration.json
|
||||||
|
Schema: { relevant_files[], patterns[], architectural_implications[], options[] }`
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parse exploration results into assessment
|
||||||
|
try {
|
||||||
|
const exploration = JSON.parse(Read(`${sessionFolder}/architecture/consult-exploration.json`))
|
||||||
|
assessment.recommendations = (exploration.options || []).map(opt => ({
|
||||||
|
area: 'architecture',
|
||||||
|
suggestion: `${opt.name}: ${opt.description}`,
|
||||||
|
trade_offs: opt.trade_offs || []
|
||||||
|
}))
|
||||||
|
} catch {}
|
||||||
|
} else {
|
||||||
|
// Simple consultation — direct analysis
|
||||||
|
assessment.recommendations.push({
|
||||||
|
area: 'architecture',
|
||||||
|
suggestion: `Direct answer based on codebase context and wisdom`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### feasibility (ARCH-FEASIBILITY-*)
|
||||||
|
|
||||||
|
技术可行性评估。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const proposal = task.description
|
||||||
|
.replace(/Session:.*\n?/g, '')
|
||||||
|
.replace(/Requester:.*\n?/g, '')
|
||||||
|
.trim()
|
||||||
|
|
||||||
|
// 1. Tech stack compatibility
|
||||||
|
const techStack = projectTech?.tech_stack || {}
|
||||||
|
// Check if proposal requires technologies not in current stack
|
||||||
|
|
||||||
|
// 2. Codebase readiness
|
||||||
|
// Use ACE search to find relevant integration points
|
||||||
|
const searchResults = mcp__ace-tool__search_context({
|
||||||
|
project_root_path: '.',
|
||||||
|
query: proposal
|
||||||
|
})
|
||||||
|
|
||||||
|
// 3. Effort estimation
|
||||||
|
const touchPoints = (searchResults?.relevant_files || []).length
|
||||||
|
const effort = touchPoints > 20 ? 'high' : touchPoints > 5 ? 'medium' : 'low'
|
||||||
|
|
||||||
|
// 4. Risk assessment
|
||||||
|
assessment.verdict = 'FEASIBLE' // FEASIBLE | RISKY | INFEASIBLE
|
||||||
|
assessment.effort_estimate = effort
|
||||||
|
assessment.prerequisites = []
|
||||||
|
assessment.risks = []
|
||||||
|
|
||||||
|
if (touchPoints > 20) {
|
||||||
|
assessment.verdict = 'RISKY'
|
||||||
|
assessment.risks.push({
|
||||||
|
risk: 'High touch-point count suggests significant refactoring',
|
||||||
|
mitigation: 'Phase the implementation, start with core module'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verdict Logic
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function determineVerdict(assessment) {
|
||||||
|
const highConcerns = (assessment.concerns || []).filter(c => c.severity === 'high')
|
||||||
|
const mediumConcerns = (assessment.concerns || []).filter(c => c.severity === 'medium')
|
||||||
|
|
||||||
|
if (highConcerns.length >= 2) return 'BLOCK'
|
||||||
|
if (highConcerns.length >= 1 || mediumConcerns.length >= 3) return 'CONCERN'
|
||||||
|
return 'APPROVE'
|
||||||
|
}
|
||||||
|
|
||||||
|
assessment.overall_verdict = determineVerdict(assessment)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
| Scenario | Resolution |
|
||||||
|
|----------|------------|
|
||||||
|
| Architecture docs not found | Assess from available context, note limitation in report |
|
||||||
|
| Plan file missing | Report to coordinator via arch_concern |
|
||||||
|
| Git diff fails (no commits) | Use staged changes or skip code-review mode |
|
||||||
|
| CLI exploration timeout | Provide partial assessment, flag as incomplete |
|
||||||
|
| Exploration results unparseable | Fall back to direct analysis without exploration |
|
||||||
368
.claude/skills/team-lifecycle-v2/roles/architect/role.md
Normal file
368
.claude/skills/team-lifecycle-v2/roles/architect/role.md
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
# Role: architect
|
||||||
|
|
||||||
|
架构顾问。提供架构决策咨询、技术可行性评估、设计模式建议。咨询角色,在 spec 和 impl 流程关键节点提供专业判断。
|
||||||
|
|
||||||
|
## Role Identity
|
||||||
|
|
||||||
|
- **Name**: `architect`
|
||||||
|
- **Task Prefix**: `ARCH-*`
|
||||||
|
- **Responsibility**: Context loading → Mode detection → Architecture analysis → Package assessment → Report
|
||||||
|
- **Communication**: SendMessage to coordinator only
|
||||||
|
- **Output Tag**: `[architect]`
|
||||||
|
- **Role Type**: Consulting(咨询角色,不阻塞主链路,输出被引用)
|
||||||
|
|
||||||
|
## Role Boundaries
|
||||||
|
|
||||||
|
### MUST
|
||||||
|
|
||||||
|
- 仅处理 `ARCH-*` 前缀的任务
|
||||||
|
- 所有输出(SendMessage、team_msg、日志)必须带 `[architect]` 标识
|
||||||
|
- 仅通过 SendMessage 与 coordinator 通信
|
||||||
|
- 输出结构化评估报告供调用方消费
|
||||||
|
- 根据任务前缀自动切换咨询模式
|
||||||
|
|
||||||
|
### MUST NOT
|
||||||
|
|
||||||
|
- ❌ 直接修改源代码文件
|
||||||
|
- ❌ 执行需求分析、代码实现、测试等其他角色职责
|
||||||
|
- ❌ 直接与其他 worker 角色通信
|
||||||
|
- ❌ 为其他角色创建任务
|
||||||
|
- ❌ 做最终决策(仅提供建议,决策权在 coordinator/用户)
|
||||||
|
- ❌ 在输出中省略 `[architect]` 标识
|
||||||
|
|
||||||
|
## Message Types
|
||||||
|
|
||||||
|
| Type | Direction | Trigger | Description |
|
||||||
|
|------|-----------|---------|-------------|
|
||||||
|
| `arch_ready` | architect → coordinator | Consultation complete | 架构评估/建议已就绪 |
|
||||||
|
| `arch_concern` | architect → coordinator | Significant risk found | 发现重大架构风险 |
|
||||||
|
| `arch_progress` | architect → coordinator | Long analysis progress | 复杂分析进度更新 |
|
||||||
|
| `error` | architect → coordinator | Analysis failure | 分析失败或上下文不足 |
|
||||||
|
|
||||||
|
## Message Bus
|
||||||
|
|
||||||
|
每次 SendMessage **前**,必须调用 `mcp__ccw-tools__team_msg` 记录消息:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Consultation complete
|
||||||
|
mcp__ccw-tools__team_msg({
|
||||||
|
operation: "log", team: teamName,
|
||||||
|
from: "architect", to: "coordinator",
|
||||||
|
type: "arch_ready",
|
||||||
|
summary: "[architect] ARCH complete: 3 recommendations, 1 concern",
|
||||||
|
ref: outputPath
|
||||||
|
})
|
||||||
|
|
||||||
|
// Risk alert
|
||||||
|
mcp__ccw-tools__team_msg({
|
||||||
|
operation: "log", team: teamName,
|
||||||
|
from: "architect", to: "coordinator",
|
||||||
|
type: "arch_concern",
|
||||||
|
summary: "[architect] RISK: circular dependency in module graph"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### CLI 回退
|
||||||
|
|
||||||
|
当 `mcp__ccw-tools__team_msg` MCP 不可用时,使用 `ccw team` CLI 作为等效回退:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Bash(`ccw team log --team "${teamName}" --from "architect" --to "coordinator" --type "arch_ready" --summary "[architect] ARCH complete" --ref "${outputPath}" --json`)
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数映射**: `team_msg(params)` → `ccw team log --team <team> --from architect --to coordinator --type <type> --summary "<text>" [--ref <path>] [--json]`
|
||||||
|
|
||||||
|
## Toolbox
|
||||||
|
|
||||||
|
### Available Commands
|
||||||
|
- `commands/assess.md` — Multi-mode architecture assessment (Phase 3)
|
||||||
|
|
||||||
|
### Subagent Capabilities
|
||||||
|
|
||||||
|
| Agent Type | Used By | Purpose |
|
||||||
|
|------------|---------|---------|
|
||||||
|
| `cli-explore-agent` | commands/assess.md | 深度架构探索(模块依赖、分层结构) |
|
||||||
|
|
||||||
|
### CLI Capabilities
|
||||||
|
|
||||||
|
| CLI Tool | Mode | Used By | Purpose |
|
||||||
|
|----------|------|---------|---------|
|
||||||
|
| `ccw cli --tool gemini --mode analysis` | analysis | commands/assess.md | 架构分析、模式评估 |
|
||||||
|
|
||||||
|
## Consultation Modes
|
||||||
|
|
||||||
|
根据任务 subject 前缀自动切换:
|
||||||
|
|
||||||
|
| Mode | Task Pattern | Focus | Output |
|
||||||
|
|------|-------------|-------|--------|
|
||||||
|
| `spec-review` | ARCH-SPEC-* | 审查架构文档(ADR、组件图) | 架构评审报告 |
|
||||||
|
| `plan-review` | ARCH-PLAN-* | 审查实现计划的架构合理性 | 计划评审意见 |
|
||||||
|
| `code-review` | ARCH-CODE-* | 评估代码变更的架构影响 | 架构影响分析 |
|
||||||
|
| `consult` | ARCH-CONSULT-* | 回答架构决策咨询 | 决策建议 |
|
||||||
|
| `feasibility` | ARCH-FEASIBILITY-* | 技术可行性评估 | 可行性报告 |
|
||||||
|
|
||||||
|
## Execution (5-Phase)
|
||||||
|
|
||||||
|
### Phase 1: Task Discovery
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const tasks = TaskList()
|
||||||
|
const myTasks = tasks.filter(t =>
|
||||||
|
t.subject.startsWith('ARCH-') &&
|
||||||
|
t.owner === 'architect' &&
|
||||||
|
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 & Mode Detection
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const sessionFolder = task.description.match(/Session:\s*([^\n]+)/)?.[1]?.trim()
|
||||||
|
|
||||||
|
// Auto-detect consultation mode from task subject
|
||||||
|
const MODE_MAP = {
|
||||||
|
'ARCH-SPEC': 'spec-review',
|
||||||
|
'ARCH-PLAN': 'plan-review',
|
||||||
|
'ARCH-CODE': 'code-review',
|
||||||
|
'ARCH-CONSULT': 'consult',
|
||||||
|
'ARCH-FEASIBILITY': 'feasibility'
|
||||||
|
}
|
||||||
|
const modePrefix = Object.keys(MODE_MAP).find(p => task.subject.startsWith(p))
|
||||||
|
const consultMode = modePrefix ? MODE_MAP[modePrefix] : 'consult'
|
||||||
|
|
||||||
|
// Load wisdom (accumulated knowledge from previous tasks)
|
||||||
|
let wisdom = {}
|
||||||
|
if (sessionFolder) {
|
||||||
|
try { wisdom.learnings = Read(`${sessionFolder}/wisdom/learnings.md`) } catch {}
|
||||||
|
try { wisdom.decisions = Read(`${sessionFolder}/wisdom/decisions.md`) } catch {}
|
||||||
|
try { wisdom.conventions = Read(`${sessionFolder}/wisdom/conventions.md`) } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load project tech context
|
||||||
|
let projectTech = {}
|
||||||
|
try { projectTech = JSON.parse(Read('.workflow/project-tech.json')) } catch {}
|
||||||
|
|
||||||
|
// Load exploration results if available
|
||||||
|
let explorations = []
|
||||||
|
if (sessionFolder) {
|
||||||
|
try {
|
||||||
|
const exploreFiles = Glob({ pattern: `${sessionFolder}/explorations/*.json` })
|
||||||
|
explorations = exploreFiles.map(f => {
|
||||||
|
try { return JSON.parse(Read(f)) } catch { return null }
|
||||||
|
}).filter(Boolean)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Architecture Assessment
|
||||||
|
|
||||||
|
Delegate to command file for mode-specific analysis:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
const assessCommand = Read("commands/assess.md")
|
||||||
|
// Execute mode-specific strategy defined in command file
|
||||||
|
// Input: consultMode, sessionFolder, wisdom, explorations, projectTech
|
||||||
|
// Output: assessment object
|
||||||
|
} catch {
|
||||||
|
// Fallback: inline execution (see below)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Command**: [commands/assess.md](commands/assess.md)
|
||||||
|
|
||||||
|
**Inline Fallback** (when command file unavailable):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const assessment = {
|
||||||
|
mode: consultMode,
|
||||||
|
overall_verdict: 'APPROVE', // APPROVE | CONCERN | BLOCK
|
||||||
|
dimensions: [],
|
||||||
|
concerns: [],
|
||||||
|
recommendations: [],
|
||||||
|
_metadata: { timestamp: new Date().toISOString(), wisdom_loaded: Object.keys(wisdom).length > 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode-specific analysis
|
||||||
|
if (consultMode === 'spec-review') {
|
||||||
|
// Load architecture documents, check ADR consistency, scalability, security
|
||||||
|
const archIndex = Read(`${sessionFolder}/spec/architecture/_index.md`)
|
||||||
|
const adrFiles = Glob({ pattern: `${sessionFolder}/spec/architecture/ADR-*.md` })
|
||||||
|
// Score dimensions: consistency, scalability, security, tech-fitness
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consultMode === 'plan-review') {
|
||||||
|
// Load plan.json, check task granularity, dependency cycles, convention compliance
|
||||||
|
const plan = JSON.parse(Read(`${sessionFolder}/plan/plan.json`))
|
||||||
|
// Detect circular dependencies, oversized tasks, missing risk assessment
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consultMode === 'code-review') {
|
||||||
|
// Analyze changed files for layer violations, new deps, module boundary changes
|
||||||
|
const changedFiles = Bash(`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached`)
|
||||||
|
.split('\n').filter(Boolean)
|
||||||
|
// Check import depth, package.json changes, index.ts modifications
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consultMode === 'consult') {
|
||||||
|
// Free-form consultation — use CLI for complex questions
|
||||||
|
const question = task.description.replace(/Session:.*\n?/g, '').replace(/Requester:.*\n?/g, '').trim()
|
||||||
|
const isComplex = question.length > 200 || /architect|design|pattern|refactor|migrate/i.test(question)
|
||||||
|
if (isComplex) {
|
||||||
|
Bash({
|
||||||
|
command: `ccw cli -p "PURPOSE: Architecture consultation — ${question}
|
||||||
|
TASK: • Analyze architectural implications • Identify options with trade-offs • Recommend approach
|
||||||
|
MODE: analysis
|
||||||
|
CONTEXT: @**/*
|
||||||
|
EXPECTED: Structured analysis with options, trade-offs, recommendation
|
||||||
|
CONSTRAINTS: Architecture-level only" --tool gemini --mode analysis --rule analysis-review-architecture`,
|
||||||
|
run_in_background: true
|
||||||
|
})
|
||||||
|
// Wait for result, parse into assessment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consultMode === 'feasibility') {
|
||||||
|
// Assess technical feasibility against current codebase
|
||||||
|
// Output: verdict (FEASIBLE|RISKY|INFEASIBLE), risks, effort estimate, prerequisites
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Package & Wisdom Contribution
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Write assessment to session
|
||||||
|
const outputPath = sessionFolder
|
||||||
|
? `${sessionFolder}/architecture/arch-${task.subject.replace(/[^a-zA-Z0-9-]/g, '-').toLowerCase()}.json`
|
||||||
|
: '.workflow/.tmp/arch-assessment.json'
|
||||||
|
|
||||||
|
Bash(`mkdir -p "$(dirname '${outputPath}')"`)
|
||||||
|
Write(outputPath, JSON.stringify(assessment, null, 2))
|
||||||
|
|
||||||
|
// Contribute to wisdom: record architectural decisions
|
||||||
|
if (sessionFolder && assessment.recommendations?.length > 0) {
|
||||||
|
try {
|
||||||
|
const decisionsPath = `${sessionFolder}/wisdom/decisions.md`
|
||||||
|
const existing = Read(decisionsPath)
|
||||||
|
const newDecisions = assessment.recommendations
|
||||||
|
.map(r => `- [${new Date().toISOString().substring(0, 10)}] ${r.area || r.dimension}: ${r.suggestion}`)
|
||||||
|
.join('\n')
|
||||||
|
Write(decisionsPath, existing + '\n' + newDecisions)
|
||||||
|
} catch {} // wisdom not initialized
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 5: Report to Coordinator
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const verdict = assessment.overall_verdict || assessment.verdict || 'N/A'
|
||||||
|
const concernCount = (assessment.concerns || []).length
|
||||||
|
const highConcerns = (assessment.concerns || []).filter(c => c.severity === 'high').length
|
||||||
|
const recCount = (assessment.recommendations || []).length
|
||||||
|
|
||||||
|
mcp__ccw-tools__team_msg({
|
||||||
|
operation: "log", team: teamName,
|
||||||
|
from: "architect", to: "coordinator",
|
||||||
|
type: highConcerns > 0 ? "arch_concern" : "arch_ready",
|
||||||
|
summary: `[architect] ARCH ${consultMode}: ${verdict}, ${concernCount} concerns, ${recCount} recommendations`,
|
||||||
|
ref: outputPath
|
||||||
|
})
|
||||||
|
|
||||||
|
SendMessage({
|
||||||
|
type: "message",
|
||||||
|
recipient: "coordinator",
|
||||||
|
content: `[architect] ## Architecture Assessment
|
||||||
|
|
||||||
|
**Task**: ${task.subject}
|
||||||
|
**Mode**: ${consultMode}
|
||||||
|
**Verdict**: ${verdict}
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
- **Concerns**: ${concernCount} (${highConcerns} high)
|
||||||
|
- **Recommendations**: ${recCount}
|
||||||
|
${assessment.architectural_impact ? `- **Impact**: ${assessment.architectural_impact}` : ''}
|
||||||
|
|
||||||
|
${assessment.dimensions?.length > 0 ? `### Dimension Scores
|
||||||
|
${assessment.dimensions.map(d => `- **${d.name}**: ${d.score}%`).join('\n')}` : ''}
|
||||||
|
|
||||||
|
${concernCount > 0 ? `### Concerns
|
||||||
|
${assessment.concerns.map(c => `- [${(c.severity || 'medium').toUpperCase()}] ${c.task || c.file || ''}: ${c.concern}`).join('\n')}` : ''}
|
||||||
|
|
||||||
|
### Recommendations
|
||||||
|
${(assessment.recommendations || []).map(r => `- ${r.area || r.dimension || ''}: ${r.suggestion}`).join('\n') || 'None'}
|
||||||
|
|
||||||
|
### Output: ${outputPath}`,
|
||||||
|
summary: `[architect] ARCH ${consultMode}: ${verdict}`
|
||||||
|
})
|
||||||
|
|
||||||
|
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||||
|
|
||||||
|
// Check for next ARCH task → back to Phase 1
|
||||||
|
const nextTasks = TaskList().filter(t =>
|
||||||
|
t.subject.startsWith('ARCH-') &&
|
||||||
|
t.owner === 'architect' &&
|
||||||
|
t.status === 'pending' &&
|
||||||
|
t.blockedBy.length === 0
|
||||||
|
)
|
||||||
|
if (nextTasks.length > 0) {
|
||||||
|
// Continue → back to Phase 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Coordinator Integration
|
||||||
|
|
||||||
|
Architect 由 coordinator 在关键节点按需创建 ARCH-* 任务:
|
||||||
|
|
||||||
|
### Spec Pipeline (after DRAFT-003, before DISCUSS-004)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
TaskCreate({
|
||||||
|
subject: 'ARCH-SPEC-001: 架构文档专业评审',
|
||||||
|
description: `评审架构文档的技术合理性\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/spec/architecture/`,
|
||||||
|
activeForm: '架构评审中'
|
||||||
|
})
|
||||||
|
TaskUpdate({ taskId: archSpecId, owner: 'architect' })
|
||||||
|
// DISCUSS-004 addBlockedBy [archSpecId]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Impl Pipeline (after PLAN-001, before IMPL-001)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
TaskCreate({
|
||||||
|
subject: 'ARCH-PLAN-001: 实现计划架构审查',
|
||||||
|
description: `审查实现计划的架构合理性\n\nSession: ${sessionFolder}\nPlan: ${sessionFolder}/plan/plan.json`,
|
||||||
|
activeForm: '计划审查中'
|
||||||
|
})
|
||||||
|
TaskUpdate({ taskId: archPlanId, owner: 'architect' })
|
||||||
|
// IMPL-001 addBlockedBy [archPlanId]
|
||||||
|
```
|
||||||
|
|
||||||
|
### On-Demand (any point via coordinator)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
TaskCreate({
|
||||||
|
subject: 'ARCH-CONSULT-001: 架构决策咨询',
|
||||||
|
description: `${question}\n\nSession: ${sessionFolder}\nRequester: ${role}`,
|
||||||
|
activeForm: '架构咨询中'
|
||||||
|
})
|
||||||
|
TaskUpdate({ taskId: archConsultId, owner: 'architect' })
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
| Scenario | Resolution |
|
||||||
|
|----------|------------|
|
||||||
|
| No ARCH-* tasks available | Idle, wait for coordinator assignment |
|
||||||
|
| Architecture documents not found | Assess from available context, note limitation |
|
||||||
|
| Plan file not found | Report to coordinator, request location |
|
||||||
|
| CLI analysis timeout | Provide partial assessment, note incomplete |
|
||||||
|
| Insufficient context | Request explorer to gather more context via coordinator |
|
||||||
|
| Conflicting requirements | Flag as concern, provide options |
|
||||||
|
| Command file not found | Fall back to inline execution |
|
||||||
|
| Unexpected error | Log error via team_msg, report to coordinator |
|
||||||
@@ -366,6 +366,14 @@ TeamCreate({
|
|||||||
|
|
||||||
Output(`[coordinator] Team created: ${teamId}`)
|
Output(`[coordinator] Team created: ${teamId}`)
|
||||||
|
|
||||||
|
// Initialize wisdom directory
|
||||||
|
const wisdomDir = `${sessionFolder}/wisdom`
|
||||||
|
Bash(`mkdir -p "${wisdomDir}"`)
|
||||||
|
Write(`${wisdomDir}/learnings.md`, `# Learnings\n\n<!-- Auto-accumulated by team roles -->\n`)
|
||||||
|
Write(`${wisdomDir}/decisions.md`, `# Decisions\n\n<!-- Architectural and design decisions -->\n`)
|
||||||
|
Write(`${wisdomDir}/conventions.md`, `# Conventions\n\n<!-- Codebase conventions discovered -->\n<!-- explorer-patterns -->\n`)
|
||||||
|
Write(`${wisdomDir}/issues.md`, `# Known Issues\n\n<!-- Risks and issues found during execution -->\n`)
|
||||||
|
|
||||||
// Initialize session file
|
// Initialize session file
|
||||||
const sessionFile = `D:/Claude_dms3/.workflow/.sessions/${sessionId}.json`
|
const sessionFile = `D:/Claude_dms3/.workflow/.sessions/${sessionId}.json`
|
||||||
const sessionData = {
|
const sessionData = {
|
||||||
|
|||||||
301
.claude/skills/team-lifecycle-v2/roles/explorer/role.md
Normal file
301
.claude/skills/team-lifecycle-v2/roles/explorer/role.md
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
# Explorer Role
|
||||||
|
|
||||||
|
专职代码搜索与模式发现。服务角色,被 analyst/planner/executor/discussant 按需调用。
|
||||||
|
|
||||||
|
## 1. Role Identity
|
||||||
|
|
||||||
|
- **Name**: explorer
|
||||||
|
- **Task Prefix**: EXPLORE-*
|
||||||
|
- **Output Tag**: `[explorer]`
|
||||||
|
- **Role Type**: Service(按需调用,不占主链路位置)
|
||||||
|
- **Responsibility**: Parse request → Multi-strategy search → Dependency trace → Package results → Report
|
||||||
|
|
||||||
|
## 2. Role Boundaries
|
||||||
|
|
||||||
|
### MUST
|
||||||
|
- Only process EXPLORE-* tasks
|
||||||
|
- Output structured JSON for downstream consumption
|
||||||
|
- Use priority-ordered search strategies (ACE → Grep → cli-explore-agent)
|
||||||
|
- Tag all outputs with `[explorer]`
|
||||||
|
- Cache results in `{session}/explorations/` for cross-role reuse
|
||||||
|
|
||||||
|
### MUST NOT
|
||||||
|
- Create tasks
|
||||||
|
- Contact other workers directly
|
||||||
|
- Modify any source code files
|
||||||
|
- Execute analysis, planning, or implementation
|
||||||
|
- Make architectural decisions (only discover patterns)
|
||||||
|
|
||||||
|
## 3. Message Types
|
||||||
|
|
||||||
|
| Type | Direction | Purpose | Format |
|
||||||
|
|------|-----------|---------|--------|
|
||||||
|
| `explore_ready` | TO coordinator | Search complete | `{ type: "explore_ready", task_id, file_count, pattern_count, output_path }` |
|
||||||
|
| `explore_progress` | TO coordinator | Multi-angle progress | `{ type: "explore_progress", task_id, angle, status }` |
|
||||||
|
| `task_failed` | TO coordinator | Search failure | `{ type: "task_failed", task_id, error, fallback_used }` |
|
||||||
|
|
||||||
|
## 4. Message Bus
|
||||||
|
|
||||||
|
**Primary**: Use `team_msg` for all coordinator communication with `[explorer]` tag:
|
||||||
|
```javascript
|
||||||
|
team_msg({
|
||||||
|
to: "coordinator",
|
||||||
|
type: "explore_ready",
|
||||||
|
task_id: "EXPLORE-001",
|
||||||
|
file_count: 15,
|
||||||
|
pattern_count: 3,
|
||||||
|
output_path: `${sessionFolder}/explorations/explore-001.json`
|
||||||
|
}, "[explorer]")
|
||||||
|
```
|
||||||
|
|
||||||
|
**CLI Fallback**: When message bus unavailable:
|
||||||
|
```bash
|
||||||
|
ccw team log --team "${teamName}" --from "explorer" --to "coordinator" --type "explore_ready" --summary "[explorer] 15 files, 3 patterns" --json
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Toolbox
|
||||||
|
|
||||||
|
### Available Commands
|
||||||
|
- None (inline execution, search logic is straightforward)
|
||||||
|
|
||||||
|
### Search Tools (priority order)
|
||||||
|
|
||||||
|
| Tool | Priority | Use Case |
|
||||||
|
|------|----------|----------|
|
||||||
|
| `mcp__ace-tool__search_context` | P0 | Semantic code search |
|
||||||
|
| `Grep` / `Glob` | P1 | Pattern matching, file discovery |
|
||||||
|
| `Read` | P1 | File content reading |
|
||||||
|
| `Bash` (rg, find) | P2 | Structured search fallback |
|
||||||
|
| `WebSearch` | P3 | External docs/best practices |
|
||||||
|
|
||||||
|
### Subagent Capabilities
|
||||||
|
- `cli-explore-agent` — Deep multi-angle codebase exploration
|
||||||
|
|
||||||
|
## 6. Execution (5-Phase)
|
||||||
|
|
||||||
|
### Phase 1: Task Discovery & Request Parsing
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const tasks = TaskList()
|
||||||
|
const myTasks = tasks.filter(t =>
|
||||||
|
t.subject.startsWith('EXPLORE-') &&
|
||||||
|
t.owner === 'explorer' &&
|
||||||
|
t.status === 'pending' &&
|
||||||
|
t.blockedBy.length === 0
|
||||||
|
)
|
||||||
|
if (myTasks.length === 0) return
|
||||||
|
const task = TaskGet({ taskId: myTasks[0].id })
|
||||||
|
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||||
|
|
||||||
|
// Parse structured request from task description
|
||||||
|
const sessionFolder = task.description.match(/Session:\s*([^\n]+)/)?.[1]?.trim()
|
||||||
|
const exploreMode = task.description.match(/Mode:\s*([^\n]+)/)?.[1]?.trim() || 'codebase'
|
||||||
|
const angles = (task.description.match(/Angles:\s*([^\n]+)/)?.[1] || 'general').split(',').map(a => a.trim())
|
||||||
|
const keywords = (task.description.match(/Keywords:\s*([^\n]+)/)?.[1] || '').split(',').map(k => k.trim()).filter(Boolean)
|
||||||
|
const requester = task.description.match(/Requester:\s*([^\n]+)/)?.[1]?.trim() || 'coordinator'
|
||||||
|
|
||||||
|
const outputDir = sessionFolder ? `${sessionFolder}/explorations` : '.workflow/.tmp'
|
||||||
|
Bash(`mkdir -p "${outputDir}"`)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Multi-Strategy Search
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const findings = {
|
||||||
|
relevant_files: [], // { path, rationale, role, discovery_source, key_symbols }
|
||||||
|
patterns: [], // { name, description, files }
|
||||||
|
dependencies: [], // { file, imports[] }
|
||||||
|
external_refs: [], // { keyword, results[] }
|
||||||
|
_metadata: { angles, mode: exploreMode, requester, timestamp: new Date().toISOString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Strategy 1: ACE Semantic Search (P0) ===
|
||||||
|
if (exploreMode !== 'external') {
|
||||||
|
for (const kw of keywords) {
|
||||||
|
try {
|
||||||
|
const results = mcp__ace-tool__search_context({ project_root_path: '.', query: kw })
|
||||||
|
// Deduplicate and add to findings.relevant_files with discovery_source: 'ace-search'
|
||||||
|
} catch { /* ACE unavailable, fall through */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Strategy 2: Grep Pattern Scan (P1) ===
|
||||||
|
if (exploreMode !== 'external') {
|
||||||
|
for (const kw of keywords) {
|
||||||
|
// Find imports/exports/definitions
|
||||||
|
const defResults = Grep({
|
||||||
|
pattern: `(class|function|const|export|interface|type)\\s+.*${kw}`,
|
||||||
|
glob: '*.{ts,tsx,js,jsx,py,go,rs}',
|
||||||
|
'-n': true, output_mode: 'content'
|
||||||
|
})
|
||||||
|
// Add to findings with discovery_source: 'grep-scan'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Strategy 3: Dependency Tracing ===
|
||||||
|
if (exploreMode !== 'external') {
|
||||||
|
for (const file of findings.relevant_files.slice(0, 10)) {
|
||||||
|
try {
|
||||||
|
const content = Read(file.path)
|
||||||
|
const imports = (content.match(/from\s+['"]([^'"]+)['"]/g) || [])
|
||||||
|
.map(i => i.match(/['"]([^'"]+)['"]/)?.[1]).filter(Boolean)
|
||||||
|
if (imports.length > 0) {
|
||||||
|
findings.dependencies.push({ file: file.path, imports })
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Strategy 4: Deep Exploration (multi-angle, via cli-explore-agent) ===
|
||||||
|
if (angles.length > 1 && exploreMode !== 'external') {
|
||||||
|
for (const angle of angles) {
|
||||||
|
Task({
|
||||||
|
subagent_type: "cli-explore-agent",
|
||||||
|
run_in_background: false,
|
||||||
|
description: `Explore: ${angle}`,
|
||||||
|
prompt: `## Exploration: ${angle} angle
|
||||||
|
Keywords: ${keywords.join(', ')}
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
1. rg -l "${keywords[0]}" --type-add 'code:*.{ts,tsx,js,py,go,rs}' --type code
|
||||||
|
2. Read .workflow/project-tech.json (if exists)
|
||||||
|
3. Focus on ${angle} perspective
|
||||||
|
|
||||||
|
## Output
|
||||||
|
Write to: ${outputDir}/exploration-${angle}.json
|
||||||
|
Schema: { relevant_files[], patterns[], dependencies[] }`
|
||||||
|
})
|
||||||
|
// Merge angle results into main findings
|
||||||
|
try {
|
||||||
|
const angleData = JSON.parse(Read(`${outputDir}/exploration-${angle}.json`))
|
||||||
|
findings.relevant_files.push(...(angleData.relevant_files || []))
|
||||||
|
findings.patterns.push(...(angleData.patterns || []))
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Strategy 5: External Search (P3) ===
|
||||||
|
if (exploreMode === 'external' || exploreMode === 'hybrid') {
|
||||||
|
for (const kw of keywords.slice(0, 3)) {
|
||||||
|
try {
|
||||||
|
const results = WebSearch({ query: `${kw} best practices documentation` })
|
||||||
|
findings.external_refs.push({ keyword: kw, results })
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduplicate relevant_files by path
|
||||||
|
const seen = new Set()
|
||||||
|
findings.relevant_files = findings.relevant_files.filter(f => {
|
||||||
|
if (seen.has(f.path)) return false
|
||||||
|
seen.add(f.path)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Wisdom Contribution
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// If wisdom directory exists, contribute discovered patterns
|
||||||
|
if (sessionFolder) {
|
||||||
|
try {
|
||||||
|
const conventionsPath = `${sessionFolder}/wisdom/conventions.md`
|
||||||
|
const existing = Read(conventionsPath)
|
||||||
|
if (findings.patterns.length > 0) {
|
||||||
|
const newPatterns = findings.patterns
|
||||||
|
.map(p => `- ${p.name}: ${p.description || ''}`)
|
||||||
|
.join('\n')
|
||||||
|
Edit({
|
||||||
|
file_path: conventionsPath,
|
||||||
|
old_string: '<!-- explorer-patterns -->',
|
||||||
|
new_string: `<!-- explorer-patterns -->\n${newPatterns}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch {} // wisdom not initialized
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Package Results
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const outputPath = `${outputDir}/explore-${task.subject.replace(/[^a-zA-Z0-9-]/g, '-').toLowerCase()}.json`
|
||||||
|
Write(outputPath, JSON.stringify(findings, null, 2))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 5: Report to Coordinator
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const summary = `${findings.relevant_files.length} files, ${findings.patterns.length} patterns, ${findings.dependencies.length} deps`
|
||||||
|
|
||||||
|
mcp__ccw-tools__team_msg({
|
||||||
|
operation: "log", team: teamName,
|
||||||
|
from: "explorer", to: "coordinator",
|
||||||
|
type: "explore_ready",
|
||||||
|
summary: `[explorer] EXPLORE complete: ${summary}`,
|
||||||
|
ref: outputPath
|
||||||
|
})
|
||||||
|
|
||||||
|
SendMessage({
|
||||||
|
type: "message",
|
||||||
|
recipient: "coordinator",
|
||||||
|
content: `[explorer] ## Exploration Results
|
||||||
|
|
||||||
|
**Task**: ${task.subject}
|
||||||
|
**Mode**: ${exploreMode} | **Angles**: ${angles.join(', ')} | **Requester**: ${requester}
|
||||||
|
|
||||||
|
### Files: ${findings.relevant_files.length}
|
||||||
|
${findings.relevant_files.slice(0, 8).map(f => `- \`${f.path}\` (${f.role}) — ${f.rationale}`).join('\n')}
|
||||||
|
|
||||||
|
### Patterns: ${findings.patterns.length}
|
||||||
|
${findings.patterns.slice(0, 5).map(p => `- ${p.name}: ${p.description || ''}`).join('\n') || 'None'}
|
||||||
|
|
||||||
|
### Output: ${outputPath}`,
|
||||||
|
summary: `[explorer] ${summary}`
|
||||||
|
})
|
||||||
|
|
||||||
|
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||||
|
// Check for next EXPLORE task → back to Phase 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Coordinator Integration
|
||||||
|
|
||||||
|
Explorer 是服务角色,coordinator 在以下场景按需创建 EXPLORE-* 任务:
|
||||||
|
|
||||||
|
| Trigger | Task Example | Requester |
|
||||||
|
|---------|-------------|-----------|
|
||||||
|
| RESEARCH-001 需要代码库上下文 | `EXPLORE-001: 代码库上下文搜索` | analyst |
|
||||||
|
| PLAN-001 需要多角度探索 | `EXPLORE-002: 实现相关代码探索` | planner |
|
||||||
|
| DISCUSS-004 需要外部最佳实践 | `EXPLORE-003: 外部文档搜索` | discussant |
|
||||||
|
| IMPL-001 遇到未知代码 | `EXPLORE-004: 依赖追踪` | executor |
|
||||||
|
|
||||||
|
**Task Description Template**:
|
||||||
|
```
|
||||||
|
搜索描述
|
||||||
|
|
||||||
|
Session: {sessionFolder}
|
||||||
|
Mode: codebase|external|hybrid
|
||||||
|
Angles: architecture,patterns,dependencies
|
||||||
|
Keywords: auth,middleware,session
|
||||||
|
Requester: analyst
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Result Caching
|
||||||
|
|
||||||
|
```
|
||||||
|
{sessionFolder}/explorations/
|
||||||
|
├── explore-explore-001-*.json # Consolidated results
|
||||||
|
├── exploration-architecture.json # Angle-specific (from cli-explore-agent)
|
||||||
|
└── exploration-patterns.json
|
||||||
|
```
|
||||||
|
|
||||||
|
后续角色 Phase 2 可直接读取已有探索结果,避免重复搜索。
|
||||||
|
|
||||||
|
## 9. Error Handling
|
||||||
|
|
||||||
|
| Error Type | Recovery Strategy | Escalation |
|
||||||
|
|------------|-------------------|------------|
|
||||||
|
| ACE unavailable | Fallback to Grep + rg | Continue with degraded results |
|
||||||
|
| cli-explore-agent failure | Fallback to direct search | Report partial results |
|
||||||
|
| No results found | Report empty, suggest broader keywords | Coordinator decides |
|
||||||
|
| Web search fails | Skip external refs | Continue with codebase results |
|
||||||
|
| Session folder missing | Use .workflow/.tmp | Notify coordinator |
|
||||||
@@ -47,6 +47,19 @@
|
|||||||
"additional_prefixes": ["QUALITY"],
|
"additional_prefixes": ["QUALITY"],
|
||||||
"responsibility": "Code review (REVIEW-*) + Spec quality validation (QUALITY-*)",
|
"responsibility": "Code review (REVIEW-*) + Spec quality validation (QUALITY-*)",
|
||||||
"message_types": ["review_result", "quality_result", "fix_required", "error"]
|
"message_types": ["review_result", "quality_result", "fix_required", "error"]
|
||||||
|
},
|
||||||
|
"explorer": {
|
||||||
|
"task_prefix": "EXPLORE",
|
||||||
|
"responsibility": "Code search, pattern discovery, dependency tracing. Service role — on-demand by coordinator",
|
||||||
|
"role_type": "service",
|
||||||
|
"message_types": ["explore_ready", "explore_progress", "task_failed"]
|
||||||
|
},
|
||||||
|
"architect": {
|
||||||
|
"task_prefix": "ARCH",
|
||||||
|
"responsibility": "Architecture assessment, tech feasibility, design pattern review. Consulting role — on-demand by coordinator",
|
||||||
|
"role_type": "consulting",
|
||||||
|
"consultation_modes": ["spec-review", "plan-review", "code-review", "consult", "feasibility"],
|
||||||
|
"message_types": ["arch_ready", "arch_concern", "arch_progress", "error"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -77,6 +90,9 @@
|
|||||||
"spec": "spec/",
|
"spec": "spec/",
|
||||||
"discussions": "discussions/",
|
"discussions": "discussions/",
|
||||||
"plan": "plan/",
|
"plan": "plan/",
|
||||||
|
"explorations": "explorations/",
|
||||||
|
"architecture": "architecture/",
|
||||||
|
"wisdom": "wisdom/",
|
||||||
"messages": ".workflow/.team-msg/{team-name}/"
|
"messages": ".workflow/.team-msg/{team-name}/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user