mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
feat: Enhance role functionality and task management across coordinator, explorer, implementer, planner, reviewer, and workflow phases
This commit is contained in:
@@ -101,7 +101,8 @@ function detectMode(issueIds, userMode) {
|
|||||||
const hasHighPriority = issues.some(i => i.priority >= 4)
|
const hasHighPriority = issues.some(i => i.priority >= 4)
|
||||||
return hasHighPriority ? 'full' : 'quick'
|
return hasHighPriority ? 'full' : 'quick'
|
||||||
}
|
}
|
||||||
return count <= 5 ? 'full' : 'batch'
|
// 3-4 issues with review, 5+ triggers batch parallel processing
|
||||||
|
return count >= 5 ? 'batch' : 'full'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -228,19 +229,25 @@ for (const issueId of issueIds) {
|
|||||||
const exploreBatches = chunkArray(issueIds, 5) // max 5 parallel
|
const exploreBatches = chunkArray(issueIds, 5) // max 5 parallel
|
||||||
const solveBatches = chunkArray(issueIds, 3) // max 3 parallel
|
const solveBatches = chunkArray(issueIds, 3) // max 3 parallel
|
||||||
|
|
||||||
// Create EXPLORE tasks (parallel within batch)
|
// Create EXPLORE tasks — all parallel within each batch, batches run in rolling window
|
||||||
|
// Each batch of ≤5 runs concurrently; next batch starts when current batch completes
|
||||||
const exploreTaskIds = []
|
const exploreTaskIds = []
|
||||||
|
let prevBatchLastId = null
|
||||||
for (const [batchIdx, batch] of exploreBatches.entries()) {
|
for (const [batchIdx, batch] of exploreBatches.entries()) {
|
||||||
|
const batchTaskIds = []
|
||||||
for (const issueId of batch) {
|
for (const issueId of batch) {
|
||||||
const id = TaskCreate({
|
const id = TaskCreate({
|
||||||
subject: `EXPLORE-${String(exploreTaskIds.length + 1).padStart(3, '0')}: Context for ${issueId}`,
|
subject: `EXPLORE-${String(exploreTaskIds.length + 1).padStart(3, '0')}: Context for ${issueId}`,
|
||||||
description: `Batch ${batchIdx + 1}: Explore codebase context for issue ${issueId}.`,
|
description: `Batch ${batchIdx + 1}: Explore codebase context for issue ${issueId}.`,
|
||||||
activeForm: `Exploring ${issueId}`,
|
activeForm: `Exploring ${issueId}`,
|
||||||
owner: "explorer",
|
owner: "explorer",
|
||||||
addBlockedBy: batchIdx > 0 ? [exploreTaskIds[exploreTaskIds.length - 1]] : []
|
// Only block on previous batch's LAST task (not within same batch)
|
||||||
|
addBlockedBy: prevBatchLastId ? [prevBatchLastId] : []
|
||||||
})
|
})
|
||||||
|
batchTaskIds.push(id)
|
||||||
exploreTaskIds.push(id)
|
exploreTaskIds.push(id)
|
||||||
}
|
}
|
||||||
|
prevBatchLastId = batchTaskIds[batchTaskIds.length - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create SOLVE tasks (blocked by corresponding EXPLORE)
|
// Create SOLVE tasks (blocked by corresponding EXPLORE)
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
|||||||
### Phase 2: Issue Loading & Context Setup
|
### Phase 2: Issue Loading & Context Setup
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
// Resolve project root from working directory
|
||||||
|
const projectRoot = Bash('pwd').trim()
|
||||||
|
|
||||||
// Extract issue ID from task description
|
// Extract issue ID from task description
|
||||||
const issueIdMatch = task.description.match(/(?:GH-\d+|ISS-\d{8}-\d{6})/)
|
const issueIdMatch = task.description.match(/(?:GH-\d+|ISS-\d{8}-\d{6})/)
|
||||||
const issueId = issueIdMatch ? issueIdMatch[0] : null
|
const issueId = issueIdMatch ? issueIdMatch[0] : null
|
||||||
|
|||||||
@@ -185,8 +185,20 @@ Dependencies: ${explorerContext.dependencies?.join(', ') || 'N/A'}
|
|||||||
### Phase 4: Verify & Commit
|
### Phase 4: Verify & Commit
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
// Detect test command from package.json or project config
|
||||||
|
let testCmd = 'npm test'
|
||||||
|
try {
|
||||||
|
const pkgJson = JSON.parse(Read('package.json'))
|
||||||
|
if (pkgJson.scripts?.test) testCmd = 'npm test'
|
||||||
|
else if (pkgJson.scripts?.['test:unit']) testCmd = 'npm run test:unit'
|
||||||
|
} catch {
|
||||||
|
// Fallback: try common test runners
|
||||||
|
const hasYarn = Bash('test -f yarn.lock && echo yes || echo no').trim() === 'yes'
|
||||||
|
if (hasYarn) testCmd = 'yarn test'
|
||||||
|
}
|
||||||
|
|
||||||
// Verify implementation
|
// Verify implementation
|
||||||
const testResult = Bash(`npm test 2>&1 || echo "TEST_FAILED"`)
|
const testResult = Bash(`${testCmd} 2>&1 || echo "TEST_FAILED"`)
|
||||||
const testPassed = !testResult.includes('TEST_FAILED') && !testResult.includes('FAIL')
|
const testPassed = !testResult.includes('TEST_FAILED') && !testResult.includes('FAIL')
|
||||||
|
|
||||||
if (!testPassed) {
|
if (!testPassed) {
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
|||||||
### Phase 2: Context Loading
|
### Phase 2: Context Loading
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
// Resolve project root from working directory
|
||||||
|
const projectRoot = Bash('pwd').trim()
|
||||||
|
|
||||||
// Extract issue ID
|
// Extract issue ID
|
||||||
const issueIdMatch = task.description.match(/(?:GH-\d+|ISS-\d{8}-\d{6})/)
|
const issueIdMatch = task.description.match(/(?:GH-\d+|ISS-\d{8}-\d{6})/)
|
||||||
const issueId = issueIdMatch ? issueIdMatch[0] : null
|
const issueId = issueIdMatch ? issueIdMatch[0] : null
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ for (const issueId of issueIds) {
|
|||||||
completeness: { score: 0, findings: [] }
|
completeness: { score: 0, findings: [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Technical Feasibility — verify solution references real files
|
// 1. Technical Feasibility — verify solution references real files + semantic validation
|
||||||
if (context && context.relevant_files) {
|
if (context && context.relevant_files) {
|
||||||
const solutionFiles = solution.bound.tasks?.flatMap(t => t.files || []) || []
|
const solutionFiles = solution.bound.tasks?.flatMap(t => t.files || []) || []
|
||||||
const contextFiles = context.relevant_files.map(f => f.path || f)
|
const contextFiles = context.relevant_files.map(f => f.path || f)
|
||||||
@@ -177,6 +177,24 @@ for (const issueId of issueIds) {
|
|||||||
`Uncovered files: ${uncovered.join(', ')}`
|
`Uncovered files: ${uncovered.join(', ')}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Semantic validation via ACE — verify solution references exist in codebase
|
||||||
|
const projectRoot = Bash('pwd').trim()
|
||||||
|
const aceResults = mcp__ace-tool__search_context({
|
||||||
|
project_root_path: projectRoot,
|
||||||
|
query: `${solution.bound.title || issue.title}. Verify patterns: ${solutionFiles.slice(0, 5).join(', ')}`
|
||||||
|
})
|
||||||
|
if (aceResults && aceResults.length > 0) {
|
||||||
|
// Cross-check ACE results against solution's assumed patterns
|
||||||
|
const aceFiles = aceResults.map(r => r.file || r.path).filter(Boolean)
|
||||||
|
const missedByAce = solutionFiles.filter(sf => !aceFiles.some(af => af.includes(sf)))
|
||||||
|
if (missedByAce.length > solutionFiles.length * 0.5) {
|
||||||
|
review.technical_feasibility.score = Math.max(50, review.technical_feasibility.score - 10)
|
||||||
|
review.technical_feasibility.findings.push(
|
||||||
|
`ACE semantic search found divergent patterns — solution may reference outdated code`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
review.technical_feasibility.score = 70 // No context to validate against
|
review.technical_feasibility.score = 70 // No context to validate against
|
||||||
review.technical_feasibility.findings.push('Explorer context not available for cross-validation')
|
review.technical_feasibility.findings.push('Explorer context not available for cross-validation')
|
||||||
|
|||||||
@@ -468,7 +468,12 @@ if (userChoice.answers["Next Action"] === "Verify Plan Quality (Recommended)") {
|
|||||||
Skill(skill="workflow-execute", args="--session " + sessionId);
|
Skill(skill="workflow-execute", args="--session " + sessionId);
|
||||||
} else if (userChoice.answers["Next Action"] === "Review Status Only") {
|
} else if (userChoice.answers["Next Action"] === "Review Status Only") {
|
||||||
console.log("\nDisplaying session status...\n");
|
console.log("\nDisplaying session status...\n");
|
||||||
Skill(skill="workflow:status", args="--session " + sessionId);
|
// Display session status inline
|
||||||
|
const sessionMeta = JSON.parse(Read(`.workflow/active/${sessionId}/workflow-session.json`));
|
||||||
|
const todoList = Read(`.workflow/active/${sessionId}/TODO_LIST.md`);
|
||||||
|
console.log(`Session: ${sessionId}`);
|
||||||
|
console.log(`Status: ${sessionMeta.status}`);
|
||||||
|
console.log(`\n--- TODO List ---\n${todoList}`);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -477,7 +482,7 @@ if (userChoice.answers["Next Action"] === "Verify Plan Quality (Recommended)") {
|
|||||||
**Return to Orchestrator**: Based on user's choice:
|
**Return to Orchestrator**: Based on user's choice:
|
||||||
- **Verify** -> Orchestrator reads phases/05-plan-verify.md and executes Phase 5 in-process
|
- **Verify** -> Orchestrator reads phases/05-plan-verify.md and executes Phase 5 in-process
|
||||||
- **Execute** -> Skill(skill="workflow-execute")
|
- **Execute** -> Skill(skill="workflow-execute")
|
||||||
- **Review** -> Route to /workflow:status
|
- **Review** -> Display session status inline
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
|
||||||
@@ -492,4 +497,4 @@ if (userChoice.answers["Next Action"] === "Verify Plan Quality (Recommended)") {
|
|||||||
Based on user's plan confirmation choice:
|
Based on user's plan confirmation choice:
|
||||||
- If "Verify" -> [Phase 5: Plan Verification](05-plan-verify.md)
|
- If "Verify" -> [Phase 5: Plan Verification](05-plan-verify.md)
|
||||||
- If "Execute" -> Skill(skill="workflow-execute")
|
- If "Execute" -> Skill(skill="workflow-execute")
|
||||||
- If "Review" -> External: /workflow:status
|
- If "Review" -> Display session status inline
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ const userConfig = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Auto Mode**: When `--yes` or `-y`: Skip user questions, use defaults (no materials, Agent executor).
|
**Auto Mode**: When `workflowPreferences.autoYes` is true, skip user questions, use defaults (no materials, Agent executor).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,12 @@ if (userChoice === "Verify TDD Compliance (Recommended)") {
|
|||||||
} else if (userChoice === "Start Execution") {
|
} else if (userChoice === "Start Execution") {
|
||||||
Skill(skill="workflow-execute", args="--session " + sessionId);
|
Skill(skill="workflow-execute", args="--session " + sessionId);
|
||||||
} else if (userChoice === "Review Status Only") {
|
} else if (userChoice === "Review Status Only") {
|
||||||
Skill(skill="workflow:status", args="--session " + sessionId);
|
// Display session status inline
|
||||||
|
const sessionMeta = JSON.parse(Read(`.workflow/active/${sessionId}/workflow-session.json`));
|
||||||
|
const todoList = Read(`.workflow/active/${sessionId}/TODO_LIST.md`);
|
||||||
|
console.log(`\nSession: ${sessionId}`);
|
||||||
|
console.log(`Status: ${sessionMeta.status}`);
|
||||||
|
console.log(`\n--- TODO List ---\n${todoList}`);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -176,4 +181,4 @@ if (userChoice === "Verify TDD Compliance (Recommended)") {
|
|||||||
Based on user's plan confirmation choice:
|
Based on user's plan confirmation choice:
|
||||||
- If "Verify" → [Phase 7: TDD Verification](07-tdd-verify.md)
|
- If "Verify" → [Phase 7: TDD Verification](07-tdd-verify.md)
|
||||||
- If "Execute" → Skill(skill="workflow-execute")
|
- If "Execute" → Skill(skill="workflow-execute")
|
||||||
- If "Review" → External: /workflow:status
|
- If "Review" -> Display session status inline
|
||||||
|
|||||||
@@ -54,20 +54,14 @@ Task Pipeline (generated in Phase 4, executed in Phase 5):
|
|||||||
5. **Progressive Phase Loading**: Phase docs read **only** when that phase executes, not upfront
|
5. **Progressive Phase Loading**: Phase docs read **only** when that phase executes, not upfront
|
||||||
6. **Adaptive Strategy**: Fix loop auto-selects strategy (conservative/aggressive/surgical) based on iteration context
|
6. **Adaptive Strategy**: Fix loop auto-selects strategy (conservative/aggressive/surgical) based on iteration context
|
||||||
7. **Quality Gate**: Pass rate >= 95% (criticality-aware) terminates the fix loop
|
7. **Quality Gate**: Pass rate >= 95% (criticality-aware) terminates the fix loop
|
||||||
8. **Original Commands Preserved**: Phase files preserve full original command content and Skill() calls
|
8. **Phase File Hygiene**: Phase files reference `workflowPreferences.*` for preferences, no CLI flag parsing
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
Full pipeline and execute-only modes are triggered by skill name routing (see Mode Detection). Workflow preferences (auto mode) are collected interactively via AskUserQuestion before dispatching to phases.
|
||||||
# Full pipeline: generate + execute
|
|
||||||
/workflow:test-fix-gen "Test the user authentication API"
|
|
||||||
/workflow:test-fix-gen WFS-user-auth-v2
|
|
||||||
|
|
||||||
# Execute only (resume from existing test session with generated tasks)
|
**Full pipeline** (workflow:test-fix-gen): Task description or session ID as arguments → interactive preference collection → generate + execute pipeline
|
||||||
/workflow:test-cycle-execute
|
**Execute only** (workflow:test-cycle-execute): Auto-discovers active session → interactive preference collection → execution loop
|
||||||
/workflow:test-cycle-execute --resume-session="WFS-test-user-auth"
|
|
||||||
/workflow:test-cycle-execute --max-iterations=15
|
|
||||||
```
|
|
||||||
|
|
||||||
## Interactive Preference Collection
|
## Interactive Preference Collection
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user