mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -1,220 +0,0 @@
|
|||||||
---
|
|
||||||
name: team-command-designer
|
|
||||||
description: Design and generate team command .md files following established patterns (8 infrastructure patterns + 10 collaboration patterns with convergence control). Triggers on "design team command", "create team role", "new teammate".
|
|
||||||
allowed-tools: Task, AskUserQuestion, Read, Write, Bash, Glob, Grep
|
|
||||||
---
|
|
||||||
|
|
||||||
# Team Command Designer
|
|
||||||
|
|
||||||
Design and generate team command .md files following established patterns extracted from existing team commands (coordinate, plan, execute, test, review). Supports 10 collaboration patterns for diverse team interaction models.
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
```
|
|
||||||
Phase 0: Specification Study (Mandatory - read design patterns + collaboration patterns)
|
|
||||||
|
|
|
||||||
Phase 1: Requirements Collection -> role-config.json
|
|
||||||
|
|
|
||||||
Phase 2: Pattern Analysis -> applicable-patterns.json (infra + collaboration)
|
|
||||||
|
|
|
||||||
Phase 3: Command Generation -> {team-name}/{role-name}.md
|
|
||||||
|
|
|
||||||
Phase 4: Integration Verification -> integration-report.json
|
|
||||||
|
|
|
||||||
Phase 5: Validation -> validation-report.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Design Principles
|
|
||||||
|
|
||||||
1. **Pattern Compliance**: All generated commands must follow infrastructure + collaboration patterns
|
|
||||||
2. **Message Bus Integration**: Every command must include team_msg logging
|
|
||||||
3. **Task Lifecycle**: Standard TaskList -> TaskGet -> TaskUpdate flow
|
|
||||||
4. **Complexity-Adaptive**: Support direct execution and sub-agent delegation
|
|
||||||
5. **Five-Phase Execution**: Each command follows the 5-phase structure
|
|
||||||
6. **Convergence Control**: Every collaboration pattern has explicit convergence criteria
|
|
||||||
7. **Feedback Loops**: Every pattern has structured feedback mechanisms
|
|
||||||
8. **Composable Patterns**: Collaboration patterns can be combined for complex workflows
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Mandatory Prerequisites
|
|
||||||
|
|
||||||
> **Do NOT skip**: Before performing any operations, you **must** completely read the following documents.
|
|
||||||
|
|
||||||
### Specification Documents (Required Reading)
|
|
||||||
|
|
||||||
| Document | Purpose | When |
|
|
||||||
|----------|---------|------|
|
|
||||||
| [specs/team-design-patterns.md](specs/team-design-patterns.md) | Infrastructure patterns (8) + collaboration pattern index | **Must read before execution** |
|
|
||||||
| [specs/collaboration-patterns.md](specs/collaboration-patterns.md) | 10 collaboration patterns with convergence/feedback control | **Must read before execution** |
|
|
||||||
| [specs/quality-standards.md](specs/quality-standards.md) | Quality standards for generated team commands | Must read before generation |
|
|
||||||
|
|
||||||
### Template Files (Must read before generation)
|
|
||||||
|
|
||||||
| Document | Purpose |
|
|
||||||
|----------|---------|
|
|
||||||
| [templates/command-template.md](templates/command-template.md) | Team command .md file template with all required sections |
|
|
||||||
|
|
||||||
### Existing Team Commands (Reference)
|
|
||||||
|
|
||||||
| Document | Purpose |
|
|
||||||
|----------|---------|
|
|
||||||
| `.claude/commands/team/coordinate.md` | Coordinator pattern - orchestration, team lifecycle |
|
|
||||||
| `.claude/commands/team/plan.md` | Planner pattern - exploration, plan generation |
|
|
||||||
| `.claude/commands/team/execute.md` | Executor pattern - implementation, self-validation |
|
|
||||||
| `.claude/commands/team/test.md` | Tester pattern - adaptive test-fix cycle |
|
|
||||||
| `.claude/commands/team/review.md` | Reviewer pattern - multi-dimensional review |
|
|
||||||
| `.claude/commands/team/spec/` | Spec team folder - folder-based team example |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Execution Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
Input Parsing:
|
|
||||||
Parse $ARGUMENTS for role name and capabilities description
|
|
||||||
|
|
||||||
Phase 0: Specification Study (MANDATORY)
|
|
||||||
-> Refer to: specs/team-design-patterns.md, specs/collaboration-patterns.md, templates/command-template.md
|
|
||||||
- Read infrastructure patterns (Section A of team-design-patterns.md)
|
|
||||||
- Read collaboration patterns specification (collaboration-patterns.md)
|
|
||||||
- Read command template
|
|
||||||
- Read 1-2 existing team commands most similar to the new role
|
|
||||||
- Output: Internalized requirements (in-memory)
|
|
||||||
|
|
||||||
Phase 1: Requirements Collection
|
|
||||||
-> Refer to: phases/01-requirements-collection.md
|
|
||||||
- Collect team name (folder name) and role name
|
|
||||||
- Collect responsibilities, communication patterns
|
|
||||||
- Determine task prefix (e.g., PLAN-*, IMPL-*, ANALYZE-*)
|
|
||||||
- Select applicable tools and capabilities
|
|
||||||
- Output: role-config.json (includes team_name, skill_path, output_folder)
|
|
||||||
|
|
||||||
Phase 2: Pattern Analysis
|
|
||||||
-> Refer to: phases/02-pattern-analysis.md, specs/team-design-patterns.md
|
|
||||||
- Identify which existing command is most similar
|
|
||||||
- Select applicable design patterns
|
|
||||||
- Determine message types needed
|
|
||||||
- Map phase structure to role responsibilities
|
|
||||||
- Output: applicable-patterns.json
|
|
||||||
|
|
||||||
Phase 3: Command Generation
|
|
||||||
-> Refer to: phases/03-command-generation.md, templates/command-template.md
|
|
||||||
- Apply template with role-specific content
|
|
||||||
- Generate YAML front matter
|
|
||||||
- Generate message bus section
|
|
||||||
- Generate 5-phase execution process
|
|
||||||
- Generate implementation code
|
|
||||||
- Generate error handling table
|
|
||||||
- Output: {team-name}/{role-name}.md
|
|
||||||
|
|
||||||
Phase 4: Integration Verification
|
|
||||||
-> Refer to: phases/04-integration-verification.md
|
|
||||||
- Verify consistency with coordinate.md spawn patterns
|
|
||||||
- Check message type compatibility
|
|
||||||
- Verify task prefix uniqueness
|
|
||||||
- Ensure allowed-tools are sufficient
|
|
||||||
- Output: integration-report.json
|
|
||||||
|
|
||||||
Phase 5: Validation
|
|
||||||
-> Refer to: phases/05-validation.md, specs/quality-standards.md
|
|
||||||
- Check all required sections exist
|
|
||||||
- Verify message bus compliance
|
|
||||||
- Validate task lifecycle pattern
|
|
||||||
- Score against quality standards
|
|
||||||
- Output: validation-report.json + final {team-name}/{role-name}.md
|
|
||||||
```
|
|
||||||
|
|
||||||
## Directory Setup
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const timestamp = new Date().toISOString().slice(0,19).replace(/[-:T]/g, '');
|
|
||||||
const workDir = `.workflow/.scratchpad/team-cmd-${timestamp}`;
|
|
||||||
|
|
||||||
Bash(`mkdir -p "${workDir}"`);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
.workflow/.scratchpad/team-cmd-{timestamp}/
|
|
||||||
├── role-config.json # Phase 1 output (includes team_name)
|
|
||||||
├── applicable-patterns.json # Phase 2 output
|
|
||||||
├── integration-report.json # Phase 4 output
|
|
||||||
├── validation-report.json # Phase 5 output
|
|
||||||
└── {role-name}.md # Final generated command
|
|
||||||
|
|
||||||
Final delivery (folder-based):
|
|
||||||
.claude/commands/team/{team-name}/
|
|
||||||
├── {role-name}.md # e.g., coordinator.md, analyst.md
|
|
||||||
├── ... # Other roles in same team
|
|
||||||
└── (each team = one folder)
|
|
||||||
|
|
||||||
Skill path mapping:
|
|
||||||
.claude/commands/team/{team-name}/{role-name}.md → /team:{team-name}:{role-name}
|
|
||||||
Example: .claude/commands/team/spec/analyst.md → /team:spec:analyst
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Reference Documents by Phase
|
|
||||||
|
|
||||||
### Phase 0: Specification Study
|
|
||||||
|
|
||||||
| Document | Purpose | When to Use |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| [specs/team-design-patterns.md](specs/team-design-patterns.md) | Team command design patterns | Understand all required patterns **Required Reading** |
|
|
||||||
| [templates/command-template.md](templates/command-template.md) | Command file template | Understand output structure **Required Reading** |
|
|
||||||
|
|
||||||
### Phase 1: Requirements Collection
|
|
||||||
|
|
||||||
| Document | Purpose | When to Use |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| [phases/01-requirements-collection.md](phases/01-requirements-collection.md) | Collection process guide | Execute requirements gathering |
|
|
||||||
| [specs/team-design-patterns.md](specs/team-design-patterns.md) | Pattern reference | Validate role fits team architecture |
|
|
||||||
|
|
||||||
### Phase 2: Pattern Analysis
|
|
||||||
|
|
||||||
| Document | Purpose | When to Use |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| [phases/02-pattern-analysis.md](phases/02-pattern-analysis.md) | Analysis process guide | Execute pattern matching |
|
|
||||||
| [specs/team-design-patterns.md](specs/team-design-patterns.md) | Full pattern catalog | Select applicable patterns |
|
|
||||||
|
|
||||||
### Phase 3: Command Generation
|
|
||||||
|
|
||||||
| Document | Purpose | When to Use |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| [phases/03-command-generation.md](phases/03-command-generation.md) | Generation process guide | Execute command file generation |
|
|
||||||
| [templates/command-template.md](templates/command-template.md) | Command template | Apply template with role content |
|
|
||||||
|
|
||||||
### Phase 4: Integration Verification
|
|
||||||
|
|
||||||
| Document | Purpose | When to Use |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| [phases/04-integration-verification.md](phases/04-integration-verification.md) | Verification process guide | Execute integration checks |
|
|
||||||
|
|
||||||
### Phase 5: Validation
|
|
||||||
|
|
||||||
| Document | Purpose | When to Use |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| [phases/05-validation.md](phases/05-validation.md) | Validation process guide | Execute quality checks |
|
|
||||||
| [specs/quality-standards.md](specs/quality-standards.md) | Quality criteria | Score generated command |
|
|
||||||
|
|
||||||
### Debugging & Troubleshooting
|
|
||||||
|
|
||||||
| Issue | Solution Document |
|
|
||||||
|-------|------------------|
|
|
||||||
| Generated command missing message bus | [specs/team-design-patterns.md](specs/team-design-patterns.md) - Pattern 1 |
|
|
||||||
| Task lifecycle not standard | [specs/team-design-patterns.md](specs/team-design-patterns.md) - Pattern 3 |
|
|
||||||
| Integration check fails | [phases/04-integration-verification.md](phases/04-integration-verification.md) |
|
|
||||||
| Quality score below threshold | [specs/quality-standards.md](specs/quality-standards.md) |
|
|
||||||
|
|
||||||
### Reference & Background
|
|
||||||
|
|
||||||
| Document | Purpose | Notes |
|
|
||||||
|----------|---------|-------|
|
|
||||||
| `.claude/commands/team/coordinate.md` | Coordinator reference | Spawn patterns, task chain creation |
|
|
||||||
| `.claude/commands/team/plan.md` | Planner reference | Exploration, plan generation patterns |
|
|
||||||
| `.claude/commands/team/execute.md` | Executor reference | Implementation, delegation patterns |
|
|
||||||
| `.claude/commands/team/test.md` | Tester reference | Adaptive fix cycle pattern |
|
|
||||||
| `.claude/commands/team/review.md` | Reviewer reference | Multi-dimensional review pattern |
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
# Phase 1: Requirements Collection
|
|
||||||
|
|
||||||
Collect team definition, role definition, capabilities, and communication patterns for the new team command.
|
|
||||||
|
|
||||||
## Objective
|
|
||||||
|
|
||||||
- Determine team name (folder name)
|
|
||||||
- Determine role name and responsibilities
|
|
||||||
- Define task prefix and communication patterns
|
|
||||||
- Select required tools and capabilities
|
|
||||||
- Generate role-config.json
|
|
||||||
|
|
||||||
## Input
|
|
||||||
|
|
||||||
- Dependency: User request (`$ARGUMENTS` or interactive input)
|
|
||||||
- Specification: `specs/team-design-patterns.md` (read in Phase 0)
|
|
||||||
|
|
||||||
## Execution Steps
|
|
||||||
|
|
||||||
### Step 1: Team & Role Basic Information
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const teamInfo = await AskUserQuestion({
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
question: "What is the team name? (lowercase, used as folder name under .claude/commands/team/{team-name}/)",
|
|
||||||
header: "Team Name",
|
|
||||||
multiSelect: false,
|
|
||||||
options: [
|
|
||||||
{ label: "Custom team", description: "Enter a custom team name" },
|
|
||||||
{ label: "spec", description: "Specification documentation team" },
|
|
||||||
{ label: "security", description: "Security audit and compliance team" },
|
|
||||||
{ label: "devops", description: "Deployment and operations team" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "What is the role name for this teammate? (lowercase, e.g., 'analyzer', 'deployer')",
|
|
||||||
header: "Role Name",
|
|
||||||
multiSelect: false,
|
|
||||||
options: [
|
|
||||||
{ label: "Custom role", description: "Enter a custom role name" },
|
|
||||||
{ label: "coordinator", description: "Team coordinator / orchestrator" },
|
|
||||||
{ label: "analyzer", description: "Code/data analysis specialist" },
|
|
||||||
{ label: "deployer", description: "Deployment and release management" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "What is the primary responsibility type?",
|
|
||||||
header: "Responsibility",
|
|
||||||
multiSelect: false,
|
|
||||||
options: [
|
|
||||||
{ label: "Read-only analysis", description: "Analyze, review, report (no file modification)" },
|
|
||||||
{ label: "Code generation", description: "Write/modify code files" },
|
|
||||||
{ label: "Orchestration", description: "Coordinate sub-tasks and agents" },
|
|
||||||
{ label: "Validation", description: "Test, verify, audit" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Task Configuration
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const taskConfig = await AskUserQuestion({
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
question: "What task prefix should this role use? (UPPERCASE, unique, e.g., 'ANALYZE', 'DEPLOY')",
|
|
||||||
header: "Task Prefix",
|
|
||||||
multiSelect: false,
|
|
||||||
options: [
|
|
||||||
{ label: "Custom prefix", description: "Enter a unique task prefix" },
|
|
||||||
{ label: "ANALYZE", description: "For analysis tasks (ANALYZE-001)" },
|
|
||||||
{ label: "DEPLOY", description: "For deployment tasks (DEPLOY-001)" },
|
|
||||||
{ label: "DOC", description: "For documentation tasks (DOC-001)" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Where does this role fit in the task chain?",
|
|
||||||
header: "Chain Position",
|
|
||||||
multiSelect: false,
|
|
||||||
options: [
|
|
||||||
{ label: "After PLAN (parallel with IMPL)", description: "Runs alongside implementation" },
|
|
||||||
{ label: "After IMPL (parallel with TEST/REVIEW)", description: "Post-implementation validation" },
|
|
||||||
{ label: "After TEST+REVIEW (final stage)", description: "Final processing before completion" },
|
|
||||||
{ label: "Independent (coordinator-triggered)", description: "No dependency on other tasks" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Capability Selection
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const capabilities = await AskUserQuestion({
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
question: "What capabilities does this role need?",
|
|
||||||
header: "Capabilities",
|
|
||||||
multiSelect: true,
|
|
||||||
options: [
|
|
||||||
{ label: "File modification (Write/Edit)", description: "Can create and modify files" },
|
|
||||||
{ label: "Sub-agent delegation (Task)", description: "Can spawn sub-agents for complex work" },
|
|
||||||
{ label: "CLI tool invocation", description: "Can invoke ccw cli tools (gemini/qwen/codex)" },
|
|
||||||
{ label: "User interaction (AskUserQuestion)", description: "Can ask user questions during execution" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Does this role need complexity-adaptive routing?",
|
|
||||||
header: "Adaptive",
|
|
||||||
multiSelect: false,
|
|
||||||
options: [
|
|
||||||
{ label: "Yes (Recommended)", description: "Low=direct, Medium/High=agent delegation" },
|
|
||||||
{ label: "No", description: "Always use the same execution path" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Message Types Definition
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Infer message types from role type
|
|
||||||
const responsibilityType = roleInfo["Responsibility"]
|
|
||||||
|
|
||||||
const baseMessageTypes = [
|
|
||||||
{ type: "error", direction: "-> coordinator", trigger: "Blocking error" }
|
|
||||||
]
|
|
||||||
|
|
||||||
const roleMessageTypes = {
|
|
||||||
"Read-only analysis": [
|
|
||||||
{ type: "{role}_result", direction: "-> coordinator", trigger: "Analysis complete" },
|
|
||||||
{ type: "{role}_progress", direction: "-> coordinator", trigger: "Long analysis progress" }
|
|
||||||
],
|
|
||||||
"Code generation": [
|
|
||||||
{ type: "{role}_complete", direction: "-> coordinator", trigger: "Generation complete" },
|
|
||||||
{ type: "{role}_progress", direction: "-> coordinator", trigger: "Batch progress update" }
|
|
||||||
],
|
|
||||||
"Orchestration": [
|
|
||||||
{ type: "{role}_ready", direction: "-> coordinator", trigger: "Sub-task results ready" },
|
|
||||||
{ type: "{role}_progress", direction: "-> coordinator", trigger: "Sub-task progress" }
|
|
||||||
],
|
|
||||||
"Validation": [
|
|
||||||
{ type: "{role}_result", direction: "-> coordinator", trigger: "Validation complete" },
|
|
||||||
{ type: "fix_required", direction: "-> coordinator", trigger: "Critical issues found" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const messageTypes = [
|
|
||||||
...baseMessageTypes,
|
|
||||||
...(roleMessageTypes[responsibilityType] || [])
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Generate Configuration
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const teamName = teamInfo["Team Name"] === "Custom team"
|
|
||||||
? teamInfo["Team Name_other"]
|
|
||||||
: teamInfo["Team Name"]
|
|
||||||
|
|
||||||
const roleName = teamInfo["Role Name"] === "Custom role"
|
|
||||||
? teamInfo["Role Name_other"]
|
|
||||||
: teamInfo["Role Name"]
|
|
||||||
|
|
||||||
const taskPrefix = taskConfig["Task Prefix"] === "Custom prefix"
|
|
||||||
? taskConfig["Task Prefix_other"]
|
|
||||||
: taskConfig["Task Prefix"]
|
|
||||||
|
|
||||||
// Build allowed-tools list
|
|
||||||
const baseTools = ["SendMessage(*)", "TaskUpdate(*)", "TaskList(*)", "TaskGet(*)", "TodoWrite(*)", "Read(*)", "Bash(*)", "Glob(*)", "Grep(*)"]
|
|
||||||
const selectedCapabilities = capabilities["Capabilities"] || []
|
|
||||||
|
|
||||||
if (selectedCapabilities.includes("File modification")) {
|
|
||||||
baseTools.push("Write(*)", "Edit(*)")
|
|
||||||
}
|
|
||||||
if (selectedCapabilities.includes("Sub-agent delegation")) {
|
|
||||||
baseTools.push("Task(*)")
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
team_name: teamName,
|
|
||||||
role_name: roleName,
|
|
||||||
display_name: `Team ${teamName} ${roleName}`,
|
|
||||||
description_cn: `Team ${teamName} ${roleName} - ${teamInfo["Responsibility"]}`,
|
|
||||||
responsibility_type: responsibilityType,
|
|
||||||
task_prefix: taskPrefix.toUpperCase(),
|
|
||||||
chain_position: taskConfig["Chain Position"],
|
|
||||||
allowed_tools: baseTools,
|
|
||||||
capabilities: selectedCapabilities,
|
|
||||||
adaptive_routing: capabilities["Adaptive"].includes("Yes"),
|
|
||||||
message_types: messageTypes.map(mt => ({
|
|
||||||
...mt,
|
|
||||||
type: mt.type.replace('{role}', roleName)
|
|
||||||
})),
|
|
||||||
cli_integration: selectedCapabilities.includes("CLI tool invocation"),
|
|
||||||
user_interaction: selectedCapabilities.includes("User interaction"),
|
|
||||||
// Derived paths
|
|
||||||
skill_path: `team:${teamName}:${roleName}`, // e.g., team:spec:analyst
|
|
||||||
output_folder: `.claude/commands/team/${teamName}`, // e.g., .claude/commands/team/spec
|
|
||||||
output_file: `${roleName}.md` // e.g., analyst.md
|
|
||||||
}
|
|
||||||
|
|
||||||
Write(`${workDir}/role-config.json`, JSON.stringify(config, null, 2))
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
- **File**: `role-config.json`
|
|
||||||
- **Format**: JSON
|
|
||||||
- **Location**: `{workDir}/role-config.json`
|
|
||||||
|
|
||||||
## Quality Checklist
|
|
||||||
|
|
||||||
- [ ] Team name is lowercase, valid as folder name
|
|
||||||
- [ ] Role name is lowercase, unique within the team folder
|
|
||||||
- [ ] Task prefix is UPPERCASE, unique (not PLAN/IMPL/TEST/REVIEW)
|
|
||||||
- [ ] Allowed tools include minimum set (SendMessage, TaskUpdate, TaskList, TaskGet)
|
|
||||||
- [ ] Message types follow naming convention
|
|
||||||
- [ ] Chain position is clearly defined
|
|
||||||
- [ ] Derived paths (skill_path, output_folder, output_file) are consistent
|
|
||||||
|
|
||||||
## Next Phase
|
|
||||||
|
|
||||||
-> [Phase 2: Pattern Analysis](02-pattern-analysis.md)
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
# Phase 2: Pattern Analysis
|
|
||||||
|
|
||||||
Identify applicable design patterns from existing team commands for the new role.
|
|
||||||
|
|
||||||
## Objective
|
|
||||||
|
|
||||||
- Find the most similar existing team command
|
|
||||||
- Select applicable infrastructure patterns (Section A)
|
|
||||||
- Select applicable collaboration patterns (Section B: CP-1 through CP-10)
|
|
||||||
- Map role responsibilities to phase structure
|
|
||||||
- Generate applicable-patterns.json
|
|
||||||
|
|
||||||
## Input
|
|
||||||
|
|
||||||
- Dependency: `role-config.json` (from Phase 1)
|
|
||||||
- Specification: `specs/team-design-patterns.md` (read in Phase 0)
|
|
||||||
|
|
||||||
## Execution Steps
|
|
||||||
|
|
||||||
### Step 1: Load Configuration
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const config = JSON.parse(Read(`${workDir}/role-config.json`))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Find Most Similar Existing Command
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Similarity mapping based on responsibility type
|
|
||||||
const similarityMap = {
|
|
||||||
"Read-only analysis": {
|
|
||||||
primary: "review", // Multi-dimensional analysis -> report
|
|
||||||
secondary: "plan", // Also does exploration
|
|
||||||
reason: "Both analyze code and report findings with severity classification"
|
|
||||||
},
|
|
||||||
"Code generation": {
|
|
||||||
primary: "execute", // Code implementation
|
|
||||||
secondary: "test", // Also modifies code (fixes)
|
|
||||||
reason: "Both write/modify code files and self-validate"
|
|
||||||
},
|
|
||||||
"Orchestration": {
|
|
||||||
primary: "plan", // Manages exploration and plan generation
|
|
||||||
secondary: "coordinate", // High-level orchestration
|
|
||||||
reason: "Both coordinate multiple sub-tasks and produce structured output"
|
|
||||||
},
|
|
||||||
"Validation": {
|
|
||||||
primary: "test", // Test execution and fix cycles
|
|
||||||
secondary: "review", // Verification
|
|
||||||
reason: "Both validate output quality with structured criteria"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const similarity = similarityMap[config.responsibility_type]
|
|
||||||
|
|
||||||
// Read the most similar command for pattern extraction
|
|
||||||
const primaryRef = Read(`.claude/commands/team/${similarity.primary}.md`)
|
|
||||||
const secondaryRef = Read(`.claude/commands/team/${similarity.secondary}.md`)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Select Applicable Patterns
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// All commands use these core patterns (mandatory)
|
|
||||||
const corePatterns = [
|
|
||||||
"pattern-1-message-bus", // Always required
|
|
||||||
"pattern-2-yaml-front-matter", // Always required
|
|
||||||
"pattern-3-task-lifecycle", // Always required
|
|
||||||
"pattern-4-five-phase", // Always required
|
|
||||||
"pattern-6-coordinator-spawn", // Always required
|
|
||||||
"pattern-7-error-handling" // Always required
|
|
||||||
]
|
|
||||||
|
|
||||||
// Conditional patterns based on config
|
|
||||||
const conditionalPatterns = []
|
|
||||||
|
|
||||||
if (config.adaptive_routing) {
|
|
||||||
conditionalPatterns.push("pattern-5-complexity-adaptive")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.responsibility_type === "Code generation" ||
|
|
||||||
config.responsibility_type === "Orchestration") {
|
|
||||||
conditionalPatterns.push("pattern-8-session-files")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Map Phase Structure
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Map 5-phase structure to role-specific content
|
|
||||||
const phaseMapping = {
|
|
||||||
"Read-only analysis": {
|
|
||||||
phase1: "Task Discovery",
|
|
||||||
phase2: "Context Loading (read changed files, load plan)",
|
|
||||||
phase3: `${config.role_name}-specific analysis`,
|
|
||||||
phase4: "Finding Summary (classify severity)",
|
|
||||||
phase5: "Report to Coordinator"
|
|
||||||
},
|
|
||||||
"Code generation": {
|
|
||||||
phase1: "Task & Plan Loading",
|
|
||||||
phase2: "Task Grouping (dependency analysis)",
|
|
||||||
phase3: "Code Implementation (direct or sub-agent)",
|
|
||||||
phase4: "Self-Validation (syntax, criteria)",
|
|
||||||
phase5: "Completion Report"
|
|
||||||
},
|
|
||||||
"Orchestration": {
|
|
||||||
phase1: "Task Discovery",
|
|
||||||
phase2: "Context & Complexity Assessment",
|
|
||||||
phase3: "Orchestrated Execution (parallel sub-agents)",
|
|
||||||
phase4: "Result Aggregation",
|
|
||||||
phase5: "Submit for Approval + Loop"
|
|
||||||
},
|
|
||||||
"Validation": {
|
|
||||||
phase1: "Task Discovery",
|
|
||||||
phase2: "Framework/Environment Detection",
|
|
||||||
phase3: "Execution & Fix Cycle",
|
|
||||||
phase4: "Result Analysis",
|
|
||||||
phase5: "Report to Coordinator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const phases = phaseMapping[config.responsibility_type]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Extract Implementation Patterns from Reference
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Extract specific code patterns from the most similar command
|
|
||||||
function extractPatterns(commandContent) {
|
|
||||||
const patterns = {}
|
|
||||||
|
|
||||||
// Extract task discovery pattern
|
|
||||||
const taskDiscovery = commandContent.match(
|
|
||||||
/\/\/ Find my assigned.*?if \(my\w+Tasks\.length === 0\).*?return/s
|
|
||||||
)
|
|
||||||
if (taskDiscovery) patterns.taskDiscovery = taskDiscovery[0]
|
|
||||||
|
|
||||||
// Extract message bus examples
|
|
||||||
const msgExamples = commandContent.match(
|
|
||||||
/mcp__ccw-tools__team_msg\(\{[^}]+\}\)/g
|
|
||||||
)
|
|
||||||
if (msgExamples) patterns.messageExamples = msgExamples
|
|
||||||
|
|
||||||
// Extract error handling table
|
|
||||||
const errorTable = commandContent.match(
|
|
||||||
/## Error Handling[\s\S]*?\n\n/
|
|
||||||
)
|
|
||||||
if (errorTable) patterns.errorHandling = errorTable[0]
|
|
||||||
|
|
||||||
return patterns
|
|
||||||
}
|
|
||||||
|
|
||||||
const referencePatterns = extractPatterns(primaryRef)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6: Select Collaboration Patterns
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Collaboration pattern selection based on role characteristics
|
|
||||||
function selectCollaborationPatterns(config) {
|
|
||||||
const patterns = ['CP-1'] // CP-1 Linear Pipeline is always the base
|
|
||||||
|
|
||||||
const responsibilityType = config.responsibility_type
|
|
||||||
|
|
||||||
// Rule-based selection
|
|
||||||
if (responsibilityType === 'Validation' || responsibilityType === 'Read-only analysis') {
|
|
||||||
patterns.push('CP-2') // Review-Fix Cycle - natural for validation roles
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responsibilityType === 'Orchestration') {
|
|
||||||
patterns.push('CP-3') // Fan-out/Fan-in for orchestration
|
|
||||||
patterns.push('CP-4') // Consensus Gate for decisions
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.adaptive_routing) {
|
|
||||||
patterns.push('CP-5') // Escalation Chain for when self-repair fails
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responsibilityType === 'Code generation') {
|
|
||||||
patterns.push('CP-6') // Incremental Delivery for large implementations
|
|
||||||
patterns.push('CP-2') // Review-Fix Cycle for code quality
|
|
||||||
}
|
|
||||||
|
|
||||||
// CP-5 Escalation is always available as a fallback
|
|
||||||
if (!patterns.includes('CP-5')) {
|
|
||||||
patterns.push('CP-5')
|
|
||||||
}
|
|
||||||
|
|
||||||
// CP-10 Post-Mortem is always included at team level
|
|
||||||
patterns.push('CP-10')
|
|
||||||
|
|
||||||
return [...new Set(patterns)] // Deduplicate
|
|
||||||
}
|
|
||||||
|
|
||||||
const collaborationPatterns = selectCollaborationPatterns(config)
|
|
||||||
|
|
||||||
// Map collaboration patterns to convergence configurations
|
|
||||||
const convergenceConfig = collaborationPatterns.map(cp => {
|
|
||||||
const defaults = {
|
|
||||||
'CP-1': { max_iterations: 1, timeout: null, success_gate: 'all_stages_completed' },
|
|
||||||
'CP-2': { max_iterations: 5, timeout: null, success_gate: 'verdict_approve_or_conditional' },
|
|
||||||
'CP-3': { max_iterations: 1, timeout: 300000, success_gate: 'quorum_100_percent' },
|
|
||||||
'CP-4': { max_iterations: 2, timeout: 300000, success_gate: 'quorum_67_percent' },
|
|
||||||
'CP-5': { max_iterations: null, timeout: null, success_gate: 'issue_resolved_at_any_level' },
|
|
||||||
'CP-6': { max_iterations: 3, timeout: null, success_gate: 'all_increments_validated' },
|
|
||||||
'CP-7': { max_iterations: 2, timeout: 600000, success_gate: 'blocker_resolved' },
|
|
||||||
'CP-8': { max_iterations: 2, timeout: 120000, success_gate: 'advice_applied' },
|
|
||||||
'CP-9': { max_iterations: 2, timeout: 300000, success_gate: 'all_sync_points_aligned' },
|
|
||||||
'CP-10': { max_iterations: 1, timeout: 180000, success_gate: 'report_generated' }
|
|
||||||
}
|
|
||||||
return { pattern: cp, convergence: defaults[cp] }
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 7: Generate Patterns Document
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const applicablePatterns = {
|
|
||||||
role_name: config.role_name,
|
|
||||||
similar_to: {
|
|
||||||
primary: similarity.primary,
|
|
||||||
secondary: similarity.secondary,
|
|
||||||
reason: similarity.reason
|
|
||||||
},
|
|
||||||
// Infrastructure patterns
|
|
||||||
core_patterns: corePatterns,
|
|
||||||
conditional_patterns: conditionalPatterns,
|
|
||||||
// Collaboration patterns
|
|
||||||
collaboration_patterns: collaborationPatterns,
|
|
||||||
convergence_config: convergenceConfig,
|
|
||||||
// Phase and reference mapping
|
|
||||||
phase_structure: phases,
|
|
||||||
reference_patterns: {
|
|
||||||
task_discovery: "Adapt from " + similarity.primary + ".md Phase 1",
|
|
||||||
core_work: "Adapt from " + similarity.primary + ".md Phase 3",
|
|
||||||
reporting: "Adapt from " + similarity.primary + ".md Phase 5"
|
|
||||||
},
|
|
||||||
message_types: config.message_types,
|
|
||||||
implementation_hints: {
|
|
||||||
phase1: `Standard task lifecycle with ${config.task_prefix}-* prefix`,
|
|
||||||
phase2: phases.phase2,
|
|
||||||
phase3: phases.phase3,
|
|
||||||
phase4: phases.phase4,
|
|
||||||
phase5: `SendMessage to coordinator with ${config.role_name} results`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write(`${workDir}/applicable-patterns.json`, JSON.stringify(applicablePatterns, null, 2))
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
- **File**: `applicable-patterns.json`
|
|
||||||
- **Format**: JSON
|
|
||||||
- **Location**: `{workDir}/applicable-patterns.json`
|
|
||||||
|
|
||||||
## Quality Checklist
|
|
||||||
|
|
||||||
- [ ] Most similar existing command identified
|
|
||||||
- [ ] All mandatory patterns included (6 core patterns)
|
|
||||||
- [ ] Phase structure mapped to role responsibilities
|
|
||||||
- [ ] Implementation hints are specific and actionable
|
|
||||||
- [ ] Reference patterns point to concrete sections
|
|
||||||
|
|
||||||
## Next Phase
|
|
||||||
|
|
||||||
-> [Phase 3: Command Generation](03-command-generation.md)
|
|
||||||
@@ -1,364 +0,0 @@
|
|||||||
# Phase 3: Command Generation
|
|
||||||
|
|
||||||
Generate the team command .md file using template and pattern analysis results.
|
|
||||||
|
|
||||||
## Objective
|
|
||||||
|
|
||||||
- Apply command template with role-specific content
|
|
||||||
- Generate complete YAML front matter
|
|
||||||
- Generate message bus section
|
|
||||||
- Generate 5-phase implementation with code
|
|
||||||
- Generate error handling table
|
|
||||||
- Output final command file
|
|
||||||
|
|
||||||
## Input
|
|
||||||
|
|
||||||
- Dependency: `role-config.json` (Phase 1), `applicable-patterns.json` (Phase 2)
|
|
||||||
- Template: `templates/command-template.md`
|
|
||||||
|
|
||||||
## Execution Steps
|
|
||||||
|
|
||||||
### Step 1: Load Inputs
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const config = JSON.parse(Read(`${workDir}/role-config.json`))
|
|
||||||
const patterns = JSON.parse(Read(`${workDir}/applicable-patterns.json`))
|
|
||||||
const template = Read(`${skillDir}/templates/command-template.md`)
|
|
||||||
|
|
||||||
// Read most similar command for code reference
|
|
||||||
// Note: reference may be in a folder (e.g. .claude/commands/team/folder/cmd.md) if config.output_folder is set
|
|
||||||
const refCommand = Read(`.claude/commands/team/${patterns.similar_to.primary}.md`)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Generate YAML Front Matter
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const frontMatter = `---
|
|
||||||
name: ${config.role_name}
|
|
||||||
description: ${config.description_cn}
|
|
||||||
argument-hint: ""
|
|
||||||
allowed-tools: ${config.allowed_tools.join(', ')}
|
|
||||||
group: team
|
|
||||||
---`
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Generate Message Bus Section
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const messageBusSection = `## Message Bus
|
|
||||||
|
|
||||||
Every SendMessage **before**, must call \`mcp__ccw-tools__team_msg\` to log:
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "${config.role_name}", to: "coordinator", type: "<type>", summary: "<summary>" })
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### Supported Message Types
|
|
||||||
|
|
||||||
| Type | Direction | Trigger | Description |
|
|
||||||
|------|-----------|---------|-------------|
|
|
||||||
${config.message_types.map(mt =>
|
|
||||||
`| \`${mt.type}\` | ${config.role_name} -> coordinator | ${mt.trigger} | ${mt.description || mt.trigger} |`
|
|
||||||
).join('\n')}
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
${config.message_types.filter(mt => mt.type !== 'error').map(mt =>
|
|
||||||
`// ${mt.trigger}
|
|
||||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "${config.role_name}", to: "coordinator", type: "${mt.type}", summary: "${mt.trigger}" })`
|
|
||||||
).join('\n\n')}
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### CLI 回退
|
|
||||||
|
|
||||||
当 \`mcp__ccw-tools__team_msg\` MCP 不可用时,使用 \`ccw team\` CLI 作为等效回退:
|
|
||||||
|
|
||||||
\\\`\\\`\\\`javascript
|
|
||||||
// 回退: 将 MCP 调用替换为 Bash CLI(参数一一对应)
|
|
||||||
Bash(\\\`ccw team log --team "\${teamName}" --from "${config.role_name}" --to "coordinator" --type "${config.message_types[0]?.type || 'result'}" --summary "<摘要>" --json\\\`)
|
|
||||||
\\\`\\\`\\\`
|
|
||||||
|
|
||||||
**参数映射**: \`team_msg(params)\` → \`ccw team log --team <team> --from ${config.role_name} --to coordinator --type <type> --summary "<text>" [--ref <path>] [--data '<json>'] [--json]\``
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Generate Phase Implementations
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Phase 1: Task Discovery (standard for all roles)
|
|
||||||
const phase1 = `### Phase 1: Task Discovery
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Find assigned ${config.task_prefix}-* tasks
|
|
||||||
const tasks = TaskList()
|
|
||||||
const myTasks = tasks.filter(t =>
|
|
||||||
t.subject.startsWith('${config.task_prefix}-') &&
|
|
||||||
t.owner === '${config.role_name}' &&
|
|
||||||
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 (adapted by responsibility type)
|
|
||||||
const phase2Templates = {
|
|
||||||
"Read-only analysis": `### Phase 2: Context Loading
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Load plan for criteria reference
|
|
||||||
const planPathMatch = task.description.match(/\\.workflow\\/\\.team-plan\\/[^\\s]+\\/plan\\.json/)
|
|
||||||
let plan = null
|
|
||||||
if (planPathMatch) {
|
|
||||||
try { plan = JSON.parse(Read(planPathMatch[0])) } catch {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get changed files
|
|
||||||
const changedFiles = Bash(\`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached\`)
|
|
||||||
.split('\\n').filter(Boolean)
|
|
||||||
|
|
||||||
// Read file contents for analysis
|
|
||||||
const fileContents = {}
|
|
||||||
for (const file of changedFiles.slice(0, 20)) {
|
|
||||||
try { fileContents[file] = Read(file) } catch {}
|
|
||||||
}
|
|
||||||
\`\`\``,
|
|
||||||
|
|
||||||
"Code generation": `### Phase 2: Task & Plan Loading
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Extract plan path from task description
|
|
||||||
const planPathMatch = task.description.match(/\\.workflow\\/\\.team-plan\\/[^\\s]+\\/plan\\.json/)
|
|
||||||
if (!planPathMatch) {
|
|
||||||
SendMessage({ type: "message", recipient: "coordinator",
|
|
||||||
content: \`Cannot find plan.json path in task \${task.subject}\`,
|
|
||||||
summary: "Plan path not found" })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const plan = JSON.parse(Read(planPathMatch[0]))
|
|
||||||
// Load task files from .task/ directory
|
|
||||||
const planTasks = plan.task_ids.map(id =>
|
|
||||||
JSON.parse(Read(\`\${planPathMatch[0].replace('plan.json', '')}.task/\${id}.json\`))
|
|
||||||
)
|
|
||||||
\`\`\``,
|
|
||||||
|
|
||||||
"Orchestration": `### Phase 2: Context & Complexity Assessment
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Assess task complexity
|
|
||||||
function assessComplexity(desc) {
|
|
||||||
let score = 0
|
|
||||||
if (/refactor|architect|restructure|module|system/.test(desc)) score += 2
|
|
||||||
if (/multiple|across|cross/.test(desc)) score += 2
|
|
||||||
if (/integrate|api|database/.test(desc)) score += 1
|
|
||||||
if (/security|performance/.test(desc)) score += 1
|
|
||||||
return score >= 4 ? 'High' : score >= 2 ? 'Medium' : 'Low'
|
|
||||||
}
|
|
||||||
|
|
||||||
const complexity = assessComplexity(task.description)
|
|
||||||
|
|
||||||
// Load related context
|
|
||||||
const projectTech = Bash(\`test -f .workflow/project-tech.json && cat .workflow/project-tech.json || echo "{}"\`)
|
|
||||||
\`\`\``,
|
|
||||||
|
|
||||||
"Validation": `### Phase 2: Environment Detection
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Detect relevant tools/frameworks
|
|
||||||
// (customize based on specific validation domain)
|
|
||||||
const changedFiles = Bash(\`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached\`)
|
|
||||||
.split('\\n').filter(Boolean)
|
|
||||||
|
|
||||||
// Load context based on validation type
|
|
||||||
\`\`\``
|
|
||||||
}
|
|
||||||
|
|
||||||
const phase2 = phase2Templates[config.responsibility_type]
|
|
||||||
|
|
||||||
// Phase 3: Core Work (role-specific, provides skeleton)
|
|
||||||
const phase3 = `### Phase 3: ${patterns.phase_structure.phase3}
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Core ${config.role_name} logic
|
|
||||||
// TODO: Implement based on role requirements
|
|
||||||
// Reference: .claude/commands/team/${patterns.similar_to.primary}.md Phase 3
|
|
||||||
|
|
||||||
${config.adaptive_routing ? `
|
|
||||||
// Complexity-adaptive execution
|
|
||||||
if (complexity === 'Low') {
|
|
||||||
// Direct execution
|
|
||||||
} else {
|
|
||||||
// Delegate to sub-agent
|
|
||||||
Task({
|
|
||||||
subagent_type: "universal-executor",
|
|
||||||
run_in_background: false,
|
|
||||||
description: "${config.role_name} work",
|
|
||||||
prompt: \`
|
|
||||||
## Task
|
|
||||||
\${task.description}
|
|
||||||
|
|
||||||
## MANDATORY FIRST STEPS
|
|
||||||
1. Read: .workflow/project-tech.json (if exists)
|
|
||||||
2. Read: .workflow/project-guidelines.json (if exists)
|
|
||||||
|
|
||||||
## Expected Output
|
|
||||||
\${expectedFormat}
|
|
||||||
\`
|
|
||||||
})
|
|
||||||
}` : `// Direct execution for all tasks`}
|
|
||||||
\`\`\``
|
|
||||||
|
|
||||||
// Phase 4: Validation/Summary
|
|
||||||
const phase4 = `### Phase 4: ${patterns.phase_structure.phase4}
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Validate/summarize results
|
|
||||||
// TODO: Implement based on role requirements
|
|
||||||
// Reference: .claude/commands/team/${patterns.similar_to.primary}.md Phase 4
|
|
||||||
\`\`\``
|
|
||||||
|
|
||||||
// Phase 5: Report + Loop (standard for all roles)
|
|
||||||
const phase5 = `### Phase 5: Report to Coordinator
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Log message before SendMessage
|
|
||||||
mcp__ccw-tools__team_msg({
|
|
||||||
operation: "log", team: teamName,
|
|
||||||
from: "${config.role_name}", to: "coordinator",
|
|
||||||
type: "${config.message_types[0]?.type || config.role_name + '_complete'}",
|
|
||||||
summary: \`${config.task_prefix} complete: \${task.subject}\`
|
|
||||||
})
|
|
||||||
|
|
||||||
SendMessage({
|
|
||||||
type: "message",
|
|
||||||
recipient: "coordinator",
|
|
||||||
content: \`## ${config.display_name} Results
|
|
||||||
|
|
||||||
**Task**: \${task.subject}
|
|
||||||
**Status**: \${resultStatus}
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
\${resultSummary}
|
|
||||||
|
|
||||||
### Details
|
|
||||||
\${resultDetails}\`,
|
|
||||||
summary: \`${config.task_prefix} complete\`
|
|
||||||
})
|
|
||||||
|
|
||||||
// Mark task completed
|
|
||||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
|
||||||
|
|
||||||
// Check for next task
|
|
||||||
const nextTasks = TaskList().filter(t =>
|
|
||||||
t.subject.startsWith('${config.task_prefix}-') &&
|
|
||||||
t.owner === '${config.role_name}' &&
|
|
||||||
t.status === 'pending' &&
|
|
||||||
t.blockedBy.length === 0
|
|
||||||
)
|
|
||||||
|
|
||||||
if (nextTasks.length > 0) {
|
|
||||||
// Continue with next task -> back to Phase 1
|
|
||||||
}
|
|
||||||
\`\`\``
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Generate Error Handling Table
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const errorTable = `## Error Handling
|
|
||||||
|
|
||||||
| Scenario | Resolution |
|
|
||||||
|----------|------------|
|
|
||||||
| No ${config.task_prefix}-* tasks available | Idle, wait for coordinator assignment |
|
|
||||||
| Plan/Context file not found | Notify coordinator, request location |
|
|
||||||
${config.adaptive_routing ? '| Sub-agent failure | Retry once, then fallback to direct execution |\n' : ''}| Max iterations exceeded | Report to coordinator, suggest intervention |
|
|
||||||
| Critical issue beyond scope | SendMessage fix_required to coordinator |
|
|
||||||
| Unexpected error | Log error via team_msg, report to coordinator |`
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6: Assemble Final Command File
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const commandContent = `${frontMatter}
|
|
||||||
|
|
||||||
# Team ${config.display_name} Command (/${config.skill_path})
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Team ${config.role_name} role command. Operates as a teammate within an Agent Team, responsible for ${config.responsibility_type.toLowerCase()}.
|
|
||||||
|
|
||||||
**Core capabilities:**
|
|
||||||
- Task discovery from shared team task list (${config.task_prefix}-* tasks)
|
|
||||||
${patterns.core_patterns.includes('pattern-5-complexity-adaptive') ? '- Complexity-adaptive routing (Low -> direct, Medium/High -> agent)\n' : ''}- ${config.responsibility_type}-specific processing
|
|
||||||
- Structured result reporting to coordinator
|
|
||||||
|
|
||||||
## Role Definition
|
|
||||||
|
|
||||||
**Name**: \`${config.role_name}\`
|
|
||||||
**Responsibility**: ${patterns.phase_structure.phase2} -> ${patterns.phase_structure.phase3} -> ${patterns.phase_structure.phase5}
|
|
||||||
**Communication**: SendMessage to coordinator only
|
|
||||||
|
|
||||||
${messageBusSection}
|
|
||||||
|
|
||||||
## Execution Process
|
|
||||||
|
|
||||||
\`\`\`
|
|
||||||
Phase 1: Task Discovery
|
|
||||||
├─ TaskList to find unblocked ${config.task_prefix}-* tasks
|
|
||||||
├─ TaskGet to read full task details
|
|
||||||
└─ TaskUpdate to mark in_progress
|
|
||||||
|
|
||||||
Phase 2: ${patterns.phase_structure.phase2}
|
|
||||||
|
|
||||||
Phase 3: ${patterns.phase_structure.phase3}
|
|
||||||
|
|
||||||
Phase 4: ${patterns.phase_structure.phase4}
|
|
||||||
|
|
||||||
Phase 5: ${patterns.phase_structure.phase5}
|
|
||||||
├─ team_msg log + SendMessage results
|
|
||||||
├─ TaskUpdate completed
|
|
||||||
└─ Check for next ${config.task_prefix}-* task
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
${phase1}
|
|
||||||
|
|
||||||
${phase2}
|
|
||||||
|
|
||||||
${phase3}
|
|
||||||
|
|
||||||
${phase4}
|
|
||||||
|
|
||||||
${phase5}
|
|
||||||
|
|
||||||
${errorTable}
|
|
||||||
`
|
|
||||||
|
|
||||||
Write(`${workDir}/${config.role_name}.md`, commandContent)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
- **File**: `{role-name}.md`
|
|
||||||
- **Format**: Markdown
|
|
||||||
- **Location**: `{workDir}/{role-name}.md`
|
|
||||||
|
|
||||||
## Quality Checklist
|
|
||||||
|
|
||||||
- [ ] YAML front matter includes all required fields
|
|
||||||
- [ ] `group: team` is present
|
|
||||||
- [ ] Message bus section has team_msg examples
|
|
||||||
- [ ] All 5 phases are present with implementation code
|
|
||||||
- [ ] Task lifecycle follows standard pattern
|
|
||||||
- [ ] Error handling table is present
|
|
||||||
- [ ] SendMessage always preceded by team_msg
|
|
||||||
- [ ] Role communicates only with coordinator
|
|
||||||
|
|
||||||
## Next Phase
|
|
||||||
|
|
||||||
-> [Phase 4: Integration Verification](04-integration-verification.md)
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
# Phase 4: Integration Verification
|
|
||||||
|
|
||||||
Verify the generated command integrates correctly with the existing team system.
|
|
||||||
|
|
||||||
## Objective
|
|
||||||
|
|
||||||
- Verify consistency with coordinate.md spawn patterns
|
|
||||||
- Check message type compatibility
|
|
||||||
- Verify task prefix uniqueness
|
|
||||||
- Ensure allowed-tools are sufficient
|
|
||||||
- Generate integration-report.json
|
|
||||||
|
|
||||||
## Input
|
|
||||||
|
|
||||||
- Dependency: `{role-name}.md` (Phase 3), `role-config.json` (Phase 1)
|
|
||||||
- Reference: `.claude/commands/team/coordinate.md`
|
|
||||||
|
|
||||||
## Execution Steps
|
|
||||||
|
|
||||||
### Step 1: Load Generated Command and Config
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const config = JSON.parse(Read(`${workDir}/role-config.json`))
|
|
||||||
const generatedCommand = Read(`${workDir}/${config.role_name}.md`)
|
|
||||||
const coordinateCmd = Read(`.claude/commands/team/coordinate.md`)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Check Task Prefix Uniqueness
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Extract existing prefixes from coordinate.md
|
|
||||||
const existingPrefixes = ['PLAN', 'IMPL', 'TEST', 'REVIEW']
|
|
||||||
|
|
||||||
// Also scan all team command files for prefixes
|
|
||||||
const teamFiles = Glob('.claude/commands/team/**/*.md')
|
|
||||||
for (const file of teamFiles) {
|
|
||||||
const content = Read(file)
|
|
||||||
const prefixMatch = content.match(/startsWith\('([A-Z]+)-'\)/)
|
|
||||||
if (prefixMatch && !existingPrefixes.includes(prefixMatch[1])) {
|
|
||||||
existingPrefixes.push(prefixMatch[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const prefixConflict = existingPrefixes.includes(config.task_prefix)
|
|
||||||
|
|
||||||
const prefixCheck = {
|
|
||||||
status: prefixConflict ? 'FAIL' : 'PASS',
|
|
||||||
existing: existingPrefixes,
|
|
||||||
new_prefix: config.task_prefix,
|
|
||||||
message: prefixConflict
|
|
||||||
? `Prefix ${config.task_prefix} conflicts with existing: ${existingPrefixes.join(', ')}`
|
|
||||||
: `Prefix ${config.task_prefix} is unique`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Verify Spawn Pattern Compatibility
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Check that the generated command can be spawned by coordinate.md
|
|
||||||
const spawnCheck = {
|
|
||||||
has_skill_invocation: generatedCommand.includes('Skill(skill="team:'),
|
|
||||||
has_task_lifecycle: generatedCommand.includes('TaskList') &&
|
|
||||||
generatedCommand.includes('TaskGet') &&
|
|
||||||
generatedCommand.includes('TaskUpdate'),
|
|
||||||
has_message_bus: generatedCommand.includes('mcp__ccw-tools__team_msg'),
|
|
||||||
has_send_message: generatedCommand.includes('SendMessage'),
|
|
||||||
has_group_team: generatedCommand.includes('group: team')
|
|
||||||
}
|
|
||||||
|
|
||||||
const spawnCompatible = Object.values(spawnCheck).every(v => v)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Verify Message Type Compatibility
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Extract all message types used in coordinate.md handlers
|
|
||||||
const coordinateTypes = coordinateCmd.match(/type:\s*["']([^"']+)["']/g)
|
|
||||||
?.map(m => m.match(/["']([^"']+)["']/)[1]) || []
|
|
||||||
|
|
||||||
// Check new message types don't conflict
|
|
||||||
const msgTypeCheck = {
|
|
||||||
coordinator_knows: coordinateTypes,
|
|
||||||
new_types: config.message_types.map(mt => mt.type),
|
|
||||||
conflicts: config.message_types
|
|
||||||
.filter(mt => coordinateTypes.includes(mt.type))
|
|
||||||
.map(mt => mt.type),
|
|
||||||
recommendation: "Add new message types to coordinate.md handler table"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Verify Allowed-Tools Sufficiency
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const requiredTools = ['SendMessage', 'TaskUpdate', 'TaskList', 'TaskGet']
|
|
||||||
const missingTools = requiredTools.filter(tool =>
|
|
||||||
!config.allowed_tools.some(at => at.includes(tool))
|
|
||||||
)
|
|
||||||
|
|
||||||
const toolCheck = {
|
|
||||||
status: missingTools.length === 0 ? 'PASS' : 'FAIL',
|
|
||||||
required: requiredTools,
|
|
||||||
configured: config.allowed_tools,
|
|
||||||
missing: missingTools
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6: Verify Chain Position Integration
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Check coordinate.md has or can add the task chain
|
|
||||||
const chainCheck = {
|
|
||||||
position: config.chain_position,
|
|
||||||
existing_chain: "PLAN-001 -> IMPL-001 -> TEST-001 + REVIEW-001",
|
|
||||||
integration_needed: true,
|
|
||||||
suggestion: generateChainSuggestion(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateChainSuggestion(config) {
|
|
||||||
const pos = config.chain_position
|
|
||||||
if (pos.includes("After PLAN")) {
|
|
||||||
return `PLAN-001 -> IMPL-001 + ${config.task_prefix}-001 -> TEST-001 + REVIEW-001`
|
|
||||||
}
|
|
||||||
if (pos.includes("After IMPL")) {
|
|
||||||
return `PLAN-001 -> IMPL-001 -> TEST-001 + REVIEW-001 + ${config.task_prefix}-001`
|
|
||||||
}
|
|
||||||
if (pos.includes("After TEST")) {
|
|
||||||
return `PLAN-001 -> IMPL-001 -> TEST-001 + REVIEW-001 -> ${config.task_prefix}-001`
|
|
||||||
}
|
|
||||||
return `PLAN-001 -> IMPL-001 -> TEST-001 + REVIEW-001 (+ ${config.task_prefix}-001 independent)`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 7: Generate Coordinator Spawn Snippet
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Generate the spawn code that should be added to coordinate.md
|
|
||||||
const spawnSnippet = `// ${config.display_name}
|
|
||||||
Task({
|
|
||||||
subagent_type: "general-purpose",
|
|
||||||
team_name: teamName,
|
|
||||||
name: "${config.role_name}",
|
|
||||||
prompt: \`You are team "\${teamName}" ${config.role_name.toUpperCase()}.
|
|
||||||
|
|
||||||
When you receive ${config.task_prefix}-* tasks, call Skill(skill="${config.skill_path}") to execute.
|
|
||||||
|
|
||||||
Current requirement: \${taskDescription}
|
|
||||||
Constraints: \${constraints}
|
|
||||||
|
|
||||||
## Message Bus (Required)
|
|
||||||
Before each SendMessage, call mcp__ccw-tools__team_msg:
|
|
||||||
mcp__ccw-tools__team_msg({ operation: "log", team: "\${teamName}", from: "${config.role_name}", to: "coordinator", type: "<type>", summary: "<summary>" })
|
|
||||||
|
|
||||||
Workflow:
|
|
||||||
1. TaskList -> find ${config.task_prefix}-* tasks assigned to you
|
|
||||||
2. Skill(skill="${config.skill_path}") to execute
|
|
||||||
3. team_msg log + SendMessage results to coordinator
|
|
||||||
4. TaskUpdate completed -> check next task\`
|
|
||||||
})`
|
|
||||||
```
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Skill path: ${config.skill_path} (e.g., team:spec:analyst)
|
|
||||||
// Folder: ${config.output_folder} (e.g., .claude/commands/team/spec)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 8: Generate Integration Report
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const report = {
|
|
||||||
role_name: config.role_name,
|
|
||||||
checks: {
|
|
||||||
prefix_unique: prefixCheck,
|
|
||||||
spawn_compatible: { status: spawnCompatible ? 'PASS' : 'FAIL', details: spawnCheck },
|
|
||||||
message_types: msgTypeCheck,
|
|
||||||
tools_sufficient: toolCheck,
|
|
||||||
chain_integration: chainCheck
|
|
||||||
},
|
|
||||||
overall: (prefixCheck.status === 'PASS' &&
|
|
||||||
spawnCompatible &&
|
|
||||||
toolCheck.status === 'PASS') ? 'PASS' : 'NEEDS_ATTENTION',
|
|
||||||
destination: `${config.output_folder}/${config.output_file}`,
|
|
||||||
coordinator_updates: {
|
|
||||||
spawn_snippet: spawnSnippet,
|
|
||||||
task_chain: chainCheck.suggestion,
|
|
||||||
handler_additions: config.message_types.map(mt => ({
|
|
||||||
type: mt.type,
|
|
||||||
action: `Handle ${mt.trigger}`
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write(`${workDir}/integration-report.json`, JSON.stringify(report, null, 2))
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
- **File**: `integration-report.json`
|
|
||||||
- **Format**: JSON
|
|
||||||
- **Location**: `{workDir}/integration-report.json`
|
|
||||||
|
|
||||||
## Quality Checklist
|
|
||||||
|
|
||||||
- [ ] Task prefix does not conflict with existing prefixes
|
|
||||||
- [ ] Spawn pattern compatible with coordinate.md
|
|
||||||
- [ ] All required tools are in allowed-tools
|
|
||||||
- [ ] Message types documented
|
|
||||||
- [ ] Chain position has integration suggestion
|
|
||||||
- [ ] Coordinator spawn snippet is ready to copy
|
|
||||||
|
|
||||||
## Next Phase
|
|
||||||
|
|
||||||
-> [Phase 5: Validation](05-validation.md)
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
# Phase 5: Validation
|
|
||||||
|
|
||||||
Verify completeness and quality of the generated team command.
|
|
||||||
|
|
||||||
## Objective
|
|
||||||
|
|
||||||
- Check all required sections exist
|
|
||||||
- Verify pattern compliance
|
|
||||||
- Score against quality standards
|
|
||||||
- Generate validation report
|
|
||||||
- Deliver final command file
|
|
||||||
|
|
||||||
## Input
|
|
||||||
|
|
||||||
- Dependency: `{role-name}.md` (Phase 3), `integration-report.json` (Phase 4)
|
|
||||||
- Specification: `specs/quality-standards.md`
|
|
||||||
|
|
||||||
## Execution Steps
|
|
||||||
|
|
||||||
### Step 1: Load Files
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const config = JSON.parse(Read(`${workDir}/role-config.json`))
|
|
||||||
const command = Read(`${workDir}/${config.role_name}.md`)
|
|
||||||
const integration = JSON.parse(Read(`${workDir}/integration-report.json`))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Structural Completeness Check
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const requiredSections = [
|
|
||||||
{ name: "YAML Front Matter", pattern: /^---\n[\s\S]+?\n---/ },
|
|
||||||
{ name: "group: team", pattern: /group:\s*team/ },
|
|
||||||
{ name: "Overview Section", pattern: /## Overview/ },
|
|
||||||
{ name: "Role Definition", pattern: /## Role Definition/ },
|
|
||||||
{ name: "Message Bus Section", pattern: /## .*[Mm]essage.*[Bb]us/ },
|
|
||||||
{ name: "team_msg Examples", pattern: /mcp__ccw-tools__team_msg/ },
|
|
||||||
{ name: "Message Types Table", pattern: /\| Type \| Direction/ },
|
|
||||||
{ name: "Execution Process", pattern: /## Execution Process/ },
|
|
||||||
{ name: "Phase 1: Task Discovery", pattern: /Phase 1.*Task Discovery/i },
|
|
||||||
{ name: "TaskList Usage", pattern: /TaskList/ },
|
|
||||||
{ name: "TaskGet Usage", pattern: /TaskGet/ },
|
|
||||||
{ name: "TaskUpdate Usage", pattern: /TaskUpdate/ },
|
|
||||||
{ name: "SendMessage to Coordinator", pattern: /SendMessage.*coordinator/i },
|
|
||||||
{ name: "CLI Fallback Section", pattern: /CLI 回退|CLI Fallback/ },
|
|
||||||
{ name: "ccw team CLI Example", pattern: /ccw team log/ },
|
|
||||||
{ name: "Error Handling Table", pattern: /## Error Handling/ },
|
|
||||||
{ name: "Implementation Section", pattern: /## Implementation/ }
|
|
||||||
]
|
|
||||||
|
|
||||||
const structureResults = requiredSections.map(section => ({
|
|
||||||
section: section.name,
|
|
||||||
present: section.pattern.test(command),
|
|
||||||
status: section.pattern.test(command) ? 'PASS' : 'FAIL'
|
|
||||||
}))
|
|
||||||
|
|
||||||
const structureScore = structureResults.filter(r => r.status === 'PASS').length /
|
|
||||||
structureResults.length * 100
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Pattern Compliance Check
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const patternChecks = [
|
|
||||||
{
|
|
||||||
name: "Message Bus Before SendMessage",
|
|
||||||
check: () => {
|
|
||||||
// Every SendMessage should be preceded by team_msg
|
|
||||||
const sendMessages = command.match(/SendMessage\(/g)?.length || 0
|
|
||||||
const teamMsgs = command.match(/team_msg\(/g)?.length || 0
|
|
||||||
return teamMsgs >= sendMessages
|
|
||||||
},
|
|
||||||
severity: "critical"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Task Lifecycle Pattern",
|
|
||||||
check: () => {
|
|
||||||
return command.includes('TaskList') &&
|
|
||||||
command.includes('TaskGet') &&
|
|
||||||
command.includes("status: 'in_progress'") &&
|
|
||||||
command.includes("status: 'completed'")
|
|
||||||
},
|
|
||||||
severity: "critical"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Task Prefix Usage",
|
|
||||||
check: () => {
|
|
||||||
return command.includes(`'${config.task_prefix}-'`)
|
|
||||||
},
|
|
||||||
severity: "high"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Coordinator-Only Communication",
|
|
||||||
check: () => {
|
|
||||||
return command.includes('recipient: "coordinator"') &&
|
|
||||||
!command.includes('recipient: "executor"') &&
|
|
||||||
!command.includes('recipient: "planner"')
|
|
||||||
},
|
|
||||||
severity: "high"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Next Task Loop",
|
|
||||||
check: () => {
|
|
||||||
return command.includes('Check for next') ||
|
|
||||||
command.includes('back to Phase 1')
|
|
||||||
},
|
|
||||||
severity: "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Idle on No Tasks",
|
|
||||||
check: () => {
|
|
||||||
return command.includes('idle') || command.includes('return')
|
|
||||||
},
|
|
||||||
severity: "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "CLI Fallback Present",
|
|
||||||
check: () => {
|
|
||||||
return (command.includes('CLI 回退') || command.includes('CLI Fallback')) &&
|
|
||||||
command.includes('ccw team log')
|
|
||||||
},
|
|
||||||
severity: "high"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const patternResults = patternChecks.map(pc => ({
|
|
||||||
pattern: pc.name,
|
|
||||||
compliant: pc.check(),
|
|
||||||
severity: pc.severity,
|
|
||||||
status: pc.check() ? 'PASS' : 'FAIL'
|
|
||||||
}))
|
|
||||||
|
|
||||||
const criticalFails = patternResults.filter(r =>
|
|
||||||
r.status === 'FAIL' && r.severity === 'critical'
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Quality Scoring
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const qualityDimensions = {
|
|
||||||
completeness: structureScore,
|
|
||||||
pattern_compliance: patternResults.filter(r => r.status === 'PASS').length /
|
|
||||||
patternResults.length * 100,
|
|
||||||
integration: integration.overall === 'PASS' ? 100 : 50,
|
|
||||||
consistency: checkConsistency(command, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkConsistency(command, config) {
|
|
||||||
let score = 100
|
|
||||||
// Check role name consistency
|
|
||||||
if (!command.includes(config.role_name)) score -= 20
|
|
||||||
// Check task prefix consistency
|
|
||||||
if (!command.includes(config.task_prefix)) score -= 20
|
|
||||||
// Check front matter matches config
|
|
||||||
if (!command.includes(`name: ${config.role_name}`)) score -= 20
|
|
||||||
// Check group: team
|
|
||||||
if (!command.includes('group: team')) score -= 20
|
|
||||||
return Math.max(0, score)
|
|
||||||
}
|
|
||||||
|
|
||||||
const overallScore = Object.values(qualityDimensions)
|
|
||||||
.reduce((a, b) => a + b, 0) / Object.keys(qualityDimensions).length
|
|
||||||
|
|
||||||
const qualityGate = overallScore >= 80 ? 'PASS' :
|
|
||||||
overallScore >= 60 ? 'REVIEW' : 'FAIL'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Generate Validation Report
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const report = {
|
|
||||||
role_name: config.role_name,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
scores: {
|
|
||||||
completeness: qualityDimensions.completeness,
|
|
||||||
pattern_compliance: qualityDimensions.pattern_compliance,
|
|
||||||
integration: qualityDimensions.integration,
|
|
||||||
consistency: qualityDimensions.consistency,
|
|
||||||
overall: overallScore
|
|
||||||
},
|
|
||||||
quality_gate: qualityGate,
|
|
||||||
structure_checks: structureResults,
|
|
||||||
pattern_checks: patternResults,
|
|
||||||
critical_failures: criticalFails,
|
|
||||||
recommendations: generateRecommendations(structureResults, patternResults, integration),
|
|
||||||
delivery: {
|
|
||||||
source: `${workDir}/${config.role_name}.md`,
|
|
||||||
destination: `${config.output_folder}/${config.output_file}`,
|
|
||||||
ready: qualityGate !== 'FAIL' && criticalFails.length === 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateRecommendations(structure, patterns, integration) {
|
|
||||||
const recs = []
|
|
||||||
structure.filter(s => s.status === 'FAIL').forEach(s => {
|
|
||||||
recs.push(`Add missing section: ${s.section}`)
|
|
||||||
})
|
|
||||||
patterns.filter(p => p.status === 'FAIL').forEach(p => {
|
|
||||||
recs.push(`Fix pattern violation: ${p.pattern} [${p.severity}]`)
|
|
||||||
})
|
|
||||||
if (integration.overall === 'NEEDS_ATTENTION') {
|
|
||||||
recs.push('Review integration report for coordinate.md updates')
|
|
||||||
}
|
|
||||||
return recs
|
|
||||||
}
|
|
||||||
|
|
||||||
Write(`${workDir}/validation-report.json`, JSON.stringify(report, null, 2))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6: Deliver Final File
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
if (report.delivery.ready) {
|
|
||||||
// Copy to final location
|
|
||||||
const finalContent = Read(`${workDir}/${config.role_name}.md`)
|
|
||||||
// Ensure team folder exists
|
|
||||||
Bash(`mkdir -p "${config.output_folder}"`)
|
|
||||||
Write(`${config.output_folder}/${config.output_file}`, finalContent)
|
|
||||||
|
|
||||||
// Report success
|
|
||||||
console.log(`Team command delivered to: ${config.output_folder}/${config.output_file}`)
|
|
||||||
console.log(`Skill path: /${config.skill_path}`)
|
|
||||||
console.log(`Quality score: ${overallScore.toFixed(1)}% (${qualityGate})`)
|
|
||||||
console.log(`Integration: ${integration.overall}`)
|
|
||||||
|
|
||||||
if (report.recommendations.length > 0) {
|
|
||||||
console.log('\nRecommendations:')
|
|
||||||
report.recommendations.forEach(r => console.log(` - ${r}`))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remind about coordinate.md updates
|
|
||||||
console.log('\nNext steps:')
|
|
||||||
console.log('1. Update coordinate.md to add spawn snippet (see integration-report.json)')
|
|
||||||
console.log('2. Add new message type handlers to coordinator')
|
|
||||||
console.log(`3. Test with: /${config.skill_path}`)
|
|
||||||
} else {
|
|
||||||
console.log(`Validation FAILED (score: ${overallScore.toFixed(1)}%)`)
|
|
||||||
console.log('Critical failures:')
|
|
||||||
criticalFails.forEach(f => console.log(` - ${f.pattern}`))
|
|
||||||
console.log('Fix issues and re-run Phase 3-5')
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
- **File**: `validation-report.json`
|
|
||||||
- **Format**: JSON
|
|
||||||
- **Location**: `{workDir}/validation-report.json`
|
|
||||||
- **Delivery**: `.claude/commands/team/{team-name}/{role-name}.md` (if validation passes)
|
|
||||||
|
|
||||||
## Quality Checklist
|
|
||||||
|
|
||||||
- [ ] All 15+ structural checks executed
|
|
||||||
- [ ] All 6+ pattern compliance checks executed
|
|
||||||
- [ ] No critical failures remaining
|
|
||||||
- [ ] Overall score >= 80% (PASS gate)
|
|
||||||
- [ ] Integration report reviewed
|
|
||||||
- [ ] Final file delivered to `.claude/commands/team/{team-name}/`
|
|
||||||
- [ ] Coordinator update instructions provided
|
|
||||||
|
|
||||||
## Completion
|
|
||||||
|
|
||||||
This is the final phase. The generated team command is ready for use.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,126 +0,0 @@
|
|||||||
# Quality Standards for Team Commands
|
|
||||||
|
|
||||||
Quality assessment criteria for generated team command .md files.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
|
|
||||||
| Phase | Usage | Section |
|
|
||||||
|-------|-------|---------|
|
|
||||||
| Phase 5 | Score generated command | All dimensions |
|
|
||||||
| Phase 3 | Guide generation quality | Checklist |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Quality Dimensions
|
|
||||||
|
|
||||||
### 1. Completeness (25%)
|
|
||||||
|
|
||||||
| Score | Criteria |
|
|
||||||
|-------|----------|
|
|
||||||
| 100% | All 15 required sections present with substantive content |
|
|
||||||
| 80% | 12+ sections present, minor gaps in non-critical areas |
|
|
||||||
| 60% | Core sections present (front matter, message bus, 5 phases, error handling) |
|
|
||||||
| 40% | Missing critical sections |
|
|
||||||
| 0% | Skeleton only |
|
|
||||||
|
|
||||||
**Required Sections Checklist:**
|
|
||||||
- [ ] YAML front matter with `group: team`
|
|
||||||
- [ ] Overview with core capabilities
|
|
||||||
- [ ] Role Definition (name, responsibility, communication)
|
|
||||||
- [ ] Message Bus section with team_msg examples
|
|
||||||
- [ ] Message Types table
|
|
||||||
- [ ] Execution Process overview diagram
|
|
||||||
- [ ] Phase 1: Task Discovery implementation
|
|
||||||
- [ ] Phase 2: Context Loading implementation
|
|
||||||
- [ ] Phase 3: Core Work implementation
|
|
||||||
- [ ] Phase 4: Validation/Summary implementation
|
|
||||||
- [ ] Phase 5: Report + Loop implementation
|
|
||||||
- [ ] Error Handling table
|
|
||||||
- [ ] Code examples in all phases
|
|
||||||
|
|
||||||
### 2. Pattern Compliance (25%)
|
|
||||||
|
|
||||||
| Score | Criteria |
|
|
||||||
|-------|----------|
|
|
||||||
| 100% | All 8 infrastructure patterns + selected collaboration patterns fully implemented |
|
|
||||||
| 80% | 6 core infra patterns + at least 1 collaboration pattern with convergence |
|
|
||||||
| 60% | Minimum 6 infra patterns, collaboration patterns present but incomplete |
|
|
||||||
| 40% | Missing critical patterns (message bus or task lifecycle) |
|
|
||||||
| 0% | No pattern compliance |
|
|
||||||
|
|
||||||
**Infrastructure Pattern Checklist:**
|
|
||||||
- [ ] Pattern 1: Message bus - team_msg before every SendMessage
|
|
||||||
- [ ] Pattern 1b: CLI fallback - `ccw team` CLI fallback section with parameter mapping
|
|
||||||
- [ ] Pattern 2: YAML front matter - all fields present, group: team
|
|
||||||
- [ ] Pattern 3: Task lifecycle - TaskList/Get/Update flow
|
|
||||||
- [ ] Pattern 4: Five-phase structure - all 5 phases present
|
|
||||||
- [ ] Pattern 5: Complexity-adaptive (if applicable)
|
|
||||||
- [ ] Pattern 6: Coordinator spawn compatible
|
|
||||||
- [ ] Pattern 7: Error handling table
|
|
||||||
- [ ] Pattern 8: Session files (if applicable)
|
|
||||||
|
|
||||||
**Collaboration Pattern Checklist:**
|
|
||||||
- [ ] At least one CP selected (CP-1 minimum)
|
|
||||||
- [ ] Each selected CP has convergence criteria defined
|
|
||||||
- [ ] Each selected CP has feedback loop mechanism
|
|
||||||
- [ ] Each selected CP has timeout/fallback behavior
|
|
||||||
- [ ] CP-specific message types registered in message bus section
|
|
||||||
- [ ] Escalation path defined (CP-5) for error scenarios
|
|
||||||
|
|
||||||
### 3. Integration (25%)
|
|
||||||
|
|
||||||
| Score | Criteria |
|
|
||||||
|-------|----------|
|
|
||||||
| 100% | All integration checks pass, spawn snippet ready |
|
|
||||||
| 80% | Minor integration notes, no blocking issues |
|
|
||||||
| 60% | Some checks need attention but functional |
|
|
||||||
| 40% | Task prefix conflict or missing critical tools |
|
|
||||||
| 0% | Incompatible with team system |
|
|
||||||
|
|
||||||
### 4. Consistency (25%)
|
|
||||||
|
|
||||||
| Score | Criteria |
|
|
||||||
|-------|----------|
|
|
||||||
| 100% | Role name, task prefix, message types consistent throughout |
|
|
||||||
| 80% | Minor inconsistencies in non-critical areas |
|
|
||||||
| 60% | Some mixed terminology but intent clear |
|
|
||||||
| 40% | Confusing or contradictory content |
|
|
||||||
| 0% | Internally inconsistent |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Quality Gates
|
|
||||||
|
|
||||||
| Gate | Threshold | Action |
|
|
||||||
|------|-----------|--------|
|
|
||||||
| PASS | >= 80% | Deliver to `.claude/commands/team/{team-name}/` |
|
|
||||||
| REVIEW | 60-79% | Fix recommendations, re-validate |
|
|
||||||
| FAIL | < 60% | Major rework needed, re-run from Phase 3 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Issue Classification
|
|
||||||
|
|
||||||
### Errors (Must Fix)
|
|
||||||
|
|
||||||
- Missing YAML front matter
|
|
||||||
- Missing `group: team`
|
|
||||||
- No message bus section
|
|
||||||
- No task lifecycle (TaskList/Get/Update)
|
|
||||||
- No SendMessage to coordinator
|
|
||||||
- Task prefix conflicts with existing
|
|
||||||
|
|
||||||
### Warnings (Should Fix)
|
|
||||||
|
|
||||||
- Missing error handling table
|
|
||||||
- Incomplete Phase implementation (skeleton only)
|
|
||||||
- Missing team_msg before some SendMessage calls
|
|
||||||
- Missing CLI fallback section (`### CLI 回退` with `ccw team` examples)
|
|
||||||
- No complexity-adaptive routing when role is complex
|
|
||||||
|
|
||||||
### Info (Nice to Have)
|
|
||||||
|
|
||||||
- Code examples could be more detailed
|
|
||||||
- Additional message type examples
|
|
||||||
- Session file structure documentation
|
|
||||||
- CLI integration examples
|
|
||||||
@@ -1,472 +0,0 @@
|
|||||||
# Team Command Design Patterns
|
|
||||||
|
|
||||||
> Extracted from 5 production team commands: coordinate, plan, execute, test, review
|
|
||||||
> Extended with 10 collaboration patterns for diverse team interaction models
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
Team Design Patterns
|
|
||||||
├── Section A: Infrastructure Patterns (8) ← HOW to build a team command
|
|
||||||
│ ├── Pattern 1: Message Bus Integration
|
|
||||||
│ ├── Pattern 2: YAML Front Matter
|
|
||||||
│ ├── Pattern 3: Task Lifecycle
|
|
||||||
│ ├── Pattern 4: Five-Phase Execution
|
|
||||||
│ ├── Pattern 5: Complexity-Adaptive Routing
|
|
||||||
│ ├── Pattern 6: Coordinator Spawn Integration
|
|
||||||
│ ├── Pattern 7: Error Handling Table
|
|
||||||
│ └── Pattern 8: Session File Structure
|
|
||||||
│
|
|
||||||
└── Section B: Collaboration Patterns (10) ← HOW agents interact
|
|
||||||
├── CP-1: Linear Pipeline (线性流水线)
|
|
||||||
├── CP-2: Review-Fix Cycle (审查修复循环)
|
|
||||||
├── CP-3: Parallel Fan-out/Fan-in (并行扇出扇入)
|
|
||||||
├── CP-4: Consensus Gate (共识门控)
|
|
||||||
├── CP-5: Escalation Chain (逐级升级)
|
|
||||||
├── CP-6: Incremental Delivery (增量交付)
|
|
||||||
├── CP-7: Swarming (群策攻关)
|
|
||||||
├── CP-8: Consulting/Advisory (咨询顾问)
|
|
||||||
├── CP-9: Dual-Track (双轨并行)
|
|
||||||
└── CP-10: Post-Mortem (复盘回顾)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Section B** collaboration patterns are documented in: [collaboration-patterns.md](collaboration-patterns.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
|
|
||||||
| Phase | Usage | Section |
|
|
||||||
|-------|-------|---------|
|
|
||||||
| Phase 0 | Understand all patterns before design | All sections |
|
|
||||||
| Phase 2 | Select applicable infrastructure + collaboration patterns | Pattern catalog |
|
|
||||||
| Phase 3 | Apply patterns during generation | Implementation details |
|
|
||||||
| Phase 4 | Verify compliance | Checklists |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Section A: Infrastructure Patterns
|
|
||||||
|
|
||||||
## Pattern 1: Message Bus Integration
|
|
||||||
|
|
||||||
Every teammate must use `mcp__ccw-tools__team_msg` for persistent logging before every `SendMessage`.
|
|
||||||
|
|
||||||
### Structure
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// BEFORE every SendMessage, call:
|
|
||||||
mcp__ccw-tools__team_msg({
|
|
||||||
operation: "log",
|
|
||||||
team: teamName,
|
|
||||||
from: "<role-name>", // planner | executor | tester | <new-role>
|
|
||||||
to: "coordinator",
|
|
||||||
type: "<message-type>",
|
|
||||||
summary: "<human-readable summary>",
|
|
||||||
ref: "<optional file path>",
|
|
||||||
data: { /* optional structured payload */ }
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Standard Message Types
|
|
||||||
|
|
||||||
| Type | Direction | Trigger | Payload |
|
|
||||||
|------|-----------|---------|---------|
|
|
||||||
| `plan_ready` | planner -> coordinator | Plan generation complete | `{ taskCount, complexity }` |
|
|
||||||
| `plan_approved` | coordinator -> planner | Plan reviewed | `{ approved: true }` |
|
|
||||||
| `plan_revision` | planner -> coordinator | Plan modified per feedback | `{ changes }` |
|
|
||||||
| `task_unblocked` | coordinator -> any | Dependency resolved | `{ taskId }` |
|
|
||||||
| `impl_complete` | executor -> coordinator | Implementation done | `{ changedFiles, syntaxClean }` |
|
|
||||||
| `impl_progress` | any -> coordinator | Progress update | `{ batch, total }` |
|
|
||||||
| `test_result` | tester -> coordinator | Test cycle end | `{ passRate, iterations }` |
|
|
||||||
| `review_result` | tester -> coordinator | Review done | `{ verdict, findings }` |
|
|
||||||
| `fix_required` | any -> coordinator | Critical issues | `{ details[] }` |
|
|
||||||
| `error` | any -> coordinator | Blocking error | `{ message }` |
|
|
||||||
| `shutdown` | coordinator -> all | Team dissolved | `{}` |
|
|
||||||
|
|
||||||
### Collaboration Pattern Message Types
|
|
||||||
|
|
||||||
| Type | Used By | Direction | Trigger |
|
|
||||||
|------|---------|-----------|---------|
|
|
||||||
| `vote` | CP-4 Consensus | any -> coordinator | Agent casts vote on proposal |
|
|
||||||
| `escalate` | CP-5 Escalation | any -> coordinator | Agent escalates unresolved issue |
|
|
||||||
| `increment_ready` | CP-6 Incremental | executor -> coordinator | Increment delivered for validation |
|
|
||||||
| `swarm_join` | CP-7 Swarming | any -> coordinator | Agent joins swarm on blocker |
|
|
||||||
| `consult_request` | CP-8 Consulting | any -> specialist | Agent requests expert advice |
|
|
||||||
| `consult_response` | CP-8 Consulting | specialist -> requester | Expert provides advice |
|
|
||||||
| `sync_checkpoint` | CP-9 Dual-Track | any -> coordinator | Track reaches sync point |
|
|
||||||
| `retro_finding` | CP-10 Post-Mortem | any -> coordinator | Retrospective insight |
|
|
||||||
|
|
||||||
### Adding New Message Types
|
|
||||||
|
|
||||||
When designing a new role, define role-specific message types following the convention:
|
|
||||||
- `{action}_ready` - Work product ready for review
|
|
||||||
- `{action}_complete` - Work phase finished
|
|
||||||
- `{action}_progress` - Intermediate progress update
|
|
||||||
|
|
||||||
### CLI Fallback
|
|
||||||
|
|
||||||
When `mcp__ccw-tools__team_msg` MCP is unavailable, use `ccw team` CLI as equivalent fallback:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Fallback: Replace MCP call with Bash CLI (parameters map 1:1)
|
|
||||||
Bash(`ccw team log --team "${teamName}" --from "<role>" --to "coordinator" --type "<type>" --summary "<summary>" [--ref <path>] [--data '<json>'] --json`)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Parameter mapping**: `team_msg(params)` → `ccw team <operation> --team <team> [--from/--to/--type/--summary/--ref/--data/--id/--last] [--json]`
|
|
||||||
|
|
||||||
**Coordinator** uses all 4 operations: `log`, `list`, `status`, `read`
|
|
||||||
**Teammates** primarily use: `log`
|
|
||||||
|
|
||||||
### Message Bus Section Template
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## 消息总线
|
|
||||||
|
|
||||||
每次 SendMessage **前**,必须调用 `mcp__ccw-tools__team_msg` 记录消息:
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "<role>", to: "coordinator", type: "<type>", summary: "<summary>" })
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### 支持的 Message Types
|
|
||||||
|
|
||||||
| Type | 方向 | 触发时机 | 说明 |
|
|
||||||
|------|------|----------|------|
|
|
||||||
| `<type>` | <role> → coordinator | <when> | <what> |
|
|
||||||
|
|
||||||
### CLI 回退
|
|
||||||
|
|
||||||
当 `mcp__ccw-tools__team_msg` MCP 不可用时,使用 `ccw team` CLI 作为等效回退:
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// 回退: 将 MCP 调用替换为 Bash CLI(参数一一对应)
|
|
||||||
Bash(\`ccw team log --team "${teamName}" --from "<role>" --to "coordinator" --type "<type>" --summary "<summary>" --json\`)
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
**参数映射**: `team_msg(params)` → `ccw team log --team <team> --from <role> --to coordinator --type <type> --summary "<text>" [--ref <path>] [--data '<json>'] [--json]`
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern 2: YAML Front Matter
|
|
||||||
|
|
||||||
Every team command file must start with standardized YAML front matter.
|
|
||||||
|
|
||||||
### Structure
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
name: <command-name>
|
|
||||||
description: Team <role> - <capabilities in Chinese>
|
|
||||||
argument-hint: ""
|
|
||||||
allowed-tools: SendMessage(*), TaskUpdate(*), TaskList(*), TaskGet(*), TodoWrite(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*), Task(*)
|
|
||||||
group: team
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
### Field Rules
|
|
||||||
|
|
||||||
| Field | Rule | Example |
|
|
||||||
|-------|------|---------|
|
|
||||||
| `name` | Lowercase, matches filename | `plan`, `execute`, `test` |
|
|
||||||
| `description` | `Team <role> -` prefix + Chinese capability list | `Team planner - 多角度代码探索、结构化实现规划` |
|
|
||||||
| `argument-hint` | Empty string for teammates, has hint for coordinator | `""` |
|
|
||||||
| `allowed-tools` | Start with `SendMessage(*), TaskUpdate(*), TaskList(*), TaskGet(*)` | See each role |
|
|
||||||
| `group` | Always `team` | `team` |
|
|
||||||
|
|
||||||
### Minimum Tool Set (All Teammates)
|
|
||||||
|
|
||||||
```
|
|
||||||
SendMessage(*), TaskUpdate(*), TaskList(*), TaskGet(*), TodoWrite(*), Read(*), Bash(*), Glob(*), Grep(*)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Role-Specific Additional Tools
|
|
||||||
|
|
||||||
| Role Type | Additional Tools |
|
|
||||||
|-----------|-----------------|
|
|
||||||
| Read-only (reviewer, analyzer) | None extra |
|
|
||||||
| Write-capable (executor, fixer) | `Write(*), Edit(*)` |
|
|
||||||
| Agent-delegating (planner, executor) | `Task(*)` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern 3: Task Lifecycle
|
|
||||||
|
|
||||||
All teammates follow the same task discovery and lifecycle pattern.
|
|
||||||
|
|
||||||
### Standard Flow
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Step 1: Find my tasks
|
|
||||||
const tasks = TaskList()
|
|
||||||
const myTasks = tasks.filter(t =>
|
|
||||||
t.subject.startsWith('<PREFIX>-') && // PLAN-*, IMPL-*, TEST-*, REVIEW-*
|
|
||||||
t.owner === '<role-name>' &&
|
|
||||||
t.status === 'pending' &&
|
|
||||||
t.blockedBy.length === 0 // Not blocked
|
|
||||||
)
|
|
||||||
|
|
||||||
// Step 2: No tasks -> idle
|
|
||||||
if (myTasks.length === 0) return
|
|
||||||
|
|
||||||
// Step 3: Claim task (lowest ID first)
|
|
||||||
const task = TaskGet({ taskId: myTasks[0].id })
|
|
||||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
|
||||||
|
|
||||||
// Step 4: Execute work
|
|
||||||
// ... role-specific logic ...
|
|
||||||
|
|
||||||
// Step 5: Complete and loop
|
|
||||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
|
||||||
|
|
||||||
// Step 6: Check for next task
|
|
||||||
const nextTasks = TaskList().filter(t =>
|
|
||||||
t.subject.startsWith('<PREFIX>-') &&
|
|
||||||
t.owner === '<role-name>' &&
|
|
||||||
t.status === 'pending' &&
|
|
||||||
t.blockedBy.length === 0
|
|
||||||
)
|
|
||||||
if (nextTasks.length > 0) {
|
|
||||||
// Continue with next task -> back to Step 3
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task Prefix Convention
|
|
||||||
|
|
||||||
| Prefix | Role | Example |
|
|
||||||
|--------|------|---------|
|
|
||||||
| `PLAN-` | planner | `PLAN-001: Explore and plan implementation` |
|
|
||||||
| `IMPL-` | executor | `IMPL-001: Implement approved plan` |
|
|
||||||
| `TEST-` | tester | `TEST-001: Test-fix cycle` |
|
|
||||||
| `REVIEW-` | tester | `REVIEW-001: Code review and requirement verification` |
|
|
||||||
| `<NEW>-` | new role | Must be unique, uppercase, hyphen-suffixed |
|
|
||||||
|
|
||||||
### Task Chain (defined in coordinate.md)
|
|
||||||
|
|
||||||
```
|
|
||||||
PLAN-001 → IMPL-001 → TEST-001 + REVIEW-001
|
|
||||||
↑ blockedBy ↑ blockedBy
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern 4: Five-Phase Execution Structure
|
|
||||||
|
|
||||||
Every team command follows a consistent 5-phase internal structure.
|
|
||||||
|
|
||||||
### Standard Phases
|
|
||||||
|
|
||||||
| Phase | Purpose | Common Actions |
|
|
||||||
|-------|---------|----------------|
|
|
||||||
| Phase 1: Task Discovery | Find and claim assigned tasks | TaskList, TaskGet, TaskUpdate |
|
|
||||||
| Phase 2: Context Loading | Load necessary context for work | Read plan/config, detect framework |
|
|
||||||
| Phase 3: Core Work | Execute primary responsibility | Role-specific logic |
|
|
||||||
| Phase 4: Validation/Summary | Verify work quality | Syntax check, criteria verification |
|
|
||||||
| Phase 5: Report + Loop | Report to coordinator, check next | SendMessage, TaskUpdate, TaskList |
|
|
||||||
|
|
||||||
### Phase Structure Template
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
### Phase N: <Phase Name>
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Implementation code
|
|
||||||
\`\`\`
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern 5: Complexity-Adaptive Routing
|
|
||||||
|
|
||||||
All roles that process varying-difficulty tasks should implement adaptive routing.
|
|
||||||
|
|
||||||
### Decision Logic
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
function assessComplexity(description) {
|
|
||||||
let score = 0
|
|
||||||
if (/refactor|architect|restructure|module|system/.test(description)) score += 2
|
|
||||||
if (/multiple|across|cross/.test(description)) score += 2
|
|
||||||
if (/integrate|api|database/.test(description)) score += 1
|
|
||||||
if (/security|performance/.test(description)) score += 1
|
|
||||||
return score >= 4 ? 'High' : score >= 2 ? 'Medium' : 'Low'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Routing Table
|
|
||||||
|
|
||||||
| Complexity | Direct Claude | CLI Agent | Sub-agent |
|
|
||||||
|------------|---------------|-----------|-----------|
|
|
||||||
| Low | Direct execution | - | - |
|
|
||||||
| Medium | - | `cli-explore-agent` / `cli-lite-planning-agent` | - |
|
|
||||||
| High | - | CLI agent | `code-developer` / `universal-executor` |
|
|
||||||
|
|
||||||
### Sub-agent Delegation Pattern
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
Task({
|
|
||||||
subagent_type: "<agent-type>",
|
|
||||||
run_in_background: false,
|
|
||||||
description: "<brief description>",
|
|
||||||
prompt: `
|
|
||||||
## Task Objective
|
|
||||||
${taskDescription}
|
|
||||||
|
|
||||||
## Output Location
|
|
||||||
${sessionFolder}/${outputFile}
|
|
||||||
|
|
||||||
## MANDATORY FIRST STEPS
|
|
||||||
1. Read: .workflow/project-tech.json (if exists)
|
|
||||||
2. Read: .workflow/project-guidelines.json (if exists)
|
|
||||||
|
|
||||||
## Expected Output
|
|
||||||
${expectedFormat}
|
|
||||||
`
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern 6: Coordinator Spawn Integration
|
|
||||||
|
|
||||||
New teammates must be spawnable from coordinate.md using standard pattern.
|
|
||||||
|
|
||||||
### Skill Path Format (Folder-Based)
|
|
||||||
|
|
||||||
Team commands use folder-based organization with colon-separated skill paths:
|
|
||||||
|
|
||||||
```
|
|
||||||
File location: .claude/commands/team/{team-name}/{role-name}.md
|
|
||||||
Skill path: team:{team-name}:{role-name}
|
|
||||||
|
|
||||||
Example:
|
|
||||||
.claude/commands/team/spec/analyst.md → team:spec:analyst
|
|
||||||
.claude/commands/team/security/scanner.md → team:security:scanner
|
|
||||||
```
|
|
||||||
|
|
||||||
### Spawn Template
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
Task({
|
|
||||||
subagent_type: "general-purpose",
|
|
||||||
team_name: teamName,
|
|
||||||
name: "<role-name>",
|
|
||||||
prompt: `You are team "${teamName}" <ROLE>.
|
|
||||||
|
|
||||||
When you receive <PREFIX>-* tasks, call Skill(skill="team:${teamName}:<role-name>") to execute.
|
|
||||||
|
|
||||||
Current requirement: ${taskDescription}
|
|
||||||
Constraints: ${constraints}
|
|
||||||
|
|
||||||
## Message Bus (Required)
|
|
||||||
Before each SendMessage, call mcp__ccw-tools__team_msg:
|
|
||||||
mcp__ccw-tools__team_msg({ operation: "log", team: "${teamName}", from: "<role>", to: "coordinator", type: "<type>", summary: "<summary>" })
|
|
||||||
|
|
||||||
Workflow:
|
|
||||||
1. TaskList -> find <PREFIX>-* tasks assigned to you
|
|
||||||
2. Skill(skill="team:${teamName}:<role-name>") to execute
|
|
||||||
3. team_msg log + SendMessage results to coordinator
|
|
||||||
4. TaskUpdate completed -> check next task`
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern 7: Error Handling Table
|
|
||||||
|
|
||||||
Every command ends with a standardized error handling table.
|
|
||||||
|
|
||||||
### Template
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
| Scenario | Resolution |
|
|
||||||
|----------|------------|
|
|
||||||
| No tasks available | Idle, wait for coordinator assignment |
|
|
||||||
| Plan/Context file not found | Notify coordinator, request location |
|
|
||||||
| Sub-agent failure | Retry once, then fallback to direct execution |
|
|
||||||
| Max iterations exceeded | Report to coordinator, suggest intervention |
|
|
||||||
| Critical issue beyond scope | SendMessage fix_required to coordinator |
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern 8: Session File Structure
|
|
||||||
|
|
||||||
Roles that produce artifacts follow standard session directory patterns.
|
|
||||||
|
|
||||||
### Convention
|
|
||||||
|
|
||||||
```
|
|
||||||
.workflow/.team-<purpose>/{identifier}-{YYYY-MM-DD}/
|
|
||||||
├── <work-product-files>
|
|
||||||
├── manifest.json (if multiple outputs)
|
|
||||||
└── .task/ (if generating task files)
|
|
||||||
├── TASK-001.json
|
|
||||||
└── TASK-002.json
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Section B: Collaboration Patterns
|
|
||||||
|
|
||||||
> Complete specification: [collaboration-patterns.md](collaboration-patterns.md)
|
|
||||||
|
|
||||||
## Collaboration Pattern Quick Reference
|
|
||||||
|
|
||||||
Every collaboration pattern has these standard elements:
|
|
||||||
|
|
||||||
| Element | Description |
|
|
||||||
|---------|-------------|
|
|
||||||
| **Entry Condition** | When to activate this pattern |
|
|
||||||
| **Workflow** | Step-by-step execution flow |
|
|
||||||
| **Convergence Criteria** | How the pattern terminates successfully |
|
|
||||||
| **Feedback Loop** | How information flows back to enable correction |
|
|
||||||
| **Timeout/Fallback** | What happens when the pattern doesn't converge |
|
|
||||||
| **Max Iterations** | Hard limit on cycles (where applicable) |
|
|
||||||
|
|
||||||
### Pattern Selection Guide
|
|
||||||
|
|
||||||
| Scenario | Recommended Pattern | Why |
|
|
||||||
|----------|-------------------|-----|
|
|
||||||
| Standard feature development | CP-1: Linear Pipeline | Well-defined sequential stages |
|
|
||||||
| Code review with fixes needed | CP-2: Review-Fix Cycle | Iterative improvement until quality met |
|
|
||||||
| Multi-angle analysis needed | CP-3: Fan-out/Fan-in | Parallel exploration, aggregated results |
|
|
||||||
| Critical decision (architecture, security) | CP-4: Consensus Gate | Multiple perspectives before committing |
|
|
||||||
| Agent stuck / self-repair failed | CP-5: Escalation Chain | Progressive expertise levels |
|
|
||||||
| Large feature (many files) | CP-6: Incremental Delivery | Validated increments reduce risk |
|
|
||||||
| Blocking issue stalls pipeline | CP-7: Swarming | All resources on one problem |
|
|
||||||
| Domain-specific expertise needed | CP-8: Consulting | Expert advice without role change |
|
|
||||||
| Design + Implementation parallel | CP-9: Dual-Track | Faster delivery with sync checkpoints |
|
|
||||||
| Post-completion learning | CP-10: Post-Mortem | Capture insights for future improvement |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern Summary Checklist
|
|
||||||
|
|
||||||
When designing a new team command, verify:
|
|
||||||
|
|
||||||
### Infrastructure Patterns
|
|
||||||
- [ ] YAML front matter with `group: team`
|
|
||||||
- [ ] Message bus section with `team_msg` logging
|
|
||||||
- [ ] CLI fallback section with `ccw team` CLI examples and parameter mapping
|
|
||||||
- [ ] Role-specific message types defined
|
|
||||||
- [ ] Task lifecycle: TaskList -> TaskGet -> TaskUpdate flow
|
|
||||||
- [ ] Unique task prefix (no collision with existing PLAN/IMPL/TEST/REVIEW, scan `team/**/*.md`)
|
|
||||||
- [ ] 5-phase execution structure
|
|
||||||
- [ ] Complexity-adaptive routing (if applicable)
|
|
||||||
- [ ] Coordinator spawn template integration
|
|
||||||
- [ ] Error handling table
|
|
||||||
- [ ] SendMessage communication to coordinator only
|
|
||||||
- [ ] Session file structure (if producing artifacts)
|
|
||||||
|
|
||||||
### Collaboration Patterns
|
|
||||||
- [ ] At least one collaboration pattern selected
|
|
||||||
- [ ] Convergence criteria defined (max iterations / quality gate / timeout)
|
|
||||||
- [ ] Feedback loop implemented (how results flow back)
|
|
||||||
- [ ] Timeout/fallback behavior specified
|
|
||||||
- [ ] Pattern-specific message types registered
|
|
||||||
- [ ] Coordinator aware of pattern (can route messages accordingly)
|
|
||||||
@@ -1,230 +0,0 @@
|
|||||||
# Team Command Template
|
|
||||||
|
|
||||||
Ready-to-use template for generating team command .md files.
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Provide a complete, fill-in-the-blanks template for generating new team command files that comply with all design patterns.
|
|
||||||
|
|
||||||
## Usage Context
|
|
||||||
|
|
||||||
| Phase | Usage |
|
|
||||||
|-------|-------|
|
|
||||||
| Phase 0 | Read to understand output structure |
|
|
||||||
| Phase 3 | Apply with role-specific content |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Template
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
name: {{role_name}}
|
|
||||||
description: Team {{role_name}} - {{description_cn}}
|
|
||||||
argument-hint: ""
|
|
||||||
allowed-tools: {{allowed_tools}}
|
|
||||||
group: team
|
|
||||||
---
|
|
||||||
|
|
||||||
# Team {{display_name}} Command (/{{skill_path}})
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Team {{role_name}} role command. Operates as a teammate within an Agent Team, responsible for {{responsibility_type}}.
|
|
||||||
|
|
||||||
**Core capabilities:**
|
|
||||||
- Task discovery from shared team task list ({{task_prefix}}-* tasks)
|
|
||||||
{{#if adaptive_routing}}
|
|
||||||
- Complexity-adaptive routing (Low -> direct, Medium/High -> agent)
|
|
||||||
{{/if}}
|
|
||||||
- {{responsibility_type}}-specific processing
|
|
||||||
- Structured result reporting to coordinator
|
|
||||||
|
|
||||||
## Role Definition
|
|
||||||
|
|
||||||
**Name**: `{{role_name}}`
|
|
||||||
**Responsibility**: {{phase2_name}} -> {{phase3_name}} -> Report results
|
|
||||||
**Communication**: SendMessage to coordinator only
|
|
||||||
|
|
||||||
## Message Bus
|
|
||||||
|
|
||||||
Every SendMessage **before**, must call `mcp__ccw-tools__team_msg` to log:
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "{{role_name}}", to: "coordinator", type: "<type>", summary: "<summary>" })
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### Supported Message Types
|
|
||||||
|
|
||||||
| Type | Direction | Trigger | Description |
|
|
||||||
|------|-----------|---------|-------------|
|
|
||||||
{{#each message_types}}
|
|
||||||
| `{{this.type}}` | {{../role_name}} -> coordinator | {{this.trigger}} | {{this.description}} |
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
{{#each message_types}}
|
|
||||||
// {{this.trigger}}
|
|
||||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "{{../role_name}}", to: "coordinator", type: "{{this.type}}", summary: "{{this.trigger}}" })
|
|
||||||
{{/each}}
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### CLI 回退
|
|
||||||
|
|
||||||
当 `mcp__ccw-tools__team_msg` MCP 不可用时,使用 `ccw team` CLI 作为等效回退:
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// 回退: 将 MCP 调用替换为 Bash CLI(参数一一对应)
|
|
||||||
Bash(\`ccw team log --team "${teamName}" --from "{{role_name}}" --to "coordinator" --type "{{primary_message_type}}" --summary "<摘要>" --json\`)
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
**参数映射**: `team_msg(params)` → `ccw team log --team <team> --from {{role_name}} --to coordinator --type <type> --summary "<text>" [--ref <path>] [--data '<json>'] [--json]`
|
|
||||||
|
|
||||||
## Execution Process
|
|
||||||
|
|
||||||
\`\`\`
|
|
||||||
Phase 1: Task Discovery
|
|
||||||
|-- TaskList to find unblocked {{task_prefix}}-* tasks
|
|
||||||
|-- TaskGet to read full task details
|
|
||||||
\`-- TaskUpdate to mark in_progress
|
|
||||||
|
|
||||||
Phase 2: {{phase2_name}}
|
|
||||||
|
|
||||||
Phase 3: {{phase3_name}}
|
|
||||||
|
|
||||||
Phase 4: {{phase4_name}}
|
|
||||||
|
|
||||||
Phase 5: Report to Coordinator
|
|
||||||
|-- team_msg log + SendMessage results
|
|
||||||
|-- TaskUpdate completed
|
|
||||||
\`-- Check for next {{task_prefix}}-* task
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
### Phase 1: Task Discovery
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
const tasks = TaskList()
|
|
||||||
const myTasks = tasks.filter(t =>
|
|
||||||
t.subject.startsWith('{{task_prefix}}-') &&
|
|
||||||
t.owner === '{{role_name}}' &&
|
|
||||||
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: {{phase2_name}}
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// TODO: Implement context loading for {{role_name}}
|
|
||||||
// Reference: .claude/commands/team/{{reference_command}}.md Phase 2
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### Phase 3: {{phase3_name}}
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// TODO: Implement core {{role_name}} logic
|
|
||||||
// Reference: .claude/commands/team/{{reference_command}}.md Phase 3
|
|
||||||
{{#if adaptive_routing}}
|
|
||||||
|
|
||||||
// Complexity-adaptive execution
|
|
||||||
if (complexity === 'Low') {
|
|
||||||
// Direct execution
|
|
||||||
} else {
|
|
||||||
// Delegate to sub-agent
|
|
||||||
Task({
|
|
||||||
subagent_type: "universal-executor",
|
|
||||||
run_in_background: false,
|
|
||||||
description: "{{role_name}} work",
|
|
||||||
prompt: `Execute {{role_name}} task: ${task.description}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{{/if}}
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### Phase 4: {{phase4_name}}
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// TODO: Implement validation/summary for {{role_name}}
|
|
||||||
// Reference: .claude/commands/team/{{reference_command}}.md Phase 4
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### Phase 5: Report to Coordinator
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
mcp__ccw-tools__team_msg({
|
|
||||||
operation: "log", team: teamName,
|
|
||||||
from: "{{role_name}}", to: "coordinator",
|
|
||||||
type: "{{primary_message_type}}",
|
|
||||||
summary: `{{task_prefix}} complete: ${task.subject}`
|
|
||||||
})
|
|
||||||
|
|
||||||
SendMessage({
|
|
||||||
type: "message",
|
|
||||||
recipient: "coordinator",
|
|
||||||
content: `## {{display_name}} Results
|
|
||||||
|
|
||||||
**Task**: ${task.subject}
|
|
||||||
**Status**: ${resultStatus}
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
${resultSummary}`,
|
|
||||||
summary: `{{task_prefix}} complete`
|
|
||||||
})
|
|
||||||
|
|
||||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
|
||||||
|
|
||||||
const nextTasks = TaskList().filter(t =>
|
|
||||||
t.subject.startsWith('{{task_prefix}}-') &&
|
|
||||||
t.owner === '{{role_name}}' &&
|
|
||||||
t.status === 'pending' &&
|
|
||||||
t.blockedBy.length === 0
|
|
||||||
)
|
|
||||||
|
|
||||||
if (nextTasks.length > 0) {
|
|
||||||
// Continue with next task -> back to Phase 1
|
|
||||||
}
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
| Scenario | Resolution |
|
|
||||||
|----------|------------|
|
|
||||||
| No {{task_prefix}}-* tasks available | Idle, wait for coordinator assignment |
|
|
||||||
| Context/Plan file not found | Notify coordinator, request location |
|
|
||||||
{{#if adaptive_routing}}
|
|
||||||
| Sub-agent failure | Retry once, then fallback to direct execution |
|
|
||||||
{{/if}}
|
|
||||||
| Critical issue beyond scope | SendMessage fix_required to coordinator |
|
|
||||||
| Unexpected error | Log error via team_msg, report to coordinator |
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Variable Reference
|
|
||||||
|
|
||||||
| Variable | Source | Description |
|
|
||||||
|----------|--------|-------------|
|
|
||||||
| `{{team_name}}` | config.team_name | Team folder name (lowercase) |
|
|
||||||
| `{{role_name}}` | config.role_name | Role identifier (lowercase) |
|
|
||||||
| `{{skill_path}}` | config.skill_path | Full skill path (e.g., `team:spec:analyst`) |
|
|
||||||
| `{{display_name}}` | config.display_name | Human-readable role name |
|
|
||||||
| `{{description_cn}}` | config.description_cn | Chinese description |
|
|
||||||
| `{{task_prefix}}` | config.task_prefix | Task prefix (UPPERCASE) |
|
|
||||||
| `{{allowed_tools}}` | config.allowed_tools | Tool list |
|
|
||||||
| `{{responsibility_type}}` | config.responsibility_type | Role type |
|
|
||||||
| `{{adaptive_routing}}` | config.adaptive_routing | Boolean |
|
|
||||||
| `{{message_types}}` | config.message_types | Array of message type objects |
|
|
||||||
| `{{phase2_name}}` | patterns.phase_structure.phase2 | Phase 2 name |
|
|
||||||
| `{{phase3_name}}` | patterns.phase_structure.phase3 | Phase 3 name |
|
|
||||||
| `{{phase4_name}}` | patterns.phase_structure.phase4 | Phase 4 name |
|
|
||||||
| `{{reference_command}}` | patterns.similar_to.primary | Most similar existing command |
|
|
||||||
| `{{primary_message_type}}` | config.message_types[0].type | Primary message type |
|
|
||||||
264
.claude/skills/team-planex/SKILL.md
Normal file
264
.claude/skills/team-planex/SKILL.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
---
|
||||||
|
name: team-planex
|
||||||
|
description: Unified team skill for plan-and-execute pipeline. 2-member team (planner + executor) with wave pipeline for concurrent planning and execution. All roles invoke this skill with --role arg. Triggers on "team planex".
|
||||||
|
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Task(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Team PlanEx
|
||||||
|
|
||||||
|
2 成员边规划边执行团队。通过 Wave Pipeline(波次流水线)实现 planner 和 executor 并行工作:planner 完成一个 wave 的 queue 后立即创建 EXEC-* 任务,同时进入下一 wave 规划。所有成员通过 `--role=xxx` 路由。
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────┐
|
||||||
|
│ Skill(skill="team-planex", args="--role=xxx") │
|
||||||
|
└────────────────┬─────────────────────────────┘
|
||||||
|
│ Role Router
|
||||||
|
┌───────┴───────┐
|
||||||
|
↓ ↓
|
||||||
|
┌─────────┐ ┌──────────┐
|
||||||
|
│ planner │ │ executor │
|
||||||
|
│ PLAN-* │ │ EXEC-* │
|
||||||
|
└─────────┘ └──────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计原则**: 只有 2 个角色,没有独立 coordinator。SKILL.md 入口承担轻量编排(创建团队、派发初始任务链),然后 planner 担任 lead 角色持续推进。
|
||||||
|
|
||||||
|
## Role Router
|
||||||
|
|
||||||
|
### Input Parsing
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const args = "$ARGUMENTS"
|
||||||
|
const roleMatch = args.match(/--role[=\s]+(\w+)/)
|
||||||
|
|
||||||
|
if (!roleMatch) {
|
||||||
|
// No --role: orchestration mode (lightweight coordinator)
|
||||||
|
// → See "Orchestration Mode" section below
|
||||||
|
}
|
||||||
|
|
||||||
|
const role = roleMatch[1]
|
||||||
|
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "planex"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Role Dispatch
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const VALID_ROLES = {
|
||||||
|
"planner": { file: "roles/planner.md", prefix: "PLAN" },
|
||||||
|
"executor": { file: "roles/executor.md", prefix: "EXEC" }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!VALID_ROLES[role]) {
|
||||||
|
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and execute role-specific logic
|
||||||
|
Read(VALID_ROLES[role].file)
|
||||||
|
// → Execute the 5-phase process defined in that file
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available Roles
|
||||||
|
|
||||||
|
| Role | Task Prefix | Responsibility | Reuses Agent | Role File |
|
||||||
|
|------|-------------|----------------|--------------|-----------|
|
||||||
|
| `planner` | PLAN-* | 需求拆解 → issue 创建 → 方案设计 → 队列编排 → EXEC 任务派发 | issue-plan-agent, issue-queue-agent | [roles/planner.md](roles/planner.md) |
|
||||||
|
| `executor` | EXEC-* | 加载 solution → 代码实现 → 测试 → 提交 | code-developer | [roles/executor.md](roles/executor.md) |
|
||||||
|
|
||||||
|
## Input Types
|
||||||
|
|
||||||
|
支持 3 种输入方式(通过 args 传入 planner):
|
||||||
|
|
||||||
|
| 输入类型 | 格式 | 示例 |
|
||||||
|
|----------|------|------|
|
||||||
|
| Issue IDs | 直接传入 ID | `--role=planner ISS-20260215-001 ISS-20260215-002` |
|
||||||
|
| 需求文本 | `--text '...'` | `--role=planner --text '实现用户认证模块'` |
|
||||||
|
| Plan 文件 | `--plan path` | `--role=planner --plan plan/2026-02-15-auth.md` |
|
||||||
|
|
||||||
|
## Shared Infrastructure
|
||||||
|
|
||||||
|
### Role Isolation Rules
|
||||||
|
|
||||||
|
#### Output Tagging(强制)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
SendMessage({ content: `## [${role}] ...`, summary: `[${role}] ...` })
|
||||||
|
mcp__ccw-tools__team_msg({ summary: `[${role}] ...` })
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Planner 边界
|
||||||
|
|
||||||
|
| 允许 | 禁止 |
|
||||||
|
|------|------|
|
||||||
|
| 需求拆解 (issue 创建) | ❌ 直接编写/修改代码 |
|
||||||
|
| 方案设计 (issue-plan-agent) | ❌ 调用 code-developer |
|
||||||
|
| 队列编排 (issue-queue-agent) | ❌ 运行测试 |
|
||||||
|
| 创建 EXEC-* 任务 | ❌ git commit |
|
||||||
|
| 监控进度 (消息总线) | |
|
||||||
|
|
||||||
|
#### Executor 边界
|
||||||
|
|
||||||
|
| 允许 | 禁止 |
|
||||||
|
|------|------|
|
||||||
|
| 处理 EXEC-* 前缀的任务 | ❌ 创建 issue |
|
||||||
|
| 调用 code-developer 实现 | ❌ 修改 solution/queue |
|
||||||
|
| 运行测试验证 | ❌ 为 planner 创建 PLAN-* 任务 |
|
||||||
|
| git commit 提交 | ❌ 直接与用户交互 (AskUserQuestion) |
|
||||||
|
| SendMessage 给 planner | |
|
||||||
|
|
||||||
|
### Team Configuration
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const TEAM_CONFIG = {
|
||||||
|
name: "planex",
|
||||||
|
sessionDir: ".workflow/.team/PEX-{slug}-{date}/",
|
||||||
|
msgDir: ".workflow/.team-msg/planex/",
|
||||||
|
issueDataDir: ".workflow/issues/"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Message Bus
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
mcp__ccw-tools__team_msg({
|
||||||
|
operation: "log",
|
||||||
|
team: teamName,
|
||||||
|
from: role,
|
||||||
|
to: role === "planner" ? "executor" : "planner",
|
||||||
|
type: "<type>",
|
||||||
|
summary: `[${role}] <summary>`,
|
||||||
|
ref: "<file_path>"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**Message types by role**:
|
||||||
|
|
||||||
|
| Role | Types |
|
||||||
|
|------|-------|
|
||||||
|
| planner | `wave_ready`, `queue_ready`, `all_planned`, `error` |
|
||||||
|
| executor | `impl_complete`, `impl_failed`, `wave_done`, `error` |
|
||||||
|
|
||||||
|
### CLI Fallback
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "${role === 'planner' ? 'executor' : 'planner'}" --type "<type>" --summary "<summary>" --json`)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task Lifecycle (Both Roles)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const tasks = TaskList()
|
||||||
|
const myTasks = tasks.filter(t =>
|
||||||
|
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
|
||||||
|
t.owner === role &&
|
||||||
|
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-4: Role-specific (see roles/{role}.md)
|
||||||
|
// Phase 5: Report + Loop
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wave Pipeline
|
||||||
|
|
||||||
|
```
|
||||||
|
Wave 1: planner 创建 issues + 规划 solutions + 形成 queue
|
||||||
|
↓ (queue ready → 创建 EXEC-* 任务)
|
||||||
|
Wave 1 执行: executor 开始实现 ←→ planner 继续规划 Wave 2
|
||||||
|
↓
|
||||||
|
Wave 2 执行: executor 实现 Wave 2 ←→ planner 规划 Wave 3
|
||||||
|
...
|
||||||
|
Final: planner 发送 all_planned → executor 完成剩余 EXEC-* → 结束
|
||||||
|
```
|
||||||
|
|
||||||
|
**波次规则**:
|
||||||
|
- planner 每完成一个 wave 的 queue 后,立即创建 EXEC-* 任务供 executor 消费
|
||||||
|
- planner 不等待 executor 完成当前 wave,直接进入下一 wave
|
||||||
|
- executor 持续轮询并消费可用的 EXEC-* 任务
|
||||||
|
- 当 planner 发送 `all_planned` 消息后,executor 完成所有剩余任务即可结束
|
||||||
|
|
||||||
|
## Orchestration Mode
|
||||||
|
|
||||||
|
当不带 `--role` 调用时,SKILL.md 进入轻量编排模式:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 1. 创建团队
|
||||||
|
TeamCreate({ team_name: teamName })
|
||||||
|
|
||||||
|
// 2. 解析输入参数
|
||||||
|
const issueIds = args.match(/ISS-\d{8}-\d{6}/g) || []
|
||||||
|
const textMatch = args.match(/--text\s+['"]([^'"]+)['"]/)
|
||||||
|
const planMatch = args.match(/--plan\s+(\S+)/)
|
||||||
|
|
||||||
|
let plannerInput = args // 透传给 planner
|
||||||
|
|
||||||
|
// 3. 创建初始 PLAN-* 任务
|
||||||
|
TaskCreate({
|
||||||
|
subject: "PLAN-001: 初始规划",
|
||||||
|
description: `规划任务。输入: ${plannerInput}`,
|
||||||
|
activeForm: "规划中",
|
||||||
|
owner: "planner"
|
||||||
|
})
|
||||||
|
|
||||||
|
// 4. Spawn planner agent
|
||||||
|
Task({
|
||||||
|
subagent_type: "general-purpose",
|
||||||
|
team_name: teamName,
|
||||||
|
name: "planner",
|
||||||
|
prompt: `你是 team "${teamName}" 的 PLANNER。
|
||||||
|
当你收到 PLAN-* 任务时,调用 Skill(skill="team-planex", args="--role=planner") 执行。
|
||||||
|
当前输入: ${plannerInput}
|
||||||
|
|
||||||
|
## 角色准则(强制)
|
||||||
|
- 你只能处理 PLAN-* 前缀的任务
|
||||||
|
- 所有输出必须带 [planner] 标识前缀
|
||||||
|
- 完成每个 wave 后立即创建 EXEC-* 任务供 executor 消费
|
||||||
|
|
||||||
|
## 消息总线(必须)
|
||||||
|
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||||
|
|
||||||
|
工作流程:
|
||||||
|
1. TaskList → 找到 PLAN-* 任务
|
||||||
|
2. Skill(skill="team-planex", args="--role=planner") 执行
|
||||||
|
3. team_msg log + SendMessage
|
||||||
|
4. TaskUpdate completed → 检查下一个任务`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 5. Spawn executor agent
|
||||||
|
Task({
|
||||||
|
subagent_type: "general-purpose",
|
||||||
|
team_name: teamName,
|
||||||
|
name: "executor",
|
||||||
|
prompt: `你是 team "${teamName}" 的 EXECUTOR。
|
||||||
|
当你收到 EXEC-* 任务时,调用 Skill(skill="team-planex", args="--role=executor") 执行。
|
||||||
|
|
||||||
|
## 角色准则(强制)
|
||||||
|
- 你只能处理 EXEC-* 前缀的任务
|
||||||
|
- 所有输出必须带 [executor] 标识前缀
|
||||||
|
- 每个 solution 完成后通知 planner
|
||||||
|
|
||||||
|
## 消息总线(必须)
|
||||||
|
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||||
|
|
||||||
|
工作流程:
|
||||||
|
1. TaskList → 找到 EXEC-* 任务(等待 planner 创建)
|
||||||
|
2. Skill(skill="team-planex", args="--role=executor") 执行
|
||||||
|
3. team_msg log + SendMessage
|
||||||
|
4. TaskUpdate completed → 检查下一个任务`
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
| Scenario | Resolution |
|
||||||
|
|----------|------------|
|
||||||
|
| Unknown --role value | Error with available role list |
|
||||||
|
| Missing --role arg | Enter orchestration mode |
|
||||||
|
| Role file not found | Error with expected path (roles/{name}.md) |
|
||||||
|
| Planner wave failure | Retry once, then report error and halt pipeline |
|
||||||
|
| Executor impl failure | Report to planner, continue with next EXEC-* task |
|
||||||
|
| No EXEC-* tasks yet | Executor idles, polls for new tasks |
|
||||||
|
| Pipeline stall | Planner monitors — if executor blocked > 2 tasks, escalate to user |
|
||||||
BIN
ccw/frontend/settings-full-page.png
Normal file
BIN
ccw/frontend/settings-full-page.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 750 KiB |
@@ -5,7 +5,7 @@
|
|||||||
// Used for displayMode: 'popup' surfaces (e.g., ask_question)
|
// Used for displayMode: 'popup' surfaces (e.g., ask_question)
|
||||||
// Supports markdown content parsing and multi-page navigation
|
// Supports markdown content parsing and multi-page navigation
|
||||||
|
|
||||||
import { useState, useCallback, useMemo } from 'react';
|
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
@@ -167,6 +167,23 @@ function SinglePagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
|||||||
|
|
||||||
const questionId = (surface.initialState as any)?.questionId as string | undefined;
|
const questionId = (surface.initialState as any)?.questionId as string | undefined;
|
||||||
|
|
||||||
|
// Countdown timer for auto-selection
|
||||||
|
const timeoutAt = (surface.initialState as any)?.timeoutAt as string | undefined;
|
||||||
|
const defaultLabel = (surface.initialState as any)?.defaultValue as string | undefined;
|
||||||
|
const [remaining, setRemaining] = useState<number | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!timeoutAt || !defaultLabel) return;
|
||||||
|
const target = new Date(timeoutAt).getTime();
|
||||||
|
const tick = () => {
|
||||||
|
const secs = Math.max(0, Math.ceil((target - Date.now()) / 1000));
|
||||||
|
setRemaining(secs);
|
||||||
|
};
|
||||||
|
tick();
|
||||||
|
const id = setInterval(tick, 1000);
|
||||||
|
return () => clearInterval(id);
|
||||||
|
}, [timeoutAt, defaultLabel]);
|
||||||
|
|
||||||
// Extract title, message, and description from surface components
|
// Extract title, message, and description from surface components
|
||||||
const titleComponent = surface.components.find(
|
const titleComponent = surface.components.find(
|
||||||
(c) => c.id === 'title' && 'Text' in (c.component as any)
|
(c) => c.id === 'title' && 'Text' in (c.component as any)
|
||||||
@@ -351,6 +368,15 @@ function SinglePagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Countdown for auto-selection */}
|
||||||
|
{remaining !== null && defaultLabel && (
|
||||||
|
<div className="text-xs text-muted-foreground text-center pt-2">
|
||||||
|
{remaining > 0
|
||||||
|
? `${remaining}s 后将自动选择「${defaultLabel}」`
|
||||||
|
: `即将自动选择「${defaultLabel}」`}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Footer - Action buttons */}
|
{/* Footer - Action buttons */}
|
||||||
{actionButtons.length > 0 && (
|
{actionButtons.length > 0 && (
|
||||||
<DialogFooter className="pt-4">
|
<DialogFooter className="pt-4">
|
||||||
@@ -383,6 +409,22 @@ function MultiPagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
|||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(0);
|
const [currentPage, setCurrentPage] = useState(0);
|
||||||
|
|
||||||
|
// Countdown timer for auto-selection
|
||||||
|
const timeoutAt = (state as any)?.timeoutAt as string | undefined;
|
||||||
|
const [remaining, setRemaining] = useState<number | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!timeoutAt) return;
|
||||||
|
const target = new Date(timeoutAt).getTime();
|
||||||
|
const tick = () => {
|
||||||
|
const secs = Math.max(0, Math.ceil((target - Date.now()) / 1000));
|
||||||
|
setRemaining(secs);
|
||||||
|
};
|
||||||
|
tick();
|
||||||
|
const id = setInterval(tick, 1000);
|
||||||
|
return () => clearInterval(id);
|
||||||
|
}, [timeoutAt]);
|
||||||
|
|
||||||
// "Other" per-page state
|
// "Other" per-page state
|
||||||
const [otherSelectedPages, setOtherSelectedPages] = useState<Set<number>>(new Set());
|
const [otherSelectedPages, setOtherSelectedPages] = useState<Set<number>>(new Set());
|
||||||
const [otherTexts, setOtherTexts] = useState<Map<number, string>>(new Map());
|
const [otherTexts, setOtherTexts] = useState<Map<number, string>>(new Map());
|
||||||
@@ -613,6 +655,15 @@ function MultiPagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Countdown for auto-selection */}
|
||||||
|
{remaining !== null && (
|
||||||
|
<div className="text-xs text-muted-foreground text-center">
|
||||||
|
{remaining > 0
|
||||||
|
? `${remaining}s 后将自动提交默认选项`
|
||||||
|
: '即将自动提交默认选项'}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Footer - Navigation buttons */}
|
{/* Footer - Navigation buttons */}
|
||||||
<DialogFooter className="pt-2">
|
<DialogFooter className="pt-2">
|
||||||
<div className="flex flex-row justify-between w-full">
|
<div className="flex flex-row justify-between w-full">
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ export const RadioGroupComponentSchema = z.object({
|
|||||||
label: TextContentSchema,
|
label: TextContentSchema,
|
||||||
value: z.string(),
|
value: z.string(),
|
||||||
description: TextContentSchema.optional(),
|
description: TextContentSchema.optional(),
|
||||||
|
isDefault: z.boolean().optional(),
|
||||||
})),
|
})),
|
||||||
selectedValue: TextContentSchema.optional(),
|
selectedValue: TextContentSchema.optional(),
|
||||||
onChange: ActionSchema,
|
onChange: ActionSchema,
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ export const A2UIRadioGroup: ComponentRenderer = ({ component, onAction, resolve
|
|||||||
return (
|
return (
|
||||||
<RadioGroup value={selectedValue} onValueChange={handleChange} className="space-y-2">
|
<RadioGroup value={selectedValue} onValueChange={handleChange} className="space-y-2">
|
||||||
{radioConfig.options.map((option, idx) => {
|
{radioConfig.options.map((option, idx) => {
|
||||||
const labelText = resolveTextContent(option.label, resolveBinding);
|
const rawLabel = resolveTextContent(option.label, resolveBinding);
|
||||||
|
const labelText = rawLabel.replace(/\s*\(Recommended\)\s*/i, '');
|
||||||
|
const isDefault = (option as any).isDefault === true || /\(Recommended\)/i.test(rawLabel);
|
||||||
const descriptionText = option.description
|
const descriptionText = option.description
|
||||||
? resolveTextContent(option.description, resolveBinding)
|
? resolveTextContent(option.description, resolveBinding)
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -61,6 +63,11 @@ export const A2UIRadioGroup: ComponentRenderer = ({ component, onAction, resolve
|
|||||||
className="text-sm font-medium leading-none cursor-pointer"
|
className="text-sm font-medium leading-none cursor-pointer"
|
||||||
>
|
>
|
||||||
{labelText}
|
{labelText}
|
||||||
|
{isDefault && (
|
||||||
|
<span className="ml-2 inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-primary/10 text-primary">
|
||||||
|
推荐
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</Label>
|
</Label>
|
||||||
{descriptionText && (
|
{descriptionText && (
|
||||||
<span className="text-xs text-muted-foreground mt-1">
|
<span className="text-xs text-muted-foreground mt-1">
|
||||||
|
|||||||
@@ -751,6 +751,7 @@ Type inference: options + multiSelect=true → multi-select; options + multiSele
|
|||||||
properties: {
|
properties: {
|
||||||
label: { type: 'string', description: 'Display text, also used as value' },
|
label: { type: 'string', description: 'Display text, also used as value' },
|
||||||
description: { type: 'string', description: 'Option description' },
|
description: { type: 'string', description: 'Option description' },
|
||||||
|
isDefault: { type: 'boolean', description: 'Mark as default/recommended option' },
|
||||||
},
|
},
|
||||||
required: ['label'],
|
required: ['label'],
|
||||||
},
|
},
|
||||||
@@ -830,6 +831,7 @@ interface PageMeta {
|
|||||||
function generateMultiQuestionSurface(
|
function generateMultiQuestionSurface(
|
||||||
questions: SimpleQuestion[],
|
questions: SimpleQuestion[],
|
||||||
surfaceId: string,
|
surfaceId: string,
|
||||||
|
timeoutMs: number,
|
||||||
): {
|
): {
|
||||||
surfaceUpdate: {
|
surfaceUpdate: {
|
||||||
surfaceId: string;
|
surfaceId: string;
|
||||||
@@ -997,6 +999,7 @@ function generateMultiQuestionSurface(
|
|||||||
questionType: 'multi-question',
|
questionType: 'multi-question',
|
||||||
pages,
|
pages,
|
||||||
totalPages: questions.length,
|
totalPages: questions.length,
|
||||||
|
timeoutAt: new Date(Date.now() + timeoutMs).toISOString(),
|
||||||
},
|
},
|
||||||
displayMode: 'popup',
|
displayMode: 'popup',
|
||||||
},
|
},
|
||||||
@@ -1055,7 +1058,7 @@ async function executeSimpleFormat(
|
|||||||
const compositeId = `multi-${Date.now()}`;
|
const compositeId = `multi-${Date.now()}`;
|
||||||
const surfaceId = `question-${compositeId}`;
|
const surfaceId = `question-${compositeId}`;
|
||||||
|
|
||||||
const { surfaceUpdate, pages } = generateMultiQuestionSurface(questions, surfaceId);
|
const { surfaceUpdate, pages } = generateMultiQuestionSurface(questions, surfaceId, timeout ?? DEFAULT_TIMEOUT_MS);
|
||||||
|
|
||||||
// Create promise for the composite answer
|
// Create promise for the composite answer
|
||||||
const resultPromise = new Promise<AskQuestionResult>((resolve, reject) => {
|
const resultPromise = new Promise<AskQuestionResult>((resolve, reject) => {
|
||||||
|
|||||||
@@ -324,6 +324,15 @@ class AstGrepPythonProcessor(BaseAstGrepProcessor):
|
|||||||
for node in from_matches:
|
for node in from_matches:
|
||||||
module = self._get_match(node, "MODULE")
|
module = self._get_match(node, "MODULE")
|
||||||
names = self._get_match(node, "NAMES")
|
names = self._get_match(node, "NAMES")
|
||||||
|
# Prefer parsing from full node text to handle multiple imports
|
||||||
|
# (ast-grep-py capture may only include the first name).
|
||||||
|
try:
|
||||||
|
node_text = self._binding._get_node_text(node) if self._binding else ""
|
||||||
|
except Exception:
|
||||||
|
node_text = ""
|
||||||
|
parsed_names = self._extract_import_names_from_text(node_text) if node_text else ""
|
||||||
|
if parsed_names:
|
||||||
|
names = parsed_names
|
||||||
start_line, end_line = self._get_line_range(node)
|
start_line, end_line = self._get_line_range(node)
|
||||||
if module:
|
if module:
|
||||||
all_matches.append((start_line, end_line, "from_import", f"{module}:{names}", node))
|
all_matches.append((start_line, end_line, "from_import", f"{module}:{names}", node))
|
||||||
@@ -478,29 +487,46 @@ class AstGrepPythonProcessor(BaseAstGrepProcessor):
|
|||||||
module = parts[0]
|
module = parts[0]
|
||||||
names = parts[1] if len(parts) > 1 else ""
|
names = parts[1] if len(parts) > 1 else ""
|
||||||
|
|
||||||
# Record the import relationship
|
names = (names or "").strip()
|
||||||
|
if names.startswith("(") and names.endswith(")"):
|
||||||
|
names = names[1:-1].strip()
|
||||||
|
|
||||||
|
# Record IMPORTS edges for the imported names (module.symbol), and
|
||||||
|
# update aliases for call/usage resolution.
|
||||||
|
if names and names != "*":
|
||||||
|
for name in names.split(","):
|
||||||
|
name = name.strip()
|
||||||
|
if not name or name == "*":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if " as " in name:
|
||||||
|
as_parts = name.split(" as ", 1)
|
||||||
|
original = as_parts[0].strip()
|
||||||
|
alias = as_parts[1].strip()
|
||||||
|
if not original:
|
||||||
|
continue
|
||||||
|
target = f"{module}.{original}" if module else original
|
||||||
|
if alias:
|
||||||
|
update_aliases({alias: target})
|
||||||
relationships.append(CodeRelationship(
|
relationships.append(CodeRelationship(
|
||||||
source_symbol=get_current_scope(),
|
source_symbol=get_current_scope(),
|
||||||
target_symbol=module,
|
target_symbol=target,
|
||||||
|
relationship_type=RelationshipType.IMPORTS,
|
||||||
|
source_file=source_file,
|
||||||
|
target_file=None,
|
||||||
|
source_line=start_line,
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
target = f"{module}.{name}" if module else name
|
||||||
|
update_aliases({name: target})
|
||||||
|
relationships.append(CodeRelationship(
|
||||||
|
source_symbol=get_current_scope(),
|
||||||
|
target_symbol=target,
|
||||||
relationship_type=RelationshipType.IMPORTS,
|
relationship_type=RelationshipType.IMPORTS,
|
||||||
source_file=source_file,
|
source_file=source_file,
|
||||||
target_file=None,
|
target_file=None,
|
||||||
source_line=start_line,
|
source_line=start_line,
|
||||||
))
|
))
|
||||||
|
|
||||||
# Add aliases for imported names
|
|
||||||
if names and names != "*":
|
|
||||||
for name in names.split(","):
|
|
||||||
name = name.strip()
|
|
||||||
# Handle "name as alias" syntax
|
|
||||||
if " as " in name:
|
|
||||||
as_parts = name.split(" as ")
|
|
||||||
original = as_parts[0].strip()
|
|
||||||
alias = as_parts[1].strip()
|
|
||||||
if alias:
|
|
||||||
update_aliases({alias: f"{module}.{original}"})
|
|
||||||
elif name:
|
|
||||||
update_aliases({name: f"{module}.{name}"})
|
|
||||||
|
|
||||||
elif match_type == "call":
|
elif match_type == "call":
|
||||||
# Resolve alias for call target
|
# Resolve alias for call target
|
||||||
|
|||||||
@@ -595,7 +595,7 @@ class TreeSitterSymbolParser:
|
|||||||
targets: List[str] = []
|
targets: List[str] = []
|
||||||
|
|
||||||
if node.type == "import_statement":
|
if node.type == "import_statement":
|
||||||
for child in node.children:
|
for i, child in enumerate(node.children):
|
||||||
if child.type == "aliased_import":
|
if child.type == "aliased_import":
|
||||||
name_node = child.child_by_field_name("name")
|
name_node = child.child_by_field_name("name")
|
||||||
alias_node = child.child_by_field_name("alias")
|
alias_node = child.child_by_field_name("alias")
|
||||||
@@ -632,7 +632,7 @@ class TreeSitterSymbolParser:
|
|||||||
if module_node is not None:
|
if module_node is not None:
|
||||||
module_name = self._node_text(source_bytes, module_node).strip()
|
module_name = self._node_text(source_bytes, module_node).strip()
|
||||||
|
|
||||||
for child in node.children:
|
for i, child in enumerate(node.children):
|
||||||
if child.type == "aliased_import":
|
if child.type == "aliased_import":
|
||||||
name_node = child.child_by_field_name("name")
|
name_node = child.child_by_field_name("name")
|
||||||
alias_node = child.child_by_field_name("alias")
|
alias_node = child.child_by_field_name("alias")
|
||||||
@@ -650,7 +650,18 @@ class TreeSitterSymbolParser:
|
|||||||
if bound_name:
|
if bound_name:
|
||||||
aliases[bound_name] = target
|
aliases[bound_name] = target
|
||||||
targets.append(target)
|
targets.append(target)
|
||||||
elif child.type == "identifier":
|
elif child.type == "dotted_name" and node.field_name_for_child(i) == "name":
|
||||||
|
# tree-sitter-python represents `from X import A, B, C` as
|
||||||
|
# multiple dotted_name nodes (field: "name").
|
||||||
|
imported_name = self._node_text(source_bytes, child).strip()
|
||||||
|
if not imported_name:
|
||||||
|
continue
|
||||||
|
target = (
|
||||||
|
f"{module_name}.{imported_name}" if module_name else imported_name
|
||||||
|
)
|
||||||
|
aliases[imported_name] = target
|
||||||
|
targets.append(target)
|
||||||
|
elif child.type == "identifier" and node.field_name_for_child(i) == "name":
|
||||||
imported_name = self._node_text(source_bytes, child).strip()
|
imported_name = self._node_text(source_bytes, child).strip()
|
||||||
if not imported_name or imported_name in {"from", "import", "*"}:
|
if not imported_name or imported_name in {"from", "import", "*"}:
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in New Issue
Block a user