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,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++`