claude-code-workflow 7.2.11 → 7.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/workflow/analyze-with-file.md +108 -54
- package/.claude/commands/workflow-tune.md +811 -0
- package/.claude/skills/workflow-lite-execute/SKILL.md +106 -14
- package/.claude/skills/workflow-lite-plan/SKILL.md +34 -72
- package/.claude/skills/workflow-lite-test-review/SKILL.md +39 -26
- package/package.json +1 -1
- package/.claude/commands/ddd/auto.md +0 -359
- package/.claude/commands/ddd/doc-generate.md +0 -222
- package/.claude/commands/ddd/doc-refresh.md +0 -218
- package/.claude/commands/ddd/execute.md +0 -416
- package/.claude/commands/ddd/index-build.md +0 -212
- package/.claude/commands/ddd/plan.md +0 -611
- package/.claude/commands/ddd/scan.md +0 -365
- package/.claude/commands/ddd/sync.md +0 -353
- package/.claude/commands/ddd/update.md +0 -160
- package/.claude/commands/idaw/add.md +0 -287
- package/.claude/commands/idaw/resume.md +0 -442
- package/.claude/commands/idaw/run-coordinate.md +0 -648
- package/.claude/commands/idaw/run.md +0 -539
- package/.claude/commands/idaw/status.md +0 -182
- package/.claude/skills/workflow-tune/SKILL.md +0 -487
- package/.claude/skills/workflow-tune/phases/01-setup.md +0 -548
- package/.claude/skills/workflow-tune/phases/02-step-execute.md +0 -197
- package/.claude/skills/workflow-tune/phases/03-step-analyze.md +0 -386
- package/.claude/skills/workflow-tune/phases/04-synthesize.md +0 -257
- package/.claude/skills/workflow-tune/phases/05-optimize-report.md +0 -246
- package/.claude/skills/workflow-tune/specs/workflow-eval-criteria.md +0 -57
- package/.claude/skills/workflow-tune/templates/step-analysis-prompt.md +0 -88
- package/.claude/skills/workflow-tune/templates/synthesis-prompt.md +0 -90
|
@@ -1,648 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: run-coordinate
|
|
3
|
-
description: IDAW coordinator - execute task skill chains via external CLI with hook callbacks and git checkpoints
|
|
4
|
-
argument-hint: "[-y|--yes] [--task <id>[,<id>,...]] [--dry-run] [--tool <tool>]"
|
|
5
|
-
allowed-tools: Agent(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*), Grep(*)
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# IDAW Run Coordinate Command (/idaw:run-coordinate)
|
|
9
|
-
|
|
10
|
-
Coordinator variant of `/idaw:run`: external CLI execution with background tasks and hook callbacks.
|
|
11
|
-
|
|
12
|
-
**Execution Model**: `ccw cli -p "..." --tool <tool> --mode write` in background → hook callback → next step.
|
|
13
|
-
|
|
14
|
-
**vs `/idaw:run`**: Direct `Skill()` calls (blocking, main process) vs `ccw cli` (background, external process).
|
|
15
|
-
|
|
16
|
-
## When to Use
|
|
17
|
-
|
|
18
|
-
| Scenario | Use |
|
|
19
|
-
|----------|-----|
|
|
20
|
-
| Standard IDAW execution (main process) | `/idaw:run` |
|
|
21
|
-
| External CLI execution (background, hook-driven) | `/idaw:run-coordinate` |
|
|
22
|
-
| Need `claude` or `gemini` as execution tool | `/idaw:run-coordinate --tool claude` |
|
|
23
|
-
| Long-running tasks, avoid context window pressure | `/idaw:run-coordinate` |
|
|
24
|
-
|
|
25
|
-
## Skill Chain Mapping
|
|
26
|
-
|
|
27
|
-
```javascript
|
|
28
|
-
const SKILL_CHAIN_MAP = {
|
|
29
|
-
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
|
|
30
|
-
'bugfix-hotfix': ['workflow-lite-plan'],
|
|
31
|
-
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
|
|
32
|
-
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
|
|
33
|
-
'refactor': ['workflow:refactor-cycle'],
|
|
34
|
-
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
|
|
35
|
-
'test': ['workflow-test-fix'],
|
|
36
|
-
'test-fix': ['workflow-test-fix'],
|
|
37
|
-
'review': ['review-cycle'],
|
|
38
|
-
'docs': ['workflow-lite-plan']
|
|
39
|
-
};
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Task Type Inference
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
function inferTaskType(title, description) {
|
|
46
|
-
const text = `${title} ${description}`.toLowerCase();
|
|
47
|
-
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
|
|
48
|
-
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
|
|
49
|
-
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
|
|
50
|
-
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
|
|
51
|
-
if (/generate test|写测试|add test/.test(text)) return 'test';
|
|
52
|
-
if (/review|code review/.test(text)) return 'review';
|
|
53
|
-
if (/docs|documentation|readme/.test(text)) return 'docs';
|
|
54
|
-
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
|
|
55
|
-
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
|
|
56
|
-
return 'feature';
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## 6-Phase Execution (Coordinator Model)
|
|
61
|
-
|
|
62
|
-
### Phase 1: Load Tasks
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
const args = $ARGUMENTS;
|
|
66
|
-
const autoYes = /(-y|--yes)/.test(args);
|
|
67
|
-
const dryRun = /--dry-run/.test(args);
|
|
68
|
-
const taskFilter = args.match(/--task\s+([\w,-]+)/)?.[1]?.split(',') || null;
|
|
69
|
-
const cliTool = args.match(/--tool\s+(\w+)/)?.[1] || 'claude';
|
|
70
|
-
|
|
71
|
-
// Load task files
|
|
72
|
-
const taskFiles = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
|
|
73
|
-
|
|
74
|
-
if (taskFiles.length === 0) {
|
|
75
|
-
console.log('No IDAW tasks found. Use /idaw:add to create tasks.');
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Parse and filter
|
|
80
|
-
let tasks = taskFiles.map(f => JSON.parse(Read(f)));
|
|
81
|
-
|
|
82
|
-
if (taskFilter) {
|
|
83
|
-
tasks = tasks.filter(t => taskFilter.includes(t.id));
|
|
84
|
-
} else {
|
|
85
|
-
tasks = tasks.filter(t => t.status === 'pending');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (tasks.length === 0) {
|
|
89
|
-
console.log('No pending tasks to execute. Use /idaw:add to add tasks or --task to specify IDs.');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Sort: priority ASC (1=critical first), then ID ASC
|
|
94
|
-
tasks.sort((a, b) => {
|
|
95
|
-
if (a.priority !== b.priority) return a.priority - b.priority;
|
|
96
|
-
return a.id.localeCompare(b.id);
|
|
97
|
-
});
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Phase 2: Session Setup
|
|
101
|
-
|
|
102
|
-
```javascript
|
|
103
|
-
// Generate session ID: IDA-{slug}-YYYYMMDD
|
|
104
|
-
const slug = tasks[0].title
|
|
105
|
-
.toLowerCase()
|
|
106
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
107
|
-
.substring(0, 20)
|
|
108
|
-
.replace(/-$/, '');
|
|
109
|
-
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
110
|
-
let sessionId = `IDA-${slug}-${dateStr}`;
|
|
111
|
-
|
|
112
|
-
// Check collision
|
|
113
|
-
const existingSession = Glob(`.workflow/.idaw/sessions/${sessionId}/session.json`);
|
|
114
|
-
if (existingSession?.length > 0) {
|
|
115
|
-
sessionId = `${sessionId}-2`;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
|
|
119
|
-
Bash(`mkdir -p "${sessionDir}"`);
|
|
120
|
-
|
|
121
|
-
const session = {
|
|
122
|
-
session_id: sessionId,
|
|
123
|
-
mode: 'coordinate', // ★ Marks this as coordinator-mode session
|
|
124
|
-
cli_tool: cliTool,
|
|
125
|
-
status: 'running',
|
|
126
|
-
created_at: new Date().toISOString(),
|
|
127
|
-
updated_at: new Date().toISOString(),
|
|
128
|
-
tasks: tasks.map(t => t.id),
|
|
129
|
-
current_task: null,
|
|
130
|
-
current_skill_index: 0,
|
|
131
|
-
completed: [],
|
|
132
|
-
failed: [],
|
|
133
|
-
skipped: [],
|
|
134
|
-
prompts_used: []
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
138
|
-
|
|
139
|
-
// Initialize progress.md
|
|
140
|
-
const progressHeader = `# IDAW Progress — ${sessionId} (coordinate mode)\nStarted: ${session.created_at}\nCLI Tool: ${cliTool}\n\n`;
|
|
141
|
-
Write(`${sessionDir}/progress.md`, progressHeader);
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Phase 3: Startup Protocol
|
|
145
|
-
|
|
146
|
-
```javascript
|
|
147
|
-
// Check for existing running sessions
|
|
148
|
-
const runningSessions = Glob('.workflow/.idaw/sessions/IDA-*/session.json')
|
|
149
|
-
?.map(f => { try { return JSON.parse(Read(f)); } catch { return null; } })
|
|
150
|
-
.filter(s => s && s.status === 'running' && s.session_id !== sessionId) || [];
|
|
151
|
-
|
|
152
|
-
if (runningSessions.length > 0 && !autoYes) {
|
|
153
|
-
const answer = AskUserQuestion({
|
|
154
|
-
questions: [{
|
|
155
|
-
question: `Found running session: ${runningSessions[0].session_id}. How to proceed?`,
|
|
156
|
-
header: 'Conflict',
|
|
157
|
-
multiSelect: false,
|
|
158
|
-
options: [
|
|
159
|
-
{ label: 'Resume existing', description: 'Use /idaw:resume instead' },
|
|
160
|
-
{ label: 'Start fresh', description: 'Continue with new session' },
|
|
161
|
-
{ label: 'Abort', description: 'Cancel this run' }
|
|
162
|
-
]
|
|
163
|
-
}]
|
|
164
|
-
});
|
|
165
|
-
if (answer.answers?.Conflict === 'Resume existing') {
|
|
166
|
-
console.log(`Use: /idaw:resume ${runningSessions[0].session_id}`);
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
if (answer.answers?.Conflict === 'Abort') return;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Check git status
|
|
173
|
-
const gitStatus = Bash('git status --porcelain 2>/dev/null');
|
|
174
|
-
if (gitStatus?.trim() && !autoYes) {
|
|
175
|
-
const answer = AskUserQuestion({
|
|
176
|
-
questions: [{
|
|
177
|
-
question: 'Working tree has uncommitted changes. How to proceed?',
|
|
178
|
-
header: 'Git',
|
|
179
|
-
multiSelect: false,
|
|
180
|
-
options: [
|
|
181
|
-
{ label: 'Continue', description: 'Proceed with dirty tree' },
|
|
182
|
-
{ label: 'Stash', description: 'git stash before running' },
|
|
183
|
-
{ label: 'Abort', description: 'Stop and handle manually' }
|
|
184
|
-
]
|
|
185
|
-
}]
|
|
186
|
-
});
|
|
187
|
-
if (answer.answers?.Git === 'Stash') Bash('git stash push -m "idaw-pre-run"');
|
|
188
|
-
if (answer.answers?.Git === 'Abort') return;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Dry run
|
|
192
|
-
if (dryRun) {
|
|
193
|
-
console.log(`# Dry Run — ${sessionId} (coordinate mode, tool: ${cliTool})\n`);
|
|
194
|
-
for (const task of tasks) {
|
|
195
|
-
const taskType = task.task_type || inferTaskType(task.title, task.description);
|
|
196
|
-
const chain = task.skill_chain || SKILL_CHAIN_MAP[taskType] || SKILL_CHAIN_MAP['feature'];
|
|
197
|
-
console.log(`## ${task.id}: ${task.title}`);
|
|
198
|
-
console.log(` Type: ${taskType} | Priority: ${task.priority}`);
|
|
199
|
-
console.log(` Chain: ${chain.join(' → ')}`);
|
|
200
|
-
console.log(` CLI: ccw cli --tool ${cliTool} --mode write\n`);
|
|
201
|
-
}
|
|
202
|
-
console.log(`Total: ${tasks.length} tasks`);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Phase 4: Launch First Task (then wait for hook)
|
|
208
|
-
|
|
209
|
-
```javascript
|
|
210
|
-
// Start with the first task, first skill
|
|
211
|
-
const firstTask = tasks[0];
|
|
212
|
-
const resolvedType = firstTask.task_type || inferTaskType(firstTask.title, firstTask.description);
|
|
213
|
-
const chain = firstTask.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
|
|
214
|
-
|
|
215
|
-
// Update task → in_progress
|
|
216
|
-
firstTask.status = 'in_progress';
|
|
217
|
-
firstTask.task_type = resolvedType;
|
|
218
|
-
firstTask.execution.started_at = new Date().toISOString();
|
|
219
|
-
Write(`.workflow/.idaw/tasks/${firstTask.id}.json`, JSON.stringify(firstAgent, null, 2));
|
|
220
|
-
|
|
221
|
-
// Update session
|
|
222
|
-
session.current_task = firstTask.id;
|
|
223
|
-
session.current_skill_index = 0;
|
|
224
|
-
session.updated_at = new Date().toISOString();
|
|
225
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
226
|
-
|
|
227
|
-
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
|
|
228
|
-
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
|
|
229
|
-
console.log(`Pre-analysis: gathering context for ${resolvedType} task...`);
|
|
230
|
-
const affectedFiles = (firstTask.context?.affected_files || []).join(', ');
|
|
231
|
-
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task.
|
|
232
|
-
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + firstTask.title} • Identify dependencies and risk areas
|
|
233
|
-
MODE: analysis
|
|
234
|
-
CONTEXT: @**/*
|
|
235
|
-
EXPECTED: Brief context summary in 3-5 bullet points
|
|
236
|
-
CONSTRAINTS: Keep concise`;
|
|
237
|
-
Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Assemble prompt for first skill
|
|
241
|
-
const skillName = chain[0];
|
|
242
|
-
const prompt = assembleCliPrompt(skillName, firstAgent, null, autoYes);
|
|
243
|
-
|
|
244
|
-
session.prompts_used.push({
|
|
245
|
-
task_id: firstTask.id,
|
|
246
|
-
skill_index: 0,
|
|
247
|
-
skill: skillName,
|
|
248
|
-
prompt: prompt,
|
|
249
|
-
timestamp: new Date().toISOString()
|
|
250
|
-
});
|
|
251
|
-
session.updated_at = new Date().toISOString();
|
|
252
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
253
|
-
|
|
254
|
-
// Launch via ccw cli in background
|
|
255
|
-
console.log(`[1/${tasks.length}] ${firstTask.id}: ${firstTask.title}`);
|
|
256
|
-
console.log(` Chain: ${chain.join(' → ')}`);
|
|
257
|
-
console.log(` Launching: ${skillName} via ccw cli --tool ${cliTool}`);
|
|
258
|
-
|
|
259
|
-
Bash(
|
|
260
|
-
`ccw cli -p "${escapeForShell(prompt)}" --tool ${cliTool} --mode write`,
|
|
261
|
-
{ run_in_background: true }
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
// ★ STOP HERE — wait for hook callback
|
|
265
|
-
// Hook callback will trigger handleStepCompletion() below
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Phase 5: Hook Callback Handler (per-step completion)
|
|
269
|
-
|
|
270
|
-
```javascript
|
|
271
|
-
// Called by hook when background CLI completes
|
|
272
|
-
async function handleStepCompletion(sessionId, cliOutput) {
|
|
273
|
-
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
|
|
274
|
-
const session = JSON.parse(Read(`${sessionDir}/session.json`));
|
|
275
|
-
|
|
276
|
-
const taskId = session.current_task;
|
|
277
|
-
const task = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
|
|
278
|
-
|
|
279
|
-
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
|
|
280
|
-
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
|
|
281
|
-
const skillIdx = session.current_skill_index;
|
|
282
|
-
const skillName = chain[skillIdx];
|
|
283
|
-
|
|
284
|
-
// Parse CLI output for session ID
|
|
285
|
-
const parsedOutput = parseCliOutput(cliOutput);
|
|
286
|
-
|
|
287
|
-
// Record skill result
|
|
288
|
-
task.execution.skill_results.push({
|
|
289
|
-
skill: skillName,
|
|
290
|
-
status: parsedOutput.success ? 'completed' : 'failed',
|
|
291
|
-
session_id: parsedOutput.sessionId,
|
|
292
|
-
timestamp: new Date().toISOString()
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// ━━━ Handle failure with CLI diagnosis ━━━
|
|
296
|
-
if (!parsedOutput.success) {
|
|
297
|
-
console.log(` ${skillName} failed. Running CLI diagnosis...`);
|
|
298
|
-
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task.
|
|
299
|
-
TASK: • Analyze error output • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'}
|
|
300
|
-
MODE: analysis
|
|
301
|
-
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
|
|
302
|
-
EXPECTED: Root cause + fix recommendation
|
|
303
|
-
CONSTRAINTS: Actionable diagnosis`;
|
|
304
|
-
Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || true`);
|
|
305
|
-
|
|
306
|
-
task.execution.skill_results.push({
|
|
307
|
-
skill: `cli-diagnosis:${skillName}`,
|
|
308
|
-
status: 'completed',
|
|
309
|
-
timestamp: new Date().toISOString()
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// Retry once
|
|
313
|
-
console.log(` Retrying: ${skillName}`);
|
|
314
|
-
const retryPrompt = assembleCliPrompt(skillName, task, parsedOutput, true);
|
|
315
|
-
session.prompts_used.push({
|
|
316
|
-
task_id: taskId,
|
|
317
|
-
skill_index: skillIdx,
|
|
318
|
-
skill: `${skillName}-retry`,
|
|
319
|
-
prompt: retryPrompt,
|
|
320
|
-
timestamp: new Date().toISOString()
|
|
321
|
-
});
|
|
322
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
323
|
-
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
|
|
324
|
-
|
|
325
|
-
Bash(
|
|
326
|
-
`ccw cli -p "${escapeForShell(retryPrompt)}" --tool ${session.cli_tool} --mode write`,
|
|
327
|
-
{ run_in_background: true }
|
|
328
|
-
);
|
|
329
|
-
return; // Wait for retry hook
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// ━━━ Skill succeeded — advance ━━━
|
|
333
|
-
const nextSkillIdx = skillIdx + 1;
|
|
334
|
-
|
|
335
|
-
if (nextSkillIdx < chain.length) {
|
|
336
|
-
// More skills in this task's chain → launch next skill
|
|
337
|
-
session.current_skill_index = nextSkillIdx;
|
|
338
|
-
session.updated_at = new Date().toISOString();
|
|
339
|
-
|
|
340
|
-
const nextSkill = chain[nextSkillIdx];
|
|
341
|
-
const nextPrompt = assembleCliPrompt(nextSkill, task, parsedOutput, true);
|
|
342
|
-
|
|
343
|
-
session.prompts_used.push({
|
|
344
|
-
task_id: taskId,
|
|
345
|
-
skill_index: nextSkillIdx,
|
|
346
|
-
skill: nextSkill,
|
|
347
|
-
prompt: nextPrompt,
|
|
348
|
-
timestamp: new Date().toISOString()
|
|
349
|
-
});
|
|
350
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
351
|
-
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
|
|
352
|
-
|
|
353
|
-
console.log(` Next skill: ${nextSkill}`);
|
|
354
|
-
Bash(
|
|
355
|
-
`ccw cli -p "${escapeForShell(nextPrompt)}" --tool ${session.cli_tool} --mode write`,
|
|
356
|
-
{ run_in_background: true }
|
|
357
|
-
);
|
|
358
|
-
return; // Wait for next hook
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// ━━━ Task chain complete — git checkpoint ━━━
|
|
362
|
-
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
|
|
363
|
-
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
|
|
364
|
-
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
|
|
365
|
-
|
|
366
|
-
if (diffCheck?.trim() || untrackedCheck?.trim()) {
|
|
367
|
-
Bash('git add -A');
|
|
368
|
-
Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
|
|
369
|
-
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
|
|
370
|
-
task.execution.git_commit = commitHash;
|
|
371
|
-
} else {
|
|
372
|
-
task.execution.git_commit = 'no-commit';
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
task.status = 'completed';
|
|
376
|
-
task.execution.completed_at = new Date().toISOString();
|
|
377
|
-
task.updated_at = new Date().toISOString();
|
|
378
|
-
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
|
|
379
|
-
|
|
380
|
-
session.completed.push(taskId);
|
|
381
|
-
|
|
382
|
-
// Append progress
|
|
383
|
-
const progressEntry = `## ${task.id} — ${task.title}\n` +
|
|
384
|
-
`- Status: completed\n` +
|
|
385
|
-
`- Type: ${task.task_type}\n` +
|
|
386
|
-
`- Chain: ${chain.join(' → ')}\n` +
|
|
387
|
-
`- Commit: ${task.execution.git_commit || '-'}\n` +
|
|
388
|
-
`- Mode: coordinate (${session.cli_tool})\n\n`;
|
|
389
|
-
const currentProgress = Read(`${sessionDir}/progress.md`);
|
|
390
|
-
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
|
|
391
|
-
|
|
392
|
-
// ━━━ Advance to next task ━━━
|
|
393
|
-
const allTaskIds = session.tasks;
|
|
394
|
-
const completedSet = new Set([...session.completed, ...session.failed, ...session.skipped]);
|
|
395
|
-
const nextTaskId = allTaskIds.find(id => !completedSet.has(id));
|
|
396
|
-
|
|
397
|
-
if (nextTaskId) {
|
|
398
|
-
// Load next task
|
|
399
|
-
const nextTask = JSON.parse(Read(`.workflow/.idaw/tasks/${nextTaskId}.json`));
|
|
400
|
-
const nextType = nextTask.task_type || inferTaskType(nextTask.title, nextTask.description);
|
|
401
|
-
const nextChain = nextTask.skill_chain || SKILL_CHAIN_MAP[nextType] || SKILL_CHAIN_MAP['feature'];
|
|
402
|
-
|
|
403
|
-
nextTask.status = 'in_progress';
|
|
404
|
-
nextTask.task_type = nextType;
|
|
405
|
-
nextTask.execution.started_at = new Date().toISOString();
|
|
406
|
-
Write(`.workflow/.idaw/tasks/${nextTaskId}.json`, JSON.stringify(nextAgent, null, 2));
|
|
407
|
-
|
|
408
|
-
session.current_task = nextTaskId;
|
|
409
|
-
session.current_skill_index = 0;
|
|
410
|
-
session.updated_at = new Date().toISOString();
|
|
411
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
412
|
-
|
|
413
|
-
// Pre-analysis for complex tasks
|
|
414
|
-
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(nextType)) {
|
|
415
|
-
const affectedFiles = (nextTask.context?.affected_files || []).join(', ');
|
|
416
|
-
Bash(`ccw cli -p 'PURPOSE: Pre-analyze context for ${nextTask.title}. TASK: Check ${affectedFiles || "related files"}. MODE: analysis. EXPECTED: 3-5 bullet points.' --tool gemini --mode analysis 2>&1 || true`);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const nextSkillName = nextChain[0];
|
|
420
|
-
const nextPrompt = assembleCliPrompt(nextSkillName, nextAgent, null, true);
|
|
421
|
-
|
|
422
|
-
session.prompts_used.push({
|
|
423
|
-
task_id: nextTaskId,
|
|
424
|
-
skill_index: 0,
|
|
425
|
-
skill: nextSkillName,
|
|
426
|
-
prompt: nextPrompt,
|
|
427
|
-
timestamp: new Date().toISOString()
|
|
428
|
-
});
|
|
429
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
430
|
-
|
|
431
|
-
const taskNum = session.completed.length + 1;
|
|
432
|
-
const totalTasks = session.tasks.length;
|
|
433
|
-
console.log(`\n[${taskNum}/${totalTasks}] ${nextTaskId}: ${nextTask.title}`);
|
|
434
|
-
console.log(` Chain: ${nextChain.join(' → ')}`);
|
|
435
|
-
|
|
436
|
-
Bash(
|
|
437
|
-
`ccw cli -p "${escapeForShell(nextPrompt)}" --tool ${session.cli_tool} --mode write`,
|
|
438
|
-
{ run_in_background: true }
|
|
439
|
-
);
|
|
440
|
-
return; // Wait for hook
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// ━━━ All tasks complete — Phase 6: Report ━━━
|
|
444
|
-
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
|
|
445
|
-
session.current_task = null;
|
|
446
|
-
session.updated_at = new Date().toISOString();
|
|
447
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
448
|
-
|
|
449
|
-
const summary = `\n---\n## Summary (coordinate mode)\n` +
|
|
450
|
-
`- CLI Tool: ${session.cli_tool}\n` +
|
|
451
|
-
`- Completed: ${session.completed.length}\n` +
|
|
452
|
-
`- Failed: ${session.failed.length}\n` +
|
|
453
|
-
`- Skipped: ${session.skipped.length}\n` +
|
|
454
|
-
`- Total: ${session.tasks.length}\n`;
|
|
455
|
-
const finalProgress = Read(`${sessionDir}/progress.md`);
|
|
456
|
-
Write(`${sessionDir}/progress.md`, finalProgress + summary);
|
|
457
|
-
|
|
458
|
-
console.log('\n=== IDAW Coordinate Complete ===');
|
|
459
|
-
console.log(`Session: ${sessionId}`);
|
|
460
|
-
console.log(`Completed: ${session.completed.length}/${session.tasks.length}`);
|
|
461
|
-
if (session.failed.length > 0) console.log(`Failed: ${session.failed.join(', ')}`);
|
|
462
|
-
}
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
## Helper Functions
|
|
466
|
-
|
|
467
|
-
### assembleCliPrompt
|
|
468
|
-
|
|
469
|
-
```javascript
|
|
470
|
-
function assembleCliPrompt(skillName, task, previousResult, autoYes) {
|
|
471
|
-
let prompt = '';
|
|
472
|
-
const yFlag = autoYes ? ' -y' : '';
|
|
473
|
-
|
|
474
|
-
// Map skill to command invocation
|
|
475
|
-
if (skillName === 'workflow-lite-plan') {
|
|
476
|
-
const goal = sanitize(`${task.title}\n${task.description}`);
|
|
477
|
-
prompt = `/workflow-lite-plan${yFlag} "${goal}"`;
|
|
478
|
-
if (task.task_type === 'bugfix') prompt = `/workflow-lite-plan${yFlag} --bugfix "${goal}"`;
|
|
479
|
-
if (task.task_type === 'bugfix-hotfix') prompt = `/workflow-lite-plan${yFlag} --hotfix "${goal}"`;
|
|
480
|
-
|
|
481
|
-
} else if (skillName === 'workflow-plan') {
|
|
482
|
-
prompt = `/workflow-plan${yFlag} "${sanitize(task.title)}"`;
|
|
483
|
-
|
|
484
|
-
} else if (skillName === 'workflow-execute') {
|
|
485
|
-
if (previousResult?.sessionId) {
|
|
486
|
-
prompt = `/workflow-execute${yFlag} --resume-session="${previousResult.sessionId}"`;
|
|
487
|
-
} else {
|
|
488
|
-
prompt = `/workflow-execute${yFlag}`;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
} else if (skillName === 'workflow-test-fix') {
|
|
492
|
-
if (previousResult?.sessionId) {
|
|
493
|
-
prompt = `/workflow-test-fix${yFlag} "${previousResult.sessionId}"`;
|
|
494
|
-
} else {
|
|
495
|
-
prompt = `/workflow-test-fix${yFlag} "${sanitize(task.title)}"`;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
} else if (skillName === 'workflow-tdd-plan') {
|
|
499
|
-
prompt = `/workflow-tdd-plan${yFlag} "${sanitize(task.title)}"`;
|
|
500
|
-
|
|
501
|
-
} else if (skillName === 'workflow:refactor-cycle') {
|
|
502
|
-
prompt = `/workflow:refactor-cycle${yFlag} "${sanitize(task.title)}"`;
|
|
503
|
-
|
|
504
|
-
} else if (skillName === 'review-cycle') {
|
|
505
|
-
if (previousResult?.sessionId) {
|
|
506
|
-
prompt = `/review-cycle${yFlag} --session="${previousResult.sessionId}"`;
|
|
507
|
-
} else {
|
|
508
|
-
prompt = `/review-cycle${yFlag}`;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
} else {
|
|
512
|
-
// Generic fallback
|
|
513
|
-
prompt = `/${skillName}${yFlag} "${sanitize(task.title)}"`;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// Append task context
|
|
517
|
-
prompt += `\n\nTask: ${task.title}\nDescription: ${task.description}`;
|
|
518
|
-
if (task.context?.affected_files?.length > 0) {
|
|
519
|
-
prompt += `\nAffected files: ${task.context.affected_files.join(', ')}`;
|
|
520
|
-
}
|
|
521
|
-
if (task.context?.acceptance_criteria?.length > 0) {
|
|
522
|
-
prompt += `\nAcceptance criteria: ${task.context.acceptance_criteria.join('; ')}`;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
return prompt;
|
|
526
|
-
}
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### sanitize & escapeForShell
|
|
530
|
-
|
|
531
|
-
```javascript
|
|
532
|
-
function sanitize(text) {
|
|
533
|
-
return text
|
|
534
|
-
.replace(/\\/g, '\\\\')
|
|
535
|
-
.replace(/"/g, '\\"')
|
|
536
|
-
.replace(/\$/g, '\\$')
|
|
537
|
-
.replace(/`/g, '\\`');
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
function escapeForShell(prompt) {
|
|
541
|
-
return prompt.replace(/'/g, "'\\''");
|
|
542
|
-
}
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
### parseCliOutput
|
|
546
|
-
|
|
547
|
-
```javascript
|
|
548
|
-
function parseCliOutput(output) {
|
|
549
|
-
// Extract session ID from CLI output (e.g., WFS-xxx, session-xxx)
|
|
550
|
-
const sessionMatch = output.match(/(?:session|WFS|Session ID)[:\s]*([\w-]+)/i);
|
|
551
|
-
const success = !/(?:error|failed|fatal)/i.test(output) || /completed|success/i.test(output);
|
|
552
|
-
|
|
553
|
-
return {
|
|
554
|
-
success,
|
|
555
|
-
sessionId: sessionMatch?.[1] || null,
|
|
556
|
-
raw: output?.substring(0, 500)
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
## CLI-Assisted Analysis
|
|
562
|
-
|
|
563
|
-
Same as `/idaw:run` — integrated at two points:
|
|
564
|
-
|
|
565
|
-
### Pre-Task Context Analysis
|
|
566
|
-
For `bugfix`, `bugfix-hotfix`, `feature-complex` tasks: auto-invoke `ccw cli --tool gemini --mode analysis` before launching skill chain.
|
|
567
|
-
|
|
568
|
-
### Error Recovery with CLI Diagnosis
|
|
569
|
-
When a skill's CLI execution fails: invoke diagnosis → retry once → if still fails, mark failed and advance.
|
|
570
|
-
|
|
571
|
-
```
|
|
572
|
-
Skill CLI fails → CLI diagnosis (gemini) → Retry CLI → Still fails → mark failed → next task
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
## State Flow
|
|
576
|
-
|
|
577
|
-
```
|
|
578
|
-
Phase 4: Launch first skill
|
|
579
|
-
↓
|
|
580
|
-
ccw cli --tool claude --mode write (background)
|
|
581
|
-
↓
|
|
582
|
-
★ STOP — wait for hook callback
|
|
583
|
-
↓
|
|
584
|
-
Phase 5: handleStepCompletion()
|
|
585
|
-
├─ Skill succeeded + more in chain → launch next skill → STOP
|
|
586
|
-
├─ Skill succeeded + chain complete → git checkpoint → next task → STOP
|
|
587
|
-
├─ Skill failed → CLI diagnosis → retry → STOP
|
|
588
|
-
└─ All tasks done → Phase 6: Report
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
## Session State (session.json)
|
|
592
|
-
|
|
593
|
-
```json
|
|
594
|
-
{
|
|
595
|
-
"session_id": "IDA-fix-login-20260301",
|
|
596
|
-
"mode": "coordinate",
|
|
597
|
-
"cli_tool": "claude",
|
|
598
|
-
"status": "running|waiting|completed|failed",
|
|
599
|
-
"created_at": "ISO",
|
|
600
|
-
"updated_at": "ISO",
|
|
601
|
-
"tasks": ["IDAW-001", "IDAW-002"],
|
|
602
|
-
"current_task": "IDAW-001",
|
|
603
|
-
"current_skill_index": 0,
|
|
604
|
-
"completed": [],
|
|
605
|
-
"failed": [],
|
|
606
|
-
"skipped": [],
|
|
607
|
-
"prompts_used": [
|
|
608
|
-
{
|
|
609
|
-
"task_id": "IDAW-001",
|
|
610
|
-
"skill_index": 0,
|
|
611
|
-
"skill": "workflow-lite-plan",
|
|
612
|
-
"prompt": "/workflow-lite-plan -y \"Fix login timeout\"",
|
|
613
|
-
"timestamp": "ISO"
|
|
614
|
-
}
|
|
615
|
-
]
|
|
616
|
-
}
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
## Differences from /idaw:run
|
|
620
|
-
|
|
621
|
-
| Aspect | /idaw:run | /idaw:run-coordinate |
|
|
622
|
-
|--------|-----------|---------------------|
|
|
623
|
-
| Execution | `Skill()` blocking in main process | `ccw cli` background + hook callback |
|
|
624
|
-
| Context window | Shared (each skill uses main context) | Isolated (each CLI gets fresh context) |
|
|
625
|
-
| Concurrency | Sequential blocking | Sequential non-blocking (hook-driven) |
|
|
626
|
-
| State tracking | session.json + task.json | session.json + task.json + prompts_used |
|
|
627
|
-
| Tool selection | N/A (Skill native) | `--tool claude\|gemini\|qwen` |
|
|
628
|
-
| Resume | Via `/idaw:resume` (same) | Via `/idaw:resume` (same, detects mode) |
|
|
629
|
-
| Best for | Short chains, interactive | Long chains, autonomous, context-heavy |
|
|
630
|
-
|
|
631
|
-
## Examples
|
|
632
|
-
|
|
633
|
-
```bash
|
|
634
|
-
# Execute all pending tasks via claude CLI
|
|
635
|
-
/idaw:run-coordinate -y
|
|
636
|
-
|
|
637
|
-
# Use specific CLI tool
|
|
638
|
-
/idaw:run-coordinate -y --tool gemini
|
|
639
|
-
|
|
640
|
-
# Execute specific tasks
|
|
641
|
-
/idaw:run-coordinate --task IDAW-001,IDAW-003 --tool claude
|
|
642
|
-
|
|
643
|
-
# Dry run (show plan without executing)
|
|
644
|
-
/idaw:run-coordinate --dry-run
|
|
645
|
-
|
|
646
|
-
# Interactive mode
|
|
647
|
-
/idaw:run-coordinate
|
|
648
|
-
```
|