Auto-enable worktrees for code tasks
This commit is contained in:
@@ -2,6 +2,7 @@ package orch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -15,14 +16,14 @@ import (
|
||||
)
|
||||
|
||||
func newDispatchWorkspacePreparer(cmd *cobra.Command, opts dispatchOptions) store.DispatchWorkspacePreparer {
|
||||
if !dispatchUsesWorktree(opts) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := cmd.Context()
|
||||
|
||||
return func(task store.Task, attemptNo int) (store.DispatchWorkspace, func(), error) {
|
||||
return provisionDispatchWorkspace(ctx, opts, task, attemptNo)
|
||||
effectiveOpts, useWorktree := resolveDispatchWorktreeOptions(task, opts)
|
||||
if !useWorktree {
|
||||
return store.DispatchWorkspace{}, func() {}, nil
|
||||
}
|
||||
return provisionDispatchWorkspace(ctx, effectiveOpts, task, attemptNo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +53,104 @@ func newAttemptReuseWorkspacePreparer(cmd *cobra.Command, task store.Task, attem
|
||||
}
|
||||
|
||||
func dispatchUsesWorktree(opts dispatchOptions) bool {
|
||||
return strings.TrimSpace(opts.repoPath) != "" ||
|
||||
strings.TrimSpace(opts.workspaceRoot) != "" ||
|
||||
return strings.TrimSpace(opts.workspaceRoot) != "" ||
|
||||
opts.strictWorktree
|
||||
}
|
||||
|
||||
func resolveDispatchWorktreeOptions(task store.Task, opts dispatchOptions) (dispatchOptions, bool) {
|
||||
if dispatchUsesWorktree(opts) {
|
||||
return opts, true
|
||||
}
|
||||
if !taskLooksLikeCodeWork(task) {
|
||||
return opts, false
|
||||
}
|
||||
|
||||
auto := opts
|
||||
auto.strictWorktree = true
|
||||
return auto, true
|
||||
}
|
||||
|
||||
func taskLooksLikeCodeWork(task store.Task) bool {
|
||||
if acceptanceJSONLooksCodeLike(task.AcceptanceJSON) {
|
||||
return true
|
||||
}
|
||||
return roleLooksCodeLike(task.DefaultTo)
|
||||
}
|
||||
|
||||
func acceptanceJSONLooksCodeLike(raw json.RawMessage) bool {
|
||||
if len(raw) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var value any
|
||||
if err := json.Unmarshal(raw, &value); err != nil {
|
||||
return false
|
||||
}
|
||||
return acceptanceValueLooksCodeLike(value)
|
||||
}
|
||||
|
||||
func acceptanceValueLooksCodeLike(value any) bool {
|
||||
switch typed := value.(type) {
|
||||
case map[string]any:
|
||||
for key, raw := range typed {
|
||||
lowerKey := strings.ToLower(strings.TrimSpace(key))
|
||||
switch lowerKey {
|
||||
case "code", "code_task", "writes_code", "worktree":
|
||||
if boolValue, ok := raw.(bool); ok && boolValue {
|
||||
return true
|
||||
}
|
||||
case "kind", "task_type", "mode", "type":
|
||||
if stringValue, ok := raw.(string); ok && isCodeLikeMarker(stringValue) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if acceptanceValueLooksCodeLike(raw) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case []any:
|
||||
for _, item := range typed {
|
||||
if acceptanceValueLooksCodeLike(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case string:
|
||||
return isCodeLikeMarker(typed)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func roleLooksCodeLike(role string) bool {
|
||||
role = strings.ToLower(strings.TrimSpace(role))
|
||||
if role == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, token := range splitIdentifierTokens(role) {
|
||||
switch token {
|
||||
case "backend", "frontend", "front", "admin", "ui", "fullstack", "foundation", "db", "database", "mobile", "ios", "android", "web", "platform", "infra", "api":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isCodeLikeMarker(value string) bool {
|
||||
value = strings.ToLower(strings.TrimSpace(value))
|
||||
switch value {
|
||||
case "code", "code_task", "code-task", "code-change", "code_change", "implementation", "patch", "diff", "repo":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func splitIdentifierTokens(value string) []string {
|
||||
return strings.FieldsFunc(value, func(r rune) bool {
|
||||
return !((r >= 'a' && r <= 'z') || (r >= '0' && r <= '9'))
|
||||
})
|
||||
}
|
||||
|
||||
func provisionDispatchWorkspace(ctx context.Context, opts dispatchOptions, task store.Task, attemptNo int) (store.DispatchWorkspace, func(), error) {
|
||||
repoRoot, err := resolveRepoRoot(ctx, opts.repoPath)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user