#!/bin/bash # Makima Orchestrator Helper Script # Usage: ./orchestrate.sh [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 ] [--files "file1,file2"] if [ -z "$2" ] || [ -z "$3" ]; then echo "Usage: $0 create \"\" \"\" [--continue-from ] [--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 " >&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 " >&2 exit 1 fi api_call POST "$API_URL/api/v1/mesh/tasks/$2/stop" ;; status) if [ -z "$2" ]; then echo "Usage: $0 status " >&2 exit 1 fi api_call GET "$API_URL/api/v1/mesh/tasks/$2" ;; output) if [ -z "$2" ]; then echo "Usage: $0 output " >&2 exit 1 fi api_call GET "$API_URL/api/v1/mesh/tasks/$2/output" ;; worktree) if [ -z "$2" ]; then echo "Usage: $0 worktree " >&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 [args...]" echo "" echo "Subtask Commands:" echo " list List all subtasks and their status" echo " create \"\" \"\" 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 Start a subtask" echo " stop Stop a running subtask" echo " status Get detailed subtask status" echo " output Get subtask output history" echo " worktree 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