feat: Implement CCW Coordinator for interactive command orchestration

- Add action files for session management, command selection, building, execution, and completion.
- Introduce orchestrator logic to drive state transitions and action selection.
- Create state schema to define session state structure.
- Develop command registry and validation tools for command metadata extraction and chain validation.
- Establish skill configuration and specifications for command library and validation rules.
- Implement tools for command registry and chain validation with CLI support.
This commit is contained in:
catlog22
2026-01-23 23:39:16 +08:00
parent 8179472e56
commit e727a07fc5
15 changed files with 1728 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
# CCW Coordinator
交互式命令编排工具
## 使用
```
/ccw-coordinator
/coordinator
```
## 流程
1. 用户描述任务
2. Claude推荐命令链
3. 用户确认或调整
4. 执行命令链
5. 生成报告
## 示例
**Bug修复**
```
任务: 修复登录bug
推荐: lite-fix → test-cycle-execute
```
**新功能**
```
任务: 实现注册功能
推荐: plan → execute → test-cycle-execute
```
## 文件说明
| 文件 | 用途 |
|------|------|
| SKILL.md | Skill入口 |
| phases/orchestrator.md | 编排逻辑 |
| phases/state-schema.md | 状态定义 |
| phases/actions/*.md | 动作实现 |
| specs/chain-registry.json | 命令元数据 |
| specs/chain-validation-rules.md | 验证规则 |
| tools/chain-validate.js | 验证工具 |

View File

@@ -0,0 +1,320 @@
---
name: ccw-coordinator
description: Interactive command orchestration tool for building and executing Claude CLI command chains. Triggers on "coordinator", "ccw-coordinator", "命令编排", "command chain", "orchestrate commands", "编排CLI命令".
allowed-tools: Task, AskUserQuestion, Read, Write, Bash, Glob, Grep
---
# CCW Coordinator
交互式命令编排工具允许用户依次选择命令形成命令串然后依次调用claude cli执行整个命令串。
支持灵活的工作流组合,提供交互式界面用于命令选择、编排和执行管理。
## Architecture Overview
```
┌─────────────────────────────────────────────────────────────────┐
│ Orchestrator (状态驱动决策) │
│ 根据用户选择编排命令和执行流程 │
└───────────────┬─────────────────────────────────────────────────┘
┌───────────┼───────────┬───────────────┐
↓ ↓ ↓ ↓
┌─────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────┐
│ Init │ │ Command │ │ Command │ │ Execute │
│ │ │ Selection │ │ Build │ │ │
│ │ │ │ │ │ │ │
│ 初始化 │ │ 选择命令 │ │ 编排调整 │ │ 执行链 │
└─────────┘ └──────────────┘ └────────────┘ └──────────┘
│ │ │ │
└───────────────┼──────────────┴────────────┘
┌──────────────┐
│ Complete │
│ 生成报告 │
└──────────────┘
```
## Key Design Principles
1. **智能推荐**: Claude 根据用户任务描述,自动推荐最优命令链
2. **交互式编排**: 用户通过交互式界面选择和编排命令,实时反馈
3. **无状态动作**: 每个动作独立执行,通过共享状态进行通信
4. **灵活的命令库**: 支持ccw workflow命令和标准claude cli命令
5. **执行透明性**: 展示执行进度、结果和可能的错误
6. **会话持久化**: 保存编排会话,支持中途暂停和恢复
7. **智能提示词生成**: 根据任务上下文和前序产物自动生成 ccw cli 提示词
## Intelligent Prompt Generation
执行命令时,系统根据以下信息智能生成 `ccw cli -p` 提示词:
### 提示词构成
```javascript
// 集成命令注册表 (~/.claude/tools/command-registry.js)
const registry = new CommandRegistry();
registry.buildRegistry();
function generatePrompt(cmd, state) {
const cmdMeta = registry.getCommand(cmd.command);
let prompt = `任务: ${state.task_description}\n`;
if (state.execution_results.length > 0) {
const previousOutputs = state.execution_results
.filter(r => r.status === 'success')
.map(r => {
if (r.summary?.session) {
return `- ${r.command}: ${r.summary.session} (${r.summary.files?.join(', ')})`;
}
return `- ${r.command}: 已完成`;
})
.join('\n');
prompt += `\n前序完成:\n${previousOutputs}\n`;
}
// 从 YAML 头提取命令元数据
if (cmdMeta) {
prompt += `\n命令: ${cmd.command}`;
if (cmdMeta.argumentHint) {
prompt += ` ${cmdMeta.argumentHint}`;
}
}
return prompt;
}
```
### 产物追踪
每个命令执行后自动提取关键产物:
```javascript
{
command: "/workflow:lite-plan",
status: "success",
output: "...",
summary: {
session: "WFS-plan-20250123", // 会话ID
files: [".workflow/IMPL_PLAN.md"], // 产物文件
timestamp: "2025-01-23T10:30:00Z"
}
}
```
### 命令调用示例
```bash
# 自动生成的智能提示词
ccw cli -p "任务: 实现用户认证功能
前序完成:
- /workflow:lite-plan: WFS-plan-20250123 (.workflow/IMPL_PLAN.md)
命令: /workflow:lite-execute [--resume-session=\"session-id\"]" /workflow:lite-execute
```
### 命令注册表集成
- **位置**: `tools/command-registry.js` (skill 内置)
- **工作模式**: 按需提取(只提取用户任务链中的命令)
- **功能**: 自动查找全局 `.claude/commands/workflow` 目录,解析命令 YAML 头元数据
- **作用**: 确保提示词包含准确的命令参数和上下文
详见 `tools/README.md`
---
## Execution Flow
### Orchestrator Execution Loop
```javascript
1. 初始化会话
2. 循环执行直到完成
读取当前状态
选择下一个动作根据状态和用户意图
执行动作更新状态
检查终止条件
3. 生成最终报告
```
### Action Sequence (Typical)
```
action-init
↓ (status: pending → running)
action-command-selection (可重复)
↓ (添加命令到链)
action-command-build (可选)
↓ (调整命令顺序)
action-command-execute
↓ (依次执行所有命令)
action-complete
↓ (status: running → completed)
```
## State Management
### Initial State
```json
{
"status": "pending",
"task_description": "",
"command_chain": [],
"confirmed": false,
"error_count": 0,
"execution_results": [],
"current_command_index": 0,
"started_at": null
}
```
### State Transitions
```
pending → running (init) → running → completed (execute)
aborted (error or user exit)
```
## Directory Setup
```javascript
const timestamp = new Date().toISOString().slice(0,19).replace(/[-:T]/g, '');
const workDir = `.workflow/.ccw-coordinator/${timestamp}`;
Bash(`mkdir -p "${workDir}"`);
Bash(`mkdir -p "${workDir}/commands"`);
Bash(`mkdir -p "${workDir}/logs"`);
```
## Output Structure
```
.workflow/.ccw-coordinator/{timestamp}/
├── state.json # 当前会话状态
├── command-chain.json # 编排的完整命令链
├── execution-log.md # 执行日志
├── final-summary.md # 最终报告
├── commands/ # 各命令执行详情
│ ├── 01-command.log
│ ├── 02-command.log
│ └── ...
└── logs/ # 错误和警告日志
├── errors.log
└── warnings.log
```
## Reference Documents
| Document | Purpose |
|----------|---------|
| [phases/orchestrator.md](phases/orchestrator.md) | 编排器实现 |
| [phases/state-schema.md](phases/state-schema.md) | 状态结构定义 |
| [phases/actions/action-init.md](phases/actions/action-init.md) | 初始化动作 |
| [phases/actions/action-command-selection.md](phases/actions/action-command-selection.md) | 命令选择动作 |
| [phases/actions/action-command-build.md](phases/actions/action-command-build.md) | 命令编排动作 |
| [phases/actions/action-command-execute.md](phases/actions/action-command-execute.md) | 命令执行动作 |
| [phases/actions/action-complete.md](phases/actions/action-complete.md) | 完成动作 |
| [phases/actions/action-abort.md](phases/actions/action-abort.md) | 中止动作 |
| [specs/command-library.md](specs/command-library.md) | 命令库 |
| [specs/chain-registry.json](specs/chain-registry.json) | 命令元数据 |
| [specs/chain-validation-rules.md](specs/chain-validation-rules.md) | 验证规则 |
| [tools/chain-validate.js](tools/chain-validate.js) | 验证工具 |
---
## Usage Examples
### 快速命令链
用户想要执行:规划 → 执行 → 测试
```
1. 触发 /ccw-coordinator
2. 描述任务:"实现用户注册功能"
3. Claude推荐: plan → execute → test-cycle-execute
4. 用户确认
5. 执行命令链
```
### 复杂工作流
用户想要执行:规划 → 执行 → 审查 → 修复
```
1. 触发 /ccw-coordinator
2. 描述任务:"重构认证模块"
3. Claude推荐: plan → execute → review-session-cycle → review-fix
4. 用户可调整命令顺序
5. 确认执行
6. 实时查看执行进度
```
### 紧急修复
用户想要快速修复bug
```
1. 触发 /ccw-coordinator
2. 描述任务:"修复生产环境登录bug"
3. Claude推荐: lite-fix --hotfix → test-cycle-execute
4. 用户确认
5. 快速执行修复
```
## Constraints and Rules
### 1. 命令推荐约束
- **智能推荐优先**: 必须先基于用户任务描述进行智能推荐,而非直接展示命令库
- **不使用静态映射**: 禁止使用查表或硬编码的推荐逻辑(如 `if task=bug则推荐lite-fix`
- **推荐必须说明理由**: Claude 推荐命令链时必须解释为什么这样推荐
- **用户保留选择权**: 推荐后,用户可选择:使用推荐/调整/手动选择
### 2. 验证约束
- **执行前必须验证**: 使用 `chain-validate.js` 验证命令链合法性
- **不合法必须提示**: 如果验证失败,必须明确告知用户错误原因和修复方法
- **允许用户覆盖**: 验证失败时,询问用户是否仍要执行(警告模式)
### 3. 执行约束
- **顺序执行**: 命令必须严格按照 command_chain 中的 order 顺序执行
- **错误处理**: 单个命令失败时,询问用户:重试/跳过/中止
- **错误上限**: 连续 3 次错误自动中止会话
- **实时反馈**: 每个命令执行时显示进度(如 `[2/5] 执行: lite-execute`
### 4. 状态管理约束
- **状态持久化**: 每次状态更新必须立即写入磁盘
- **单一数据源**: 状态只保存在 `state.json`,禁止多个状态文件
- **原子操作**: 状态更新必须使用 read-modify-write 模式,避免并发冲突
### 5. 用户体验约束
- **最小交互**: 默认使用智能推荐 + 一次确认,避免多次询问
- **清晰输出**: 每个步骤输出必须包含:当前状态、可用选项、建议操作
- **可恢复性**: 会话中断后,用户可从上次状态恢复
### 6. 禁止行为
-**禁止跳过推荐步骤**: 不能直接进入手动选择,必须先尝试推荐
-**禁止静态推荐**: 不能使用 recommended-chains.json 查表
-**禁止无验证执行**: 不能跳过链条验证直接执行
-**禁止静默失败**: 错误必须明确报告,不能静默跳过
## Notes
- 编排器使用状态机模式,确保执行流程的可靠性
- 所有命令链和执行结果都被持久化保存,支持后续查询和调试
- 支持用户中途修改命令链(在执行前)
- 执行错误会自动记录,支持重试机制
- Claude 智能推荐基于任务分析,非查表静态推荐

View File

@@ -0,0 +1,9 @@
# action-abort
中止会话,保存状态
```javascript
updateState({ status: 'aborted' });
console.log(`会话已中止: ${workDir}`);
```

View File

@@ -0,0 +1,40 @@
# action-command-build
调整命令链顺序或删除命令
## 流程
1. 显示当前命令链
2. 让用户调整(重新排序、删除)
3. 确认执行
## 伪代码
```javascript
// 显示链
console.log('命令链:');
state.command_chain.forEach((cmd, i) => {
console.log(`${i+1}. ${cmd.command}`);
});
// 询问用户
const action = await AskUserQuestion({
options: [
'继续执行',
'删除命令',
'重新排序',
'返回选择'
]
});
// 处理用户操作
if (action === '继续执行') {
updateState({confirmed: true, status: 'executing'});
}
// ... 其他操作
```
## 状态更新
- command_chain (可能修改)
- confirmed = true 时状态转为 executing

View File

@@ -0,0 +1,124 @@
# action-command-execute
依次执行命令链,智能生成 ccw cli 提示词
## 命令注册表集成
```javascript
// 从 ./tools/command-registry.js 按需提取命令元数据
const CommandRegistry = require('./tools/command-registry.js');
const registry = new CommandRegistry();
// 只提取当前任务链中的命令
const commandNames = command_chain.map(cmd => cmd.command);
const commandMeta = registry.getCommands(commandNames);
```
## 提示词生成策略
```javascript
function generatePrompt(cmd, state, commandMeta) {
const { task_description, execution_results } = state;
// 获取命令元数据(从已提取的 commandMeta
const cmdInfo = commandMeta[cmd.command];
// 提取前序产物信息
const previousOutputs = execution_results
.filter(r => r.status === 'success')
.map(r => {
const summary = r.summary;
if (summary?.session) {
return `- ${r.command}: ${summary.session} (${summary.files?.join(', ') || '完成'})`;
}
return `- ${r.command}: 已完成`;
})
.join('\n');
// 根据命令类型构建提示词
let prompt = `任务: ${task_description}\n`;
if (previousOutputs) {
prompt += `\n前序完成:\n${previousOutputs}\n`;
}
// 添加命令元数据上下文
if (cmdInfo) {
prompt += `\n命令: ${cmd.command}`;
if (cmdInfo.argumentHint) {
prompt += ` ${cmdInfo.argumentHint}`;
}
}
return prompt;
}
```
## 执行逻辑
```javascript
for (let i = current_command_index; i < command_chain.length; i++) {
const cmd = command_chain[i];
console.log(`[${i+1}/${command_chain.length}] 执行: ${cmd.command}`);
// 生成智能提示词
const prompt = generatePrompt(cmd, state, commandMeta);
try {
// 使用 ccw cli 执行
const result = Bash(`ccw cli -p "${prompt.replace(/"/g, '\\"')}" ${cmd.command}`, {
run_in_background: true
});
execution_results.push({
command: cmd.command,
status: result.exit_code === 0 ? 'success' : 'failed',
exit_code: result.exit_code,
output: result.stdout,
summary: extractSummary(result.stdout) // 提取关键产物
});
command_chain[i].status = 'completed';
current_command_index = i + 1;
} catch (error) {
error_count++;
command_chain[i].status = 'failed';
if (error_count >= 3) break;
const action = await AskUserQuestion({
options: ['重试', '跳过', '中止']
});
if (action === '重试') i--;
if (action === '中止') break;
}
updateState({ command_chain, execution_results, current_command_index, error_count });
}
```
## 产物提取
```javascript
function extractSummary(output) {
// 从输出提取关键产物信息
// 例如: 会话ID, 文件路径, 任务完成状态等
const sessionMatch = output.match(/WFS-\w+-\d+/);
const fileMatch = output.match(/\.workflow\/[^\s]+/g);
return {
session: sessionMatch?.[0],
files: fileMatch || [],
timestamp: new Date().toISOString()
};
}
```
## 状态更新
- execution_results (包含 summary 产物信息)
- command_chain[].status
- current_command_index

View File

@@ -0,0 +1,48 @@
# action-command-selection
## 流程
1. 问用户任务
2. Claude推荐命令链
3. 用户确认/手动选择
4. 添加到command_chain
## 伪代码
```javascript
// 1. 获取用户任务描述
const taskInput = await AskUserQuestion({
question: '请描述您的任务',
options: [
{ label: '手动选择命令', value: 'manual' }
]
});
// 保存任务描述到状态
updateState({ task_description: taskInput.text || taskInput.value });
// 2. 若用户描述任务Claude推荐
if (taskInput.text) {
console.log('推荐: ', recommendChain(taskInput.text));
const confirm = await AskUserQuestion({
question: '是否使用推荐链?',
options: ['使用推荐', '调整', '手动选择']
});
if (confirm === '使用推荐') {
addCommandsToChain(recommendedChain);
updateState({ confirmed: true });
return;
}
}
// 3. 手动选择
const commands = loadCommandLibrary();
const selected = await AskUserQuestion(commands);
addToChain(selected);
```
## 状态更新
- task_description = 用户任务描述
- command_chain.push(newCommand)
- 如果用户确认: confirmed = true

View File

@@ -0,0 +1,25 @@
# action-complete
生成执行报告
```javascript
const success = execution_results.filter(r => r.status === 'success').length;
const failed = execution_results.filter(r => r.status === 'failed').length;
const duration = Date.now() - new Date(started_at).getTime();
const report = `
# 执行报告
- 会话: ${session_id}
- 耗时: ${Math.round(duration/1000)}s
- 成功: ${success}
- 失败: ${failed}
## 命令详情
${command_chain.map((c, i) => `${i+1}. ${c.command} - ${c.status}`).join('\n')}
`;
Write(`${workDir}/final-report.md`, report);
updateState({ status: 'completed' });
```

View File

@@ -0,0 +1,25 @@
# action-init
初始化编排会话
```javascript
const timestamp = Date.now();
const workDir = `.workflow/.ccw-coordinator/${timestamp}`;
Bash(`mkdir -p "${workDir}"`);
const state = {
session_id: `coord-${timestamp}`,
status: 'running',
started_at: new Date().toISOString(),
command_chain: [],
current_command_index: 0,
execution_results: [],
confirmed: false,
error_count: 0
};
Write(`${workDir}/state.json`, JSON.stringify(state, null, 2));
console.log(`会话已初始化: ${workDir}`);
```

View File

@@ -0,0 +1,59 @@
# Orchestrator
状态驱动编排:读状态 → 选动作 → 执行 → 更新状态
## 决策逻辑
```javascript
function selectNextAction(state) {
if (['completed', 'aborted'].includes(state.status)) return null;
if (state.error_count >= 3) return 'action-abort';
switch (state.status) {
case 'pending':
return 'action-init';
case 'running':
return state.confirmed && state.command_chain.length > 0
? 'action-command-execute'
: 'action-command-selection';
case 'executing':
const pending = state.command_chain.filter(c => c.status === 'pending');
return pending.length === 0 ? 'action-complete' : 'action-command-execute';
default:
return 'action-abort';
}
}
```
## 执行循环
```javascript
const timestamp = Date.now();
const workDir = `.workflow/.ccw-coordinator/${timestamp}`;
Bash(`mkdir -p "${workDir}"`);
const state = {
session_id: `coord-${timestamp}`,
status: 'pending',
started_at: new Date().toISOString(),
task_description: '', // 从 action-command-selection 获取
command_chain: [],
current_command_index: 0,
execution_results: [],
confirmed: false,
error_count: 0
};
Write(`${workDir}/state.json`, JSON.stringify(state, null, 2));
let iterations = 0;
while (iterations < 50) {
const state = JSON.parse(Read(`${workDir}/state.json`));
const nextAction = selectNextAction(state);
if (!nextAction) break;
console.log(`[${nextAction}]`);
// 执行 phases/actions/{nextAction}.md
iterations++;
}
```

View File

@@ -0,0 +1,66 @@
# State Schema
```typescript
interface State {
session_id: string;
status: 'pending' | 'running' | 'executing' | 'completed' | 'aborted';
started_at: string;
task_description: string; // 用户任务描述
command_chain: Command[];
current_command_index: number;
execution_results: ExecutionResult[];
confirmed: boolean;
error_count: number;
}
interface Command {
id: string;
order: number;
command: string;
status: 'pending' | 'running' | 'completed' | 'failed';
result?: ExecutionResult;
}
interface ExecutionResult {
command: string;
status: 'success' | 'failed';
exit_code: number;
output?: string;
summary?: { // 提取的关键产物
session?: string;
files?: string[];
timestamp: string;
};
}
```
## 状态转移
```
pending → running → executing → completed
↓ ↓
(abort) (error → abort)
```
## 初始化
```javascript
{
session_id: generateId(),
status: 'pending',
started_at: new Date().toISOString(),
task_description: '', // 从用户输入获取
command_chain: [],
current_command_index: 0,
execution_results: [],
confirmed: false,
error_count: 0
}
```
## 更新
- 添加命令: `command_chain.push(cmd)`
- 确认执行: `confirmed = true, status = 'executing'`
- 记录执行: `execution_results.push(...), current_command_index++`
- 错误计数: `error_count++`

View File

@@ -0,0 +1,66 @@
{
"skill_name": "ccw-coordinator",
"display_name": "CCW Coordinator",
"description": "Interactive command orchestration - select, build, and execute workflow command chains",
"execution_mode": "autonomous",
"version": "1.0.0",
"triggers": [
"coordinator",
"ccw-coordinator",
"命令编排",
"command chain"
],
"allowed_tools": [
"Task",
"AskUserQuestion",
"Read",
"Write",
"Bash"
],
"actions": [
{
"id": "action-init",
"name": "Init",
"description": "Initialize orchestration session"
},
{
"id": "action-command-selection",
"name": "Select Commands",
"description": "Interactive command selection from library"
},
{
"id": "action-command-build",
"name": "Build Chain",
"description": "Adjust and confirm command chain"
},
{
"id": "action-command-execute",
"name": "Execute",
"description": "Execute command chain sequentially"
},
{
"id": "action-complete",
"name": "Complete",
"description": "Generate final report"
},
{
"id": "action-abort",
"name": "Abort",
"description": "Abort session and save state"
}
],
"termination_conditions": [
"user_exit",
"task_completed",
"error"
],
"output": {
"location": ".workflow/.ccw-coordinator/{timestamp}",
"artifacts": [
"state.json",
"command-chain.json",
"execution-log.md",
"final-report.md"
]
}
}

View File

@@ -0,0 +1,362 @@
# CCW Coordinator Specifications
命令库、验证规则和注册表一体化规范。
---
## 命令库
### Planning Commands
| Command | Description | Level |
|---------|-------------|-------|
| `/workflow:lite-plan` | 轻量级规划 | L2 |
| `/workflow:plan` | 标准规划 | L3 |
| `/workflow:multi-cli-plan` | 多CLI协作规划 | L2 |
| `/workflow:brainstorm:auto-parallel` | 头脑风暴规划 | L4 |
| `/workflow:tdd-plan` | TDD规划 | L3 |
### Execution Commands
| Command | Description | Level |
|---------|-------------|-------|
| `/workflow:lite-execute` | 轻量级执行 | L2 |
| `/workflow:execute` | 标准执行 | L3 |
| `/workflow:test-cycle-execute` | 测试循环执行 | L3 |
### BugFix Commands
| Command | Description | Level |
|---------|-------------|-------|
| `/workflow:lite-fix` | 轻量级修复 | L2 |
| `/workflow:lite-fix --hotfix` | 紧急修复 | L2 |
### Testing Commands
| Command | Description | Level |
|---------|-------------|-------|
| `/workflow:test-gen` | 测试生成 | L3 |
| `/workflow:test-fix-gen` | 测试修复生成 | L3 |
| `/workflow:tdd-verify` | TDD验证 | L3 |
### Review Commands
| Command | Description | Level |
|---------|-------------|-------|
| `/workflow:review-session-cycle` | 会话审查 | L3 |
| `/workflow:review-module-cycle` | 模块审查 | L3 |
| `/workflow:review-fix` | 审查修复 | L3 |
| `/workflow:action-plan-verify` | 计划验证 | L3 |
### Documentation Commands
| Command | Description | Level |
|---------|-------------|-------|
| `/memory:docs` | 生成文档 | L2 |
| `/memory:update-related` | 更新相关文档 | L2 |
| `/memory:update-full` | 全面更新文档 | L2 |
### Issue Commands
| Command | Description |
|---------|-------------|
| `/issue:discover` | 发现Issue |
| `/issue:discover-by-prompt` | 基于提示发现Issue |
| `/issue:plan --all-pending` | 规划所有待处理Issue |
| `/issue:queue` | 排队Issue |
| `/issue:execute` | 执行Issue |
---
## 命令链推荐
### 标准开发流程
```
1. /workflow:lite-plan
2. /workflow:lite-execute
3. /workflow:test-cycle-execute
```
### 完整规划流程
```
1. /workflow:plan
2. /workflow:action-plan-verify
3. /workflow:execute
4. /workflow:review-session-cycle
```
### TDD 流程
```
1. /workflow:tdd-plan
2. /workflow:execute
3. /workflow:tdd-verify
```
### Issue 批处理流程
```
1. /issue:plan --all-pending
2. /issue:queue
3. /issue:execute
```
---
## 验证规则
### Rule 1: Single Planning Command
每条链最多包含一个规划命令。
| 有效 | 无效 |
|------|------|
| `plan → execute` | `plan → lite-plan → execute` |
### Rule 2: Compatible Pairs
规划和执行命令必须兼容。
| Planning | Execution | 兼容 |
|----------|-----------|------|
| lite-plan | lite-execute | ✓ |
| lite-plan | execute | ✗ |
| multi-cli-plan | lite-execute | ✓ |
| multi-cli-plan | execute | ✓ |
| plan | execute | ✓ |
| plan | lite-execute | ✗ |
| tdd-plan | execute | ✓ |
| tdd-plan | lite-execute | ✗ |
### Rule 3: Testing After Execution
测试命令必须在执行命令之后。
| 有效 | 无效 |
|------|------|
| `execute → test-cycle-execute` | `test-cycle-execute → execute` |
### Rule 4: Review After Execution
审查命令必须在执行命令之后。
| 有效 | 无效 |
|------|------|
| `execute → review-session-cycle` | `review-session-cycle → execute` |
### Rule 5: BugFix Standalone
`lite-fix` 必须单独执行,不能与其他命令组合。
| 有效 | 无效 |
|------|------|
| `lite-fix` | `plan → lite-fix → execute` |
| `lite-fix --hotfix` | `lite-fix → test-cycle-execute` |
### Rule 6: Dependency Satisfaction
每个命令的依赖必须在前面执行。
```javascript
test-fix-gen test-cycle-execute
test-cycle-execute
```
### Rule 7: No Redundancy
链条中不能有重复的命令。
| 有效 | 无效 |
|------|------|
| `plan → execute → test` | `plan → plan → execute` |
### Rule 8: Command Exists
所有命令必须在此规范中定义。
---
## 反模式(避免)
### ❌ Pattern 1: Multiple Planning
```
plan → lite-plan → execute
```
**问题**: 重复分析,浪费时间
**修复**: 选一个规划命令
### ❌ Pattern 2: Test Without Context
```
test-cycle-execute (独立执行)
```
**问题**: 没有执行上下文,无法工作
**修复**: 先执行 `execute``test-fix-gen`
### ❌ Pattern 3: BugFix with Planning
```
plan → execute → lite-fix
```
**问题**: lite-fix 是独立命令,不应与规划混合
**修复**: 用 `lite-fix` 单独修复,或用 `plan → execute` 做大改
### ❌ Pattern 4: Review Without Changes
```
review-session-cycle (独立执行)
```
**问题**: 没有 git 改动可审查
**修复**: 先执行 `execute` 生成改动
### ❌ Pattern 5: TDD Misuse
```
tdd-plan → lite-execute
```
**问题**: lite-execute 无法处理 TDD 任务结构
**修复**: 用 `tdd-plan → execute → tdd-verify`
---
## 命令注册表
### 命令元数据结构
```json
{
"command_name": {
"category": "Planning|Execution|Testing|Review|BugFix|Maintenance",
"level": "L0|L1|L2|L3",
"description": "命令描述",
"inputs": ["input1", "input2"],
"outputs": ["output1", "output2"],
"dependencies": ["依赖命令"],
"parameters": [
{"name": "--flag", "type": "string|boolean|number", "default": "value"}
],
"chain_position": "start|middle|middle_or_end|end|standalone",
"next_recommended": ["推荐的下一个命令"]
}
}
```
### 命令分组
| Group | Commands |
|-------|----------|
| planning | lite-plan, multi-cli-plan, plan, tdd-plan |
| execution | lite-execute, execute, develop-with-file |
| testing | test-gen, test-fix-gen, test-cycle-execute, tdd-verify |
| review | review-session-cycle, review-module-cycle, review-fix |
| bugfix | lite-fix, debug, debug-with-file |
| maintenance | clean, replan |
| verification | action-plan-verify, tdd-verify |
### 兼容性矩阵
| 组合 | 状态 |
|------|------|
| lite-plan + lite-execute | ✓ compatible |
| lite-plan + execute | ✗ incompatible - use plan |
| multi-cli-plan + lite-execute | ✓ compatible |
| plan + execute | ✓ compatible |
| plan + lite-execute | ✗ incompatible - use lite-plan |
| tdd-plan + execute | ✓ compatible |
| execute + test-cycle-execute | ✓ compatible |
| lite-execute + test-cycle-execute | ✓ compatible |
| test-fix-gen + test-cycle-execute | ✓ required |
| review-session-cycle + review-fix | ✓ compatible |
| lite-fix + test-cycle-execute | ✗ incompatible - lite-fix standalone |
---
## 验证工具
### chain-validate.js
位置: `tools/chain-validate.js`
验证命令链合法性:
```bash
node tools/chain-validate.js plan execute test-cycle-execute
```
输出:
```
{
"valid": true,
"errors": [],
"warnings": []
}
```
## 命令注册表
### 工具位置
位置: `tools/command-registry.js` (skill 内置)
### 工作模式
**按需提取**: 只提取用户确定的任务链中的命令,不是全量扫描。
```javascript
// 用户任务链: [lite-plan, lite-execute]
const commandNames = command_chain.map(cmd => cmd.command);
const commandMeta = registry.getCommands(commandNames);
// 只提取这 2 个命令的元数据
```
### 功能
- 自动查找全局 `.claude/commands/workflow` 目录(相对路径 > 用户 home
- 按需提取指定命令的 YAML 头元数据
- 缓存机制避免重复读取
- 提供批量查询接口
### 集成方式
在 action-command-execute 中自动集成:
```javascript
const CommandRegistry = require('./tools/command-registry.js');
const registry = new CommandRegistry();
// 只提取任务链中的命令
const commandNames = command_chain.map(cmd => cmd.command);
const commandMeta = registry.getCommands(commandNames);
// 使用元数据生成提示词
const cmdInfo = commandMeta[cmd.command];
// {
// name: 'lite-plan',
// description: '轻量级规划...',
// argumentHint: '[-e|--explore] "task description"',
// allowedTools: [...],
// filePath: '...'
// }
```
### 提示词生成
智能提示词自动包含:
1. **任务上下文**: 用户任务描述
2. **前序产物**: 已完成命令的产物信息
3. **命令元数据**: 命令的参数提示和描述
```
任务: 实现用户注册功能
前序完成:
- /workflow:lite-plan: WFS-plan-001 (IMPL_PLAN.md)
命令: /workflow:lite-execute [--resume-session="session-id"]
```
详见 `tools/README.md`

View File

@@ -0,0 +1,77 @@
# CCW Coordinator Tools
## command-registry.js
命令注册表工具:按需查找并提取命令 YAML 头元数据。
### 功能
- **按需提取**: 只提取用户任务链中的命令(不是全量扫描)
- **自动查找**: 从全局 `.claude/commands/workflow` 目录读取(项目相对路径 > 用户 home
- **解析 YAML 头**: 提取 name, description, argument-hint, allowed-tools
- **缓存机制**: 避免重复读取文件
### 编程接口
```javascript
const CommandRegistry = require('./tools/command-registry.js');
const registry = new CommandRegistry();
// 按需提取命令链中的命令元数据
const commandNames = ['/workflow:lite-plan', '/workflow:lite-execute'];
const commands = registry.getCommands(commandNames);
// 输出:
// {
// "/workflow:lite-plan": {
// name: 'lite-plan',
// command: '/workflow:lite-plan',
// description: '...',
// argumentHint: '[-e|--explore] "task description"',
// allowedTools: [...],
// filePath: '...'
// },
// "/workflow:lite-execute": { ... }
// }
```
### 命令行接口
```bash
# 提取指定命令
node .claude/skills/ccw-coordinator/tools/command-registry.js lite-plan lite-execute
# 输出 JSON
node .claude/skills/ccw-coordinator/tools/command-registry.js /workflow:lite-plan
```
### 集成用途
`action-command-execute` 中使用:
```javascript
// 1. 只提取任务链中的命令
const commandNames = command_chain.map(cmd => cmd.command);
const commandMeta = registry.getCommands(commandNames);
// 2. 生成提示词时使用
function generatePrompt(cmd, state, commandMeta) {
const cmdInfo = commandMeta[cmd.command];
let prompt = `任务: ${state.task_description}\n`;
if (cmdInfo?.argumentHint) {
prompt += `命令: ${cmd.command} ${cmdInfo.argumentHint}`;
}
return prompt;
}
```
确保 `ccw cli -p "..."` 提示词包含准确的命令参数提示。
### 目录查找逻辑
自动查找顺序:
1. `.claude/commands/workflow` (相对于当前工作目录)
2. `~/.claude/commands/workflow` (用户 home 目录)

View File

@@ -0,0 +1,281 @@
#!/usr/bin/env node
/**
* Chain Validation Tool
*
* Validates workflow command chains against defined rules.
*
* Usage:
* node chain-validate.js plan execute test-cycle-execute
* node chain-validate.js --json "plan,execute,test-cycle-execute"
* node chain-validate.js --file custom-chain.json
*/
const fs = require('fs');
const path = require('path');
// Load registry
const registryPath = path.join(__dirname, '..', 'specs', 'chain-registry.json');
const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
class ChainValidator {
constructor(registry) {
this.registry = registry;
this.errors = [];
this.warnings = [];
}
validate(chain) {
this.errors = [];
this.warnings = [];
this.validateSinglePlanning(chain);
this.validateCompatiblePairs(chain);
this.validateTestingPosition(chain);
this.validateReviewPosition(chain);
this.validateBugfixStandalone(chain);
this.validateDependencies(chain);
this.validateNoRedundancy(chain);
this.validateCommandExistence(chain);
return {
valid: this.errors.length === 0,
errors: this.errors,
warnings: this.warnings
};
}
validateSinglePlanning(chain) {
const planningCommands = chain.filter(cmd =>
['plan', 'lite-plan', 'multi-cli-plan', 'tdd-plan'].includes(cmd)
);
if (planningCommands.length > 1) {
this.errors.push({
rule: 'Single Planning Command',
message: `Too many planning commands: ${planningCommands.join(', ')}`,
severity: 'error'
});
}
}
validateCompatiblePairs(chain) {
const compatibility = {
'lite-plan': ['lite-execute'],
'multi-cli-plan': ['lite-execute', 'execute'],
'plan': ['execute'],
'tdd-plan': ['execute']
};
const planningCmd = chain.find(cmd =>
['plan', 'lite-plan', 'multi-cli-plan', 'tdd-plan'].includes(cmd)
);
const executionCmd = chain.find(cmd =>
['execute', 'lite-execute'].includes(cmd)
);
if (planningCmd && executionCmd) {
const compatible = compatibility[planningCmd] || [];
if (!compatible.includes(executionCmd)) {
this.errors.push({
rule: 'Compatible Pairs',
message: `${planningCmd} incompatible with ${executionCmd}`,
fix: `Use ${planningCmd} with ${compatible.join(' or ')}`,
severity: 'error'
});
}
}
}
validateTestingPosition(chain) {
const executionIdx = chain.findIndex(cmd =>
['execute', 'lite-execute', 'develop-with-file'].includes(cmd)
);
const testingIdx = chain.findIndex(cmd =>
['test-cycle-execute', 'tdd-verify', 'test-gen', 'test-fix-gen'].includes(cmd)
);
if (testingIdx !== -1 && executionIdx !== -1 && executionIdx > testingIdx) {
this.errors.push({
rule: 'Testing After Execution',
message: 'Testing commands must come after execution',
severity: 'error'
});
}
if (testingIdx !== -1 && executionIdx === -1) {
const hasTestGen = chain.some(cmd => ['test-gen', 'test-fix-gen'].includes(cmd));
if (!hasTestGen) {
this.warnings.push({
rule: 'Testing After Execution',
message: 'test-cycle-execute without execution context - needs test-gen or execute first',
severity: 'warning'
});
}
}
}
validateReviewPosition(chain) {
const executionIdx = chain.findIndex(cmd =>
['execute', 'lite-execute'].includes(cmd)
);
const reviewIdx = chain.findIndex(cmd =>
cmd.includes('review')
);
if (reviewIdx !== -1 && executionIdx !== -1 && executionIdx > reviewIdx) {
this.errors.push({
rule: 'Review After Changes',
message: 'Review commands must come after execution',
severity: 'error'
});
}
if (reviewIdx !== -1 && executionIdx === -1) {
const isModuleReview = chain[reviewIdx] === 'review-module-cycle';
if (!isModuleReview) {
this.warnings.push({
rule: 'Review After Changes',
message: 'Review without execution - needs git changes to review',
severity: 'warning'
});
}
}
}
validateBugfixStandalone(chain) {
if (chain.includes('lite-fix')) {
const others = chain.filter(cmd => cmd !== 'lite-fix');
if (others.length > 0) {
this.errors.push({
rule: 'BugFix Standalone',
message: 'lite-fix must be standalone, cannot combine with other commands',
fix: 'Use lite-fix alone OR use plan + execute for larger changes',
severity: 'error'
});
}
}
}
validateDependencies(chain) {
for (let i = 0; i < chain.length; i++) {
const cmd = chain[i];
const cmdMeta = this.registry.commands[cmd];
if (!cmdMeta) continue;
const deps = cmdMeta.dependencies || [];
const depsOptional = cmdMeta.dependencies_optional || false;
if (deps.length > 0 && !depsOptional) {
const hasDependency = deps.some(dep => {
const depIdx = chain.indexOf(dep);
return depIdx !== -1 && depIdx < i;
});
if (!hasDependency) {
this.errors.push({
rule: 'Dependency Satisfaction',
message: `${cmd} requires ${deps.join(' or ')} before it`,
severity: 'error'
});
}
}
}
}
validateNoRedundancy(chain) {
const seen = new Set();
const duplicates = [];
for (const cmd of chain) {
if (seen.has(cmd)) {
duplicates.push(cmd);
}
seen.add(cmd);
}
if (duplicates.length > 0) {
this.errors.push({
rule: 'No Redundant Commands',
message: `Duplicate commands: ${duplicates.join(', ')}`,
severity: 'error'
});
}
}
validateCommandExistence(chain) {
for (const cmd of chain) {
if (!this.registry.commands[cmd]) {
this.errors.push({
rule: 'Command Existence',
message: `Unknown command: ${cmd}`,
severity: 'error'
});
}
}
}
}
function main() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.log('Usage:');
console.log(' chain-validate.js <command1> <command2> ...');
console.log(' chain-validate.js --json "cmd1,cmd2,cmd3"');
console.log(' chain-validate.js --file chain.json');
process.exit(1);
}
let chain;
if (args[0] === '--json') {
chain = args[1].split(',').map(s => s.trim());
} else if (args[0] === '--file') {
const filePath = args[1];
const fileContent = JSON.parse(fs.readFileSync(filePath, 'utf8'));
chain = fileContent.chain || fileContent.steps.map(s => s.command);
} else {
chain = args;
}
const validator = new ChainValidator(registry);
const result = validator.validate(chain);
console.log('\n=== Chain Validation Report ===\n');
console.log('Chain:', chain.join(' → '));
console.log('');
if (result.valid) {
console.log('✓ Chain is valid!\n');
} else {
console.log('✗ Chain has errors:\n');
result.errors.forEach(err => {
console.log(` [${err.rule}] ${err.message}`);
if (err.fix) {
console.log(` Fix: ${err.fix}`);
}
});
console.log('');
}
if (result.warnings.length > 0) {
console.log('⚠ Warnings:\n');
result.warnings.forEach(warn => {
console.log(` [${warn.rule}] ${warn.message}`);
});
console.log('');
}
process.exit(result.valid ? 0 : 1);
}
if (require.main === module) {
main();
}
module.exports = { ChainValidator };

View File

@@ -0,0 +1,181 @@
#!/usr/bin/env node
/**
* Command Registry Tool
*
* 功能:
* 1. 根据命令名称查找并提取 YAML 头
* 2. 从全局 .claude/commands/workflow 目录读取
* 3. 支持按需提取(不是全量扫描)
*/
const fs = require('fs');
const path = require('path');
const os = require('os');
class CommandRegistry {
constructor(commandDir = null) {
// 优先使用传入的目录
if (commandDir) {
this.commandDir = commandDir;
} else {
// 自动查找 .claude/commands/workflow
this.commandDir = this.findCommandDir();
}
this.cache = {};
}
/**
* 自动查找 .claude/commands/workflow 目录
* 支持: 项目相对路径、用户 home 目录
*/
findCommandDir() {
// 1. 尝试相对于当前工作目录
const relativePath = path.join('.claude', 'commands', 'workflow');
if (fs.existsSync(relativePath)) {
return path.resolve(relativePath);
}
// 2. 尝试用户 home 目录
const homeDir = os.homedir();
const homeCommandDir = path.join(homeDir, '.claude', 'commands', 'workflow');
if (fs.existsSync(homeCommandDir)) {
return homeCommandDir;
}
// 未找到时返回 null后续操作会失败并提示
return null;
}
/**
* 解析 YAML 头
*/
parseYamlHeader(content) {
const match = content.match(/^---\n([\s\S]*?)\n---/);
if (!match) return null;
const yamlContent = match[1];
const result = {};
const lines = yamlContent.split('\n');
for (const line of lines) {
if (!line.trim()) continue;
const colonIndex = line.indexOf(':');
if (colonIndex === -1) continue;
const key = line.substring(0, colonIndex).trim();
const value = line.substring(colonIndex + 1).trim();
let cleanValue = value.replace(/^["']|["']$/g, '');
if (key === 'allowed-tools') {
cleanValue = cleanValue.split(',').map(t => t.trim());
}
result[key] = cleanValue;
}
return result;
}
/**
* 获取单个命令的元数据
* @param {string} commandName 命令名称 (e.g., "lite-plan" 或 "/workflow:lite-plan")
* @returns {object|null} 命令信息或 null
*/
getCommand(commandName) {
if (!this.commandDir) {
console.error('ERROR: .claude/commands/workflow 目录未找到');
return null;
}
// 标准化命令名称
const normalized = commandName.startsWith('/workflow:')
? commandName.substring('/workflow:'.length)
: commandName;
// 检查缓存
if (this.cache[normalized]) {
return this.cache[normalized];
}
// 读取命令文件
const filePath = path.join(this.commandDir, `${normalized}.md`);
if (!fs.existsSync(filePath)) {
return null;
}
try {
const content = fs.readFileSync(filePath, 'utf-8');
const header = this.parseYamlHeader(content);
if (header && header.name) {
const result = {
name: header.name,
command: `/workflow:${header.name}`,
description: header.description || '',
argumentHint: header['argument-hint'] || '',
allowedTools: Array.isArray(header['allowed-tools'])
? header['allowed-tools']
: (header['allowed-tools'] ? [header['allowed-tools']] : []),
filePath: filePath
};
// 缓存结果
this.cache[normalized] = result;
return result;
}
} catch (error) {
console.error(`读取命令失败 ${filePath}:`, error.message);
}
return null;
}
/**
* 批量获取多个命令的元数据
* @param {array} commandNames 命令名称数组
* @returns {object} 命令信息映射
*/
getCommands(commandNames) {
const result = {};
for (const name of commandNames) {
const cmd = this.getCommand(name);
if (cmd) {
result[cmd.command] = cmd;
}
}
return result;
}
/**
* 生成注册表 JSON
*/
toJSON(commands = null) {
const data = commands || this.cache;
return JSON.stringify(data, null, 2);
}
}
// CLI 模式
if (require.main === module) {
const args = process.argv.slice(2);
if (args.length === 0) {
console.error('用法: node command-registry.js <command-name> [command-name2] ...');
console.error('示例: node command-registry.js lite-plan lite-execute');
console.error(' node command-registry.js /workflow:lite-plan');
process.exit(1);
}
const registry = new CommandRegistry();
const commands = registry.getCommands(args);
console.log(JSON.stringify(commands, null, 2));
}
module.exports = CommandRegistry;