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,197 +0,0 @@
|
|
|
1
|
-
# Phase 2: Execute Step
|
|
2
|
-
|
|
3
|
-
> **COMPACT SENTINEL [Phase 2: Execute Step]**
|
|
4
|
-
> This phase contains 4 execution steps (Step 2.1 -- 2.4).
|
|
5
|
-
> If you can read this sentinel but cannot find the full Step protocol below, context has been compressed.
|
|
6
|
-
> Recovery: `Read("phases/02-step-execute.md")`
|
|
7
|
-
|
|
8
|
-
Execute a single workflow step and collect its output artifacts.
|
|
9
|
-
|
|
10
|
-
## Objective
|
|
11
|
-
|
|
12
|
-
- Determine step execution method (skill invoke / ccw cli / shell command)
|
|
13
|
-
- Execute step with appropriate tool
|
|
14
|
-
- Collect output artifacts into step directory
|
|
15
|
-
- Write artifacts manifest
|
|
16
|
-
|
|
17
|
-
## Execution
|
|
18
|
-
|
|
19
|
-
### Step 2.1: Prepare Step Directory
|
|
20
|
-
|
|
21
|
-
```javascript
|
|
22
|
-
const stepIdx = currentStepIndex; // from orchestrator loop
|
|
23
|
-
const step = state.steps[stepIdx];
|
|
24
|
-
const stepDir = `${state.work_dir}/steps/step-${stepIdx + 1}`;
|
|
25
|
-
const artifactsDir = `${stepDir}/artifacts`;
|
|
26
|
-
|
|
27
|
-
// Capture pre-execution state (git status, file timestamps)
|
|
28
|
-
const preGitStatus = Bash('git status --porcelain 2>/dev/null || echo "not a git repo"').stdout;
|
|
29
|
-
|
|
30
|
-
// ★ Warn if dirty git working directory (first step only)
|
|
31
|
-
if (stepIdx === 0 && preGitStatus.trim() && preGitStatus.trim() !== 'not a git repo') {
|
|
32
|
-
const dirtyLines = preGitStatus.trim().split('\n').length;
|
|
33
|
-
// Log warning — artifact collection via git diff may be unreliable
|
|
34
|
-
// This is informational; does not block execution
|
|
35
|
-
console.warn(`⚠ Dirty git working directory detected (${dirtyLines} changed files). Artifact collection via git diff may include pre-existing changes.`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const preExecSnapshot = {
|
|
39
|
-
timestamp: new Date().toISOString(),
|
|
40
|
-
git_status: preGitStatus,
|
|
41
|
-
working_files: Glob('**/*.{ts,js,md,json}').slice(0, 50) // sample
|
|
42
|
-
};
|
|
43
|
-
Write(`${stepDir}/pre-exec-snapshot.json`, JSON.stringify(preExecSnapshot, null, 2));
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Step 2.2: Execute by Step Type
|
|
47
|
-
|
|
48
|
-
```javascript
|
|
49
|
-
let executionResult = { success: false, method: '', output: '', duration: 0 };
|
|
50
|
-
const startTime = Date.now();
|
|
51
|
-
|
|
52
|
-
switch (step.type) {
|
|
53
|
-
case 'skill': {
|
|
54
|
-
// Skill invocation — use Skill tool
|
|
55
|
-
// Extract skill name and arguments from command
|
|
56
|
-
const skillCmd = step.command.replace(/^\//, '');
|
|
57
|
-
const [skillName, ...skillArgs] = skillCmd.split(/\s+/);
|
|
58
|
-
|
|
59
|
-
// Execute skill (this runs synchronously within current context)
|
|
60
|
-
// Note: Skill execution produces artifacts in the working directory
|
|
61
|
-
// We capture changes by comparing pre/post state
|
|
62
|
-
Skill({
|
|
63
|
-
name: skillName,
|
|
64
|
-
arguments: skillArgs.join(' ')
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
executionResult.method = 'skill';
|
|
68
|
-
executionResult.success = true;
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
case 'ccw-cli': {
|
|
73
|
-
// Direct ccw cli command
|
|
74
|
-
const cliCommand = step.command;
|
|
75
|
-
|
|
76
|
-
Bash({
|
|
77
|
-
command: cliCommand,
|
|
78
|
-
run_in_background: true,
|
|
79
|
-
timeout: 600000 // 10 minutes
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// STOP — wait for hook callback
|
|
83
|
-
// After callback:
|
|
84
|
-
executionResult.method = 'ccw-cli';
|
|
85
|
-
executionResult.success = true;
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
case 'command': {
|
|
90
|
-
// Generic shell command
|
|
91
|
-
const result = Bash({
|
|
92
|
-
command: step.command,
|
|
93
|
-
timeout: 300000 // 5 minutes
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
executionResult.method = 'command';
|
|
97
|
-
executionResult.output = result.stdout || '';
|
|
98
|
-
executionResult.success = result.exitCode === 0;
|
|
99
|
-
|
|
100
|
-
// Save command output
|
|
101
|
-
if (executionResult.output) {
|
|
102
|
-
Write(`${artifactsDir}/command-output.txt`, executionResult.output);
|
|
103
|
-
}
|
|
104
|
-
if (result.stderr) {
|
|
105
|
-
Write(`${artifactsDir}/command-stderr.txt`, result.stderr);
|
|
106
|
-
}
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
executionResult.duration = Date.now() - startTime;
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Step 2.3: Collect Artifacts
|
|
115
|
-
|
|
116
|
-
```javascript
|
|
117
|
-
// Capture post-execution state
|
|
118
|
-
const postExecSnapshot = {
|
|
119
|
-
timestamp: new Date().toISOString(),
|
|
120
|
-
git_status: Bash('git status --porcelain 2>/dev/null || echo "not a git repo"').stdout,
|
|
121
|
-
working_files: Glob('**/*.{ts,js,md,json}').slice(0, 50)
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Detect changed/new files by comparing snapshots
|
|
125
|
-
const preFiles = new Set(preExecSnapshot.working_files);
|
|
126
|
-
const newOrChanged = postExecSnapshot.working_files.filter(f => !preFiles.has(f));
|
|
127
|
-
|
|
128
|
-
// Also check git diff for modified files
|
|
129
|
-
const gitDiff = Bash('git diff --name-only 2>/dev/null || true').stdout.trim().split('\n').filter(Boolean);
|
|
130
|
-
|
|
131
|
-
// Collect all artifacts (new files + git-changed files + declared expected_artifacts)
|
|
132
|
-
const declaredArtifacts = (step.expected_artifacts || []).filter(f => {
|
|
133
|
-
// Verify declared artifacts actually exist
|
|
134
|
-
const exists = Glob(f);
|
|
135
|
-
return exists.length > 0;
|
|
136
|
-
}).flatMap(f => Glob(f));
|
|
137
|
-
|
|
138
|
-
const allArtifacts = [...new Set([...newOrChanged, ...gitDiff, ...declaredArtifacts])];
|
|
139
|
-
|
|
140
|
-
// Copy detected artifacts to step artifacts dir (or record references)
|
|
141
|
-
const artifactManifest = {
|
|
142
|
-
step: step.name,
|
|
143
|
-
step_index: stepIdx,
|
|
144
|
-
execution_method: executionResult.method,
|
|
145
|
-
success: executionResult.success,
|
|
146
|
-
duration_ms: executionResult.duration,
|
|
147
|
-
artifacts: allArtifacts.map(f => ({
|
|
148
|
-
path: f,
|
|
149
|
-
type: f.endsWith('.md') ? 'markdown' : f.endsWith('.json') ? 'json' : 'other',
|
|
150
|
-
size: 'unknown' // Can be filled by stat if needed
|
|
151
|
-
})),
|
|
152
|
-
// For skill type: also check .workflow/.scratchpad for generated files
|
|
153
|
-
scratchpad_files: step.type === 'skill'
|
|
154
|
-
? Glob('.workflow/.scratchpad/**/*').filter(f => {
|
|
155
|
-
// Only include files created after step started
|
|
156
|
-
return true; // Heuristic: include recent scratchpad files
|
|
157
|
-
}).slice(0, 20)
|
|
158
|
-
: [],
|
|
159
|
-
collected_at: new Date().toISOString()
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
Write(`${stepDir}/artifacts-manifest.json`, JSON.stringify(artifactManifest, null, 2));
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Step 2.4: Update State
|
|
166
|
-
|
|
167
|
-
```javascript
|
|
168
|
-
state.steps[stepIdx].status = 'executed';
|
|
169
|
-
state.steps[stepIdx].execution = {
|
|
170
|
-
method: executionResult.method,
|
|
171
|
-
success: executionResult.success,
|
|
172
|
-
duration_ms: executionResult.duration,
|
|
173
|
-
artifacts_dir: artifactsDir,
|
|
174
|
-
manifest_path: `${stepDir}/artifacts-manifest.json`,
|
|
175
|
-
artifact_count: artifactManifest.artifacts.length,
|
|
176
|
-
started_at: preExecSnapshot.timestamp,
|
|
177
|
-
completed_at: new Date().toISOString()
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
state.updated_at = new Date().toISOString();
|
|
181
|
-
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Error Handling
|
|
185
|
-
|
|
186
|
-
| Error | Recovery |
|
|
187
|
-
|-------|----------|
|
|
188
|
-
| Skill not found | Record failure, set success=false, continue to Phase 3 |
|
|
189
|
-
| CLI timeout (10min) | Retry once with shorter timeout, then record failure |
|
|
190
|
-
| Command exit non-zero | Record stderr, set success=false, continue to Phase 3 |
|
|
191
|
-
| No artifacts detected | Continue to Phase 3 — analysis evaluates step definition quality |
|
|
192
|
-
|
|
193
|
-
## Output
|
|
194
|
-
|
|
195
|
-
- **Files**: `pre-exec-snapshot.json`, `artifacts-manifest.json`, `artifacts/` (if command type)
|
|
196
|
-
- **State**: `steps[stepIdx].execution` updated
|
|
197
|
-
- **Next**: Phase 3 (Analyze Step)
|
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
# Phase 3: Analyze Step
|
|
2
|
-
|
|
3
|
-
> **COMPACT SENTINEL [Phase 3: Analyze Step]**
|
|
4
|
-
> This phase contains 5 execution steps (Step 3.1 -- 3.5).
|
|
5
|
-
> If you can read this sentinel but cannot find the full Step protocol below, context has been compressed.
|
|
6
|
-
> Recovery: `Read("phases/03-step-analyze.md")`
|
|
7
|
-
|
|
8
|
-
Analyze a completed step's artifacts and quality using `ccw cli --tool gemini --mode analysis`. Uses `--resume` to maintain context across step analyses, building a continuous analysis chain.
|
|
9
|
-
|
|
10
|
-
## Objective
|
|
11
|
-
|
|
12
|
-
- Inspect step artifacts (file list, content, quality signals)
|
|
13
|
-
- Build analysis prompt with step context + prior process log
|
|
14
|
-
- Execute via ccw cli Gemini with resume chain
|
|
15
|
-
- Parse analysis results → write step-{N}-analysis.md
|
|
16
|
-
- Append findings to process-log.md
|
|
17
|
-
- Return updated session ID for resume chain
|
|
18
|
-
|
|
19
|
-
## Execution
|
|
20
|
-
|
|
21
|
-
### Step 3.1: Inspect Artifacts
|
|
22
|
-
|
|
23
|
-
```javascript
|
|
24
|
-
const stepIdx = currentStepIndex;
|
|
25
|
-
const step = state.steps[stepIdx];
|
|
26
|
-
const stepDir = `${state.work_dir}/steps/step-${stepIdx + 1}`;
|
|
27
|
-
|
|
28
|
-
// Read artifacts manifest
|
|
29
|
-
const manifest = JSON.parse(Read(`${stepDir}/artifacts-manifest.json`));
|
|
30
|
-
|
|
31
|
-
// Build artifact summary based on analysis depth
|
|
32
|
-
let artifactSummary = '';
|
|
33
|
-
|
|
34
|
-
if (state.analysis_depth === 'quick') {
|
|
35
|
-
// Quick: just file list and sizes
|
|
36
|
-
artifactSummary = `Artifacts (${manifest.artifacts.length} files):\n` +
|
|
37
|
-
manifest.artifacts.map(a => `- ${a.path} (${a.type})`).join('\n');
|
|
38
|
-
} else {
|
|
39
|
-
// Standard/Deep: include file content summaries
|
|
40
|
-
artifactSummary = manifest.artifacts.map(a => {
|
|
41
|
-
const maxLines = state.analysis_depth === 'deep' ? 300 : 150;
|
|
42
|
-
try {
|
|
43
|
-
const content = Read(a.path, { limit: maxLines });
|
|
44
|
-
return `--- ${a.path} (${a.type}) ---\n${content}`;
|
|
45
|
-
} catch {
|
|
46
|
-
return `--- ${a.path} --- [unreadable]`;
|
|
47
|
-
}
|
|
48
|
-
}).join('\n\n');
|
|
49
|
-
|
|
50
|
-
// Deep: also include scratchpad files
|
|
51
|
-
if (state.analysis_depth === 'deep' && manifest.scratchpad_files?.length > 0) {
|
|
52
|
-
artifactSummary += '\n\n--- Scratchpad Files ---\n' +
|
|
53
|
-
manifest.scratchpad_files.slice(0, 5).map(f => {
|
|
54
|
-
const content = Read(f, { limit: 100 });
|
|
55
|
-
return `--- ${f} ---\n${content}`;
|
|
56
|
-
}).join('\n\n');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Execution result summary
|
|
61
|
-
const execSummary = `Execution: ${step.execution.method} | ` +
|
|
62
|
-
`Success: ${step.execution.success} | ` +
|
|
63
|
-
`Duration: ${step.execution.duration_ms}ms | ` +
|
|
64
|
-
`Artifacts: ${manifest.artifacts.length} files`;
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Step 3.2: Build Prior Context
|
|
68
|
-
|
|
69
|
-
```javascript
|
|
70
|
-
// Build accumulated process log context for this analysis
|
|
71
|
-
const priorProcessLog = Read(`${state.work_dir}/process-log.md`);
|
|
72
|
-
|
|
73
|
-
// Build step chain context (what came before, what comes after)
|
|
74
|
-
const stepChainContext = state.steps.map((s, i) => {
|
|
75
|
-
const status = i < stepIdx ? 'completed' : i === stepIdx ? 'CURRENT' : 'pending';
|
|
76
|
-
const score = s.analysis?.quality_score || '-';
|
|
77
|
-
return `${i + 1}. [${status}] ${s.name} (${s.type}) — Quality: ${score}`;
|
|
78
|
-
}).join('\n');
|
|
79
|
-
|
|
80
|
-
// Previous step handoff context (if not first step)
|
|
81
|
-
let handoffContext = '';
|
|
82
|
-
if (stepIdx > 0) {
|
|
83
|
-
const prevStep = state.steps[stepIdx - 1];
|
|
84
|
-
const prevAnalysis = prevStep.analysis;
|
|
85
|
-
if (prevAnalysis) {
|
|
86
|
-
handoffContext = `PREVIOUS STEP OUTPUT SUMMARY:
|
|
87
|
-
Step "${prevStep.name}" produced ${prevStep.execution?.artifact_count || 0} artifacts.
|
|
88
|
-
Quality: ${prevAnalysis.quality_score}/100
|
|
89
|
-
Key outputs: ${prevAnalysis.key_outputs?.join(', ') || 'unknown'}
|
|
90
|
-
Handoff notes: ${prevAnalysis.handoff_notes || 'none'}`;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Step 3.3: Construct Analysis Prompt
|
|
96
|
-
|
|
97
|
-
```javascript
|
|
98
|
-
// Ref: templates/step-analysis-prompt.md
|
|
99
|
-
|
|
100
|
-
const depthInstructions = {
|
|
101
|
-
quick: 'Provide brief assessment (3-5 bullet points). Focus on: execution success, output completeness, obvious issues.',
|
|
102
|
-
standard: 'Provide detailed assessment. Cover: execution quality, output completeness, artifact quality, step-to-step handoff readiness, potential issues.',
|
|
103
|
-
deep: 'Provide exhaustive assessment. Cover: execution quality, output completeness and correctness, artifact quality and structure, step-to-step handoff integrity, error handling, performance signals, architecture implications, edge cases.'
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// ★ Build test requirements section (the evaluation baseline)
|
|
107
|
-
const testReqs = step.test_requirements;
|
|
108
|
-
let testReqSection = '';
|
|
109
|
-
if (testReqs) {
|
|
110
|
-
testReqSection = `
|
|
111
|
-
TEST REQUIREMENTS (Acceptance Criteria — use these as the PRIMARY evaluation baseline):
|
|
112
|
-
Pass Criteria: ${testReqs.pass_criteria}
|
|
113
|
-
Expected Outputs: ${(testReqs.expected_outputs || []).join(', ') || 'not specified'}
|
|
114
|
-
Content Signals (patterns that indicate success): ${(testReqs.content_signals || []).join(', ') || 'not specified'}
|
|
115
|
-
Quality Thresholds: ${(testReqs.quality_thresholds || []).join(', ') || 'not specified'}
|
|
116
|
-
Fail Signals (patterns that indicate failure): ${(testReqs.fail_signals || []).join(', ') || 'not specified'}
|
|
117
|
-
Handoff Contract (what next step needs): ${testReqs.handoff_contract || 'not specified'}
|
|
118
|
-
|
|
119
|
-
IMPORTANT: Score quality_score based on how well the actual output matches these test requirements.
|
|
120
|
-
- 90-100: All pass_criteria met, all expected_outputs present, content_signals found, no fail_signals
|
|
121
|
-
- 70-89: Most criteria met, minor gaps
|
|
122
|
-
- 50-69: Partial match, significant gaps
|
|
123
|
-
- 0-49: Fail — fail_signals present or pass_criteria not met`;
|
|
124
|
-
} else {
|
|
125
|
-
testReqSection = `
|
|
126
|
-
NOTE: No pre-generated test requirements for this step. Evaluate based on general quality signals and workflow context.`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const analysisPrompt = `PURPOSE: Evaluate workflow step "${step.name}" (step ${stepIdx + 1}/${state.steps.length}) against its acceptance criteria. Judge whether the command execution met the pre-defined test requirements.
|
|
130
|
-
|
|
131
|
-
WORKFLOW CONTEXT:
|
|
132
|
-
Name: ${state.workflow_name}
|
|
133
|
-
Goal: ${state.workflow_context}
|
|
134
|
-
Step Chain:
|
|
135
|
-
${stepChainContext}
|
|
136
|
-
|
|
137
|
-
CURRENT STEP:
|
|
138
|
-
Name: ${step.name}
|
|
139
|
-
Type: ${step.type}
|
|
140
|
-
Command: ${step.command}
|
|
141
|
-
${step.success_criteria ? `Success Criteria: ${step.success_criteria}` : ''}
|
|
142
|
-
${testReqSection}
|
|
143
|
-
|
|
144
|
-
EXECUTION RESULT:
|
|
145
|
-
${execSummary}
|
|
146
|
-
|
|
147
|
-
${handoffContext}
|
|
148
|
-
|
|
149
|
-
STEP ARTIFACTS:
|
|
150
|
-
${artifactSummary}
|
|
151
|
-
|
|
152
|
-
ANALYSIS DEPTH: ${state.analysis_depth}
|
|
153
|
-
${depthInstructions[state.analysis_depth]}
|
|
154
|
-
|
|
155
|
-
TASK:
|
|
156
|
-
1. **Requirement Matching**: Compare actual output against test requirements (pass_criteria, expected_outputs, content_signals)
|
|
157
|
-
2. **Fail Signal Detection**: Check for any fail_signals in the output
|
|
158
|
-
3. **Handoff Contract Verification**: Does the output satisfy handoff_contract for the next step?
|
|
159
|
-
4. **Gap Analysis**: What's missing between actual output and requirements?
|
|
160
|
-
5. **Quality Score**: Rate 0-100 based on requirement fulfillment (NOT general quality)
|
|
161
|
-
|
|
162
|
-
EXPECTED OUTPUT (strict JSON, no markdown):
|
|
163
|
-
{
|
|
164
|
-
"quality_score": <0-100>,
|
|
165
|
-
"requirement_match": {
|
|
166
|
-
"pass": <true|false>,
|
|
167
|
-
"criteria_met": ["<which pass_criteria were satisfied>"],
|
|
168
|
-
"criteria_missed": ["<which pass_criteria were NOT satisfied>"],
|
|
169
|
-
"expected_outputs_found": ["<expected files that exist>"],
|
|
170
|
-
"expected_outputs_missing": ["<expected files that are absent>"],
|
|
171
|
-
"content_signals_found": ["<success patterns detected in output>"],
|
|
172
|
-
"content_signals_missing": ["<success patterns NOT found>"],
|
|
173
|
-
"fail_signals_detected": ["<failure patterns found, if any>"]
|
|
174
|
-
},
|
|
175
|
-
"execution_assessment": {
|
|
176
|
-
"success": <true|false>,
|
|
177
|
-
"completeness": "<complete|partial|failed>",
|
|
178
|
-
"notes": "<brief assessment>"
|
|
179
|
-
},
|
|
180
|
-
"artifact_assessment": {
|
|
181
|
-
"count": <number>,
|
|
182
|
-
"quality": "<high|medium|low>",
|
|
183
|
-
"key_outputs": ["<main output 1>", "<main output 2>"],
|
|
184
|
-
"missing_outputs": ["<expected but missing>"]
|
|
185
|
-
},
|
|
186
|
-
"handoff_assessment": {
|
|
187
|
-
"ready": <true|false>,
|
|
188
|
-
"contract_satisfied": <true|false|null>,
|
|
189
|
-
"next_step_compatible": <true|false|null>,
|
|
190
|
-
"handoff_notes": "<what next step should know>"
|
|
191
|
-
},
|
|
192
|
-
"issues": [
|
|
193
|
-
{ "severity": "high|medium|low", "description": "<issue>", "suggestion": "<fix>" }
|
|
194
|
-
],
|
|
195
|
-
"optimization_opportunities": [
|
|
196
|
-
{ "area": "<area>", "description": "<opportunity>", "impact": "high|medium|low" }
|
|
197
|
-
],
|
|
198
|
-
"step_summary": "<1-2 sentence summary for process log>"
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
CONSTRAINTS: Be specific, reference artifact content where possible, score against requirements not general quality, output ONLY JSON`;
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
### Step 3.4: Execute via ccw cli Gemini with Resume
|
|
205
|
-
|
|
206
|
-
```javascript
|
|
207
|
-
function escapeForShell(str) {
|
|
208
|
-
return str.replace(/"/g, '\\"').replace(/\$/g, '\\$').replace(/`/g, '\\`');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Build CLI command with optional resume
|
|
212
|
-
let cliCommand = `ccw cli -p "${escapeForShell(analysisPrompt)}" --tool gemini --mode analysis`;
|
|
213
|
-
|
|
214
|
-
// Resume from previous step's analysis session (maintains context chain)
|
|
215
|
-
if (state.analysis_session_id) {
|
|
216
|
-
cliCommand += ` --resume ${state.analysis_session_id}`;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
Bash({
|
|
220
|
-
command: cliCommand,
|
|
221
|
-
run_in_background: true,
|
|
222
|
-
timeout: 300000 // 5 minutes
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
// STOP — wait for hook callback
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### Step 3.5: Parse Results and Update Process Log
|
|
229
|
-
|
|
230
|
-
After CLI completes:
|
|
231
|
-
|
|
232
|
-
```javascript
|
|
233
|
-
const rawOutput = /* CLI output from callback */;
|
|
234
|
-
|
|
235
|
-
// Extract session ID from CLI output for resume chain
|
|
236
|
-
const sessionIdMatch = rawOutput.match(/\[CCW_EXEC_ID=([^\]]+)\]/);
|
|
237
|
-
if (sessionIdMatch) {
|
|
238
|
-
state.analysis_session_id = sessionIdMatch[1];
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Parse JSON
|
|
242
|
-
const jsonMatch = rawOutput.match(/\{[\s\S]*\}/);
|
|
243
|
-
let analysis;
|
|
244
|
-
|
|
245
|
-
if (jsonMatch) {
|
|
246
|
-
try {
|
|
247
|
-
analysis = JSON.parse(jsonMatch[0]);
|
|
248
|
-
} catch (e) {
|
|
249
|
-
// Fallback: extract score heuristically
|
|
250
|
-
const scoreMatch = rawOutput.match(/"quality_score"\s*:\s*(\d+)/);
|
|
251
|
-
analysis = {
|
|
252
|
-
quality_score: scoreMatch ? parseInt(scoreMatch[1]) : 50,
|
|
253
|
-
execution_assessment: { success: step.execution.success, completeness: 'unknown', notes: 'Parse failed' },
|
|
254
|
-
artifact_assessment: { count: manifest.artifacts.length, quality: 'unknown', key_outputs: [], missing_outputs: [] },
|
|
255
|
-
handoff_assessment: { ready: true, next_step_compatible: null, handoff_notes: '' },
|
|
256
|
-
issues: [{ severity: 'low', description: 'Analysis output parsing failed', suggestion: 'Review raw output' }],
|
|
257
|
-
optimization_opportunities: [],
|
|
258
|
-
step_summary: 'Analysis parsing failed — raw output saved for manual review'
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
} else {
|
|
262
|
-
analysis = {
|
|
263
|
-
quality_score: 50,
|
|
264
|
-
step_summary: 'No structured analysis output received'
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Write step analysis file
|
|
269
|
-
const reqMatch = analysis.requirement_match;
|
|
270
|
-
const reqMatchSection = reqMatch ? `
|
|
271
|
-
## Requirement Match — ${reqMatch.pass ? 'PASS ✓' : 'FAIL ✗'}
|
|
272
|
-
|
|
273
|
-
### Criteria Met
|
|
274
|
-
${(reqMatch.criteria_met || []).map(c => `- ✓ ${c}`).join('\n') || '- None'}
|
|
275
|
-
|
|
276
|
-
### Criteria Missed
|
|
277
|
-
${(reqMatch.criteria_missed || []).map(c => `- ✗ ${c}`).join('\n') || '- None'}
|
|
278
|
-
|
|
279
|
-
### Expected Outputs
|
|
280
|
-
- Found: ${(reqMatch.expected_outputs_found || []).join(', ') || 'None'}
|
|
281
|
-
- Missing: ${(reqMatch.expected_outputs_missing || []).join(', ') || 'None'}
|
|
282
|
-
|
|
283
|
-
### Content Signals
|
|
284
|
-
- Detected: ${(reqMatch.content_signals_found || []).join(', ') || 'None'}
|
|
285
|
-
- Missing: ${(reqMatch.content_signals_missing || []).join(', ') || 'None'}
|
|
286
|
-
|
|
287
|
-
### Fail Signals
|
|
288
|
-
${(reqMatch.fail_signals_detected || []).length > 0
|
|
289
|
-
? (reqMatch.fail_signals_detected || []).map(f => `- ⚠ ${f}`).join('\n')
|
|
290
|
-
: '- None detected'}
|
|
291
|
-
` : '';
|
|
292
|
-
|
|
293
|
-
const stepAnalysisReport = `# Step ${stepIdx + 1} Analysis: ${step.name}
|
|
294
|
-
|
|
295
|
-
**Quality Score**: ${analysis.quality_score}/100
|
|
296
|
-
**Requirement Match**: ${reqMatch ? (reqMatch.pass ? 'PASS' : 'FAIL') : 'N/A (no test requirements)'}
|
|
297
|
-
**Date**: ${new Date().toISOString()}
|
|
298
|
-
${reqMatchSection}
|
|
299
|
-
## Execution
|
|
300
|
-
- Success: ${analysis.execution_assessment?.success}
|
|
301
|
-
- Completeness: ${analysis.execution_assessment?.completeness}
|
|
302
|
-
- Notes: ${analysis.execution_assessment?.notes}
|
|
303
|
-
|
|
304
|
-
## Artifacts
|
|
305
|
-
- Count: ${analysis.artifact_assessment?.count}
|
|
306
|
-
- Quality: ${analysis.artifact_assessment?.quality}
|
|
307
|
-
- Key Outputs: ${analysis.artifact_assessment?.key_outputs?.join(', ') || 'N/A'}
|
|
308
|
-
- Missing: ${analysis.artifact_assessment?.missing_outputs?.join(', ') || 'None'}
|
|
309
|
-
|
|
310
|
-
## Handoff Readiness
|
|
311
|
-
- Ready: ${analysis.handoff_assessment?.ready}
|
|
312
|
-
- Contract Satisfied: ${analysis.handoff_assessment?.contract_satisfied}
|
|
313
|
-
- Next Step Compatible: ${analysis.handoff_assessment?.next_step_compatible}
|
|
314
|
-
- Notes: ${analysis.handoff_assessment?.handoff_notes}
|
|
315
|
-
|
|
316
|
-
## Issues
|
|
317
|
-
${(analysis.issues || []).map(i => `- [${i.severity}] ${i.description} → ${i.suggestion}`).join('\n') || 'None'}
|
|
318
|
-
|
|
319
|
-
## Optimization Opportunities
|
|
320
|
-
${(analysis.optimization_opportunities || []).map(o => `- [${o.impact}] ${o.area}: ${o.description}`).join('\n') || 'None'}
|
|
321
|
-
`;
|
|
322
|
-
|
|
323
|
-
Write(`${stepDir}/step-${stepIdx + 1}-analysis.md`, stepAnalysisReport);
|
|
324
|
-
|
|
325
|
-
// Append to process log
|
|
326
|
-
const reqPassStr = reqMatch ? (reqMatch.pass ? 'PASS' : 'FAIL') : 'N/A';
|
|
327
|
-
const processLogEntry = `
|
|
328
|
-
## Step ${stepIdx + 1}: ${step.name} — Score: ${analysis.quality_score}/100 | Req: ${reqPassStr}
|
|
329
|
-
|
|
330
|
-
**Command**: \`${step.command}\`
|
|
331
|
-
**Result**: ${analysis.execution_assessment?.completeness || 'unknown'} | ${analysis.artifact_assessment?.count || 0} artifacts
|
|
332
|
-
**Requirement Match**: ${reqPassStr}${reqMatch ? ` — Met: ${(reqMatch.criteria_met || []).length}, Missed: ${(reqMatch.criteria_missed || []).length}, Fail Signals: ${(reqMatch.fail_signals_detected || []).length}` : ''}
|
|
333
|
-
**Summary**: ${analysis.step_summary || 'No summary'}
|
|
334
|
-
**Issues**: ${(analysis.issues || []).filter(i => i.severity === 'high').map(i => i.description).join('; ') || 'None critical'}
|
|
335
|
-
**Handoff**: ${analysis.handoff_assessment?.contract_satisfied ? 'Contract satisfied' : analysis.handoff_assessment?.handoff_notes || 'Ready'}
|
|
336
|
-
|
|
337
|
-
---
|
|
338
|
-
`;
|
|
339
|
-
|
|
340
|
-
// Append to process-log.md
|
|
341
|
-
const currentLog = Read(`${state.work_dir}/process-log.md`);
|
|
342
|
-
Write(`${state.work_dir}/process-log.md`, currentLog + processLogEntry);
|
|
343
|
-
|
|
344
|
-
// Update state
|
|
345
|
-
state.steps[stepIdx].analysis = {
|
|
346
|
-
quality_score: analysis.quality_score,
|
|
347
|
-
requirement_pass: reqMatch?.pass ?? null,
|
|
348
|
-
criteria_met_count: (reqMatch?.criteria_met || []).length,
|
|
349
|
-
criteria_missed_count: (reqMatch?.criteria_missed || []).length,
|
|
350
|
-
fail_signals_count: (reqMatch?.fail_signals_detected || []).length,
|
|
351
|
-
key_outputs: analysis.artifact_assessment?.key_outputs || [],
|
|
352
|
-
handoff_notes: analysis.handoff_assessment?.handoff_notes || '',
|
|
353
|
-
contract_satisfied: analysis.handoff_assessment?.contract_satisfied ?? null,
|
|
354
|
-
issue_count: (analysis.issues || []).length,
|
|
355
|
-
high_issues: (analysis.issues || []).filter(i => i.severity === 'high').length,
|
|
356
|
-
optimization_count: (analysis.optimization_opportunities || []).length,
|
|
357
|
-
analysis_file: `${stepDir}/step-${stepIdx + 1}-analysis.md`
|
|
358
|
-
};
|
|
359
|
-
state.steps[stepIdx].status = 'analyzed';
|
|
360
|
-
|
|
361
|
-
state.process_log_entries.push({
|
|
362
|
-
step_index: stepIdx,
|
|
363
|
-
step_name: step.name,
|
|
364
|
-
quality_score: analysis.quality_score,
|
|
365
|
-
summary: analysis.step_summary,
|
|
366
|
-
timestamp: new Date().toISOString()
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
state.updated_at = new Date().toISOString();
|
|
370
|
-
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
## Error Handling
|
|
374
|
-
|
|
375
|
-
| Error | Recovery |
|
|
376
|
-
|-------|----------|
|
|
377
|
-
| CLI timeout | Retry once without --resume (fresh session) |
|
|
378
|
-
| Resume session not found | Start fresh analysis session, continue |
|
|
379
|
-
| JSON parse fails | Extract score heuristically, save raw output |
|
|
380
|
-
| No output | Default score 50, minimal process log entry |
|
|
381
|
-
|
|
382
|
-
## Output
|
|
383
|
-
|
|
384
|
-
- **Files**: `step-{N}-analysis.md`, updated `process-log.md`
|
|
385
|
-
- **State**: `steps[stepIdx].analysis` updated, `analysis_session_id` updated
|
|
386
|
-
- **Next**: Phase 2 for next step, or Phase 4 (Synthesize) if all steps done
|