#!/usr/bin/env bash set -e # Omni/Agent/start-worker.sh # Launches an Amp worker agent in the specified worktree in a loop. # Usage: ./Omni/Agent/start-worker.sh [worker-directory-name-or-path] # Example: ./Omni/Agent/start-worker.sh omni-worker-1 TARGET="${1:-omni-worker-1}" # 1. Find the Main Repo (where node_modules lives) # The first worktree listed is always the main one MAIN_REPO="$(git worktree list --porcelain | grep '^worktree ' | head -n 1 | cut -d ' ' -f 2)" AMP_BIN="$MAIN_REPO/node_modules/.bin/amp" TASK_BIN="$MAIN_REPO/_/bin/task" # 2. Resolve Worker Path if [ -d "$TARGET" ]; then WORKER_PATH="$(realpath "$TARGET")" elif [ -d "$MAIN_REPO/../$TARGET" ]; then WORKER_PATH="$(realpath "$MAIN_REPO/../$TARGET")" else echo "Error: Worker directory for '$TARGET' not found." exit 1 fi if [ ! -x "$AMP_BIN" ]; then echo "Error: Amp binary not found at '$AMP_BIN'." exit 1 fi # Ensure task binary is built/available if [ ! -x "$TASK_BIN" ]; then echo "Warning: Task binary not found at '$TASK_BIN'. Assuming it's in path or build it first." fi echo "Starting Worker Agent Loop" echo " Worker Path: $WORKER_PATH" echo " Amp Binary: $AMP_BIN" echo " Log File: $WORKER_PATH/_/llm/amp.log" echo " Monitor: tail -f $WORKER_PATH/_/llm/amp.log" echo " Press Ctrl+C to stop." # Function to sync tasks safely sync_tasks() { "$MAIN_REPO/Omni/Agent/sync-tasks.sh" "$@" } cd "$WORKER_PATH" # 3. The Worker Loop while true; do echo "----------------------------------------------------------------" echo "$(date): Syncing and checking for work..." # A. Sync with Live # We use 'git rebase' to keep history linear git checkout omni-worker-1 >/dev/null 2>&1 # Rebase directly on local live branch (shared repo) if ! git rebase live >/dev/null 2>&1; then echo "Warning: Rebase conflict at start of loop. Aborting rebase and proceeding with local state." git rebase --abort || true fi # B. Sync Tasks sync_tasks # C. Find Ready Work # We use jq to parse the first task # Note: task ready --json returns an array [...] TASK_JSON=$("$TASK_BIN" ready --json 2>/dev/null | jq -r '.[0] // empty') if [ -z "$TASK_JSON" ]; then echo "$(date): No ready tasks. Sleeping for 60s..." sleep 60 continue fi TASK_ID=$(echo "$TASK_JSON" | jq -r '.taskId') TASK_TITLE=$(echo "$TASK_JSON" | jq -r '.taskTitle') TASK_NS=$(echo "$TASK_JSON" | jq -r '.taskNamespace // "root"') echo "$(date): Claiming task $TASK_ID: $TASK_TITLE" # D. Claim Task "$TASK_BIN" update "$TASK_ID" in-progress >/dev/null sync_tasks --commit >/dev/null # E. Prepare Branch BRANCH_NAME="task/$TASK_ID" if git show-ref --verify --quiet "refs/heads/$BRANCH_NAME"; then echo "Resuming existing branch $BRANCH_NAME" # Force checkout to overwrite untracked files (like .tasks/counters.jsonl) # that may have been generated by sync tools but are tracked in the branch. git checkout -f "$BRANCH_NAME" >/dev/null else echo "Creating new branch $BRANCH_NAME" git checkout -b "$BRANCH_NAME" >/dev/null fi # F. Execute Agent echo "Launching Amp to implement task..." TASK_DETAILS=$("$TASK_BIN" show "$TASK_ID") # We construct a specific prompt for the agent PROMPT="You are a Worker Agent. Your goal is to implement the following task: $TASK_DETAILS INSTRUCTIONS: 1. Analyze the codebase (use finder/Grep) to understand where to make changes. 2. Implement the changes by editing files. 3. Run tests to verify your work (e.g., 'bild --test Omni/Namespace'). 4. Fix any errors found during testing. 5. Do NOT update the task status or manage git branches (the system handles that). 6. When finished and tested, exit. Context: - You are working in '$WORKER_PATH'. - The task is in namespace '$TASK_NS'. " mkdir -p _/llm "$AMP_BIN" --log-level debug --log-file "_/llm/amp.log" --dangerously-allow-all -x "$PROMPT" AGENT_EXIT_CODE=$? if [ $AGENT_EXIT_CODE -eq 0 ]; then echo "Agent finished successfully." # G. Submit Work if [ -n "$(git status --porcelain)" ]; then echo "Committing changes..." git add . git commit -m "feat: implement $TASK_ID" || true else echo "No changes to commit." fi echo "Submitting for review..." # Switch back to base git checkout omni-worker-1 >/dev/null # Sync again (rebase on latest live) # If rebase fails, we MUST abort to avoid leaving the repo in a broken state if ! git rebase live >/dev/null 2>&1; then echo "Warning: Rebase conflict. Aborting rebase and proceeding with local state." git rebase --abort || true fi sync_tasks # Update status echo "Marking task $TASK_ID as Review..." if "$TASK_BIN" update "$TASK_ID" review; then sync_tasks --commit >/dev/null echo "Task $TASK_ID submitted for review." else echo "Error: Failed to update task status to Review." fi else echo "Agent failed (exit code $AGENT_EXIT_CODE). Sleeping for 10s before retrying..." sleep 10 fi echo "Cooldown..." sleep 5 done