feat: añadir skills create-tui, init-frontend, init-go-module y utilidades
Nuevas skills para crear TUIs, inicializar frontends React y módulos Go. Incluye binario parallel-executor y utilidades de soporte. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lucasdataproyects/devfactory/core"
|
||||
dfshell "github.com/lucasdataproyects/devfactory/shell"
|
||||
|
||||
pcore "github.com/lucasdataproyects/parallel-executor/core"
|
||||
)
|
||||
|
||||
const defaultTimeout = 30 * time.Minute
|
||||
|
||||
// ExecuteIssue ejecuta claude para resolver una issue en un worktree.
|
||||
// Invoca `claude -p` con el prompt de fix-issue dentro del worktree.
|
||||
func ExecuteIssue(spec pcore.WorktreeSpec, timeout time.Duration) pcore.ExecutionResult {
|
||||
start := time.Now()
|
||||
|
||||
if timeout == 0 {
|
||||
timeout = defaultTimeout
|
||||
}
|
||||
|
||||
prompt := fmt.Sprintf(
|
||||
"Read the issue file dev/issues/%04d-*.md and implement all tasks. "+
|
||||
"Run tests after each change. Follow pure core / impure shell pattern. "+
|
||||
"When done, commit all changes with a descriptive message.",
|
||||
spec.Issue.Number,
|
||||
)
|
||||
|
||||
result := dfshell.RunWithTimeout("claude",
|
||||
timeout,
|
||||
"-p", prompt,
|
||||
"--cwd", spec.WorkDir,
|
||||
)
|
||||
|
||||
duration := time.Since(start).Round(time.Second).String()
|
||||
|
||||
if result.IsErr() {
|
||||
return pcore.ExecutionResult{
|
||||
Issue: spec.Issue,
|
||||
Success: false,
|
||||
Duration: duration,
|
||||
Error: result.Error().Error(),
|
||||
}
|
||||
}
|
||||
|
||||
cmdResult := result.Unwrap()
|
||||
if !cmdResult.Success() {
|
||||
return pcore.ExecutionResult{
|
||||
Issue: spec.Issue,
|
||||
Success: false,
|
||||
Duration: duration,
|
||||
Error: cmdResult.Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
return pcore.ExecutionResult{
|
||||
Issue: spec.Issue,
|
||||
Success: true,
|
||||
Duration: duration,
|
||||
}
|
||||
}
|
||||
|
||||
// PushWorktreeBranch hace push de la branch del worktree al remote.
|
||||
func PushWorktreeBranch(spec pcore.WorktreeSpec) core.Result[struct{}] {
|
||||
result := dfshell.Run("git", "-C", spec.WorkDir,
|
||||
"push", "-u", "origin", spec.BranchName,
|
||||
)
|
||||
if result.IsErr() {
|
||||
return core.Err[struct{}](fmt.Errorf("push failed for %s: %w",
|
||||
spec.BranchName, result.Error()))
|
||||
}
|
||||
return core.Ok(struct{}{})
|
||||
}
|
||||
|
||||
// MergeBranchToMaster mergea una branch a master con --no-ff.
|
||||
func MergeBranchToMaster(branchName string, repoRoot string) core.Result[struct{}] {
|
||||
// Checkout master
|
||||
result := dfshell.Run("git", "-C", repoRoot, "checkout", "master")
|
||||
if result.IsErr() {
|
||||
return core.Err[struct{}](result.Error())
|
||||
}
|
||||
|
||||
// Merge --no-ff
|
||||
message := fmt.Sprintf("merge: %s — parallel execution", branchName)
|
||||
result = dfshell.Run("git", "-C", repoRoot,
|
||||
"merge", "--no-ff", "-m", message, branchName,
|
||||
)
|
||||
if result.IsErr() {
|
||||
return core.Err[struct{}](fmt.Errorf("merge failed for %s: %w",
|
||||
branchName, result.Error()))
|
||||
}
|
||||
|
||||
return core.Ok(struct{}{})
|
||||
}
|
||||
|
||||
// DeleteBranch elimina una branch local.
|
||||
func DeleteBranch(branchName string, repoRoot string) core.Result[struct{}] {
|
||||
result := dfshell.Run("git", "-C", repoRoot, "branch", "-d", branchName)
|
||||
if result.IsErr() {
|
||||
return core.Err[struct{}](result.Error())
|
||||
}
|
||||
return core.Ok(struct{}{})
|
||||
}
|
||||
|
||||
// ReadIssueFiles lee todos los archivos de issues de un directorio.
|
||||
func ReadIssueFiles(issuesDir string) core.Result[map[string]string] {
|
||||
entries := dfshell.ListDir(issuesDir)
|
||||
if entries.IsErr() {
|
||||
return core.Err[map[string]string](entries.Error())
|
||||
}
|
||||
|
||||
files := make(map[string]string)
|
||||
for _, entry := range entries.Unwrap() {
|
||||
if !strings.HasSuffix(entry, ".md") || entry == "README.md" {
|
||||
continue
|
||||
}
|
||||
content := dfshell.ReadString(issuesDir + "/" + entry)
|
||||
if content.IsOk() {
|
||||
files[entry] = content.Unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
return core.Ok(files)
|
||||
}
|
||||
Reference in New Issue
Block a user