blob: 15095bd9c2176760b9c06d14ffb2ee9136c742ad (
plain) (
blame)
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
#!/bin/bash
# Makima Orchestrator Helper Script
# Usage: ./orchestrate.sh <command> [args...]
API_URL="${MAKIMA_API_URL:-http://localhost:8080}"
API_KEY="${MAKIMA_API_KEY}"
TASK_ID="${MAKIMA_TASK_ID}"
if [ -z "$API_KEY" ]; then
echo "Error: MAKIMA_API_KEY not set" >&2
exit 1
fi
if [ -z "$TASK_ID" ]; then
echo "Error: MAKIMA_TASK_ID not set" >&2
exit 1
fi
# Helper function to make API calls and check for errors
api_call() {
local method="$1"
local url="$2"
local data="$3"
local response
local http_code
if [ -n "$data" ]; then
response=$(curl -s -w "\n%{http_code}" -X "$method" \
-H "X-Makima-Tool-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "$data" \
"$url")
else
response=$(curl -s -w "\n%{http_code}" -X "$method" \
-H "X-Makima-Tool-Key: $API_KEY" \
"$url")
fi
# Extract HTTP code (last line) and body (everything else)
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
# Check for curl errors or non-2xx status
if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then
echo "Error: API request failed with HTTP $http_code" >&2
echo "URL: $url" >&2
echo "Response: $body" >&2
echo "$body"
return 1
fi
echo "$body"
return 0
}
case "$1" in
list)
api_call GET "$API_URL/api/v1/mesh/tasks/$TASK_ID/subtasks"
;;
create)
# Parse arguments: create "name" "plan" [--continue-from <task_id>] [--files "file1,file2"]
if [ -z "$2" ] || [ -z "$3" ]; then
echo "Usage: $0 create \"<name>\" \"<plan>\" [--continue-from <task_id>] [--files \"file1,file2\"]" >&2
exit 1
fi
NAME="$2"
PLAN="$3"
CONTINUE_FROM=""
COPY_FILES=""
# Parse optional flags (can be in any order after name and plan)
shift 3
while [ $# -gt 0 ]; do
case "$1" in
--continue-from)
CONTINUE_FROM="$2"
shift 2
;;
--files)
COPY_FILES="$2"
shift 2
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
# Escape quotes in name and plan for JSON
NAME_ESCAPED=$(echo "$NAME" | sed 's/"/\\"/g' | sed 's/\\/\\\\/g')
PLAN_ESCAPED=$(echo "$PLAN" | sed 's/"/\\"/g' | sed 's/\\/\\\\/g')
# Build JSON body
JSON_BODY="{\"name\":\"$NAME_ESCAPED\",\"plan\":\"$PLAN_ESCAPED\",\"parentTaskId\":\"$TASK_ID\""
if [ -n "$CONTINUE_FROM" ]; then
echo "Creating subtask: $NAME (continuing from $CONTINUE_FROM)..." >&2
JSON_BODY="$JSON_BODY,\"continueFromTaskId\":\"$CONTINUE_FROM\""
else
echo "Creating subtask: $NAME..." >&2
fi
if [ -n "$COPY_FILES" ]; then
# Convert comma-separated file list to JSON array
FILES_JSON="["
first=true
IFS=',' read -ra FILE_ARRAY <<< "$COPY_FILES"
for file in "${FILE_ARRAY[@]}"; do
file=$(echo "$file" | xargs) # trim whitespace
if [ "$first" = true ]; then
FILES_JSON="$FILES_JSON\"$file\""
first=false
else
FILES_JSON="$FILES_JSON,\"$file\""
fi
done
FILES_JSON="$FILES_JSON]"
JSON_BODY="$JSON_BODY,\"copyFiles\":$FILES_JSON"
echo " (copying files: $COPY_FILES)" >&2
fi
JSON_BODY="$JSON_BODY}"
api_call POST "$API_URL/api/v1/mesh/tasks" "$JSON_BODY"
;;
start)
if [ -z "$2" ]; then
echo "Usage: $0 start <subtask_id>" >&2
exit 1
fi
echo "Starting subtask $2..." >&2
api_call POST "$API_URL/api/v1/mesh/tasks/$2/start"
;;
stop)
if [ -z "$2" ]; then
echo "Usage: $0 stop <subtask_id>" >&2
exit 1
fi
api_call POST "$API_URL/api/v1/mesh/tasks/$2/stop"
;;
status)
if [ -z "$2" ]; then
echo "Usage: $0 status <subtask_id>" >&2
exit 1
fi
api_call GET "$API_URL/api/v1/mesh/tasks/$2"
;;
output)
if [ -z "$2" ]; then
echo "Usage: $0 output <subtask_id>" >&2
exit 1
fi
api_call GET "$API_URL/api/v1/mesh/tasks/$2/output"
;;
worktree)
if [ -z "$2" ]; then
echo "Usage: $0 worktree <subtask_id>" >&2
exit 1
fi
# Get the worktree path from the task's overlayPath field via API
TASK_JSON=$(api_call GET "$API_URL/api/v1/mesh/tasks/$2")
if [ $? -ne 0 ]; then
echo "Error: Failed to get task info" >&2
exit 1
fi
WORKTREE_PATH=$(echo "$TASK_JSON" | grep -o '"overlayPath":"[^"]*"' | cut -d'"' -f4)
if [ -z "$WORKTREE_PATH" ]; then
echo "Error: Task has no worktree path (may not have started yet)" >&2
exit 1
fi
if [ -d "$WORKTREE_PATH" ]; then
echo "$WORKTREE_PATH"
else
echo "Error: Worktree not found at $WORKTREE_PATH" >&2
echo "The worktree may have been cleaned up." >&2
exit 1
fi
;;
done)
SUMMARY="${2:-Task completed}"
api_call PUT "$API_URL/api/v1/mesh/tasks/$TASK_ID" "{\"status\":\"done\",\"progressSummary\":\"$SUMMARY\"}"
;;
*)
echo "Makima Orchestrator Helper"
echo ""
echo "Usage: $0 <command> [args...]"
echo ""
echo "Subtask Commands:"
echo " list List all subtasks and their status"
echo " create \"<name>\" \"<plan>\" Create a new subtask"
echo " create \"...\" --continue-from ID Create subtask continuing from another task's worktree"
echo " create \"...\" --files \"file1,file2\" Copy specific files from parent (orchestrator) worktree"
echo " start <subtask_id> Start a subtask"
echo " stop <subtask_id> Stop a running subtask"
echo " status <subtask_id> Get detailed subtask status"
echo " output <subtask_id> Get subtask output history"
echo " worktree <subtask_id> Get path to subtask's worktree"
echo ""
echo "Completion:"
echo " done [summary] Mark orchestrator as complete"
echo ""
echo "Examples:"
echo " create \"Fix bug\" \"Fix the null check bug\" --files \"PLAN.md\""
echo " create \"Step 2\" \"Continue work\" --continue-from abc123 --files \"shared.rs,types.rs\""
;;
esac
|