claude-code-workflow 7.2.11 → 7.2.13
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/agents/workflow-research-agent.md +112 -0
- package/.claude/commands/workflow/analyze-with-file.md +185 -60
- 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,442 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: resume
|
|
3
|
-
description: Resume interrupted IDAW session from last checkpoint
|
|
4
|
-
argument-hint: "[-y|--yes] [session-id]"
|
|
5
|
-
allowed-tools: Skill(*), TodoWrite(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*)
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# IDAW Resume Command (/idaw:resume)
|
|
9
|
-
|
|
10
|
-
## Auto Mode
|
|
11
|
-
|
|
12
|
-
When `--yes` or `-y`: Auto-skip interrupted task, continue with remaining.
|
|
13
|
-
|
|
14
|
-
## Skill Chain Mapping
|
|
15
|
-
|
|
16
|
-
```javascript
|
|
17
|
-
const SKILL_CHAIN_MAP = {
|
|
18
|
-
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
|
|
19
|
-
'bugfix-hotfix': ['workflow-lite-plan'],
|
|
20
|
-
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
|
|
21
|
-
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
|
|
22
|
-
'refactor': ['workflow:refactor-cycle'],
|
|
23
|
-
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
|
|
24
|
-
'test': ['workflow-test-fix'],
|
|
25
|
-
'test-fix': ['workflow-test-fix'],
|
|
26
|
-
'review': ['review-cycle'],
|
|
27
|
-
'docs': ['workflow-lite-plan']
|
|
28
|
-
};
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Task Type Inference
|
|
32
|
-
|
|
33
|
-
```javascript
|
|
34
|
-
function inferTaskType(title, description) {
|
|
35
|
-
const text = `${title} ${description}`.toLowerCase();
|
|
36
|
-
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
|
|
37
|
-
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
|
|
38
|
-
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
|
|
39
|
-
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
|
|
40
|
-
if (/generate test|写测试|add test/.test(text)) return 'test';
|
|
41
|
-
if (/review|code review/.test(text)) return 'review';
|
|
42
|
-
if (/docs|documentation|readme/.test(text)) return 'docs';
|
|
43
|
-
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
|
|
44
|
-
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
|
|
45
|
-
return 'feature';
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Implementation
|
|
50
|
-
|
|
51
|
-
### Phase 1: Find Resumable Session
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
const args = $ARGUMENTS;
|
|
55
|
-
const autoYes = /(-y|--yes)/.test(args);
|
|
56
|
-
const targetSessionId = args.replace(/(-y|--yes)/g, '').trim();
|
|
57
|
-
|
|
58
|
-
let session = null;
|
|
59
|
-
let sessionDir = null;
|
|
60
|
-
|
|
61
|
-
if (targetSessionId) {
|
|
62
|
-
// Load specific session
|
|
63
|
-
sessionDir = `.workflow/.idaw/sessions/${targetSessionId}`;
|
|
64
|
-
try {
|
|
65
|
-
session = JSON.parse(Read(`${sessionDir}/session.json`));
|
|
66
|
-
} catch {
|
|
67
|
-
console.log(`Session "${targetSessionId}" not found.`);
|
|
68
|
-
console.log('Use /idaw:status to list sessions, or /idaw:run to start a new one.');
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
} else {
|
|
72
|
-
// Find most recent running session
|
|
73
|
-
const sessionFiles = Glob('.workflow/.idaw/sessions/IDA-*/session.json') || [];
|
|
74
|
-
|
|
75
|
-
for (const f of sessionFiles) {
|
|
76
|
-
try {
|
|
77
|
-
const s = JSON.parse(Read(f));
|
|
78
|
-
if (s.status === 'running') {
|
|
79
|
-
session = s;
|
|
80
|
-
sessionDir = f.replace(/\/session\.json$/, '').replace(/\\session\.json$/, '');
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
// Skip malformed
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (!session) {
|
|
89
|
-
console.log('No running sessions found to resume.');
|
|
90
|
-
console.log('Use /idaw:run to start a new execution.');
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
console.log(`Resuming session: ${session.session_id}`);
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Phase 2: Handle Interrupted Task
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
// Find the task that was in_progress when interrupted
|
|
102
|
-
let currentTaskId = session.current_task;
|
|
103
|
-
let currentTask = null;
|
|
104
|
-
|
|
105
|
-
if (currentTaskId) {
|
|
106
|
-
try {
|
|
107
|
-
currentTask = JSON.parse(Read(`.workflow/.idaw/tasks/${currentTaskId}.json`));
|
|
108
|
-
} catch {
|
|
109
|
-
console.log(`Warning: Could not read task ${currentTaskId}`);
|
|
110
|
-
currentTaskId = null;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (currentTask && currentTask.status === 'in_progress') {
|
|
115
|
-
if (autoYes) {
|
|
116
|
-
// Auto: skip interrupted task
|
|
117
|
-
currentTask.status = 'skipped';
|
|
118
|
-
currentTask.execution.error = 'Skipped on resume (auto mode)';
|
|
119
|
-
currentTask.execution.completed_at = new Date().toISOString();
|
|
120
|
-
currentTask.updated_at = new Date().toISOString();
|
|
121
|
-
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
|
|
122
|
-
session.skipped.push(currentTaskId);
|
|
123
|
-
console.log(`Skipped interrupted task: ${currentTaskId}`);
|
|
124
|
-
} else {
|
|
125
|
-
const answer = AskUserQuestion({
|
|
126
|
-
questions: [{
|
|
127
|
-
question: `Task ${currentTaskId} was interrupted: "${currentTask.title}". How to proceed?`,
|
|
128
|
-
header: 'Resume',
|
|
129
|
-
multiSelect: false,
|
|
130
|
-
options: [
|
|
131
|
-
{ label: 'Retry', description: 'Reset to pending, re-execute from beginning' },
|
|
132
|
-
{ label: 'Skip', description: 'Mark as skipped, move to next task' }
|
|
133
|
-
]
|
|
134
|
-
}]
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
if (answer.answers?.Resume === 'Skip') {
|
|
138
|
-
currentTask.status = 'skipped';
|
|
139
|
-
currentTask.execution.error = 'Skipped on resume (user choice)';
|
|
140
|
-
currentTask.execution.completed_at = new Date().toISOString();
|
|
141
|
-
currentTask.updated_at = new Date().toISOString();
|
|
142
|
-
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
|
|
143
|
-
session.skipped.push(currentTaskId);
|
|
144
|
-
} else {
|
|
145
|
-
// Retry: reset to pending
|
|
146
|
-
currentTask.status = 'pending';
|
|
147
|
-
currentTask.execution.started_at = null;
|
|
148
|
-
currentTask.execution.completed_at = null;
|
|
149
|
-
currentTask.execution.skill_results = [];
|
|
150
|
-
currentTask.execution.error = null;
|
|
151
|
-
currentTask.updated_at = new Date().toISOString();
|
|
152
|
-
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Phase 3: Build Remaining Task Queue
|
|
159
|
-
|
|
160
|
-
```javascript
|
|
161
|
-
// Collect remaining tasks (pending, or the retried current task)
|
|
162
|
-
const allTaskIds = session.tasks;
|
|
163
|
-
const completedSet = new Set([...session.completed, ...session.failed, ...session.skipped]);
|
|
164
|
-
|
|
165
|
-
const remainingTasks = [];
|
|
166
|
-
for (const taskId of allTaskIds) {
|
|
167
|
-
if (completedSet.has(taskId)) continue;
|
|
168
|
-
try {
|
|
169
|
-
const task = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
|
|
170
|
-
if (task.status === 'pending') {
|
|
171
|
-
remainingTasks.push(task);
|
|
172
|
-
}
|
|
173
|
-
} catch {
|
|
174
|
-
console.log(`Warning: Could not read task ${taskId}, skipping`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (remainingTasks.length === 0) {
|
|
179
|
-
console.log('No remaining tasks to execute. Session complete.');
|
|
180
|
-
session.status = 'completed';
|
|
181
|
-
session.current_task = null;
|
|
182
|
-
session.updated_at = new Date().toISOString();
|
|
183
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Sort: priority ASC, then ID ASC
|
|
188
|
-
remainingTasks.sort((a, b) => {
|
|
189
|
-
if (a.priority !== b.priority) return a.priority - b.priority;
|
|
190
|
-
return a.id.localeCompare(b.id);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
console.log(`Remaining tasks: ${remainingTasks.length}`);
|
|
194
|
-
|
|
195
|
-
// Append resume marker to progress.md
|
|
196
|
-
const progressFile = `${sessionDir}/progress.md`;
|
|
197
|
-
try {
|
|
198
|
-
const currentProgress = Read(progressFile);
|
|
199
|
-
Write(progressFile, currentProgress + `\n---\n**Resumed**: ${new Date().toISOString()}\n\n`);
|
|
200
|
-
} catch {
|
|
201
|
-
Write(progressFile, `# IDAW Progress — ${session.session_id}\n\n---\n**Resumed**: ${new Date().toISOString()}\n\n`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Update TodoWrite
|
|
205
|
-
TodoWrite({
|
|
206
|
-
todos: remainingTasks.map((t, i) => ({
|
|
207
|
-
content: `IDAW:[${i + 1}/${remainingTasks.length}] ${t.title}`,
|
|
208
|
-
status: i === 0 ? 'in_progress' : 'pending',
|
|
209
|
-
activeForm: `Executing ${t.title}`
|
|
210
|
-
}))
|
|
211
|
-
});
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Phase 4-6: Execute Remaining (reuse run.md main loop)
|
|
215
|
-
|
|
216
|
-
Execute remaining tasks using the same Phase 4-6 logic from `/idaw:run`:
|
|
217
|
-
|
|
218
|
-
```javascript
|
|
219
|
-
// Phase 4: Main Loop — identical to run.md Phase 4
|
|
220
|
-
for (let taskIdx = 0; taskIdx < remainingTasks.length; taskIdx++) {
|
|
221
|
-
const task = remainingTasks[taskIdx];
|
|
222
|
-
|
|
223
|
-
// Resolve skill chain
|
|
224
|
-
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
|
|
225
|
-
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
|
|
226
|
-
|
|
227
|
-
// Update task → in_progress
|
|
228
|
-
task.status = 'in_progress';
|
|
229
|
-
task.task_type = resolvedType;
|
|
230
|
-
task.execution.started_at = new Date().toISOString();
|
|
231
|
-
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
|
232
|
-
|
|
233
|
-
session.current_task = task.id;
|
|
234
|
-
session.updated_at = new Date().toISOString();
|
|
235
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
236
|
-
|
|
237
|
-
console.log(`\n--- [${taskIdx + 1}/${remainingTasks.length}] ${task.id}: ${task.title} ---`);
|
|
238
|
-
console.log(`Chain: ${chain.join(' → ')}`);
|
|
239
|
-
|
|
240
|
-
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
|
|
241
|
-
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
|
|
242
|
-
console.log(` Pre-analysis: gathering context for ${resolvedType} task...`);
|
|
243
|
-
const affectedFiles = (task.context?.affected_files || []).join(', ');
|
|
244
|
-
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task before execution.
|
|
245
|
-
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + task.title} • Identify dependencies and risk areas • Note existing patterns to follow
|
|
246
|
-
MODE: analysis
|
|
247
|
-
CONTEXT: @**/*
|
|
248
|
-
EXPECTED: Brief context summary (affected modules, dependencies, risk areas) in 3-5 bullet points
|
|
249
|
-
CONSTRAINTS: Keep concise | Focus on execution-relevant context`;
|
|
250
|
-
const preAnalysis = Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
|
|
251
|
-
task.execution.skill_results.push({
|
|
252
|
-
skill: 'cli-pre-analysis',
|
|
253
|
-
status: 'completed',
|
|
254
|
-
context_summary: preAnalysis?.substring(0, 500),
|
|
255
|
-
timestamp: new Date().toISOString()
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Execute skill chain
|
|
260
|
-
let previousResult = null;
|
|
261
|
-
let taskFailed = false;
|
|
262
|
-
|
|
263
|
-
for (let skillIdx = 0; skillIdx < chain.length; skillIdx++) {
|
|
264
|
-
const skillName = chain[skillIdx];
|
|
265
|
-
const skillArgs = assembleSkillArgs(skillName, task, previousResult, autoYes, skillIdx === 0);
|
|
266
|
-
|
|
267
|
-
console.log(` [${skillIdx + 1}/${chain.length}] ${skillName}`);
|
|
268
|
-
|
|
269
|
-
try {
|
|
270
|
-
const result = Skill({ skill: skillName, args: skillArgs });
|
|
271
|
-
previousResult = result;
|
|
272
|
-
task.execution.skill_results.push({
|
|
273
|
-
skill: skillName,
|
|
274
|
-
status: 'completed',
|
|
275
|
-
timestamp: new Date().toISOString()
|
|
276
|
-
});
|
|
277
|
-
} catch (error) {
|
|
278
|
-
// ━━━ CLI-Assisted Error Recovery ━━━
|
|
279
|
-
console.log(` Diagnosing failure: ${skillName}...`);
|
|
280
|
-
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task execution.
|
|
281
|
-
TASK: • Analyze error: ${String(error).substring(0, 300)} • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'} • Identify root cause • Suggest fix strategy
|
|
282
|
-
MODE: analysis
|
|
283
|
-
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
|
|
284
|
-
EXPECTED: Root cause + actionable fix recommendation (1-2 sentences)
|
|
285
|
-
CONSTRAINTS: Focus on actionable diagnosis`;
|
|
286
|
-
const diagnosisResult = Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || echo "CLI diagnosis unavailable"`);
|
|
287
|
-
|
|
288
|
-
task.execution.skill_results.push({
|
|
289
|
-
skill: `cli-diagnosis:${skillName}`,
|
|
290
|
-
status: 'completed',
|
|
291
|
-
diagnosis: diagnosisResult?.substring(0, 500),
|
|
292
|
-
timestamp: new Date().toISOString()
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// Retry with diagnosis context
|
|
296
|
-
console.log(` Retry with diagnosis: ${skillName}`);
|
|
297
|
-
try {
|
|
298
|
-
const retryResult = Skill({ skill: skillName, args: skillArgs });
|
|
299
|
-
previousResult = retryResult;
|
|
300
|
-
task.execution.skill_results.push({
|
|
301
|
-
skill: skillName,
|
|
302
|
-
status: 'completed-retry-with-diagnosis',
|
|
303
|
-
timestamp: new Date().toISOString()
|
|
304
|
-
});
|
|
305
|
-
} catch (retryError) {
|
|
306
|
-
task.execution.skill_results.push({
|
|
307
|
-
skill: skillName,
|
|
308
|
-
status: 'failed',
|
|
309
|
-
error: String(retryError).substring(0, 200),
|
|
310
|
-
timestamp: new Date().toISOString()
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
if (autoYes) {
|
|
314
|
-
taskFailed = true;
|
|
315
|
-
break;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const answer = AskUserQuestion({
|
|
319
|
-
questions: [{
|
|
320
|
-
question: `${skillName} failed after CLI diagnosis + retry: ${String(retryError).substring(0, 100)}`,
|
|
321
|
-
header: 'Error',
|
|
322
|
-
multiSelect: false,
|
|
323
|
-
options: [
|
|
324
|
-
{ label: 'Skip task', description: 'Mark as failed, continue' },
|
|
325
|
-
{ label: 'Abort', description: 'Stop run' }
|
|
326
|
-
]
|
|
327
|
-
}]
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
if (answer.answers?.Error === 'Abort') {
|
|
331
|
-
task.status = 'failed';
|
|
332
|
-
task.execution.error = String(retryError).substring(0, 200);
|
|
333
|
-
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
|
334
|
-
session.failed.push(task.id);
|
|
335
|
-
session.status = 'failed';
|
|
336
|
-
session.updated_at = new Date().toISOString();
|
|
337
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
taskFailed = true;
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Phase 5: Checkpoint
|
|
347
|
-
if (taskFailed) {
|
|
348
|
-
task.status = 'failed';
|
|
349
|
-
task.execution.error = 'Skill chain failed after retry';
|
|
350
|
-
task.execution.completed_at = new Date().toISOString();
|
|
351
|
-
session.failed.push(task.id);
|
|
352
|
-
} else {
|
|
353
|
-
// Git commit
|
|
354
|
-
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
|
|
355
|
-
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
|
|
356
|
-
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
|
|
357
|
-
|
|
358
|
-
if (diffCheck?.trim() || untrackedCheck?.trim()) {
|
|
359
|
-
Bash('git add -A');
|
|
360
|
-
Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
|
|
361
|
-
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
|
|
362
|
-
task.execution.git_commit = commitHash;
|
|
363
|
-
} else {
|
|
364
|
-
task.execution.git_commit = 'no-commit';
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
task.status = 'completed';
|
|
368
|
-
task.execution.completed_at = new Date().toISOString();
|
|
369
|
-
session.completed.push(task.id);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
task.updated_at = new Date().toISOString();
|
|
373
|
-
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
|
374
|
-
session.updated_at = new Date().toISOString();
|
|
375
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
376
|
-
|
|
377
|
-
// Append progress
|
|
378
|
-
const chain_str = chain.join(' → ');
|
|
379
|
-
const progressEntry = `## ${task.id} — ${task.title}\n- Status: ${task.status}\n- Chain: ${chain_str}\n- Commit: ${task.execution.git_commit || '-'}\n\n`;
|
|
380
|
-
const currentProgress = Read(`${sessionDir}/progress.md`);
|
|
381
|
-
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Phase 6: Report
|
|
385
|
-
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
|
|
386
|
-
session.current_task = null;
|
|
387
|
-
session.updated_at = new Date().toISOString();
|
|
388
|
-
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
|
389
|
-
|
|
390
|
-
const summary = `\n---\n## Summary (Resumed)\n- Completed: ${session.completed.length}\n- Failed: ${session.failed.length}\n- Skipped: ${session.skipped.length}\n`;
|
|
391
|
-
const finalProgress = Read(`${sessionDir}/progress.md`);
|
|
392
|
-
Write(`${sessionDir}/progress.md`, finalProgress + summary);
|
|
393
|
-
|
|
394
|
-
console.log('\n=== IDAW Resume Complete ===');
|
|
395
|
-
console.log(`Session: ${session.session_id}`);
|
|
396
|
-
console.log(`Completed: ${session.completed.length} | Failed: ${session.failed.length} | Skipped: ${session.skipped.length}`);
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
## Helper Functions
|
|
400
|
-
|
|
401
|
-
### assembleSkillArgs
|
|
402
|
-
|
|
403
|
-
```javascript
|
|
404
|
-
function assembleSkillArgs(skillName, task, previousResult, autoYes, isFirst) {
|
|
405
|
-
let args = '';
|
|
406
|
-
|
|
407
|
-
if (isFirst) {
|
|
408
|
-
// Sanitize for shell safety
|
|
409
|
-
const goal = `${task.title}\n${task.description}`
|
|
410
|
-
.replace(/\\/g, '\\\\')
|
|
411
|
-
.replace(/"/g, '\\"')
|
|
412
|
-
.replace(/\$/g, '\\$')
|
|
413
|
-
.replace(/`/g, '\\`');
|
|
414
|
-
args = `"${goal}"`;
|
|
415
|
-
if (task.task_type === 'bugfix-hotfix') args += ' --hotfix';
|
|
416
|
-
} else if (previousResult?.session_id) {
|
|
417
|
-
args = `--session="${previousResult.session_id}"`;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (autoYes && !args.includes('-y') && !args.includes('--yes')) {
|
|
421
|
-
args = args ? `${args} -y` : '-y';
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return args;
|
|
425
|
-
}
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
## Examples
|
|
429
|
-
|
|
430
|
-
```bash
|
|
431
|
-
# Resume most recent running session (interactive)
|
|
432
|
-
/idaw:resume
|
|
433
|
-
|
|
434
|
-
# Resume specific session
|
|
435
|
-
/idaw:resume IDA-auth-fix-20260301
|
|
436
|
-
|
|
437
|
-
# Resume with auto mode (skip interrupted, continue)
|
|
438
|
-
/idaw:resume -y
|
|
439
|
-
|
|
440
|
-
# Resume specific session with auto mode
|
|
441
|
-
/idaw:resume -y IDA-auth-fix-20260301
|
|
442
|
-
```
|