mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
feat: Enhance parallel-dev-cycle with prep-package integration
- Added argument parsing and prep package loading in session initialization. - Implemented validation checks for prep-package.json integrity. - Integrated prep package data into cycle state, including task refinement and auto-iteration settings. - Updated agent execution to utilize source references and focus directives from prep package. - Modified context gathering and test context generation to reference active workflow paths. - Introduced a new interactive prompt for pre-flight checklist and task quality assessment. - Created a detailed schema and integration specification for prep-package.json. - Ensured all relevant phases validate and utilize the prep package effectively.
This commit is contained in:
@@ -74,6 +74,15 @@ Each agent **maintains one main document** (e.g., requirements.md, plan.json, im
|
||||
|
||||
When `--auto`: Run all phases sequentially without user confirmation between iterations. Use recommended defaults for all decisions. Automatically continue iteration loop until tests pass or max iterations reached.
|
||||
|
||||
## Prep Package Integration
|
||||
|
||||
When `prep-package.json` exists at `{projectRoot}/.workflow/.cycle/prep-package.json`, Phase 1 consumes it to:
|
||||
- Use refined task description instead of raw TASK
|
||||
- Apply auto-iteration config (convergence criteria, phase gates)
|
||||
- Inject per-iteration agent focus directives (0→1 vs 1→100)
|
||||
|
||||
Prep packages are generated by the interactive prompt `/prompts:prep-cycle`. See [phases/00-prep-checklist.md](phases/00-prep-checklist.md) for schema.
|
||||
|
||||
## Execution Flow
|
||||
|
||||
```
|
||||
|
||||
191
.codex/skills/parallel-dev-cycle/phases/00-prep-checklist.md
Normal file
191
.codex/skills/parallel-dev-cycle/phases/00-prep-checklist.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# Prep Package Schema & Integration Spec
|
||||
|
||||
Schema definition for `prep-package.json` and integration points with the parallel-dev-cycle skill.
|
||||
|
||||
## File Location
|
||||
|
||||
```
|
||||
{projectRoot}/.workflow/.cycle/prep-package.json
|
||||
```
|
||||
|
||||
Generated by: `/prompts:prep-cycle` (interactive prompt)
|
||||
Consumed by: Phase 1 (Session Initialization)
|
||||
|
||||
## JSON Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"generated_at": "ISO8601",
|
||||
"prep_status": "ready | needs_refinement | blocked",
|
||||
|
||||
"environment": {
|
||||
"project_root": "/path/to/project",
|
||||
"prerequisites": {
|
||||
"required_passed": true,
|
||||
"recommended_passed": true,
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"tech_stack": "string (e.g. Express.js + TypeORM + PostgreSQL)",
|
||||
"test_framework": "string (e.g. jest, vitest, pytest)",
|
||||
"has_project_tech": true,
|
||||
"has_project_guidelines": true
|
||||
},
|
||||
|
||||
"task": {
|
||||
"original": "raw user input",
|
||||
"refined": "enhanced task description with all 5 dimensions",
|
||||
"quality_score": 8,
|
||||
"dimensions": {
|
||||
"objective": { "score": 2, "value": "..." },
|
||||
"success_criteria": { "score": 2, "value": "..." },
|
||||
"scope": { "score": 2, "value": "..." },
|
||||
"constraints": { "score": 1, "value": "..." },
|
||||
"context": { "score": 1, "value": "..." }
|
||||
},
|
||||
"source_refs": [
|
||||
{
|
||||
"path": "docs/prd.md",
|
||||
"type": "local_file | url | auto_detected",
|
||||
"status": "verified | linked | not_found",
|
||||
"preview": "first ~20 lines (local_file only)"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"auto_iteration": {
|
||||
"enabled": true,
|
||||
"no_confirmation": true,
|
||||
"max_iterations": 5,
|
||||
"timeout_per_iteration_ms": 1800000,
|
||||
"convergence": {
|
||||
"test_pass_rate": 90,
|
||||
"coverage": 80,
|
||||
"max_critical_bugs": 0,
|
||||
"max_open_issues": 3
|
||||
},
|
||||
"phase_gates": {
|
||||
"zero_to_one": {
|
||||
"iterations": [1, 2],
|
||||
"exit_criteria": {
|
||||
"code_compiles": true,
|
||||
"core_test_passes": true,
|
||||
"min_requirements_implemented": 1
|
||||
}
|
||||
},
|
||||
"one_to_hundred": {
|
||||
"iterations": [3, 4, 5],
|
||||
"exit_criteria": {
|
||||
"test_pass_rate": 90,
|
||||
"coverage": 80,
|
||||
"critical_bugs": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"agent_focus": {
|
||||
"zero_to_one": {
|
||||
"ra": "core_requirements_only",
|
||||
"ep": "minimal_viable_architecture",
|
||||
"cd": "happy_path_first",
|
||||
"vas": "smoke_tests_only"
|
||||
},
|
||||
"one_to_hundred": {
|
||||
"ra": "full_requirements_with_nfr",
|
||||
"ep": "refined_architecture_with_risks",
|
||||
"cd": "complete_implementation_with_error_handling",
|
||||
"vas": "full_test_suite_with_coverage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Phase 1 Integration (Consume & Check)
|
||||
|
||||
Phase 1 对 prep-package.json 执行 **6 项验证**,全部通过才加载,任一失败回退默认行为:
|
||||
|
||||
| # | 检查项 | 条件 | 失败处理 |
|
||||
|---|--------|------|----------|
|
||||
| 1 | prep_status | `=== "ready"` | 跳过 prep |
|
||||
| 2 | project_root | 与当前 projectRoot 一致 | 跳过 prep(防错误项目) |
|
||||
| 3 | quality_score | `>= 6` | 跳过 prep(任务质量不达标) |
|
||||
| 4 | 时效性 | generated_at 在 24h 以内 | 跳过 prep(可能过期) |
|
||||
| 5 | 必需字段 | task.refined, convergence, phase_gates, agent_focus 全部存在 | 跳过 prep |
|
||||
| 6 | 收敛值合法 | test_pass_rate/coverage 为 0-100 的数字 | 跳过 prep |
|
||||
|
||||
```javascript
|
||||
// In 01-session-init.md, Step 1.1:
|
||||
const prepPath = `${projectRoot}/.workflow/.cycle/prep-package.json`
|
||||
if (fs.existsSync(prepPath)) {
|
||||
const raw = JSON.parse(Read(prepPath))
|
||||
const checks = validatePrepPackage(raw, projectRoot)
|
||||
|
||||
if (checks.valid) {
|
||||
prepPackage = raw
|
||||
task = prepPackage.task.refined
|
||||
// Inject into state:
|
||||
state.convergence = prepPackage.auto_iteration.convergence
|
||||
state.phase_gates = prepPackage.auto_iteration.phase_gates
|
||||
state.agent_focus = prepPackage.auto_iteration.agent_focus
|
||||
state.max_iterations = prepPackage.auto_iteration.max_iterations
|
||||
} else {
|
||||
console.warn('Prep package validation failed, using defaults')
|
||||
// prepPackage remains null → no convergence/phase_gates/agent_focus
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Phase 2 Integration (Agent Focus Directives)
|
||||
|
||||
```javascript
|
||||
// Before spawning each agent, append focus directive:
|
||||
function getAgentFocusDirective(agentName, state) {
|
||||
if (!state.phase_gates) return ""
|
||||
const iteration = state.current_iteration
|
||||
const isZeroToOne = state.phase_gates.zero_to_one.iterations.includes(iteration)
|
||||
const focus = isZeroToOne
|
||||
? state.agent_focus.zero_to_one[agentName]
|
||||
: state.agent_focus.one_to_hundred[agentName]
|
||||
|
||||
const directives = {
|
||||
core_requirements_only: "Focus ONLY on core functional requirements. Skip NFRs and edge cases.",
|
||||
minimal_viable_architecture: "Design the simplest working architecture. Skip optimization.",
|
||||
happy_path_first: "Implement ONLY the happy path. Skip error handling and edge cases.",
|
||||
smoke_tests_only: "Run smoke tests only. Skip coverage analysis and exhaustive validation.",
|
||||
full_requirements_with_nfr: "Complete requirements including NFRs, edge cases, security.",
|
||||
refined_architecture_with_risks: "Refine architecture with risk mitigation and scalability.",
|
||||
complete_implementation_with_error_handling: "Complete all tasks with error handling and validation.",
|
||||
full_test_suite_with_coverage: "Full test suite with coverage report and quality audit."
|
||||
}
|
||||
return `\n## FOCUS DIRECTIVE (${isZeroToOne ? '0→1' : '1→100'})\n${directives[focus] || ''}\n`
|
||||
}
|
||||
```
|
||||
|
||||
## Phase 3 Integration (Convergence Evaluation)
|
||||
|
||||
```javascript
|
||||
// In 03-result-aggregation.md, Step 3.4:
|
||||
function evaluateConvergence(parsedResults, state) {
|
||||
if (!state.phase_gates) {
|
||||
// No prep package: use default issue detection
|
||||
return { converged: !parsedResults.vas.issues?.length, phase: "default" }
|
||||
}
|
||||
const iteration = state.current_iteration
|
||||
const isZeroToOne = state.phase_gates.zero_to_one.iterations.includes(iteration)
|
||||
|
||||
if (isZeroToOne) {
|
||||
return {
|
||||
converged: parsedResults.cd.status !== 'failed'
|
||||
&& (parsedResults.vas.test_pass_rate > 0 || parsedResults.cd.tests_passing),
|
||||
phase: "0→1"
|
||||
}
|
||||
}
|
||||
const conv = state.convergence
|
||||
return {
|
||||
converged: (parsedResults.vas.test_pass_rate || 0) >= conv.test_pass_rate
|
||||
&& (parsedResults.vas.coverage || 0) >= conv.coverage
|
||||
&& (parsedResults.vas.critical_issues || 0) <= conv.max_critical_bugs,
|
||||
phase: "1→100"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -12,7 +12,7 @@ Create or resume a development cycle, initialize state file and directory struct
|
||||
|
||||
## Execution
|
||||
|
||||
### Step 1.1: Parse Arguments
|
||||
### Step 1.1: Parse Arguments & Load Prep Package
|
||||
|
||||
```javascript
|
||||
const { cycleId: existingCycleId, task, mode = 'interactive', extension } = options
|
||||
@@ -22,6 +22,102 @@ if (!existingCycleId && !task) {
|
||||
console.error('Either --cycle-id or task description is required')
|
||||
return { status: 'error', message: 'Missing cycleId or task' }
|
||||
}
|
||||
|
||||
// ── Prep Package: Detect → Validate → Consume ──
|
||||
let prepPackage = null
|
||||
const prepPath = `${projectRoot}/.workflow/.cycle/prep-package.json`
|
||||
|
||||
if (fs.existsSync(prepPath)) {
|
||||
const raw = JSON.parse(Read(prepPath))
|
||||
const checks = validatePrepPackage(raw, projectRoot)
|
||||
|
||||
if (checks.valid) {
|
||||
prepPackage = raw
|
||||
task = prepPackage.task.refined
|
||||
console.log(`✓ Prep package loaded: score=${prepPackage.task.quality_score}/10, auto=${prepPackage.auto_iteration.enabled}`)
|
||||
console.log(` Checks passed: ${checks.passed.join(', ')}`)
|
||||
} else {
|
||||
console.warn(`⚠ Prep package found but failed validation:`)
|
||||
checks.failures.forEach(f => console.warn(` ✗ ${f}`))
|
||||
console.warn(` → Falling back to default behavior (prep-package ignored)`)
|
||||
prepPackage = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate prep-package.json integrity before consumption.
|
||||
* Returns { valid: bool, passed: string[], failures: string[] }
|
||||
*/
|
||||
function validatePrepPackage(prep, projectRoot) {
|
||||
const passed = []
|
||||
const failures = []
|
||||
|
||||
// Check 1: prep_status must be "ready"
|
||||
if (prep.prep_status === 'ready') {
|
||||
passed.push('status=ready')
|
||||
} else {
|
||||
failures.push(`prep_status is "${prep.prep_status}", expected "ready"`)
|
||||
}
|
||||
|
||||
// Check 2: project_root must match current project
|
||||
if (prep.environment?.project_root === projectRoot) {
|
||||
passed.push('project_root match')
|
||||
} else {
|
||||
failures.push(`project_root mismatch: prep="${prep.environment?.project_root}", current="${projectRoot}"`)
|
||||
}
|
||||
|
||||
// Check 3: quality_score must be >= 6
|
||||
if ((prep.task?.quality_score || 0) >= 6) {
|
||||
passed.push(`quality=${prep.task.quality_score}/10`)
|
||||
} else {
|
||||
failures.push(`quality_score ${prep.task?.quality_score || 0} < 6 minimum`)
|
||||
}
|
||||
|
||||
// Check 4: generated_at must be within 24 hours
|
||||
const generatedAt = new Date(prep.generated_at)
|
||||
const hoursSince = (Date.now() - generatedAt.getTime()) / (1000 * 60 * 60)
|
||||
if (hoursSince <= 24) {
|
||||
passed.push(`age=${Math.round(hoursSince)}h`)
|
||||
} else {
|
||||
failures.push(`prep-package is ${Math.round(hoursSince)}h old (max 24h), may be stale`)
|
||||
}
|
||||
|
||||
// Check 5: required fields exist
|
||||
const requiredFields = [
|
||||
'task.refined',
|
||||
'auto_iteration.convergence.test_pass_rate',
|
||||
'auto_iteration.convergence.coverage',
|
||||
'auto_iteration.phase_gates.zero_to_one',
|
||||
'auto_iteration.phase_gates.one_to_hundred',
|
||||
'auto_iteration.agent_focus.zero_to_one',
|
||||
'auto_iteration.agent_focus.one_to_hundred'
|
||||
]
|
||||
const missing = requiredFields.filter(path => {
|
||||
const val = path.split('.').reduce((obj, key) => obj?.[key], prep)
|
||||
return val === undefined || val === null
|
||||
})
|
||||
if (missing.length === 0) {
|
||||
passed.push('fields complete')
|
||||
} else {
|
||||
failures.push(`missing fields: ${missing.join(', ')}`)
|
||||
}
|
||||
|
||||
// Check 6: convergence values are valid numbers
|
||||
const conv = prep.auto_iteration?.convergence
|
||||
if (conv && typeof conv.test_pass_rate === 'number' && typeof conv.coverage === 'number'
|
||||
&& conv.test_pass_rate > 0 && conv.test_pass_rate <= 100
|
||||
&& conv.coverage > 0 && conv.coverage <= 100) {
|
||||
passed.push(`convergence valid (test≥${conv.test_pass_rate}%, cov≥${conv.coverage}%)`)
|
||||
} else {
|
||||
failures.push(`convergence values invalid: test_pass_rate=${conv?.test_pass_rate}, coverage=${conv?.coverage}`)
|
||||
}
|
||||
|
||||
return {
|
||||
valid: failures.length === 0,
|
||||
passed,
|
||||
failures
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1.2: Utility Functions
|
||||
@@ -73,7 +169,7 @@ function createCycleState(cycleId, taskDescription) {
|
||||
cycle_id: cycleId,
|
||||
title: taskDescription.substring(0, 100),
|
||||
description: taskDescription,
|
||||
max_iterations: 5,
|
||||
max_iterations: prepPackage?.auto_iteration?.max_iterations || 5,
|
||||
status: 'running',
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
@@ -96,7 +192,13 @@ function createCycleState(cycleId, taskDescription) {
|
||||
exploration: null,
|
||||
plan: null,
|
||||
changes: [],
|
||||
test_results: null
|
||||
test_results: null,
|
||||
|
||||
// Prep package integration (from /prompts:prep-cycle)
|
||||
convergence: prepPackage?.auto_iteration?.convergence || null,
|
||||
phase_gates: prepPackage?.auto_iteration?.phase_gates || null,
|
||||
agent_focus: prepPackage?.auto_iteration?.agent_focus || null,
|
||||
source_refs: prepPackage?.task?.source_refs || null
|
||||
}
|
||||
|
||||
Write(stateFile, JSON.stringify(state, null, 2))
|
||||
|
||||
@@ -27,6 +27,31 @@ Each agent reads its detailed role definition at execution time:
|
||||
|
||||
```javascript
|
||||
function spawnRAAgent(cycleId, state, progressDir) {
|
||||
// Build source references section from prep-package
|
||||
const sourceRefsSection = (state.source_refs && state.source_refs.length > 0)
|
||||
? `## REQUIREMENT SOURCE DOCUMENTS
|
||||
|
||||
Read these original requirement documents BEFORE analyzing the task:
|
||||
|
||||
${state.source_refs
|
||||
.filter(r => r.status === 'verified' || r.status === 'linked')
|
||||
.map((r, i) => {
|
||||
if (r.type === 'local_file' || r.type === 'auto_detected') {
|
||||
return `${i + 1}. **Read**: ${r.path} (${r.type})`
|
||||
} else if (r.type === 'url') {
|
||||
return `${i + 1}. **Reference URL**: ${r.path} (fetch if accessible)`
|
||||
}
|
||||
return ''
|
||||
}).join('\n')}
|
||||
|
||||
Use these documents as the primary source of truth for requirements analysis.
|
||||
Cross-reference the task description against these documents for completeness.
|
||||
`
|
||||
: ''
|
||||
|
||||
// Build focus directive from prep-package
|
||||
const focusDirective = getAgentFocusDirective('ra', state)
|
||||
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
@@ -39,6 +64,7 @@ function spawnRAAgent(cycleId, state, progressDir) {
|
||||
|
||||
---
|
||||
|
||||
${sourceRefsSection}
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
@@ -61,7 +87,7 @@ Requirements Analyst - Analyze and refine requirements throughout the cycle.
|
||||
3. Identify edge cases and implicit requirements
|
||||
4. Track requirement changes across iterations
|
||||
5. Maintain requirements.md and changes.log
|
||||
|
||||
${focusDirective}
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/ra/:
|
||||
|
||||
Reference in New Issue
Block a user