#!/bin/bash # Makima Supervisor Helper Script # Usage: ./supervisor.sh [args...] API_URL="${MAKIMA_API_URL:-http://localhost:8080}" API_KEY="${MAKIMA_API_KEY}" TASK_ID="${MAKIMA_TASK_ID}" CONTRACT_ID="${MAKIMA_CONTRACT_ID}" if [ -z "$API_KEY" ]; then echo "Error: MAKIMA_API_KEY not set" >&2 exit 1 fi if [ -z "$CONTRACT_ID" ]; then echo "Error: MAKIMA_CONTRACT_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 tasks) # Get all tasks in this contract's tree api_call GET "$API_URL/api/v1/mesh/supervisor/contracts/$CONTRACT_ID/tasks" ;; tree) # Get full task tree structure api_call GET "$API_URL/api/v1/mesh/supervisor/contracts/$CONTRACT_ID/tree" ;; spawn) # Create a new task (fire and forget) if [ -z "$2" ] || [ -z "$3" ]; then echo "Usage: $0 spawn \"\" \"\" [--parent ] [--checkpoint ]" >&2 exit 1 fi NAME="$2" PLAN="$3" PARENT_ID="" CHECKPOINT_SHA="" shift 3 while [ $# -gt 0 ]; do case "$1" in --parent) PARENT_ID="$2" shift 2 ;; --checkpoint) CHECKPOINT_SHA="$2" shift 2 ;; *) echo "Unknown option: $1" >&2 exit 1 ;; esac done # Escape for JSON: backslashes first, then quotes, then newlines NAME_ESCAPED=$(printf '%s' "$NAME" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g') PLAN_ESCAPED=$(printf '%s' "$PLAN" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g') # Build JSON body JSON_BODY="{\"name\":\"$NAME_ESCAPED\",\"plan\":\"$PLAN_ESCAPED\",\"contractId\":\"$CONTRACT_ID\"" if [ -n "$PARENT_ID" ]; then JSON_BODY="$JSON_BODY,\"parentTaskId\":\"$PARENT_ID\"" fi if [ -n "$CHECKPOINT_SHA" ]; then JSON_BODY="$JSON_BODY,\"checkpointSha\":\"$CHECKPOINT_SHA\"" fi JSON_BODY="$JSON_BODY}" echo "Creating task: $NAME..." >&2 api_call POST "$API_URL/api/v1/mesh/supervisor/tasks" "$JSON_BODY" ;; wait) # Wait for a task to complete if [ -z "$2" ]; then echo "Usage: $0 wait [timeout_seconds]" >&2 exit 1 fi WAIT_TASK_ID="$2" TIMEOUT="${3:-300}" echo "Waiting for task $WAIT_TASK_ID (timeout: ${TIMEOUT}s)..." >&2 api_call POST "$API_URL/api/v1/mesh/supervisor/tasks/$WAIT_TASK_ID/wait" "{\"timeoutSeconds\":$TIMEOUT}" ;; read-file) # Read a file from any task's worktree if [ -z "$2" ] || [ -z "$3" ]; then echo "Usage: $0 read-file " >&2 exit 1 fi READ_TASK_ID="$2" FILE_PATH="$3" FILE_PATH_ESCAPED=$(echo "$FILE_PATH" | sed 's/"/\\"/g') api_call POST "$API_URL/api/v1/mesh/supervisor/tasks/$READ_TASK_ID/read-file" "{\"filePath\":\"$FILE_PATH_ESCAPED\"}" ;; checkpoint) # Create a git checkpoint if [ -z "$2" ]; then echo "Usage: $0 checkpoint \"\"" >&2 exit 1 fi MESSAGE_ESCAPED=$(printf '%s' "$2" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g') api_call POST "$API_URL/api/v1/mesh/tasks/$TASK_ID/checkpoint" "{\"message\":\"$MESSAGE_ESCAPED\"}" ;; checkpoints) # List checkpoints for a task CHECK_TASK_ID="${2:-$TASK_ID}" api_call GET "$API_URL/api/v1/mesh/tasks/$CHECK_TASK_ID/checkpoints" ;; status) # Get contract status api_call GET "$API_URL/api/v1/contracts/$CONTRACT_ID/daemon/status" ;; branch) # Create a new branch if [ -z "$2" ]; then echo "Usage: $0 branch [--from ]" >&2 exit 1 fi BRANCH_NAME="$2" FROM_REF="" shift 2 while [ $# -gt 0 ]; do case "$1" in --from) FROM_REF="$2" shift 2 ;; *) echo "Unknown option: $1" >&2 exit 1 ;; esac done JSON_BODY="{\"branchName\":\"$BRANCH_NAME\"" if [ -n "$FROM_REF" ]; then JSON_BODY="$JSON_BODY,\"fromRef\":\"$FROM_REF\"" fi JSON_BODY="$JSON_BODY}" echo "Creating branch: $BRANCH_NAME..." >&2 api_call POST "$API_URL/api/v1/mesh/supervisor/branches" "$JSON_BODY" ;; merge) # Merge a task's changes to a branch if [ -z "$2" ]; then echo "Usage: $0 merge [--to ] [--squash]" >&2 exit 1 fi MERGE_TASK_ID="$2" TARGET_BRANCH="" SQUASH="false" shift 2 while [ $# -gt 0 ]; do case "$1" in --to) TARGET_BRANCH="$2" shift 2 ;; --squash) SQUASH="true" shift ;; *) echo "Unknown option: $1" >&2 exit 1 ;; esac done JSON_BODY="{\"squash\":$SQUASH" if [ -n "$TARGET_BRANCH" ]; then JSON_BODY="$JSON_BODY,\"targetBranch\":\"$TARGET_BRANCH\"" fi JSON_BODY="$JSON_BODY}" echo "Merging task $MERGE_TASK_ID..." >&2 api_call POST "$API_URL/api/v1/mesh/supervisor/tasks/$MERGE_TASK_ID/merge" "$JSON_BODY" ;; pr) # Create a pull request if [ -z "$2" ]; then echo "Usage: $0 pr --title \"Title\" [--body \"Body\"] [--base main]" >&2 exit 1 fi PR_TASK_ID="$2" PR_TITLE="" PR_BODY="" PR_BASE="main" shift 2 while [ $# -gt 0 ]; do case "$1" in --title) PR_TITLE="$2" shift 2 ;; --body) PR_BODY="$2" shift 2 ;; --base) PR_BASE="$2" shift 2 ;; *) echo "Unknown option: $1" >&2 exit 1 ;; esac done if [ -z "$PR_TITLE" ]; then echo "Error: --title is required" >&2 exit 1 fi TITLE_ESCAPED=$(printf '%s' "$PR_TITLE" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g') BODY_ESCAPED=$(printf '%s' "$PR_BODY" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g') JSON_BODY="{\"taskId\":\"$PR_TASK_ID\",\"title\":\"$TITLE_ESCAPED\",\"body\":\"$BODY_ESCAPED\",\"baseBranch\":\"$PR_BASE\"}" echo "Creating PR for task $PR_TASK_ID..." >&2 api_call POST "$API_URL/api/v1/mesh/supervisor/pr" "$JSON_BODY" ;; diff) # Get diff for a task if [ -z "$2" ]; then echo "Usage: $0 diff " >&2 exit 1 fi DIFF_TASK_ID="$2" api_call GET "$API_URL/api/v1/mesh/supervisor/tasks/$DIFF_TASK_ID/diff" ;; *) echo "Makima Supervisor Helper" echo "" echo "Usage: $0 [args...]" echo "" echo "Task Management:" echo " tasks List all tasks in contract tree" echo " tree Get full task tree structure" echo " spawn \"\" \"\" Create and start a new task" echo " --parent Parent task to branch from" echo " --checkpoint Checkpoint to start from" echo " wait [timeout] Wait for task completion" echo " read-file Read file from task's worktree" echo "" echo "Git Operations:" echo " branch [--from ] Create a new branch" echo " merge [--to ] Merge task changes" echo " --squash Squash commits on merge" echo " pr --title \"Title\" Create a pull request" echo " --body \"Body\" PR description" echo " --base Target branch (default: main)" echo " diff View task's diff" echo "" echo "Checkpoints:" echo " checkpoint \"\" Create git checkpoint" echo " checkpoints [task_id] List task checkpoints" echo "" echo "Contract:" echo " status Get contract status" echo "" echo "Examples:" echo " $0 tasks" echo " $0 spawn \"Implement auth\" \"Add user authentication system\"" echo " $0 wait abc12345 600" echo " $0 merge abc12345 --to main --squash" echo " $0 pr abc12345 --title \"Add auth\" --base main" ;; esac