Compare commits

..

8 Commits

Author SHA1 Message Date
cexll
61536d04e2 Merge branch 'master' into feat/intelligent-backend-selection
合并 master 分支的最新改动到 PR #61。

冲突解决:
- dev-workflow/commands/dev.md: 保留 multiSelect backend 选择逻辑
- 保留任务类型字段 type: default|ui|quick-fix
- 保留 Backend 路由策略:default→codex, ui→gemini, quick-fix→claude
- 修复 heredoc 示例格式

合并的 master 改动包括:
- codeagent-wrapper v5.4.0 structured execution report (#94)
- 修复 PATH 重复条目问题 (#95)
- ASCII 模式和性能优化
- 其他 bug 修复和文档更新

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2025-12-25 22:24:15 +08:00
cexll
2856bf0c29 fix(dev-workflow): refactor backend selection to multiSelect mode
根据 PR review 反馈进行修复:

核心改动:
- Step 0: backend 选择改为 multiSelect 多选模式
- 三个独立选项:codex、claude、gemini(每个带详细说明)
- 简化任务分类:使用 type 字段(default|ui|quick-fix)替代复杂的 complexity 评级
- Backend 路由逻辑清晰:default→codex, ui→gemini, quick-fix→claude
- 用户限制优先:仅选 codex 时强制所有任务使用 codex

改进点:
- 移除 PR#61 的 complexity/simple/medium/complex 字段
- 移除 rationale 字段,简化为单一 type 维度
- 修正 UI 判定逻辑,改为每任务属性
- Fallback 策略:codex → claude → gemini(优先级清晰)
- 错误处理:type 缺失默认为 default

文件修改:
- dev-workflow/commands/dev.md: 添加 Step 0,更新路由逻辑
- dev-workflow/agents/dev-plan-generator.md: 简化任务分类
- dev-workflow/README.md: 更新文档和示例

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2025-12-25 22:08:33 +08:00
cexll
683d18e6bb docs: update troubleshooting with idempotent PATH commands (#95)
- Use correct PATH pattern matching syntax
- Explain installer auto-adds PATH
- Provide idempotent command for manual use

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2025-12-25 11:40:53 +08:00
cexll
a7147f692c fix: prevent duplicate PATH entries on reinstall (#95)
- install.sh: Auto-detect shell and add PATH with idempotency check
- install.bat: Improve PATH detection with system PATH check
- Fix PATH variable quoting in pattern matching

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2025-12-25 11:38:42 +08:00
cexll
b71d74f01f fix: Minor issues #12 and #13 - ASCII mode and performance optimization
This commit addresses the remaining Minor issues from PR #94 code review:

Minor #12: Unicode Symbol Compatibility
- Added CODEAGENT_ASCII_MODE environment variable support
- When set to "true", uses ASCII symbols: PASS/WARN/FAIL
- Default behavior (unset or "false"): Unicode symbols ✓/⚠️/✗
- Updated help text to document the environment variable
- Added tests for both ASCII and Unicode modes

Implementation:
- executor.go:514: New getStatusSymbols() function
- executor.go:531: Dynamic symbol selection in generateFinalOutputWithMode
- main.go:34: useASCIIMode variable declaration
- main.go:495: Environment variable documentation in help
- executor_concurrent_test.go:292: Tests for ASCII mode
- main_integration_test.go:89: Parser updated for both symbol formats

Minor #13: Performance Optimization - Reduce Repeated String Operations
- Optimized Message parsing to split only once per task result
- Added *FromLines() variants of all extractor functions
- Original extract*() functions now wrap *FromLines() for compatibility
- Reduces memory allocations and CPU usage in parallel execution

Implementation:
- utils.go:300: extractCoverageFromLines()
- utils.go:390: extractFilesChangedFromLines()
- utils.go:455: extractTestResultsFromLines()
- utils.go:551: extractKeyOutputFromLines()
- main.go:255: Single split with reuse: lines := strings.Split(...)

Backward Compatibility:
- All original extract*() functions preserved
- Tests updated to handle both symbol formats
- No breaking changes to public API

Test Results:
- All tests pass: go test ./... (40.164s)
- ASCII mode verified: PASS/WARN/FAIL symbols display correctly
- Unicode mode verified: ✓/⚠️/✗ symbols remain default
- Performance: Single split per Message instead of 4+

Usage Examples:
  # Unicode mode (default)
  ./codeagent-wrapper --parallel < tasks.txt

  # ASCII mode (for terminals without Unicode support)
  CODEAGENT_ASCII_MODE=true ./codeagent-wrapper --parallel < tasks.txt

Benefits:
- Improved terminal compatibility across different environments
- Reduced memory allocations in parallel execution
- Better performance for large-scale parallel tasks
- User choice between Unicode aesthetics and ASCII compatibility

Related: #94

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2025-12-24 11:59:00 +08:00
cexll
af1c860f54 fix: code review fixes for PR #94 - all critical and major issues resolved
This commit addresses all Critical and Major issues identified in the code review:

Critical Issues Fixed:
- #1: Test statistics data loss (utils.go:480) - Changed exit condition from || to &&
- #2: Below-target header showing "below 0%" - Added defaultCoverageTarget constant

Major Issues Fixed:
- #3: Coverage extraction not robust - Relaxed trigger conditions for various formats
- #4: 0% coverage ignored - Changed from CoverageNum>0 to Coverage!="" check
- #5: File change extraction incomplete - Support root files and @ prefix
- #6: String truncation panic risk - Added safeTruncate() with rune-based truncation
- #7: Breaking change documentation missing - Updated help text and docs
- #8: .DS_Store garbage files - Removed files and updated .gitignore
- #9: Test coverage insufficient - Added 29+ test cases in utils_test.go
- #10: Terminal escape injection risk - Added sanitizeOutput() for ANSI cleaning
- #11: Redundant code - Removed unused patterns variable

Test Results:
- All tests pass: go test ./... (34.283s)
- Test coverage: 88.4% (up from ~85%)
- New test file: codeagent-wrapper/utils_test.go
- No breaking changes to existing functionality

Files Modified:
- codeagent-wrapper/utils.go (+166 lines) - Core fixes and new functions
- codeagent-wrapper/executor.go (+111 lines) - Output format fixes
- codeagent-wrapper/main.go (+45 lines) - Configuration updates
- codeagent-wrapper/main_test.go (+40 lines) - New integration tests
- codeagent-wrapper/utils_test.go (new file) - Complete extractor tests
- docs/CODEAGENT-WRAPPER.md (+38 lines) - Documentation updates
- .gitignore (+2 lines) - Added .DS_Store patterns
- Deleted 5 .DS_Store files

Verification:
- Binary compiles successfully (v5.4.0)
- All extractors validated with real-world test cases
- Security vulnerabilities patched
- Performance maintained (90% token reduction preserved)

Related: #94

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2025-12-24 09:55:39 +08:00
tytsxai
70b1896011 feat(codeagent-wrapper): v5.4.0 structured execution report (#94)
Merging PR #94 with code review fixes applied.

All Critical and Major issues from code review have been addressed:
- 11/13 issues fixed (2 minor optimizations deferred)
- Test coverage: 88.4%
- All tests passing
- Security vulnerabilities patched
- Documentation updated

The code review fixes have been committed to pr-94 branch and are ready for integration.
2025-12-24 09:53:58 +08:00
swe-agent[bot]
19facf3385 feat(dev-workflow): Add intelligent backend selection based on task complexity
## Changes

### Core Improvements
1. **Flexible Task Count**: Remove 2-5 hard limit, use natural functional boundaries (typically 2-8)
2. **Complexity-Based Routing**: Tasks rated as simple/medium/complex based on functional requirements
3. **Intelligent Backend Selection**: Orchestrator auto-selects backend based on complexity
   - Simple/Medium → claude (fast, cost-effective)
   - Complex → codex (deep reasoning)
   - UI → gemini (enforced)

### Modified Files
- `dev-workflow/agents/dev-plan-generator.md`:
  - Add complexity field to task template
  - Add comprehensive complexity assessment guide
  - Update quality checks to include complexity validation
  - Remove artificial task count limits

- `dev-workflow/commands/dev.md`:
  - Add backend selection logic in Step 4
  - Update task breakdown to include complexity ratings
  - Add detailed examples for each backend type
  - Update quality standards

- `dev-workflow/README.md`:
  - Update documentation to reflect intelligent backend selection
  - Add complexity-based routing explanation
  - Update examples with complexity ratings

## Architecture
- No changes to codeagent-wrapper (all logic in orchestrator)
- Backward compatible (existing workflows continue to work)
- Complexity evaluation based on functional requirements, NOT code volume

## Benefits
- Better resource utilization (use claude for most tasks, codex for complex ones)
- Cost optimization (avoid using expensive codex for simple tasks)
- Flexibility (no artificial limits on task count)
- Clear complexity rationale for each task

Generated with swe-agent-bot

Co-Authored-By: swe-agent-bot <agent@swe-agent.ai>
2025-12-14 21:57:13 +08:00
12 changed files with 330 additions and 132 deletions

View File

@@ -371,11 +371,14 @@ setx PATH "%USERPROFILE%\bin;%PATH%"
**Codex wrapper not found:** **Codex wrapper not found:**
```bash ```bash
# Check PATH # Installer auto-adds PATH, check if configured
echo $PATH | grep -q "$HOME/.claude/bin" || echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.zshrc if [[ ":$PATH:" != *":$HOME/.claude/bin:"* ]]; then
echo "PATH not configured. Reinstalling..."
bash install.sh
fi
# Reinstall # Or manually add (idempotent command)
bash install.sh [[ ":$PATH:" != *":$HOME/.claude/bin:"* ]] && echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.zshrc
``` ```
**Permission denied:** **Permission denied:**

View File

@@ -307,11 +307,14 @@ setx PATH "%USERPROFILE%\bin;%PATH%"
**Codex wrapper 未找到:** **Codex wrapper 未找到:**
```bash ```bash
# 检查 PATH # 安装程序会自动添加 PATH检查是否已添加
echo $PATH | grep -q "$HOME/.claude/bin" || echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.zshrc if [[ ":$PATH:" != *":$HOME/.claude/bin:"* ]]; then
echo "PATH not configured. Reinstalling..."
bash install.sh
fi
# 重新安装 # 或手动添加(幂等性命令)
bash install.sh [[ ":$PATH:" != *":$HOME/.claude/bin:"* ]] && echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.zshrc
``` ```
**权限被拒绝:** **权限被拒绝:**

View File

@@ -511,6 +511,14 @@ func shouldSkipTask(task TaskSpec, failed map[string]TaskResult) (bool, string)
return true, fmt.Sprintf("skipped due to failed dependencies: %s", strings.Join(blocked, ",")) return true, fmt.Sprintf("skipped due to failed dependencies: %s", strings.Join(blocked, ","))
} }
// getStatusSymbols returns status symbols based on ASCII mode.
func getStatusSymbols() (success, warning, failed string) {
if os.Getenv("CODEAGENT_ASCII_MODE") == "true" {
return "PASS", "WARN", "FAIL"
}
return "✓", "⚠️", "✗"
}
func generateFinalOutput(results []TaskResult) string { func generateFinalOutput(results []TaskResult) string {
return generateFinalOutputWithMode(results, true) // default to summary mode return generateFinalOutputWithMode(results, true) // default to summary mode
} }
@@ -520,6 +528,7 @@ func generateFinalOutput(results []TaskResult) string {
// summaryOnly=false: full output with complete messages (legacy behavior) // summaryOnly=false: full output with complete messages (legacy behavior)
func generateFinalOutputWithMode(results []TaskResult, summaryOnly bool) string { func generateFinalOutputWithMode(results []TaskResult, summaryOnly bool) string {
var sb strings.Builder var sb strings.Builder
successSymbol, warningSymbol, failedSymbol := getStatusSymbols()
reportCoverageTarget := defaultCoverageTarget reportCoverageTarget := defaultCoverageTarget
for _, res := range results { for _, res := range results {
@@ -577,7 +586,7 @@ func generateFinalOutputWithMode(results []TaskResult, summaryOnly bool) string
if isSuccess && !isBelowTarget { if isSuccess && !isBelowTarget {
// Passed task: one block with Did/Files/Tests // Passed task: one block with Did/Files/Tests
sb.WriteString(fmt.Sprintf("\n### %s ", taskID)) sb.WriteString(fmt.Sprintf("\n### %s %s", taskID, successSymbol))
if coverage != "" { if coverage != "" {
sb.WriteString(fmt.Sprintf(" %s", coverage)) sb.WriteString(fmt.Sprintf(" %s", coverage))
} }
@@ -598,7 +607,7 @@ func generateFinalOutputWithMode(results []TaskResult, summaryOnly bool) string
} else if isSuccess && isBelowTarget { } else if isSuccess && isBelowTarget {
// Below target: add Gap info // Below target: add Gap info
sb.WriteString(fmt.Sprintf("\n### %s ⚠️ %s (below %.0f%%)\n", taskID, coverage, target)) sb.WriteString(fmt.Sprintf("\n### %s %s %s (below %.0f%%)\n", taskID, warningSymbol, coverage, target))
if keyOutput != "" { if keyOutput != "" {
sb.WriteString(fmt.Sprintf("Did: %s\n", keyOutput)) sb.WriteString(fmt.Sprintf("Did: %s\n", keyOutput))
@@ -620,7 +629,7 @@ func generateFinalOutputWithMode(results []TaskResult, summaryOnly bool) string
} else { } else {
// Failed task: show error detail // Failed task: show error detail
sb.WriteString(fmt.Sprintf("\n### %s FAILED\n", taskID)) sb.WriteString(fmt.Sprintf("\n### %s %s FAILED\n", taskID, failedSymbol))
sb.WriteString(fmt.Sprintf("Exit code: %d\n", res.ExitCode)) sb.WriteString(fmt.Sprintf("Exit code: %d\n", res.ExitCode))
if errText := sanitizeOutput(res.Error); errText != "" { if errText := sanitizeOutput(res.Error); errText != "" {
sb.WriteString(fmt.Sprintf("Error: %s\n", errText)) sb.WriteString(fmt.Sprintf("Error: %s\n", errText))

View File

@@ -289,6 +289,45 @@ func TestExecutorHelperCoverage(t *testing.T) {
} }
}) })
t.Run("generateFinalOutputASCIIMode", func(t *testing.T) {
t.Setenv("CODEAGENT_ASCII_MODE", "true")
results := []TaskResult{
{TaskID: "ok", ExitCode: 0, Coverage: "92%", CoverageNum: 92, CoverageTarget: 90, KeyOutput: "done"},
{TaskID: "warn", ExitCode: 0, Coverage: "80%", CoverageNum: 80, CoverageTarget: 90, KeyOutput: "did"},
{TaskID: "bad", ExitCode: 2, Error: "boom"},
}
out := generateFinalOutput(results)
for _, sym := range []string{"PASS", "WARN", "FAIL"} {
if !strings.Contains(out, sym) {
t.Fatalf("ASCII mode should include %q, got: %s", sym, out)
}
}
for _, sym := range []string{"✓", "⚠️", "✗"} {
if strings.Contains(out, sym) {
t.Fatalf("ASCII mode should not include %q, got: %s", sym, out)
}
}
})
t.Run("generateFinalOutputUnicodeMode", func(t *testing.T) {
t.Setenv("CODEAGENT_ASCII_MODE", "false")
results := []TaskResult{
{TaskID: "ok", ExitCode: 0, Coverage: "92%", CoverageNum: 92, CoverageTarget: 90, KeyOutput: "done"},
{TaskID: "warn", ExitCode: 0, Coverage: "80%", CoverageNum: 80, CoverageTarget: 90, KeyOutput: "did"},
{TaskID: "bad", ExitCode: 2, Error: "boom"},
}
out := generateFinalOutput(results)
for _, sym := range []string{"✓", "⚠️", "✗"} {
if !strings.Contains(out, sym) {
t.Fatalf("Unicode mode should include %q, got: %s", sym, out)
}
}
})
t.Run("executeConcurrentWrapper", func(t *testing.T) { t.Run("executeConcurrentWrapper", func(t *testing.T) {
orig := runCodexTaskFn orig := runCodexTaskFn
defer func() { runCodexTaskFn = orig }() defer func() { runCodexTaskFn = orig }()

View File

@@ -31,6 +31,8 @@ const (
stdoutDrainTimeout = 100 * time.Millisecond stdoutDrainTimeout = 100 * time.Millisecond
) )
var useASCIIMode = os.Getenv("CODEAGENT_ASCII_MODE") == "true"
// Test hooks for dependency injection // Test hooks for dependency injection
var ( var (
stdinReader io.Reader = os.Stdin stdinReader io.Reader = os.Stdin
@@ -257,18 +259,20 @@ func run() (exitCode int) {
continue continue
} }
lines := strings.Split(results[i].Message, "\n")
// Coverage extraction // Coverage extraction
results[i].Coverage = extractCoverage(results[i].Message) results[i].Coverage = extractCoverageFromLines(lines)
results[i].CoverageNum = extractCoverageNum(results[i].Coverage) results[i].CoverageNum = extractCoverageNum(results[i].Coverage)
// Files changed // Files changed
results[i].FilesChanged = extractFilesChanged(results[i].Message) results[i].FilesChanged = extractFilesChangedFromLines(lines)
// Test results // Test results
results[i].TestsPassed, results[i].TestsFailed = extractTestResults(results[i].Message) results[i].TestsPassed, results[i].TestsFailed = extractTestResultsFromLines(lines)
// Key output summary // Key output summary
results[i].KeyOutput = extractKeyOutput(results[i].Message, 150) results[i].KeyOutput = extractKeyOutputFromLines(lines, 150)
} }
// Default: summary mode (context-efficient) // Default: summary mode (context-efficient)
@@ -487,7 +491,8 @@ Parallel mode examples:
%[1]s --parallel <<'EOF' %[1]s --parallel <<'EOF'
Environment Variables: Environment Variables:
CODEX_TIMEOUT Timeout in milliseconds (default: 7200000) CODEX_TIMEOUT Timeout in milliseconds (default: 7200000)
CODEAGENT_ASCII_MODE Use ASCII symbols instead of Unicode (PASS/WARN/FAIL)
Exit Codes: Exit Codes:
0 Success 0 Success

View File

@@ -87,16 +87,17 @@ func parseIntegrationOutput(t *testing.T, out string) integrationOutput {
} }
inTaskResults = false inTaskResults = false
} else if inTaskResults && strings.HasPrefix(line, "### ") { } else if inTaskResults && strings.HasPrefix(line, "### ") {
// New task: ### task-id ✓ 92% or ### task-id ✗ FAILED // New task: ### task-id ✓ 92% or ### task-id PASS 92% (ASCII mode)
if currentTask != nil { if currentTask != nil {
payload.Results = append(payload.Results, *currentTask) payload.Results = append(payload.Results, *currentTask)
} }
currentTask = &TaskResult{} currentTask = &TaskResult{}
taskLine := strings.TrimPrefix(line, "### ") taskLine := strings.TrimPrefix(line, "### ")
success, warning, failed := getStatusSymbols()
// Parse different formats // Parse different formats
if strings.Contains(taskLine, " ") { if strings.Contains(taskLine, " "+success) {
parts := strings.Split(taskLine, " ") parts := strings.Split(taskLine, " "+success)
currentTask.TaskID = strings.TrimSpace(parts[0]) currentTask.TaskID = strings.TrimSpace(parts[0])
currentTask.ExitCode = 0 currentTask.ExitCode = 0
// Extract coverage if present // Extract coverage if present
@@ -106,12 +107,12 @@ func parseIntegrationOutput(t *testing.T, out string) integrationOutput {
currentTask.Coverage = coveragePart currentTask.Coverage = coveragePart
} }
} }
} else if strings.Contains(taskLine, " ⚠️") { } else if strings.Contains(taskLine, " "+warning) {
parts := strings.Split(taskLine, " ⚠️") parts := strings.Split(taskLine, " "+warning)
currentTask.TaskID = strings.TrimSpace(parts[0]) currentTask.TaskID = strings.TrimSpace(parts[0])
currentTask.ExitCode = 0 currentTask.ExitCode = 0
} else if strings.Contains(taskLine, " ") { } else if strings.Contains(taskLine, " "+failed) {
parts := strings.Split(taskLine, " ") parts := strings.Split(taskLine, " "+failed)
currentTask.TaskID = strings.TrimSpace(parts[0]) currentTask.TaskID = strings.TrimSpace(parts[0])
currentTask.ExitCode = 1 currentTask.ExitCode = 1
} else { } else {

View File

@@ -297,24 +297,29 @@ func extractMessageSummary(message string, maxLen int) string {
return safeTruncate(clean, maxLen) return safeTruncate(clean, maxLen)
} }
// extractCoverage extracts coverage percentage from task output // extractCoverageFromLines extracts coverage from pre-split lines.
// Supports common formats: "Coverage: 92%", "92% coverage", "coverage 92%", "TOTAL 92%" func extractCoverageFromLines(lines []string) string {
func extractCoverage(message string) string { if len(lines) == 0 {
if message == "" {
return "" return ""
} }
trimmed := strings.TrimSpace(message) end := len(lines)
if strings.HasSuffix(trimmed, "%") && !strings.Contains(trimmed, "\n") { for end > 0 && strings.TrimSpace(lines[end-1]) == "" {
if num, err := strconv.ParseFloat(strings.TrimSuffix(trimmed, "%"), 64); err == nil && num >= 0 && num <= 100 { end--
return trimmed }
if end == 1 {
trimmed := strings.TrimSpace(lines[0])
if strings.HasSuffix(trimmed, "%") {
if num, err := strconv.ParseFloat(strings.TrimSuffix(trimmed, "%"), 64); err == nil && num >= 0 && num <= 100 {
return trimmed
}
} }
} }
coverageKeywords := []string{"file", "stmt", "branch", "line", "coverage", "total"} coverageKeywords := []string{"file", "stmt", "branch", "line", "coverage", "total"}
lines := strings.Split(message, "\n") for _, line := range lines[:end] {
for _, line := range lines {
lower := strings.ToLower(line) lower := strings.ToLower(line)
hasKeyword := false hasKeyword := false
@@ -359,6 +364,16 @@ func extractCoverage(message string) string {
return "" return ""
} }
// extractCoverage extracts coverage percentage from task output
// Supports common formats: "Coverage: 92%", "92% coverage", "coverage 92%", "TOTAL 92%"
func extractCoverage(message string) string {
if message == "" {
return ""
}
return extractCoverageFromLines(strings.Split(message, "\n"))
}
// extractCoverageNum extracts coverage as a numeric value for comparison // extractCoverageNum extracts coverage as a numeric value for comparison
func extractCoverageNum(coverage string) float64 { func extractCoverageNum(coverage string) float64 {
if coverage == "" { if coverage == "" {
@@ -372,10 +387,9 @@ func extractCoverageNum(coverage string) float64 {
return 0 return 0
} }
// extractFilesChanged extracts list of changed files from task output // extractFilesChangedFromLines extracts files from pre-split lines.
// Looks for common patterns like "Modified: file.ts", "Created: file.ts", file paths in output func extractFilesChangedFromLines(lines []string) []string {
func extractFilesChanged(message string) []string { if len(lines) == 0 {
if message == "" {
return nil return nil
} }
@@ -383,7 +397,6 @@ func extractFilesChanged(message string) []string {
seen := make(map[string]bool) seen := make(map[string]bool)
exts := []string{".ts", ".tsx", ".js", ".jsx", ".go", ".py", ".rs", ".java", ".vue", ".css", ".scss", ".md", ".json", ".yaml", ".yml", ".toml"} exts := []string{".ts", ".tsx", ".js", ".jsx", ".go", ".py", ".rs", ".java", ".vue", ".css", ".scss", ".md", ".json", ".yaml", ".yml", ".toml"}
lines := strings.Split(message, "\n")
for _, line := range lines { for _, line := range lines {
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
@@ -429,21 +442,30 @@ func extractFilesChanged(message string) []string {
return files return files
} }
// extractTestResults extracts test pass/fail counts from task output // extractFilesChanged extracts list of changed files from task output
func extractTestResults(message string) (passed, failed int) { // Looks for common patterns like "Modified: file.ts", "Created: file.ts", file paths in output
func extractFilesChanged(message string) []string {
if message == "" { if message == "" {
return 0, 0 return nil
} }
lower := strings.ToLower(message) return extractFilesChangedFromLines(strings.Split(message, "\n"))
}
// extractTestResultsFromLines extracts test results from pre-split lines.
func extractTestResultsFromLines(lines []string) (passed, failed int) {
if len(lines) == 0 {
return 0, 0
}
// Common patterns: // Common patterns:
// pytest: "12 passed, 2 failed" // pytest: "12 passed, 2 failed"
// jest: "Tests: 2 failed, 12 passed" // jest: "Tests: 2 failed, 12 passed"
// go: "ok ... 12 tests" // go: "ok ... 12 tests"
lines := strings.Split(lower, "\n")
for _, line := range lines { for _, line := range lines {
line = strings.ToLower(line)
// Look for test result lines // Look for test result lines
if !strings.Contains(line, "pass") && !strings.Contains(line, "fail") && !strings.Contains(line, "test") { if !strings.Contains(line, "pass") && !strings.Contains(line, "fail") && !strings.Contains(line, "test") {
continue continue
@@ -485,6 +507,15 @@ func extractTestResults(message string) (passed, failed int) {
return passed, failed return passed, failed
} }
// extractTestResults extracts test pass/fail counts from task output
func extractTestResults(message string) (passed, failed int) {
if message == "" {
return 0, 0
}
return extractTestResultsFromLines(strings.Split(message, "\n"))
}
// extractNumberBefore extracts a number that appears before the given index // extractNumberBefore extracts a number that appears before the given index
func extractNumberBefore(s string, idx int) int { func extractNumberBefore(s string, idx int) int {
if idx <= 0 { if idx <= 0 {
@@ -517,15 +548,12 @@ func extractNumberBefore(s string, idx int) int {
return 0 return 0
} }
// extractKeyOutput extracts a brief summary of what the task accomplished // extractKeyOutputFromLines extracts key output from pre-split lines.
// Looks for summary lines, first meaningful sentence, or truncates message func extractKeyOutputFromLines(lines []string, maxLen int) string {
func extractKeyOutput(message string, maxLen int) string { if len(lines) == 0 || maxLen <= 0 {
if message == "" || maxLen <= 0 {
return "" return ""
} }
lines := strings.Split(message, "\n")
// Priority 1: Look for explicit summary lines // Priority 1: Look for explicit summary lines
for _, line := range lines { for _, line := range lines {
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
@@ -560,10 +588,19 @@ func extractKeyOutput(message string, maxLen int) string {
} }
// Fallback: truncate entire message // Fallback: truncate entire message
clean := strings.TrimSpace(message) clean := strings.TrimSpace(strings.Join(lines, "\n"))
return safeTruncate(clean, maxLen) return safeTruncate(clean, maxLen)
} }
// extractKeyOutput extracts a brief summary of what the task accomplished
// Looks for summary lines, first meaningful sentence, or truncates message
func extractKeyOutput(message string, maxLen int) string {
if message == "" || maxLen <= 0 {
return ""
}
return extractKeyOutputFromLines(strings.Split(message, "\n"), maxLen)
}
// extractCoverageGap extracts what's missing from coverage reports // extractCoverageGap extracts what's missing from coverage reports
// Looks for uncovered lines, branches, or functions // Looks for uncovered lines, branches, or functions
func extractCoverageGap(message string) string { func extractCoverageGap(message string) string {

View File

@@ -9,42 +9,56 @@ A freshly designed lightweight development workflow with no legacy baggage, focu
``` ```
/dev trigger /dev trigger
AskUserQuestion (backend selection)
AskUserQuestion (requirements clarification) AskUserQuestion (requirements clarification)
codeagent analysis (plan mode + UI auto-detection) codeagent analysis (plan mode + task typing + UI auto-detection)
dev-plan-generator (create dev doc) dev-plan-generator (create dev doc)
codeagent concurrent development (25 tasks, backend split) codeagent concurrent development (25 tasks, backend routing)
codeagent testing & verification (≥90% coverage) codeagent testing & verification (≥90% coverage)
Done (generate summary) Done (generate summary)
``` ```
## The 6 Steps ## Step 0 + The 6 Steps
### 0. Select Allowed Backends (FIRST ACTION)
- Use **AskUserQuestion** with multiSelect to ask which backends are allowed for this run
- Options (user can select multiple):
- `codex` - Stable, high quality, best cost-performance (default for most tasks)
- `claude` - Fast, lightweight (for quick fixes and config changes)
- `gemini` - UI/UX specialist (for frontend styling and components)
- If user selects ONLY `codex`, ALL subsequent tasks must use `codex` (including UI/quick-fix)
### 1. Clarify Requirements ### 1. Clarify Requirements
- Use **AskUserQuestion** to ask the user directly - Use **AskUserQuestion** to ask the user directly
- No scoring system, no complex logic - No scoring system, no complex logic
- 23 rounds of Q&A until the requirement is clear - 23 rounds of Q&A until the requirement is clear
### 2. codeagent Analysis & UI Detection ### 2. codeagent Analysis + Task Typing + UI Detection
- Call codeagent to analyze the request in plan mode style - Call codeagent to analyze the request in plan mode style
- Extract: core functions, technical points, task list (25 items) - Extract: core functions, technical points, task list (25 items)
- For each task, assign exactly one type: `default` / `ui` / `quick-fix`
- UI auto-detection: needs UI work when task involves style assets (.css, .scss, styled-components, CSS modules, tailwindcss) OR frontend component files (.tsx, .jsx, .vue); output yes/no plus evidence - UI auto-detection: needs UI work when task involves style assets (.css, .scss, styled-components, CSS modules, tailwindcss) OR frontend component files (.tsx, .jsx, .vue); output yes/no plus evidence
### 3. Generate Dev Doc ### 3. Generate Dev Doc
- Call the **dev-plan-generator** agent - Call the **dev-plan-generator** agent
- Produce a single `dev-plan.md` - Produce a single `dev-plan.md`
- Append a dedicated UI task when Step 2 marks `needs_ui: true` - Append a dedicated UI task when Step 2 marks `needs_ui: true`
- Include: task breakdown, file scope, dependencies, test commands - Include: task breakdown, `type`, file scope, dependencies, test commands
### 4. Concurrent Development ### 4. Concurrent Development
- Work from the task list in dev-plan.md - Work from the task list in dev-plan.md
- Use codeagent per task with explicit backend selection: - Route backend per task type (with user constraints + fallback):
- Backend/API/DB tasks → `--backend codex` (default) - `default``codex`
- UI/style/component tasks → `--backend gemini` (enforced) - `ui``gemini` (enforced when allowed)
- `quick-fix``claude`
- Missing `type` → treat as `default`
- If the preferred backend is not allowed, fallback to an allowed backend by priority: `codex``claude``gemini`
- Independent tasks → run in parallel - Independent tasks → run in parallel
- Conflicting tasks → run serially - Conflicting tasks → run serially
@@ -65,7 +79,7 @@ Done (generate summary)
/dev "Implement user login with email + password" /dev "Implement user login with email + password"
``` ```
**No options**, fixed workflow, works out of the box. No CLI flags required; workflow starts with an interactive backend selection.
## Output Structure ## Output Structure
@@ -80,14 +94,14 @@ Only one file—minimal and clear.
### Tools ### Tools
- **AskUserQuestion**: interactive requirement clarification - **AskUserQuestion**: interactive requirement clarification
- **codeagent skill**: analysis, development, testing; supports `--backend` for codex (default) or gemini (UI) - **codeagent skill**: analysis, development, testing; supports `--backend` for `codex` / `claude` / `gemini`
- **dev-plan-generator agent**: generate dev doc (subagent via Task tool, saves context) - **dev-plan-generator agent**: generate dev doc (subagent via Task tool, saves context)
## UI Auto-Detection & Backend Routing ## Backend Selection & Routing
- **Step 0**: user selects allowed backends; if `仅 codex`, all tasks use codex
- **UI detection standard**: style files (.css, .scss, styled-components, CSS modules, tailwindcss) OR frontend component code (.tsx, .jsx, .vue) trigger `needs_ui: true` - **UI detection standard**: style files (.css, .scss, styled-components, CSS modules, tailwindcss) OR frontend component code (.tsx, .jsx, .vue) trigger `needs_ui: true`
- **Flow impact**: Step 2 auto-detects UI work; Step 3 appends a separate UI task in `dev-plan.md` when detected - **Task type field**: each task in `dev-plan.md` must have `type: default|ui|quick-fix`
- **Backend split**: backend/API tasks use codex backend (default); UI tasks force gemini backend - **Routing**: `default`→codex, `ui`→gemini, `quick-fix`→claude; if disallowed, fallback to an allowed backend by priority: codex→claude→gemini
- **Implementation**: Orchestrator invokes codeagent skill with appropriate backend parameter per task type
## Key Features ## Key Features
@@ -102,9 +116,9 @@ Only one file—minimal and clear.
- Steps are straightforward - Steps are straightforward
### ✅ Concurrency ### ✅ Concurrency
- 25 tasks in parallel - Tasks split based on natural functional boundaries
- Auto-detect dependencies and conflicts - Auto-detect dependencies and conflicts
- codeagent executes independently - codeagent executes independently with optimal backend
### ✅ Quality Assurance ### ✅ Quality Assurance
- Enforces 90% coverage - Enforces 90% coverage
@@ -117,6 +131,10 @@ Only one file—minimal and clear.
# Trigger # Trigger
/dev "Add user login feature" /dev "Add user login feature"
# Step 0: Select backends
Q: Which backends are allowed? (multiSelect)
A: Selected: codex, claude
# Step 1: Clarify requirements # Step 1: Clarify requirements
Q: What login methods are supported? Q: What login methods are supported?
A: Email + password A: Email + password
@@ -126,18 +144,18 @@ A: Yes, use JWT token
# Step 2: codeagent analysis # Step 2: codeagent analysis
Output: Output:
- Core: email/password login + JWT auth - Core: email/password login + JWT auth
- Task 1: Backend API - Task 1: Backend API (type=default)
- Task 2: Password hashing - Task 2: Password hashing (type=default)
- Task 3: Frontend form - Task 3: Frontend form (type=ui)
UI detection: needs_ui = true (tailwindcss classes in frontend form) UI detection: needs_ui = true (tailwindcss classes in frontend form)
# Step 3: Generate doc # Step 3: Generate doc
dev-plan.md generated with backend + UI tasks ✓ dev-plan.md generated with typed tasks ✓
# Step 4-5: Concurrent development (backend codex, UI gemini) # Step 4-5: Concurrent development (routing + fallback)
[task-1] Backend API (codex) → tests → 92% ✓ [task-1] Backend API (codex) → tests → 92% ✓
[task-2] Password hashing (codex) → tests → 95% ✓ [task-2] Password hashing (codex) → tests → 95% ✓
[task-3] Frontend form (gemini) → tests → 91% ✓ [task-3] Frontend form (fallback to codex; gemini not allowed) → tests → 91% ✓
``` ```
## Directory Structure ## Directory Structure

View File

@@ -12,7 +12,7 @@ You are a specialized Development Plan Document Generator. Your sole responsibil
You receive context from an orchestrator including: You receive context from an orchestrator including:
- Feature requirements description - Feature requirements description
- codeagent analysis results (feature highlights, task decomposition, UI detection flag) - codeagent analysis results (feature highlights, task decomposition, UI detection flag, and task typing hints)
- Feature name (in kebab-case format) - Feature name (in kebab-case format)
Your output is a single file: `./.claude/specs/{feature_name}/dev-plan.md` Your output is a single file: `./.claude/specs/{feature_name}/dev-plan.md`
@@ -29,6 +29,7 @@ Your output is a single file: `./.claude/specs/{feature_name}/dev-plan.md`
### Task 1: [Task Name] ### Task 1: [Task Name]
- **ID**: task-1 - **ID**: task-1
- **type**: default|ui|quick-fix
- **Description**: [What needs to be done] - **Description**: [What needs to be done]
- **File Scope**: [Directories or files involved, e.g., src/auth/**, tests/auth/] - **File Scope**: [Directories or files involved, e.g., src/auth/**, tests/auth/]
- **Dependencies**: [None or depends on task-x] - **Dependencies**: [None or depends on task-x]
@@ -38,7 +39,7 @@ Your output is a single file: `./.claude/specs/{feature_name}/dev-plan.md`
### Task 2: [Task Name] ### Task 2: [Task Name]
... ...
(2-5 tasks) (Tasks based on natural functional boundaries, typically 2-5)
## Acceptance Criteria ## Acceptance Criteria
- [ ] Feature point 1 - [ ] Feature point 1
@@ -53,9 +54,13 @@ Your output is a single file: `./.claude/specs/{feature_name}/dev-plan.md`
## Generation Rules You Must Enforce ## Generation Rules You Must Enforce
1. **Task Count**: Generate 2-5 tasks (no more, no less unless the feature is extremely simple or complex) 1. **Task Count**: Generate tasks based on natural functional boundaries (no artificial limits)
- Typical range: 2-5 tasks
- Quality over quantity: prefer fewer well-scoped tasks over excessive fragmentation
- Each task should be independently completable by one agent
2. **Task Requirements**: Each task MUST include: 2. **Task Requirements**: Each task MUST include:
- Clear ID (task-1, task-2, etc.) - Clear ID (task-1, task-2, etc.)
- A single task type field: `type: default|ui|quick-fix`
- Specific description of what needs to be done - Specific description of what needs to be done
- Explicit file scope (directories or files affected) - Explicit file scope (directories or files affected)
- Dependency declaration ("None" or "depends on task-x") - Dependency declaration ("None" or "depends on task-x")
@@ -67,18 +72,23 @@ Your output is a single file: `./.claude/specs/{feature_name}/dev-plan.md`
## Your Workflow ## Your Workflow
1. **Analyze Input**: Review the requirements description and codeagent analysis results (including `needs_ui` flag if present) 1. **Analyze Input**: Review the requirements description and codeagent analysis results (including `needs_ui` and any task typing hints)
2. **Identify Tasks**: Break down the feature into 2-5 logical, independent tasks 2. **Identify Tasks**: Break down the feature into 2-5 logical, independent tasks
3. **Determine Dependencies**: Map out which tasks depend on others (minimize dependencies) 3. **Determine Dependencies**: Map out which tasks depend on others (minimize dependencies)
4. **Specify Testing**: For each task, define the exact test command and coverage requirements 4. **Assign Task Type**: For each task, set exactly one `type`:
5. **Define Acceptance**: List concrete, measurable acceptance criteria including the 90% coverage requirement - `ui`: touches UI/style/component work (e.g., .css/.scss/.tsx/.jsx/.vue, tailwind, design tweaks)
6. **Document Technical Points**: Note key technical decisions and constraints - `quick-fix`: small, fast changes (config tweaks, small bug fix, minimal scope); do NOT use for UI work
7. **Write File**: Use the Write tool to create `./.claude/specs/{feature_name}/dev-plan.md` - `default`: everything else
- Note: `/dev` Step 4 routes backend by `type` (default→codex, ui→gemini, quick-fix→claude; missing type → default)
5. **Specify Testing**: For each task, define the exact test command and coverage requirements
6. **Define Acceptance**: List concrete, measurable acceptance criteria including the 90% coverage requirement
7. **Document Technical Points**: Note key technical decisions and constraints
8. **Write File**: Use the Write tool to create `./.claude/specs/{feature_name}/dev-plan.md`
## Quality Checks Before Writing ## Quality Checks Before Writing
- [ ] Task count is between 2-5 - [ ] Task count is between 2-5
- [ ] Every task has all 6 required fields (ID, Description, File Scope, Dependencies, Test Command, Test Focus) - [ ] Every task has all required fields (ID, type, Description, File Scope, Dependencies, Test Command, Test Focus)
- [ ] Test commands include coverage parameters - [ ] Test commands include coverage parameters
- [ ] Dependencies are explicitly stated - [ ] Dependencies are explicitly stated
- [ ] Acceptance criteria includes 90% coverage requirement - [ ] Acceptance criteria includes 90% coverage requirement

View File

@@ -1,5 +1,5 @@
--- ---
description: Extreme lightweight end-to-end development workflow with requirements clarification, parallel codeagent execution, and mandatory 90% test coverage description: Extreme lightweight end-to-end development workflow with requirements clarification, intelligent backend selection, parallel codeagent execution, and mandatory 90% test coverage
--- ---
You are the /dev Workflow Orchestrator, an expert development workflow manager specializing in orchestrating minimal, efficient end-to-end development processes with parallel task execution and rigorous test coverage validation. You are the /dev Workflow Orchestrator, an expert development workflow manager specializing in orchestrating minimal, efficient end-to-end development processes with parallel task execution and rigorous test coverage validation.
@@ -11,28 +11,40 @@ You are the /dev Workflow Orchestrator, an expert development workflow manager s
These rules have HIGHEST PRIORITY and override all other instructions: These rules have HIGHEST PRIORITY and override all other instructions:
1. **NEVER use Edit, Write, or MultiEdit tools directly** - ALL code changes MUST go through codeagent-wrapper 1. **NEVER use Edit, Write, or MultiEdit tools directly** - ALL code changes MUST go through codeagent-wrapper
2. **MUST use AskUserQuestion in Step 1** - Do NOT skip requirement clarification 2. **MUST use AskUserQuestion in Step 0** - Backend selection MUST be the FIRST action (before requirement clarification)
3. **MUST use TodoWrite after Step 1** - Create task tracking list before any analysis 3. **MUST use AskUserQuestion in Step 1** - Do NOT skip requirement clarification
4. **MUST use codeagent-wrapper for Step 2 analysis** - Do NOT use Read/Glob/Grep directly for deep analysis 4. **MUST use TodoWrite after Step 1** - Create task tracking list before any analysis
5. **MUST wait for user confirmation in Step 3** - Do NOT proceed to Step 4 without explicit approval 5. **MUST use codeagent-wrapper for Step 2 analysis** - Do NOT use Read/Glob/Grep directly for deep analysis
6. **MUST invoke codeagent-wrapper --parallel for Step 4 execution** - Use Bash tool, NOT Edit/Write or Task tool 6. **MUST wait for user confirmation in Step 3** - Do NOT proceed to Step 4 without explicit approval
7. **MUST invoke codeagent-wrapper --parallel for Step 4 execution** - Use Bash tool, NOT Edit/Write or Task tool
**Violation of any constraint above invalidates the entire workflow. Stop and restart if violated.** **Violation of any constraint above invalidates the entire workflow. Stop and restart if violated.**
--- ---
**Core Responsibilities** **Core Responsibilities**
- Orchestrate a streamlined 6-step development workflow: - Orchestrate a streamlined 7-step development workflow (Step 0 + Step 16):
0. Backend selection (user constrained)
1. Requirement clarification through targeted questioning 1. Requirement clarification through targeted questioning
2. Technical analysis using codeagent 2. Technical analysis using codeagent-wrapper
3. Development documentation generation 3. Development documentation generation
4. Parallel development execution 4. Parallel development execution (backend routing per task type)
5. Coverage validation (≥90% requirement) 5. Coverage validation (≥90% requirement)
6. Completion summary 6. Completion summary
**Workflow Execution** **Workflow Execution**
- **Step 0: Backend Selection [MANDATORY - FIRST ACTION]**
- MUST use AskUserQuestion tool as the FIRST action with multiSelect enabled
- Ask which backends are allowed for this /dev run
- Options (user can select multiple):
- `codex` - Stable, high quality, best cost-performance (default for most tasks)
- `claude` - Fast, lightweight (for quick fixes and config changes)
- `gemini` - UI/UX specialist (for frontend styling and components)
- Store the selected backends as `allowed_backends` set for routing in Step 4
- Special rule: if user selects ONLY `codex`, then ALL subsequent tasks (including UI/quick-fix) MUST use `codex` (no exceptions)
- **Step 1: Requirement Clarification [MANDATORY - DO NOT SKIP]** - **Step 1: Requirement Clarification [MANDATORY - DO NOT SKIP]**
- MUST use AskUserQuestion tool as the FIRST action - no exceptions - MUST use AskUserQuestion tool
- Focus questions on functional boundaries, inputs/outputs, constraints, testing, and required unit-test coverage levels - Focus questions on functional boundaries, inputs/outputs, constraints, testing, and required unit-test coverage levels
- Iterate 2-3 rounds until clear; rely on judgment; keep questions concise - Iterate 2-3 rounds until clear; rely on judgment; keep questions concise
- After clarification complete: MUST use TodoWrite to create task tracking list with workflow steps - After clarification complete: MUST use TodoWrite to create task tracking list with workflow steps
@@ -43,7 +55,10 @@ These rules have HIGHEST PRIORITY and override all other instructions:
**How to invoke for analysis**: **How to invoke for analysis**:
```bash ```bash
codeagent-wrapper --backend codex - <<'EOF' # analysis_backend selection:
# - prefer codex if it is in allowed_backends
# - otherwise pick the first backend in allowed_backends
codeagent-wrapper --backend {analysis_backend} - <<'EOF'
Analyze the codebase for implementing [feature name]. Analyze the codebase for implementing [feature name].
Requirements: Requirements:
@@ -54,8 +69,9 @@ These rules have HIGHEST PRIORITY and override all other instructions:
1. Explore codebase structure and existing patterns 1. Explore codebase structure and existing patterns
2. Evaluate implementation options with trade-offs 2. Evaluate implementation options with trade-offs
3. Make architectural decisions 3. Make architectural decisions
4. Break down into 2-5 parallelizable tasks with dependencies 4. Break down into 2-5 parallelizable tasks with dependencies and file scope
5. Determine if UI work is needed (check for .css/.tsx/.vue files) 5. Classify each task with a single `type`: `default` / `ui` / `quick-fix`
6. Determine if UI work is needed (check for .css/.tsx/.vue files)
Output the analysis following the structure below. Output the analysis following the structure below.
EOF EOF
@@ -76,7 +92,7 @@ These rules have HIGHEST PRIORITY and override all other instructions:
2. **Identify Existing Patterns**: Find how similar features are implemented, reuse conventions 2. **Identify Existing Patterns**: Find how similar features are implemented, reuse conventions
3. **Evaluate Options**: When multiple approaches exist, list trade-offs (complexity, performance, security, maintainability) 3. **Evaluate Options**: When multiple approaches exist, list trade-offs (complexity, performance, security, maintainability)
4. **Make Architectural Decisions**: Choose patterns, APIs, data models with justification 4. **Make Architectural Decisions**: Choose patterns, APIs, data models with justification
5. **Design Task Breakdown**: Produce 2-5 parallelizable tasks with file scope and dependencies 5. **Design Task Breakdown**: Produce parallelizable tasks based on natural functional boundaries with file scope and dependencies
**Analysis Output Structure**: **Analysis Output Structure**:
``` ```
@@ -93,7 +109,7 @@ These rules have HIGHEST PRIORITY and override all other instructions:
[API design, data models, architecture choices made] [API design, data models, architecture choices made]
## Task Breakdown ## Task Breakdown
[2-5 tasks with: ID, description, file scope, dependencies, test command] [2-5 tasks with: ID, description, file scope, dependencies, test command, type(default|ui|quick-fix)]
## UI Determination ## UI Determination
needs_ui: [true/false] needs_ui: [true/false]
@@ -107,27 +123,37 @@ These rules have HIGHEST PRIORITY and override all other instructions:
- **Step 3: Generate Development Documentation** - **Step 3: Generate Development Documentation**
- invoke agent dev-plan-generator - invoke agent dev-plan-generator
- When creating `dev-plan.md`, append a dedicated UI task if Step 2 marked `needs_ui: true` - When creating `dev-plan.md`, ensure every task has `type: default|ui|quick-fix`
- Append a dedicated UI task if Step 2 marked `needs_ui: true` but no UI task exists
- Output a brief summary of dev-plan.md: - Output a brief summary of dev-plan.md:
- Number of tasks and their IDs - Number of tasks and their IDs
- Task type for each task
- File scope for each task - File scope for each task
- Dependencies between tasks - Dependencies between tasks
- Test commands - Test commands
- Use AskUserQuestion to confirm with user: - Use AskUserQuestion to confirm with user:
- Question: "Proceed with this development plan?" (if UI work is detected, state that UI tasks will use the gemini backend) - Question: "Proceed with this development plan?" (state backend routing rules and any forced fallback due to allowed_backends)
- Options: "Confirm and execute" / "Need adjustments" - Options: "Confirm and execute" / "Need adjustments"
- If user chooses "Need adjustments", return to Step 1 or Step 2 based on feedback - If user chooses "Need adjustments", return to Step 1 or Step 2 based on feedback
- **Step 4: Parallel Development Execution [CODEAGENT-WRAPPER ONLY - NO DIRECT EDITS]** - **Step 4: Parallel Development Execution [CODEAGENT-WRAPPER ONLY - NO DIRECT EDITS]**
- MUST use Bash tool to invoke `codeagent-wrapper --parallel` for ALL code changes - MUST use Bash tool to invoke `codeagent-wrapper --parallel` for ALL code changes
- NEVER use Edit, Write, MultiEdit, or Task tools to modify code directly - NEVER use Edit, Write, MultiEdit, or Task tools to modify code directly
- Backend routing (must be deterministic and enforceable):
- Task field: `type: default|ui|quick-fix` (missing → treat as `default`)
- Preferred backend by type:
- `default` → `codex`
- `ui` → `gemini` (enforced when allowed)
- `quick-fix` → `claude`
- If user selected `仅 codex`: all tasks MUST use `codex`
- Otherwise, if preferred backend is not in `allowed_backends`, fallback to the first available backend by priority: `codex` → `claude` → `gemini`
- Build ONE `--parallel` config that includes all tasks in `dev-plan.md` and submit it once via Bash tool: - Build ONE `--parallel` config that includes all tasks in `dev-plan.md` and submit it once via Bash tool:
```bash ```bash
# One shot submission - wrapper handles topology + concurrency # One shot submission - wrapper handles topology + concurrency
codeagent-wrapper --parallel <<'EOF' codeagent-wrapper --parallel <<'EOF'
---TASK--- ---TASK---
id: [task-id-1] id: [task-id-1]
backend: codex backend: [routed-backend-from-type-and-allowed_backends]
workdir: . workdir: .
dependencies: [optional, comma-separated ids] dependencies: [optional, comma-separated ids]
---CONTENT--- ---CONTENT---
@@ -139,7 +165,7 @@ These rules have HIGHEST PRIORITY and override all other instructions:
---TASK--- ---TASK---
id: [task-id-2] id: [task-id-2]
backend: gemini backend: [routed-backend-from-type-and-allowed_backends]
workdir: . workdir: .
dependencies: [optional, comma-separated ids] dependencies: [optional, comma-separated ids]
---CONTENT--- ---CONTENT---
@@ -152,6 +178,7 @@ These rules have HIGHEST PRIORITY and override all other instructions:
``` ```
- **Note**: Use `workdir: .` (current directory) for all tasks unless specific subdirectory is required - **Note**: Use `workdir: .` (current directory) for all tasks unless specific subdirectory is required
- Execute independent tasks concurrently; serialize conflicting ones; track coverage reports - Execute independent tasks concurrently; serialize conflicting ones; track coverage reports
- Backend is routed deterministically based on task `type`, no manual intervention needed
- **Step 5: Coverage Validation** - **Step 5: Coverage Validation**
- Validate each tasks coverage: - Validate each tasks coverage:
@@ -168,11 +195,13 @@ These rules have HIGHEST PRIORITY and override all other instructions:
- Circular dependencies: codeagent-wrapper will detect and fail with error; revise task breakdown to remove cycles - Circular dependencies: codeagent-wrapper will detect and fail with error; revise task breakdown to remove cycles
- Missing dependencies: Ensure all task IDs referenced in `dependencies` field exist - Missing dependencies: Ensure all task IDs referenced in `dependencies` field exist
- **Parallel execution timeout**: Individual tasks timeout after 2 hours (configurable via CODEX_TIMEOUT); failed tasks can be retried individually - **Parallel execution timeout**: Individual tasks timeout after 2 hours (configurable via CODEX_TIMEOUT); failed tasks can be retried individually
- **Backend unavailable**: If codex/claude/gemini CLI not found, fail immediately with clear error message - **Backend unavailable**: If a routed backend is unavailable, fallback to another backend in `allowed_backends` (priority: codexclaudegemini); if none works, fail with a clear error message
**Quality Standards** **Quality Standards**
- Code coverage ≥90% - Code coverage ≥90%
- 2-5 genuinely parallelizable tasks - Tasks based on natural functional boundaries (typically 2-5)
- Each task has exactly one `type: default|ui|quick-fix`
- Backend routed by `type`: `default`→codex, `ui`→gemini, `quick-fix`→claude (with allowed_backends fallback)
- Documentation must be minimal yet actionable - Documentation must be minimal yet actionable
- No verbose implementations; only essential code - No verbose implementations; only essential code

View File

@@ -46,17 +46,23 @@ echo.
echo codeagent-wrapper installed successfully at: echo codeagent-wrapper installed successfully at:
echo %DEST% echo %DEST%
rem Automatically ensure %USERPROFILE%\bin is in the USER (HKCU) PATH rem Ensure %USERPROFILE%\bin is in PATH without duplicating entries
rem 1) Read current user PATH from registry (REG_SZ or REG_EXPAND_SZ) rem 1) Read current user PATH from registry (REG_SZ or REG_EXPAND_SZ)
set "USER_PATH_RAW=" set "USER_PATH_RAW="
set "USER_PATH_TYPE="
for /f "tokens=1,2,*" %%A in ('reg query "HKCU\Environment" /v Path 2^>nul ^| findstr /I /R "^ *Path *REG_"') do ( for /f "tokens=1,2,*" %%A in ('reg query "HKCU\Environment" /v Path 2^>nul ^| findstr /I /R "^ *Path *REG_"') do (
set "USER_PATH_TYPE=%%B"
set "USER_PATH_RAW=%%C" set "USER_PATH_RAW=%%C"
) )
rem Trim leading spaces from USER_PATH_RAW rem Trim leading spaces from USER_PATH_RAW
for /f "tokens=* delims= " %%D in ("!USER_PATH_RAW!") do set "USER_PATH_RAW=%%D" for /f "tokens=* delims= " %%D in ("!USER_PATH_RAW!") do set "USER_PATH_RAW=%%D"
rem 2) Read current system PATH from registry (REG_SZ or REG_EXPAND_SZ)
set "SYS_PATH_RAW="
for /f "tokens=1,2,*" %%A in ('reg query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v Path 2^>nul ^| findstr /I /R "^ *Path *REG_"') do (
set "SYS_PATH_RAW=%%C"
)
rem Trim leading spaces from SYS_PATH_RAW
for /f "tokens=* delims= " %%D in ("!SYS_PATH_RAW!") do set "SYS_PATH_RAW=%%D"
rem Normalize DEST_DIR by removing a trailing backslash if present rem Normalize DEST_DIR by removing a trailing backslash if present
if "!DEST_DIR:~-1!"=="\" set "DEST_DIR=!DEST_DIR:~0,-1!" if "!DEST_DIR:~-1!"=="\" set "DEST_DIR=!DEST_DIR:~0,-1!"
@@ -67,42 +73,63 @@ set "SEARCH_EXP2=;!DEST_DIR!\;"
set "SEARCH_LIT=;!PCT!USERPROFILE!PCT!\bin;" set "SEARCH_LIT=;!PCT!USERPROFILE!PCT!\bin;"
set "SEARCH_LIT2=;!PCT!USERPROFILE!PCT!\bin\;" set "SEARCH_LIT2=;!PCT!USERPROFILE!PCT!\bin\;"
rem Prepare user PATH variants for containment tests rem Prepare PATH variants for containment tests (strip quotes to avoid false negatives)
set "CHECK_RAW=;!USER_PATH_RAW!;" set "USER_PATH_RAW_CLEAN=!USER_PATH_RAW:"=!"
set "USER_PATH_EXP=!USER_PATH_RAW!" set "SYS_PATH_RAW_CLEAN=!SYS_PATH_RAW:"=!"
if defined USER_PATH_EXP call set "USER_PATH_EXP=%%USER_PATH_EXP%%"
set "CHECK_EXP=;!USER_PATH_EXP!;"
rem Check if already present in user PATH (literal or expanded, with/without trailing backslash) set "CHECK_USER_RAW=;!USER_PATH_RAW_CLEAN!;"
set "USER_PATH_EXP=!USER_PATH_RAW_CLEAN!"
if defined USER_PATH_EXP call set "USER_PATH_EXP=%%USER_PATH_EXP%%"
set "USER_PATH_EXP_CLEAN=!USER_PATH_EXP:"=!"
set "CHECK_USER_EXP=;!USER_PATH_EXP_CLEAN!;"
set "CHECK_SYS_RAW=;!SYS_PATH_RAW_CLEAN!;"
set "SYS_PATH_EXP=!SYS_PATH_RAW_CLEAN!"
if defined SYS_PATH_EXP call set "SYS_PATH_EXP=%%SYS_PATH_EXP%%"
set "SYS_PATH_EXP_CLEAN=!SYS_PATH_EXP:"=!"
set "CHECK_SYS_EXP=;!SYS_PATH_EXP_CLEAN!;"
rem Check if already present (literal or expanded, with/without trailing backslash)
set "ALREADY_IN_USERPATH=0" set "ALREADY_IN_USERPATH=0"
echo !CHECK_RAW! | findstr /I /C:"!SEARCH_LIT!" /C:"!SEARCH_LIT2!" >nul && set "ALREADY_IN_USERPATH=1" echo(!CHECK_USER_RAW! | findstr /I /C:"!SEARCH_LIT!" /C:"!SEARCH_LIT2!" >nul && set "ALREADY_IN_USERPATH=1"
if "!ALREADY_IN_USERPATH!"=="0" ( if "!ALREADY_IN_USERPATH!"=="0" (
echo !CHECK_EXP! | findstr /I /C:"!SEARCH_EXP!" /C:"!SEARCH_EXP2!" >nul && set "ALREADY_IN_USERPATH=1" echo(!CHECK_USER_EXP! | findstr /I /C:"!SEARCH_EXP!" /C:"!SEARCH_EXP2!" >nul && set "ALREADY_IN_USERPATH=1"
)
set "ALREADY_IN_SYSPATH=0"
echo(!CHECK_SYS_RAW! | findstr /I /C:"!SEARCH_LIT!" /C:"!SEARCH_LIT2!" >nul && set "ALREADY_IN_SYSPATH=1"
if "!ALREADY_IN_SYSPATH!"=="0" (
echo(!CHECK_SYS_EXP! | findstr /I /C:"!SEARCH_EXP!" /C:"!SEARCH_EXP2!" >nul && set "ALREADY_IN_SYSPATH=1"
) )
if "!ALREADY_IN_USERPATH!"=="1" ( if "!ALREADY_IN_USERPATH!"=="1" (
echo User PATH already includes %%USERPROFILE%%\bin. echo User PATH already includes %%USERPROFILE%%\bin.
) else ( ) else (
rem Not present: append to user PATH using setx without duplicating system PATH if "!ALREADY_IN_SYSPATH!"=="1" (
if defined USER_PATH_RAW ( echo System PATH already includes %%USERPROFILE%%\bin; skipping user PATH update.
set "USER_PATH_NEW=!USER_PATH_RAW!"
if not "!USER_PATH_NEW:~-1!"==";" set "USER_PATH_NEW=!USER_PATH_NEW!;"
set "USER_PATH_NEW=!USER_PATH_NEW!!PCT!USERPROFILE!PCT!\bin"
) else ( ) else (
set "USER_PATH_NEW=!PCT!USERPROFILE!PCT!\bin" rem Not present: append to user PATH
) if defined USER_PATH_RAW (
rem Persist update to HKCU\Environment\Path (user scope) set "USER_PATH_NEW=!USER_PATH_RAW!"
setx PATH "!USER_PATH_NEW!" >nul if not "!USER_PATH_NEW:~-1!"==";" set "USER_PATH_NEW=!USER_PATH_NEW!;"
if errorlevel 1 ( set "USER_PATH_NEW=!USER_PATH_NEW!!PCT!USERPROFILE!PCT!\bin"
echo WARNING: Failed to append %%USERPROFILE%%\bin to your user PATH. ) else (
) else ( set "USER_PATH_NEW=!PCT!USERPROFILE!PCT!\bin"
echo Added %%USERPROFILE%%\bin to your user PATH. )
rem Persist update to HKCU\Environment\Path (user scope)
setx Path "!USER_PATH_NEW!" >nul
if errorlevel 1 (
echo WARNING: Failed to append %%USERPROFILE%%\bin to your user PATH.
) else (
echo Added %%USERPROFILE%%\bin to your user PATH.
)
) )
) )
rem Update current session PATH so codex-wrapper is immediately available rem Update current session PATH so codeagent-wrapper is immediately available
set "CURPATH=;%PATH%;" set "CURPATH=;%PATH%;"
echo !CURPATH! | findstr /I /C:"!SEARCH_EXP!" /C:"!SEARCH_EXP2!" /C:"!SEARCH_LIT!" /C:"!SEARCH_LIT2!" >nul set "CURPATH_CLEAN=!CURPATH:"=!"
echo(!CURPATH_CLEAN! | findstr /I /C:"!SEARCH_EXP!" /C:"!SEARCH_EXP2!" /C:"!SEARCH_LIT!" /C:"!SEARCH_LIT2!" >nul
if errorlevel 1 set "PATH=!DEST_DIR!;!PATH!" if errorlevel 1 set "PATH=!DEST_DIR!;!PATH!"
goto :cleanup goto :cleanup

View File

@@ -48,11 +48,28 @@ else
exit 1 exit 1
fi fi
if [[ ":$PATH:" != *":${BIN_DIR}:"* ]]; then # Auto-add to shell config files with idempotency
if [[ ":${PATH}:" != *":${BIN_DIR}:"* ]]; then
echo "" echo ""
echo "WARNING: ${BIN_DIR} is not in your PATH" echo "WARNING: ${BIN_DIR} is not in your PATH"
echo "Add this line to your ~/.bashrc or ~/.zshrc (then restart your shell):"
echo "" # Detect shell config file
echo " export PATH=\"${BIN_DIR}:\$PATH\"" if [ -n "$ZSH_VERSION" ]; then
RC_FILE="$HOME/.zshrc"
else
RC_FILE="$HOME/.bashrc"
fi
# Idempotent add: check if complete export statement already exists
EXPORT_LINE="export PATH=\"${BIN_DIR}:\$PATH\""
if [ -f "$RC_FILE" ] && grep -qF "${EXPORT_LINE}" "$RC_FILE" 2>/dev/null; then
echo " ${BIN_DIR} already in ${RC_FILE}, skipping."
else
echo " Adding to ${RC_FILE}..."
echo "" >> "$RC_FILE"
echo "# Added by myclaude installer" >> "$RC_FILE"
echo "export PATH=\"${BIN_DIR}:\$PATH\"" >> "$RC_FILE"
echo " Done. Run 'source ${RC_FILE}' or restart shell."
fi
echo "" echo ""
fi fi