summaryrefslogtreecommitdiff
path: root/internal/cli/create.go
blob: 396cd778f851b96beb8d7dc4a6679a6b450aa51a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package cli

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"

	"github.com/spf13/cobra"
)

func newCreateCmd() *cobra.Command {
	var (
		serverURL    string
		instructions string
		workingDir   string
		model        string
		agentType    string
		parentID     string
		budget       float64
		timeout      string
		priority     string
		autoStart    bool
	)

	cmd := &cobra.Command{
		Use:   "create <name>",
		Short: "Create a task via the running server",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return createTask(serverURL, args[0], instructions, workingDir, model, agentType, parentID, budget, timeout, priority, autoStart)
		},
	}

	cmd.Flags().StringVar(&serverURL, "server", defaultServerURL, "claudomator server URL")
	cmd.Flags().StringVarP(&instructions, "instructions", "i", "", "task instructions (required)")
	cmd.Flags().StringVarP(&workingDir, "working-dir", "d", "", "working directory for the task")
	cmd.Flags().StringVarP(&model, "model", "m", "", "model to use")
	cmd.Flags().StringVar(&agentType, "agent-type", "claude", "agent type: claude, gemini")
	cmd.Flags().StringVar(&parentID, "parent-id", "", "parent task ID (makes this a subtask)")
	cmd.Flags().Float64Var(&budget, "budget", 1.0, "max budget in USD")
	cmd.Flags().StringVar(&timeout, "timeout", "15m", "task timeout")
	cmd.Flags().StringVar(&priority, "priority", "normal", "priority: high, normal, low")
	cmd.Flags().BoolVar(&autoStart, "start", false, "queue for execution immediately after creating")
	_ = cmd.MarkFlagRequired("instructions")

	return cmd
}

func createTask(serverURL, name, instructions, workingDir, model, agentType, parentID string, budget float64, timeout, priority string, autoStart bool) error {
	body := map[string]interface{}{
		"name":     name,
		"timeout":  timeout,
		"priority": priority,
		"agent": map[string]interface{}{
			"type":           agentType,
			"instructions":   instructions,
			"project_dir":    workingDir,
			"model":          model,
			"max_budget_usd": budget,
		},
	}
	if parentID != "" {
		body["parent_task_id"] = parentID
	}

	data, _ := json.Marshal(body)
	resp, err := httpClient.Post(serverURL+"/api/tasks", "application/json", bytes.NewReader(data)) //nolint:noctx
	if err != nil {
		return fmt.Errorf("POST /api/tasks: %w", err)
	}
	defer resp.Body.Close()

	raw, _ := io.ReadAll(resp.Body)
	var result map[string]interface{}
	if err := json.Unmarshal(raw, &result); err != nil {
		return fmt.Errorf("server returned invalid JSON (status %d): %s", resp.StatusCode, string(raw))
	}

	if resp.StatusCode >= 300 {
		return fmt.Errorf("server returned %d: %v", resp.StatusCode, result["error"])
	}

	id, _ := result["id"].(string)
	if id == "" {
		return fmt.Errorf("server returned task without id field")
	}
	fmt.Printf("Created task %s\n", id)

	if autoStart {
		return startTask(serverURL, id, agentType)
	}
	return nil
}